[PATCH vkd3d 4/4] vkd3d: Use merged array bindings for descriptor ranges if descriptor indexing is available.
Conor McCarthy
cmccarthy at codeweavers.com
Wed May 26 03:06:19 CDT 2021
Unbounded ranges are handled using variable-count Vulkan bindings.
Signed-off-by: Conor McCarthy <cmccarthy at 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;
--
2.31.1
More information about the wine-devel
mailing list