Runtime descriptor arrays should be used for descriptor bindings with a variable count.
Support for SpvCapabilityRuntimeDescriptorArrayEXT is required by the Vulkan spec as part of descriptor indexing support.
The current implementation depends on a separate array declaration for each range because binding_base_idx is stored in the array data. This occurs in practice because binding.count is always different. Use of runtime arrays eliminates the count from the key, so binding_base_idx must be separated from the array data.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d-shader/spirv.c | 70 ++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 31 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 698c3054..dbe741ab 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1972,6 +1972,14 @@ struct vkd3d_symbol_register_data bool is_dynamically_indexed; /* If member_idx is a variable ID instead of a constant. */ };
+struct vkd3d_symbol; + +struct vkd3d_descriptor_array_symbol +{ + const struct vkd3d_symbol *symbol; + unsigned int binding_base_idx; +}; + struct vkd3d_symbol_resource_data { struct vkd3d_shader_register_range range; @@ -1992,7 +2000,6 @@ struct vkd3d_symbol_descriptor_array_data { SpvStorageClass storage_class; uint32_t contained_type_id; - unsigned int binding_base_idx; };
struct vkd3d_symbol @@ -2018,8 +2025,8 @@ struct vkd3d_symbol } key;
uint32_t id; - /* The array declaration which this symbol maps to, or NULL. */ - const struct vkd3d_symbol *descriptor_array; + /* descriptor_array.symbol is the array declaration which this symbol maps to, or NULL. */ + struct vkd3d_descriptor_array_symbol descriptor_array;
union { @@ -2064,7 +2071,8 @@ 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->descriptor_array.symbol = NULL; + symbol->descriptor_array.binding_base_idx = 0; symbol->info.reg.storage_class = storage_class; symbol->info.reg.member_idx = 0; symbol->info.reg.component_type = component_type; @@ -3135,7 +3143,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; + struct vkd3d_descriptor_array_symbol descriptor_array; SpvStorageClass storage_class; enum vkd3d_shader_component_type component_type; unsigned int write_mask; @@ -3158,7 +3166,8 @@ 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->descriptor_array.symbol = NULL; + register_info->descriptor_array.binding_base_idx = 0; register_info->member_idx = 0; register_info->component_type = VKD3D_SHADER_COMPONENT_FLOAT; register_info->write_mask = VKD3DSP_WRITEMASK_ALL; @@ -3243,7 +3252,7 @@ static bool vkd3d_dxbc_compiler_enable_descriptor_indexing(struct vkd3d_dxbc_com }
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, + const struct vkd3d_shader_register *reg, const struct vkd3d_descriptor_array_symbol *array_symbol, enum vkd3d_shader_resource_type resource_type) { struct vkd3d_shader_register_index index = reg->idx[1]; @@ -3260,7 +3269,7 @@ static uint32_t vkd3d_dxbc_compiler_get_descriptor_index(struct vkd3d_dxbc_compi } }
- index.offset -= binding_base_idx; + index.offset -= array_symbol->binding_base_idx; index_id = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &index);
return index_id; @@ -3277,10 +3286,9 @@ static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_comp if (reg->type == VKD3DSPR_CONSTBUFFER) { assert(!reg->idx[0].rel_addr); - if (register_info->descriptor_array) + if (register_info->descriptor_array.symbol) indexes[index_count++] = vkd3d_dxbc_compiler_get_descriptor_index(compiler, reg, - register_info->descriptor_array->info.descriptor_array.binding_base_idx, - VKD3D_SHADER_RESOURCE_BUFFER); + ®ister_info->descriptor_array, VKD3D_SHADER_RESOURCE_BUFFER); indexes[index_count++] = vkd3d_dxbc_compiler_get_constant_uint(compiler, register_info->member_idx); indexes[index_count++] = vkd3d_dxbc_compiler_emit_register_addressing(compiler, ®->idx[2]); } @@ -5543,17 +5551,16 @@ 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_descriptor_array_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); + resource_type, false, &array_symbol->binding_base_idx);
if (binding.count == 1 && range->last != ~0u) { @@ -5564,12 +5571,12 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, &binding); vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
- *array_symbol = NULL; + array_symbol->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)); + array_type_id = vkd3d_spirv_get_op_type_runtime_array(builder, type_id); + vkd3d_spirv_enable_capability(builder, SpvCapabilityRuntimeDescriptorArrayEXT); 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 @@ -5581,8 +5588,8 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ 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; + array_symbol->symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); + return array_symbol->symbol->id; }
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, @@ -5591,11 +5598,11 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
symbol.id = var_id; - symbol.descriptor_array = NULL; + symbol.descriptor_array.symbol = NULL; + symbol.descriptor_array.binding_base_idx = 0; 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); + array_symbol->symbol = vkd3d_dxbc_compiler_put_symbol(compiler, &symbol);
return var_id; } @@ -5609,7 +5616,7 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi 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_descriptor_array_symbol array_symbol; struct vkd3d_symbol reg_symbol;
assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC)); @@ -5690,7 +5697,7 @@ 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; - const struct vkd3d_symbol *array_symbol; + struct vkd3d_descriptor_array_symbol array_symbol; struct vkd3d_symbol reg_symbol; uint32_t type_id, var_id;
@@ -5887,8 +5894,8 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp SpvStorageClass storage_class = SpvStorageClassUniformConstant; const struct vkd3d_shader_register *reg = &resource->reg.reg; const struct vkd3d_spirv_resource_type *resource_type_info; + struct vkd3d_descriptor_array_symbol array_symbol; enum vkd3d_shader_component_type sampled_type; - const struct vkd3d_symbol *array_symbol; struct vkd3d_symbol resource_symbol; bool is_uav;
@@ -8022,13 +8029,14 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil if (!symbol) symbol = vkd3d_dxbc_compiler_find_resource(compiler, resource_reg);
- if (symbol->descriptor_array) + if (symbol->descriptor_array.symbol) { - const struct vkd3d_symbol_descriptor_array_data *array_data = &symbol->descriptor_array->info.descriptor_array; + const struct vkd3d_symbol_descriptor_array_data *array_data + = &symbol->descriptor_array.symbol->info.descriptor_array; uint32_t ptr_type_id, index_id;
index_id = vkd3d_dxbc_compiler_get_descriptor_index(compiler, resource_reg, - array_data->binding_base_idx, symbol->info.resource.resource_type_info->resource_type); + &symbol->descriptor_array, symbol->info.resource.resource_type_info->resource_type);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, array_data->storage_class, array_data->contained_type_id); @@ -8081,14 +8089,14 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil if (!vkd3d_dxbc_compiler_get_register_info(compiler, sampler_reg, ®ister_info)) ERR("Failed to get sampler register info.\n"); sampler_var_id = register_info.id; - if (register_info.descriptor_array) + if (register_info.descriptor_array.symbol) { const struct vkd3d_symbol_descriptor_array_data *array_data - = ®ister_info.descriptor_array->info.descriptor_array; + = ®ister_info.descriptor_array.symbol->info.descriptor_array; uint32_t ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, register_info.storage_class, array_data->contained_type_id); uint32_t array_idx = vkd3d_dxbc_compiler_get_descriptor_index(compiler, - sampler_reg, array_data->binding_base_idx, VKD3D_SHADER_RESOURCE_NONE); + sampler_reg, ®ister_info.descriptor_array, VKD3D_SHADER_RESOURCE_NONE); sampler_var_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, register_info.id, &array_idx, 1); }