[PATCH vkd3d v3 3/5] vkd3d-shader: Introduce to struct vkd3d_symbol a descriptor array symbol type.

Conor McCarthy cmccarthy at codeweavers.com
Fri Jul 23 08:01:37 CDT 2021


Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 libs/vkd3d-shader/spirv.c                | 137 ++++++++++++++++++++---
 libs/vkd3d-shader/vkd3d_shader_private.h |   1 +
 2 files changed, 125 insertions(+), 13 deletions(-)

diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index fe839adf..d4debc86 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
@@ -1920,6 +1921,13 @@ struct vkd3d_symbol_combined_sampler
     unsigned int sampler_index;
 };
 
+struct vkd3d_symbol_descriptor_array
+{
+    uint32_t ptr_type_id;
+    unsigned int set;
+    unsigned int binding;
+};
+
 struct vkd3d_symbol_register_data
 {
     SpvStorageClass storage_class;
@@ -1948,6 +1956,13 @@ struct vkd3d_symbol_sampler_data
     struct vkd3d_shader_register_range range;
 };
 
+struct vkd3d_symbol_descriptor_array_data
+{
+    SpvStorageClass storage_class;
+    uint32_t contained_type_id;
+    unsigned int binding_base_idx;
+};
+
 struct vkd3d_symbol
 {
     struct rb_entry entry;
@@ -1958,6 +1973,7 @@ struct vkd3d_symbol
         VKD3D_SYMBOL_RESOURCE,
         VKD3D_SYMBOL_SAMPLER,
         VKD3D_SYMBOL_COMBINED_SAMPLER,
+        VKD3D_SYMBOL_DESCRIPTOR_ARRAY,
     } type;
 
     union
@@ -1966,14 +1982,19 @@ struct vkd3d_symbol
         struct vkd3d_symbol_resource resource;
         struct vkd3d_symbol_sampler sampler;
         struct vkd3d_symbol_combined_sampler combined_sampler;
+        struct vkd3d_symbol_descriptor_array descriptor_array;
     } key;
 
     uint32_t id;
+    /* The array declaration which this symbol maps to, or NULL. */
+    const struct vkd3d_symbol *descriptor_array;
+
     union
     {
         struct vkd3d_symbol_register_data reg;
         struct vkd3d_symbol_resource_data resource;
         struct vkd3d_symbol_sampler_data sampler;
+        struct vkd3d_symbol_descriptor_array_data descriptor_array;
     } info;
 };
 
@@ -2011,6 +2032,7 @@ static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol,
         enum vkd3d_shader_component_type component_type, DWORD write_mask)
 {
     symbol->id = val_id;
+    symbol->descriptor_array = NULL;
     symbol->info.reg.storage_class = storage_class;
     symbol->info.reg.member_idx = 0;
     symbol->info.reg.component_type = component_type;
@@ -2494,7 +2516,7 @@ static struct vkd3d_string_buffer *vkd3d_dxbc_compiler_binding_error(struct vkd3
 static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_binding(
         struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg,
         const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type,
-        bool is_uav_counter)
+        bool is_uav_counter, unsigned int *binding_base_idx)
 {
     const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface;
     unsigned int register_last = (range->last == ~0u) ? range->first : range->last;
@@ -2551,6 +2573,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor
                         range->first, range->space, current->binding.count);
             }
 
+            *binding_base_idx = current->register_index;
             return current->binding;
         }
         if (shader_interface->uav_counter_count)
@@ -2577,6 +2600,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor
                     || current->binding.count <= register_last - current->register_index)
                 continue;
 
+            *binding_base_idx = current->register_index;
             return current->binding;
         }
         if (shader_interface->binding_count)
@@ -2591,6 +2615,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor
     }
 
 done:
+    *binding_base_idx = range->first;
     binding.set = 0;
     binding.count = 1;
     binding.binding = compiler->binding_idx++;
@@ -2611,12 +2636,14 @@ static void vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(struct vkd3d_dxb
         enum vkd3d_shader_resource_type resource_type, bool is_uav_counter)
 {
     struct vkd3d_shader_descriptor_binding binding;
+    unsigned int binding_base_idx; /* Value not used. */
 
-    binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range, resource_type, is_uav_counter);
+    binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range, resource_type, is_uav_counter,
+            &binding_base_idx);
     vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding);
 }
 
-static void vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler,
+static const struct vkd3d_symbol *vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler,
         const struct vkd3d_symbol *symbol)
 {
     struct vkd3d_symbol *s;
@@ -2626,7 +2653,9 @@ static void vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler,
     {
         ERR("Failed to insert symbol entry (%s).\n", debug_vkd3d_symbol(symbol));
         vkd3d_free(s);
+        return NULL;
     }
+    return s;
 }
 
 static uint32_t vkd3d_dxbc_compiler_get_constant(struct vkd3d_dxbc_compiler *compiler,
@@ -3017,6 +3046,7 @@ static uint32_t vkd3d_dxbc_compiler_emit_register_addressing(struct vkd3d_dxbc_c
 struct vkd3d_shader_register_info
 {
     uint32_t id;
+    const struct vkd3d_symbol *descriptor_array;
     SpvStorageClass storage_class;
     enum vkd3d_shader_component_type component_type;
     unsigned int write_mask;
@@ -3039,6 +3069,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->descriptor_array = NULL;
         register_info->member_idx = 0;
         register_info->component_type = VKD3D_SHADER_COMPONENT_FLOAT;
         register_info->write_mask = VKD3DSP_WRITEMASK_ALL;
@@ -3058,6 +3089,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->descriptor_array = symbol->descriptor_array;
     register_info->storage_class = symbol->info.reg.storage_class;
     register_info->member_idx = symbol->info.reg.member_idx;
     register_info->component_type = symbol->info.reg.component_type;
@@ -3084,17 +3116,40 @@ static bool register_is_descriptor(const struct vkd3d_shader_register *reg)
     }
 }
 
+static uint32_t vkd3d_dxbc_compiler_get_descriptor_index(struct vkd3d_dxbc_compiler *compiler,
+        const struct vkd3d_shader_register *reg, unsigned int binding_base_idx)
+{
+    struct vkd3d_shader_register_index index = reg->idx[1];
+    uint32_t index_id;
+
+    if (index.rel_addr)
+    {
+        FIXME("Descriptor dynamic indexing is not supported.\n");
+        vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED,
+                "Cannot dynamically index a descriptor array of type %#x, id %u. "
+                "Dynamic indexing is not supported.", reg->type, reg->idx[0].offset);
+    }
+
+    index.offset -= binding_base_idx;
+    index_id = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &index);
+
+    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->descriptor_array)
+            indexes[index_count++] = vkd3d_dxbc_compiler_get_descriptor_index(compiler, reg,
+                    register_info->descriptor_array->info.descriptor_array.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]);
     }
@@ -5298,15 +5353,76 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com
     }
 }
 
+static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_compiler *compiler,
+        SpvStorageClass storage_class, uint32_t type_id, const struct vkd3d_shader_register *reg,
+        const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type,
+        const struct vkd3d_symbol **array_symbol)
+{
+    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    struct vkd3d_shader_descriptor_binding binding;
+    uint32_t array_type_id, ptr_type_id, var_id;
+    unsigned int binding_base_idx;
+    struct vkd3d_symbol symbol;
+    struct rb_entry *entry;
+
+    binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range,
+            resource_type, false, &binding_base_idx);
+
+    if (binding.count == 1 && range->last != ~0u)
+    {
+        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(compiler, var_id, &binding);
+        vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+
+        *array_symbol = NULL;
+        return var_id;
+    }
+
+    array_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, array_type_id);
+
+    /* Declare one array variable per Vulkan binding, and use it for
+     * all array declarations which map to it. */
+    symbol.type = VKD3D_SYMBOL_DESCRIPTOR_ARRAY;
+    memset(&symbol.key, 0, sizeof(symbol.key));
+    symbol.key.descriptor_array.ptr_type_id = ptr_type_id;
+    symbol.key.descriptor_array.set = binding.set;
+    symbol.key.descriptor_array.binding = binding.binding;
+    if ((entry = rb_get(&compiler->symbol_table, &symbol)))
+    {
+        *array_symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
+        return (*array_symbol)->id;
+    }
+
+    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);
+
+    symbol.id = var_id;
+    symbol.descriptor_array = NULL;
+    symbol.info.descriptor_array.storage_class = storage_class;
+    symbol.info.descriptor_array.contained_type_id = type_id;
+    symbol.info.descriptor_array.binding_base_idx = binding_base_idx;
+    *array_symbol = vkd3d_dxbc_compiler_put_symbol(compiler, &symbol);
+
+    return var_id;
+}
+
 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;
     const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb;
     struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+    uint32_t vec4_id, array_type_id, length_id, struct_id, var_id;
     const SpvStorageClass storage_class = SpvStorageClassUniform;
     const struct vkd3d_shader_register *reg = &cb->src.reg;
     struct vkd3d_push_constant_buffer_binding *push_cb;
+    const struct vkd3d_symbol *array_symbol;
     struct vkd3d_symbol reg_symbol;
 
     assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC));
@@ -5337,18 +5453,13 @@ 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);
-
-    vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler,
-            var_id, reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, false);
-
-    vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
+    var_id = vkd3d_dxbc_compiler_build_descriptor_variable(compiler, storage_class, struct_id,
+            reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, &array_symbol);
 
     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.descriptor_array = array_symbol;
     vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
 }
 
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index f5d22c5c..b247acc0 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -74,6 +74,7 @@ enum vkd3d_shader_error
     VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND = 2000,
     VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE        = 2001,
     VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING   = 2002,
+    VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED   = 2003,
 
     VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY                 = 3000,
     VKD3D_SHADER_ERROR_RS_INVALID_VERSION               = 3001,
-- 
2.32.0




More information about the wine-devel mailing list