Based on a patch by Patrick Rudolph from a while ago.
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com --- dlls/ddraw/tests/ddraw4.c | 197 +++++++++++++++++++++++++++++++++++++++++++++ dlls/ddraw/tests/ddraw7.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 396 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index b280628f567..c86fcc58851 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -14011,6 +14011,202 @@ static void test_compute_sphere_visibility(void) DestroyWindow(window); }
+static void test_map_synchronisation(void) +{ + LARGE_INTEGER frequency, diff, ts[3]; + IDirect3DVertexBuffer *buffer; + IDirect3DViewport3 *viewport; + unsigned int i, j, tri_count; + D3DVERTEXBUFFERDESC vb_desc; + IDirect3DDevice3 *device; + BOOL unsynchronised, ret; + IDirectDrawSurface4 *rt; + IDirect3D3 *d3d; + D3DCOLOR colour; + ULONG refcount; + HWND window; + HRESULT hr; + + static D3DRECT clear_rect = {{0}, {0}, {640}, {480}}; + + /* DDLOCK_DISCARDCONTENTS and DDLOCK_NOOVERWRITE were introduced with + * ddraw7 and are ignored in earlier versions. */ + static const struct + { + unsigned int flags; + BOOL unsynchronised; + } + tests[] = + { + {0, FALSE}, + {DDLOCK_NOOVERWRITE, FALSE}, + {DDLOCK_DISCARDCONTENTS, FALSE}, + {DDLOCK_NOOVERWRITE | DDLOCK_DISCARDCONTENTS, FALSE}, + }; + + static const struct quad + { + struct + { + struct vec3 position; + DWORD diffuse; + } strip[4]; + } + quad1 = + { + { + {{-1.0f, -1.0f, 0.0f}, 0xffff0000}, + {{-1.0f, 1.0f, 0.0f}, 0xff00ff00}, + {{ 1.0f, -1.0f, 0.0f}, 0xff0000ff}, + {{ 1.0f, 1.0f, 0.0f}, 0xffffffff}, + } + }, + quad2 = + { + { + {{-1.0f, -1.0f, 0.0f}, 0xffffff00}, + {{-1.0f, 1.0f, 0.0f}, 0xffffff00}, + {{ 1.0f, -1.0f, 0.0f}, 0xffffff00}, + {{ 1.0f, 1.0f, 0.0f}, 0xffffff00}, + } + }; + struct quad *quads; + + 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 = 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); + + tri_count = 0x1000; + + ret = QueryPerformanceFrequency(&frequency); + ok(ret, "Failed to get performance counter frequency.\n"); + + vb_desc.dwSize = sizeof(vb_desc); + vb_desc.dwCaps = D3DVBCAPS_WRITEONLY; + vb_desc.dwFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE; + vb_desc.dwNumVertices = tri_count + 2; + hr = IDirect3D3_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0, NULL); + ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr); + hr = IDirect3DVertexBuffer_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&quads, NULL); + ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr); + for (j = 0; j < vb_desc.dwNumVertices / 4; ++j) + { + quads[j] = quad1; + } + hr = IDirect3DVertexBuffer_Unlock(buffer); + ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr); + + hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE); + ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); + + /* Initial draw to initialise states, compile shaders, etc. */ + hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, vb_desc.dwNumVertices, 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); + /* Read the result to ensure the GPU has finished drawing. */ + colour = get_surface_color(rt, 320, 240); + + /* Time drawing tri_count triangles. */ + ret = QueryPerformanceCounter(&ts[0]); + ok(ret, "Failed to read performance counter.\n"); + hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, vb_desc.dwNumVertices, 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); + colour = get_surface_color(rt, 320, 240); + /* Time drawing a single triangle. */ + ret = QueryPerformanceCounter(&ts[1]); + ok(ret, "Failed to read performance counter.\n"); + hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, 3, 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); + colour = get_surface_color(rt, 320, 240); + ret = QueryPerformanceCounter(&ts[2]); + ok(ret, "Failed to read performance counter.\n"); + + IDirect3DVertexBuffer_Release(buffer); + + /* Estimate the number of triangles we can draw in 100ms. */ + diff.QuadPart = ts[1].QuadPart - ts[0].QuadPart + ts[1].QuadPart - ts[2].QuadPart; + tri_count = (tri_count * frequency.QuadPart) / (diff.QuadPart * 10); + tri_count = ((tri_count + 2 + 3) & ~3) - 2; + vb_desc.dwNumVertices = tri_count + 2; + + for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i) + { + hr = IDirect3D3_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0, NULL); + ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr); + hr = IDirect3DVertexBuffer_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&quads, NULL); + ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr); + for (j = 0; j < vb_desc.dwNumVertices / 4; ++j) + { + quads[j] = quad1; + } + hr = IDirect3DVertexBuffer_Unlock(buffer); + ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr); + + /* Start a draw operation. */ + hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, vb_desc.dwNumVertices, 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); + + /* Map the last quad while the draw is in progress. */ + hr = IDirect3DVertexBuffer_Lock(buffer, DDLOCK_WAIT | tests[i].flags, (void **)&quads, NULL); + ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr); + quads[(vb_desc.dwNumVertices / 4) - 1] = quad2; + hr = IDirect3DVertexBuffer_Unlock(buffer); + ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr); + + colour = get_surface_color(rt, 320, 240); + unsynchronised = compare_color(colour, 0x00ffff00, 1); + ok(tests[i].unsynchronised == unsynchronised, "Expected %s map for flags %#x.\n", + tests[i].unsynchronised ? "unsynchronised" : "synchronised", tests[i].flags); + + IDirect3DVertexBuffer_Release(buffer); + } + + destroy_viewport(device, viewport); + IDirectDrawSurface4_Release(rt); + IDirect3D3_Release(d3d); + refcount = IDirect3DDevice3_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); + DestroyWindow(window); +} + START_TEST(ddraw4) { DDDEVICEIDENTIFIER identifier; @@ -14129,4 +14325,5 @@ START_TEST(ddraw4) test_ck_operation(); test_vb_refcount(); test_compute_sphere_visibility(); + test_map_synchronisation(); } diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index 846a83de08e..f776efaa33e 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -13387,6 +13387,204 @@ static void test_clip_planes_limits(void) DestroyWindow(window); }
+static void test_map_synchronisation(void) +{ + LARGE_INTEGER frequency, diff, ts[3]; + IDirect3DVertexBuffer7 *buffer; + unsigned int i, j, tri_count; + D3DVERTEXBUFFERDESC vb_desc; + IDirect3DDevice7 *device; + BOOL unsynchronised, ret; + IDirectDrawSurface7 *rt; + IDirectDraw7 *ddraw; + IDirect3D7 *d3d; + D3DCOLOR colour; + ULONG refcount; + HWND window; + HRESULT hr; + + static const struct + { + unsigned int flags; + BOOL unsynchronised; + } + tests[] = + { + {0, FALSE}, + {DDLOCK_NOOVERWRITE, TRUE}, + {DDLOCK_DISCARDCONTENTS, FALSE}, + {DDLOCK_NOOVERWRITE | DDLOCK_DISCARDCONTENTS, TRUE}, + }; + + static const struct quad + { + struct + { + struct vec3 position; + DWORD diffuse; + } strip[4]; + } + quad1 = + { + { + {{-1.0f, -1.0f, 0.0f}, 0xffff0000}, + {{-1.0f, 1.0f, 0.0f}, 0xff00ff00}, + {{ 1.0f, -1.0f, 0.0f}, 0xff0000ff}, + {{ 1.0f, 1.0f, 0.0f}, 0xffffffff}, + } + }, + quad2 = + { + { + {{-1.0f, -1.0f, 0.0f}, 0xffffff00}, + {{-1.0f, 1.0f, 0.0f}, 0xffffff00}, + {{ 1.0f, -1.0f, 0.0f}, 0xffffff00}, + {{ 1.0f, 1.0f, 0.0f}, 0xffffff00}, + } + }; + struct quad *quads; + + 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); + /* Maps are always synchronised on WARP. */ + if (ddraw_is_warp(ddraw)) + { + skip("Running on WARP, skipping test.\n"); + goto done; + } + + hr = IDirect3DDevice7_GetRenderTarget(device, &rt); + ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr); + + tri_count = 0x1000; + + ret = QueryPerformanceFrequency(&frequency); + ok(ret, "Failed to get performance counter frequency.\n"); + + vb_desc.dwSize = sizeof(vb_desc); + vb_desc.dwCaps = D3DVBCAPS_WRITEONLY; + vb_desc.dwFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE; + vb_desc.dwNumVertices = tri_count + 2; + hr = IDirect3D7_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0); + ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr); + hr = IDirect3DVertexBuffer7_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&quads, NULL); + ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr); + for (j = 0; j < vb_desc.dwNumVertices / 4; ++j) + { + quads[j] = quad1; + } + hr = IDirect3DVertexBuffer7_Unlock(buffer); + ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr); + + hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE); + ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); + + /* Initial draw to initialise states, compile shaders, etc. */ + hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, vb_desc.dwNumVertices, 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); + /* Read the result to ensure the GPU has finished drawing. */ + colour = get_surface_color(rt, 320, 240); + + /* Time drawing tri_count triangles. */ + ret = QueryPerformanceCounter(&ts[0]); + ok(ret, "Failed to read performance counter.\n"); + hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, vb_desc.dwNumVertices, 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); + colour = get_surface_color(rt, 320, 240); + /* Time drawing a single triangle. */ + ret = QueryPerformanceCounter(&ts[1]); + ok(ret, "Failed to read performance counter.\n"); + hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, 3, 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); + colour = get_surface_color(rt, 320, 240); + ret = QueryPerformanceCounter(&ts[2]); + ok(ret, "Failed to read performance counter.\n"); + + IDirect3DVertexBuffer7_Release(buffer); + + /* Estimate the number of triangles we can draw in 100ms. */ + diff.QuadPart = ts[1].QuadPart - ts[0].QuadPart + ts[1].QuadPart - ts[2].QuadPart; + tri_count = (tri_count * frequency.QuadPart) / (diff.QuadPart * 10); + tri_count = ((tri_count + 2 + 3) & ~3) - 2; + vb_desc.dwNumVertices = tri_count + 2; + + for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i) + { + hr = IDirect3D7_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0); + ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr); + hr = IDirect3DVertexBuffer7_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&quads, NULL); + ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr); + for (j = 0; j < vb_desc.dwNumVertices / 4; ++j) + { + quads[j] = quad1; + } + hr = IDirect3DVertexBuffer7_Unlock(buffer); + ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr); + + /* Start a draw operation. */ + hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.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_DrawPrimitiveVB(device, D3DPT_TRIANGLESTRIP, buffer, 0, vb_desc.dwNumVertices, 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); + + /* Map the last quad while the draw is in progress. */ + hr = IDirect3DVertexBuffer7_Lock(buffer, DDLOCK_WAIT | tests[i].flags, (void **)&quads, NULL); + ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr); + quads[(vb_desc.dwNumVertices / 4) - 1] = quad2; + hr = IDirect3DVertexBuffer7_Unlock(buffer); + ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr); + + colour = get_surface_color(rt, 320, 240); + unsynchronised = compare_color(colour, 0x00ffff00, 1); + ok(tests[i].unsynchronised == unsynchronised, "Expected %s map for flags %#x.\n", + tests[i].unsynchronised ? "unsynchronised" : "synchronised", tests[i].flags); + + IDirect3DVertexBuffer7_Release(buffer); + } + + IDirectDrawSurface7_Release(rt); +done: + 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; @@ -13515,4 +13713,5 @@ START_TEST(ddraw7) test_vb_refcount(); test_compute_sphere_visibility(); test_clip_planes_limits(); + test_map_synchronisation(); }