Using a new wined3d WINED3D_NO_CLIP_CHILDREN flag which will remove the style, as native, to allow win32u offscreen rendering to blit over child windows but still invalidate them after WM_PAINT, as necessary for some game such as Command & Conquer 2 to refresh their display properly.
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58844 --- dlls/ddraw/tests/ddraw1.c | 102 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw2.c | 102 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw4.c | 102 ++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw7.c | 102 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 408 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index fb5201f66ba..53397088829 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -16305,6 +16305,107 @@ out: DestroyWindow(window); }
+static RGNDATA *get_region_data(HRGN region) +{ + RGNDATA *data = NULL; + DWORD size; + + if (region && (size = GetRegionData(region, 0, NULL)) && (data = malloc(size))) + GetRegionData(region, size, data); + + return data; +} + +static void test_window_clipping(void) +{ + IDirectDraw *ddraw; + ULONG refcount; + RGNDATA *data; + HRGN region; + HWND window; + HRESULT hr; + UINT ret; + HDC dc; + + window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, NULL, NULL); + CreateWindowA("#32770", "", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, window, NULL, NULL, NULL); + flush_events(); + + ddraw = create_ddraw(); + ok(!!ddraw, "Failed to create a ddraw object.\n"); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + refcount = IDirectDraw_Release(ddraw); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + DestroyWindow(window); +} + START_TEST(ddraw1) { DDDEVICEIDENTIFIER identifier; @@ -16429,4 +16530,5 @@ START_TEST(ddraw1) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_window_clipping(); } diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index f163ec80bed..d4678344585 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -17376,6 +17376,107 @@ out: DestroyWindow(window); }
+static RGNDATA *get_region_data(HRGN region) +{ + RGNDATA *data = NULL; + DWORD size; + + if (region && (size = GetRegionData(region, 0, NULL)) && (data = malloc(size))) + GetRegionData(region, size, data); + + return data; +} + +static void test_window_clipping(void) +{ + IDirectDraw2 *ddraw; + ULONG refcount; + RGNDATA *data; + HRGN region; + HWND window; + HRESULT hr; + UINT ret; + HDC dc; + + window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, NULL, NULL); + CreateWindowA("#32770", "", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, window, NULL, NULL, NULL); + flush_events(); + + ddraw = create_ddraw(); + ok(!!ddraw, "Failed to create a ddraw object.\n"); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + refcount = IDirectDraw_Release(ddraw); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + DestroyWindow(window); +} + START_TEST(ddraw2) { DDDEVICEIDENTIFIER identifier; @@ -17506,4 +17607,5 @@ START_TEST(ddraw2) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_window_clipping(); } diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index 60eaa3ec8d0..7a955155099 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -20457,6 +20457,107 @@ out: DestroyWindow(window); }
+static RGNDATA *get_region_data(HRGN region) +{ + RGNDATA *data = NULL; + DWORD size; + + if (region && (size = GetRegionData(region, 0, NULL)) && (data = malloc(size))) + GetRegionData(region, size, data); + + return data; +} + +static void test_window_clipping(void) +{ + IDirectDraw4 *ddraw; + ULONG refcount; + RGNDATA *data; + HRGN region; + HWND window; + HRESULT hr; + UINT ret; + HDC dc; + + window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, NULL, NULL); + CreateWindowA("#32770", "", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, window, NULL, NULL, NULL); + flush_events(); + + ddraw = create_ddraw(); + ok(!!ddraw, "Failed to create a ddraw object.\n"); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + refcount = IDirectDraw_Release(ddraw); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + DestroyWindow(window); +} + START_TEST(ddraw4) { DDDEVICEIDENTIFIER identifier; @@ -20604,4 +20705,5 @@ START_TEST(ddraw4) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_window_clipping(); } diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index a3df2fa659f..50963559fb3 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -20857,6 +20857,107 @@ out: DestroyWindow(window); }
+static RGNDATA *get_region_data(HRGN region) +{ + RGNDATA *data = NULL; + DWORD size; + + if (region && (size = GetRegionData(region, 0, NULL)) && (data = malloc(size))) + GetRegionData(region, size, data); + + return data; +} + +static void test_window_clipping(void) +{ + IDirectDraw7 *ddraw; + ULONG refcount; + RGNDATA *data; + HRGN region; + HWND window; + HRESULT hr; + UINT ret; + HDC dc; + + window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, NULL, NULL); + CreateWindowA("#32770", "", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, window, NULL, NULL, NULL); + flush_events(); + + ddraw = create_ddraw(); + ok(!!ddraw, "Failed to create a ddraw object.\n"); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!!(ret & WS_CLIPCHILDREN), "Missing WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children to be clipped out */ + ok(data->rdh.nCount == 2, "Got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES); + ok(hr == DD_OK, "Got unexpected hr %#lx.\n", hr); + ret = GetWindowLongW(window, GWL_STYLE); + ok(!(ret & WS_CLIPCHILDREN), "Got WS_CLIPCHILDREN\n"); + ok(!!(ret & WS_CLIPSIBLINGS), "Missing WS_CLIPSIBLINGS\n"); + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "Got unexpected ret %d\n", ret); + data = get_region_data(region); + /* expect children *not* to be clipped out */ + todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + refcount = IDirectDraw_Release(ddraw); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + DestroyWindow(window); +} + START_TEST(ddraw7) { DDDEVICEIDENTIFIER2 identifier; @@ -21038,4 +21139,5 @@ START_TEST(ddraw7) test_sysmem_x_channel(); test_yuv_blit(); test_blit_to_self(); + test_window_clipping(); }
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58844 --- dlls/d3d9/tests/device.c | 124 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+)
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c index b782833c37d..a67c4025ac1 100644 --- a/dlls/d3d9/tests/device.c +++ b/dlls/d3d9/tests/device.c @@ -15299,6 +15299,129 @@ static void test_d3d9on12(void) out: DestroyWindow(window); } +static RGNDATA *get_region_data(HRGN region) +{ + RGNDATA *data = NULL; + DWORD size; + + if (region && (size = GetRegionData(region, 0, NULL)) && (data = malloc(size))) + GetRegionData(region, size, data); + + return data; +} + +static void test_window_region(void) +{ + struct device_desc device_desc; + IDirect3DDevice9 *device; + IDirect3D9 *d3d9; + RGNDATA *data; + HRGN region; + HWND window; + UINT ret; + HDC dc; + + window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, NULL, NULL); + CreateWindowA("#32770", "", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, window, NULL, NULL, NULL); + flush_events(); + + d3d9 = Direct3DCreate9(D3D_SDK_VERSION); + ok(!!d3d9, "Failed to create a D3D object.\n"); + + + device_desc.adapter_ordinal = D3DADAPTER_DEFAULT; + device_desc.device_window = window; + device_desc.width = 300; + device_desc.height = 300; + device_desc.flags = CREATE_DEVICE_NOWINDOWCHANGES; + if (!(device = create_device(d3d9, window, &device_desc))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + IDirect3D9_Release(d3d9); + DestroyWindow(window); + return; + } + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "got %d\n", ret); + data = get_region_data(region); + ok(data->rdh.nCount == 2, "got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + IDirect3DDevice9_Release(device); + + device_desc.flags = 0; + if (!(device = create_device(d3d9, window, &device_desc))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + IDirect3D9_Release(d3d9); + DestroyWindow(window); + return; + } + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "got %d\n", ret); + data = get_region_data(region); + ok(data->rdh.nCount == 2, "got nCount %lu\n", data->rdh.nCount); + free(data); + DeleteObject(region); + + IDirect3DDevice9_Release(device); + + device_desc.width = registry_mode.dmPelsWidth; + device_desc.height = registry_mode.dmPelsHeight; + device_desc.flags = CREATE_DEVICE_NOWINDOWCHANGES | CREATE_DEVICE_FULLSCREEN; + if (!(device = create_device(d3d9, window, &device_desc))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + IDirect3D9_Release(d3d9); + DestroyWindow(window); + return; + } + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "got %d\n", ret); + data = get_region_data(region); + ok(data->rdh.nCount == 2, "got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + IDirect3DDevice9_Release(device); + + device_desc.flags = CREATE_DEVICE_FULLSCREEN; + if (!(device = create_device(d3d9, window, &device_desc))) + { + skip("Failed to create a D3D device, skipping tests.\n"); + IDirect3D9_Release(d3d9); + DestroyWindow(window); + return; + } + + region = CreateRectRgn(0, 0, 0, 0); + dc = GetDCEx(window, 0, DCX_CACHE | DCX_USESTYLE); + ret = GetRandomRgn(dc, region, SYSRGN); + ok(ret == 1, "got %d\n", ret); + data = get_region_data(region); + ok(data->rdh.nCount == 2, "got nCount %lu\n", data->rdh.nCount); + free(data); + ReleaseDC(window, dc); + DeleteObject(region); + + IDirect3DDevice9_Release(device); + + + IDirect3D9_Release(d3d9); + DestroyWindow(window); +}
START_TEST(device) { @@ -15437,6 +15560,7 @@ START_TEST(device) test_cursor_clipping(); test_window_position(); test_d3d9on12(); + test_window_region();
UnregisterClassA("d3d9_test_wc", GetModuleHandleA(NULL)); }
From: Rémi Bernon rbernon@codeweavers.com
Using a new wined3d WINED3D_NO_CLIP_CHILDREN flag which will remove the style, as native, to allow win32u offscreen rendering to blit over child windows but still invalidate them after WM_PAINT, as necessary for some game such as Command & Conquer 2 to refresh their display properly.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58844 --- dlls/ddraw/ddraw_private.h | 3 ++- dlls/ddraw/tests/ddraw1.c | 4 ++-- dlls/ddraw/tests/ddraw2.c | 4 ++-- dlls/ddraw/tests/ddraw4.c | 4 ++-- dlls/ddraw/tests/ddraw7.c | 4 ++-- dlls/wined3d/device.c | 19 +++++++++++++++++++ dlls/wined3d/swapchain.c | 9 ++++++--- include/wine/wined3d.h | 1 + 8 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index bd1df8e1b82..b8e830296dc 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -62,7 +62,8 @@ struct FvfToDecl
#define DDRAW_WINED3D_FLAGS (WINED3D_LEGACY_DEPTH_BIAS | WINED3D_RESTORE_MODE_ON_ACTIVATE \ | WINED3D_FOCUS_MESSAGES | WINED3D_PIXEL_CENTER_INTEGER | WINED3D_LEGACY_UNBOUND_RESOURCE_COLOR \ - | WINED3D_NO_PRIMITIVE_RESTART | WINED3D_LEGACY_CUBEMAP_FILTERING | WINED3D_NO_DRAW_INDIRECT) + | WINED3D_NO_PRIMITIVE_RESTART | WINED3D_LEGACY_CUBEMAP_FILTERING | WINED3D_NO_DRAW_INDIRECT \ + | WINED3D_NO_CLIP_CHILDREN)
#define DDRAW_WINED3D_SWAPCHAIN_FLAGS (WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH \ | WINED3D_SWAPCHAIN_IMPLICIT | WINED3D_SWAPCHAIN_REGISTER_TOPMOST_TIMER) diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 53397088829..60496a0921b 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -16364,7 +16364,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
@@ -16397,7 +16397,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index d4678344585..c6b3f9aa9da 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -17435,7 +17435,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
@@ -17468,7 +17468,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index 7a955155099..4f49d50359a 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -20516,7 +20516,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
@@ -20549,7 +20549,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index 50963559fb3..c0360cf8966 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -20916,7 +20916,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
@@ -20949,7 +20949,7 @@ static void test_window_clipping(void) ok(ret == 1, "Got unexpected ret %d\n", ret); data = get_region_data(region); /* expect children *not* to be clipped out */ - todo_wine ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); + ok(data->rdh.nCount == 1, "Got nCount %lu\n", data->rdh.nCount); free(data); DeleteObject(region);
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 443bf10ab76..2736a4be4f6 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -5633,6 +5633,25 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL DefWindowProcA(window, message, wparam, lparam); } } + else if (message == WM_PAINT && device->wined3d->flags & WINED3D_NO_CLIP_CHILDREN) + { + struct wined3d_swapchain *swapchain; + LRESULT res; + + if (unicode) + res = CallWindowProcW(proc, window, message, wparam, lparam); + else + res = CallWindowProcA(proc, window, message, wparam, lparam); + + if ((swapchain = wined3d_device_get_swapchain(device, 0)) + && swapchain->state.style & WS_CLIPCHILDREN) + { + RedrawWindow(window, NULL, 0, RDW_INVALIDATE | RDW_NOFRAME); + RedrawWindow(window, NULL, 0, RDW_VALIDATE | RDW_NOFRAME | RDW_NOCHILDREN); + } + + return res; + }
if (unicode) return CallWindowProcW(proc, window, message, wparam, lparam); diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index a1000ec2393..fbba1f348ba 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -2148,11 +2148,13 @@ HRESULT CDECL wined3d_swapchain_state_resize_target(struct wined3d_swapchain_sta return WINED3D_OK; }
-static LONG fullscreen_style(LONG style) +static LONG fullscreen_style(LONG style, UINT flags) { /* Make sure the window is managed, otherwise we won't get keyboard input. */ style |= WS_POPUP | WS_SYSMENU; style &= ~(WS_CAPTION | WS_THICKFRAME); + if (flags & WINED3D_NO_CLIP_CHILDREN) + style &= ~WS_CLIPCHILDREN;
return style; } @@ -2282,7 +2284,7 @@ HRESULT wined3d_swapchain_state_setup_fullscreen(struct wined3d_swapchain_state state->style = GetWindowLongW(window, GWL_STYLE); state->exstyle = GetWindowLongW(window, GWL_EXSTYLE);
- s->style = fullscreen_style(state->style); + s->style = fullscreen_style(state->style, state->wined3d->flags); s->exstyle = fullscreen_exstyle(state->exstyle); s->set_style = true; s->register_topmost_timer = !!(state->desc.flags & WINED3D_SWAPCHAIN_REGISTER_TOPMOST_TIMER); @@ -2340,7 +2342,8 @@ void wined3d_swapchain_state_restore_from_fullscreen(struct wined3d_swapchain_st * fullscreen phase. Some applications change it before calling Reset() * when switching between windowed and fullscreen modes (HL2), some * depend on the original style (Eve Online). */ - s->set_style = style == fullscreen_style(state->style) && exstyle == fullscreen_exstyle(state->exstyle); + s->set_style = style == fullscreen_style(state->style, state->wined3d->flags) + && exstyle == fullscreen_exstyle(state->exstyle); s->register_topmost_timer = !!(state->desc.flags & WINED3D_SWAPCHAIN_REGISTER_TOPMOST_TIMER); s->set_topmost_timer = false;
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 2c57b55cb1a..9aa16f78f0d 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -1345,6 +1345,7 @@ enum wined3d_memory_segment_group #define WINED3D_LEGACY_CUBEMAP_FILTERING 0x00001000 #define WINED3D_NORMALIZED_DEPTH_BIAS 0x00002000 #define WINED3D_NO_DRAW_INDIRECT 0x00004000 +#define WINED3D_NO_CLIP_CHILDREN 0x00008000
#define WINED3D_RESZ_CODE 0x7fa05000
I am very, very nervous about doing this. This is not how native ddraw behaves on windows 98 (I checked), and we have other bugs that are caused by us messing with window styles.
The fact that newer Windows versions behave like this isn't really an argument. Newer Windows tends to break a lot of ddraw games in various ways.
I think the ideal way to fix this, and the aforementioned other bugs, would be to manually escape into the user driver rather than relying on GL or Vulkan WSI. Possibly this would use D3DKMTPresent(), although I'm not entirely sure how. I believe Henri (@hverbeet) has an idea of how to achieve this?
Well that game works fine on recent Windows, and the tests show that recent Windows do this kind of thing. I'm not sure to see any reason to try doing otherwise, and break things which we won't be able to even test because of a Wine-specific mechanism, until we know for sure that some other game is broken.
I think it has less chance of breaking something than other style edition we already do: it doesn't have an effect on the window geometry for instance and recent Windows is shown to edit that specific style (unlike the other styles we change).