ddraw/tests: Introduce a test for vertex buffer map synchronisation.

Based on a patch by Patrick Rudolph from a while ago.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2018-01-03 16:06:57 +01:00 committed by Alexandre Julliard
parent 3037097198
commit 5aefc4e3c9
2 changed files with 396 additions and 0 deletions

View File

@ -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();
}

View File

@ -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();
}