diff --git a/Makefile.am b/Makefile.am index 6ddb828d8..886a42db0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -104,6 +104,7 @@ vkd3d_shader_tests = \ tests/hlsl/default-values.shader_test \ tests/hlsl/depth-bounds.shader_test \ tests/hlsl/depth-out.shader_test \ + tests/hlsl/descriptors.shader_test \ tests/hlsl/determinant.shader_test \ tests/hlsl/discard.shader_test \ tests/hlsl/distance.shader_test \ diff --git a/tests/hlsl/descriptors.shader_test b/tests/hlsl/descriptors.shader_test new file mode 100644 index 000000000..33e411105 --- /dev/null +++ b/tests/hlsl/descriptors.shader_test @@ -0,0 +1,98 @@ +[require] +shader model >= 5.0 +descriptors + +[srv 0] +format r32-float +size (2d, 1, 1) + +1.0 + +[srv 1] +format r32-float +size (2d, 1, 1) + +2.0 + +[srv 2] +format r32-float +size (2d, 1, 1) + +3.0 + +[pixel shader] +Texture2D t : register(t1); + +float4 main() : SV_Target +{ + return t.Load(uint3(0, 0, 0)); +} + +[test] +draw quad +probe (0, 0) f32(2.0, 2.0, 2.0, 2.0) + +[descriptors] +t[1:1], space 0, srv 2 + +[test] +draw quad +probe (0, 0) f32(3.0, 3.0, 3.0, 3.0) + +[descriptors] +t[1:2], space 0, srv 0 + +[test] +draw quad +probe (0, 0) f32(1.0, 1.0, 1.0, 1.0) + +[require] +shader model >= 5.0 +descriptors +format r32-float uav-load + +[uav 1] +format r32-float +size (2d, 1, 1) + +1.0 + +[uav 2] +format r32-float +size (2d, 1, 1) + +2.0 + +[uav 3] +format r32-float +size (2d, 1, 1) + +3.0 + +[pixel shader] +RWTexture2D u : register(u2); + +float4 main() : SV_Target +{ + return u[uint2(0, 0)]; +} + +[descriptors] + +[test] +todo(msl) draw quad +probe (0, 0) f32(2.0, 2.0, 2.0, 2.0) + +[descriptors] +u[2:2], space 0, uav 3 + +[test] +draw quad +probe (0, 0) f32(3.0, 3.0, 3.0, 3.0) + +[descriptors] +u[2:3], space 0, uav 1 + +[test] +draw quad +probe (0, 0) f32(1.0, 1.0, 1.0, 1.0) diff --git a/tests/shader_runner.c b/tests/shader_runner.c index dd00fd8be..868b2d8a6 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -102,6 +102,7 @@ void fatal_error(const char *format, ...) enum parse_state { STATE_NONE, + STATE_DESCRIPTORS, STATE_INPUT_LAYOUT, STATE_PREPROC, STATE_PREPROC_INVALID, @@ -463,6 +464,7 @@ static const char *const shader_cap_strings[] = [SHADER_CAP_CLIP_PLANES] = "clip-planes", [SHADER_CAP_CULL_DISTANCE] = "cull-distance", [SHADER_CAP_DEPTH_BOUNDS] = "depth-bounds", + [SHADER_CAP_DESCRIPTORS] = "descriptors", [SHADER_CAP_FLOAT64] = "float64", [SHADER_CAP_FOG] = "fog", [SHADER_CAP_GEOMETRY_SHADER] = "geometry-shader", @@ -1756,6 +1758,48 @@ static void parse_test_directive(struct shader_runner *runner, const char *line) } } +static void parse_descriptors_directive(struct shader_runner *runner, const char *line) +{ + struct descriptor_mapping *descriptor; + const char *target_template; + unsigned int register_to; + char type_chr; + int pos; + + if (runner->descriptor_count == ARRAY_SIZE(runner->descriptors)) + fatal_error("Too many descriptors (%u).\n", runner->descriptor_count); + + descriptor = &runner->descriptors[runner->descriptor_count++]; + + if (sscanf(line, " %c [ %u : %u ] , space %u ,%n", &type_chr, &descriptor->register_idx, + ®ister_to, &descriptor->register_space, &pos) < 4) + fatal_error("Malformed descriptors directive '%s'.\n", line); + + descriptor->count = register_to - descriptor->register_idx + 1; + + switch (type_chr) + { + case 't': + descriptor->type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV; + target_template = " srv %u"; + break; + + case 'u': + descriptor->type = VKD3D_SHADER_DESCRIPTOR_TYPE_UAV; + target_template = " uav %u"; + break; + + /* Samplers and CBVs are not supported yet. */ + + default: + fatal_error("Malformed descriptors directive '%s'.\n", line); + break; + } + + if (sscanf(&line[pos], target_template, &descriptor->target_idx) < 1) + fatal_error("Malformed descriptors directive '%s'.\n", line); +} + struct sampler *shader_runner_get_sampler(struct shader_runner *runner, unsigned int slot) { struct sampler *sampler; @@ -2427,6 +2471,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c case STATE_INPUT_LAYOUT: case STATE_NONE: case STATE_SAMPLER: + case STATE_DESCRIPTORS: break; case STATE_TEST: @@ -2722,6 +2767,11 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c free(runner->input_elements[i].name); runner->input_element_count = 0; } + else if (!strcmp(line, "[descriptors]\n")) + { + state = STATE_DESCRIPTORS; + runner->descriptor_count = 0; + } else { fatal_error("Unknown directive '%s'.\n", line); @@ -2775,6 +2825,10 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c && SUCCEEDED(runner->hlsl_hrs[runner->minimum_shader_model])) parse_test_directive(runner, line); break; + + case STATE_DESCRIPTORS: + parse_descriptors_directive(runner, line); + break; } } } diff --git a/tests/shader_runner.h b/tests/shader_runner.h index 49881a8a7..c62a4fd24 100644 --- a/tests/shader_runner.h +++ b/tests/shader_runner.h @@ -138,6 +138,7 @@ struct viewport float height; }; +#define MAX_DESCRIPTORS 32 #define MAX_RESOURCES 32 #define MAX_SAMPLERS 32 #define DXGI_FORMAT_COUNT (DXGI_FORMAT_B4G4R4A4_UNORM + 1) @@ -152,6 +153,7 @@ enum shader_cap SHADER_CAP_CLIP_PLANES, SHADER_CAP_CULL_DISTANCE, SHADER_CAP_DEPTH_BOUNDS, + SHADER_CAP_DESCRIPTORS, SHADER_CAP_FLOAT64, SHADER_CAP_FOG, SHADER_CAP_GEOMETRY_SHADER, @@ -230,6 +232,15 @@ enum source_format SOURCE_FORMAT_DXBC_DXIL_HEX, }; +struct descriptor_mapping +{ + enum vkd3d_shader_descriptor_type type; + unsigned int register_idx; + unsigned int register_space; + unsigned int count; + unsigned int target_idx; +}; + struct shader_runner { const struct shader_runner_ops *ops; @@ -295,6 +306,9 @@ struct shader_runner struct viewport viewports[4]; unsigned int viewport_count; + + struct descriptor_mapping descriptors[MAX_DESCRIPTORS]; + unsigned int descriptor_count; }; struct shader_runner_ops diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c index ede85a8f3..1f519dc64 100644 --- a/tests/shader_runner_d3d12.c +++ b/tests/shader_runner_d3d12.c @@ -304,11 +304,20 @@ static void d3d12_runner_destroy_resource(struct shader_runner *r, struct resour free(resource); } +static const D3D12_DESCRIPTOR_RANGE_TYPE range_types[] = +{ + [VKD3D_SHADER_DESCRIPTOR_TYPE_SRV] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV, + [VKD3D_SHADER_DESCRIPTOR_TYPE_UAV] = D3D12_DESCRIPTOR_RANGE_TYPE_UAV, + [VKD3D_SHADER_DESCRIPTOR_TYPE_CBV] = D3D12_DESCRIPTOR_RANGE_TYPE_CBV, + [VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER] = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, +}; + static ID3D12RootSignature *d3d12_runner_create_root_signature(struct d3d12_shader_runner *runner, ID3D12CommandQueue *queue, ID3D12CommandAllocator *allocator, ID3D12GraphicsCommandList *command_list, unsigned int *uniform_index) { D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {0}; + D3D12_DESCRIPTOR_RANGE root_ranges[MAX_DESCRIPTORS]; D3D12_ROOT_PARAMETER root_params[17], *root_param; D3D12_STATIC_SAMPLER_DESC static_samplers[7]; struct d3d12_resource *base_resource = NULL; @@ -323,49 +332,77 @@ static ID3D12RootSignature *d3d12_runner_create_root_signature(struct d3d12_shad root_signature_desc.pStaticSamplers = static_samplers; root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - for (i = 0; i < runner->r.resource_count; ++i) + if (runner->r.descriptor_count) { - struct d3d12_resource *resource = d3d12_resource(runner->r.resources[i]); - D3D12_DESCRIPTOR_RANGE *range; + root_param = &root_params[root_signature_desc.NumParameters++]; - switch (resource->r.desc.type) + root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + root_param->DescriptorTable.NumDescriptorRanges = 0; + root_param->DescriptorTable.pDescriptorRanges = root_ranges; + + for (i = 0; i < runner->r.descriptor_count; ++i) { - case RESOURCE_TYPE_TEXTURE: - case RESOURCE_TYPE_UAV: - range = &resource->descriptor_range; + D3D12_DESCRIPTOR_RANGE *range = &root_ranges[root_param->DescriptorTable.NumDescriptorRanges++]; + struct descriptor_mapping *descriptor = &runner->r.descriptors[i]; - if (base_resource && resource->r.desc.type == base_resource->r.desc.type && resource->r.desc.slot == slot + 1) - { - ++base_resource->descriptor_range.NumDescriptors; - resource->descriptor_range.NumDescriptors = 0; - ++slot; - continue; - } + range->RangeType = range_types[descriptor->type]; + range->BaseShaderRegister = descriptor->register_idx; + range->RegisterSpace = descriptor->register_space; + range->NumDescriptors = descriptor->count; - resource->root_index = root_signature_desc.NumParameters++; - root_param = &root_params[resource->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->OffsetInDescriptorsFromTableStart = descriptor->target_idx; + if (descriptor->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) + range->OffsetInDescriptorsFromTableStart += MAX_RESOURCES; + } + } + else + { + for (i = 0; i < runner->r.resource_count; ++i) + { + struct d3d12_resource *resource = d3d12_resource(runner->r.resources[i]); + D3D12_DESCRIPTOR_RANGE *range; - if (resource->r.desc.type == RESOURCE_TYPE_UAV) - range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - else - range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - range->NumDescriptors = 1; - range->BaseShaderRegister = resource->r.desc.slot; - range->RegisterSpace = 0; - range->OffsetInDescriptorsFromTableStart = 0; + switch (resource->r.desc.type) + { + case RESOURCE_TYPE_TEXTURE: + case RESOURCE_TYPE_UAV: + range = &resource->descriptor_range; - base_resource = resource; - slot = resource->r.desc.slot; - break; + if (base_resource && resource->r.desc.type == base_resource->r.desc.type + && resource->r.desc.slot == slot + 1) + { + ++base_resource->descriptor_range.NumDescriptors; + resource->descriptor_range.NumDescriptors = 0; + ++slot; + continue; + } - case RESOURCE_TYPE_RENDER_TARGET: - case RESOURCE_TYPE_DEPTH_STENCIL: - case RESOURCE_TYPE_VERTEX_BUFFER: - break; + resource->root_index = root_signature_desc.NumParameters++; + root_param = &root_params[resource->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; + + if (resource->r.desc.type == RESOURCE_TYPE_UAV) + range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + else + range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + range->NumDescriptors = 1; + range->BaseShaderRegister = resource->r.desc.slot; + range->RegisterSpace = 0; + range->OffsetInDescriptorsFromTableStart = 0; + + base_resource = resource; + slot = resource->r.desc.slot; + break; + + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_DEPTH_STENCIL: + case RESOURCE_TYPE_VERTEX_BUFFER: + break; + } } } @@ -461,13 +498,13 @@ static bool d3d12_runner_dispatch(struct shader_runner *r, unsigned int x, unsig switch (resource->r.desc.type) { case RESOURCE_TYPE_TEXTURE: - if (resource->descriptor_range.NumDescriptors) + if (resource->descriptor_range.NumDescriptors && !r->descriptor_count) ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index, get_gpu_descriptor_handle(test_context, runner->heap, resource->r.desc.slot)); break; case RESOURCE_TYPE_UAV: - if (resource->descriptor_range.NumDescriptors) + if (resource->descriptor_range.NumDescriptors && !r->descriptor_count) ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, resource->root_index, get_gpu_descriptor_handle(test_context, runner->heap, resource->r.desc.slot + MAX_RESOURCES)); break; @@ -479,6 +516,10 @@ static bool d3d12_runner_dispatch(struct shader_runner *r, unsigned int x, unsig } } + if (r->descriptor_count) + ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0, + get_gpu_descriptor_handle(test_context, runner->heap, 0)); + ID3D12GraphicsCommandList_SetPipelineState(command_list, pso); ID3D12GraphicsCommandList_Dispatch(command_list, x, y, z); ID3D12RootSignature_Release(root_signature); @@ -806,8 +847,8 @@ static ID3D12PipelineState *create_pipeline_device2(struct d3d12_shader_runner * return pso; } -static bool d3d12_runner_draw(struct shader_runner *r, - D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count, unsigned int instance_count) +static bool d3d12_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY primitive_topology, + unsigned int vertex_count, unsigned int instance_count) { struct d3d12_shader_runner *runner = d3d12_shader_runner(r); struct test_context *test_context = &runner->test_context; @@ -921,13 +962,13 @@ static bool d3d12_runner_draw(struct shader_runner *r, break; case RESOURCE_TYPE_TEXTURE: - if (resource->descriptor_range.NumDescriptors) + if (resource->descriptor_range.NumDescriptors && !r->descriptor_count) ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, resource->root_index, get_gpu_descriptor_handle(test_context, runner->heap, resource->r.desc.slot)); break; case RESOURCE_TYPE_UAV: - if (resource->descriptor_range.NumDescriptors) + if (resource->descriptor_range.NumDescriptors && !r->descriptor_count) ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, resource->root_index, get_gpu_descriptor_handle(test_context, runner->heap, resource->r.desc.slot + MAX_RESOURCES)); break; @@ -942,6 +983,10 @@ static bool d3d12_runner_draw(struct shader_runner *r, } } + if (r->descriptor_count) + ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0, + get_gpu_descriptor_handle(test_context, runner->heap, 0)); + set_rect(&test_context->scissor_rect, 0, 0, fb_width, fb_height); set_viewport(&test_context->viewport, 0.0f, 0.0f, fb_width, fb_height, 0.0f, 1.0f); viewports[0] = test_context->viewport; @@ -1112,6 +1157,7 @@ static void d3d12_runner_init_caps(struct d3d12_shader_runner *runner, if (is_cull_distance_supported(device)) runner->caps.shader_caps[SHADER_CAP_CULL_DISTANCE] = true; runner->caps.shader_caps[SHADER_CAP_DEPTH_BOUNDS] = options2.DepthBoundsTestSupported; + runner->caps.shader_caps[SHADER_CAP_DESCRIPTORS] = true; runner->caps.shader_caps[SHADER_CAP_FLOAT64] = options.DoublePrecisionFloatShaderOps; if (is_geometry_shader_supported(device)) runner->caps.shader_caps[SHADER_CAP_GEOMETRY_SHADER] = true;