Signed-off-by: Henri Verbeet hverbeet@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(); }