Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/ddraw/tests/ddraw1.c | 134 +++++++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw2.c | 132 +++++++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw4.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw7.c | 141 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 555 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 52c5e858f91..9a872f830cd 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -217,6 +217,20 @@ static void destroy_window_thread(struct create_window_thread_param *p)
CloseHandle(p->thread);
}
+static IDirectDrawSurface *get_depth_stencil(IDirect3DDevice *device)
+{
+ IDirectDrawSurface *rt, *ret;
+ DDSCAPS caps = {DDSCAPS_ZBUFFER};
+ HRESULT hr;
+
+ hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
+ ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+ hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ret);
+ ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#x.\n", hr);
+ IDirectDrawSurface_Release(rt);
+ return ret;
+}
+
static HRESULT set_display_mode(IDirectDraw *ddraw, DWORD width, DWORD height)
{
if (SUCCEEDED(IDirectDraw_SetDisplayMode(ddraw, width, height, 32)))
@@ -10779,6 +10793,125 @@ done:
DestroyWindow(window);
}
+static void test_depth_readback(void)
+{
+ DWORD depth, expected_depth, max_diff, z_depth, z_mask;
+ IDirect3DExecuteBuffer *execute_buffer;
+ IDirect3DMaterial *blue_background;
+ D3DEXECUTEBUFFERDESC exec_desc;
+ IDirectDrawSurface *rt, *ds;
+ IDirect3DViewport *viewport;
+ DDSURFACEDESC surface_desc;
+ IDirect3DDevice *device;
+ IDirectDraw *ddraw;
+ unsigned int x, y;
+ UINT inst_length;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ void *ptr;
+
+ static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
+ static D3DLVERTEX quad[] =
+ {
+ {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xff00ff00}},
+ {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
+ {{ 1.0f}, {-1.0f}, {1.0f}, 0, {0xff00ff00}},
+ {{ 1.0f}, { 1.0f}, {0.9f}, 0, {0xff00ff00}},
+ };
+
+ window = create_window();
+ ok(!!window, "Failed to create a window.\n");
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a D3D device, skipping tests.\n");
+ IDirectDraw_Release(ddraw);
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
+ ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+ z_depth = get_device_z_depth(device);
+ z_mask = 0xffffffff >> (32 - z_depth);
+ ds = get_depth_stencil(device);
+
+ /* Changing depth buffers is hard in d3d1, so we only test with the
+ * initial depth buffer here. */
+
+ blue_background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+ viewport = create_viewport(device, 0, 0, 640, 480);
+ viewport_set_background(device, viewport, blue_background);
+
+ memset(&exec_desc, 0, sizeof(exec_desc));
+ exec_desc.dwSize = sizeof(exec_desc);
+ exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
+ exec_desc.dwBufferSize = 1024;
+ exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
+ hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
+ ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
+ ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
+
+ memcpy(exec_desc.lpData, quad, sizeof(quad));
+ ptr = (BYTE *)exec_desc.lpData + sizeof(quad);
+ emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORM, 0, 4);
+ emit_tquad(&ptr, 0);
+ emit_end(&ptr);
+
+ inst_length = ((BYTE *)ptr - sizeof(quad)) - (BYTE *)exec_desc.lpData;
+
+ hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
+ ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ set_execute_data(execute_buffer, 4, sizeof(quad), inst_length);
+ hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_UNCLIPPED);
+ ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
+ hr = IDirect3DDevice_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ hr = IDirectDrawSurface_Lock(ds, NULL, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
+ ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+
+ for (y = 60; y < 480; y += 120)
+ {
+ for (x = 80; x < 640; x += 160)
+ {
+ ptr = (BYTE *)surface_desc.lpSurface
+ + y * U1(surface_desc).lPitch
+ + x * (z_depth == 16 ? 2 : 4);
+ depth = *((DWORD *)ptr) & z_mask;
+ expected_depth = (x * (0.9 / 640.0) + y * (0.1 / 480.0)) * z_mask;
+ max_diff = ((0.5f * 0.9f) / 640.0f) * z_mask;
+ ok(abs(expected_depth - depth) <= max_diff,
+ "z_depth %u: Got depth 0x%08x (diff %d), expected 0x%08x+/-%u, at %u, %u.\n",
+ z_depth, depth, expected_depth - depth, expected_depth, max_diff, x, y);
+ }
+ }
+
+ hr = IDirectDrawSurface_Unlock(ds, NULL);
+ ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+ IDirect3DExecuteBuffer_Release(execute_buffer);
+ destroy_viewport(device, viewport);
+ destroy_material(blue_background);
+ IDirectDrawSurface_Release(ds);
+ IDirect3DDevice_Release(device);
+ refcount = IDirectDrawSurface_Release(rt);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ IDirectDraw_Release(ddraw);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw1)
{
DDDEVICEIDENTIFIER identifier;
@@ -10877,4 +11010,5 @@ START_TEST(ddraw1)
test_surface_desc_size();
test_texture_load();
test_ck_operation();
+ test_depth_readback();
}
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index e87244bb143..dc74c6998ff 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -12155,6 +12155,137 @@ done:
DestroyWindow(window);
}
+static void test_depth_readback(void)
+{
+ DWORD depth, expected_depth, max_diff;
+ IDirect3DMaterial2 *blue_background;
+ IDirectDrawSurface *rt, *ds;
+ IDirect3DViewport2 *viewport;
+ DDSURFACEDESC surface_desc;
+ IDirect3DDevice2 *device;
+ unsigned int i, x, y;
+ IDirectDraw2 *ddraw;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ void *ptr;
+
+ static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
+ static D3DLVERTEX quad[] =
+ {
+ {{-1.0f}, {-1.0f}, {0.1f}, 0, {0xff00ff00}},
+ {{-1.0f}, { 1.0f}, {0.0f}, 0, {0xff00ff00}},
+ {{ 1.0f}, {-1.0f}, {1.0f}, 0, {0xff00ff00}},
+ {{ 1.0f}, { 1.0f}, {0.9f}, 0, {0xff00ff00}},
+ };
+
+ static const struct
+ {
+ unsigned int z_depth, z_mask;
+ }
+ tests[] =
+ {
+ {16, 0x0000ffff},
+ {24, 0x00ffffff},
+ {32, 0xffffffff},
+ };
+
+ window = create_window();
+ ok(!!window, "Failed to create a window.\n");
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a D3D device, skipping tests.\n");
+ IDirectDraw2_Release(ddraw);
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
+ ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+ blue_background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+ viewport = create_viewport(device, 0, 0, 640, 480);
+ viewport_set_background(device, viewport, blue_background);
+ hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
+ ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
+
+ ds = get_depth_stencil(device);
+ hr = IDirectDrawSurface_DeleteAttachedSurface(rt, 0, ds);
+ ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#x.\n", hr);
+ IDirectDrawSurface_Release(ds);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
+ surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
+ U2(surface_desc).dwZBufferBitDepth = tests[i].z_depth;
+ surface_desc.dwWidth = 640;
+ surface_desc.dwHeight = 480;
+ hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
+ if (FAILED(hr))
+ {
+ skip("Format %u not supported, skipping test.\n", i);
+ continue;
+ }
+
+ hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
+ ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
+ hr = IDirect3DDevice2_SetRenderTarget(device, rt, 0);
+ ok(SUCCEEDED(hr), "Failed to set render target, hr %#x.\n", hr);
+
+ hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice2_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad, 4, 0);
+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+ hr = IDirect3DDevice2_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ hr = IDirectDrawSurface_Lock(ds, NULL, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
+ ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+
+ for (y = 60; y < 480; y += 120)
+ {
+ for (x = 80; x < 640; x += 160)
+ {
+ ptr = (BYTE *)surface_desc.lpSurface
+ + y * U1(surface_desc).lPitch
+ + x * (tests[i].z_depth == 16 ? 2 : 4);
+ depth = *((DWORD *)ptr) & tests[i].z_mask;
+ expected_depth = (x * (0.9 / 640.0) + y * (0.1 / 480.0)) * tests[i].z_mask;
+ max_diff = ((0.5f * 0.9f) / 640.0f) * tests[i].z_mask;
+ ok(abs(expected_depth - depth) <= max_diff,
+ "Test %u: Got depth 0x%08x (diff %d), expected 0x%08x+/-%u, at %u, %u.\n",
+ i, depth, expected_depth - depth, expected_depth, max_diff, x, y);
+ }
+ }
+
+ hr = IDirectDrawSurface_Unlock(ds, NULL);
+ ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+ hr = IDirectDrawSurface_DeleteAttachedSurface(rt, 0, ds);
+ ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#x.\n", hr);
+ IDirectDrawSurface_Release(ds);
+ }
+
+ destroy_viewport(device, viewport);
+ destroy_material(blue_background);
+ IDirectDrawSurface_Release(rt);
+ refcount = IDirect3DDevice2_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ IDirectDraw2_Release(ddraw);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw2)
{
DDDEVICEIDENTIFIER identifier;
@@ -12261,4 +12392,5 @@ START_TEST(ddraw2)
test_display_mode_surface_pixel_format();
test_surface_desc_size();
test_ck_operation();
+ test_depth_readback();
}
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index c86fcc58851..aeac118483f 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -14207,6 +14207,153 @@ static void test_map_synchronisation(void)
DestroyWindow(window);
}
+static void test_depth_readback(void)
+{
+ DWORD depth, expected_depth, max_diff;
+ IDirectDrawSurface4 *rt, *ds;
+ IDirect3DViewport3 *viewport;
+ DDSURFACEDESC2 surface_desc;
+ IDirect3DDevice3 *device;
+ unsigned int i, x, y;
+ IDirectDraw4 *ddraw;
+ IDirect3D3 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ RECT r;
+
+ static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
+ static struct
+ {
+ struct vec3 position;
+ DWORD diffuse;
+ }
+ quad[] =
+ {
+ {{-1.0f, -1.0f, 0.1f}, 0xff00ff00},
+ {{-1.0f, 1.0f, 0.0f}, 0xff00ff00},
+ {{ 1.0f, -1.0f, 1.0f}, 0xff00ff00},
+ {{ 1.0f, 1.0f, 0.9f}, 0xff00ff00},
+ };
+
+ static const struct
+ {
+ unsigned int z_depth, s_depth, z_mask, s_mask;
+ BOOL todo;
+ }
+ tests[] =
+ {
+ {16, 0, 0x0000ffff, 0x00000000},
+ {24, 0, 0x00ffffff, 0x00000000},
+ {32, 0, 0x00ffffff, 0x00000000},
+ {32, 8, 0x00ffffff, 0xff000000, TRUE},
+ {32, 0, 0xffffffff, 0x00000000},
+ };
+
+ window = create_window();
+ ok(!!window, "Failed to create a window.\n");
+
+ if (!(device = create_device(window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a D3D device, skipping tests.\n");
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
+ ok(SUCCEEDED(hr), "Failed to get Direct3D3 interface, hr %#x.\n", hr);
+ hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
+ ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
+ ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+ viewport = create_viewport(device, 0, 0, 640, 480);
+ hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
+ ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
+
+ ds = get_depth_stencil(device);
+ hr = IDirectDrawSurface4_DeleteAttachedSurface(rt, 0, ds);
+ ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#x.\n", hr);
+ IDirectDrawSurface4_Release(ds);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
+ surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
+ U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
+ U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
+ if (tests[i].s_depth)
+ U4(surface_desc).ddpfPixelFormat.dwFlags |= DDPF_STENCILBUFFER;
+ U1(U4(surface_desc).ddpfPixelFormat).dwZBufferBitDepth = tests[i].z_depth;
+ U2(U4(surface_desc).ddpfPixelFormat).dwStencilBitDepth = tests[i].s_depth;
+ U3(U4(surface_desc).ddpfPixelFormat).dwZBitMask = tests[i].z_mask;
+ U4(U4(surface_desc).ddpfPixelFormat).dwStencilBitMask = tests[i].s_mask;
+ surface_desc.dwWidth = 640;
+ surface_desc.dwHeight = 480;
+ hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &ds, NULL);
+ if (FAILED(hr))
+ {
+ skip("Format %u not supported, skipping test.\n", i);
+ continue;
+ }
+
+ hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
+ ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
+ hr = IDirect3DDevice3_SetRenderTarget(device, rt, 0);
+ ok(SUCCEEDED(hr), "Failed to set render target, hr %#x.\n", hr);
+
+ hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect,
+ D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff0000ff, 1.0f, 0);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice3_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ | D3DFVF_DIFFUSE, quad, 4, 0);
+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+ hr = IDirect3DDevice3_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+
+ for (y = 60; y < 480; y += 120)
+ {
+ for (x = 80; x < 640; x += 160)
+ {
+ SetRect(&r, x, y, x + 1, y + 1);
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ hr = IDirectDrawSurface4_Lock(ds, &r, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
+ ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+
+ depth = *((DWORD *)surface_desc.lpSurface) & tests[i].z_mask;
+ expected_depth = (x * (0.9 / 640.0) + y * (0.1 / 480.0)) * tests[i].z_mask;
+ max_diff = ((0.5f * 0.9f) / 640.0f) * tests[i].z_mask;
+ todo_wine_if(tests[i].todo)
+ ok(abs(expected_depth - depth) <= max_diff,
+ "Test %u: Got depth 0x%08x (diff %d), expected 0x%08x+/-%u, at %u, %u.\n",
+ i, depth, expected_depth - depth, expected_depth, max_diff, x, y);
+
+ hr = IDirectDrawSurface4_Unlock(ds, &r);
+ ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+ }
+ }
+
+ hr = IDirectDrawSurface4_DeleteAttachedSurface(rt, 0, ds);
+ ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#x.\n", hr);
+ IDirectDrawSurface4_Release(ds);
+ }
+
+ destroy_viewport(device, viewport);
+ IDirectDrawSurface4_Release(rt);
+ IDirectDraw4_Release(ddraw);
+ IDirect3D3_Release(d3d);
+ refcount = IDirect3DDevice3_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw4)
{
DDDEVICEIDENTIFIER identifier;
@@ -14326,4 +14473,5 @@ START_TEST(ddraw4)
test_vb_refcount();
test_compute_sphere_visibility();
test_map_synchronisation();
+ test_depth_readback();
}
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index f776efaa33e..ce4117bf35e 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -13585,6 +13585,146 @@ done:
DestroyWindow(window);
}
+static void test_depth_readback(void)
+{
+ DWORD depth, expected_depth, max_diff;
+ IDirectDrawSurface7 *rt, *ds;
+ DDSURFACEDESC2 surface_desc;
+ IDirect3DDevice7 *device;
+ unsigned int i, x, y;
+ IDirectDraw7 *ddraw;
+ IDirect3D7 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ RECT r;
+
+ static struct
+ {
+ struct vec3 position;
+ DWORD diffuse;
+ }
+ quad[] =
+ {
+ {{-1.0f, -1.0f, 0.1f}, 0xff00ff00},
+ {{-1.0f, 1.0f, 0.0f}, 0xff00ff00},
+ {{ 1.0f, -1.0f, 1.0f}, 0xff00ff00},
+ {{ 1.0f, 1.0f, 0.9f}, 0xff00ff00},
+ };
+
+ static const struct
+ {
+ unsigned int z_depth, s_depth, z_mask, s_mask;
+ BOOL todo;
+ }
+ tests[] =
+ {
+ {16, 0, 0x0000ffff, 0x00000000},
+ {24, 0, 0x00ffffff, 0x00000000},
+ {32, 0, 0x00ffffff, 0x00000000},
+ {32, 8, 0x00ffffff, 0xff000000, TRUE},
+ {32, 0, 0xffffffff, 0x00000000},
+ };
+
+ window = create_window();
+ ok(!!window, "Failed to create a window.\n");
+
+ if (!(device = create_device(window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a D3D device, skipping tests.\n");
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
+ ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
+ hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
+ ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
+ ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
+
+ ds = get_depth_stencil(device);
+ hr = IDirectDrawSurface7_DeleteAttachedSurface(rt, 0, ds);
+ ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#x.\n", hr);
+ IDirectDrawSurface7_Release(ds);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
+ surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
+ U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
+ U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
+ if (tests[i].s_depth)
+ U4(surface_desc).ddpfPixelFormat.dwFlags |= DDPF_STENCILBUFFER;
+ U1(U4(surface_desc).ddpfPixelFormat).dwZBufferBitDepth = tests[i].z_depth;
+ U2(U4(surface_desc).ddpfPixelFormat).dwStencilBitDepth = tests[i].s_depth;
+ U3(U4(surface_desc).ddpfPixelFormat).dwZBitMask = tests[i].z_mask;
+ U4(U4(surface_desc).ddpfPixelFormat).dwStencilBitMask = tests[i].s_mask;
+ surface_desc.dwWidth = 640;
+ surface_desc.dwHeight = 480;
+ hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &ds, NULL);
+ if (FAILED(hr))
+ {
+ skip("Format %u not supported, skipping test.\n", i);
+ continue;
+ }
+
+ hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
+ ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
+ hr = IDirect3DDevice7_SetRenderTarget(device, rt, 0);
+ ok(SUCCEEDED(hr), "Failed to set render target, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff0000ff, 1.0f, 0);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice7_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DFVF_XYZ | D3DFVF_DIFFUSE, quad, 4, 0);
+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+ hr = IDirect3DDevice7_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+
+ for (y = 60; y < 480; y += 120)
+ {
+ for (x = 80; x < 640; x += 160)
+ {
+ SetRect(&r, x, y, x + 1, y + 1);
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ hr = IDirectDrawSurface7_Lock(ds, &r, &surface_desc, DDLOCK_READONLY, NULL);
+ ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+
+ depth = *((DWORD *)surface_desc.lpSurface) & tests[i].z_mask;
+ expected_depth = (x * (0.9 / 640.0) + y * (0.1 / 480.0)) * tests[i].z_mask;
+ max_diff = ((0.5f * 0.9f) / 640.0f) * tests[i].z_mask;
+ todo_wine_if(tests[i].todo)
+ ok(abs(expected_depth - depth) <= max_diff,
+ "Test %u: Got depth 0x%08x (diff %d), expected 0x%08x+/-%u, at %u, %u.\n",
+ i, depth, expected_depth - depth, expected_depth, max_diff, x, y);
+
+ hr = IDirectDrawSurface7_Unlock(ds, &r);
+ ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+ }
+ }
+
+ hr = IDirectDrawSurface7_DeleteAttachedSurface(rt, 0, ds);
+ ok(SUCCEEDED(hr), "Failed to detach depth buffer, hr %#x.\n", hr);
+ IDirectDrawSurface7_Release(ds);
+ }
+
+ IDirectDrawSurface7_Release(rt);
+ IDirectDraw7_Release(ddraw);
+ IDirect3D7_Release(d3d);
+ refcount = IDirect3DDevice7_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw7)
{
DDDEVICEIDENTIFIER2 identifier;
@@ -13714,4 +13854,5 @@ START_TEST(ddraw7)
test_compute_sphere_visibility();
test_clip_planes_limits();
test_map_synchronisation();
+ test_depth_readback();
}
--
2.11.0