From 809a43f06b56f146e71783420a752ce651f47ebf Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 16 Aug 2021 18:55:56 -0500 Subject: [PATCH] tests: Add a test for compute thread IDs. --- tests/d3d12.c | 39 ---------- tests/d3d12_test_utils.h | 29 +++++++ tests/hlsl_d3d12.c | 161 +++++++++++++++++++++++++++++++++++++++ tests/utils.h | 10 +++ 4 files changed, 200 insertions(+), 39 deletions(-) diff --git a/tests/d3d12.c b/tests/d3d12.c index 1e995aa8..ea569bc3 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -26,11 +26,6 @@ static PFN_D3D12_CREATE_VERSIONED_ROOT_SIGNATURE_DESERIALIZER pfn_D3D12CreateVersionedRootSignatureDeserializer; static PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE pfn_D3D12SerializeVersionedRootSignature; -struct uvec4 -{ - unsigned int x, y, z, w; -}; - struct ivec4 { int x, y, z, w; @@ -41,11 +36,6 @@ struct dvec2 double x, y; }; -static bool compare_uvec4(const struct uvec4* v1, const struct uvec4 *v2) -{ - return v1->x == v2->x && v1->y == v2->y && v1->z == v2->z && v1->w == v2->w; -} - static bool compare_uint8(uint8_t a, uint8_t b, unsigned int max_diff) { return abs(a - b) <= max_diff; @@ -725,35 +715,6 @@ static ID3D12CommandSignature *create_command_signature_(unsigned int line, return command_signature; } -#define init_compute_test_context(context) init_compute_test_context_(__LINE__, context) -static bool init_compute_test_context_(unsigned int line, struct test_context *context) -{ - ID3D12Device *device; - HRESULT hr; - - memset(context, 0, sizeof(*context)); - - if (!(context->device = create_device())) - { - skip_(line)("Failed to create device.\n"); - return false; - } - device = context->device; - - context->queue = create_command_queue_(line, device, - D3D12_COMMAND_LIST_TYPE_COMPUTE, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL); - - hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_COMPUTE, - &IID_ID3D12CommandAllocator, (void **)&context->allocator); - ok_(line)(hr == S_OK, "Failed to create command allocator, hr %#x.\n", hr); - - hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_COMPUTE, - context->allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&context->list); - ok_(line)(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); - - return true; -} - struct depth_stencil_resource { ID3D12Resource *texture; diff --git a/tests/d3d12_test_utils.h b/tests/d3d12_test_utils.h index eebf3206..b6a99d43 100644 --- a/tests/d3d12_test_utils.h +++ b/tests/d3d12_test_utils.h @@ -1034,6 +1034,35 @@ static inline bool init_test_context_(unsigned int line, struct test_context *co return true; } +#define init_compute_test_context(context) init_compute_test_context_(__LINE__, context) +static inline bool init_compute_test_context_(unsigned int line, struct test_context *context) +{ + ID3D12Device *device; + HRESULT hr; + + memset(context, 0, sizeof(*context)); + + if (!(context->device = create_device())) + { + skip_(line)("Failed to create device.\n"); + return false; + } + device = context->device; + + context->queue = create_command_queue_(line, device, + D3D12_COMMAND_LIST_TYPE_COMPUTE, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL); + + hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_COMPUTE, + &IID_ID3D12CommandAllocator, (void **)&context->allocator); + ok_(line)(hr == S_OK, "Failed to create command allocator, hr %#x.\n", hr); + + hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_COMPUTE, + context->allocator, NULL, &IID_ID3D12GraphicsCommandList, (void **)&context->list); + ok_(line)(hr == S_OK, "Failed to create command list, hr %#x.\n", hr); + + return true; +} + static inline void destroy_pipeline_state_objects(struct test_context *context) { size_t i; diff --git a/tests/hlsl_d3d12.c b/tests/hlsl_d3d12.c index da8e0eac..8de8d653 100644 --- a/tests/hlsl_d3d12.c +++ b/tests/hlsl_d3d12.c @@ -416,6 +416,166 @@ static void test_preprocess(void) ID3D10Blob_Release(errors); } +#define compile_shader(a, b) compile_shader_(__LINE__, a, b, 0) +#define compile_shader_flags(a, b, c) compile_shader_(__LINE__, a, b, c) +static ID3D10Blob *compile_shader_(unsigned int line, const char *source, const char *target, UINT flags) +{ + ID3D10Blob *blob = NULL, *errors = NULL; + HRESULT hr; + + hr = D3DCompile(source, strlen(source), NULL, NULL, NULL, "main", target, flags, 0, &blob, &errors); + ok_(line)(hr == S_OK, "Failed to compile shader, hr %#x.\n", hr); + if (errors) + { + if (vkd3d_test_state.debug_level) + trace_(line)("%s\n", (char *)ID3D10Blob_GetBufferPointer(errors)); + ID3D10Blob_Release(errors); + } + return blob; +} + +static void test_thread_id(void) +{ + ID3D12GraphicsCommandList *command_list; + struct d3d12_resource_readback rb; + struct test_context context; + ID3D12Resource *textures[3]; + ID3D12DescriptorHeap *heap; + unsigned int i, x, y, z; + ID3D12Device *device; + ID3D10Blob *cs_code; + HRESULT hr; + + static const char cs_source[] = + "RWTexture3D group_uav, thread_uav, dispatch_uav;\n" + "[numthreads(5, 3, 2)]\n" + "void main(uint3 group : sv_groupid, uint3 thread : sv_groupthreadid, uint3 dispatch : sv_dispatchthreadid)\n" + "{\n" + " group_uav[dispatch] = uint4(group, 1);\n" + " thread_uav[dispatch] = uint4(thread, 2);\n" + " dispatch_uav[dispatch] = uint4(dispatch, 3);\n" + "}"; + + static const D3D12_DESCRIPTOR_RANGE descriptor_range = {D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 3, 0, 0, 0}; + + static const D3D12_ROOT_PARAMETER root_parameter = + { + .ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, + .DescriptorTable = {1, &descriptor_range}, + }; + + static const D3D12_ROOT_SIGNATURE_DESC root_signature_desc = + { + .NumParameters = 1, + .pParameters = &root_parameter, + }; + + if (!init_compute_test_context(&context)) + return; + command_list = context.list; + device = context.device; + + hr = create_root_signature(device, &root_signature_desc, &context.root_signature); + ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); + + heap = create_gpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 3); + + for (i = 0; i < 3; ++i) + { + textures[i] = create_default_texture3d(device, 16, 8, 8, 1, DXGI_FORMAT_R32G32B32A32_UINT, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + ID3D12Device_CreateUnorderedAccessView(device, textures[i], NULL, NULL, + get_cpu_descriptor_handle(&context, heap, i)); + } + + todo cs_code = compile_shader(cs_source, "cs_5_0"); + if (cs_code) + { + context.pipeline_state = create_compute_pipeline_state(device, context.root_signature, + shader_bytecode(ID3D10Blob_GetBufferPointer(cs_code), ID3D10Blob_GetBufferSize(cs_code))); + + ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state); + ID3D12GraphicsCommandList_SetComputeRootSignature(command_list, context.root_signature); + ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, + 0, get_gpu_descriptor_handle(&context, heap, 0)); + ID3D12GraphicsCommandList_Dispatch(command_list, 2, 2, 2); + + transition_resource_state(command_list, textures[0], + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); + get_texture_readback_with_command_list(textures[0], 0, &rb, context.queue, command_list); + for (x = 0; x < 16; ++x) + { + for (y = 0; y < 8; ++y) + { + for (z = 0; z < 8; ++z) + { + const struct uvec4 *v = get_readback_data(&rb.rb, x, y, z, sizeof(struct uvec4)); + struct uvec4 expect = {x / 5, y / 3, z / 2, 1}; + + if (x >= 10 || y >= 6 || z >= 4) + memset(&expect, 0, sizeof(expect)); + + ok(compare_uvec4(v, &expect), "Got {%u, %u, %u, %u} at (%u, %u, %u).\n", + v->x, v->y, v->z, v->w, x, y, z); + } + } + } + release_resource_readback(&rb); + reset_command_list(command_list, context.allocator); + + transition_resource_state(command_list, textures[1], + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); + get_texture_readback_with_command_list(textures[1], 0, &rb, context.queue, command_list); + for (x = 0; x < 16; ++x) + { + for (y = 0; y < 8; ++y) + { + for (z = 0; z < 8; ++z) + { + const struct uvec4 *v = get_readback_data(&rb.rb, x, y, z, sizeof(struct uvec4)); + struct uvec4 expect = {x % 5, y % 3, z % 2, 2}; + + if (x >= 10 || y >= 6 || z >= 4) + memset(&expect, 0, sizeof(expect)); + + ok(compare_uvec4(v, &expect), "Got {%u, %u, %u, %u} at (%u, %u, %u).\n", + v->x, v->y, v->z, v->w, x, y, z); + } + } + } + release_resource_readback(&rb); + reset_command_list(command_list, context.allocator); + + transition_resource_state(command_list, textures[2], + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); + get_texture_readback_with_command_list(textures[2], 0, &rb, context.queue, command_list); + for (x = 0; x < 16; ++x) + { + for (y = 0; y < 8; ++y) + { + for (z = 0; z < 8; ++z) + { + const struct uvec4 *v = get_readback_data(&rb.rb, x, y, z, sizeof(struct uvec4)); + struct uvec4 expect = {x, y, z, 3}; + + if (x >= 10 || y >= 6 || z >= 4) + memset(&expect, 0, sizeof(expect)); + + ok(compare_uvec4(v, &expect), "Got {%u, %u, %u, %u} at (%u, %u, %u).\n", + v->x, v->y, v->z, v->w, x, y, z); + } + } + } + release_resource_readback(&rb); + reset_command_list(command_list, context.allocator); + } + + for (i = 0; i < 3; ++i) + ID3D12Resource_Release(textures[i]); + ID3D12DescriptorHeap_Release(heap); + destroy_test_context(&context); +} + START_TEST(hlsl_d3d12) { parse_args(argc, argv); @@ -423,4 +583,5 @@ START_TEST(hlsl_d3d12) init_adapter_info(); run_test(test_preprocess); + run_test(test_thread_id); } diff --git a/tests/utils.h b/tests/utils.h index 82f0fc35..4097b6d1 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -35,6 +35,11 @@ struct vec4 float x, y, z, w; }; +struct uvec4 +{ + unsigned int x, y, z, w; +}; + struct resource_readback { uint64_t width; @@ -97,6 +102,11 @@ static bool compare_float(float f, float g, unsigned int ulps) return true; } +static inline bool compare_uvec4(const struct uvec4 *v1, const struct uvec4 *v2) +{ + return v1->x == v2->x && v1->y == v2->y && v1->z == v2->z && v1->w == v2->w; +} + static inline bool compare_vec4(const struct vec4 *v1, const struct vec4 *v2, unsigned int ulps) { return compare_float(v1->x, v2->x, ulps)