Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr9.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 54e9b53afb1..4994829641b 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -2769,7 +2769,7 @@ static D3DFORMAT allocator_format; static DWORD allocator_accept_flags; static IDirect3DSurface9 *allocator_surfaces[5]; static IVMRSurfaceAllocatorNotify9 *allocator_notify; -static unsigned int allocator_got_PresentImage; +static unsigned int allocator_got_PresentImage, allocator_got_TerminateDevice;
static HRESULT WINAPI presenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID iid, void **out) { @@ -2882,6 +2882,7 @@ static HRESULT WINAPI allocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DW 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; return E_NOTIMPL; }
@@ -3253,6 +3254,32 @@ static void test_clipping_window(void) DestroyWindow(window); }
+static void test_surface_allocator_notify_refcount(void) +{ + 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 **)¬ify); + + hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &allocator_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ref = IBaseFilter_Release(filter); + todo_wine ok(!ref, "Got outstanding refcount %d.\n", ref); + todo_wine ok(allocator_got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n", + allocator_got_TerminateDevice); + todo_wine ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_refcount); + + ref = IVMRSurfaceAllocatorNotify9_Release(notify); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(vmr9) { IBaseFilter *filter; @@ -3284,6 +3311,7 @@ START_TEST(vmr9) test_renderless_formats(); test_mixing_mode(); test_clipping_window(); + test_surface_allocator_notify_refcount();
CoUninitialize(); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr9.c | 4 ++-- dlls/quartz/vmr9.c | 41 +++++++++++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 4994829641b..c0fb6a6f34a 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -3271,10 +3271,10 @@ static void test_surface_allocator_notify_refcount(void) ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IBaseFilter_Release(filter); - todo_wine ok(!ref, "Got outstanding refcount %d.\n", ref); + ok(!ref, "Got outstanding refcount %d.\n", ref); todo_wine ok(allocator_got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n", allocator_got_TerminateDevice); - todo_wine ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_refcount); + ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_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 93fc3417e7f..a8f88e3d04b 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -56,6 +56,12 @@ struct quartz_vmr IVMRWindowlessControl IVMRWindowlessControl_iface; IVMRWindowlessControl9 IVMRWindowlessControl9_iface;
+ /* Devil May Cry 3 releases the last IBaseFilter reference while still + * holding an IVMRSurfaceAllocatorNotify9 reference, and depends on + * IVMRSurfaceAllocator9::TerminateDevice() being called as a result. + * Native uses a separate reference count for IVMRSurfaceAllocatorNotify9. */ + LONG IVMRSurfaceAllocatorNotify9_refcount; + IOverlay IOverlay_iface;
IVMRSurfaceAllocatorEx9 *allocator; @@ -571,12 +577,23 @@ static HRESULT WINAPI VMR9_BreakConnect(struct strmbase_renderer *This) return hr; }
+static void vmr_free(struct quartz_vmr *filter) +{ + free(filter); + InterlockedDecrement(&object_locks); +} + static void vmr_destroy(struct strmbase_renderer *iface) { struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface);
video_window_cleanup(&filter->baseControlWindow);
+ /* Devil May Cry 3 releases the IVMRSurfaceAllocatorNotify9 interface from + * TerminateDevice(). Artificially increase the reference count so that we + * don't free the filter yet. */ + InterlockedIncrement(&filter->renderer.filter.refcount); + if (filter->allocator) IVMRSurfaceAllocatorEx9_Release(filter->allocator); if (filter->presenter) @@ -592,9 +609,8 @@ static void vmr_destroy(struct strmbase_renderer *iface) CloseHandle(filter->run_event); FreeLibrary(filter->hD3d9); strmbase_renderer_cleanup(&filter->renderer); - free(filter); - - InterlockedDecrement(&object_locks); + if (!filter->IVMRSurfaceAllocatorNotify9_refcount) + vmr_free(filter); }
static HRESULT vmr_query_interface(struct strmbase_renderer *iface, REFIID iid, void **out) @@ -2044,14 +2060,25 @@ static HRESULT WINAPI VMR9SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAlloc
static ULONG WINAPI VMR9SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify9 *iface) { - struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface); - return IUnknown_AddRef(This->renderer.filter.outer_unk); + struct quartz_vmr *filter = impl_from_IVMRSurfaceAllocatorNotify9(iface); + ULONG refcount = InterlockedIncrement(&filter->IVMRSurfaceAllocatorNotify9_refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; }
static ULONG WINAPI VMR9SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify9 *iface) { - struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface); - return IUnknown_Release(This->renderer.filter.outer_unk); + struct quartz_vmr *filter = impl_from_IVMRSurfaceAllocatorNotify9(iface); + ULONG refcount = InterlockedDecrement(&filter->IVMRSurfaceAllocatorNotify9_refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount && !filter->renderer.filter.refcount) + vmr_free(filter); + + return refcount; }
static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator(IVMRSurfaceAllocatorNotify9 *iface, DWORD_PTR id, IVMRSurfaceAllocator9 *alloc)
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr9.c | 2 +- dlls/quartz/vmr9.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index c0fb6a6f34a..5c08868fc09 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -3272,7 +3272,7 @@ static void test_surface_allocator_notify_refcount(void)
ref = IBaseFilter_Release(filter); ok(!ref, "Got outstanding refcount %d.\n", ref); - todo_wine ok(allocator_got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n", + 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);
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index a8f88e3d04b..4fd3e70b96d 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -595,7 +595,10 @@ static void vmr_destroy(struct strmbase_renderer *iface) InterlockedIncrement(&filter->renderer.filter.refcount);
if (filter->allocator) + { + IVMRSurfaceAllocatorEx9_TerminateDevice(filter->allocator, filter->cookie); IVMRSurfaceAllocatorEx9_Release(filter->allocator); + } if (filter->presenter) IVMRImagePresenter9_Release(filter->presenter);
Needed by Sniper Fury and Modern Combat 5.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr9.c | 2 +- dlls/quartz/vmr9.c | 67 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 5c08868fc09..189b7d4f892 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -231,7 +231,7 @@ static void test_common_interfaces(IBaseFilter *filter) todo_wine check_interface(filter, &IID_IVMRAspectRatioControl9, TRUE); todo_wine check_interface(filter, &IID_IVMRDeinterlaceControl9, TRUE); check_interface(filter, &IID_IVMRFilterConfig9, TRUE); - todo_wine check_interface(filter, &IID_IVMRMixerBitmap9, TRUE); + check_interface(filter, &IID_IVMRMixerBitmap9, TRUE);
check_interface(filter, &IID_IBasicAudio, FALSE); check_interface(filter, &IID_IDirectDrawVideo, FALSE); diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 4fd3e70b96d..8ef8fc07e3e 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -39,6 +39,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+static inline const char *debugstr_normalized_rect(const VMR9NormalizedRect *rect) +{ + if (!rect) return "(null)"; + return wine_dbg_sprintf("(%.8e,%.8e)-(%.8e,%.8e)", rect->left, rect->top, rect->right, rect->bottom); +} + struct quartz_vmr { struct strmbase_renderer renderer; @@ -49,6 +55,7 @@ struct quartz_vmr IAMFilterMiscFlags IAMFilterMiscFlags_iface; IVMRFilterConfig IVMRFilterConfig_iface; IVMRFilterConfig9 IVMRFilterConfig9_iface; + IVMRMixerBitmap9 IVMRMixerBitmap9_iface; IVMRMonitorConfig IVMRMonitorConfig_iface; IVMRMonitorConfig9 IVMRMonitorConfig9_iface; IVMRSurfaceAllocatorNotify IVMRSurfaceAllocatorNotify_iface; @@ -632,6 +639,8 @@ static HRESULT vmr_query_interface(struct strmbase_renderer *iface, REFIID iid, *out = &filter->IVMRFilterConfig_iface; else if (IsEqualGUID(iid, &IID_IVMRFilterConfig9)) *out = &filter->IVMRFilterConfig9_iface; + else if (IsEqualGUID(iid, &IID_IVMRMixerBitmap9) && is_vmr9(filter)) + *out = &filter->IVMRMixerBitmap9_iface; else if (IsEqualGUID(iid, &IID_IVMRMonitorConfig)) *out = &filter->IVMRMonitorConfig_iface; else if (IsEqualGUID(iid, &IID_IVMRMonitorConfig9)) @@ -2254,6 +2263,63 @@ static const IVMRSurfaceAllocatorNotify9Vtbl VMR9_SurfaceAllocatorNotify_Vtbl = VMR9SurfaceAllocatorNotify_NotifyEvent };
+static inline struct quartz_vmr *impl_from_IVMRMixerBitmap9(IVMRMixerBitmap9 *iface) +{ + return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRMixerBitmap9_iface); +} + +static HRESULT WINAPI mixer_bitmap9_QueryInterface(IVMRMixerBitmap9 *iface, REFIID iid, void **out) +{ + struct quartz_vmr *filter = impl_from_IVMRMixerBitmap9(iface); + return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, iid, out); +} + +static ULONG WINAPI mixer_bitmap9_AddRef(IVMRMixerBitmap9 *iface) +{ + struct quartz_vmr *filter = impl_from_IVMRMixerBitmap9(iface); + return IUnknown_AddRef(filter->renderer.filter.outer_unk); +} + +static ULONG WINAPI mixer_bitmap9_Release(IVMRMixerBitmap9 *iface) +{ + struct quartz_vmr *filter = impl_from_IVMRMixerBitmap9(iface); + return IUnknown_Release(filter->renderer.filter.outer_unk); +} + +static HRESULT WINAPI mixer_bitmap9_SetAlphaBitmap(IVMRMixerBitmap9 *iface, + const VMR9AlphaBitmap *bitmap) +{ + FIXME("iface %p, bitmap %p, stub!\n", iface, bitmap); + TRACE("dwFlags %#x, hdc %p, pDDS %p, rSrc %s, rDest %s, fAlpha %.8e, clrSrcKey #%06x, dwFilterMode %#x.\n", + bitmap->dwFlags, bitmap->hdc, bitmap->pDDS, wine_dbgstr_rect(&bitmap->rSrc), + debugstr_normalized_rect(&bitmap->rDest), bitmap->fAlpha, bitmap->clrSrcKey, bitmap->dwFilterMode); + return E_NOTIMPL; +} + +static HRESULT WINAPI mixer_bitmap9_UpdateAlphaBitmapParameters(IVMRMixerBitmap9 *iface, + const VMR9AlphaBitmap *bitmap) +{ + FIXME("iface %p, bitmap %p, stub!\n", iface, bitmap); + return E_NOTIMPL; +} + +static HRESULT WINAPI mixer_bitmap9_GetAlphaBitmapParameters(IVMRMixerBitmap9 *iface, + VMR9AlphaBitmap *bitmap) +{ + FIXME("iface %p, bitmap %p, stub!\n", iface, bitmap); + return E_NOTIMPL; +} + +static const IVMRMixerBitmap9Vtbl mixer_bitmap9_vtbl = +{ + mixer_bitmap9_QueryInterface, + mixer_bitmap9_AddRef, + mixer_bitmap9_Release, + mixer_bitmap9_SetAlphaBitmap, + mixer_bitmap9_UpdateAlphaBitmapParameters, + mixer_bitmap9_GetAlphaBitmapParameters, +}; + static inline struct quartz_vmr *impl_from_IOverlay(IOverlay *iface) { return CONTAINING_RECORD(iface, struct quartz_vmr, IOverlay_iface); @@ -2379,6 +2445,7 @@ static HRESULT vmr_create(IUnknown *outer, IUnknown **out, const CLSID *clsid) object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl; object->IVMRFilterConfig_iface.lpVtbl = &VMR7_FilterConfig_Vtbl; object->IVMRFilterConfig9_iface.lpVtbl = &VMR9_FilterConfig_Vtbl; + object->IVMRMixerBitmap9_iface.lpVtbl = &mixer_bitmap9_vtbl; object->IVMRMonitorConfig_iface.lpVtbl = &VMR7_MonitorConfig_Vtbl; object->IVMRMonitorConfig9_iface.lpVtbl = &VMR9_MonitorConfig_Vtbl; object->IVMRSurfaceAllocatorNotify_iface.lpVtbl = &VMR7_SurfaceAllocatorNotify_Vtbl;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=71138
Your paranoid android.
=== w1064v1809 (32 bit report) ===
quartz: vmr9.c:2342: Test failed: Got unexpected status 0. vmr9.c:2345: Test failed: Wait timed out. vmr9.c:2353: Test failed: Got unexpected status 0x400040.