From: Zebediah Figura zfigura@codeweavers.com
--- dlls/quartz/Makefile.in | 2 +- dlls/quartz/tests/Makefile.in | 2 +- dlls/quartz/tests/vmr7.c | 171 ++++++++++++++++++++++++++++++++++ dlls/quartz/vmr7_presenter.c | 79 +++++++++++++++- 4 files changed, 247 insertions(+), 7 deletions(-)
diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 0670ba95b48..a1859dd58a5 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -1,6 +1,6 @@ MODULE = quartz.dll IMPORTLIB = quartz -IMPORTS = strmiids dxguid strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 rpcrt4 user32 gdi32 advapi32 winmm +IMPORTS = strmiids dxguid strmbase uuid ddraw dsound msacm32 msvfw32 ole32 oleaut32 rpcrt4 user32 gdi32 advapi32 winmm
SOURCES = \ acmwrapper.c \ diff --git a/dlls/quartz/tests/Makefile.in b/dlls/quartz/tests/Makefile.in index 56a98d138c7..c3b96272fbf 100644 --- a/dlls/quartz/tests/Makefile.in +++ b/dlls/quartz/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = quartz.dll -IMPORTS = strmbase advapi32 d3d9 dsound msdmo msvfw32 ole32 oleaut32 user32 uuid winmm +IMPORTS = strmbase advapi32 d3d9 ddraw dsound msdmo msvfw32 ole32 oleaut32 user32 uuid winmm
SOURCES = \ acmwrapper.c \ diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index 50e3da462d2..fda4c6d46d8 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -3153,6 +3153,176 @@ static void test_unconnected_eos(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_default_presenter_allocate(void) +{ + IDirectDrawSurface7 *frontbuffer, *backbuffer, *backbuffer2, *backbuffer3; + IDirectDraw7 *ddraw, *prev_ddraw = NULL; + IVMRSurfaceAllocator *allocator; + VMRALLOCATIONINFO info; + DDSURFACEDESC2 desc; + HRESULT hr; + LONG ref; + + BITMAPINFOHEADER bitmap_header = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 32, + .biHeight = 16, + .biCompression = mmioFOURCC('Y','U','Y','2'), + .biBitCount = 16, + .biPlanes = 1, + }; + + static const struct + { + WORD depth; + DWORD compression; + DDPIXELFORMAT format; + } + tests[] = + { + {32, BI_RGB}, + {12, mmioFOURCC('N','V','1','2')}, + {12, mmioFOURCC('Y','V','1','2')}, + {16, mmioFOURCC('U','Y','V','Y')}, + {16, mmioFOURCC('Y','U','Y','2')}, + }; + + hr = CoCreateInstance(&CLSID_AllocPresenter, NULL, CLSCTX_INPROC_SERVER, + &IID_IVMRSurfaceAllocator, (void **)&allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IVMRSurfaceAllocator_FreeSurface(allocator, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + info.dwFlags = AMAP_DIRECTED_FLIP | AMAP_ALLOW_SYSMEM; + info.dwMinBuffers = 2; + info.dwMaxBuffers = 2; + info.dwInterlaceFlags = 0; + info.szNativeSize.cx = info.szAspectRatio.cx = 640; + info.szNativeSize.cy = info.szAspectRatio.cy = 480; + info.lpHdr = &bitmap_header; + info.lpPixFmt = NULL; + + for (unsigned int i = 0; i < ARRAY_SIZE(tests); ++i) + { + DWORD count = 2; + + winetest_push_context("Compression %#lx, depth %u", tests[i].compression, tests[i].depth); + + bitmap_header.biBitCount = tests[i].depth; + bitmap_header.biCompression = tests[i].compression; + + hr = IVMRSurfaceAllocator_AllocateSurface(allocator, 0, &info, &count, &frontbuffer); + if (hr == VFW_E_DDRAW_CAPS_NOT_SUITABLE) + { + skip("Format is not supported.\n"); + winetest_pop_context(); + continue; + } + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(count == 3, "Got count %lu.\n", count); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + hr = IDirectDrawSurface7_GetSurfaceDesc(frontbuffer, &desc); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(desc.dwFlags == (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_PIXELFORMAT), + "Got flags %#lx.\n", desc.dwFlags); + todo_wine ok(desc.ddsCaps.dwCaps == (DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN + | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP), "Got caps %#lx.\n", desc.ddsCaps.dwCaps); + ok(!desc.ddsCaps.dwCaps2, "Got caps2 %#lx.\n", desc.ddsCaps.dwCaps2); + ok(!desc.ddsCaps.dwCaps3, "Got caps2 %#lx.\n", desc.ddsCaps.dwCaps3); + ok(!desc.ddsCaps.dwCaps4, "Got caps2 %#lx.\n", desc.ddsCaps.dwCaps4); + ok(desc.dwWidth == 32, "Got width %lu.\n", desc.dwWidth); + ok(desc.dwHeight == 16, "Got height %lu.\n", desc.dwHeight); + ok(desc.ddpfPixelFormat.dwSize == sizeof(desc.ddpfPixelFormat), + "Got size %lu.\n", desc.ddpfPixelFormat.dwSize); + if (tests[i].compression) + { + ok(desc.ddpfPixelFormat.dwFlags == DDPF_FOURCC, "Got flags %#lx.\n", desc.ddpfPixelFormat.dwFlags); + ok(desc.ddpfPixelFormat.dwFourCC == bitmap_header.biCompression, + "Got fourcc %08lx.\n", desc.ddpfPixelFormat.dwFourCC); + } + else + { + ok(desc.ddpfPixelFormat.dwFlags == DDPF_RGB, "Got flags %#lx.\n", desc.ddpfPixelFormat.dwFlags); + ok(desc.ddpfPixelFormat.dwRGBBitCount == 32, "Got depth %lu.\n", desc.ddpfPixelFormat.dwRGBBitCount); + ok(desc.ddpfPixelFormat.dwRBitMask == 0x00ff0000, "Got red mask %#lx.\n", desc.ddpfPixelFormat.dwRBitMask); + ok(desc.ddpfPixelFormat.dwGBitMask == 0x0000ff00, "Got green mask %#lx.\n", desc.ddpfPixelFormat.dwGBitMask); + ok(desc.ddpfPixelFormat.dwBBitMask == 0x000000ff, "Got blue mask %#lx.\n", desc.ddpfPixelFormat.dwBBitMask); + } + + desc.ddsCaps.dwCaps = DDSCAPS_FLIP; + hr = IDirectDrawSurface7_GetAttachedSurface(frontbuffer, &desc.ddsCaps, &backbuffer); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + hr = IDirectDrawSurface7_GetSurfaceDesc(backbuffer, &desc); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(desc.dwFlags == (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_PIXELFORMAT), + "Got flags %#lx.\n", desc.dwFlags); + todo_wine ok(desc.ddsCaps.dwCaps == (DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN + | DDSCAPS_BACKBUFFER | DDSCAPS_FLIP), "Got caps %#lx.\n", desc.ddsCaps.dwCaps); + + desc.ddsCaps.dwCaps = DDSCAPS_FLIP; + hr = IDirectDrawSurface7_GetAttachedSurface(backbuffer, &desc.ddsCaps, &backbuffer2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + hr = IDirectDrawSurface7_GetSurfaceDesc(backbuffer2, &desc); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + todo_wine ok(desc.dwFlags == (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_PIXELFORMAT), + "Got flags %#lx.\n", desc.dwFlags); + todo_wine ok(desc.ddsCaps.dwCaps == (DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN + | DDSCAPS_FLIP), "Got caps %#lx.\n", desc.ddsCaps.dwCaps); + + desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; + hr = IDirectDrawSurface7_GetAttachedSurface(backbuffer2, &desc.ddsCaps, &backbuffer3); + todo_wine_if (tests[i].compression) ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(backbuffer3 == frontbuffer, "Expected only 2 backbuffers.\n"); + IDirectDrawSurface7_Release(backbuffer3); + } + + IDirectDrawSurface7_Release(backbuffer2); + IDirectDrawSurface7_Release(backbuffer); + + hr = IDirectDrawSurface7_GetDDInterface(frontbuffer, (void **)&ddraw); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (prev_ddraw) + { + ok(ddraw == prev_ddraw, "Expected the same ddraw object.\n"); + IDirectDraw7_Release(ddraw); + } + else + { + prev_ddraw = ddraw; + } + + /* AllocateSurface does *not* give the application a reference to the + * surface. */ + + IDirectDrawSurface7_AddRef(frontbuffer); + + hr = IVMRSurfaceAllocator_FreeSurface(allocator, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ref = IDirectDrawSurface7_Release(frontbuffer); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + + winetest_pop_context(); + } + + ref = IVMRSurfaceAllocator_Release(allocator); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IDirectDraw7_Release(prev_ddraw); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + START_TEST(vmr7) { CoInitialize(NULL); @@ -3172,6 +3342,7 @@ START_TEST(vmr7) test_basic_video(); test_windowless_size(); test_unconnected_eos(); + test_default_presenter_allocate();
CoUninitialize(); } diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index 222e6db6048..78d97bd5e10 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -30,6 +30,9 @@ struct vmr7_presenter IVMRSurfaceAllocator IVMRSurfaceAllocator_iface; IVMRWindowlessControl IVMRWindowlessControl_iface; LONG refcount; + + IDirectDraw7 *ddraw; + IDirectDrawSurface7 *frontbuffer; };
static struct vmr7_presenter *impl_from_IVMRImagePresenter(IVMRImagePresenter *iface) @@ -76,7 +79,12 @@ static ULONG WINAPI image_presenter_Release(IVMRImagePresenter *iface)
TRACE("%p decreasing refcount to %lu.\n", presenter, refcount); if (!refcount) + { + if (presenter->frontbuffer) + IDirectDrawSurface7_Release(presenter->frontbuffer); + IDirectDraw7_Release(presenter->ddraw); free(presenter); + } return refcount; }
@@ -136,16 +144,66 @@ static ULONG WINAPI surface_allocator_Release(IVMRSurfaceAllocator *iface) }
static HRESULT WINAPI surface_allocator_AllocateSurface(IVMRSurfaceAllocator *iface, - DWORD_PTR id, VMRALLOCATIONINFO *info, DWORD *count, IDirectDrawSurface7 **surfaces) + DWORD_PTR id, VMRALLOCATIONINFO *info, DWORD *count, IDirectDrawSurface7 **surface) { - FIXME("iface %p, id %#Ix, info %p, count %p, surfaces %p, stub!\n", iface, id, info, count, surfaces); - return E_NOTIMPL; + struct vmr7_presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + DDSURFACEDESC2 surface_desc = {.dwSize = sizeof(surface_desc)}; + HRESULT hr; + + TRACE("presenter %p, id %#Ix, info %p, count %p, surface %p.\n", presenter, id, info, count, surface); + + surface_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + surface_desc.dwWidth = info->lpHdr->biWidth; + surface_desc.dwHeight = info->lpHdr->biHeight; + surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat); + surface_desc.ddsCaps.dwCaps = DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwBackBufferCount = *count; + + if (info->lpHdr->biCompression == BI_RGB) + { + if (info->lpHdr->biBitCount != 32) + { + FIXME("Unhandled bit depth %u.\n", info->lpHdr->biBitCount); + return E_NOTIMPL; + } + + surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; + surface_desc.ddpfPixelFormat.dwRGBBitCount = 32; + surface_desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000; + surface_desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00; + surface_desc.ddpfPixelFormat.dwBBitMask = 0x000000ff; + } + else + { + surface_desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC; + surface_desc.ddpfPixelFormat.dwFourCC = info->lpHdr->biCompression; + } + + if (FAILED(hr = IDirectDraw7_CreateSurface(presenter->ddraw, + &surface_desc, &presenter->frontbuffer, NULL))) + { + WARN("Failed to create surface, hr %#lx.\n", hr); + return hr; + } + *surface = presenter->frontbuffer; + ++*count; + return S_OK; }
static HRESULT WINAPI surface_allocator_FreeSurface(IVMRSurfaceAllocator *iface, DWORD_PTR id) { - FIXME("iface %p, id %#Ix, stub!\n", iface, id); - return E_NOTIMPL; + struct vmr7_presenter *presenter = impl_from_IVMRSurfaceAllocator(iface); + DDSURFACEDESC2 surface_desc = {.dwSize = sizeof(surface_desc)}; + + TRACE("presenter %p, id %#Ix.\n", presenter, id); + + if (presenter->frontbuffer) + { + IDirectDrawSurface7_Release(presenter->frontbuffer); + presenter->frontbuffer = NULL; + } + + return S_OK; }
static HRESULT WINAPI surface_allocator_PrepareSurface(IVMRSurfaceAllocator *iface, @@ -324,6 +382,7 @@ static const IVMRWindowlessControlVtbl windowless_control_vtbl = HRESULT vmr7_presenter_create(IUnknown *outer, IUnknown **out) { struct vmr7_presenter *object; + HRESULT hr;
TRACE("outer %p, out %p.\n", outer, out);
@@ -337,6 +396,16 @@ HRESULT vmr7_presenter_create(IUnknown *outer, IUnknown **out) object->IVMRWindowlessControl_iface.lpVtbl = &windowless_control_vtbl; object->refcount = 1;
+ if (FAILED(hr = DirectDrawCreateEx(NULL, (void **)&object->ddraw, &IID_IDirectDraw7, NULL))) + { + ERR("Failed to create ddraw object, hr %#lx.\n", hr); + free(object); + return hr; + } + + if (FAILED(hr = IDirectDraw7_SetCooperativeLevel(object->ddraw, NULL, DDSCL_NORMAL))) + ERR("Failed to set cooperative level, hr %#lx.\n", hr); + TRACE("Created VMR7 default presenter %p.\n", object); *out = (IUnknown *)&object->IVMRSurfaceAllocator_iface; return S_OK;