[PATCH 1/2] d3d9/tests/visual: Add Vertexbuffer locking tests

Patrick Rudolph siro at das-labor.org
Fri Jul 8 11:15:51 CDT 2016


Test flags D3DLOCK_NOOVERWRITE and D3DLOCK_DISCARD on POOL_DEFAULT
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
(and primitive count) is incremented a few times.

The results have been verified on Windows 7 and
AMD Radeon Mobility HD4300 Series.

Given D3DLOCK_NOOVERWRITE the flag D3DLOCK_DISCARD has no effect.
The flag D3DLOCK_NOOVERWRITE works on both DYNAMIC and non-DYNAMIC
buffers.

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

diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index a2adc54..58d8caf 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -4309,6 +4309,283 @@ done:
     DestroyWindow(window);
 }
 
+static void test_vb_lock_flags(void)
+{
+    IDirect3DVertexBuffer9 *buffer;
+    IDirect3DDevice9 *device;
+    IDirect3D9 *d3d9;
+    DWORD i, j, tri, quads;
+    HWND window;
+    HRESULT hr;
+    ULONG size;
+    unsigned refcount;
+    D3DCOLOR color;
+    BOOL unsyncronized;
+    D3DCAPS9 caps;
+    BOOL res;
+
+    static const struct
+    {
+        const char *flags_s;
+        unsigned int flags;
+        BOOL dynamic;
+        BOOL unsyncronized;
+        BOOL todo;
+    }
+    tests[] =
+    {
+        {
+            "0",
+            0,
+            FALSE,
+            FALSE
+        },
+        {
+            "0",
+            0,
+            TRUE,
+            FALSE
+        },
+        {
+            "D3DLOCK_NOOVERWRITE",
+            D3DLOCK_NOOVERWRITE,
+            FALSE,
+            TRUE,
+            TRUE
+        },
+        {
+            "D3DLOCK_NOOVERWRITE",
+            D3DLOCK_NOOVERWRITE,
+            TRUE,
+            TRUE,
+            FALSE
+        },
+        {
+            "D3DLOCK_DISCARD",
+            D3DLOCK_DISCARD,
+            FALSE,
+            FALSE,
+            FALSE
+        },
+        {
+            "D3DLOCK_DISCARD",
+            D3DLOCK_DISCARD,
+            TRUE,
+            FALSE,
+            FALSE
+        },
+        {
+            "D3DLOCK_NOOVERWRITE | D3DLOCK_DISCARD",
+            D3DLOCK_NOOVERWRITE | D3DLOCK_DISCARD,
+            FALSE,
+            TRUE,
+            TRUE
+        },
+        {
+            "D3DLOCK_NOOVERWRITE | D3DLOCK_DISCARD",
+            D3DLOCK_NOOVERWRITE | D3DLOCK_DISCARD,
+            TRUE,
+            TRUE,
+            TRUE
+        }
+    };
+
+    static struct
+    {
+        struct
+        {
+            struct vec3 position;
+            DWORD diffuse;
+        } strip[4];
+    }
+    *quad_strip_array, quad_strip1 =
+    {
+        {
+            {{-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},
+        }
+    },
+    quad_strip2 =
+    {
+        {
+            {{-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},
+        }
+    };
+
+    window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+            0, 0, 640, 480, NULL, NULL, NULL, NULL);
+    ok(!!window, "Failed to create a window.\n");
+
+    d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+    ok(!!d3d9, "Failed to create a D3D object.\n");
+    if (!(device = create_device(d3d9, window, window, TRUE)))
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        IDirect3D9_Release(d3d9);
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+    ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
+    ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %08x\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGENABLE, FALSE);
+    ok(SUCCEEDED(hr), "Failed to disable fog, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE);
+    ok(hr == D3D_OK, "IDirect3DDevice9_SetFVF failed with %08x\n", hr);
+
+    /* sanity check */
+    hr = IDirect3DDevice9_CreateVertexBuffer(device, sizeof(quad_strip1), 0, 0, D3DPOOL_DEFAULT, &buffer, NULL);
+    ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
+
+    /* place test data */
+    hr = IDirect3DVertexBuffer9_Lock(buffer, 0, sizeof(quad_strip1), (void **)&quad_strip_array, 0);
+    ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
+    if (!SUCCEEDED(hr))
+    {
+        skip("Failed to create a vertex buffer object.\n");
+        return;
+    }
+    quad_strip_array[0] = quad_strip1;
+
+    hr = IDirect3DVertexBuffer9_Unlock(buffer);
+    ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetStreamSource(device, 0, buffer, 0, sizeof(quad_strip1.strip[0]));
+    ok(hr == D3D_OK, "Failed to set stream source, hr %#x.\n", hr);
+
+    /* draw a quad to make use of the bound buffer */
+    hr = IDirect3DDevice9_BeginScene(device);
+    ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+    hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, 2);
+    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);
+
+    color = getPixelColor(device, 160, 360);
+    res = color_match(color, D3DCOLOR_ARGB(0x00, 0x80, 0x40, 0x40), 1);
+    ok(res, "Unexpected color %#x.\n", color);
+
+    IDirect3DVertexBuffer9_Release(buffer);
+
+    if (!res)
+    {
+        skip("Sanity check failed.\n");
+        return;
+    }
+
+    for (i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i)
+    {
+        unsyncronized = FALSE;
+
+        /* Increase triangle draw count for faster GPUs.
+          Limit size to 0x40000 as bigger values causes the Nvidia driver to crash. */
+        for (size = 0x1000; size <= 0x10000; size <<= 1)
+        {
+            /* calculate triangle count */
+            tri = (size / sizeof(quad_strip1.strip[0])) - 2;
+            if (tri > caps.MaxPrimitiveCount)
+                break;
+
+            quads = size / sizeof(quad_strip1);
+
+            if (tests[i].dynamic)
+                hr = IDirect3DDevice9_CreateVertexBuffer(device, size, D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &buffer, NULL);
+            else
+                hr = IDirect3DDevice9_CreateVertexBuffer(device, size, 0, 0, D3DPOOL_DEFAULT, &buffer, NULL);
+            ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
+            if (!SUCCEEDED(hr))
+                continue;
+
+            /* place quads */
+            hr = IDirect3DVertexBuffer9_Lock(buffer, 0, size, (void **)&quad_strip_array, 0);
+            ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
+            if (!SUCCEEDED(hr) || !quad_strip_array)
+            {
+                IDirect3DVertexBuffer9_Release(buffer);
+                continue;
+            }
+            for (j = 0; j < quads; j++)
+                quad_strip_array[j] = quad_strip1;
+
+            hr = IDirect3DVertexBuffer9_Unlock(buffer);
+            ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
+
+            hr = IDirect3DDevice9_SetStreamSource(device, 0, buffer, 0, sizeof(quad_strip1.strip[0]));
+            ok(hr == D3D_OK, "Failed to set stream source, hr %#x.\n", hr);
+
+            /* draw a quad to make use of the bound buffer */
+            hr = IDirect3DDevice9_BeginScene(device);
+            ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+            hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, tri);
+            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 draw is in progress */
+            hr = IDirect3DVertexBuffer9_Lock(buffer, (quads - 1) * sizeof(quad_strip1), sizeof(quad_strip1), (void **)&quad_strip_array, tests[i].flags);
+            ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
+            if (!SUCCEEDED(hr) || !quad_strip_array)
+            {
+                IDirect3DVertexBuffer9_Release(buffer);
+                continue;
+            }
+
+            /* Replace last quad with yellow quad */
+            quad_strip_array[0] = quad_strip2;
+
+            hr = IDirect3DVertexBuffer9_Unlock(buffer);
+            ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
+
+            /* Test if last triangle has different color */
+            color = getPixelColor(device, 160, 360);
+            unsyncronized |= color_match(color, D3DCOLOR_ARGB(0x00, 0xff, 0xff, 0x00), 1);
+
+            hr = IDirect3DVertexBuffer9_Lock(buffer, (quads - 1) * sizeof(quad_strip1), sizeof(quad_strip1), (void **)&quad_strip_array, D3DLOCK_READONLY);
+            ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#x.\n", hr);
+            if (!SUCCEEDED(hr) || !quad_strip_array)
+            {
+                IDirect3DVertexBuffer9_Release(buffer);
+                continue;
+            }
+
+            hr = IDirect3DVertexBuffer9_Unlock(buffer);
+            ok(SUCCEEDED(hr), "Failed to unlock vertex buffer, hr %#x.\n", hr);
+
+            IDirect3DVertexBuffer9_Release(buffer);
+
+            hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+            ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
+
+            if (tests[i].unsyncronized == unsyncronized)
+                break;
+        }
+        if (tests[i].todo)
+        {
+            todo_wine ok(tests[i].unsyncronized == unsyncronized, "Expected buffer mapped %s. Flags = %s. Dynamic = %d.\n",
+                tests[i].unsyncronized ? "unsyncronized" : "syncronized", tests[i].flags_s, tests[i].dynamic);
+        }
+        else
+        {
+            ok(tests[i].unsyncronized == unsyncronized, "Expected buffer mapped %s. Flags = %s. Dynamic = %d.\n",
+                tests[i].unsyncronized ? "unsyncronized" : "syncronized", tests[i].flags_s, tests[i].dynamic);
+        }
+    }
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    IDirect3D9_Release(d3d9);
+    DestroyWindow(window);
+}
+
 static void release_buffer_test(void)
 {
     IDirect3DVertexBuffer9 *vb;
@@ -21794,4 +22071,5 @@ START_TEST(visual)
     test_multisample_init();
     test_texture_blending();
     test_color_clamping();
+    test_vb_lock_flags();
 }
-- 
2.7.4




More information about the wine-patches mailing list