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

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47161
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2020-07-23 19:30:16 -05:00 committed by Alexandre Julliard
parent 41a9f82870
commit 1ce2cae3e9
2 changed files with 109 additions and 44 deletions

View File

@ -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);
test_renderless_present(graph, input);
ok(presenter.format == tests[i].format, "Test %u: Got format %u (%#x).\n",
i, presenter.format, presenter.format);
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);

View File

@ -1982,20 +1982,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;
}