[PATCH vkd3d v2 3/3] vkd3d-shader: Emit SPIR-V for descriptor arrays and arrayed bindings.

Conor McCarthy cmccarthy at codeweavers.com
Thu Jun 3 00:01:24 CDT 2021


A SPIR-V array is declared if binding.count > 1 or the dxbc declares
an unbounded array.

Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 include/vkd3d_shader.h     |   6 +-
 libs/vkd3d-shader/spirv.c  | 356 ++++++++++++++++++++++++++++++-------
 libs/vkd3d/device.c        |   4 +
 libs/vkd3d/vkd3d_private.h |   2 +-
 4 files changed, 300 insertions(+), 68 deletions(-)

diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h
index 03225d37..922d0275 100644
--- a/include/vkd3d_shader.h
+++ b/include/vkd3d_shader.h
@@ -208,8 +208,9 @@ 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. Descriptor arrays are supported in
+     * this version of vkd3d-shader, but arrayed UAV counters and non-uniform
+     * array indexing are not.
      */
     unsigned int count;
 };
@@ -573,6 +574,7 @@ enum vkd3d_shader_spirv_extension
 {
     VKD3D_SHADER_SPIRV_EXTENSION_NONE,
     VKD3D_SHADER_SPIRV_EXTENSION_EXT_DEMOTE_TO_HELPER_INVOCATION,
+    VKD3D_SHADER_SPIRV_EXTENSION_EXT_DESCRIPTOR_INDEXING,
 
     VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SPIRV_EXTENSION),
 };
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index 0e75b0ae..cf2e5829 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2017 Józef Kucia 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
@@ -335,6 +336,7 @@ struct vkd3d_spirv_builder
     uint64_t capability_mask;
     uint64_t capability_draw_parameters : 1;
     uint64_t capability_demote_to_helper_invocation : 1;
+    uint64_t capability_descriptor_indexing : 1;
     uint32_t ext_instr_set_glsl_450;
     uint32_t invocation_count;
     SpvExecutionModel execution_model;
@@ -391,6 +393,11 @@ static void vkd3d_spirv_enable_capability(struct vkd3d_spirv_builder *builder,
     }
 }
 
+static void vkd3d_spirv_enable_descriptor_indexing(struct vkd3d_spirv_builder *builder)
+{
+    builder->capability_descriptor_indexing = 1;
+}
+
 static uint32_t vkd3d_spirv_get_glsl_std450_instr_set(struct vkd3d_spirv_builder *builder)
 {
     if (!builder->ext_instr_set_glsl_450)
@@ -1808,6 +1815,8 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder,
         vkd3d_spirv_build_op_extension(&stream, "SPV_KHR_shader_draw_parameters");
     if (builder->capability_demote_to_helper_invocation)
         vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_demote_to_helper_invocation");
+    if (builder->capability_descriptor_indexing)
+        vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_descriptor_indexing");
 
     if (builder->ext_instr_set_glsl_450)
         vkd3d_spirv_build_op_ext_inst_import(&stream, builder->ext_instr_set_glsl_450, "GLSL.std.450");
@@ -1926,6 +1935,7 @@ struct vkd3d_symbol_register_data
     unsigned int write_mask;
     uint32_t dcl_mask;
     unsigned int structure_stride;
+    unsigned int binding_base_idx;
     bool is_aggregate; /* An aggregate, i.e. a structure or an array. */
     bool is_dynamically_indexed; /* If member_idx is a variable ID instead of a constant. */
 };
@@ -1936,6 +1946,9 @@ struct vkd3d_symbol_resource_data
     unsigned int register_index;
     enum vkd3d_shader_component_type sampled_type;
     uint32_t type_id;
+    uint32_t contained_type_id;
+    unsigned int binding_base_idx;
+    SpvStorageClass storage_class;
     const struct vkd3d_spirv_resource_type *resource_type_info;
     unsigned int structure_stride;
     bool raw;
@@ -1977,6 +1990,35 @@ struct vkd3d_symbol
     } info;
 };
 
+struct vkd3d_array_variable_key
+{
+    uint32_t ptr_type_id;
+    unsigned int set;
+    unsigned int binding;
+};
+
+struct vkd3d_array_variable
+{
+    struct rb_entry entry;
+    struct vkd3d_array_variable_key key;
+    uint32_t id;
+};
+
+static int vkd3d_array_variable_compare(const void *key, const struct rb_entry *entry)
+{
+    const struct vkd3d_array_variable *a = key;
+    const struct vkd3d_array_variable *b = RB_ENTRY_VALUE(entry, const struct vkd3d_array_variable, entry);
+
+    return memcmp(&a->key, &b->key, sizeof(a->key));
+}
+
+static void vkd3d_array_variable_free(struct rb_entry *entry, void *context)
+{
+    struct vkd3d_array_variable *s = RB_ENTRY_VALUE(entry, struct vkd3d_array_variable, entry);
+
+    vkd3d_free(s);
+}
+
 static int vkd3d_symbol_compare(const void *key, const struct rb_entry *entry)
 {
     const struct vkd3d_symbol *a = key;
@@ -2012,6 +2054,7 @@ static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol,
 {
     symbol->id = val_id;
     symbol->info.reg.storage_class = storage_class;
+    symbol->info.reg.binding_base_idx = ~0u;
     symbol->info.reg.member_idx = 0;
     symbol->info.reg.component_type = component_type;
     symbol->info.reg.write_mask = write_mask;
@@ -2077,6 +2120,14 @@ static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol)
     }
 }
 
+static const char *debug_register_range(unsigned int register_first, unsigned int register_last, bool bounded)
+{
+    if (bounded)
+        return vkd3d_dbg_sprintf("[%u:%u]", register_first, register_last);
+    else
+        return vkd3d_dbg_sprintf("[%u:*]", register_first);
+}
+
 struct vkd3d_if_cf_info
 {
     size_t stream_location;
@@ -2164,11 +2215,13 @@ struct vkd3d_dxbc_compiler
     bool ssbo_uavs;
 
     struct rb_tree symbol_table;
+    struct rb_tree array_var_table;
     uint32_t temp_id;
     unsigned int temp_count;
     struct vkd3d_hull_shader_variables hs;
     uint32_t sample_positions_id;
 
+    struct vkd3d_shader_version shader_version;
     enum vkd3d_shader_type shader_type;
 
     unsigned int branch_id;
@@ -2216,6 +2269,11 @@ struct vkd3d_dxbc_compiler
     enum vkd3d_shader_compile_option_formatting_flags formatting;
 };
 
+static bool shader_is_sm_5_1(const struct vkd3d_dxbc_compiler *compiler)
+{
+    return (((unsigned int)compiler->shader_version.major << 8) + compiler->shader_version.minor) >= 0x501;
+}
+
 static bool is_control_point_phase(const struct vkd3d_shader_phase *phase)
 {
     return phase && phase->type == VKD3DSIH_HS_CONTROL_POINT_PHASE;
@@ -2309,7 +2367,9 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader
     }
 
     rb_init(&compiler->symbol_table, vkd3d_symbol_compare);
+    rb_init(&compiler->array_var_table, vkd3d_array_variable_compare);
 
+    compiler->shader_version = *shader_version;
     compiler->shader_type = shader_version->type;
 
     compiler->input_signature = &shader_desc->input_signature;
@@ -2404,9 +2464,12 @@ static struct vkd3d_push_constant_buffer_binding *vkd3d_dxbc_compiler_find_push_
         const struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_constant_buffer *cb)
 {
     unsigned int register_space = cb->register_space;
-    unsigned int reg_idx = cb->register_index;
+    unsigned int reg_idx = cb->register_first;
     unsigned int i;
 
+    if (cb->register_first != cb->register_last)
+        return NULL;
+
     for (i = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i)
     {
         struct vkd3d_push_constant_buffer_binding *current = &compiler->push_constants[i];
@@ -2431,7 +2494,10 @@ static bool vkd3d_dxbc_compiler_has_combined_sampler(const struct vkd3d_dxbc_com
     if (!shader_interface->combined_sampler_count)
         return false;
 
-    if (resource && resource->reg.reg.type == VKD3DSPR_UAV)
+    if (resource && (resource->reg.reg.type == VKD3DSPR_UAV || resource->register_last != resource->register_first))
+        return false;
+
+    if (sampler && sampler->register_first != sampler->register_last)
         return false;
 
     for (i = 0; i < shader_interface->combined_sampler_count; ++i)
@@ -2442,9 +2508,9 @@ static bool vkd3d_dxbc_compiler_has_combined_sampler(const struct vkd3d_dxbc_com
             continue;
 
         if ((!resource || (combined_sampler->resource_space == resource->register_space
-                && combined_sampler->resource_index == resource->register_index))
+                && combined_sampler->resource_index == resource->register_first))
                 && (!sampler || (combined_sampler->sampler_space == sampler->register_space
-                && combined_sampler->sampler_index == sampler->register_index)))
+                && combined_sampler->sampler_index == sampler->register_first)))
             return true;
     }
 
@@ -2464,12 +2530,14 @@ static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_dxbc_compiler_error(struct vkd3d_dxbc_
 
 static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_binding(
         struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg, unsigned int register_space,
-        unsigned int reg_idx, enum vkd3d_shader_resource_type resource_type, bool is_uav_counter)
+        unsigned int register_first, unsigned int register_last, enum vkd3d_shader_resource_type resource_type,
+        bool is_uav_counter, unsigned int *binding_base_idx)
 {
     const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
     enum vkd3d_shader_descriptor_type descriptor_type;
     enum vkd3d_shader_binding_flag resource_type_flag;
     struct vkd3d_shader_descriptor_binding binding;
+    bool bounded = true;
     unsigned int i;
 
     if (reg->type == VKD3DSPR_CONSTBUFFER)
@@ -2491,6 +2559,12 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor
     resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER
             ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
 
+    if (register_last == ~0u)
+    {
+        bounded = false;
+        register_last = register_first;
+    }
+
     if (is_uav_counter)
     {
         assert(descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV);
@@ -2501,32 +2575,37 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor
             if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->shader_visibility))
                 continue;
 
-            if (current->register_space != register_space || current->register_index != reg_idx)
+            if (current->register_space != register_space || current->register_index > register_first
+                    || current->register_index + current->binding.count <= register_last)
                 continue;
 
             if (current->offset)
             {
                 FIXME("Atomic counter offsets are not supported yet.\n");
                 vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
-                        "Descriptor binding for UAV counter %u, space %u has unsupported ‘offset’ %u.",
-                        reg_idx, register_space, current->offset);
+                        "Descriptor binding for UAV counter %s, space %u has unsupported ‘offset’ %u.",
+                        debug_register_range(register_first, register_last, bounded),
+                        register_space, current->offset);
             }
 
-            if (current->binding.count != 1)
+            if (current->binding.count != 1 || !bounded)
             {
                 FIXME("Descriptor arrays are not supported.\n");
                 vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
                         "Descriptor binding for UAV counter %u, space %u has unsupported ‘count’ %u.",
-                        reg_idx, register_space, current->binding.count);
+                        register_first, register_space, current->binding.count);
             }
 
+            *binding_base_idx = ~0u;
             return current->binding;
         }
         if (shader_interface->uav_counter_count)
         {
-            FIXME("Could not find descriptor binding for UAV counter %u, space %u.\n", reg_idx, register_space);
+            FIXME("Could not find descriptor binding for UAV counters %s, space %u.\n",
+                    debug_register_range(register_first, register_last, bounded), register_space);
             vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND,
-                    "Could not find descriptor binding for UAV counter %u, space %u.", reg_idx, register_space);
+                    "Could not find descriptor binding for UAV counters %s, space %u.",
+                    debug_register_range(register_first, register_last, bounded), register_space);
         }
     }
     else
@@ -2542,31 +2621,27 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor
                 continue;
 
             if (current->type != descriptor_type || current->register_space != register_space
-                    || current->register_index != reg_idx)
+                    || current->register_index > register_first
+                    || current->register_index + current->binding.count <= register_last)
                 continue;
 
-            if (current->binding.count != 1)
-            {
-                FIXME("Descriptor arrays are not supported.\n");
-                vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING,
-                        "Descriptor binding for type %#x, space %u, register %u, "
-                        "shader type %#x has unsupported ‘count’ %u.",
-                        descriptor_type, register_space, reg_idx, compiler->shader_type, current->binding.count);
-            }
-
+            *binding_base_idx = (current->binding.count != 1 || !bounded) ? current->register_index : ~0u;
             return current->binding;
         }
         if (shader_interface->binding_count)
         {
-            FIXME("Could not find binding for type %#x, space %u, register %u, shader type %#x.\n",
-                    descriptor_type, register_space, reg_idx, compiler->shader_type);
+            FIXME("Could not find binding for type %#x, space %u, registers %s, shader type %#x.\n",
+                    descriptor_type, register_space, debug_register_range(register_first, register_last, bounded),
+                    compiler->shader_type);
             vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND,
-                    "Could not find descriptor binding for type %#x, space %u, register %u, shader type %#x.",
-                    descriptor_type, register_space, reg_idx, compiler->shader_type);
+                    "Could not find descriptor binding for type %#x, space %u, registers %s, shader type %#x.",
+                    descriptor_type, register_space, debug_register_range(register_first, register_last, bounded),
+                    compiler->shader_type);
         }
     }
 
 done:
+    *binding_base_idx = ~0u;
     binding.set = 0;
     binding.count = 1;
     binding.binding = compiler->binding_idx++;
@@ -2584,12 +2659,14 @@ static void vkd3d_dxbc_compiler_emit_descriptor_binding(struct vkd3d_dxbc_compil
 
 static void vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(struct vkd3d_dxbc_compiler *compiler,
         uint32_t variable_id, const struct vkd3d_shader_register *reg, unsigned int register_space,
-        unsigned int register_index, enum vkd3d_shader_resource_type resource_type, bool is_uav_counter)
+        unsigned int register_first, unsigned int register_last, enum vkd3d_shader_resource_type resource_type,
+        bool is_uav_counter)
 {
     struct vkd3d_shader_descriptor_binding binding;
+    unsigned int binding_base_idx; /* Not used because UAV counter arrays are not implemented. */
 
     binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, register_space,
-            register_index, resource_type, is_uav_counter);
+            register_first, register_last, resource_type, is_uav_counter, &binding_base_idx);
     vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding);
 }
 
@@ -2814,6 +2891,66 @@ static uint32_t vkd3d_dxbc_compiler_emit_array_variable(struct vkd3d_dxbc_compil
     return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0);
 }
 
+static uint32_t vkd3d_dxbc_compiler_get_resource_variable(struct vkd3d_dxbc_compiler *compiler,
+        SpvStorageClass storage_class, uint32_t ptr_type_id, const struct vkd3d_shader_register *reg,
+        const struct vkd3d_shader_descriptor_binding *binding, bool array_variable)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+    if (array_variable)
+    {
+        struct vkd3d_array_variable *array_var_entry;
+        struct vkd3d_array_variable array_var;
+        struct rb_entry *entry;
+
+        /* Declare one array variable per Vulkan binding, and use it for all array declarations
+         * which map to it. In this case ptr_type_id must point to an array type. */
+        array_var.key.ptr_type_id = ptr_type_id;
+        array_var.key.set = binding->set;
+        array_var.key.binding = binding->binding;
+        if ((entry = rb_get(&compiler->array_var_table, &array_var)))
+        {
+            array_var_entry = RB_ENTRY_VALUE(entry, struct vkd3d_array_variable, entry);
+            return array_var_entry->id;
+        }
+
+        array_var.id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+            ptr_type_id, storage_class, 0);
+        vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, array_var.id, binding);
+        vkd3d_dxbc_compiler_emit_register_debug_name(builder, array_var.id, reg);
+
+        array_var_entry = vkd3d_malloc(sizeof(*array_var_entry));
+        memcpy(array_var_entry, &array_var, sizeof(*array_var_entry));
+        rb_put(&compiler->array_var_table, array_var_entry, &array_var_entry->entry);
+
+        return array_var.id;
+    }
+    else
+    {
+        uint32_t var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
+                ptr_type_id, storage_class, 0);
+        vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, binding);
+        vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+        return var_id;
+    }
+}
+
+static uint32_t vkd3d_dxbc_compiler_build_resource_variable(struct vkd3d_dxbc_compiler *compiler,
+        SpvStorageClass storage_class, uint32_t type_id, const struct vkd3d_shader_register *reg,
+        const struct vkd3d_shader_descriptor_binding *binding, bool array_variable)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t ptr_type_id;
+
+    if (array_variable)
+        type_id = vkd3d_spirv_get_op_type_array(builder, type_id,
+                vkd3d_dxbc_compiler_get_constant_uint(compiler, binding->count));
+    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+
+    return vkd3d_dxbc_compiler_get_resource_variable(compiler, storage_class,
+            ptr_type_id, reg, binding, array_variable);
+}
+
 static const struct vkd3d_shader_parameter *vkd3d_dxbc_compiler_get_shader_parameter(
         struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_parameter_name name)
 {
@@ -2997,6 +3134,7 @@ struct vkd3d_shader_register_info
     SpvStorageClass storage_class;
     enum vkd3d_shader_component_type component_type;
     unsigned int write_mask;
+    unsigned int binding_base_idx;
     uint32_t member_idx;
     unsigned int structure_stride;
     bool is_aggregate;
@@ -3016,6 +3154,7 @@ static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compil
         assert(reg->idx[0].offset < compiler->temp_count);
         register_info->id = compiler->temp_id + reg->idx[0].offset;
         register_info->storage_class = SpvStorageClassFunction;
+        register_info->binding_base_idx = ~0u;
         register_info->member_idx = 0;
         register_info->component_type = VKD3D_SHADER_COMPONENT_FLOAT;
         register_info->write_mask = VKD3DSP_WRITEMASK_ALL;
@@ -3036,6 +3175,7 @@ static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compil
     symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
     register_info->id = symbol->id;
     register_info->storage_class = symbol->info.reg.storage_class;
+    register_info->binding_base_idx = symbol->info.reg.binding_base_idx;
     register_info->member_idx = symbol->info.reg.member_idx;
     register_info->component_type = symbol->info.reg.component_type;
     register_info->write_mask = symbol->info.reg.write_mask;
@@ -3061,17 +3201,42 @@ static bool register_is_descriptor(const struct vkd3d_shader_register *reg)
     }
 }
 
+static uint32_t vkd3d_dxbc_compiler_get_resource_index(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, unsigned int binding_base_idx)
+{
+    uint32_t index_id;
+
+    if (shader_is_sm_5_1(compiler))
+    {
+        struct vkd3d_shader_register_index index = reg->idx[1];
+
+        if (index.rel_addr)
+            vkd3d_spirv_enable_descriptor_indexing(&compiler->spirv_builder);
+
+        index.offset -= binding_base_idx;
+        index_id = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &index);
+    }
+    else
+    {
+        index_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, reg->idx[0].offset - binding_base_idx);
+    }
+
+    return index_id;
+}
+
 static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_compiler *compiler,
         const struct vkd3d_shader_register *reg, struct vkd3d_shader_register_info *register_info)
 {
     struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
     unsigned int component_count, index_count = 0;
     uint32_t type_id, ptr_type_id;
-    uint32_t indexes[2];
+    uint32_t indexes[3];
 
     if (reg->type == VKD3DSPR_CONSTBUFFER)
     {
         assert(!reg->idx[0].rel_addr);
+        if (register_info->binding_base_idx != ~0u)
+            indexes[index_count++] = vkd3d_dxbc_compiler_get_resource_index(compiler, reg, register_info->binding_base_idx);
         indexes[index_count++] = vkd3d_dxbc_compiler_get_constant_uint(compiler, register_info->member_idx);
         indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &reg->idx[2]);
     }
@@ -5268,13 +5433,15 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com
 static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compiler *compiler,
         const struct vkd3d_shader_instruction *instruction)
 {
-    uint32_t vec4_id, array_type_id, length_id, struct_id, pointer_type_id, var_id;
+    uint32_t vec4_id, array_type_id, length_id, struct_id, var_id;
     const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb;
     struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
     const SpvStorageClass storage_class = SpvStorageClassUniform;
     const struct vkd3d_shader_register *reg = &cb->src.reg;
     struct vkd3d_push_constant_buffer_binding *push_cb;
+    struct vkd3d_shader_descriptor_binding binding;
     struct vkd3d_symbol reg_symbol;
+    unsigned int binding_base_idx;
 
     assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC));
 
@@ -5304,18 +5471,16 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi
     vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0);
     vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", cb->size);
 
-    pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
-    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
-            pointer_type_id, storage_class, 0);
+    binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, cb->register_space,
+            cb->register_first, cb->register_last, VKD3D_SHADER_RESOURCE_BUFFER, false, &binding_base_idx);
 
-    vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler,
-            var_id, reg, cb->register_space, cb->register_index, VKD3D_SHADER_RESOURCE_BUFFER, false);
-
-    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+    var_id = vkd3d_dxbc_compiler_build_resource_variable(compiler, storage_class, struct_id,
+            reg, &binding, binding_base_idx != ~0u || cb->register_last == ~0u);
 
     vkd3d_symbol_make_register(&reg_symbol, reg);
     vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
             VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+    reg_symbol.info.reg.binding_base_idx = binding_base_idx;
     vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
 }
 
@@ -5359,30 +5524,30 @@ static void vkd3d_dxbc_compiler_emit_dcl_sampler(struct vkd3d_dxbc_compiler *com
     const SpvStorageClass storage_class = SpvStorageClassUniformConstant;
     struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
     const struct vkd3d_shader_register *reg = &sampler->src.reg;
-    uint32_t type_id, ptr_type_id, var_id;
+    struct vkd3d_shader_descriptor_binding binding;
+    unsigned int binding_base_idx;
+    uint32_t type_id, var_id;
     struct vkd3d_symbol reg_symbol;
 
     vkd3d_symbol_make_sampler(&reg_symbol, reg);
     reg_symbol.info.sampler.register_space = sampler->register_space;
-    reg_symbol.info.sampler.register_index = sampler->register_index;
+    reg_symbol.info.sampler.register_index = sampler->register_first;
     vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
 
     if (vkd3d_dxbc_compiler_has_combined_sampler(compiler, NULL, sampler))
         return;
 
-    type_id = vkd3d_spirv_get_op_type_sampler(builder);
-    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
-    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
-            ptr_type_id, storage_class, 0);
-
-    vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler, var_id, reg,
-            sampler->register_space, sampler->register_index, VKD3D_SHADER_RESOURCE_NONE, false);
+    binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, sampler->register_space,
+            sampler->register_first, sampler->register_last, VKD3D_SHADER_RESOURCE_NONE, false, &binding_base_idx);
 
-    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+    type_id = vkd3d_spirv_get_op_type_sampler(builder);
+    var_id = vkd3d_dxbc_compiler_build_resource_variable(compiler, storage_class,
+            type_id, reg, &binding, binding_base_idx != ~0u || sampler->register_last == ~0u);
 
     vkd3d_symbol_make_register(&reg_symbol, reg);
     vkd3d_symbol_set_register_info(&reg_symbol, var_id, storage_class,
             VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+    reg_symbol.info.reg.binding_base_idx = binding_base_idx;
     vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
 }
 
@@ -5434,7 +5599,8 @@ static const struct vkd3d_shader_descriptor_info *vkd3d_dxbc_compiler_get_descri
     for (i = 0; i < descriptor_info->descriptor_count; ++i)
     {
         d = &descriptor_info->descriptors[i];
-        if (d->type == type && d->register_space == register_space && d->register_index == register_index)
+        if (d->type == type && d->register_space == register_space && d->register_index <= register_index
+                    && (d->count == ~0u || d->register_index + d->count > register_index))
             return d;
     }
 
@@ -5537,6 +5703,9 @@ static void vkd3d_dxbc_compiler_emit_combined_sampler_declarations(struct vkd3d_
         symbol.info.resource.register_index = resource_index;
         symbol.info.resource.sampled_type = sampled_type;
         symbol.info.resource.type_id = image_type_id;
+        symbol.info.resource.contained_type_id = 0;
+        symbol.info.resource.binding_base_idx = ~0u;
+        symbol.info.resource.storage_class = storage_class;
         symbol.info.resource.resource_type_info = resource_type_info;
         symbol.info.resource.structure_stride = structure_stride;
         symbol.info.resource.raw = raw;
@@ -5555,9 +5724,13 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp
     const struct vkd3d_shader_register *reg = &resource->reg.reg;
     const struct vkd3d_spirv_resource_type *resource_type_info;
     unsigned int register_space = resource->register_space;
-    unsigned int register_index = resource->register_index;
+    unsigned int register_first = resource->register_first;
+    unsigned int register_last = resource->register_last;
+    struct vkd3d_shader_descriptor_binding binding;
     enum vkd3d_shader_component_type sampled_type;
     struct vkd3d_symbol resource_symbol;
+    uint32_t contained_type_id = 0;
+    unsigned int binding_base_idx;
     bool is_uav;
 
     is_uav = reg->type == VKD3DSPR_UAV;
@@ -5573,10 +5746,13 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp
     if (vkd3d_dxbc_compiler_has_combined_sampler(compiler, resource, NULL))
     {
         vkd3d_dxbc_compiler_emit_combined_sampler_declarations(compiler, reg, register_space,
-                register_index, resource_type, sampled_type, structure_stride, raw, resource_type_info);
+                register_first, resource_type, sampled_type, structure_stride, raw, resource_type_info);
         return;
     }
 
+    binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, register_space,
+            register_first, register_last, resource_type, false, &binding_base_idx);
+
     if (compiler->ssbo_uavs && is_uav && resource_type == VKD3D_SHADER_RESOURCE_BUFFER)
     {
         uint32_t array_type_id, struct_id;
@@ -5596,24 +5772,27 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp
     else
     {
         type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, reg, register_space,
-                register_index, resource_type_info, sampled_type, structure_stride || raw, 0);
+                register_first, resource_type_info, sampled_type, structure_stride || raw, 0);
+
+        if (binding_base_idx != ~0u || register_last == ~0u)
+        {
+            contained_type_id = type_id;
+            type_id = vkd3d_spirv_get_op_type_array(builder, type_id,
+                    vkd3d_dxbc_compiler_get_constant_uint(compiler, binding.count));
+        }
     }
 
     ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
-    var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
-            ptr_type_id, storage_class, 0);
 
-    vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler, var_id, reg,
-            register_space, register_index, resource_type, false);
-
-    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+    var_id = vkd3d_dxbc_compiler_get_resource_variable(compiler, storage_class,
+            ptr_type_id, reg, &binding, binding_base_idx != ~0u || register_last == ~0u);
 
     if (is_uav)
     {
         const struct vkd3d_shader_descriptor_info *d;
 
         d = vkd3d_dxbc_compiler_get_descriptor_info(compiler,
-                VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, register_space, register_index);
+                VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, register_space, register_first);
 
         if (!(d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ))
             vkd3d_spirv_build_op_decorate(builder, var_id, SpvDecorationNonReadable, NULL, 0);
@@ -5644,12 +5823,18 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp
                 storage_class = SpvStorageClassUniform;
                 ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
             }
+            else if (contained_type_id)
+            {
+                /* TODO: Not needed after UAV counter arrays are implemented. */
+                ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, contained_type_id);
+            }
 
             counter_var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
                     ptr_type_id, storage_class, 0);
 
             vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler,
-                    counter_var_id, reg, register_space, register_index, resource_type, true);
+                    counter_var_id, reg, register_space, register_first, register_last,
+                    resource_type, true);
 
             vkd3d_spirv_build_op_name(builder, counter_var_id, "u%u_counter", reg->idx[0].offset);
         }
@@ -5658,9 +5843,12 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp
     vkd3d_symbol_make_resource(&resource_symbol, reg);
     resource_symbol.id = var_id;
     resource_symbol.info.resource.register_space = register_space;
-    resource_symbol.info.resource.register_index = register_index;
+    resource_symbol.info.resource.register_index = register_first;
     resource_symbol.info.resource.sampled_type = sampled_type;
     resource_symbol.info.resource.type_id = type_id;
+    resource_symbol.info.resource.contained_type_id = contained_type_id;
+    resource_symbol.info.resource.binding_base_idx = binding_base_idx;
+    resource_symbol.info.resource.storage_class = storage_class;
     resource_symbol.info.resource.resource_type_info = resource_type_info;
     resource_symbol.info.resource.structure_stride = structure_stride;
     resource_symbol.info.resource.raw = raw;
@@ -7652,9 +7840,27 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil
     if (!symbol)
         symbol = vkd3d_dxbc_compiler_find_resource(compiler, resource_reg);
 
-    image->id = symbol->id;
+    if (symbol->info.resource.binding_base_idx != ~0u)
+    {
+        uint32_t ptr_type_id, index_id;
+
+        index_id = vkd3d_dxbc_compiler_get_resource_index(compiler,
+                resource_reg, symbol->info.resource.binding_base_idx);
+
+        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder,
+                symbol->info.resource.storage_class,
+                symbol->info.resource.contained_type_id);
+        image->image_type_id = symbol->info.resource.contained_type_id;
+
+        image->id = vkd3d_spirv_build_op_access_chain(builder,
+                ptr_type_id, symbol->id, &index_id, 1);
+    }
+    else
+    {
+        image->id = symbol->id;
+        image->image_type_id = symbol->info.resource.type_id;
+    }
     image->sampled_type = symbol->info.resource.sampled_type;
-    image->image_type_id = symbol->info.resource.type_id;
     image->resource_type_info = symbol->info.resource.resource_type_info;
     image->structure_stride = symbol->info.resource.structure_stride;
     image->raw = symbol->info.resource.raw;
@@ -7669,8 +7875,15 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil
         return;
     }
 
-    image->image_id = load ? vkd3d_spirv_build_op_load(builder,
-            image->image_type_id, image->id, SpvMemoryAccessMaskNone) : 0;
+    if (load)
+    {
+        image->image_id = vkd3d_spirv_build_op_load(builder,
+                image->image_type_id, image->id, SpvMemoryAccessMaskNone);
+    }
+    else
+    {
+        image->image_id = 0;
+    }
 
     image->image_type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, resource_reg,
             symbol->info.resource.register_space, symbol->info.resource.register_index, image->resource_type_info,
@@ -7678,10 +7891,22 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil
 
     if (sampled)
     {
+        struct vkd3d_shader_register_info register_info;
         assert(image->image_id);
         assert(sampler_reg);
 
-        sampler_var_id = vkd3d_dxbc_compiler_get_register_id(compiler, sampler_reg);
+        if (!vkd3d_dxbc_compiler_get_register_info(compiler, sampler_reg, &register_info))
+            ERR("Failed to get sampler register info.\n");
+        sampler_var_id = register_info.id;
+        if (register_info.binding_base_idx != ~0u)
+        {
+            uint32_t ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder,
+                    register_info.storage_class, vkd3d_spirv_get_op_type_sampler(builder));
+            uint32_t array_idx = vkd3d_dxbc_compiler_get_resource_index(compiler,
+                    sampler_reg, register_info.binding_base_idx);
+            sampler_var_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
+                    register_info.id, &array_idx, 1);
+        }
 
         sampler_id = vkd3d_spirv_build_op_load(builder,
                 vkd3d_spirv_get_op_type_sampler(builder), sampler_var_id, SpvMemoryAccessMaskNone);
@@ -9469,6 +9694,7 @@ void vkd3d_dxbc_compiler_destroy(struct vkd3d_dxbc_compiler *compiler)
     vkd3d_spirv_builder_free(&compiler->spirv_builder);
 
     rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
+    rb_destroy(&compiler->array_var_table, vkd3d_array_variable_free, NULL);
 
     vkd3d_free(compiler->shader_phases);
     vkd3d_free(compiler->spec_constants);
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index a63fc92b..9bce22cf 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -1457,6 +1457,10 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
         vulkan_info->shader_extensions[0] = VKD3D_SHADER_SPIRV_EXTENSION_EXT_DEMOTE_TO_HELPER_INVOCATION;
     }
 
+    if (vulkan_info->EXT_descriptor_indexing)
+        vulkan_info->shader_extensions[vulkan_info->shader_extension_count++]
+                = VKD3D_SHADER_SPIRV_EXTENSION_EXT_DESCRIPTOR_INDEXING;
+
     /* Disable unused Vulkan features. */
     features->shaderTessellationAndGeometryPointSize = VK_FALSE;
 
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index b30e38e9..8dbb05b5 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -51,7 +51,7 @@
 
 #define VKD3D_MAX_COMPATIBLE_FORMAT_COUNT 6u
 #define VKD3D_MAX_QUEUE_FAMILY_COUNT      3u
-#define VKD3D_MAX_SHADER_EXTENSIONS       1u
+#define VKD3D_MAX_SHADER_EXTENSIONS       2u
 #define VKD3D_MAX_SHADER_STAGES           5u
 #define VKD3D_MAX_VK_SYNC_OBJECTS         4u
 #define VKD3D_MAX_DESCRIPTOR_SETS         2u
-- 
2.31.1




More information about the wine-devel mailing list