[PATCH 1/6] d3d11/tests: Add a test for image UAV clears.

Henri Verbeet hverbeet at codeweavers.com
Mon Jun 7 09:55:07 CDT 2021


Ported from the similar Direct3D 12 test in vkd3d.

Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/d3d11/tests/d3d11.c | 329 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 329 insertions(+)

diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index fc0da439173..217b4870e53 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -102,6 +102,22 @@ struct device_desc
     UINT flags;
 };
 
+struct resource_desc
+{
+    D3D11_RESOURCE_DIMENSION dimension;
+    unsigned int width;
+    unsigned int height;
+    unsigned int depth_or_array_size;
+    unsigned int level_count;
+    DXGI_FORMAT format;
+    DXGI_SAMPLE_DESC sample_desc;
+    D3D11_USAGE usage;
+    unsigned int bind_flags;
+    unsigned int cpu_access_flags;
+    unsigned int misc_flags;
+    unsigned int structure_byte_stride;
+};
+
 struct swapchain_desc
 {
     BOOL windowed;
@@ -771,6 +787,66 @@ static ID3D11Buffer *create_buffer_(unsigned int line, ID3D11Device *device,
     return buffer;
 }
 
+static HRESULT create_resource(ID3D11Device *device, const struct resource_desc *desc,
+        const D3D11_SUBRESOURCE_DATA *data, ID3D11Resource **resource)
+{
+    D3D11_TEXTURE1D_DESC texture1d_desc;
+    D3D11_TEXTURE2D_DESC texture2d_desc;
+    D3D11_TEXTURE3D_DESC texture3d_desc;
+    D3D11_BUFFER_DESC buffer_desc;
+
+    switch (desc->dimension)
+    {
+        case D3D11_RESOURCE_DIMENSION_BUFFER:
+            buffer_desc.ByteWidth = desc->width;
+            buffer_desc.Usage = desc->usage;
+            buffer_desc.BindFlags = desc->bind_flags;
+            buffer_desc.CPUAccessFlags = desc->cpu_access_flags;
+            buffer_desc.MiscFlags = desc->misc_flags;
+            buffer_desc.StructureByteStride = desc->structure_byte_stride;
+            return ID3D11Device_CreateBuffer(device, &buffer_desc, data, (ID3D11Buffer **)resource);
+
+        case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
+            texture1d_desc.Width = desc->width;
+            texture1d_desc.MipLevels = desc->level_count;
+            texture1d_desc.ArraySize = desc->depth_or_array_size;
+            texture1d_desc.Format = desc->format;
+            texture1d_desc.Usage = desc->usage;
+            texture1d_desc.BindFlags = desc->bind_flags;
+            texture1d_desc.CPUAccessFlags = desc->cpu_access_flags;
+            texture1d_desc.MiscFlags = desc->misc_flags;
+            return ID3D11Device_CreateTexture1D(device, &texture1d_desc, data, (ID3D11Texture1D **)resource);
+
+        case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
+            texture2d_desc.Width = desc->width;
+            texture2d_desc.Height = desc->height;
+            texture2d_desc.MipLevels = desc->level_count;
+            texture2d_desc.ArraySize = desc->depth_or_array_size;
+            texture2d_desc.Format = desc->format;
+            texture2d_desc.SampleDesc = desc->sample_desc;
+            texture2d_desc.Usage = desc->usage;
+            texture2d_desc.BindFlags = desc->bind_flags;
+            texture2d_desc.CPUAccessFlags = desc->cpu_access_flags;
+            texture2d_desc.MiscFlags = desc->misc_flags;
+            return ID3D11Device_CreateTexture2D(device, &texture2d_desc, data, (ID3D11Texture2D **)resource);
+
+        case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
+            texture3d_desc.Width = desc->width;
+            texture3d_desc.Height = desc->height;
+            texture3d_desc.Depth = desc->depth_or_array_size;
+            texture3d_desc.MipLevels = desc->level_count;
+            texture3d_desc.Format = desc->format;
+            texture3d_desc.Usage = desc->usage;
+            texture3d_desc.BindFlags = desc->bind_flags;
+            texture3d_desc.CPUAccessFlags = desc->cpu_access_flags;
+            texture3d_desc.MiscFlags = desc->misc_flags;
+            return ID3D11Device_CreateTexture3D(device, &texture3d_desc, data, (ID3D11Texture3D **)resource);
+
+        default:
+            return E_INVALIDARG;
+    }
+}
+
 struct resource_readback
 {
     ID3D11Resource *resource;
@@ -936,6 +1012,36 @@ static void get_texture3d_readback(ID3D11Texture3D *texture, unsigned int sub_re
     ID3D11Device_Release(device);
 }
 
+static void get_resource_readback(ID3D11Resource *resource,
+        unsigned int sub_resource_idx, struct resource_readback *rb)
+{
+    D3D11_RESOURCE_DIMENSION d;
+
+    ID3D11Resource_GetType(resource, &d);
+    switch (d)
+    {
+        case D3D11_RESOURCE_DIMENSION_BUFFER:
+            get_buffer_readback((ID3D11Buffer *)resource, rb);
+            return;
+
+        case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
+            get_texture1d_readback((ID3D11Texture1D *)resource, sub_resource_idx, rb);
+            return;
+
+        case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
+            get_texture_readback((ID3D11Texture2D *)resource, sub_resource_idx, rb);
+            return;
+
+        case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
+            get_texture3d_readback((ID3D11Texture3D *)resource, sub_resource_idx, rb);
+            return;
+
+        default:
+            memset(rb, 0, sizeof(*rb));
+            return;
+    }
+}
+
 static void *get_readback_data(struct resource_readback *rb,
         unsigned int x, unsigned int y, unsigned int z, unsigned byte_width)
 {
@@ -16314,6 +16420,228 @@ static void test_clear_buffer_unordered_access_view(void)
     ok(!refcount, "Device has %u references left.\n", refcount);
 }
 
+static void test_clear_image_unordered_access_view(void)
+{
+    unsigned int expected_colour, actual_colour;
+    D3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc;
+    unsigned int i, j, d, p, x, y, z, layer;
+    struct d3d11_test_context test_context;
+    unsigned int image_size, image_depth;
+    struct resource_desc resource_desc;
+    ID3D11UnorderedAccessView *uav[2];
+    ID3D11DeviceContext *context;
+    struct resource_readback rb;
+    BOOL is_small_float_format;
+    ID3D11Resource *resource;
+    BOOL is_inside, success;
+    ID3D11Device *device;
+    UINT clear_value[4];
+    HRESULT hr;
+
+#define IMAGE_SIZE 16
+    static const struct
+    {
+        DXGI_FORMAT format;
+        unsigned int image_mips;
+        unsigned int image_layers;
+        unsigned int mip_level;
+        unsigned int first_layer;
+        unsigned int layer_count;
+        unsigned int values[4];
+        unsigned int expected;
+        BOOL is_float;
+        unsigned int clamped;
+        BOOL is_todo;
+    }
+    tests[] =
+    {
+        /* Test clearing a specific mip level. */
+        {DXGI_FORMAT_R32_FLOAT,       2, 1, 0, 0, 1, {1,          0, 0, 0}, 0x00000001, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R32_FLOAT,       2, 1, 1, 0, 1, {1,          0, 0, 0}, 0x00000001, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R32_FLOAT,       2, 1, 0, 0, 1, {0x3f000000, 0, 0, 0}, 0x3f000000, TRUE,  0, TRUE},
+        {DXGI_FORMAT_R32_FLOAT,       2, 1, 1, 0, 1, {0x3f000000, 0, 0, 0}, 0x3f000000, TRUE,  0, TRUE},
+        /* Test clearing specific array layers. */
+        {DXGI_FORMAT_R32_FLOAT,       1, IMAGE_SIZE, 0, 0, IMAGE_SIZE, {1, 0, 0, 0}, 0x00000001, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R32_FLOAT,       1, IMAGE_SIZE, 0, 3, 2,          {1, 0, 0, 0}, 0x00000001, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R32_FLOAT,       1, IMAGE_SIZE, 0, 0, IMAGE_SIZE,
+                {0x3f000000, 0, 0, 0}, 0x3f000000, TRUE, 0, TRUE},
+        {DXGI_FORMAT_R32_FLOAT,       1, IMAGE_SIZE, 0, 3, 2,
+                {0x3f000000, 0, 0, 0}, 0x3f000000, TRUE, 0, TRUE},
+        /* Test uint clears with formats. */
+        {DXGI_FORMAT_R16G16_UINT,     1, 1, 0, 0, 1, {1,       2, 3, 4}, 0x00020001, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R16G16_UINT,     1, 1, 0, 0, 1, {0x12345, 0, 0, 0}, 0x00002345, FALSE, 0x0000ffff, TRUE},
+        {DXGI_FORMAT_R16G16_UNORM,    1, 1, 0, 0, 1, {1,       2, 3, 4}, 0x00020001, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R16G16_FLOAT,    1, 1, 0, 0, 1, {1,       2, 3, 4}, 0x00020001, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R8G8B8A8_UINT,   1, 1, 0, 0, 1, {1,       2, 3, 4}, 0x04030201, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R8G8B8A8_UINT,   1, 1, 0, 0, 1, {0x123,   0, 0, 0}, 0x00000023, FALSE, 0x000000ff, TRUE},
+        {DXGI_FORMAT_R8G8B8A8_UNORM,  1, 1, 0, 0, 1, {1,       2, 3, 4}, 0x04030201, FALSE, 0, TRUE},
+        {DXGI_FORMAT_R11G11B10_FLOAT, 1, 1, 0, 0, 1, {1,       2, 3, 4}, 0x00c01001, FALSE, 0, TRUE},
+        /* Test float clears with formats. */
+        {DXGI_FORMAT_R16G16_UNORM,    1, 1, 0, 0, 1,
+                {0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0xffff8000, TRUE, 0, TRUE},
+        {DXGI_FORMAT_R16G16_FLOAT,    1, 1, 0, 0, 1,
+                {0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0x3c003800, TRUE, 0, TRUE},
+        {DXGI_FORMAT_R8G8B8A8_UNORM,  1, 1, 0, 0, 1,
+                {0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0x0000ff80, TRUE, 0, TRUE},
+        {DXGI_FORMAT_R8G8B8A8_UNORM,  1, 1, 0, 0, 1,
+                {0, 0, 0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */}, 0xff800000, TRUE, 0, TRUE},
+        {DXGI_FORMAT_R11G11B10_FLOAT, 1, 1, 0, 0, 1,
+                {0x3f000000 /* 1.0f */, 0 /* 0.0f */, 0xbf800000 /* -1.0f */, 0x3f000000 /* 1.0f */},
+                0x00000380, TRUE, 0, TRUE},
+    };
+
+    static const struct
+    {
+        D3D11_RESOURCE_DIMENSION resource_dim;
+        D3D11_UAV_DIMENSION view_dim;
+        BOOL is_layered;
+    }
+    uav_dimensions[] =
+    {
+        {D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3D11_UAV_DIMENSION_TEXTURE2D,      FALSE},
+        {D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3D11_UAV_DIMENSION_TEXTURE2DARRAY, TRUE },
+        /* Expected behaviour with partial layer coverage is unclear. */
+        {D3D11_RESOURCE_DIMENSION_TEXTURE3D, D3D11_UAV_DIMENSION_TEXTURE3D,      FALSE},
+    };
+
+    if (!init_test_context(&test_context, NULL))
+        return;
+    device = test_context.device;
+    context = test_context.immediate_context;
+
+    memset(&resource_desc, 0, sizeof(resource_desc));
+    resource_desc.width = IMAGE_SIZE;
+    resource_desc.height = IMAGE_SIZE;
+    resource_desc.sample_desc.Count = 1;
+    resource_desc.usage = D3D11_USAGE_DEFAULT;
+    resource_desc.bind_flags = D3D11_BIND_UNORDERED_ACCESS;
+
+    for (d = 0; d < ARRAY_SIZE(uav_dimensions); ++d)
+    {
+        for (i = 0; i < ARRAY_SIZE(tests); ++i)
+        {
+            winetest_push_context("Dim %u, Test %u", d, i);
+
+            if (tests[i].image_layers > 1 && !uav_dimensions[d].is_layered)
+            {
+                winetest_pop_context();
+                continue;
+            }
+
+            resource_desc.dimension = uav_dimensions[d].resource_dim;
+            resource_desc.depth_or_array_size = tests[i].image_layers;
+            resource_desc.level_count = tests[i].image_mips;
+            resource_desc.format = tests[i].format;
+            if (FAILED(hr = create_resource(device, &resource_desc, NULL, &resource)))
+            {
+                skip("Failed to create resource, hr %#x.\n", hr);
+                winetest_pop_context();
+                continue;
+            }
+
+            uav_desc.Format = tests[i].format;
+            uav_desc.ViewDimension = uav_dimensions[d].view_dim;
+
+            for (j = 0; j < 2; ++j)
+            {
+                unsigned int first_layer = j ? 0 : tests[i].first_layer;
+                unsigned int layer_count = j ? tests[i].image_layers : tests[i].layer_count;
+
+                switch (uav_desc.ViewDimension)
+                {
+                    case D3D11_UAV_DIMENSION_TEXTURE2D:
+                        uav_desc.Texture2D.MipSlice = tests[i].mip_level;
+                        break;
+
+                    case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
+                        uav_desc.Texture2DArray.MipSlice = tests[i].mip_level;
+                        uav_desc.Texture2DArray.FirstArraySlice = first_layer;
+                        uav_desc.Texture2DArray.ArraySize = layer_count;
+                        break;
+
+                    case D3D11_UAV_DIMENSION_TEXTURE3D:
+                        uav_desc.Texture3D.MipSlice = tests[i].mip_level;
+                        uav_desc.Texture3D.FirstWSlice = first_layer;
+                        uav_desc.Texture3D.WSize = layer_count;
+                        break;
+
+                    default:
+                        ok(0, "Unhandled uav dimension %#x.\n", uav_dimensions[d].view_dim);
+                        break;
+                }
+
+                hr = ID3D11Device_CreateUnorderedAccessView(device, resource, &uav_desc, &uav[j]);
+                ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+            }
+
+            for (j = 0; j < 4; ++j)
+            {
+                clear_value[j] = tests[i].expected ? 0u : ~0u;
+            }
+
+            ID3D11DeviceContext_ClearUnorderedAccessViewUint(context, uav[1], clear_value);
+            if (tests[i].is_float)
+                ID3D11DeviceContext_ClearUnorderedAccessViewFloat(context, uav[0], (const float *)tests[i].values);
+            else
+                ID3D11DeviceContext_ClearUnorderedAccessViewUint(context, uav[0], tests[i].values);
+
+            image_depth = uav_dimensions[d].resource_dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D
+                    ? max(tests[i].image_layers >> tests[i].mip_level, 1u) : 1;
+            image_size = max(IMAGE_SIZE >> tests[i].mip_level, 1u);
+
+            is_small_float_format = tests[i].format == DXGI_FORMAT_R16G16_UNORM
+                    || tests[i].format == DXGI_FORMAT_R16G16_FLOAT
+                    || tests[i].format == DXGI_FORMAT_R11G11B10_FLOAT
+                    || tests[i].format == DXGI_FORMAT_R8G8B8A8_UNORM;
+            for (layer = 0; layer < tests[i].image_layers / image_depth; ++layer)
+            {
+                get_resource_readback(resource, tests[i].mip_level + (layer * tests[i].image_mips), &rb);
+
+                success = TRUE;
+                expected_colour = actual_colour = x = y = z = 0;
+                for (p = 0; p < image_depth * image_size * image_size; ++p)
+                {
+                    x = p % image_size;
+                    y = (p / image_size) % image_size;
+                    z = p / (image_size * image_size);
+
+                    if (uav_dimensions[d].resource_dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
+                        is_inside = z >= tests[i].first_layer
+                                && z < tests[i].first_layer + tests[i].layer_count;
+                    else
+                        is_inside = layer >= tests[i].first_layer
+                                && layer < tests[i].first_layer + tests[i].layer_count;
+
+                    expected_colour = is_inside ? tests[i].expected : clear_value[0];
+                    actual_colour = get_readback_u32(&rb, x, y, z);
+                    if (!(success = compare_color(actual_colour, expected_colour, tests[i].is_float ? 1 : 0)
+                            /* Some drivers/GPUs clamp clear values that can't
+                             * be represented by the format. (Windows 7
+                             * testbot, AMD PALM) */
+                            || broken(is_inside && tests[i].clamped && actual_colour == tests[i].clamped)
+                            /* Some drivers/GPUs mishandle integer clears of
+                             * small float/normalised formats. (AMD PALM) */
+                            || broken(is_inside && !tests[i].is_float && is_small_float_format && !actual_colour)))
+                        break;
+                }
+                todo_wine_if(tests[i].is_todo && expected_colour)
+                    ok(success, "At layer %u, (%u,%u,%u), expected 0x%08x, got 0x%08x.\n",
+                            layer, x, y, z, expected_colour, actual_colour);
+
+                release_resource_readback(&rb);
+            }
+
+            ID3D11UnorderedAccessView_Release(uav[1]);
+            ID3D11UnorderedAccessView_Release(uav[0]);
+            ID3D11Resource_Release(resource);
+            winetest_pop_context();
+        }
+    }
+
+    release_test_context(&test_context);
+#undef IMAGE_SIZE
+}
+
 static void test_initial_depth_stencil_state(void)
 {
     static const struct vec4 green = {0.0f, 1.0f, 0.0f, 1.0f};
@@ -33043,6 +33371,7 @@ START_TEST(d3d11)
     queue_test(test_clear_render_target_view_3d);
     queue_test(test_clear_depth_stencil_view);
     queue_test(test_clear_buffer_unordered_access_view);
+    queue_test(test_clear_image_unordered_access_view);
     queue_test(test_initial_depth_stencil_state);
     queue_test(test_draw_depth_only);
     queue_test(test_draw_uav_only);
-- 
2.20.1




More information about the wine-devel mailing list