[PATCH 6/6] d3d11/tests: Add visual tests for locking vertexbuffers

Patrick Rudolph siro at das-labor.org
Tue Jul 26 12:09:11 CDT 2016


Test flags D3D11_MAP_WRITE_NO_OVERWRITE and D3D11_MAP_WRITE_DISCARD
on staging and dynamic vertexbuffers. After submitting a draw call
the used vertexbuffer is mapped and modified. The visual result
changes depending on used flags. As this test depends on race conditions
the buffer size is calibrated first to allow the test to pass on
fast and slow machines.

Test have been done on the following test system:
* Nvidia Ion on Windows 7
* AMD Radeon Mobility HD4300 Series on Windows 7
* Nvidia Quadro NVS 140M on Windows 8

The test isn't reliable yet.

The flag D3D11_MAP_WRITE_NO_OVERWRITE has only effect on dynamic buffers.

Signed-off-by: Patrick Rudolph <siro at das-labor.org>
---
 dlls/d3d11/tests/d3d11.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 327 insertions(+)

diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index df45eb5..1663d74 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -7249,6 +7249,332 @@ done:
     ok(!refcount, "Device has %u references left.\n", refcount);
 }
 
+static void test_vb_lock_flags(void)
+{
+    D3D11_MAPPED_SUBRESOURCE mapped_subresource;
+    struct d3d11_test_context test_context;
+    D3D11_SUBRESOURCE_DATA resource_data;
+    ID3D11InputLayout *input_layout;
+    ID3D11DeviceContext *context;
+    D3D11_BUFFER_DESC buffer_desc;
+    DWORD color, primitives, size;
+    ULONG timestamp1, timestamp2;
+    unsigned int stride, offset;
+    ID3D11VertexShader *vs;
+    ID3D11PixelShader *ps;
+    ID3D11Device *device;
+    BOOL unsyncronized;
+    ID3D11Buffer *vb;
+    HRESULT hr;
+    int i;
+
+    static const struct {
+        const char* flags_s;
+        DWORD flags;
+        HRESULT hr;
+        BOOL unsyncronized;
+        BOOL todo;
+        BOOL broken;
+    } staging_tests[] =
+    {
+        {"0", 0, E_INVALIDARG, FALSE, TRUE, FALSE},
+        {"D3D11_MAP_WRITE", D3D11_MAP_WRITE, S_OK, FALSE, FALSE, FALSE},
+        {"D3D11_MAP_READ", D3D11_MAP_READ, S_OK, FALSE, FALSE, TRUE},
+        {"D3D11_MAP_READ_WRITE", D3D11_MAP_READ_WRITE, S_OK, FALSE, FALSE, FALSE},
+        {"D3D11_MAP_WRITE_DISCARD", D3D11_MAP_WRITE_DISCARD, E_INVALIDARG, FALSE, TRUE, FALSE},
+        {"D3D11_MAP_WRITE_NO_OVERWRITE", D3D11_MAP_WRITE_NO_OVERWRITE, E_INVALIDARG, FALSE, TRUE, FALSE},
+        {"D3D11_MAP_WRITE_DISCARD | D3D11_MAP_WRITE_NO_OVERWRITE",
+                D3D11_MAP_WRITE_DISCARD | D3D11_MAP_WRITE_NO_OVERWRITE, E_INVALIDARG, FALSE, TRUE, FALSE},
+    }, dynamic_tests[] =
+    {
+        {"0", 0, E_INVALIDARG, FALSE, TRUE, FALSE},
+        {"D3D11_MAP_WRITE", D3D11_MAP_WRITE, E_INVALIDARG, FALSE, TRUE, FALSE},
+        {"D3D11_MAP_READ", D3D11_MAP_READ, E_INVALIDARG, FALSE, TRUE, FALSE},
+        {"D3D11_MAP_READ_WRITE", D3D11_MAP_READ_WRITE, E_INVALIDARG, FALSE, TRUE, FALSE},
+        {"D3D11_MAP_WRITE_DISCARD", D3D11_MAP_WRITE_DISCARD, S_OK, FALSE, FALSE, FALSE},
+        {"D3D11_MAP_WRITE_NO_OVERWRITE", D3D11_MAP_WRITE_NO_OVERWRITE, S_OK, TRUE, FALSE, FALSE},
+        {"D3D11_MAP_WRITE_DISCARD | D3D11_MAP_WRITE_NO_OVERWRITE",
+                D3D11_MAP_WRITE_DISCARD | D3D11_MAP_WRITE_NO_OVERWRITE, S_OK, TRUE, FALSE, FALSE},
+    };
+
+    static const DWORD vs_code[] =
+    {
+#if 0
+        struct vs_out
+        {
+            float4 position : SV_POSITION;
+            float4 color : COLOR;
+        };
+
+        struct vs_out main(float4 position : POSITION, float4 color : COLOR)
+        {
+            struct vs_out o;
+
+            o.position = position;
+            o.color = color;
+
+            return o;
+        }
+#endif
+        0x43425844, 0x5c73b061, 0x5c71125f, 0x3f8b345f, 0xce04b9ab, 0x00000001, 0x00000140, 0x00000003,
+        0x0000002c, 0x0000007c, 0x000000d0, 0x4e475349, 0x00000048, 0x00000002, 0x00000008, 0x00000038,
+        0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00000041, 0x00000000, 0x00000000,
+        0x00000003, 0x00000001, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0x4c4f4300, 0xab00524f, 0x4e47534f,
+        0x0000004c, 0x00000002, 0x00000008, 0x00000038, 0x00000000, 0x00000001, 0x00000003, 0x00000000,
+        0x0000000f, 0x00000044, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x0000000f, 0x505f5653,
+        0x5449534f, 0x004e4f49, 0x4f4c4f43, 0xabab0052, 0x52444853, 0x00000068, 0x00010040, 0x0000001a,
+        0x0300005f, 0x001010f2, 0x00000000, 0x0300005f, 0x001010f2, 0x00000001, 0x04000067, 0x001020f2,
+        0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000001, 0x05000036, 0x001020f2, 0x00000000,
+        0x00101e46, 0x00000000, 0x05000036, 0x001020f2, 0x00000001, 0x00101e46, 0x00000001, 0x0100003e,
+    };
+    static const DWORD ps_code[] =
+    {
+#if 0
+        struct vs_out
+        {
+            float4 position : SV_POSITION;
+            float4 color : COLOR;
+        };
+
+        float4 main(struct vs_out i) : SV_TARGET
+        {
+            return i.color;
+        }
+#endif
+        0x43425844, 0xe2087fa6, 0xa35fbd95, 0x8e585b3f, 0x67890f54, 0x00000001, 0x000000f4, 0x00000003,
+        0x0000002c, 0x00000080, 0x000000b4, 0x4e475349, 0x0000004c, 0x00000002, 0x00000008, 0x00000038,
+        0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x00000044, 0x00000000, 0x00000000,
+        0x00000003, 0x00000001, 0x00000f0f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x4f4c4f43, 0xabab0052,
+        0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
+        0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x00000038, 0x00000040,
+        0x0000000e, 0x03001062, 0x001010f2, 0x00000001, 0x03000065, 0x001020f2, 0x00000000, 0x05000036,
+        0x001020f2, 0x00000000, 0x00101e46, 0x00000001, 0x0100003e,
+    };
+
+    struct quad
+    {
+        struct
+        {
+            struct vec3 position;
+            DWORD diffuse;
+        } strip[4];
+    };
+    static const struct quad 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;
+
+    static const D3D11_INPUT_ELEMENT_DESC layout_desc[] =
+    {
+        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0},
+        {"COLOR",    0, DXGI_FORMAT_R8G8B8A8_UNORM,  0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
+    };
+    static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+    if (!init_test_context(&test_context, NULL))
+        return;
+
+    device = test_context.device;
+    context = test_context.immediate_context;
+
+    hr = ID3D11Device_CreateInputLayout(device, layout_desc, sizeof(layout_desc) / sizeof(*layout_desc),
+            vs_code, sizeof(vs_code), &input_layout);
+    ok(SUCCEEDED(hr), "Failed to create input layout, hr %#x.\n", hr);
+
+    hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &vs);
+    ok(SUCCEEDED(hr), "Failed to create vertex shader, hr %#x.\n", hr);
+    hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &ps);
+    ok(SUCCEEDED(hr), "Failed to create pixel shader, hr %#x.\n", hr);
+
+    size = 0x1000;
+    /* Allocate memory to initialize the buffer */
+    resource_data.pSysMem = HeapAlloc(GetProcessHeap(), 0, size);
+    resource_data.SysMemPitch = 0;
+    resource_data.SysMemSlicePitch = 0;
+
+    if (!resource_data.pSysMem)
+        return;
+
+    quads = (void *)resource_data.pSysMem;
+    for (i = 0; i < size / sizeof(quad1); i++)
+        quads[i] = quad1;
+
+    /* Calculate number of primitives in buffer quads[] */
+    stride = sizeof(quad1.strip[0]);
+    primitives = size / stride;
+    offset = 0;
+
+    buffer_desc.ByteWidth = size;
+    buffer_desc.Usage = D3D11_USAGE_STAGING;
+    buffer_desc.BindFlags = 0;
+    buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
+    buffer_desc.MiscFlags = 0;
+    buffer_desc.StructureByteStride = 0;
+
+    /* calibrate vertexbuffer size to allow the test to pass on slow and fast systems */
+    hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &vb);
+    ok(SUCCEEDED(hr), "Failed to create vertexbuffer.\n");
+
+    ID3D11DeviceContext_IASetInputLayout(context, input_layout);
+    ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+    ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &vb, &stride, &offset);
+    ID3D11DeviceContext_VSSetShader(context, vs, NULL, 0);
+    ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0);
+
+    ID3D11DeviceContext_ClearRenderTargetView(context, test_context.backbuffer_rtv, black);
+
+    timestamp1 = GetTickCount();
+
+    ID3D11DeviceContext_Draw(context, primitives, 0);
+    /* dummy read to wait for GPU being done */
+    color = get_texture_color(test_context.backbuffer, 160, 360);
+
+    timestamp2 = GetTickCount();
+
+    /* Adjust buffer size for 1 second draw call duration */
+    size = (size * 1000UL) / (timestamp2 - timestamp1 + 1);
+
+    ID3D11Buffer_Release(vb);
+    HeapFree(GetProcessHeap(), 0, (void *)resource_data.pSysMem);
+
+    resource_data.pSysMem = HeapAlloc(GetProcessHeap(), 0, size);
+    if (!resource_data.pSysMem)
+        return;
+
+    quads = (void *)resource_data.pSysMem;
+    for (i = 0; i < size / sizeof(quad1); i++)
+        quads[i] = quad1;
+
+    /* Calculate number of primitives in buffer quads[] */
+    stride = sizeof(quad1.strip[0]);
+    primitives = size / stride;
+    offset = 0;
+
+    buffer_desc.ByteWidth = size;
+
+    for(i = 0; i < sizeof(staging_tests)/sizeof(staging_tests[0]); i++)
+    {
+        hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &vb);
+        ok(SUCCEEDED(hr), "Failed to create vertexbuffer.\n");
+
+        ID3D11DeviceContext_IASetInputLayout(context, input_layout);
+        ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+        ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &vb, &stride, &offset);
+        ID3D11DeviceContext_VSSetShader(context, vs, NULL, 0);
+        ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0);
+
+        ID3D11DeviceContext_ClearRenderTargetView(context, test_context.backbuffer_rtv, black);
+
+        ID3D11DeviceContext_Draw(context, primitives, 0);
+
+        /* Map the last quad while draw is in progress */
+        memset(&mapped_subresource, 0, sizeof(mapped_subresource));
+        hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)vb, 0, staging_tests[i].flags, 0, &mapped_subresource);
+        todo_wine_if (staging_tests[i].todo)
+            ok(hr == staging_tests[i].hr, "Got unexpected hr %#x. Flags = %s.\n", hr, staging_tests[i].flags_s);
+        if (SUCCEEDED(hr) && SUCCEEDED(staging_tests[i].hr))
+        {
+            ok(mapped_subresource.RowPitch == size, "Got unexpected row pitch %u.\n", mapped_subresource.RowPitch);
+            ok(mapped_subresource.DepthPitch == size, "Got unexpected depth pitch %u.\n",
+                    mapped_subresource.DepthPitch);
+
+            quads = mapped_subresource.pData;
+            quads[(size / sizeof(quad1)) - 1] = quad2;
+            ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)vb, 0);
+
+            color = get_texture_color(test_context.backbuffer, 160, 360);
+            unsyncronized = compare_color(color, 0xffffff00, 1);
+
+            todo_wine_if (staging_tests[i].todo)
+            {
+                ok((staging_tests[i].unsyncronized == unsyncronized) ||
+                        broken(staging_tests[i].broken),
+                        "Expected buffer mapped %s. Flags = %s. \n",
+                        staging_tests[i].unsyncronized ? "unsyncronized" : "syncronized",
+                        staging_tests[i].flags_s);
+            }
+        }
+        else if (SUCCEEDED(hr))
+        {
+            ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)vb, 0);
+        }
+        ID3D11Buffer_Release(vb);
+    }
+
+    buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
+    buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+    buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+    for(i = 0; i < sizeof(dynamic_tests)/sizeof(dynamic_tests[0]); i++)
+    {
+        hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &vb);
+        ok(SUCCEEDED(hr), "Failed to create vertexbuffer.\n");
+
+        ID3D11DeviceContext_IASetInputLayout(context, input_layout);
+        ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+        ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &vb, &stride, &offset);
+        ID3D11DeviceContext_VSSetShader(context, vs, NULL, 0);
+        ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0);
+
+        ID3D11DeviceContext_ClearRenderTargetView(context, test_context.backbuffer_rtv, black);
+
+        ID3D11DeviceContext_Draw(context, primitives, 0);
+
+        /* Map the last quad while draw is in progress */
+        memset(&mapped_subresource, 0, sizeof(mapped_subresource));
+        hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)vb, 0, dynamic_tests[i].flags, 0, &mapped_subresource);
+        todo_wine_if (dynamic_tests[i].todo)
+            ok(hr == dynamic_tests[i].hr, "Got unexpected hr %#x. Flags = %s.\n", hr, dynamic_tests[i].flags_s);
+        if (SUCCEEDED(hr) && SUCCEEDED(dynamic_tests[i].hr))
+        {
+            ok(mapped_subresource.RowPitch == size, "Got unexpected row pitch %u.\n", mapped_subresource.RowPitch);
+            ok(mapped_subresource.DepthPitch == size, "Got unexpected depth pitch %u.\n",
+                    mapped_subresource.DepthPitch);
+
+            quads = mapped_subresource.pData;
+            quads[(size / sizeof(quad1)) - 1] = quad2;
+            ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)vb, 0);
+
+            color = get_texture_color(test_context.backbuffer, 160, 360);
+            unsyncronized = compare_color(color, 0xffffff00, 1);
+
+            todo_wine_if (dynamic_tests[i].todo)
+            {
+                ok((dynamic_tests[i].unsyncronized == unsyncronized) ||
+                        broken(dynamic_tests[i].broken),
+                        "Expected buffer mapped %s. Flags = %s. \n",
+                        dynamic_tests[i].unsyncronized ? "unsyncronized" : "syncronized",
+                        dynamic_tests[i].flags_s);
+            }
+        }
+        else if (SUCCEEDED(hr))
+        {
+            ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)vb, 0);
+        }
+        ID3D11Buffer_Release(vb);
+    }
+
+    ID3D11PixelShader_Release(ps);
+    ID3D11VertexShader_Release(vs);
+    ID3D11InputLayout_Release(input_layout);
+    release_test_context(&test_context);
+    HeapFree(GetProcessHeap(), 0, (void *)resource_data.pSysMem);
+}
+
 static void test_texture_data_init(void)
 {
     static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
@@ -9808,4 +10134,5 @@ START_TEST(d3d11)
     test_immediate_constant_buffer();
     test_fp_specials();
     test_uint_shader_instructions();
+    test_vb_lock_flags();
 }
-- 
2.7.4




More information about the wine-patches mailing list