Based on a patch by Patrick Rudolph from a while ago.
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/d3d9/tests/visual.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 218 insertions(+)
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 55047d0f4b5..4a257c3e034 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -23044,6 +23044,223 @@ static void test_null_format(void)
IDirect3D9_Release(d3d);
}
+static void test_map_synchronisation(void)
+{
+ LARGE_INTEGER frequency, diff, ts[3];
+ unsigned int i, j, tri_count, size;
+ D3DADAPTER_IDENTIFIER9 identifier;
+ IDirect3DVertexBuffer9 *buffer;
+ IDirect3DDevice9 *device;
+ BOOL unsynchronised, ret;
+ IDirect3D9 *d3d;
+ D3DCOLOR colour;
+ ULONG refcount;
+ D3DCAPS9 caps;
+ HWND window;
+ HRESULT hr;
+
+ static const struct
+ {
+ unsigned int flags;
+ BOOL unsynchronised;
+ }
+ tests[] =
+ {
+ {0, FALSE},
+ {D3DLOCK_NOOVERWRITE, TRUE},
+ {D3DLOCK_DISCARD, FALSE},
+ {D3DLOCK_NOOVERWRITE | D3DLOCK_DISCARD, 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");
+
+ d3d = Direct3DCreate9(D3D_SDK_VERSION);
+ ok(!!d3d, "Failed to create a D3D object.\n");
+ if (!(device = create_device(d3d, window, window, TRUE)))
+ {
+ skip("Failed to create a D3D device, skipping tests.\n");
+ IDirect3D9_Release(d3d);
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3D9_GetAdapterIdentifier(d3d, D3DADAPTER_DEFAULT, 0, &identifier);
+ ok(SUCCEEDED(hr), "Failed to get adapter identifier, hr %#x.\n", hr);
+ /* Maps are always synchronised on WARP. */
+ if (adapter_is_warp(&identifier))
+ {
+ skip("Running on WARP, skipping test.\n");
+ goto done;
+ }
+
+ hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+ ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
+
+ tri_count = 0x1000;
+ if (tri_count > caps.MaxPrimitiveCount)
+ {
+ skip("Device supports only %u primitives, skipping test.\n", caps.MaxPrimitiveCount);
+ goto done;
+ }
+ size = (tri_count + 2) * sizeof(*quad1.strip);
+
+ ret = QueryPerformanceFrequency(&frequency);
+ ok(ret, "Failed to get performance counter frequency.\n");
+
+ hr = IDirect3DDevice9_CreateVertexBuffer(device, size,
+ D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &buffer, NULL);
+ ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
+ hr = IDirect3DVertexBuffer9_Lock(buffer, 0, size, (void **)&quads, D3DLOCK_DISCARD);
+ ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
+ for (j = 0; j < size / sizeof(*quads); ++j)
+ {
+ quads[j] = quad1;
+ }
+ hr = IDirect3DVertexBuffer9_Unlock(buffer);
+ ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE);
+ ok(SUCCEEDED(hr), "Failed to set FVF, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_SetStreamSource(device, 0, buffer, 0, sizeof(*quads->strip));
+ ok(SUCCEEDED(hr), "Failed to set stream source, hr %#x.\n", hr);
+
+ /* Initial draw to initialise states, compile shaders, etc. */
+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.0f, 0);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, tri_count);
+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+ /* Read the result to ensure the GPU has finished drawing. */
+ colour = getPixelColor(device, 320, 240);
+
+ /* Time drawing tri_count triangles. */
+ ret = QueryPerformanceCounter(&ts[0]);
+ ok(ret, "Failed to read performance counter.\n");
+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.0f, 0);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, tri_count);
+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+ colour = getPixelColor(device, 320, 240);
+ /* Time drawing a single triangle. */
+ ret = QueryPerformanceCounter(&ts[1]);
+ ok(ret, "Failed to read performance counter.\n");
+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.0f, 0);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, 1);
+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+ colour = getPixelColor(device, 320, 240);
+ ret = QueryPerformanceCounter(&ts[2]);
+ ok(ret, "Failed to read performance counter.\n");
+
+ IDirect3DVertexBuffer9_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;
+ if (tri_count > caps.MaxPrimitiveCount)
+ {
+ skip("Would need to draw %u triangles, but the device only supports %u primitives.\n",
+ tri_count, caps.MaxPrimitiveCount);
+ goto done;
+ }
+ size = (tri_count + 2) * sizeof(*quad1.strip);
+
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
+ {
+ hr = IDirect3DDevice9_CreateVertexBuffer(device, size,
+ D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &buffer, NULL);
+ ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
+ hr = IDirect3DVertexBuffer9_Lock(buffer, 0, size, (void **)&quads, D3DLOCK_DISCARD);
+ ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
+ for (j = 0; j < size / sizeof(*quads); ++j)
+ {
+ quads[j] = quad1;
+ }
+ hr = IDirect3DVertexBuffer9_Unlock(buffer);
+ ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice9_SetStreamSource(device, 0, buffer, 0, sizeof(*quads->strip));
+ ok(SUCCEEDED(hr), "Failed to set stream source, hr %#x.\n", hr);
+
+ /* Start a draw operation. */
+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0xff0000ff, 0.0f, 0);
+ ok(SUCCEEDED(hr), "Failed to clear, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_BeginScene(device);
+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, tri_count);
+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+ hr = IDirect3DDevice9_EndScene(device);
+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+
+ /* Map the last quad while the draw is in progress. */
+ hr = IDirect3DVertexBuffer9_Lock(buffer, size - sizeof(quad2),
+ sizeof(quad2), (void **)&quads, tests[i].flags);
+ ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
+ *quads = quad2;
+ hr = IDirect3DVertexBuffer9_Unlock(buffer);
+ ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
+
+ colour = getPixelColor(device, 320, 240);
+ unsynchronised = color_match(colour, D3DCOLOR_ARGB(0x00, 0xff, 0xff, 0x00), 1);
+ ok(tests[i].unsynchronised == unsynchronised, "Expected %s map for flags %#x.\n",
+ tests[i].unsynchronised ? "unsynchronised" : "synchronised", tests[i].flags);
+
+ hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+ ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
+
+ IDirect3DVertexBuffer9_Release(buffer);
+ }
+
+done:
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ IDirect3D9_Release(d3d);
+ DestroyWindow(window);
+}
+
START_TEST(visual)
{
D3DADAPTER_IDENTIFIER9 identifier;
@@ -23176,4 +23393,5 @@ START_TEST(visual)
test_vertex_texture();
test_mvp_software_vertex_shaders();
test_null_format();
+ test_map_synchronisation();
}
--
2.11.0