From b1889215ee75cd346b4a796fe79934938ff85c1b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Oct 2021 19:19:08 -0500 Subject: [PATCH] tests: Add a test for texture load instructions. Signed-off-by: Zebediah Figura Signed-off-by: Giovanni Mascellani Signed-off-by: Matteo Bruni Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- Makefile.am | 2 + tests/d3d12.c | 89 ----------------- tests/d3d12_test_utils.h | 89 +++++++++++++++++ tests/shader_runner_d3d12.c | 175 ++++++++++++++++++++++++++++++++- tests/texture-load.shader_test | 19 ++++ 5 files changed, 281 insertions(+), 93 deletions(-) create mode 100644 tests/texture-load.shader_test diff --git a/Makefile.am b/Makefile.am index bc33e0f6..921bb796 100644 --- a/Makefile.am +++ b/Makefile.am @@ -99,6 +99,7 @@ vkd3d_shader_tests = \ tests/swizzle-5.shader_test \ tests/swizzle-6.shader_test \ tests/swizzle-7.shader_test \ + tests/texture-load.shader_test \ tests/trigonometry.shader_test \ tests/writemask-assignop-0.shader_test \ tests/writemask-assignop-1.shader_test \ @@ -299,6 +300,7 @@ XFAIL_TESTS = \ tests/hlsl-vector-indexing-uniform.shader_test \ tests/math.shader_test \ tests/max.shader_test \ + tests/texture-load.shader_test \ tests/trigonometry.shader_test \ tests/writemask-assignop-1.shader_test endif diff --git a/tests/d3d12.c b/tests/d3d12.c index 89b1f000..009f8331 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -155,22 +155,6 @@ static void uav_barrier(ID3D12GraphicsCommandList *list, ID3D12Resource *resourc ID3D12GraphicsCommandList_ResourceBarrier(list, 1, &barrier); } -static void copy_sub_resource_data(const D3D12_MEMCPY_DEST *dst, const D3D12_SUBRESOURCE_DATA *src, - unsigned int row_count, unsigned int slice_count, size_t row_size) -{ - const BYTE *src_slice_ptr; - BYTE *dst_slice_ptr; - unsigned int z, y; - - for (z = 0; z < slice_count; ++z) - { - dst_slice_ptr = (BYTE *)dst->pData + z * dst->SlicePitch; - src_slice_ptr = (const BYTE*)src->pData + z * src->SlicePitch; - for (y = 0; y < row_count; ++y) - memcpy(dst_slice_ptr + y * dst->RowPitch, src_slice_ptr + y * src->RowPitch, row_size); - } -} - #define upload_buffer_data(a, b, c, d, e, f) upload_buffer_data_(__LINE__, a, b, c, d, e, f) static void upload_buffer_data_(unsigned int line, ID3D12Resource *buffer, size_t offset, size_t size, const void *data, ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list) @@ -196,79 +180,6 @@ static void upload_buffer_data_(unsigned int line, ID3D12Resource *buffer, size_ ID3D12Device_Release(device); } -#define upload_texture_data(a, b, c, d, e) upload_texture_data_(__LINE__, a, b, c, d, e) -static void upload_texture_data_(unsigned int line, ID3D12Resource *texture, - const D3D12_SUBRESOURCE_DATA *data, unsigned int sub_resource_count, - ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list) -{ - D3D12_TEXTURE_COPY_LOCATION dst_location, src_location; - D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts; - uint64_t *row_sizes, required_size; - D3D12_RESOURCE_DESC resource_desc; - ID3D12Resource *upload_buffer; - D3D12_MEMCPY_DEST dst_data; - ID3D12Device *device; - UINT *row_counts; - unsigned int i; - HRESULT hr; - void *ptr; - - layouts = calloc(sub_resource_count, sizeof(*layouts)); - ok(layouts, "Failed to allocate memory.\n"); - row_counts = calloc(sub_resource_count, sizeof(*row_counts)); - ok(row_counts, "Failed to allocate memory.\n"); - row_sizes = calloc(sub_resource_count, sizeof(*row_sizes)); - ok(row_sizes, "Failed to allocate memory.\n"); - - resource_desc = ID3D12Resource_GetDesc(texture); - hr = ID3D12Resource_GetDevice(texture, &IID_ID3D12Device, (void **)&device); - ok_(line)(SUCCEEDED(hr), "Failed to get device, hr %#x.\n", hr); - - ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, - 0, layouts, row_counts, row_sizes, &required_size); - - upload_buffer = create_upload_buffer_(line, device, required_size, NULL); - - hr = ID3D12Resource_Map(upload_buffer, 0, NULL, (void **)&ptr); - ok_(line)(SUCCEEDED(hr), "Failed to map upload buffer, hr %#x.\n", hr); - for (i = 0; i < sub_resource_count; ++i) - { - dst_data.pData = (BYTE *)ptr + layouts[i].Offset; - dst_data.RowPitch = layouts[i].Footprint.RowPitch; - dst_data.SlicePitch = layouts[i].Footprint.RowPitch * row_counts[i]; - copy_sub_resource_data(&dst_data, &data[i], - row_counts[i], layouts[i].Footprint.Depth, row_sizes[i]); - } - ID3D12Resource_Unmap(upload_buffer, 0, NULL); - - for (i = 0; i < sub_resource_count; ++i) - { - dst_location.pResource = texture; - dst_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst_location.SubresourceIndex = i; - - src_location.pResource = upload_buffer; - src_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src_location.PlacedFootprint = layouts[i]; - - ID3D12GraphicsCommandList_CopyTextureRegion(command_list, - &dst_location, 0, 0, 0, &src_location, NULL); - } - - hr = ID3D12GraphicsCommandList_Close(command_list); - ok_(line)(SUCCEEDED(hr), "Failed to close command list, hr %#x.\n", hr); - - exec_command_list(queue, command_list); - wait_queue_idle(device, queue); - - ID3D12Resource_Release(upload_buffer); - ID3D12Device_Release(device); - - free(layouts); - free(row_counts); - free(row_sizes); -} - static const DXGI_FORMAT depth_stencil_formats[] = { DXGI_FORMAT_R32G8X24_TYPELESS, diff --git a/tests/d3d12_test_utils.h b/tests/d3d12_test_utils.h index 0374d8d1..5d900f89 100644 --- a/tests/d3d12_test_utils.h +++ b/tests/d3d12_test_utils.h @@ -697,6 +697,95 @@ static inline ID3D12Resource *create_default_texture3d_(unsigned int line, ID3D1 width, height, depth, miplevel_count, format, flags, initial_state); } +static void copy_sub_resource_data(const D3D12_MEMCPY_DEST *dst, const D3D12_SUBRESOURCE_DATA *src, + unsigned int row_count, unsigned int slice_count, size_t row_size) +{ + const BYTE *src_slice_ptr; + BYTE *dst_slice_ptr; + unsigned int z, y; + + for (z = 0; z < slice_count; ++z) + { + dst_slice_ptr = (BYTE *)dst->pData + z * dst->SlicePitch; + src_slice_ptr = (const BYTE*)src->pData + z * src->SlicePitch; + for (y = 0; y < row_count; ++y) + memcpy(dst_slice_ptr + y * dst->RowPitch, src_slice_ptr + y * src->RowPitch, row_size); + } +} + +#define upload_texture_data(a, b, c, d, e) upload_texture_data_(__LINE__, a, b, c, d, e) +static inline void upload_texture_data_(unsigned int line, ID3D12Resource *texture, + const D3D12_SUBRESOURCE_DATA *data, unsigned int sub_resource_count, + ID3D12CommandQueue *queue, ID3D12GraphicsCommandList *command_list) +{ + D3D12_TEXTURE_COPY_LOCATION dst_location, src_location; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts; + uint64_t *row_sizes, required_size; + D3D12_RESOURCE_DESC resource_desc; + ID3D12Resource *upload_buffer; + D3D12_MEMCPY_DEST dst_data; + ID3D12Device *device; + UINT *row_counts; + unsigned int i; + HRESULT hr; + void *ptr; + + layouts = calloc(sub_resource_count, sizeof(*layouts)); + ok(layouts, "Failed to allocate memory.\n"); + row_counts = calloc(sub_resource_count, sizeof(*row_counts)); + ok(row_counts, "Failed to allocate memory.\n"); + row_sizes = calloc(sub_resource_count, sizeof(*row_sizes)); + ok(row_sizes, "Failed to allocate memory.\n"); + + resource_desc = ID3D12Resource_GetDesc(texture); + hr = ID3D12Resource_GetDevice(texture, &IID_ID3D12Device, (void **)&device); + ok_(line)(SUCCEEDED(hr), "Failed to get device, hr %#x.\n", hr); + + ID3D12Device_GetCopyableFootprints(device, &resource_desc, 0, sub_resource_count, + 0, layouts, row_counts, row_sizes, &required_size); + + upload_buffer = create_upload_buffer_(line, device, required_size, NULL); + + hr = ID3D12Resource_Map(upload_buffer, 0, NULL, (void **)&ptr); + ok_(line)(SUCCEEDED(hr), "Failed to map upload buffer, hr %#x.\n", hr); + for (i = 0; i < sub_resource_count; ++i) + { + dst_data.pData = (BYTE *)ptr + layouts[i].Offset; + dst_data.RowPitch = layouts[i].Footprint.RowPitch; + dst_data.SlicePitch = layouts[i].Footprint.RowPitch * row_counts[i]; + copy_sub_resource_data(&dst_data, &data[i], + row_counts[i], layouts[i].Footprint.Depth, row_sizes[i]); + } + ID3D12Resource_Unmap(upload_buffer, 0, NULL); + + for (i = 0; i < sub_resource_count; ++i) + { + dst_location.pResource = texture; + dst_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst_location.SubresourceIndex = i; + + src_location.pResource = upload_buffer; + src_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src_location.PlacedFootprint = layouts[i]; + + ID3D12GraphicsCommandList_CopyTextureRegion(command_list, + &dst_location, 0, 0, 0, &src_location, NULL); + } + + hr = ID3D12GraphicsCommandList_Close(command_list); + ok_(line)(SUCCEEDED(hr), "Failed to close command list, hr %#x.\n", hr); + + exec_command_list(queue, command_list); + wait_queue_idle(device, queue); + + ID3D12Resource_Release(upload_buffer); + ID3D12Device_Release(device); + + free(layouts); + free(row_counts); + free(row_sizes); +} + static HRESULT create_root_signature(ID3D12Device *device, const D3D12_ROOT_SIGNATURE_DESC *desc, ID3D12RootSignature **root_signature) { diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index a0cdc5b3..171a855f 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -73,6 +73,20 @@ static bool vkd3d_array_reserve(void **elements, size_t *capacity, size_t elemen return true; } +struct texture +{ + unsigned int slot; + + unsigned int width, height; + uint8_t *data; + size_t data_size, data_capacity; + + D3D12_DESCRIPTOR_RANGE descriptor_range; + ID3D12DescriptorHeap *heap; + ID3D12Resource *resource; + unsigned int root_index; +}; + struct shader_context { struct test_context c; @@ -81,6 +95,9 @@ struct shader_context uint32_t *uniforms; size_t uniform_count; + + struct texture *textures; + size_t texture_count; }; static ID3D10Blob *compile_shader(const char *source, const char *target) @@ -99,6 +116,14 @@ static ID3D10Blob *compile_shader(const char *source, const char *target) return blob; } +static void free_texture(struct texture *texture) +{ + ID3D12DescriptorHeap_Release(texture->heap); + ID3D12Resource_Release(texture->resource); + free(texture->data); + memset(texture, 0, sizeof(*texture)); +} + enum parse_state { STATE_NONE, @@ -106,6 +131,7 @@ enum parse_state STATE_PREPROC_INVALID, STATE_SHADER_INVALID_PIXEL, STATE_SHADER_PIXEL, + STATE_TEXTURE, STATE_TEST, }; @@ -124,6 +150,37 @@ static bool match_string(const char *line, const char *token, const char **const return true; } +static void parse_texture_directive(struct texture *texture, const char *line) +{ + const char *const orig_line = line; + int ret; + + if (match_string(line, "size", &line)) + { + ret = sscanf(line, "( %u , %u )", &texture->width, &texture->height); + if (ret < 2) + goto err; + } + else + { + char *rest; + float f; + + while ((f = strtof(line, &rest)) || rest != line) + { + vkd3d_array_reserve((void **)&texture->data, &texture->data_capacity, texture->data_size + sizeof(f), 1); + memcpy(texture->data + texture->data_size, &f, sizeof(f)); + texture->data_size += sizeof(f); + line = rest; + } + } + + return; + +err: + fprintf(stderr, "Ignoring malformed line '%s'.\n", orig_line); +} + static void parse_test_directive(struct shader_context *context, const char *line) { const char *const orig_line = line; @@ -133,13 +190,66 @@ static void parse_test_directive(struct shader_context *context, const char *lin D3D12_SHADER_BYTECODE ps = {ID3D10Blob_GetBufferPointer(context->ps_code), ID3D10Blob_GetBufferSize(context->ps_code)}; ID3D12GraphicsCommandList *command_list = context->c.list; + D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {0}; + D3D12_ROOT_PARAMETER root_params[2], *root_param; static const float clear_color[4]; + unsigned int uniform_index; ID3D12PipelineState *pso; + HRESULT hr; + size_t i; + + root_signature_desc.NumParameters = 0; + root_signature_desc.pParameters = root_params; + + if (context->uniform_count) + { + uniform_index = root_signature_desc.NumParameters++; + root_param = &root_params[uniform_index]; + root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + root_param->Constants.ShaderRegister = 0; + root_param->Constants.RegisterSpace = 0; + root_param->Constants.Num32BitValues = context->uniform_count; + root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + } + + for (i = 0; i < context->texture_count; ++i) + { + struct texture *texture = &context->textures[i]; + D3D12_DESCRIPTOR_RANGE *range = &texture->descriptor_range; + D3D12_SUBRESOURCE_DATA resource_data; + + texture->root_index = root_signature_desc.NumParameters++; + root_param = &root_params[texture->root_index]; + root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + root_param->DescriptorTable.NumDescriptorRanges = 1; + root_param->DescriptorTable.pDescriptorRanges = range; + root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + range->NumDescriptors = 1; + range->BaseShaderRegister = texture->slot; + range->RegisterSpace = 0; + range->OffsetInDescriptorsFromTableStart = 0; + + texture->heap = create_gpu_descriptor_heap(context->c.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1); + texture->resource = create_default_texture(context->c.device, texture->width, texture->height, + DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_RESOURCE_STATE_COPY_DEST); + resource_data.pData = texture->data; + resource_data.SlicePitch = resource_data.RowPitch = texture->width * sizeof(struct vec4); + upload_texture_data(texture->resource, &resource_data, 1, context->c.queue, command_list); + reset_command_list(command_list, context->c.allocator); + transition_resource_state(command_list, texture->resource, D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + ID3D12Device_CreateShaderResourceView(context->c.device, texture->resource, + NULL, get_cpu_descriptor_handle(&context->c, texture->heap, 0)); + } + + assert(root_signature_desc.NumParameters <= ARRAY_SIZE(root_params)); if (context->c.root_signature) ID3D12RootSignature_Release(context->c.root_signature); - context->c.root_signature = create_32bit_constants_root_signature(context->c.device, - 0, context->uniform_count, D3D12_SHADER_VISIBILITY_ALL); + hr = create_root_signature(context->c.device, &root_signature_desc, &context->c.root_signature); + ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); pso = create_pipeline_state(context->c.device, context->c.root_signature, context->c.render_target_desc.Format, NULL, &ps, NULL); @@ -147,8 +257,13 @@ static void parse_test_directive(struct shader_context *context, const char *lin return; ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->c.root_signature); - ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 0, - context->uniform_count, context->uniforms, 0); + if (context->uniform_count) + ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, uniform_index, + context->uniform_count, context->uniforms, 0); + for (i = 0; i < context->texture_count; ++i) + ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, context->textures[i].root_index, + get_gpu_descriptor_handle(&context->c, context->textures[i].heap, 0)); + ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->c.rtv, false, NULL); ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->c.scissor_rect); ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->c.viewport); @@ -293,6 +408,21 @@ err: fprintf(stderr, "Ignoring malformed line '%s'.\n", orig_line); } +static struct texture *get_texture(struct shader_context *context, unsigned int slot) +{ + struct texture *texture; + size_t i; + + for (i = 0; i < context->texture_count; ++i) + { + texture = &context->textures[i]; + if (texture->slot == slot) + return texture; + } + + return NULL; +} + START_TEST(shader_runner_d3d12) { static const struct test_context_desc desc = @@ -305,6 +435,7 @@ START_TEST(shader_runner_d3d12) size_t shader_source_size = 0, shader_source_len = 0; enum parse_state state = STATE_NONE; unsigned int i, line_number = 0; + struct texture *current_texture; struct shader_context context; const char *filename = NULL; char *shader_source = NULL; @@ -351,6 +482,7 @@ START_TEST(shader_runner_d3d12) { case STATE_NONE: case STATE_TEST: + case STATE_TEXTURE: break; case STATE_SHADER_PIXEL: @@ -439,16 +571,45 @@ START_TEST(shader_runner_d3d12) if (line[0] == '[') { + unsigned int index; + if (!strcmp(line, "[pixel shader]\n")) + { state = STATE_SHADER_PIXEL; + } else if (!strcmp(line, "[pixel shader fail]\n")) + { state = STATE_SHADER_INVALID_PIXEL; + } + else if (sscanf(line, "[texture %u]\n", &index)) + { + state = STATE_TEXTURE; + + if ((current_texture = get_texture(&context, index))) + { + free_texture(current_texture); + } + else + { + context.textures = realloc(context.textures, + ++context.texture_count * sizeof(*context.textures)); + current_texture = &context.textures[context.texture_count - 1]; + memset(current_texture, 0, sizeof(*current_texture)); + } + current_texture->slot = index; + } else if (!strcmp(line, "[test]\n")) + { state = STATE_TEST; + } else if (!strcmp(line, "[preproc]\n")) + { state = STATE_PREPROC; + } else if (!strcmp(line, "[preproc fail]\n")) + { state = STATE_PREPROC_INVALID; + } vkd3d_test_set_context("Section %.*s, line %u", strlen(line) - 1, line, line_number); } @@ -473,6 +634,10 @@ START_TEST(shader_runner_d3d12) break; } + case STATE_TEXTURE: + parse_texture_directive(current_texture, line); + break; + case STATE_TEST: parse_test_directive(&context, line); break; @@ -482,6 +647,8 @@ START_TEST(shader_runner_d3d12) if (context.ps_code) ID3D10Blob_Release(context.ps_code); + for (i = 0; i < context.texture_count; ++i) + free_texture(&context.textures[i]); destroy_test_context(&context.c); fclose(f); diff --git a/tests/texture-load.shader_test b/tests/texture-load.shader_test new file mode 100644 index 00000000..86b36af4 --- /dev/null +++ b/tests/texture-load.shader_test @@ -0,0 +1,19 @@ +[texture 0] +size (2, 2) +0.1 0.2 0.3 0.4 0.5 0.7 0.6 0.8 +0.6 0.5 0.2 0.1 0.8 0.0 0.7 1.0 + +[pixel shader] +Texture2D t; + +float4 main(float4 pos : sv_position) : sv_target +{ + return t.Load(int3(pos.xy, 0)); +} + +[test] +draw quad +probe rgba (0, 0) (0.1, 0.2, 0.3, 0.4) +probe rgba (1, 0) (0.5, 0.7, 0.6, 0.8) +probe rgba (0, 1) (0.6, 0.5, 0.2, 0.1) +probe rgba (1, 1) (0.8, 0.0, 0.7, 1.0)