[PATCH 0/2] MR10723: ddraw: Ignore hwnd clipper in exclusive fullscreen mode.
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/tests/ddraw1.c | 183 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw2.c | 183 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw4.c | 183 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw7.c | 183 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 732 insertions(+) diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 2e2f7e62483..ed2708a84ea 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,180 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, 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); + + /* Clipper with region works. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_region); + 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); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "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, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) 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, *clipper2; + DDSURFACEDESC surface_desc; + HWND window, clip_window; + IDirectDraw *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + 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); + + hr = IDirectDraw_CreateClipper(ddraw, 0, &clipper2, 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); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + 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(clipper2, 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; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + 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 +16690,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 114b297d239..7715871758a 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,180 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, 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); + + /* Clipper with region works. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_region); + 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); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "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, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) 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, *clipper2; + DDSURFACEDESC surface_desc; + HWND window, clip_window; + IDirectDraw2 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + 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); + + hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper2, 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); + + hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + 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(clipper2, 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; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + 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 +17767,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..42c7bb5345f 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,180 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface4 *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, 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); + + /* Clipper with region works. */ + hr = IDirectDrawSurface4_SetClipper(surface, clipper_region); + 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); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface4_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "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, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) 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, *clipper2; + DDSURFACEDESC2 surface_desc; + HWND window, clip_window; + IDirectDraw4 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + 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); + + hr = IDirectDraw4_CreateClipper(ddraw, 0, &clipper2, 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); + + hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + 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(clipper2, 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; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + 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 +20883,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..ca756a1fffd 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,180 @@ out: DestroyWindow(window); } +static void check_surface_clipper(IDirectDrawSurface7 *surface, IDirectDrawClipper *clipper_hwnd, + IDirectDrawClipper *clipper_region, 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); + + /* Clipper with region works. */ + hr = IDirectDrawSurface7_SetClipper(surface, clipper_region); + 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); + + /* Clipper with window has no effect. */ + hr = IDirectDrawSurface7_SetClipper(surface, clipper_hwnd); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(surface, 0xff0000ff); + c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); + ok(c == 0x000000ff, "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, window_rect->left + 1, window_rect->top + 1); + todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + c = get_surface_color(surface, 0, 0); + todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) 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, *clipper2; + DDSURFACEDESC2 surface_desc; + HWND window, clip_window; + IDirectDraw7 *ddraw; + RGNDATA *rgn_data; + DWORD ret, style; + RECT window_rect; + ULONG refcount; + unsigned int i; + 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); + + hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper2, 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); + + hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + 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(clipper2, 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; + clip_window = CreateWindowA("static", "ddraw_clip", style, 100, 100, 100, 100, + tests[i].parent ? window : NULL, NULL, NULL, NULL); + ok(!!clip_window, "got error %ld.\n", GetLastError()); + pump_messages(); + + GetWindowRect(clip_window, &window_rect); + hr = IDirectDrawClipper_SetHWnd(clipper, 0, clip_window); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + rgn_data = malloc(ret); + hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#lx.\n", rgn_data->rdh.dwSize); + ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#lx.\n", rgn_data->rdh.iType); + if (style & WS_VISIBLE) + { + ok(rgn_data->rdh.nCount >= 1, "got %lu.\n", rgn_data->rdh.nCount); + if (!(style & WS_CHILD)) + ok(EqualRect(&rgn_data->rdh.rcBound, &window_rect), "got %s, expected %s.\n", + wine_dbgstr_rect(&rgn_data->rdh.rcBound), wine_dbgstr_rect(&window_rect)); + } + else + { + ok(!rgn_data->rdh.nCount, "got %lu.\n", rgn_data->rdh.nCount); + } + free(rgn_data); + + winetest_push_context("primary"); + check_surface_clipper(primary, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + winetest_push_context("offscreen"); + check_surface_clipper(offscreen, clipper, clipper2, &window_rect, style); + winetest_pop_context(); + + hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + DestroyWindow(clip_window); + pump_messages(); + winetest_pop_context(); + } + + 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 +21315,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/10723
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/surface.c | 18 +++++++++--------- dlls/ddraw/tests/ddraw1.c | 4 ++-- dlls/ddraw/tests/ddraw2.c | 4 ++-- dlls/ddraw/tests/ddraw4.c | 4 ++-- dlls/ddraw/tests/ddraw7.c | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index e6ed79afccf..139bf45921d 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -1647,7 +1647,14 @@ 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; + } + + 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 +1666,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); @@ -4644,9 +4645,8 @@ static HRESULT WINAPI ddraw_surface7_SetClipper(IDirectDrawSurface7 *iface, if ((This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) && This->ddraw->wined3d_swapchain) { clipWindow = NULL; - if(clipper) { + if (clipper && !(This->ddraw->cooperative_level & DDSCL_EXCLUSIVE)) IDirectDrawClipper_GetHWnd(iclipper, &clipWindow); - } if (clipWindow) { diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index ed2708a84ea..af4acea1e6a 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -16426,9 +16426,9 @@ static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClippe ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index 7715871758a..1572d3473d0 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -17497,9 +17497,9 @@ static void check_surface_clipper(IDirectDrawSurface *surface, IDirectDrawClippe ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index 42c7bb5345f..0bb0074f783 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -20596,9 +20596,9 @@ static void check_surface_clipper(IDirectDrawSurface4 *surface, IDirectDrawClipp ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface4_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index ca756a1fffd..06b821bc4e2 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -20994,9 +20994,9 @@ static void check_surface_clipper(IDirectDrawSurface7 *surface, IDirectDrawClipp ok(hr == DD_OK, "got %#lx.\n", hr); c = get_surface_color(surface, window_rect->left + 1, window_rect->top + 1); - todo_wine_if(!(style & WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); c = get_surface_color(surface, 0, 0); - todo_wine_if((style & (WS_CHILD | WS_VISIBLE)) != (WS_CHILD | WS_VISIBLE)) ok(c == 0x0000ff00, "got %#x.\n", c); + ok(c == 0x0000ff00, "got %#x.\n", c); hr = IDirectDrawSurface7_SetClipper(surface, NULL); ok(hr == DD_OK, "got %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10723
Super Naughty Maid 2 regressed during Wine 11 development cycle and only shows black screen in fullscreen mode after exclusive fullscreen mode was partially implemented. The game sets clipper with a window on primary surface. The size of the window matches that of ddraw exclusive fullscreen window and clipper window is its child. ddraw currently always sets clipper window as swapchain window. Previously that worked because rendering to child window was appearing on screen. Now if exclusive fullscreen window is set up winex11 will move that child clipper window's client surface offscreen (because it is child) and then will refuse to present because there is exclusive fullscreen window. I am not entirely sure if that refusal to present is correct as exclusive fullscreen should guarantee that presenting to it should go on top of everything but presentation to other windows might still be shown (until overwritten with exclusive presentation). But I think the core problem is probably in ddraw here. My tests show (I also observed the colours interactively adding delays to the tests) that clipper window is completely ignored in exclusive fullscreen mode, at least on modern Windows. In any case, it probably doesn't make much sense to set swapchain window to the clipping window in exclusive fullscreen. All the presentation is supposed to go exclusively and worst case clipping window could be clipping the blits (but that is not what I observe on Windows). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10723#note_137398
participants (2)
-
Paul Gofman -
Paul Gofman (@gofman)