[PATCH 0/9] MR9520: VMR7 fixes
For Resident Evil 2 Classic. These are relatively small and simple patches, but I can certainly cut at 5 or so for the first part. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Henri Verbeet <hverbeet(a)locutus.nl> --- dlls/quartz/vmr7.c | 2 +- dlls/quartz/vmr7_presenter.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/quartz/vmr7.c b/dlls/quartz/vmr7.c index 83f8b1d62d3..4263e79d54f 100644 --- a/dlls/quartz/vmr7.c +++ b/dlls/quartz/vmr7.c @@ -255,7 +255,7 @@ static HRESULT vmr_render(struct strmbase_renderer *iface, IMediaSample *sample) copy_plane(&dst, surface_desc.lPitch / 2, surface_desc.dwHeight / 2, &src, src_pitch / 2, height / 2); copy_plane(&dst, surface_desc.lPitch / 2, surface_desc.dwHeight / 2, &src, src_pitch / 2, height / 2); } - else if (height > 0 && bitmap_header->biCompression == BI_RGB) + else if (height > 0 && (bitmap_header->biCompression == BI_RGB || bitmap_header->biCompression == BI_BITFIELDS)) { BYTE *dst = surface_desc.lpSurface; const BYTE *src = data; diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index c244c86236a..90a0b906610 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -201,6 +201,16 @@ static HRESULT WINAPI surface_allocator_AllocateSurface(IVMRSurfaceAllocator *if surface_desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00; surface_desc.ddpfPixelFormat.dwBBitMask = 0x000000ff; } + else if (info->lpHdr->biCompression == BI_BITFIELDS) + { + const DWORD *mask = (DWORD *)((BITMAPINFO *)info->lpHdr)->bmiColors; + + surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; + surface_desc.ddpfPixelFormat.dwRGBBitCount = info->lpHdr->biBitCount; + surface_desc.ddpfPixelFormat.dwRBitMask = mask[0]; + surface_desc.ddpfPixelFormat.dwGBitMask = mask[1]; + surface_desc.ddpfPixelFormat.dwBBitMask = mask[2]; + } else { surface_desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Henri Verbeet <hverbeet(a)locutus.nl> --- dlls/quartz/vmr7_presenter.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index 90a0b906610..bbfca8ec695 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -189,6 +189,14 @@ static HRESULT WINAPI surface_allocator_AllocateSurface(IVMRSurfaceAllocator *if if (info->lpHdr->biCompression == BI_RGB) { + DDSURFACEDESC2 primary_desc; + + primary_desc.dwSize = sizeof(primary_desc); + if (FAILED(hr = IDirectDrawSurface7_GetSurfaceDesc(presenter->primary, &primary_desc))) + return hr; + if (info->lpHdr->biBitCount != primary_desc.ddpfPixelFormat.dwRGBBitCount) + return E_FAIL; + if (info->lpHdr->biBitCount != 32) { FIXME("Unhandled bit depth %u.\n", info->lpHdr->biBitCount); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Matteo Bruni <mbruni(a)codeweavers.com> --- dlls/ddraw/ddraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 3e66b134a75..fb8895f01b2 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -1794,7 +1794,7 @@ static HRESULT WINAPI ddraw7_GetFourCCCodes(IDirectDraw7 *iface, DWORD *NumCodes { WINED3DFMT_YUY2, WINED3DFMT_UYVY, WINED3DFMT_YV12, WINED3DFMT_DXT1, WINED3DFMT_DXT2, WINED3DFMT_DXT3, WINED3DFMT_DXT4, WINED3DFMT_DXT5, - WINED3DFMT_ATI2N, WINED3DFMT_NVHU, WINED3DFMT_NVHS + WINED3DFMT_ATI2N, WINED3DFMT_NVHU, WINED3DFMT_NVHS, WINED3DFMT_NV12, }; struct wined3d_display_mode mode; DWORD count = 0, i, outsize; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Henri Verbeet <hverbeet(a)locutus.nl> --- dlls/quartz/vmr7_presenter.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index bbfca8ec695..5b758311ba0 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -171,6 +171,37 @@ static ULONG WINAPI surface_allocator_Release(IVMRSurfaceAllocator *iface) return IVMRImagePresenter_Release(&presenter->IVMRImagePresenter_iface); } +static BOOL fourcc_is_supported(IDirectDraw7 *ddraw, DWORD fourcc) +{ + DWORD *codes, count, i; + HRESULT hr; + + if (FAILED(hr = IDirectDraw7_GetFourCCCodes(ddraw, &count, NULL))) + { + ERR("Failed to get FOURCC code count, hr %#lx.\n", hr); + return FALSE; + } + + if (!count || !(codes = calloc(count, sizeof(*codes)))) + return FALSE; + + if (FAILED(hr = IDirectDraw7_GetFourCCCodes(ddraw, &count, codes))) + { + ERR("Failed to get FOURCC codes, hr %#lx.\n", hr); + free(codes); + return FALSE; + } + + for (i = 0; i < count; ++i) + { + if (codes[i] == fourcc) + break; + } + free(codes); + + return i < count; +} + static HRESULT WINAPI surface_allocator_AllocateSurface(IVMRSurfaceAllocator *iface, DWORD_PTR id, VMRALLOCATIONINFO *info, DWORD *count, IDirectDrawSurface7 **surface) { @@ -221,6 +252,9 @@ static HRESULT WINAPI surface_allocator_AllocateSurface(IVMRSurfaceAllocator *if } else { + if (!fourcc_is_supported(presenter->ddraw, info->lpHdr->biCompression)) + return VFW_E_DDRAW_CAPS_NOT_SUITABLE; + surface_desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC; surface_desc.ddpfPixelFormat.dwFourCC = info->lpHdr->biCompression; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Henri Verbeet <hverbeet(a)locutus.nl> --- dlls/quartz/vmr7_presenter.c | 48 ++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index 5b758311ba0..72571a299cb 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -105,11 +105,47 @@ static HRESULT WINAPI image_presenter_StopPresenting(IVMRImagePresenter *iface, return E_NOTIMPL; } +static BOOL get_clip_rect(struct vmr7_presenter *presenter, RECT *r) +{ + IDirectDrawClipper *clipper; + RGNDATA *data; + HRESULT hr; + DWORD size; + + if (FAILED(hr = IDirectDrawSurface7_GetClipper(presenter->primary, &clipper))) + return FALSE; + + if (FAILED(hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &size))) + { + IDirectDrawClipper_Release(clipper); + return FALSE; + } + + if (!(data = malloc(size))) + { + IDirectDrawClipper_Release(clipper); + return FALSE; + } + + if (FAILED(hr = IDirectDrawClipper_GetClipList(clipper, NULL, data, &size))) + { + free(data); + IDirectDrawClipper_Release(clipper); + return FALSE; + } + + *r = data->rdh.rcBound; + + free(data); + IDirectDrawClipper_Release(clipper); + + return TRUE; +} + static HRESULT WINAPI image_presenter_PresentImage(IVMRImagePresenter *iface, DWORD_PTR cookie, VMRPRESENTATIONINFO *info) { struct vmr7_presenter *presenter = impl_from_IVMRImagePresenter(iface); - POINT point; HRESULT hr; RECT rect; @@ -125,10 +161,12 @@ static HRESULT WINAPI image_presenter_PresentImage(IVMRImagePresenter *iface, if (info->dwFlags & VMRSample_SrcDstRectsValid) FIXME("Ignoring src/dst rects.\n"); - GetClientRect(presenter->window, &rect); - point.x = point.y = 0; - ClientToScreen(presenter->window, &point); - OffsetRect(&rect, point.x, point.y); + if (!get_clip_rect(presenter, &rect)) + { + ERR("Failed to get clip rect.\n"); + return E_FAIL; + } + if (FAILED(hr = IDirectDrawSurface7_Blt(presenter->primary, &rect, info->lpSurf, NULL, DDBLT_WAIT, NULL))) ERR("Failed to blit, hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Henri Verbeet <hverbeet(a)locutus.nl> --- dlls/quartz/vmr7_presenter.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index 72571a299cb..6c6c2f350e1 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -146,6 +146,7 @@ static HRESULT WINAPI image_presenter_PresentImage(IVMRImagePresenter *iface, DWORD_PTR cookie, VMRPRESENTATIONINFO *info) { struct vmr7_presenter *presenter = impl_from_IVMRImagePresenter(iface); + SIZE dst_size; HRESULT hr; RECT rect; @@ -167,6 +168,26 @@ static HRESULT WINAPI image_presenter_PresentImage(IVMRImagePresenter *iface, return E_FAIL; } + dst_size.cx = rect.right - rect.left; + dst_size.cy = rect.bottom - rect.top; + + if (info->szAspectRatio.cx * dst_size.cy > dst_size.cx * info->szAspectRatio.cy) + { + unsigned int scaled_height = info->szAspectRatio.cy * dst_size.cx / info->szAspectRatio.cx; + unsigned int offset = (dst_size.cy - scaled_height) / 2; + + rect.top += offset; + rect.bottom -= offset; + } + else if (info->szAspectRatio.cx * dst_size.cy < dst_size.cx * info->szAspectRatio.cy) + { + unsigned int scaled_width = info->szAspectRatio.cx * dst_size.cy / info->szAspectRatio.cy; + unsigned int offset = (dst_size.cx - scaled_width) / 2; + + rect.left += offset; + rect.right -= offset; + } + if (FAILED(hr = IDirectDrawSurface7_Blt(presenter->primary, &rect, info->lpSurf, NULL, DDBLT_WAIT, NULL))) ERR("Failed to blit, hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Matteo Bruni <mbruni(a)codeweavers.com> --- dlls/quartz/vmr7_presenter.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/quartz/vmr7_presenter.c b/dlls/quartz/vmr7_presenter.c index 6c6c2f350e1..7e78b9c5d43 100644 --- a/dlls/quartz/vmr7_presenter.c +++ b/dlls/quartz/vmr7_presenter.c @@ -270,6 +270,12 @@ static HRESULT WINAPI surface_allocator_AllocateSurface(IVMRSurfaceAllocator *if TRACE("presenter %p, id %#Ix, info %p, count %p, surface %p.\n", presenter, id, info, count, surface); + if (info->lpHdr->biSize != sizeof(*info->lpHdr)) + { + WARN("Invalid BITMAPINFOHEADER size %lu.\n", info->lpHdr->biSize); + return DDERR_INVALIDPIXELFORMAT; + } + 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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Matteo Bruni <mbruni(a)codeweavers.com> --- dlls/quartz/tests/vmr7.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index 9502a994576..3d56bc09a39 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -3870,6 +3870,18 @@ static void test_default_presenter_allocate(void) ref = IDirectDrawSurface7_Release(frontbuffer); ok(!ref, "Got outstanding refcount %ld.\n", ref); + info.lpHdr->biCompression = BI_RGB; + frontbuffer = NULL; + hr = IVMRSurfaceAllocator_AllocateSurface(allocator, 0, &info, &count, &frontbuffer); + expect_hr = tests[i].depth == 32 ? DD_OK : E_FAIL; + ok(hr == expect_hr, "Got hr %#lx.\n", hr); + ok(!!frontbuffer == (hr == DD_OK), "Got frontbuffer %p.\n", frontbuffer); + if (frontbuffer) + { + hr = IVMRSurfaceAllocator_FreeSurface(allocator, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + winetest_pop_context(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
From: Matteo Bruni <mbruni(a)codeweavers.com> --- dlls/quartz/tests/vmr7.c | 51 +++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index 3d56bc09a39..e250695596a 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -3685,11 +3685,25 @@ static void test_default_presenter_allocate(void) .biPlanes = 1, }; + BITMAPV4HEADER bitmap_v4_header = + { + .bV4Size = sizeof(BITMAPV4HEADER), + .bV4Width = 32, + .bV4Height = 16, + .bV4Planes = 1, + .bV4BitCount = 16, + .bV4V4Compression = BI_BITFIELDS, + .bV4RedMask = 0x00ff0000, + .bV4GreenMask = 0x0000ff00, + .bV4BlueMask = 0x000000ff, + .bV4AlphaMask = 0, + }; + static const struct { WORD depth; DWORD compression; - DDPIXELFORMAT format; + BOOL v4; } tests[] = { @@ -3698,6 +3712,8 @@ static void test_default_presenter_allocate(void) {12, mmioFOURCC('Y','V','1','2')}, {16, mmioFOURCC('U','Y','V','Y')}, {16, mmioFOURCC('Y','U','Y','2')}, + {32, BI_BITFIELDS}, + {32, BI_BITFIELDS, TRUE}, }; window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, @@ -3716,7 +3732,6 @@ static void test_default_presenter_allocate(void) 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) @@ -3725,10 +3740,25 @@ static void test_default_presenter_allocate(void) HRESULT expect_hr; DWORD count = 2; - winetest_push_context("Compression %#lx, depth %u", tests[i].compression, tests[i].depth); + winetest_push_context("Test %u: Compression %#lx, depth %u", i, tests[i].compression, tests[i].depth); - bitmap_header.biBitCount = tests[i].depth; - bitmap_header.biCompression = tests[i].compression; + if (tests[i].v4 || tests[i].compression == BI_BITFIELDS) + { + info.lpHdr = (BITMAPINFOHEADER *)&bitmap_v4_header; + bitmap_v4_header.bV4BitCount = tests[i].depth; + bitmap_v4_header.bV4V4Compression = tests[i].compression; + if (tests[i].v4) + bitmap_v4_header.bV4Size = sizeof(bitmap_v4_header); + else + bitmap_v4_header.bV4Size = sizeof(BITMAPINFOHEADER); + } + else + { + bitmap_header.biBitCount = tests[i].depth; + bitmap_header.biCompression = tests[i].compression; + info.lpHdr = &bitmap_header; + bitmap_header.biSize = sizeof(BITMAPINFOHEADER); + } ddraw = create_ddraw(window); @@ -3741,7 +3771,7 @@ static void test_default_presenter_allocate(void) desc.dwWidth = desc.dwHeight = 32; desc.dwBackBufferCount = 2; desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); - if (tests[i].compression) + if (tests[i].compression != BI_RGB && tests[i].compression != BI_BITFIELDS) { desc.ddpfPixelFormat.dwFlags = DDPF_FOURCC; desc.ddpfPixelFormat.dwFourCC = tests[i].compression; @@ -3769,11 +3799,14 @@ static void test_default_presenter_allocate(void) IDirectDraw7_Release(ddraw); + if (tests[i].v4) + expect_hr = DDERR_INVALIDPIXELFORMAT; hr = IVMRSurfaceAllocator_AllocateSurface(allocator, 0, &info, &count, &frontbuffer); ok(hr == expect_hr, "Got hr %#lx.\n", hr); - if (hr == VFW_E_DDRAW_CAPS_NOT_SUITABLE) + if (FAILED(hr)) { - skip("Format is not supported.\n"); + if (hr == VFW_E_DDRAW_CAPS_NOT_SUITABLE) + skip("Format is not supported.\n"); winetest_pop_context(); continue; } @@ -3794,7 +3827,7 @@ static void test_default_presenter_allocate(void) 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) + if (tests[i].compression != BI_RGB && tests[i].compression != BI_BITFIELDS) { ok(desc.ddpfPixelFormat.dwFlags == DDPF_FOURCC, "Got flags %#lx.\n", desc.ddpfPixelFormat.dwFlags); ok(desc.ddpfPixelFormat.dwFourCC == bitmap_header.biCompression, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
This merge request was approved by Matteo Bruni. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9520
Yeah, these aren't too complicated so I don't mind the large series. However: * 1/9 could use tests; should be easy enough to plug into test_default_presenter_allocate(). * 2/9... wow, that's surprising; it allows BI_BITFIELDS but not 16- or 24-bit BI_RGB. Okay then. * 3/9 is fine, just want to write that for reference I did check with Helen and the NV11 card does report NV12. * Why do we need 4/9? Shouldn't it fail CreateSurface()? * 5/9 is probably fine, although as someone less familiar with how this area works I'd appreciate an explanation of why the current code is wrong. It's not exactly easy to look up, anyway. * 6/9 should presumably only be applied if the application has called SetAspectRatioMode(VMR_ARMODE_LETTER_BOX). Has it? And if it has, we presumably need to also clear the rest of the surface to black. * 8/9 would probably make more sense if you just fit it into the table, with depth=16 and depth=24 entries. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9520#note_122994
participants (4)
-
Elizabeth Figura (@zfigura) -
Henri Verbeet -
Matteo Bruni -
Matteo Bruni (@Mystral)