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); }
A descriptor declaration matching a range of size 1 at the end of an array binding will be emitted as a scalar variable at offset 0 in the array, which is incorrect.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d-shader/spirv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index dbe741ab..bd551f66 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5562,7 +5562,7 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range, resource_type, false, &array_symbol->binding_base_idx);
- if (binding.count == 1 && range->last != ~0u) + if (binding.count == 1 && range->first == array_symbol->binding_base_idx && 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,
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- include/vkd3d_shader.h | 36 ++++++++++++++++---- libs/vkd3d-shader/spirv.c | 70 ++++++++++++++++++++++++++++++++------ libs/vkd3d/state.c | 14 ++++++-- libs/vkd3d/vkd3d_private.h | 2 +- 4 files changed, 101 insertions(+), 21 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 4a51b3f4..791ac037 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -458,6 +458,12 @@ struct vkd3d_shader_transform_feedback_info unsigned int buffer_stride_count; };
+struct vkd3d_shader_descriptor_offset +{ + unsigned int static_offset; + unsigned int dynamic_offset_index; +}; + /** * A chained structure containing descriptor offsets. * @@ -477,10 +483,28 @@ struct vkd3d_shader_descriptor_offset_info const void *next;
/** - * Pointer to an array of offsets into the descriptor arrays referenced by - * the 'bindings' array in struct vkd3d_shader_interface_info. This allows - * mapping multiple shader resource arrays to a single binding point in - * the target environment. + * Byte offset within the push constants of an array of 32-bit + * descriptor array offsets. See the description of 'binding_offsets' + * below. + */ + unsigned int descriptor_table_offset; + /** Size, in elements, of the descriptor table push constant array. */ + unsigned int descriptor_table_count; + + /** + * Pointer to an array of struct vkd3d_shader_descriptor_offset objects. + * The 'static_offset' field contains an offset into the descriptor arrays + * referenced by the 'bindings' array in struct vkd3d_shader_interface_info. + * This allows mapping multiple shader resource arrays to a single binding + * point in the target environment. + * + * 'dynamic_offset_index' in struct vkd3d_shader_descriptor_offset allows + * offsets to be set at runtime. The 32-bit descriptor table push constant + * at this index will be added to 'static_offset' to calculate the final + * binding offset. + * + * If runtime offsets are not required, set all 'dynamic_offset_index' + * values to \c ~0u and 'descriptor_table_count' to zero. * * For example, to map Direct3D constant buffer registers 'cb0[0:3]' and * 'cb1[6:7]' to descriptors 8-12 and 4-5 in the Vulkan descriptor array in @@ -508,7 +532,7 @@ struct vkd3d_shader_descriptor_offset_info * This field may be NULL, in which case the corresponding offsets are * specified to be 0. */ - const unsigned int *binding_offsets; + const struct vkd3d_shader_descriptor_offset *binding_offsets;
/** * Pointer to an array of offsets into the descriptor arrays referenced by @@ -517,7 +541,7 @@ struct vkd3d_shader_descriptor_offset_info * not supported in this version of vkd3d-shader, and therefore this field * must either be NULL or specify 0 offsets. */ - const unsigned int *uav_counter_offsets; + const struct vkd3d_shader_descriptor_offset *uav_counter_offsets; };
/** The format of a shader to be compiled or scanned. */ diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index bd551f66..9d21cb46 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1958,6 +1958,7 @@ struct vkd3d_symbol_descriptor_array uint32_t ptr_type_id; unsigned int set; unsigned int binding; + unsigned int push_constant_index; };
struct vkd3d_symbol_register_data @@ -1996,6 +1997,12 @@ struct vkd3d_symbol_sampler_data struct vkd3d_shader_register_range range; };
+struct vkd3d_descriptor_binding_address +{ + unsigned int binding_base_idx; + unsigned int push_constant_index; +}; + struct vkd3d_symbol_descriptor_array_data { SpvStorageClass storage_class; @@ -2242,7 +2249,9 @@ struct vkd3d_dxbc_compiler
struct vkd3d_shader_interface_info shader_interface; struct vkd3d_shader_descriptor_offset_info offset_info; + unsigned int descriptor_offsets_member_idx; struct vkd3d_push_constant_buffer_binding *push_constants; + unsigned int push_constants_var_id; const struct vkd3d_shader_spirv_target_info *spirv_target_info;
bool after_declarations_section; @@ -2561,11 +2570,11 @@ static struct vkd3d_string_buffer *vkd3d_shader_register_range_string(struct vkd 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, unsigned int *binding_base_idx) + bool is_uav_counter, struct vkd3d_descriptor_binding_address *binding_address) { const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface; unsigned int register_last = (range->last == ~0u) ? range->first : range->last; - const unsigned int *binding_offsets = compiler->offset_info.binding_offsets; + const struct vkd3d_shader_descriptor_offset *binding_offsets = compiler->offset_info.binding_offsets; enum vkd3d_shader_descriptor_type descriptor_type; enum vkd3d_shader_binding_flag resource_type_flag; struct vkd3d_shader_descriptor_binding binding; @@ -2619,7 +2628,8 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor range->first, range->space, current->binding.count); }
- *binding_base_idx = current->register_index; + binding_address->binding_base_idx = current->register_index; + binding_address->push_constant_index = ~0u; return current->binding; } if (shader_interface->uav_counter_count) @@ -2646,7 +2656,9 @@ 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 - (binding_offsets ? binding_offsets[i] : 0); + binding_address->binding_base_idx = current->register_index + - (binding_offsets ? binding_offsets[i].static_offset : 0); + binding_address->push_constant_index = binding_offsets ? binding_offsets[i].dynamic_offset_index : ~0u; return current->binding; } if (shader_interface->binding_count) @@ -2663,7 +2675,8 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor }
done: - *binding_base_idx = range->first; + binding_address->binding_base_idx = range->first; + binding_address->push_constant_index = ~0u; binding.set = 0; binding.count = 1; binding.binding = compiler->binding_idx++; @@ -2684,10 +2697,10 @@ 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. */ + struct vkd3d_descriptor_binding_address binding_address; /* Values not used. */
binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range, resource_type, is_uav_counter, - &binding_base_idx); + &binding_address); vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding); }
@@ -3255,10 +3268,11 @@ static uint32_t vkd3d_dxbc_compiler_get_descriptor_index(struct vkd3d_dxbc_compi const struct vkd3d_shader_register *reg, const struct vkd3d_descriptor_array_symbol *array_symbol, enum vkd3d_shader_resource_type resource_type) { + const struct vkd3d_symbol_descriptor_array *array_key = &array_symbol->symbol->key.descriptor_array; struct vkd3d_shader_register_index index = reg->idx[1]; uint32_t index_id;
- if (index.rel_addr) + if (index.rel_addr || array_key->push_constant_index != ~0u) { if (!vkd3d_dxbc_compiler_enable_descriptor_indexing(compiler, reg->type, resource_type)) { @@ -3272,6 +3286,21 @@ static uint32_t vkd3d_dxbc_compiler_get_descriptor_index(struct vkd3d_dxbc_compi index.offset -= array_symbol->binding_base_idx; index_id = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &index);
+ if (array_key->push_constant_index != ~0u && compiler->offset_info.descriptor_table_count) + { + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t type_id, ptr_type_id, ptr_id, offset_id, index_ids[2]; + + index_ids[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, compiler->descriptor_offsets_member_idx); + index_ids[1] = vkd3d_dxbc_compiler_get_constant_uint(compiler, array_key->push_constant_index); + type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPushConstant, type_id); + ptr_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, + compiler->push_constants_var_id, index_ids, 2); + offset_id = vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone); + index_id = vkd3d_spirv_build_op_iadd(builder, type_id, index_id, offset_id); + } + return index_id; }
@@ -5489,7 +5518,7 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com struct vkd3d_symbol reg_symbol; uint32_t *member_ids;
- count = 0; + count = !!compiler->offset_info.descriptor_table_count; for (i = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i) { const struct vkd3d_push_constant_buffer_binding *cb = &compiler->push_constants[i]; @@ -5518,6 +5547,16 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com ++j; }
+ if (compiler->offset_info.descriptor_table_count) + { + uint32_t type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); + length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, compiler->offset_info.descriptor_table_count); + member_ids[j] = vkd3d_spirv_build_op_type_array(builder, type_id, length_id); + vkd3d_spirv_build_op_decorate1(builder, member_ids[j], SpvDecorationArrayStride, 4); + compiler->descriptor_offsets_member_idx = j; + assert(j == count - 1); + } + struct_id = vkd3d_spirv_build_op_type_struct(builder, member_ids, count); vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0); vkd3d_spirv_build_op_name(builder, struct_id, "push_cb"); @@ -5526,6 +5565,7 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com 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); + compiler->push_constants_var_id = var_id;
for (i = 0, j = 0; i < compiler->shader_interface.push_constant_buffer_count; ++i) { @@ -5546,6 +5586,11 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com
++j; } + if (compiler->offset_info.descriptor_table_count) + { + vkd3d_spirv_build_op_member_decorate1(builder, struct_id, compiler->descriptor_offsets_member_idx, + SpvDecorationOffset, compiler->offset_info.descriptor_table_offset); + } }
static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_compiler *compiler, @@ -5554,15 +5599,17 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ struct vkd3d_descriptor_array_symbol *array_symbol) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + struct vkd3d_descriptor_binding_address binding_address; struct vkd3d_shader_descriptor_binding binding; uint32_t array_type_id, ptr_type_id, var_id; struct vkd3d_symbol symbol; struct rb_entry *entry;
binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range, - resource_type, false, &array_symbol->binding_base_idx); + resource_type, false, &binding_address); + array_symbol->binding_base_idx = binding_address.binding_base_idx;
- if (binding.count == 1 && range->first == array_symbol->binding_base_idx && range->last != ~0u) + if (binding.count == 1 && range->first == binding_address.binding_base_idx && 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, @@ -5586,6 +5633,7 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ symbol.key.descriptor_array.ptr_type_id = ptr_type_id; symbol.key.descriptor_array.set = binding.set; symbol.key.descriptor_array.binding = binding.binding; + symbol.key.descriptor_array.push_constant_index = binding_address.push_constant_index; if ((entry = rb_get(&compiler->symbol_table, &symbol))) { array_symbol->symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 413b0a30..fbfe7bb5 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -609,7 +609,8 @@ static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature * unsigned int descriptor_count, struct vkd3d_descriptor_set_context *context) { struct vkd3d_shader_resource_binding *mapping - = &root_signature->descriptor_mapping[context->descriptor_index++]; + = &root_signature->descriptor_mapping[context->descriptor_index]; + struct vkd3d_shader_descriptor_offset *offset = &root_signature->descriptor_offsets[context->descriptor_index++];
mapping->type = descriptor_type; mapping->register_space = register_space; @@ -619,6 +620,8 @@ static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature * mapping->binding.set = root_signature->vk_set_count; mapping->binding.binding = context->descriptor_binding++; mapping->binding.count = descriptor_count; + offset->static_offset = 0; + offset->dynamic_offset_index = ~0u;
if (context->unbounded_offset != UINT_MAX) d3d12_root_signature_append_descriptor_set_layout(root_signature, context, 0); @@ -718,7 +721,7 @@ static void d3d12_root_signature_map_vk_unbounded_binding(struct d3d12_root_sign 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]; - unsigned int *offset = &root_signature->descriptor_offsets[context->descriptor_index++]; + struct vkd3d_shader_descriptor_offset *offset = &root_signature->descriptor_offsets[context->descriptor_index++];
mapping->type = range->type; mapping->register_space = range->register_space; @@ -729,7 +732,8 @@ static void d3d12_root_signature_map_vk_unbounded_binding(struct d3d12_root_sign || range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) && !buffer_descriptor); mapping->binding.binding = range->binding; mapping->binding.count = range->vk_binding_count; - *offset = descriptor_offset; + offset->static_offset = descriptor_offset; + offset->dynamic_offset_index = ~0u; }
static void d3d12_root_signature_map_descriptor_unbounded_binding(struct d3d12_root_signature *root_signature, @@ -1930,6 +1934,8 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st { offset_info.type = VKD3D_SHADER_STRUCTURE_TYPE_DESCRIPTOR_OFFSET_INFO; offset_info.next = NULL; + offset_info.descriptor_table_offset = 0; + offset_info.descriptor_table_count = 0; offset_info.binding_offsets = root_signature->descriptor_offsets; offset_info.uav_counter_offsets = NULL; vkd3d_prepend_struct(&target_info, &offset_info); @@ -2696,6 +2702,8 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s { offset_info.type = VKD3D_SHADER_STRUCTURE_TYPE_DESCRIPTOR_OFFSET_INFO; offset_info.next = NULL; + offset_info.descriptor_table_offset = 0; + offset_info.descriptor_table_count = 0; offset_info.binding_offsets = root_signature->descriptor_offsets; offset_info.uav_counter_offsets = NULL; vkd3d_prepend_struct(&shader_interface, &offset_info); diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 23af9e32..e9631313 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -737,7 +737,7 @@ struct d3d12_root_signature
unsigned int binding_count; struct vkd3d_shader_resource_binding *descriptor_mapping; - unsigned int *descriptor_offsets; + struct vkd3d_shader_descriptor_offset *descriptor_offsets;
unsigned int root_constant_count; struct vkd3d_shader_push_constant_buffer *root_constants;
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- include/vkd3d_shader.h | 4 +- libs/vkd3d-shader/spirv.c | 83 ++++++++++++++++++--------------------- 2 files changed, 39 insertions(+), 48 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 791ac037..1eae0bbe 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -537,9 +537,7 @@ struct vkd3d_shader_descriptor_offset_info /** * Pointer to an array of offsets into the descriptor arrays referenced by * the 'uav_counters' array in struct vkd3d_shader_interface_info. This - * works the same way as \ref binding_offsets above. UAV counter arrays are - * not supported in this version of vkd3d-shader, and therefore this field - * must either be NULL or specify 0 offsets. + * works the same way as \ref binding_offsets above. */ const struct vkd3d_shader_descriptor_offset *uav_counter_offsets; }; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 9d21cb46..68eb16ec 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1990,6 +1990,7 @@ struct vkd3d_symbol_resource_data unsigned int structure_stride; bool raw; uint32_t uav_counter_id; + struct vkd3d_descriptor_array_symbol uav_counter_array; };
struct vkd3d_symbol_sampler_data @@ -2410,8 +2411,6 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader if ((offset_info = vkd3d_find_struct(shader_interface->next, DESCRIPTOR_OFFSET_INFO))) { compiler->offset_info = *offset_info; - if (offset_info->uav_counter_offsets) - WARN("Ignoring UAV counter offsets %p.\n", offset_info->uav_counter_offsets); } }
@@ -2602,6 +2601,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor if (is_uav_counter) { assert(descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV); + binding_offsets = compiler->offset_info.uav_counter_offsets; for (i = 0; i < shader_interface->uav_counter_count; ++i) { const struct vkd3d_shader_uav_counter_binding *current = &shader_interface->uav_counters[i]; @@ -2609,7 +2609,8 @@ 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 != range->space || current->register_index != range->first) + if (current->register_space != range->space || current->register_index > range->first + || current->binding.count <= register_last - current->register_index) continue;
if (current->offset) @@ -2620,16 +2621,9 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor range->first, range->space, current->offset); }
- 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 UAV counter %u, space %u has unsupported ‘count’ %u.", - range->first, range->space, current->binding.count); - } - - binding_address->binding_base_idx = current->register_index; - binding_address->push_constant_index = ~0u; + binding_address->binding_base_idx = current->register_index + - (binding_offsets ? binding_offsets[i].static_offset : 0); + binding_address->push_constant_index = binding_offsets ? binding_offsets[i].dynamic_offset_index : ~0u; return current->binding; } if (shader_interface->uav_counter_count) @@ -2692,18 +2686,6 @@ static void vkd3d_dxbc_compiler_emit_descriptor_binding(struct vkd3d_dxbc_compil vkd3d_spirv_build_op_decorate1(builder, variable_id, SpvDecorationBinding, binding->binding); }
-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, const struct vkd3d_shader_register_range *range, - enum vkd3d_shader_resource_type resource_type, bool is_uav_counter) -{ - struct vkd3d_shader_descriptor_binding binding; - struct vkd3d_descriptor_binding_address binding_address; /* Values not used. */ - - binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range, resource_type, is_uav_counter, - &binding_address); - vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding); -} - static void vkd3d_dxbc_compiler_decorate_nonuniform(struct vkd3d_dxbc_compiler *compiler, uint32_t expression_id) { @@ -2938,6 +2920,7 @@ static bool vkd3d_dxbc_compiler_get_register_name(char *buffer, unsigned int buf return true; }
+/* TODO: UAV counters: vkd3d_spirv_build_op_name(builder, counter_var_id, "u%u_counter", reg->idx[0].offset); */ static void vkd3d_dxbc_compiler_emit_register_debug_name(struct vkd3d_spirv_builder *builder, uint32_t id, const struct vkd3d_shader_register *reg) { @@ -5596,7 +5579,7 @@ 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, - struct vkd3d_descriptor_array_symbol *array_symbol) + bool is_uav_counter, struct vkd3d_descriptor_array_symbol *array_symbol) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_descriptor_binding_address binding_address; @@ -5606,7 +5589,7 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ struct rb_entry *entry;
binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, range, - resource_type, false, &binding_address); + resource_type, is_uav_counter, &binding_address); array_symbol->binding_base_idx = binding_address.binding_base_idx;
if (binding.count == 1 && range->first == binding_address.binding_base_idx && range->last != ~0u) @@ -5696,7 +5679,7 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", cb->size);
var_id = vkd3d_dxbc_compiler_build_descriptor_variable(compiler, storage_class, struct_id, - reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, &array_symbol); + reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, false, &array_symbol);
vkd3d_symbol_make_register(®_symbol, reg); vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, @@ -5758,7 +5741,7 @@ static void vkd3d_dxbc_compiler_emit_dcl_sampler(struct vkd3d_dxbc_compiler *com
type_id = vkd3d_spirv_get_op_type_sampler(builder); var_id = vkd3d_dxbc_compiler_build_descriptor_variable(compiler, storage_class, type_id, reg, - &sampler->range, VKD3D_SHADER_RESOURCE_NONE, &array_symbol); + &sampler->range, VKD3D_SHADER_RESOURCE_NONE, false, &array_symbol);
vkd3d_symbol_make_register(®_symbol, reg); vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, @@ -5929,6 +5912,8 @@ static void vkd3d_dxbc_compiler_emit_combined_sampler_declarations(struct vkd3d_ symbol.info.resource.structure_stride = structure_stride; symbol.info.resource.raw = raw; symbol.info.resource.uav_counter_id = 0; + symbol.info.resource.uav_counter_array.symbol = NULL; + symbol.info.resource.uav_counter_array.binding_base_idx = 0; vkd3d_dxbc_compiler_put_symbol(compiler, &symbol); } } @@ -5937,12 +5922,12 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp const struct vkd3d_shader_resource *resource, enum vkd3d_shader_resource_type resource_type, enum vkd3d_data_type resource_data_type, unsigned int structure_stride, bool raw) { - uint32_t counter_type_id, type_id, ptr_type_id, var_id, counter_var_id = 0; + struct vkd3d_descriptor_array_symbol array_symbol, counter_array_symbol = {NULL, 0}; + uint32_t counter_type_id, type_id, var_id, counter_var_id = 0; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; 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; struct vkd3d_symbol resource_symbol; bool is_uav; @@ -5987,7 +5972,7 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp }
var_id = vkd3d_dxbc_compiler_build_descriptor_variable(compiler, storage_class, type_id, reg, - &resource->range, resource_type, &array_symbol); + &resource->range, resource_type, false, &array_symbol);
if (is_uav) { @@ -6008,7 +5993,7 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp { vkd3d_spirv_enable_capability(builder, SpvCapabilityAtomicStorage); storage_class = SpvStorageClassAtomicCounter; - ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, counter_type_id); + type_id = counter_type_id; } else if (compiler->ssbo_uavs) { @@ -6023,20 +6008,11 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0);
storage_class = SpvStorageClassUniform; - ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id); - } - else - { - ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id); + type_id = struct_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, &resource->range, resource_type, true); - - vkd3d_spirv_build_op_name(builder, counter_var_id, "u%u_counter", reg->idx[0].offset); + counter_var_id = vkd3d_dxbc_compiler_build_descriptor_variable(compiler, storage_class, type_id, reg, + &resource->range, resource_type, true, &counter_array_symbol); } }
@@ -6050,6 +6026,7 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp resource_symbol.info.resource.structure_stride = structure_stride; resource_symbol.info.resource.raw = raw; resource_symbol.info.resource.uav_counter_id = counter_var_id; + resource_symbol.info.resource.uav_counter_array = counter_array_symbol; vkd3d_dxbc_compiler_put_symbol(compiler, &resource_symbol); }
@@ -8868,6 +8845,22 @@ static void vkd3d_dxbc_compiler_emit_uav_counter_instruction(struct vkd3d_dxbc_c } else { + if (resource_symbol->info.resource.uav_counter_array.symbol) + { + const struct vkd3d_symbol_descriptor_array_data *array_data; + uint32_t index_id; + + index_id = vkd3d_dxbc_compiler_get_descriptor_index(compiler, &src->reg, + &resource_symbol->info.resource.uav_counter_array, + resource_symbol->info.resource.resource_type_info->resource_type); + + array_data = &resource_symbol->info.resource.uav_counter_array.symbol->info.descriptor_array; + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, array_data->storage_class, + array_data->contained_type_id); + + counter_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, counter_id, &index_id, 1); + } + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassImage, type_id); coordinate_id = sample_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, 0); pointer_id = vkd3d_spirv_build_op_image_texel_pointer(builder,