Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/state.c | 124 ++++++++++++++++++++++++++++++------- libs/vkd3d/vkd3d_private.h | 3 + 2 files changed, 106 insertions(+), 21 deletions(-)
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 03684264..18340a07 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -683,6 +683,9 @@ static HRESULT d3d12_root_signature_init_push_constants(struct d3d12_root_signat struct vkd3d_descriptor_set_context { VkDescriptorSetLayoutBinding *current_binding; + VkDescriptorSetLayoutBinding *first_binding; + unsigned int table_index; + bool unbounded; unsigned int descriptor_index; uint32_t descriptor_binding; }; @@ -805,6 +808,62 @@ static unsigned int vk_descriptor_count_from_d3d12_desc_range_type(D3D12_DESCRIP return min(type_max, all_max); }
+static unsigned int vkd3d_count_static_descriptor_bindings(struct vkd3d_descriptor_set_context *context) +{ + unsigned int i, binding_count, count = 0; + + binding_count = context->descriptor_binding - !!context->unbounded; + for (i = 0; i < binding_count; ++i) + count += context->first_binding[i].descriptorCount; + + return count; +} + +static HRESULT vkd3d_validate_descriptor_set_count(struct d3d12_device *device, unsigned int set_count) +{ + uint32_t max_count = min(VKD3D_MAX_DESCRIPTOR_SETS, + device->vk_info.device_limits.maxBoundDescriptorSets); + if (set_count > max_count) + { + ERR("Required descriptor set count exceeds maximum allowed count of %u.\n", max_count); + return E_INVALIDARG; + } + return S_OK; +} + +static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, + VkDescriptorSetLayoutCreateFlags flags, bool unbounded, unsigned int binding_count, + const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout); + +static HRESULT d3d12_root_signature_append_descriptor_set_layout(struct d3d12_root_signature *root_signature, + struct vkd3d_descriptor_set_context *context, VkDescriptorSetLayoutCreateFlags flags) +{ + HRESULT hr; + + if (!context->descriptor_binding) + return S_OK; + + if (FAILED(hr = vkd3d_validate_descriptor_set_count(root_signature->device, + root_signature->vk_set_count + 1))) + return hr; + + if (FAILED(hr = vkd3d_create_descriptor_set_layout(root_signature->device, + flags, context->unbounded, context->descriptor_binding, + context->first_binding, &root_signature->vk_set_layouts[root_signature->vk_set_count]))) + return hr; + root_signature->vk_unbounded_set_tables[root_signature->vk_set_count] + = context->unbounded ? context->table_index : -1; + root_signature->vk_set_layout_static_counts[root_signature->vk_set_count] + = vkd3d_count_static_descriptor_bindings(context); + ++root_signature->vk_set_count; + + context->current_binding = context->first_binding; + context->descriptor_binding = 0; + context->unbounded = false; + + return S_OK; +} + static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_root_signature *root_signature, const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context) { @@ -815,6 +874,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo uint32_t vk_binding;
root_signature->descriptor_table_mask = 0; + context->unbounded = false;
for (i = 0; i < desc->NumParameters; ++i) { @@ -832,6 +892,8 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo if (!(table->ranges = vkd3d_calloc(table->range_count, sizeof(*table->ranges)))) return E_OUTOFMEMORY;
+ context->table_index = i; + for (j = 0; j < range_count; ++j) { range = &p->u.DescriptorTable.pDescriptorRanges[j]; @@ -948,10 +1010,12 @@ static HRESULT d3d12_root_signature_init_static_samplers(struct d3d12_root_signa }
static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, - VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, + VkDescriptorSetLayoutCreateFlags flags, bool unbounded, unsigned int binding_count, const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_info; + VkDescriptorBindingFlagsEXT *set_flags = NULL; VkDescriptorSetLayoutCreateInfo set_desc; VkResult vr;
@@ -960,7 +1024,28 @@ static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, set_desc.flags = flags; set_desc.bindingCount = binding_count; set_desc.pBindings = bindings; - if ((vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL, set_layout))) < 0) + if (binding_count && device->vk_info.EXT_descriptor_indexing) + { + unsigned int i; + + if (!(set_flags = vkd3d_malloc(binding_count * sizeof(*set_flags)))) + return E_OUTOFMEMORY; + + for (i = 0; i < binding_count; ++i) + set_flags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; + + if (unbounded) + set_flags[binding_count - 1] |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT; + + set_desc.pNext = &flags_info; + flags_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; + flags_info.pNext = NULL; + flags_info.bindingCount = binding_count; + flags_info.pBindingFlags = set_flags; + } + vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL, set_layout)); + vkd3d_free(set_flags); + if (vr < 0) { WARN("Failed to create Vulkan descriptor set layout, vr %d.\n", vr); return hresult_from_vk_result(vr); @@ -977,6 +1062,10 @@ static HRESULT vkd3d_create_pipeline_layout(struct d3d12_device *device, const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct VkPipelineLayoutCreateInfo pipeline_layout_info; VkResult vr; + HRESULT hr; + + if (FAILED(hr = vkd3d_validate_descriptor_set_count(device, set_layout_count))) + return hr;
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_info.pNext = NULL; @@ -1017,6 +1106,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa root_signature->descriptor_mapping = NULL; root_signature->static_sampler_count = 0; root_signature->static_samplers = NULL; + root_signature->device = device;
if (desc->Flags & ~(D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT)) @@ -1033,6 +1123,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa root_signature->mapping_count = info.mapping_count; root_signature->static_sampler_count = desc->NumStaticSamplers; root_signature->root_descriptor_count = info.root_descriptor_count; + root_signature->bindless = device->vk_info.EXT_descriptor_indexing;
hr = E_OUTOFMEMORY; root_signature->parameter_count = desc->NumParameters; @@ -1052,22 +1143,18 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
if (!(binding_desc = vkd3d_calloc(info.binding_count, sizeof(*binding_desc)))) goto fail; + context.first_binding = binding_desc; context.current_binding = binding_desc;
if (FAILED(hr = d3d12_root_signature_init_root_descriptors(root_signature, desc, &context))) goto fail;
/* We use KHR_push_descriptor for root descriptor parameters. */ - if (vk_info->KHR_push_descriptor && context.descriptor_binding) + if (vk_info->KHR_push_descriptor) { - if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, - context.descriptor_binding, binding_desc, &root_signature->vk_set_layouts[0]))) + if (FAILED(hr = d3d12_root_signature_append_descriptor_set_layout(root_signature, + &context, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR))) goto fail; - ++root_signature->vk_set_count; - - context.current_binding = binding_desc; - context.descriptor_binding = 0; }
if (FAILED(hr = d3d12_root_signature_init_push_constants(root_signature, desc, @@ -1079,14 +1166,9 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa goto fail;
root_signature->main_set = root_signature->vk_set_count; - if (context.descriptor_binding) - { - if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, - 0, context.descriptor_binding, binding_desc, - &root_signature->vk_set_layouts[root_signature->vk_set_count]))) - goto fail; - ++root_signature->vk_set_count; - } + if (FAILED(hr = d3d12_root_signature_append_descriptor_set_layout(root_signature, &context, 0))) + goto fail; + vkd3d_free(binding_desc); binding_desc = NULL;
@@ -1098,7 +1180,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa if (FAILED(hr = vkd3d_private_store_init(&root_signature->private_store))) goto fail;
- d3d12_device_add_ref(root_signature->device = device); + d3d12_device_add_ref(device);
return S_OK;
@@ -1708,7 +1790,7 @@ static HRESULT d3d12_pipeline_state_init_compute_uav_counters(struct d3d12_pipel
/* Create a descriptor set layout for UAV counters. */ hr = vkd3d_create_descriptor_set_layout(device, - 0, descriptor_binding, binding_desc, &state->vk_set_layout); + 0, false, descriptor_binding, binding_desc, &state->vk_set_layout); vkd3d_free(binding_desc); if (FAILED(hr)) { @@ -3185,7 +3267,7 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d { set_binding.descriptorType = set_layouts[i].descriptor_type;
- if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0, 1, &set_binding, set_layouts[i].set_layout))) + if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0, false, 1, &set_binding, set_layouts[i].set_layout))) { ERR("Failed to create descriptor set layout %u, hr %#x.\n", i, hr); goto fail; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 79cd3f4f..cc1bf46f 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -702,6 +702,9 @@ struct d3d12_root_signature VkPipelineLayout vk_pipeline_layout; uint32_t vk_set_count; VkDescriptorSetLayout vk_set_layouts[VKD3D_MAX_DESCRIPTOR_SETS]; + unsigned int vk_set_layout_static_counts[VKD3D_MAX_DESCRIPTOR_SETS]; + int vk_unbounded_set_tables[VKD3D_MAX_DESCRIPTOR_SETS]; + bool bindless;
struct d3d12_root_parameter *parameters; unsigned int parameter_count;
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- include/vkd3d_shader.h | 12 ++++++++++-- libs/vkd3d-shader/spirv.c | 1 + 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 03225d37..b320de8d 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -194,6 +194,8 @@ enum vkd3d_shader_descriptor_type VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_DESCRIPTOR_TYPE), };
+#define VKD3D_SHADER_SINGLE_BINDING 0x7FFFFFFF + /** * A common structure describing the bind point of a descriptor or descriptor * array in the target environment. @@ -208,10 +210,16 @@ struct vkd3d_shader_descriptor_binding /** The binding index of the descriptor. */ unsigned int binding; /** - * The size of this descriptor array. Descriptor arrays are not supported in - * this version of vkd3d-shader, and therefore this value must be 1. + * The size of this descriptor array. If descriptor indexing is not + * supported by the Vulkan device, this value must be 1. */ unsigned int count; + /** + * The offset of the first descriptor in the binding relative to the + * register index used to map it. Valid if this binding is contained within + * a larger merged array, otherwise VKD3D_SHADER_SINGLE_BINDING. + */ + int offset; };
enum vkd3d_shader_binding_flag diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 0e75b0ae..d477b384 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2569,6 +2569,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor done: binding.set = 0; binding.count = 1; + binding.offset = 0; binding.binding = compiler->binding_idx++; return binding; }
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 6 +----- libs/vkd3d/state.c | 27 ++++++++++++++++++++++----- 2 file changed, 23 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 116a8a62..06d7746d 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -2674,7 +2674,6 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
descriptor_table = root_signature_get_descriptor_table(root_signature, index);
- descriptor = base_descriptor; descriptor_count = 0; current_descriptor_write = descriptor_writes; current_image_info = image_infos; @@ -2682,10 +2681,7 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list { range = &descriptor_table->ranges[i];
- if (range->offset != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) - { - descriptor = base_descriptor + range->offset; - } + descriptor = base_descriptor + range->offset;
for (j = 0; j < range->descriptor_count; ++j, ++descriptor) { diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 18340a07..4bc6bdec 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -879,6 +879,8 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo for (i = 0; i < desc->NumParameters; ++i) { const D3D12_ROOT_PARAMETER *p = &desc->pParameters[i]; + unsigned int offset = 0; + if (p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE) continue;
@@ -894,6 +896,26 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
context->table_index = i;
+ for (j = 0; j < range_count; ++j) + { + range = &p->u.DescriptorTable.pDescriptorRanges[j]; + + if (range->OffsetInDescriptorsFromTableStart != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + offset = range->OffsetInDescriptorsFromTableStart; + + table->ranges[j].offset = offset; + table->ranges[j].descriptor_count = range->NumDescriptors; + table->ranges[j].descriptor_magic = vkd3d_descriptor_magic_from_d3d12(range->RangeType); + table->ranges[j].register_space = range->RegisterSpace; + table->ranges[j].base_register_idx = range->BaseShaderRegister; + + TRACE("Descriptor table range %u.%u, offset %u, type %u, count %d.\n", i, j, + offset, range->RangeType, range->NumDescriptors); + + /* Validation during counting ensures this value is never used if range->NumDescriptors == UINT_MAX. */ + offset += range->NumDescriptors; + } + for (j = 0; j < range_count; ++j) { range = &p->u.DescriptorTable.pDescriptorRanges[j]; @@ -928,12 +950,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo ++cur_binding; }
- table->ranges[j].offset = range->OffsetInDescriptorsFromTableStart; - table->ranges[j].descriptor_count = range->NumDescriptors; table->ranges[j].binding = vk_binding; - table->ranges[j].descriptor_magic = vkd3d_descriptor_magic_from_d3d12(range->RangeType); - table->ranges[j].register_space = range->RegisterSpace; - table->ranges[j].base_register_idx = range->BaseShaderRegister; } }
Unbounded ranges are handled using variable-count Vulkan bindings.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/state.c | 170 +++++++++++++++++++++++++++++++++---- libs/vkd3d/vkd3d_private.h | 6 +- 2 files changed, 157 insertions(+), 19 deletions(-)
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 4bc6bdec..c3d595ed 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -1,6 +1,7 @@ /* * Copyright 2016 Józef Kucia for CodeWeavers * Copyright 2016 Henri Verbeet for CodeWeavers + * Copyright 2021 Conor McCarthy for Codeweavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -299,13 +300,12 @@ static enum vkd3d_shader_descriptor_type vkd3d_descriptor_type_from_d3d12_root_p }
static bool vk_binding_from_d3d12_descriptor_range(struct VkDescriptorSetLayoutBinding *binding_desc, - const D3D12_DESCRIPTOR_RANGE *descriptor_range, D3D12_SHADER_VISIBILITY shader_visibility, - bool is_buffer, uint32_t vk_binding) + const D3D12_DESCRIPTOR_RANGE_TYPE type, D3D12_SHADER_VISIBILITY shader_visibility, + unsigned int descriptor_count, bool is_buffer, uint32_t vk_binding) { binding_desc->binding = vk_binding; - binding_desc->descriptorType - = vk_descriptor_type_from_d3d12_range_type(descriptor_range->RangeType, is_buffer); - binding_desc->descriptorCount = 1; + binding_desc->descriptorType = vk_descriptor_type_from_d3d12_range_type(type, is_buffer); + binding_desc->descriptorCount = descriptor_count; binding_desc->stageFlags = stage_flags_from_visibility(shader_visibility); binding_desc->pImmutableSamplers = NULL;
@@ -692,8 +692,8 @@ struct vkd3d_descriptor_set_context
static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature *root_signature, enum vkd3d_shader_descriptor_type descriptor_type, unsigned int register_space, unsigned int register_idx, - bool buffer_descriptor, enum vkd3d_shader_visibility shader_visibility, - struct vkd3d_descriptor_set_context *context) + bool buffer_descriptor, unsigned int descriptor_count, unsigned int binding_offset, + enum vkd3d_shader_visibility shader_visibility, struct vkd3d_descriptor_set_context *context) { struct vkd3d_shader_resource_binding *mapping = &root_signature->descriptor_mapping[context->descriptor_index++]; @@ -705,7 +705,8 @@ static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature * mapping->flags = buffer_descriptor ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE; mapping->binding.set = root_signature->vk_set_count; mapping->binding.binding = context->descriptor_binding++; - mapping->binding.count = 1; + mapping->binding.count = descriptor_count; + mapping->binding.offset = binding_offset; }
static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature, @@ -726,10 +727,11 @@ static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signat { if (duplicate_descriptors) d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, register_space, - base_register_idx + i, true, shader_visibility, context); + base_register_idx + i, true, 1, VKD3D_SHADER_SINGLE_BINDING, shader_visibility, context);
d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, register_space, - base_register_idx + i, is_buffer_descriptor, shader_visibility, context); + base_register_idx + i, is_buffer_descriptor, 1, VKD3D_SHADER_SINGLE_BINDING, shader_visibility, + context); } return first_binding; } @@ -864,10 +866,121 @@ static HRESULT d3d12_root_signature_append_descriptor_set_layout(struct d3d12_ro return S_OK; }
+/* From a single table merge all ranges with the same descriptor type into one Vulkan descriptor binding. This + * allows array declarations for different ranges to address each other's descriptors - a D3D12 requirement + * (see test_unbounded_srv). If ranges are not contiguous, unused space will exist between them, but this probaby + * won't occur often and is the simplest way of handling the bindings. */ +static HRESULT d3d12_root_signature_append_merged_vk_binding(struct d3d12_root_signature *root_signature, + struct d3d12_root_descriptor_table *table, D3D12_DESCRIPTOR_RANGE_TYPE type, unsigned int min_offset, + unsigned int max_offset, D3D12_SHADER_VISIBILITY visibility, bool is_duplicate, + struct vkd3d_descriptor_set_context *context, const struct d3d12_root_signature_info *info) +{ + enum vkd3d_shader_visibility vkd3d_visibility = vkd3d_shader_visibility_from_d3d12(visibility); + uint32_t descriptor_magic = vkd3d_descriptor_magic_from_d3d12(type); + unsigned int i, range_count, descriptor_count = 0; + bool is_buffer, array_binding; + HRESULT hr; + + range_count = table->range_count; + is_buffer = (type == D3D12_DESCRIPTOR_RANGE_TYPE_CBV) + | (!is_duplicate && (type == D3D12_DESCRIPTOR_RANGE_TYPE_SRV || type == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)); + array_binding = (max_offset == ~0u || max_offset - min_offset > 1); + + for (i = 0; i < range_count; ++i) + { + struct d3d12_root_descriptor_table_range *range = &table->ranges[i]; + if (range->descriptor_magic != descriptor_magic) + continue; + + if (!is_duplicate) + { + range->set = root_signature->vk_set_count - root_signature->main_set; + range->binding = context->descriptor_binding; + range->binding_offset = range->offset - min_offset; + } + + descriptor_count = range->descriptor_count; + if (descriptor_count == ~0u) + { + descriptor_count = vk_descriptor_count_from_d3d12_desc_range_type(type, visibility, + info, root_signature->device); + context->unbounded = true; + } + + d3d12_root_signature_append_vk_binding(root_signature, + vkd3d_descriptor_type_from_d3d12_range_type(type), range->register_space, range->base_register_idx, + is_buffer, descriptor_count, array_binding ? range->binding_offset - range->base_register_idx + : VKD3D_SHADER_SINGLE_BINDING, vkd3d_visibility, context); + /* More mappings may be added to the current binding. */ + --context->descriptor_binding; + } + + if (!vk_binding_from_d3d12_descriptor_range(context->current_binding, + type, visibility, context->unbounded ? descriptor_count : max_offset - min_offset, + is_buffer, context->descriptor_binding)) + return E_NOTIMPL; + + ++context->current_binding; + ++context->descriptor_binding; + + if (context->unbounded) + { + /* No more bindings are allowed in the current layout. */ + if (FAILED(hr = d3d12_root_signature_append_descriptor_set_layout(root_signature, context, 0))) + return hr; + } + + return S_OK; +} + +static HRESULT d3d12_root_signature_init_bindless_descriptor_ranges(struct d3d12_root_signature *root_signature, + struct d3d12_root_descriptor_table *table, D3D12_SHADER_VISIBILITY visibility, + struct vkd3d_descriptor_set_context *context, const struct d3d12_root_signature_info *info) +{ + static const D3D12_DESCRIPTOR_RANGE_TYPE types[4] = { + D3D12_DESCRIPTOR_RANGE_TYPE_SRV, + D3D12_DESCRIPTOR_RANGE_TYPE_UAV, + D3D12_DESCRIPTOR_RANGE_TYPE_CBV, + D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER}; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(types); ++i) + { + uint32_t descriptor_magic = vkd3d_descriptor_magic_from_d3d12(types[i]); + unsigned int j, min_offset = ~0u, max_offset = 0; + HRESULT hr; + + for (j = 0; j < table->range_count; ++j) + { + struct d3d12_root_descriptor_table_range *range = &table->ranges[j]; + if (range->descriptor_magic == descriptor_magic) + { + min_offset = min(min_offset, range->offset); + max_offset = (range->descriptor_count == ~0u) ? ~0u + : max(max_offset, range->offset + range->descriptor_count); + } + } + + if (min_offset != ~0u) + { + if (FAILED(hr = d3d12_root_signature_append_merged_vk_binding(root_signature, + table, types[i], min_offset, max_offset, visibility, false, context, info))) + return hr; + + if ((types[i] == D3D12_DESCRIPTOR_RANGE_TYPE_SRV || types[i] == D3D12_DESCRIPTOR_RANGE_TYPE_UAV) + && FAILED(hr = d3d12_root_signature_append_merged_vk_binding(root_signature, + table, types[i], min_offset, max_offset, visibility, true, context, info))) + return hr; + } + } + + return S_OK; +} + static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_root_signature *root_signature, - const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context) + const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context, + const struct d3d12_root_signature_info *info) { - VkDescriptorSetLayoutBinding *cur_binding = context->current_binding; struct d3d12_root_descriptor_table *table; const D3D12_DESCRIPTOR_RANGE *range; unsigned int i, j, k, range_count; @@ -916,8 +1029,20 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo offset += range->NumDescriptors; }
+ if (root_signature->bindless) + { + HRESULT hr; + + if (FAILED(hr = d3d12_root_signature_init_bindless_descriptor_ranges(root_signature, + table, p->ShaderVisibility, context, info))) + return hr; + continue; + } + for (j = 0; j < range_count; ++j) { + VkDescriptorSetLayoutBinding *cur_binding; + range = &p->u.DescriptorTable.pDescriptorRanges[j];
vk_binding = d3d12_root_signature_assign_vk_bindings(root_signature, @@ -925,6 +1050,8 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo range->RegisterSpace, range->BaseShaderRegister, range->NumDescriptors, false, true, vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility), context);
+ cur_binding = context->current_binding; + /* Unroll descriptor range. */ for (k = 0; k < range->NumDescriptors; ++k) { @@ -937,24 +1064,27 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
/* Assign binding for image view. */ if (!vk_binding_from_d3d12_descriptor_range(cur_binding, - range, p->ShaderVisibility, false, vk_current_binding + 1)) + range->RangeType, p->ShaderVisibility, 1, false, vk_current_binding + 1)) return E_NOTIMPL;
++cur_binding; }
if (!vk_binding_from_d3d12_descriptor_range(cur_binding, - range, p->ShaderVisibility, true, vk_current_binding)) + range->RangeType, p->ShaderVisibility, 1, true, vk_current_binding)) return E_NOTIMPL;
++cur_binding; }
+ table->ranges[j].set = root_signature->vk_set_count - root_signature->main_set; table->ranges[j].binding = vk_binding; + table->ranges[j].binding_offset = 0; + + context->current_binding = cur_binding; } }
- context->current_binding = cur_binding; return S_OK; }
@@ -1158,6 +1288,8 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa sizeof(*root_signature->static_samplers)))) goto fail;
+ /* The required capacity may be less than this if unbounded ranges are present, but + * calculating the maximum is not worth the complexity. */ if (!(binding_desc = vkd3d_calloc(info.binding_count, sizeof(*binding_desc)))) goto fail; context.first_binding = binding_desc; @@ -1174,15 +1306,15 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa goto fail; }
+ root_signature->main_set = root_signature->vk_set_count; if (FAILED(hr = d3d12_root_signature_init_push_constants(root_signature, desc, root_signature->push_constant_ranges, &root_signature->push_constant_range_count))) goto fail; - if (FAILED(hr = d3d12_root_signature_init_root_descriptor_tables(root_signature, desc, &context))) - goto fail; if (FAILED(hr = d3d12_root_signature_init_static_samplers(root_signature, device, desc, &context))) goto fail; + if (FAILED(hr = d3d12_root_signature_init_root_descriptor_tables(root_signature, desc, &context, &info))) + goto fail;
- root_signature->main_set = root_signature->vk_set_count; if (FAILED(hr = d3d12_root_signature_append_descriptor_set_layout(root_signature, &context, 0))) goto fail;
@@ -1792,6 +1924,7 @@ static HRESULT d3d12_pipeline_state_init_compute_uav_counters(struct d3d12_pipel state->uav_counters[j].binding.set = set_index; state->uav_counters[j].binding.binding = descriptor_binding; state->uav_counters[j].binding.count = 1; + state->uav_counters[j].binding.offset = VKD3D_SHADER_SINGLE_BINDING;
/* FIXME: For the graphics pipeline we have to take the shader * visibility into account. */ @@ -3269,6 +3402,7 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d binding.binding.set = 0; binding.binding.binding = 0; binding.binding.count = 1; + binding.binding.offset = VKD3D_SHADER_SINGLE_BINDING;
push_constant_range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; push_constant_range.offset = 0; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index cc1bf46f..02184c87 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -54,7 +54,9 @@ #define VKD3D_MAX_SHADER_EXTENSIONS 1u #define VKD3D_MAX_SHADER_STAGES 5u #define VKD3D_MAX_VK_SYNC_OBJECTS 4u -#define VKD3D_MAX_DESCRIPTOR_SETS 2u +/* A root signature full of tables with unbounded ranges can use many more, + * but this is unlikely to occur, and Vulkan has limits, eg. 32 in RADV. */ +#define VKD3D_MAX_DESCRIPTOR_SETS 64u
struct d3d12_command_list; struct d3d12_device; @@ -658,7 +660,9 @@ struct d3d12_root_descriptor_table_range { unsigned int offset; unsigned int descriptor_count; + unsigned int binding_offset; uint32_t binding; + uint32_t set;
uint32_t descriptor_magic; unsigned int register_space;