[PATCH 0/3] MR10842: ddraw: Ignore hwnd clipper in exclusive fullscreen mode.
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/tests/ddraw2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index 114b297d239..ca030897abd 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -17053,13 +17053,13 @@ static void test_d3d_state_reset(void) window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0); - window = create_window(); ddraw = create_ddraw(); ok(!!ddraw, "Failed to create a ddraw object.\n"); if (!(device = create_device(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN))) { skip("Failed to create 3D device.\n"); + IDirectDraw2_Release(ddraw); DestroyWindow(window); return; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10842
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/tests/ddraw1.c | 140 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw2.c | 140 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw4.c | 140 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw7.c | 140 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 560 insertions(+) diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 2e2f7e62483..007daf29407 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -114,6 +114,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -16382,6 +16390,137 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface *surface, + IDirectDrawClipper *clipper, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clippers with a region work. Clippers with a window work on Windows 98, + * but are ignored on modern windows. */ + + hr = IDirectDrawSurface_SetClipper(surface, clipper); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface *primary, *offscreen; + IDirectDrawClipper *clipper; + DDSURFACEDESC surface_desc; + IDirectDraw *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HWND window; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_pop_context(); + } + + hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw1) { DDDEVICEIDENTIFIER identifier; @@ -16508,4 +16647,5 @@ START_TEST(ddraw1) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index ca030897abd..dfbd0003fb2 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -115,6 +115,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -17453,6 +17461,137 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface *surface, + IDirectDrawClipper *clipper, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clippers with a region work. Clippers with a window work on Windows 98, + * but are ignored on modern windows. */ + + hr = IDirectDrawSurface_SetClipper(surface, clipper); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface *primary, *offscreen; + IDirectDrawClipper *clipper; + DDSURFACEDESC surface_desc; + IDirectDraw2 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HWND window; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_pop_context(); + } + + hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw2_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw2) { DDDEVICEIDENTIFIER identifier; @@ -17585,4 +17724,5 @@ START_TEST(ddraw2) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index 285b36f54c6..be26a5a74e5 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -121,6 +121,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -20552,6 +20560,137 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface4 *surface, + IDirectDrawClipper *clipper, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clippers with a region work. Clippers with a window work on Windows 98, + * but are ignored on modern windows. */ + + hr = IDirectDrawSurface4_SetClipper(surface, clipper); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface4_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface4_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface4 *primary, *offscreen; + IDirectDrawClipper *clipper; + DDSURFACEDESC2 surface_desc; + IDirectDraw4 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HWND window; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw4_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_pop_context(); + } + + hr = IDirectDraw4_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface4_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface4_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw4_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw4) { DDDEVICEIDENTIFIER identifier; @@ -20701,4 +20840,5 @@ START_TEST(ddraw4) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index e8487283ead..087df10a810 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -162,6 +162,14 @@ static void flush_events(void) } } +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); +} + static HWND create_foreground_window(void) { for (UINT retries = 5; retries; retries--) @@ -20950,6 +20958,137 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface7 *surface, + IDirectDrawClipper *clipper, RECT *window_rect, DWORD style) +{ + unsigned int c; + DDBLTFX fx; + HRESULT hr; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0xff00ff00; + + fill_surface(surface, 0xffff0000); + + /* Clippers with a region work. Clippers with a window work on Windows 98, + * but are ignored on modern windows. */ + + hr = IDirectDrawSurface7_SetClipper(surface, clipper); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 101, 101); + ok(c == 0x00ff0000, "got %#x.\n", c); + hr = IDirectDrawSurface7_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx); + ok(hr == DD_OK, "got %#lx.\n", hr); + c = get_surface_color(surface, 0, 0); + ok(c == 0x00ff0000, "got %#x.\n", c); + c = get_surface_color(surface, 101, 101); + ok(c == 0x0000ff00, "got %#x.\n", c); + + hr = IDirectDrawSurface7_SetClipper(surface, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + clear_surface(surface, 0); +} + +static void test_clipper_in_exclusive_fullscreen(void) +{ + static const struct + { + DWORD style; + BOOL parent; + } + tests[] = + { + { WS_POPUP }, + { WS_POPUP, TRUE }, + { WS_CHILD, TRUE }, + { WS_OVERLAPPED }, + { WS_CHILD | WS_VISIBLE, TRUE }, + { WS_POPUP | WS_VISIBLE }, + }; + IDirectDrawSurface7 *primary, *offscreen; + IDirectDrawClipper *clipper; + DDSURFACEDESC2 surface_desc; + IDirectDraw7 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + HWND window; + HRESULT hr; + HRGN rgn; + + if (!(ddraw = create_ddraw())) + { + skip("Failed to create ddraw, skipping test.\n"); + return; + } + hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + window = CreateWindowA("static", "ddraw_fullscreen", WS_POPUP | WS_VISIBLE, 0, 0, 640, 480, NULL, NULL, NULL, NULL); + pump_messages(); + hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "got %#lx.\n", hr); + pump_messages(); + + rgn = CreateRectRgn(100, 100, 200, 200); + ok(!!rgn, "Failed to create region.\n"); + ret = GetRegionData(rgn, 0, NULL); + rgn_data = malloc(ret); + ret = GetRegionData(rgn, ret, rgn_data); + ok(!!ret, "Failed to get region data.\n"); + DeleteObject(rgn); + hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0); + ok(hr == DD_OK, "got %#lx.\n", hr); + free(rgn_data); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &primary, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + surface_desc.dwWidth = 640; + surface_desc.dwHeight = 480; + hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &offscreen, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + style = tests[i].style; + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, &window_rect, style); + winetest_pop_context(); + + winetest_pop_context(); + } + + hr = IDirectDraw7_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + IDirectDrawClipper_Release(clipper); + refcount = IDirectDrawSurface7_Release(offscreen); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + refcount = IDirectDrawSurface7_Release(primary); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + + IDirectDraw7_Release(ddraw); + DestroyWindow(window); + pump_messages(); +} + START_TEST(ddraw7) { DDDEVICEIDENTIFIER2 identifier; @@ -21133,4 +21272,5 @@ START_TEST(ddraw7) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_clipper_in_exclusive_fullscreen(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10842
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/surface.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index e6ed79afccf..9b8d1db13ca 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -1647,7 +1647,17 @@ static HRESULT ddraw_surface_blt_clipped(struct ddraw_surface *dst_surface, cons SetRectEmpty(&src_rect); } - if (!dst_surface->clipper) + if (dst_surface->clipper && !ddraw_clipper_is_valid(dst_surface->clipper)) + { + FIXME("Attempting to blit with an invalid clipper.\n"); + return DDERR_INVALIDPARAMS; + } + + /* Windows 10 won't clip to the window in exclusive fullscreen mode. + * Windows 98 does. Super Naughty Maid 2, released in 2019, depends on + * the modern Windows behaviour. */ + if (!dst_surface->clipper + || ((dst_surface->ddraw->cooperative_level & DDSCL_EXCLUSIVE) && dst_surface->clipper->window)) { if (src_surface && src_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) hr = ddraw_surface_update_frontbuffer(src_surface, &src_rect, TRUE, 0); @@ -1659,12 +1669,6 @@ static HRESULT ddraw_surface_blt_clipped(struct ddraw_surface *dst_surface, cons return hr; } - if (!ddraw_clipper_is_valid(dst_surface->clipper)) - { - FIXME("Attempting to blit with an invalid clipper.\n"); - return DDERR_INVALIDPARAMS; - } - scale_x = (float)(src_rect.right - src_rect.left) / (float)(dst_rect.right - dst_rect.left); scale_y = (float)(src_rect.bottom - src_rect.top) / (float)(dst_rect.bottom - dst_rect.top); @@ -4641,7 +4645,10 @@ static HRESULT WINAPI ddraw_surface7_SetClipper(IDirectDrawSurface7 *iface, if (old_clipper && ddraw_clipper_is_valid(old_clipper)) IDirectDrawClipper_Release(&old_clipper->IDirectDrawClipper_iface); - if ((This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) && This->ddraw->wined3d_swapchain) + /* Windows 10 won't clip to the window in exclusive fullscreen mode. + * See ddraw_surface_blt_clipped(). */ + if ((This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) && This->ddraw->wined3d_swapchain + && !(This->ddraw->cooperative_level & DDSCL_EXCLUSIVE)) { clipWindow = NULL; if(clipper) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10842
This merge request was approved by Elizabeth Figura. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10842
Paul Gofman (@gofman) commented about dlls/ddraw/surface.c:
SetRectEmpty(&src_rect); }
- if (!dst_surface->clipper) + if (dst_surface->clipper && !ddraw_clipper_is_valid(dst_surface->clipper)) + { + FIXME("Attempting to blit with an invalid clipper.\n"); + return DDERR_INVALIDPARAMS; + } + + /* Windows 10 won't clip to the window in exclusive fullscreen mode. + * Windows 98 does. Super Naughty Maid 2, released in 2019, depends on + * the modern Windows behaviour. */
Well, it is not quite the case: I think the game would probably be fine with either old or new Windows behaviour (like it was fine on Wine before 'exclusive fullscreen mode' support). The problem is not clipping, the problem is that the rendering to a separate (clipper) window just goes nowhere in exclusive fullscreen mode now. There are various ways to fix it. It seems to me that avoiding using clipper window surface is preferred (and it is orthogonal to old vs new Windows, it is just our internal kitchen how the image gets onscreen). It is not strictly necessary to remove the actual clipping, we could probably keep it and still fix a regression. Although that would need more changes (how the clipping region is got in fullscreen), I'd probably suggest to stick to the new Windows behaviour (well, at least until it breaks something) as it is easier to unit test. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10842#note_139179
On Fri May 8 02:49:55 2026 +0000, Paul Gofman wrote:
Well, it is not quite the case: I think the game would probably be fine with either old or new Windows behaviour (like it was fine on Wine before 'exclusive fullscreen mode' support). The problem is not clipping, the problem is that the rendering to a separate (clipper) window just goes nowhere in exclusive fullscreen mode now. There are various ways to fix it. It seems to me that avoiding using clipper window surface is preferred (and it is orthogonal to old vs new Windows, it is just our internal kitchen how the image gets onscreen). It is not strictly necessary to remove the actual clipping, we could probably keep it and still fix a regression. Although that would need more changes (how the clipping region is got in fullscreen), I'd probably suggest to stick to the new Windows behaviour (well, at least until it breaks something) as it is easier to unit test. Why I think avoiding client window surface is preferred (regardless whether we are going to do clipping or not) is that it is straightforward: rendering in exclusive fullscreen emulates blitting directly to screen buffer. Using another window is less straightforward: it is subject for compositing in principle, that window is not supposed to render on top of everything (would maybe need a special flag for 'exclusive fullscreen' Wine extension). Then, it results in extra GL context, 'client window' on the clipper window, blitting from it in winex11 and all that is easily avoided.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10842#note_139180
Unapproving for a second; I didn't fully understand the problem and we might want to adjust the solution in light of that. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10842#note_139242
participants (3)
-
Elizabeth Figura (@zfigura) -
Paul Gofman -
Paul Gofman (@gofman)