- Make it present some frames - Make it check that the frames are from the new device, instead of checking TerminateDevice count; fixes https://bugs.winehq.org/show_bug.cgi?id=55649 - ~~Make it check for and avoid some absurd crash on Windows~~
~~I tried everything I could think of, but Windows absolutely refuses to present a frame after changing the D3D device, instead choosing to return various absurd errors (segfaults, deadlocks, out of memory, etc). I suspect the VMR9 is haunted.~~
edit: Works on Windows now
-- v2: quartz/tests: Improve VMR9 ChangeD3DDevice test.
From: Alfred Agrell floating@muncher.se
- Checks that it presents using the new device, instead of counting TerminateDevice - Works on Windows now --- dlls/quartz/tests/vmr9.c | 93 +++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 11 deletions(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 447273a91df..4328b1beac4 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -866,6 +866,7 @@ struct testfilter { struct strmbase_filter filter; struct strmbase_source source; + AM_MEDIA_TYPE *mt; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -900,8 +901,21 @@ static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface, return S_OK; }
+static HRESULT testsource_get_media_type(struct strmbase_pin *pin, unsigned int index, AM_MEDIA_TYPE *mt) +{ + struct testfilter *filter = impl_from_strmbase_filter(pin->filter); + + if (!index && filter->mt) + { + CopyMediaType(mt, filter->mt); + return S_OK; + } + return VFW_S_NO_MORE_ITEMS; +} + static const struct strmbase_source_ops testsource_ops = { + .base.pin_get_media_type = testsource_get_media_type, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideAllocator = testsource_DecideAllocator, }; @@ -911,6 +925,7 @@ static void testfilter_init(struct testfilter *filter) static const GUID clsid = {0xabacab}; strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops); + filter->mt = NULL; }
static void test_allocator(IMemInputPin *input) @@ -1586,7 +1601,7 @@ static void test_window_close(IPin *pin, IMemInputPin *input, IMediaControl *con ok(ret == 1, "Expected EC_USERABORT.\n");
ok(IsWindow(hwnd), "Window should exist.\n"); - ok(!IsWindowVisible(hwnd), "Window should be visible.\n"); + ok(!IsWindowVisible(hwnd), "Window should be invisible.\n");
thread = send_frame(input); ret = WaitForSingleObject(thread, 1000); @@ -2934,6 +2949,7 @@ struct presenter
D3DFORMAT format; DWORD accept_flags; + IDirect3DDevice9 *device; IDirect3DSurface9 *surfaces[5]; IVMRSurfaceAllocatorNotify9 *notify; unsigned int got_PresentImage, got_TerminateDevice; @@ -2979,9 +2995,13 @@ static HRESULT WINAPI presenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD static HRESULT WINAPI presenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR cookie, VMR9PresentationInfo *info) { struct presenter *presenter = impl_from_IVMRImagePresenter9(iface); + IDirect3DDevice9 *device; static const RECT rect;
if (winetest_debug > 1) trace("PresentImage()\n"); + IDirect3DSurface9_GetDevice(info->lpSurf, &device); + ok(device == presenter->device, "got %p, expected %p\n", device, presenter->device); + IDirect3DDevice9_Release(device); ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie); todo_wine ok(info->dwFlags == VMR9Sample_TimeValid, "Got flags %#lx.\n", info->dwFlags); ok(!info->rtStart, "Got start time %s.\n", wine_dbgstr_longlong(info->rtStart)); @@ -3224,6 +3244,7 @@ static void test_renderless_formats(void) IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)¬ify);
hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); + presenter.device = device; if (hr == E_NOINTERFACE) { win_skip("Direct3D does not support video rendering.\n"); @@ -4307,12 +4328,11 @@ static void test_changed3ddevice(void) { VIDEOINFOHEADER vih = { + .rcSource = {4, 6, 16, 12}, + .rcTarget = {40, 60, 160, 120}, .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), - .bmiHeader.biBitCount = 32, .bmiHeader.biWidth = 32, .bmiHeader.biHeight = 16, - .bmiHeader.biPlanes = 1, - .bmiHeader.biCompression = BI_RGB, }; AM_MEDIA_TYPE req_mt = { @@ -4329,18 +4349,24 @@ static void test_changed3ddevice(void) .refcount = 1, .accept_flags = VMR9AllocFlag_TextureSurface, }; + ALLOCATOR_PROPERTIES req_props = {5, 32 * 16 * 4, 1, 0}, ret_props; IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless); + IDirect3DDevice9 *device, *device2 = NULL; IFilterGraph2 *graph = create_graph(); IVMRSurfaceAllocatorNotify9 *notify; - IDirect3DDevice9 *device, *device2; RECT rect = {0, 0, 640, 480}; struct testfilter source; + IMemAllocator *allocator; + IMediaControl *control; + IMemInputPin *input; + OAFilterState state; IPin *pin = NULL; HWND window; HRESULT hr; ULONG ref;
testfilter_init(&source); + source.mt = &req_mt;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, @@ -4360,6 +4386,7 @@ static void test_changed3ddevice(void) ok(hr == S_OK, "Got hr %#lx.\n", hr);
hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); + presenter.device = device; if (hr == E_NOINTERFACE) { win_skip("Direct3D does not support video rendering.\n"); @@ -4374,20 +4401,59 @@ static void test_changed3ddevice(void) hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input); + + hr = IMemInputPin_GetAllocator(input, &allocator); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == VFW_E_NO_ALLOCATOR) + { + CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)&allocator); + + hr = IMemInputPin_NotifyAllocator(input, allocator, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMemAllocator_Commit(allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + device2 = create_device(window); ok(device2 != NULL, "Couldn't create device\n");
- ok(presenter.got_TerminateDevice == 0, "got %d\n", presenter.got_TerminateDevice); - hr = IVMRSurfaceAllocatorNotify9_ChangeD3DDevice(notify, device2, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY)); ok(hr == S_OK, "Got hr %#lx.\n", hr); - ok(presenter.got_TerminateDevice == 1, "got %d\n", presenter.got_TerminateDevice); + presenter.device = device2; + presenter.got_PresentImage = 0; + Sleep(200); /* ChangeD3DDevice is partially asynchronous */
- IDirect3DDevice9_Release(device2); + hr = IMemAllocator_Decommit(allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMemAllocator_Commit(allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); + hr = IMediaControl_Run(control); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + join_thread(send_frame(input)); + + hr = IMediaControl_GetState(control, 100, &state); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ok(presenter.got_PresentImage >= 1, "Got %u calls to PresentImage().\n", presenter.got_PresentImage); + IMediaControl_Release(control); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IMemAllocator_Release(allocator); + IMemInputPin_Release(input); + IPin_Release(pin);
out: - if (pin) - IPin_Release(pin); ref = IFilterGraph2_Release(graph); ok(!ref, "Got outstanding refcount %ld.\n", ref); IVMRSurfaceAllocatorNotify9_Release(notify); @@ -4395,6 +4461,11 @@ out: ok(!ref, "Got outstanding refcount %ld.\n", ref); ref = IDirect3DDevice9_Release(device); ok(!ref, "Got outstanding refcount %ld.\n", ref); + if (device2) + { + ref = IDirect3DDevice9_Release(device2); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + } DestroyWindow(window); }
Found it. Native VMR9 disconnects and reconnects the pin when changing d3d device. Unfortunately, neither party remembers the media type, so they can't reconnect.
That took approximately seven forevers to figure out. It's always the smallest bugs that take the longest to track down @_@