[PATCH vkd3d v2 3/3] vkd3d: Use Vulkan descriptor arrays if descriptor indexing is available.

Conor McCarthy cmccarthy at codeweavers.com
Mon Aug 2 09:43:18 CDT 2021


Descriptor indexing is required for its partial binding feature. Separate
buffer and image descriptor arrays are needed for implementing D3D12 SRV and
UAV descriptor ranges, so not all of the Vulkan descriptors will be populated.

Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 libs/vkd3d/command.c       |  11 ++--
 libs/vkd3d/state.c         | 127 ++++++++++++++++++++++++++++++++-----
 libs/vkd3d/vkd3d_private.h |   1 +
 tests/d3d12.c              |   2 -
 4 files changed, 118 insertions(+), 23 deletions(-)

diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index 8bed7303..bf80a9d0 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -2592,7 +2592,7 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
 static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_descriptor_write,
         VkDescriptorImageInfo *vk_image_info, const struct d3d12_desc *descriptor,
         uint32_t descriptor_range_magic, VkDescriptorSet vk_descriptor_set,
-        uint32_t vk_binding, unsigned int index)
+        uint32_t vk_binding, unsigned int index, bool use_array)
 {
     const struct vkd3d_view *view = descriptor->u.view;
 
@@ -2602,8 +2602,8 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
     vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     vk_descriptor_write->pNext = NULL;
     vk_descriptor_write->dstSet = vk_descriptor_set;
-    vk_descriptor_write->dstBinding = vk_binding + index;
-    vk_descriptor_write->dstArrayElement = 0;
+    vk_descriptor_write->dstBinding = use_array ? vk_binding : vk_binding + index;
+    vk_descriptor_write->dstArrayElement = use_array ? index : 0;
     vk_descriptor_write->descriptorCount = 1;
     vk_descriptor_write->descriptorType = descriptor->vk_descriptor_type;
     vk_descriptor_write->pImageInfo = NULL;
@@ -2620,7 +2620,8 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
         case VKD3D_DESCRIPTOR_MAGIC_UAV:
             /* We use separate bindings for buffer and texture SRVs/UAVs.
              * See d3d12_root_signature_init(). */
-            vk_descriptor_write->dstBinding = vk_binding + 2 * index;
+            if (!use_array)
+                vk_descriptor_write->dstBinding = vk_binding + 2 * index;
             if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
                     && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
                 ++vk_descriptor_write->dstBinding;
@@ -2707,7 +2708,7 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
 
             if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write,
                     current_image_info, descriptor, range->descriptor_magic,
-                    bindings->descriptor_set, range->binding, j))
+                    bindings->descriptor_set, range->binding, j, root_signature->use_descriptor_arrays))
                 continue;
 
             ++descriptor_count;
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c
index 102201dc..5ab0af83 100644
--- a/libs/vkd3d/state.c
+++ b/libs/vkd3d/state.c
@@ -300,12 +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)
+        bool is_buffer, uint32_t vk_binding, unsigned int descriptor_count)
 {
     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->descriptorCount = descriptor_count;
     binding_desc->stageFlags = stage_flags_from_visibility(shader_visibility);
     binding_desc->pImmutableSamplers = NULL;
 
@@ -323,13 +323,14 @@ struct d3d12_root_signature_info
 };
 
 static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_signature_info *info,
-        const D3D12_ROOT_DESCRIPTOR_TABLE *table)
+        const D3D12_ROOT_DESCRIPTOR_TABLE *table, bool use_array)
 {
     unsigned int i;
 
     for (i = 0; i < table->NumDescriptorRanges; ++i)
     {
         const D3D12_DESCRIPTOR_RANGE *range = &table->pDescriptorRanges[i];
+        unsigned int binding_count;
 
         if (range->NumDescriptors == 0xffffffff)
         {
@@ -337,6 +338,8 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig
             return E_NOTIMPL;
         }
 
+        binding_count = use_array ? 1 : range->NumDescriptors;
+
         switch (range->RangeType)
         {
             case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
@@ -344,11 +347,11 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig
                 * 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. */
-                info->binding_count += range->NumDescriptors;
+                info->binding_count += binding_count;
                 break;
             case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
                 /* As above. */
-                info->binding_count += range->NumDescriptors;
+                info->binding_count += binding_count;
                 break;
             case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
                 break;
@@ -359,14 +362,14 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig
                 return E_NOTIMPL;
         }
 
-        info->binding_count += range->NumDescriptors;
+        info->binding_count += binding_count;
     }
 
     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, bool use_array)
 {
     unsigned int i;
     HRESULT hr;
@@ -381,7 +384,7 @@ static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_i
         {
             case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
                 if (FAILED(hr = d3d12_root_signature_info_count_descriptors(info,
-                        &p->u.DescriptorTable)))
+                        &p->u.DescriptorTable, use_array)))
                     return hr;
                 ++info->cost;
                 break;
@@ -518,7 +521,7 @@ 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)
+        unsigned int descriptor_count, struct vkd3d_descriptor_set_context *context)
 {
     struct vkd3d_shader_resource_binding *mapping
             = &root_signature->descriptor_mapping[context->descriptor_index++];
@@ -530,7 +533,7 @@ 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;
 }
 
 static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature,
@@ -551,10 +554,10 @@ 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, shader_visibility, 1, 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, shader_visibility, 1, context);
     }
     return first_binding;
 }
@@ -577,6 +580,36 @@ static uint32_t vkd3d_descriptor_magic_from_d3d12(D3D12_DESCRIPTOR_RANGE_TYPE ty
     }
 }
 
+static HRESULT d3d12_root_signature_init_descriptor_array_binding(struct d3d12_root_signature *root_signature,
+        const D3D12_DESCRIPTOR_RANGE *range, D3D12_SHADER_VISIBILITY visibility,
+        struct vkd3d_descriptor_set_context *context)
+{
+    enum vkd3d_shader_descriptor_type descriptor_type = vkd3d_descriptor_type_from_d3d12_range_type(range->RangeType);
+    enum vkd3d_shader_visibility shader_visibility = vkd3d_shader_visibility_from_d3d12(visibility);
+    bool is_buffer = descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV;
+
+    if (descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV || descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
+    {
+        if (!vk_binding_from_d3d12_descriptor_range(context->current_binding,
+                range, visibility, true, context->descriptor_binding, range->NumDescriptors))
+            return E_NOTIMPL;
+        ++context->current_binding;
+
+        d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->RegisterSpace,
+                range->BaseShaderRegister, true, shader_visibility, range->NumDescriptors, context);
+    }
+
+    if (!vk_binding_from_d3d12_descriptor_range(context->current_binding,
+            range, visibility, is_buffer, context->descriptor_binding, range->NumDescriptors))
+        return E_NOTIMPL;
+    ++context->current_binding;
+
+    d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->RegisterSpace,
+            range->BaseShaderRegister, is_buffer, shader_visibility, range->NumDescriptors, context);
+
+    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)
 {
@@ -584,6 +617,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
     const D3D12_DESCRIPTOR_RANGE *range;
     unsigned int i, j, k, range_count;
     uint32_t vk_binding;
+    HRESULT hr;
 
     root_signature->descriptor_table_mask = 0;
 
@@ -633,6 +667,17 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
 
             range = &p->u.DescriptorTable.pDescriptorRanges[j];
 
+            if (root_signature->use_descriptor_arrays)
+            {
+                table->ranges[j].binding = context->descriptor_binding;
+
+                if (FAILED(hr = d3d12_root_signature_init_descriptor_array_binding(root_signature,
+                        range, p->ShaderVisibility, context)))
+                    return hr;
+
+                continue;
+            }
+
             cur_binding = context->current_binding;
 
             vk_binding = d3d12_root_signature_assign_vk_bindings(root_signature,
@@ -652,14 +697,14 @@ 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, p->ShaderVisibility, false, vk_current_binding + 1, 1))
                         return E_NOTIMPL;
 
                     ++cur_binding;
                 }
 
                 if (!vk_binding_from_d3d12_descriptor_range(cur_binding,
-                        range, p->ShaderVisibility, true, vk_current_binding))
+                        range, p->ShaderVisibility, true, vk_current_binding, 1))
                     return E_NOTIMPL;
 
                 ++cur_binding;
@@ -742,11 +787,32 @@ static HRESULT d3d12_root_signature_init_static_samplers(struct d3d12_root_signa
     return S_OK;
 }
 
+static bool vk_binding_uses_partial_binding(const VkDescriptorSetLayoutBinding *binding)
+{
+    if (binding->descriptorCount == 1)
+        return false;
+
+    switch (binding->descriptorType)
+    {
+        /* Types mapped in vk_descriptor_type_from_d3d12_range_type() from D3D12 SRV and UAV types,
+         * i.e. those which can be a buffer or an image. */
+        case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+        case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+        case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+        case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+            return true;
+        default:
+            return false;
+    }
+}
+
 static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device,
         VkDescriptorSetLayoutCreateFlags flags, 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;
 
@@ -755,7 +821,35 @@ 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 (device->vk_info.EXT_descriptor_indexing)
+    {
+        unsigned int i;
+
+        for (i = 0; i < binding_count; ++i)
+            if (vk_binding_uses_partial_binding(&bindings[i]))
+                break;
+
+        if (i < binding_count)
+        {
+            if (!(set_flags = vkd3d_malloc(binding_count * sizeof(*set_flags))))
+                return E_OUTOFMEMORY;
+
+            for (i = 0; i < binding_count; ++i)
+                set_flags[i] = vk_binding_uses_partial_binding(&bindings[i])
+                        ? VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT : 0;
+
+            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;
+
+            set_desc.pNext = &flags_info;
+        }
+    }
+
+    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);
@@ -817,7 +911,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->vk_info.EXT_descriptor_indexing)))
         return hr;
     if (info.cost > D3D12_MAX_ROOT_COST)
     {
@@ -828,6 +922,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
     root_signature->binding_count = info.binding_count;
     root_signature->static_sampler_count = desc->NumStaticSamplers;
     root_signature->root_descriptor_count = info.root_descriptor_count;
+    root_signature->use_descriptor_arrays = device->vk_info.EXT_descriptor_indexing;
 
     hr = E_OUTOFMEMORY;
     root_signature->parameter_count = desc->NumParameters;
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index 70e3248f..deb8ee99 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -702,6 +702,7 @@ struct d3d12_root_signature
     VkPipelineLayout vk_pipeline_layout;
     uint32_t vk_set_count;
     VkDescriptorSetLayout vk_set_layouts[VKD3D_MAX_DESCRIPTOR_SETS];
+    bool use_descriptor_arrays;
 
     struct d3d12_root_parameter *parameters;
     unsigned int parameter_count;
diff --git a/tests/d3d12.c b/tests/d3d12.c
index b9f8c46c..e9f87382 100644
--- a/tests/d3d12.c
+++ b/tests/d3d12.c
@@ -34635,7 +34635,6 @@ static void test_resource_arrays(void)
                 get_cpu_descriptor_handle(&context, heap, ARRAY_SIZE(input_buffers) + i));
     }
 
-    todo
     context.pipeline_state = create_compute_pipeline_state(device, context.root_signature,
             shader_bytecode(cs_code, sizeof(cs_code)));
     if (!context.pipeline_state)
@@ -34658,7 +34657,6 @@ static void test_resource_arrays(void)
         transition_sub_resource_state(command_list, output_buffers[i], 0,
                 D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
         get_buffer_readback_with_command_list(output_buffers[i], DXGI_FORMAT_R32_UINT, &rb, queue, command_list);
-        todo_if(i)
         check_readback_data_uint(&rb, NULL, uav_data[i], 0);
         release_resource_readback(&rb);
         reset_command_list(command_list, context.allocator);
-- 
2.32.0




More information about the wine-devel mailing list