[PATCH] quartz/vmr9: Allow AdviseSurfaceAllocator() to be called multiple times.

Zebediah Figura z.figura12 at gmail.com
Thu Jul 23 19:30:16 CDT 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47161
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/quartz/tests/vmr9.c | 132 ++++++++++++++++++++++++++-------------
 dlls/quartz/vmr9.c       |  21 ++++++-
 2 files changed, 109 insertions(+), 44 deletions(-)

diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c
index d7065280de..c8b35c266d 100644
--- a/dlls/quartz/tests/vmr9.c
+++ b/dlls/quartz/tests/vmr9.c
@@ -2776,28 +2776,40 @@ out:
     DestroyWindow(window);
 }
 
-static IVMRSurfaceAllocator9 allocator_iface;
-static IVMRImagePresenter9 presenter_iface;
-static LONG allocator_refcount = 1;
-static D3DFORMAT allocator_format;
-static DWORD allocator_accept_flags;
-static IDirect3DSurface9 *allocator_surfaces[5];
-static IVMRSurfaceAllocatorNotify9 *allocator_notify;
-static unsigned int allocator_got_PresentImage, allocator_got_TerminateDevice;
+struct presenter
+{
+    IVMRSurfaceAllocator9 IVMRSurfaceAllocator9_iface;
+    IVMRImagePresenter9 IVMRImagePresenter9_iface;
+    LONG refcount;
+
+    D3DFORMAT format;
+    DWORD accept_flags;
+    IDirect3DSurface9 *surfaces[5];
+    IVMRSurfaceAllocatorNotify9 *notify;
+    unsigned int got_PresentImage, got_TerminateDevice;
+};
+
+static struct presenter *impl_from_IVMRImagePresenter9(IVMRImagePresenter9 *iface)
+{
+    return CONTAINING_RECORD(iface, struct presenter, IVMRImagePresenter9_iface);
+}
 
 static HRESULT WINAPI presenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID iid, void **out)
 {
-    return IVMRSurfaceAllocator9_QueryInterface(&allocator_iface, iid, out);
+    struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
+    return IVMRSurfaceAllocator9_QueryInterface(&presenter->IVMRSurfaceAllocator9_iface, iid, out);
 }
 
 static ULONG WINAPI presenter_AddRef(IVMRImagePresenter9 *iface)
 {
-    return IVMRSurfaceAllocator9_AddRef(&allocator_iface);
+    struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
+    return IVMRSurfaceAllocator9_AddRef(&presenter->IVMRSurfaceAllocator9_iface);
 }
 
 static ULONG WINAPI presenter_Release(IVMRImagePresenter9 *iface)
 {
-    return IVMRSurfaceAllocator9_Release(&allocator_iface);
+    struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
+    return IVMRSurfaceAllocator9_Release(&presenter->IVMRSurfaceAllocator9_iface);
 }
 
 static HRESULT WINAPI presenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie)
@@ -2816,7 +2828,9 @@ 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);
     static const RECT rect;
+
     if (winetest_debug > 1) trace("PresentImage()\n");
     ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
     todo_wine ok(info->dwFlags == VMR9Sample_TimeValid, "Got flags %#x.\n", info->dwFlags);
@@ -2829,7 +2843,7 @@ static HRESULT WINAPI presenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_P
     ok(!info->dwReserved1, "Got dwReserved1 %#x.\n", info->dwReserved1);
     ok(!info->dwReserved2, "Got dwReserved2 %#x.\n", info->dwReserved2);
 
-    ++allocator_got_PresentImage;
+    ++presenter->got_PresentImage;
     return S_OK;
 }
 
@@ -2843,14 +2857,21 @@ static const IVMRImagePresenter9Vtbl presenter_vtbl =
     presenter_PresentImage,
 };
 
+static struct presenter *impl_from_IVMRSurfaceAllocator9(IVMRSurfaceAllocator9 *iface)
+{
+    return CONTAINING_RECORD(iface, struct presenter, IVMRSurfaceAllocator9_iface);
+}
+
 static HRESULT WINAPI allocator_QueryInterface(IVMRSurfaceAllocator9 *iface, REFIID iid, void **out)
 {
+    struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
+
     if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid));
 
     if (IsEqualGUID(iid, &IID_IVMRImagePresenter9))
     {
-        *out = &presenter_iface;
-        IVMRImagePresenter9_AddRef(&presenter_iface);
+        *out = &presenter->IVMRImagePresenter9_iface;
+        IVMRImagePresenter9_AddRef(&presenter->IVMRImagePresenter9_iface);
         return S_OK;
     }
     ok(!IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorEx9), "Unexpected query for IVMRSurfaceAllocatorEx9.\n");
@@ -2860,17 +2881,21 @@ static HRESULT WINAPI allocator_QueryInterface(IVMRSurfaceAllocator9 *iface, REF
 
 static ULONG WINAPI allocator_AddRef(IVMRSurfaceAllocator9 *iface)
 {
-    return InterlockedIncrement(&allocator_refcount);
+    struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
+    return InterlockedIncrement(&presenter->refcount);
 }
 
 static ULONG WINAPI allocator_Release(IVMRSurfaceAllocator9 *iface)
 {
-    return InterlockedDecrement(&allocator_refcount);
+    struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
+    return InterlockedDecrement(&presenter->refcount);
 }
 
 static HRESULT WINAPI allocator_InitializeDevice(IVMRSurfaceAllocator9 *iface,
         DWORD_PTR cookie, VMR9AllocationInfo *info, DWORD *buffer_count)
 {
+    struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
+
     if (winetest_debug > 1) trace("InitializeDevice(flags %#x, format %u)\n",
             info->dwFlags, info->Format);
     ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
@@ -2884,33 +2909,37 @@ static HRESULT WINAPI allocator_InitializeDevice(IVMRSurfaceAllocator9 *iface,
     ok(info->szNativeSize.cy == 16, "Got native height %d.\n", info->szNativeSize.cy);
     todo_wine ok(*buffer_count == 5, "Got buffer count %u.\n", *buffer_count);
 
-    allocator_format = info->Format;
+    presenter->format = info->Format;
 
-    if (info->dwFlags != allocator_accept_flags)
+    if (info->dwFlags != presenter->accept_flags)
         return 0xdeadbeef;
-    return IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(allocator_notify,
-            info, buffer_count, allocator_surfaces);
+    return IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(presenter->notify,
+            info, buffer_count, presenter->surfaces);
 }
 
 static HRESULT WINAPI allocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie)
 {
+    struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
+
     if (winetest_debug > 1) trace("TerminateDevice()\n");
     ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
     /* Don't dereference the surfaces here, to mimic How to Survive. */
-    ++allocator_got_TerminateDevice;
+    ++presenter->got_TerminateDevice;
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI allocator_GetSurface(IVMRSurfaceAllocator9 *iface,
         DWORD_PTR cookie, DWORD index, DWORD flags, IDirect3DSurface9 **surface)
 {
+    struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
+
     if (winetest_debug > 1) trace("GetSurface(index %u)\n", index);
     ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
     ok(!flags, "Got flags %#x.\n", flags);
     ok(index < 5, "Got index %u.\n", index);
 
     /* Don't reference the surface here, to mimic How to Survive. */
-    *surface = allocator_surfaces[index];
+    *surface = presenter->surfaces[index];
     return S_OK;
 }
 
@@ -2931,10 +2960,8 @@ static const IVMRSurfaceAllocator9Vtbl allocator_vtbl =
     allocator_AdviseNotify,
 };
 
-static IVMRSurfaceAllocator9 allocator_iface = {&allocator_vtbl};
-static IVMRImagePresenter9 presenter_iface = {&presenter_vtbl};
-
-static void test_renderless_present(IFilterGraph2 *graph, IMemInputPin *input)
+static void test_renderless_present(struct presenter *presenter,
+        IFilterGraph2 *graph, IMemInputPin *input)
 {
     IMediaControl *control;
     OAFilterState state;
@@ -2943,7 +2970,7 @@ static void test_renderless_present(IFilterGraph2 *graph, IMemInputPin *input)
 
     IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
 
-    allocator_got_PresentImage = 0;
+    presenter->got_PresentImage = 0;
 
     hr = IMediaControl_Pause(control);
     ok(hr == S_FALSE, "Got hr %#x.\n", hr);
@@ -2954,13 +2981,13 @@ static void test_renderless_present(IFilterGraph2 *graph, IMemInputPin *input)
      * IMediaControl::Run() from a stopped state and expects that
      * IMediaControl::GetState() returns S_OK only after PresentImage() has
      * been called. */
-    ok(allocator_got_PresentImage == 1, "Got %u calls to PresentImage().\n", allocator_got_PresentImage);
+    ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage);
 
     hr = IMediaControl_Run(control);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
     hr = join_thread(thread);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
-    ok(allocator_got_PresentImage == 1, "Got %u calls to PresentImage().\n", allocator_got_PresentImage);
+    ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage);
 
     hr = IMediaControl_Stop(control);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
@@ -2986,6 +3013,13 @@ static void test_renderless_formats(void)
         .pbFormat = (BYTE *)&vih,
     };
     ALLOCATOR_PROPERTIES req_props = {5, 32 * 16 * 4, 1, 0}, ret_props;
+    struct presenter presenter =
+    {
+        .IVMRSurfaceAllocator9_iface.lpVtbl = &allocator_vtbl,
+        .IVMRImagePresenter9_iface.lpVtbl = &presenter_vtbl,
+        .refcount = 1,
+    };
+    struct presenter presenter2 = presenter;
     IVMRSurfaceAllocatorNotify9 *notify;
     RECT rect = {0, 0, 640, 480};
     struct testfilter source;
@@ -3047,10 +3081,11 @@ static void test_renderless_formats(void)
     }
     ok(hr == S_OK, "Got hr %#x.\n", hr);
 
-    hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &allocator_iface);
+    hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
+            &presenter.IVMRSurfaceAllocator9_iface);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
 
-    allocator_notify = notify;
+    presenter.notify = notify;
 
     testfilter_init(&source);
     graph = create_graph();
@@ -3062,7 +3097,7 @@ static void test_renderless_formats(void)
     for (i = 0; i < ARRAY_SIZE(tests); ++i)
     {
         req_mt.subtype = *tests[i].subtype;
-        allocator_accept_flags = tests[i].flags;
+        presenter.accept_flags = tests[i].flags;
 
         hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
         /* Connection never fails on Native, but Wine currently creates D3D
@@ -3100,10 +3135,14 @@ static void test_renderless_formats(void)
         hr = IMemAllocator_Commit(allocator);
         ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
 
-        ok(allocator_format == tests[i].format, "Test %u: Got format %u (%#x).\n",
-                i, allocator_format, allocator_format);
+        hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
+                &presenter2.IVMRSurfaceAllocator9_iface);
+        ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
+
+        ok(presenter.format == tests[i].format, "Test %u: Got format %u (%#x).\n",
+                i, presenter.format, presenter.format);
 
-        test_renderless_present(graph, input);
+        test_renderless_present(&presenter, graph, input);
 
         hr = IMemAllocator_Decommit(allocator);
         ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
@@ -3115,6 +3154,9 @@ static void test_renderless_formats(void)
         ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
     }
 
+    hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &presenter2.IVMRSurfaceAllocator9_iface);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
     ref = IFilterGraph2_Release(graph);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
     IMemInputPin_Release(input);
@@ -3124,7 +3166,8 @@ out:
     IVMRSurfaceAllocatorNotify9_Release(notify);
     ref = IBaseFilter_Release(filter);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
-    ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_refcount);
+    ok(presenter.refcount == 1, "Got outstanding refcount %d.\n", presenter.refcount);
+    ok(presenter2.refcount == 1, "Got outstanding refcount %d.\n", presenter2.refcount);
     ref = IDirect3DDevice9_Release(device);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
     DestroyWindow(window);
@@ -3279,25 +3322,30 @@ static void test_clipping_window(void)
 
 static void test_surface_allocator_notify_refcount(void)
 {
+    struct presenter presenter =
+    {
+        .IVMRSurfaceAllocator9_iface.lpVtbl = &allocator_vtbl,
+        .IVMRImagePresenter9_iface.lpVtbl = &presenter_vtbl,
+        .refcount = 1,
+    };
     IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
     IVMRSurfaceAllocatorNotify9 *notify;
     HRESULT hr;
     ULONG ref;
 
-    allocator_got_TerminateDevice = 0;
-
     set_mixing_mode(filter, 2);
 
     IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
 
-    hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &allocator_iface);
+    hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
+            &presenter.IVMRSurfaceAllocator9_iface);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
 
     ref = IBaseFilter_Release(filter);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
-    ok(allocator_got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n",
-            allocator_got_TerminateDevice);
-    ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_refcount);
+    ok(presenter.got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n",
+            presenter.got_TerminateDevice);
+    ok(presenter.refcount == 1, "Got outstanding refcount %d.\n", presenter.refcount);
 
     ref = IVMRSurfaceAllocatorNotify9_Release(notify);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c
index 5557a98b29..3b42dd0ed5 100644
--- a/dlls/quartz/vmr9.c
+++ b/dlls/quartz/vmr9.c
@@ -1985,20 +1985,37 @@ static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator(
         IVMRSurfaceAllocatorNotify9 *iface, DWORD_PTR cookie, IVMRSurfaceAllocator9 *allocator)
 {
     struct quartz_vmr *filter = impl_from_IVMRSurfaceAllocatorNotify9(iface);
+    IVMRImagePresenter9 *presenter;
 
     TRACE("filter %p, cookie %#Ix, allocator %p.\n", filter, cookie, allocator);
 
+    EnterCriticalSection(&filter->renderer.filter.csFilter);
+
     filter->cookie = cookie;
 
-    if (filter->presenter)
+    if (filter->renderer.sink.pin.peer)
+    {
+        LeaveCriticalSection(&filter->renderer.filter.csFilter);
+        WARN("Attempt to set allocator while connected; returning VFW_E_WRONG_STATE.\n");
         return VFW_E_WRONG_STATE;
+    }
 
-    if (FAILED(IVMRSurfaceAllocator9_QueryInterface(allocator, &IID_IVMRImagePresenter9, (void **)&filter->presenter)))
+    if (FAILED(IVMRSurfaceAllocator9_QueryInterface(allocator, &IID_IVMRImagePresenter9, (void **)&presenter)))
+    {
+        LeaveCriticalSection(&filter->renderer.filter.csFilter);
         return E_NOINTERFACE;
+    }
 
+    if (filter->allocator)
+    {
+        IVMRImagePresenter9_Release(filter->presenter);
+        IVMRSurfaceAllocator9_Release(filter->allocator);
+    }
     filter->allocator = allocator;
+    filter->presenter = presenter;
     IVMRSurfaceAllocator9_AddRef(allocator);
 
+    LeaveCriticalSection(&filter->renderer.filter.csFilter);
     return S_OK;
 }
 
-- 
2.27.0




More information about the wine-devel mailing list