From: Conor McCarthy Subject: [PATCH vkd3d 3/4] vkd3d: Count unbounded ranges and per-stage bound descriptors. Message-Id: <20210526080437.19137-3-cmccarthy@codeweavers.com> Date: Wed, 26 May 2021 18:04:36 +1000 In-Reply-To: <20210526080437.19137-1-cmccarthy@codeweavers.com> References: <20210526080437.19137-1-cmccarthy@codeweavers.com> Enables calculation of upper bounds for variable Vulkan bindings. The alternative is to use an arbitrary count value. The counting is complex, and can be simplified slightly if/when update-after-bind is used, as total counts will no longer be required. Signed-off-by: Conor McCarthy --- libs/vkd3d/state.c | 188 +++++++++++++++++++++++++++++++++++-- libs/vkd3d/vkd3d_private.h | 2 +- 2 files changed, 181 insertions(+), 9 deletions(-) diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index e459c998..749d3763 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -314,6 +314,19 @@ static bool vk_binding_from_d3d12_descriptor_range(struct VkDescriptorSetLayoutB struct d3d12_root_signature_info { + uint32_t cbv_stage_count[5]; + uint32_t uav_stage_count[5]; + uint32_t srv_stage_count[5]; + uint32_t sampler_stage_count[5]; + uint32_t total_stage_count[5]; + + uint32_t cbv_unbounded_set_count; + uint32_t uav_unbounded_set_count; + uint32_t srv_unbounded_set_count; + uint32_t sampler_unbounded_set_count; + uint32_t total_unbounded_set_count; + + size_t mapping_count; size_t binding_count; size_t root_constant_count; @@ -362,11 +375,149 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig info->binding_count += range->NumDescriptors; } + /* Without descriptor indexing these are always equal. */ + info->mapping_count = info->binding_count; + + return S_OK; +} + +static void d3d12_count_shader_stages(D3D12_SHADER_VISIBILITY visibility, + uint32_t stage_count[5], unsigned int count) +{ + unsigned int i; + + switch (visibility) + { + case D3D12_SHADER_VISIBILITY_ALL: + for (i = 0; i < 5; ++i) + stage_count[i] += count; + break; + case D3D12_SHADER_VISIBILITY_VERTEX: + stage_count[0] += count; + break; + case D3D12_SHADER_VISIBILITY_HULL: + stage_count[1] += count; + break; + case D3D12_SHADER_VISIBILITY_DOMAIN: + stage_count[2] += count; + break; + case D3D12_SHADER_VISIBILITY_GEOMETRY: + stage_count[3] += count; + break; + case D3D12_SHADER_VISIBILITY_PIXEL: + stage_count[4] += count; + break; + default: + break; + } +} + +static HRESULT d3d12_root_signature_info_count_bindless_descriptors(struct d3d12_root_signature_info *info, + const D3D12_ROOT_DESCRIPTOR_TABLE *table, D3D12_SHADER_VISIBILITY visibility, + const struct d3d12_device *device) +{ + /* XXX: Vulkan buffer and image descriptors have different types. In order + * to preserve compatibility between Vulkan resource bindings for the same + * root signature, we create descriptor set layouts with two bindings for + * each SRV and UAV. Space must be allowed for UAV counters too. */ + static const uint32_t multiplier[] = { 2, 3, 1, 1}; + uint32_t *const stage_count[] = { + info->srv_stage_count, + info->uav_stage_count, + info->cbv_stage_count, + info->sampler_stage_count + }; + uint32_t *const unbounded_set_count[] = { + &info->srv_unbounded_set_count, + &info->uav_unbounded_set_count, + &info->cbv_unbounded_set_count, + &info->sampler_unbounded_set_count + }; + unsigned int min_offset[4], max_offset[4]; + unsigned int i, offset = 0; + + memset(min_offset, 0xFF, sizeof(min_offset)); + memset(max_offset, 0, sizeof(max_offset)); + + for (i = 0; i < table->NumDescriptorRanges; ++i) + { + const D3D12_DESCRIPTOR_RANGE *range = &table->pDescriptorRanges[i]; + unsigned int j; + + if (range->OffsetInDescriptorsFromTableStart != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + offset = range->OffsetInDescriptorsFromTableStart; + + switch (range->RangeType) + { + case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: + info->mapping_count += 2; + j = 0; + break; + case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: + info->mapping_count += 2; + j = 1; + break; + case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: + ++info->mapping_count; + j = 2; + break; + case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: + ++info->mapping_count; + j = 3; + break; + default: + FIXME("Unhandled descriptor type %#x.\n", range->RangeType); + return E_NOTIMPL; + } + + min_offset[j] = min(min_offset[j], offset); + if (range->NumDescriptors == ~0u) + { + if (offset == ~0u && range->OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + { + ERR("Unbounded range with offset D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND occurs after " + "another unbounded range.\n"); + return E_INVALIDARG; + } + max_offset[j] = ~0u; + offset = ~0u; + } + else + { + if (offset == ~0u) + { + ERR("Static range occurs after unbounded range.\n"); + return E_INVALIDARG; + } + offset += range->NumDescriptors; + max_offset[j] = max(max_offset[j], offset); + } + } + + for (i = 0; i < 4; ++i) + { + if (min_offset[i] != ~0u) + { + /* Count descriptors bound to each stage to enable calculation of upper bounds for + * variable Vulkan bindings. */ + if (max_offset[i] != ~0u) + d3d12_count_shader_stages(visibility, stage_count[i], (max_offset[i] - min_offset[i]) * multiplier[i]); + /* One Vulkan variable binding for each descriptor type, plus possible UAV counters. */ + if (max_offset[i] == ~0u) + { + *unbounded_set_count[i] += multiplier[i]; + info->total_unbounded_set_count += multiplier[i]; + } + /* UAV counter bindings are not counted here as they are created later in separate set layouts. */ + info->binding_count += (multiplier[i] > 1) ? 2 : 1; + } + } + return S_OK; } static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_info *info, - const D3D12_ROOT_SIGNATURE_DESC *desc) + const D3D12_ROOT_SIGNATURE_DESC *desc, const struct d3d12_device *device) { unsigned int i; HRESULT hr; @@ -380,8 +531,12 @@ static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_i switch (p->ParameterType) { case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: - if (FAILED(hr = d3d12_root_signature_info_count_descriptors(info, - &p->u.DescriptorTable))) + if (device->vk_info.EXT_descriptor_indexing) + hr = d3d12_root_signature_info_count_bindless_descriptors(info, + &p->u.DescriptorTable, p->ShaderVisibility, device); + else + hr = d3d12_root_signature_info_count_descriptors(info, &p->u.DescriptorTable); + if (FAILED(hr)) return hr; ++info->cost; break; @@ -389,16 +544,22 @@ static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_i case D3D12_ROOT_PARAMETER_TYPE_CBV: ++info->root_descriptor_count; ++info->binding_count; + ++info->mapping_count; + d3d12_count_shader_stages(p->ShaderVisibility, info->cbv_stage_count, 1); info->cost += 2; break; case D3D12_ROOT_PARAMETER_TYPE_SRV: ++info->root_descriptor_count; ++info->binding_count; + ++info->mapping_count; + d3d12_count_shader_stages(p->ShaderVisibility, info->srv_stage_count, 1); info->cost += 2; break; case D3D12_ROOT_PARAMETER_TYPE_UAV: ++info->root_descriptor_count; ++info->binding_count; + ++info->mapping_count; + d3d12_count_shader_stages(p->ShaderVisibility, info->uav_stage_count, 1); info->cost += 2; break; @@ -414,6 +575,17 @@ static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_i } info->binding_count += desc->NumStaticSamplers; + info->mapping_count += desc->NumStaticSamplers; + for (i = 0; i < desc->NumStaticSamplers; ++i) + d3d12_count_shader_stages(desc->pStaticSamplers[i].ShaderVisibility, info->sampler_stage_count, 1); + + for (i = 0; i < ARRAY_SIZE(info->total_stage_count); ++i) + { + info->total_stage_count[i] += info->cbv_stage_count[i]; + info->total_stage_count[i] += info->uav_stage_count[i]; + info->total_stage_count[i] += info->srv_stage_count[i]; + info->total_stage_count[i] += info->sampler_stage_count[i]; + } return S_OK; } @@ -794,7 +966,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa | D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT)) FIXME("Ignoring root signature flags %#x.\n", desc->Flags); - if (FAILED(hr = d3d12_root_signature_info_from_desc(&info, desc))) + if (FAILED(hr = d3d12_root_signature_info_from_desc(&info, desc, device))) return hr; if (info.cost > D3D12_MAX_ROOT_COST) { @@ -802,7 +974,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa return E_INVALIDARG; } - root_signature->binding_count = info.binding_count; + root_signature->mapping_count = info.mapping_count; root_signature->static_sampler_count = desc->NumStaticSamplers; root_signature->root_descriptor_count = info.root_descriptor_count; @@ -811,7 +983,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa if (!(root_signature->parameters = vkd3d_calloc(root_signature->parameter_count, sizeof(*root_signature->parameters)))) goto fail; - if (!(root_signature->descriptor_mapping = vkd3d_calloc(root_signature->binding_count, + if (!(root_signature->descriptor_mapping = vkd3d_calloc(root_signature->mapping_count, sizeof(*root_signature->descriptor_mapping)))) goto fail; root_signature->root_constant_count = info.root_constant_count; @@ -1549,7 +1721,7 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st shader_interface.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO; shader_interface.next = NULL; shader_interface.bindings = root_signature->descriptor_mapping; - shader_interface.binding_count = root_signature->binding_count; + shader_interface.binding_count = root_signature->mapping_count; shader_interface.push_constant_buffers = root_signature->root_constants; shader_interface.push_constant_buffer_count = root_signature->root_constant_count; shader_interface.combined_samplers = NULL; @@ -2258,7 +2430,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s shader_interface.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO; shader_interface.next = NULL; shader_interface.bindings = root_signature->descriptor_mapping; - shader_interface.binding_count = root_signature->binding_count; + shader_interface.binding_count = root_signature->mapping_count; shader_interface.push_constant_buffers = root_signature->root_constants; shader_interface.push_constant_buffer_count = root_signature->root_constant_count; shader_interface.combined_samplers = NULL; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index b30e38e9..79cd3f4f 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -712,7 +712,7 @@ struct d3d12_root_signature D3D12_ROOT_SIGNATURE_FLAGS flags; - unsigned int binding_count; + unsigned int mapping_count; struct vkd3d_shader_resource_binding *descriptor_mapping; unsigned int root_constant_count; -- 2.31.1