[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