[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