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 --- v2: Store binding_base_idx in vkd3d_symbol_register_data and vkd3d_symbol_resource_data. --- libs/vkd3d-shader/spirv.c | 59 +++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index b7e7428a..522225d9 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1968,6 +1968,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. */ }; @@ -1980,6 +1981,7 @@ struct vkd3d_symbol_resource_data const struct vkd3d_spirv_resource_type *resource_type_info; unsigned int structure_stride; bool raw; + unsigned int binding_base_idx; uint32_t uav_counter_id; };
@@ -1992,7 +1994,6 @@ struct vkd3d_symbol_descriptor_array_data { SpvStorageClass storage_class; uint32_t contained_type_id; - unsigned int binding_base_idx; };
struct vkd3d_symbol @@ -2071,6 +2072,7 @@ static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol, symbol->info.reg.write_mask = write_mask; symbol->info.reg.dcl_mask = 0; symbol->info.reg.structure_stride = 0; + symbol->info.reg.binding_base_idx = 0; symbol->info.reg.is_aggregate = false; symbol->info.reg.is_dynamically_indexed = false; } @@ -3141,6 +3143,7 @@ struct vkd3d_shader_register_info unsigned int write_mask; uint32_t member_idx; unsigned int structure_stride; + unsigned int binding_base_idx; bool is_aggregate; bool is_dynamically_indexed; }; @@ -3163,6 +3166,7 @@ static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compil register_info->component_type = VKD3D_SHADER_COMPONENT_FLOAT; register_info->write_mask = VKD3DSP_WRITEMASK_ALL; register_info->structure_stride = 0; + register_info->binding_base_idx = 0; register_info->is_aggregate = false; register_info->is_dynamically_indexed = false; return true; @@ -3184,6 +3188,7 @@ static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compil register_info->component_type = symbol->info.reg.component_type; register_info->write_mask = symbol->info.reg.write_mask; register_info->structure_stride = symbol->info.reg.structure_stride; + register_info->binding_base_idx = symbol->info.reg.binding_base_idx; register_info->is_aggregate = symbol->info.reg.is_aggregate; register_info->is_dynamically_indexed = symbol->info.reg.is_dynamically_indexed;
@@ -3279,8 +3284,7 @@ static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_comp 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, - VKD3D_SHADER_RESOURCE_BUFFER); + register_info->binding_base_idx, 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]); } @@ -5557,20 +5561,25 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com } }
+struct vkd3d_descriptor_variable_info +{ + const struct vkd3d_symbol *array_symbol; + unsigned int binding_base_idx; +}; + 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_variable_info *var_info) { 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, &var_info->binding_base_idx);
if (binding.count == 1 && range->last != ~0u) { @@ -5581,12 +5590,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; + var_info->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)); + vkd3d_spirv_enable_capability(builder, SpvCapabilityRuntimeDescriptorArrayEXT); + array_type_id = vkd3d_spirv_get_op_type_runtime_array(builder, type_id); 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 @@ -5598,8 +5607,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; + var_info->array_symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); + return var_info->array_symbol->id; }
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, @@ -5611,8 +5620,7 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ 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); + var_info->array_symbol = vkd3d_dxbc_compiler_put_symbol(compiler, &symbol);
return var_id; } @@ -5626,7 +5634,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_variable_info var_info; struct vkd3d_symbol reg_symbol;
assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC)); @@ -5658,12 +5666,13 @@ 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, &var_info);
vkd3d_symbol_make_register(®_symbol, reg); vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL); - reg_symbol.descriptor_array = array_symbol; + reg_symbol.descriptor_array = var_info.array_symbol; + reg_symbol.info.reg.binding_base_idx = var_info.binding_base_idx; vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol); }
@@ -5707,7 +5716,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_variable_info var_info; struct vkd3d_symbol reg_symbol; uint32_t type_id, var_id;
@@ -5720,12 +5729,13 @@ 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, &var_info);
vkd3d_symbol_make_register(®_symbol, reg); vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL); - reg_symbol.descriptor_array = array_symbol; + reg_symbol.descriptor_array = var_info.array_symbol; + reg_symbol.info.reg.binding_base_idx = var_info.binding_base_idx; vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol); }
@@ -5904,8 +5914,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_variable_info var_info; enum vkd3d_shader_component_type sampled_type; - const struct vkd3d_symbol *array_symbol; struct vkd3d_symbol resource_symbol; bool is_uav;
@@ -5949,7 +5959,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, &var_info);
if (is_uav) { @@ -6004,13 +6014,14 @@ 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.descriptor_array = array_symbol; + resource_symbol.descriptor_array = var_info.array_symbol; resource_symbol.info.resource.range = resource->range; resource_symbol.info.resource.sampled_type = sampled_type; resource_symbol.info.resource.type_id = type_id; resource_symbol.info.resource.resource_type_info = resource_type_info; resource_symbol.info.resource.structure_stride = structure_stride; resource_symbol.info.resource.raw = raw; + resource_symbol.info.resource.binding_base_idx = var_info.binding_base_idx; resource_symbol.info.resource.uav_counter_id = counter_var_id; vkd3d_dxbc_compiler_put_symbol(compiler, &resource_symbol); } @@ -8045,7 +8056,7 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil 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->info.resource.binding_base_idx, 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); @@ -8105,7 +8116,7 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil 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, register_info.binding_base_idx, VKD3D_SHADER_RESOURCE_NONE); sampler_var_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, register_info.id, &array_idx, 1); }
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 413b0a30..cb3f99ad 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -1170,8 +1170,8 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa if (!(root_signature->descriptor_mapping = vkd3d_calloc(root_signature->binding_count, sizeof(*root_signature->descriptor_mapping)))) goto fail; - if (!(root_signature->descriptor_offsets = vkd3d_calloc(root_signature->binding_count, - sizeof(*root_signature->descriptor_offsets)))) + if (root_signature->use_descriptor_arrays && !(root_signature->descriptor_offsets = vkd3d_calloc( + root_signature->binding_count, sizeof(*root_signature->descriptor_offsets)))) goto fail; root_signature->root_constant_count = info.root_constant_count; if (!(root_signature->root_constants = vkd3d_calloc(root_signature->root_constant_count,
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- include/vkd3d_shader.h | 110 +++++++++++++++++--------------------- libs/vkd3d-shader/spirv.c | 21 ++++---- libs/vkd3d/state.c | 68 ++++++++++++++--------- 3 files changed, 101 insertions(+), 98 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 4a51b3f4..deffef19 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -249,6 +249,8 @@ enum vkd3d_shader_parameter_name { VKD3D_SHADER_PARAMETER_NAME_UNKNOWN, VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, + VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_OFFSETS, + VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_OFFSETS,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME), }; @@ -266,6 +268,52 @@ struct vkd3d_shader_parameter_specialization_constant uint32_t id; };
+struct vkd3d_shader_parameter_descriptor_offsets +{ + /** + * 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. + * + * 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 + * descriptor set 3 and with binding 2, set the following values in the + * 'bindings' array in struct vkd3d_shader_interface_info: + * + * \code + * type = VKD3D_SHADER_DESCRIPTOR_TYPE_CBV + * register_space = 0 + * register_index = 0 + * binding.set = 3 + * binding.binding = 2 + * binding.count = 4 + * + * type = VKD3D_SHADER_DESCRIPTOR_TYPE_CBV + * register_space = 0 + * register_index = 6 + * binding.set = 3 + * binding.binding = 2 + * binding.count = 2 + * \endcode + * + * and then pass \c {8, \c 4} as \a binding_offsets here. + * + * This field may be NULL, or the structure may be omitted from the + * parameter list, in which case the corresponding offsets are specified + * to be 0. + * + * If the parameter is specified under name + * VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_OFFSETS, 'offsets' points 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 described above. UAV counter arrays are not supported in + * this version of vkd3d-shader, and therefore this field must be NULL, or + * the parameter omitted. + */ + const unsigned int *offsets; +}; + struct vkd3d_shader_parameter { enum vkd3d_shader_parameter_name name; @@ -275,6 +322,7 @@ struct vkd3d_shader_parameter { struct vkd3d_shader_parameter_immediate_constant immediate_constant; struct vkd3d_shader_parameter_specialization_constant specialization_constant; + struct vkd3d_shader_parameter_descriptor_offsets descriptor_offsets; } u; };
@@ -458,68 +506,6 @@ struct vkd3d_shader_transform_feedback_info unsigned int buffer_stride_count; };
-/** - * A chained structure containing descriptor offsets. - * - * This structure is optional. - * - * This structure extends vkd3d_shader_interface_info. - * - * This structure contains only input parameters. - * - * \since 1.3 - */ -struct vkd3d_shader_descriptor_offset_info -{ - /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_DESCRIPTOR_OFFSET_INFO. */ - enum vkd3d_shader_structure_type type; - /** Optional pointer to a structure containing further parameters. */ - 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. - * - * 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 - * descriptor set 3 and with binding 2, set the following values in the - * 'bindings' array in struct vkd3d_shader_interface_info: - * - * \code - * type = VKD3D_SHADER_DESCRIPTOR_TYPE_CBV - * register_space = 0 - * register_index = 0 - * binding.set = 3 - * binding.binding = 2 - * binding.count = 4 - * - * type = VKD3D_SHADER_DESCRIPTOR_TYPE_CBV - * register_space = 0 - * register_index = 6 - * binding.set = 3 - * binding.binding = 2 - * binding.count = 2 - * \endcode - * - * and then pass \c {8, \c 4} as \a binding_offsets here. - * - * This field may be NULL, in which case the corresponding offsets are - * specified to be 0. - */ - const unsigned int *binding_offsets; - - /** - * 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. - */ - const unsigned int *uav_counter_offsets; -}; - /** The format of a shader to be compiled or scanned. */ enum vkd3d_shader_source_type { diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 522225d9..9f71c6e0 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2235,7 +2235,7 @@ struct vkd3d_dxbc_compiler size_t control_flow_info_size;
struct vkd3d_shader_interface_info shader_interface; - struct vkd3d_shader_descriptor_offset_info offset_info; + const unsigned int *binding_offsets; struct vkd3d_push_constant_buffer_binding *push_constants; const struct vkd3d_shader_spirv_target_info *spirv_target_info;
@@ -2289,6 +2289,9 @@ static const char *vkd3d_dxbc_compiler_get_entry_point_name(const struct vkd3d_d return info && info->entry_point ? info->entry_point : "main"; }
+static const struct vkd3d_shader_parameter *vkd3d_dxbc_compiler_get_shader_parameter( + struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_parameter_name name); + struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_desc *shader_desc, const struct vkd3d_shader_compile_info *compile_info, const struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info, @@ -2297,8 +2300,8 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader const struct vkd3d_shader_signature *patch_constant_signature = &shader_desc->patch_constant_signature; const struct vkd3d_shader_signature *output_signature = &shader_desc->output_signature; const struct vkd3d_shader_interface_info *shader_interface; - const struct vkd3d_shader_descriptor_offset_info *offset_info; const struct vkd3d_shader_spirv_target_info *target_info; + const struct vkd3d_shader_parameter *parameter; struct vkd3d_dxbc_compiler *compiler; unsigned int max_element_count; unsigned int i; @@ -2391,15 +2394,13 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader for (i = 0; i < shader_interface->push_constant_buffer_count; ++i) compiler->push_constants[i].pc = shader_interface->push_constant_buffers[i]; } - - 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); - } }
+ if ((parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_OFFSETS))) + compiler->binding_offsets = parameter->u.descriptor_offsets.offsets; + if ((parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_OFFSETS))) + WARN("Ignoring UAV counter offsets %p.\n", parameter->u.descriptor_offsets.offsets); + compiler->scan_descriptor_info = scan_descriptor_info;
vkd3d_string_buffer_cache_init(&compiler->string_buffers); @@ -2559,7 +2560,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor { 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 unsigned int *binding_offsets = compiler->binding_offsets; enum vkd3d_shader_descriptor_type descriptor_type; enum vkd3d_shader_binding_flag resource_type_flag; struct vkd3d_shader_descriptor_binding binding; diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index cb3f99ad..8f788dba 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -1880,13 +1880,29 @@ static HRESULT d3d12_pipeline_state_init_uav_counters(struct d3d12_pipeline_stat return S_OK; }
+static void spirv_target_info_append_descriptor_offsets(struct vkd3d_shader_spirv_target_info *target_info, + const struct d3d12_root_signature *root_signature) +{ + struct vkd3d_shader_parameter *parameter; + + if (!root_signature->descriptor_offsets) + return; + + parameter = (struct vkd3d_shader_parameter *)&target_info->parameters[target_info->parameter_count]; + parameter->name = VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_OFFSETS; + parameter->type = VKD3D_SHADER_PARAMETER_TYPE_UNKNOWN; + parameter->data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UNKNOWN; + parameter->u.descriptor_offsets.offsets = root_signature->descriptor_offsets; + ++target_info->parameter_count; +} + static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *state, struct d3d12_device *device, const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct vkd3d_shader_scan_descriptor_info shader_info; struct vkd3d_shader_interface_info shader_interface; - struct vkd3d_shader_descriptor_offset_info offset_info; + struct vkd3d_shader_parameter shader_parameters[1]; const struct d3d12_root_signature *root_signature; struct vkd3d_shader_spirv_target_info target_info; VkPipelineLayout vk_pipeline_layout; @@ -1925,15 +1941,11 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st target_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0; target_info.extensions = device->vk_info.shader_extensions; target_info.extension_count = device->vk_info.shader_extension_count; + target_info.parameters = shader_parameters; + target_info.parameter_count = 0;
- if (root_signature->descriptor_offsets) - { - offset_info.type = VKD3D_SHADER_STRUCTURE_TYPE_DESCRIPTOR_OFFSET_INFO; - offset_info.next = NULL; - offset_info.binding_offsets = root_signature->descriptor_offsets; - offset_info.uav_counter_offsets = NULL; - vkd3d_prepend_struct(&target_info, &offset_info); - } + spirv_target_info_append_descriptor_offsets(&target_info, root_signature); + assert(target_info.parameter_count <= ARRAY_SIZE(shader_parameters));
shader_interface.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO; shader_interface.next = &target_info; @@ -2437,13 +2449,14 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s VkVertexInputBindingDivisorDescriptionEXT *binding_divisor; const struct vkd3d_vulkan_info *vk_info = &device->vk_info; uint32_t instance_divisors[D3D12_VS_INPUT_REGISTER_COUNT]; + struct vkd3d_shader_spirv_target_info *stage_target_info; uint32_t aligned_offsets[D3D12_VS_INPUT_REGISTER_COUNT]; - struct vkd3d_shader_parameter ps_shader_parameters[1]; + struct vkd3d_shader_parameter ps_shader_parameters[2]; struct vkd3d_shader_transform_feedback_info xfb_info; struct vkd3d_shader_spirv_target_info ps_target_info; struct vkd3d_shader_interface_info shader_interface; - struct vkd3d_shader_descriptor_offset_info offset_info; - struct vkd3d_shader_spirv_target_info *target_info; + struct vkd3d_shader_parameter shader_parameters[1]; + struct vkd3d_shader_spirv_target_info target_info; const struct d3d12_root_signature *root_signature; struct vkd3d_shader_signature input_signature; bool have_attachment, is_dsv_format_unknown; @@ -2624,11 +2637,24 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s ps_target_info.extensions = vk_info->shader_extensions; ps_target_info.extension_count = vk_info->shader_extension_count; ps_target_info.parameters = ps_shader_parameters; - ps_target_info.parameter_count = ARRAY_SIZE(ps_shader_parameters); + ps_target_info.parameter_count = 1; ps_target_info.dual_source_blending = is_dual_source_blending(&desc->BlendState.RenderTarget[0]); ps_target_info.output_swizzles = ps_output_swizzle; ps_target_info.output_swizzle_count = rt_count;
+ memset(&target_info, 0, sizeof(target_info)); + target_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SPIRV_TARGET_INFO; + target_info.environment = VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0; + target_info.extensions = vk_info->shader_extensions; + target_info.extension_count = vk_info->shader_extension_count; + target_info.parameters = shader_parameters; + target_info.parameter_count = 0; + + spirv_target_info_append_descriptor_offsets(&target_info, root_signature); + assert(target_info.parameter_count <= ARRAY_SIZE(shader_parameters)); + spirv_target_info_append_descriptor_offsets(&ps_target_info, root_signature); + assert(ps_target_info.parameter_count <= ARRAY_SIZE(ps_shader_parameters)); + if (ps_target_info.dual_source_blending && rt_count > 1) { WARN("Only one render target is allowed when dual source blending is used.\n"); @@ -2692,15 +2718,6 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s shader_interface.combined_samplers = NULL; shader_interface.combined_sampler_count = 0;
- if (root_signature->descriptor_offsets) - { - offset_info.type = VKD3D_SHADER_STRUCTURE_TYPE_DESCRIPTOR_OFFSET_INFO; - offset_info.next = NULL; - offset_info.binding_offsets = root_signature->descriptor_offsets; - offset_info.uav_counter_offsets = NULL; - vkd3d_prepend_struct(&shader_interface, &offset_info); - } - for (i = 0; i < ARRAY_SIZE(shader_stages); ++i) { struct vkd3d_shader_scan_descriptor_info shader_info = @@ -2730,7 +2747,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
shader_interface.uav_counters = NULL; shader_interface.uav_counter_count = 0; - target_info = NULL; + stage_target_info = &target_info; switch (shader_stages[i].stage) { case VK_SHADER_STAGE_VERTEX_BIT: @@ -2757,7 +2774,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s case VK_SHADER_STAGE_FRAGMENT_BIT: shader_interface.uav_counters = state->uav_counters.bindings; shader_interface.uav_counter_count = state->uav_counters.binding_count; - target_info = &ps_target_info; + stage_target_info = &ps_target_info; break;
default: @@ -2768,8 +2785,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s shader_interface.next = NULL; if (shader_stages[i].stage == xfb_stage) vkd3d_prepend_struct(&shader_interface, &xfb_info); - if (target_info) - vkd3d_prepend_struct(&shader_interface, target_info); + vkd3d_prepend_struct(&shader_interface, stage_target_info);
if (FAILED(hr = create_shader_stage(device, &graphics->stages[graphics->stage_count], shader_stages[i].stage, b, &shader_interface)))
On Tue, 23 Nov 2021 at 15:42, Conor McCarthy cmccarthy@codeweavers.com wrote:
@@ -249,6 +249,8 @@ enum vkd3d_shader_parameter_name { VKD3D_SHADER_PARAMETER_NAME_UNKNOWN, VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT,
VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_OFFSETS,
VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_OFFSETS,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME),
};
"VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_DESCRIPTOR_OFFSETS", right?
+struct vkd3d_shader_parameter_descriptor_offsets +{
[...]
- const unsigned int *offsets;
+};
struct vkd3d_shader_parameter { enum vkd3d_shader_parameter_name name; @@ -275,6 +322,7 @@ struct vkd3d_shader_parameter { struct vkd3d_shader_parameter_immediate_constant immediate_constant; struct vkd3d_shader_parameter_specialization_constant specialization_constant;
} u;struct vkd3d_shader_parameter_descriptor_offsets descriptor_offsets;
};
That's not quite how shader parameters are supposed to work. Which of these is valid depends on the "type" field, not on the "name" field. The idea is that shaders could be parametrised using compile-time immediate constants, specialisation constants, or a mix of the two. We could in principle add push constants as a third option.
In the case of descriptor offsets, what's missing is support for specifying arrays. That may simply be a matter of adding something like "const uint32_t *u32_array;" to the union in the vkd3d_shader_parameter_immediate_constant structure. The specialisation constant path should work fine as-is in terms of API, but probably needs some work in terms of SPIR-V generation.
November 25, 2021 4:36 AM, "Henri Verbeet" hverbeet@gmail.com wrote:
In the case of descriptor offsets, what's missing is support for specifying arrays. That may simply be a matter of adding something like "const uint32_t *u32_array;" to the union in the vkd3d_shader_parameter_immediate_constant structure. The specialisation constant path should work fine as-is in terms of API, but probably needs some work in terms of SPIR-V generation.
Should this use a new helper for getting an immediate constant from an array, something like:
vkd3d_dxbc_compiler_get_uint_shader_array_parameter(struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_parameter_name name, unsigned int index)
Plus a data type check in vkd3d_dxbc_compiler_emit_uint_shader_parameter().
I don't see a need to support specialisation constant arrays. We can just emit a compiler error if the UINT32_ARRAY data type is specified for a specialisation constant.
On Thu, 25 Nov 2021 at 04:32, Conor McCarthy cmccarthy@codeweavers.com wrote:
November 25, 2021 4:36 AM, "Henri Verbeet" hverbeet@gmail.com wrote:
In the case of descriptor offsets, what's missing is support for specifying arrays. That may simply be a matter of adding something like "const uint32_t *u32_array;" to the union in the vkd3d_shader_parameter_immediate_constant structure. The specialisation constant path should work fine as-is in terms of API, but probably needs some work in terms of SPIR-V generation.
Should this use a new helper for getting an immediate constant from an array, something like:
vkd3d_dxbc_compiler_get_uint_shader_array_parameter(struct vkd3d_dxbc_compiler *compiler, enum vkd3d_shader_parameter_name name, unsigned int index)
Plus a data type check in vkd3d_dxbc_compiler_emit_uint_shader_parameter().
Something along those lines. I think vkd3d_dxbc_compiler_get_constant_uint() should work fine for arrays, the caller can just pass something like "parameter->u.immediate_constant.u.u32_array[index]". We'd want an indexed variant of vkd3d_dxbc_compiler_emit_uint_shader_parameter() though, which we could then use in vkd3d_dxbc_compiler_get_descriptor_index().
I don't see a need to support specialisation constant arrays. We can just emit a compiler error if the UINT32_ARRAY data type is specified for a specialisation constant.
We could, but it's weird in terms of API consistency. From the point of view of a user of the API, there doesn't seem to be a good reason specialisation constant arrays wouldn't/shouldn't/couldn't be supported. It doesn't seem terribly hard to add either.
November 27, 2021 10:02 PM, "Henri Verbeet" hverbeet@gmail.com wrote:
Something along those lines. I think vkd3d_dxbc_compiler_get_constant_uint() should work fine for arrays, the caller can just pass something like "parameter->u.immediate_constant.u.u32_array[index]". We'd want an indexed variant of vkd3d_dxbc_compiler_emit_uint_shader_parameter() though, which we could then use in vkd3d_dxbc_compiler_get_descriptor_index().
I don't see a need to support specialisation constant arrays. We can just emit a compiler error if the UINT32_ARRAY data type is specified for a specialisation constant.
We could, but it's weird in terms of API consistency. From the point of view of a user of the API, there doesn't seem to be a good reason specialisation constant arrays wouldn't/shouldn't/couldn't be supported. It doesn't seem terribly hard to add either.
I think the only reasonable way to use the array is similar to what I've already done, i.e. find the u32 array and store it in the compiler object, because the indexed value needs to be subtracted from the base register index in vkd3d_dxbc_compiler_get_descriptor_binding(). To load an offset value in vkd3d_dxbc_compiler_get_descriptor_index() as a variable id means adding extra SPIR-V for the subtraction, plus the overhead of finding the parameter each time a descriptor is accessed. It's a performance cost for no advantage.
We can't support specialisation constants for the offsets without the extra SPIR-V, but nothing is gained by supporting them. As a descriptor offset array would be the only possible specialisation constant array, any support for them without that would be dead code.
If what you've described is the only acceptable way to send descriptor offsets via shader parameters, then parameters aren't an efficient way to send the offsets.
On Mon, 29 Nov 2021 at 13:58, Conor McCarthy cmccarthy@codeweavers.com wrote:
November 27, 2021 10:02 PM, "Henri Verbeet" hverbeet@gmail.com wrote:
We could, but it's weird in terms of API consistency. From the point of view of a user of the API, there doesn't seem to be a good reason specialisation constant arrays wouldn't/shouldn't/couldn't be supported. It doesn't seem terribly hard to add either.
I think the only reasonable way to use the array is similar to what I've already done, i.e. find the u32 array and store it in the compiler object, because the indexed value needs to be subtracted from the base register index in vkd3d_dxbc_compiler_get_descriptor_binding(). To load an offset value in vkd3d_dxbc_compiler_get_descriptor_index() as a variable id means adding extra SPIR-V for the subtraction, plus the overhead of finding the parameter each time a descriptor is accessed. It's a performance cost for no advantage.
Finding the parameter shouldn't be an issue. In the worst case we can just store a pointer in the vkd3d_symbol for the descriptor array, but more likely we'd be able to store a SPIR-V id for the result of the subtraction.
The run-time overhead may not be that bad either. After specialisation, the subtraction in question would be a constant expression, and at least in theory, a Vulkan driver could constant-fold that before generating code for the GPU.
Perhaps more importantly, much of what you write above would equally apply to the push constant path, and I think that's perhaps the more appropriate comparison. An application using vkd3d-shader (or vkd3d-compiler) for offline compilation could use push constants to specify offsets at run-time, but if it's known up-front that these offsets will be constant over the lifetime of the pipeline object, specialisation constants would be the more appropriate choice.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- include/vkd3d_shader.h | 49 +++++++++++++++++---- libs/vkd3d-shader/spirv.c | 87 +++++++++++++++++++++++++++++++------- libs/vkd3d/state.c | 10 +++-- libs/vkd3d/vkd3d_private.h | 2 +- 4 files changed, 120 insertions(+), 28 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index deffef19..f7a0f89d 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -249,6 +249,7 @@ enum vkd3d_shader_parameter_name { VKD3D_SHADER_PARAMETER_NAME_UNKNOWN, VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, + VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_TABLE, VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_OFFSETS, VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_OFFSETS,
@@ -268,13 +269,43 @@ struct vkd3d_shader_parameter_specialization_constant uint32_t id; };
+struct vkd3d_shader_parameter_descriptor_table +{ + /** + * Byte offset within the push constants of an array of 32-bit + * descriptor array offsets. See the description of + * 'struct vkd3d_shader_parameter_descriptor_offsets' below. + * If dynamic offsets are not required, set the 'count' field to zero, or + * omit the descriptor table parameter entirely. + */ + unsigned int offset; + /** Size, in elements, of the descriptor table push constant array. */ + unsigned int count; +}; + +struct vkd3d_shader_descriptor_offset +{ + unsigned int static_offset; + unsigned int dynamic_offset_index; +}; + struct vkd3d_shader_parameter_descriptor_offsets { /** - * 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. + * 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 either omit the descriptor table parameter from the + * parameter list, or set its 'count' field 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 @@ -297,7 +328,7 @@ struct vkd3d_shader_parameter_descriptor_offsets * binding.count = 2 * \endcode * - * and then pass \c {8, \c 4} as \a binding_offsets here. + * and then pass \c {8, \c 4} for \a static_offset within \a offsets here. * * This field may be NULL, or the structure may be omitted from the * parameter list, in which case the corresponding offsets are specified @@ -310,7 +342,7 @@ struct vkd3d_shader_parameter_descriptor_offsets * this version of vkd3d-shader, and therefore this field must be NULL, or * the parameter omitted. */ - const unsigned int *offsets; + const struct vkd3d_shader_descriptor_offset *offsets; };
struct vkd3d_shader_parameter @@ -322,6 +354,7 @@ struct vkd3d_shader_parameter { struct vkd3d_shader_parameter_immediate_constant immediate_constant; struct vkd3d_shader_parameter_specialization_constant specialization_constant; + struct vkd3d_shader_parameter_descriptor_table descriptor_table; struct vkd3d_shader_parameter_descriptor_offsets descriptor_offsets; } u; }; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 9f71c6e0..bace7600 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 @@ -1990,6 +1991,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; @@ -2235,7 +2242,10 @@ struct vkd3d_dxbc_compiler size_t control_flow_info_size;
struct vkd3d_shader_interface_info shader_interface; - const unsigned int *binding_offsets; + const struct vkd3d_shader_descriptor_offset *binding_offsets; + struct vkd3d_shader_parameter_descriptor_table descriptor_table; + unsigned int descriptor_offsets_member_idx; + unsigned int push_constants_var_id; struct vkd3d_push_constant_buffer_binding *push_constants; const struct vkd3d_shader_spirv_target_info *spirv_target_info;
@@ -2396,6 +2406,8 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader } }
+ if ((parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_TABLE))) + compiler->descriptor_table = parameter->u.descriptor_table; if ((parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_OFFSETS))) compiler->binding_offsets = parameter->u.descriptor_offsets.offsets; if ((parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_OFFSETS))) @@ -2556,11 +2568,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->binding_offsets; + const struct vkd3d_shader_descriptor_offset *binding_offsets = compiler->binding_offsets; enum vkd3d_shader_descriptor_type descriptor_type; enum vkd3d_shader_binding_flag resource_type_flag; struct vkd3d_shader_descriptor_binding binding; @@ -2614,7 +2626,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) @@ -2641,7 +2654,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) @@ -2658,7 +2673,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++; @@ -2679,10 +2695,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); }
@@ -3250,12 +3266,13 @@ 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, - enum vkd3d_shader_resource_type resource_type) + const struct vkd3d_symbol *array_symbol, enum vkd3d_shader_resource_type resource_type) { + const struct vkd3d_symbol_descriptor_array *array_key = &array_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)) { @@ -3269,6 +3286,21 @@ static uint32_t vkd3d_dxbc_compiler_get_descriptor_index(struct vkd3d_dxbc_compi index.offset -= binding_base_idx; index_id = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &index);
+ if (array_key->push_constant_index != ~0u && compiler->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; }
@@ -3285,7 +3317,7 @@ static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_comp assert(!reg->idx[0].rel_addr); if (register_info->descriptor_array) indexes[index_count++] = vkd3d_dxbc_compiler_get_descriptor_index(compiler, reg, - register_info->binding_base_idx, VKD3D_SHADER_RESOURCE_BUFFER); + register_info->binding_base_idx, register_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]); } @@ -5503,7 +5535,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->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]; @@ -5532,6 +5564,16 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com ++j; }
+ if (compiler->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->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"); @@ -5540,6 +5582,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) { @@ -5560,6 +5603,12 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com
++j; } + + if (compiler->descriptor_table.count) + { + vkd3d_spirv_build_op_member_decorate1(builder, struct_id, compiler->descriptor_offsets_member_idx, + SpvDecorationOffset, compiler->descriptor_table.offset); + } }
struct vkd3d_descriptor_variable_info @@ -5574,15 +5623,18 @@ static uint32_t vkd3d_dxbc_compiler_build_descriptor_variable(struct vkd3d_dxbc_ struct vkd3d_descriptor_variable_info *var_info) { 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, &var_info->binding_base_idx); + resource_type, false, &binding_address); + var_info->binding_base_idx = binding_address.binding_base_idx;
- if (binding.count == 1 && range->last != ~0u) + if (binding.count == 1 && range->first == binding_address.binding_base_idx && range->last != ~0u + && binding_address.push_constant_index == ~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, @@ -5606,6 +5658,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))) { var_info->array_symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); @@ -8057,7 +8110,8 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil uint32_t ptr_type_id, index_id;
index_id = vkd3d_dxbc_compiler_get_descriptor_index(compiler, resource_reg, - symbol->info.resource.binding_base_idx, symbol->info.resource.resource_type_info->resource_type); + symbol->info.resource.binding_base_idx, 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); @@ -8117,7 +8171,8 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil 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, register_info.binding_base_idx, VKD3D_SHADER_RESOURCE_NONE); + sampler_reg, register_info.binding_base_idx, register_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); }
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 8f788dba..fcd82003 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, 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 --- libs/vkd3d-shader/spirv.c | 90 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index bace7600..ee109554 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1984,6 +1984,8 @@ struct vkd3d_symbol_resource_data bool raw; unsigned int binding_base_idx; uint32_t uav_counter_id; + const struct vkd3d_symbol *uav_counter_array; + unsigned int uav_counter_base_idx; };
struct vkd3d_symbol_sampler_data @@ -2243,6 +2245,7 @@ struct vkd3d_dxbc_compiler
struct vkd3d_shader_interface_info shader_interface; const struct vkd3d_shader_descriptor_offset *binding_offsets; + const struct vkd3d_shader_descriptor_offset *uav_counter_offsets; struct vkd3d_shader_parameter_descriptor_table descriptor_table; unsigned int descriptor_offsets_member_idx; unsigned int push_constants_var_id; @@ -2411,7 +2414,7 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader if ((parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_DESCRIPTOR_OFFSETS))) compiler->binding_offsets = parameter->u.descriptor_offsets.offsets; if ((parameter = vkd3d_dxbc_compiler_get_shader_parameter(compiler, VKD3D_SHADER_PARAMETER_NAME_UAV_COUNTER_OFFSETS))) - WARN("Ignoring UAV counter offsets %p.\n", parameter->u.descriptor_offsets.offsets); + compiler->uav_counter_offsets = parameter->u.descriptor_offsets.offsets;
compiler->scan_descriptor_info = scan_descriptor_info;
@@ -2572,7 +2575,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor { const struct vkd3d_shader_interface_info *shader_interface = &compiler->shader_interface; unsigned int register_last = (range->last == ~0u) ? range->first : range->last; - const struct vkd3d_shader_descriptor_offset *binding_offsets = compiler->binding_offsets; + const struct vkd3d_shader_descriptor_offset *binding_offsets; enum vkd3d_shader_descriptor_type descriptor_type; enum vkd3d_shader_binding_flag resource_type_flag; struct vkd3d_shader_descriptor_binding binding; @@ -2599,6 +2602,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor
if (is_uav_counter) { + binding_offsets = compiler->uav_counter_offsets; assert(descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV); for (i = 0; i < shader_interface->uav_counter_count; ++i) { @@ -2607,7 +2611,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) @@ -2618,16 +2623,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) @@ -2639,6 +2637,7 @@ static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor } else { + binding_offsets = compiler->binding_offsets; for (i = 0; i < shader_interface->binding_count; ++i) { const struct vkd3d_shader_resource_binding *current = &shader_interface->bindings[i]; @@ -2690,18 +2689,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) { @@ -2936,6 +2923,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) { @@ -5620,7 +5608,7 @@ struct vkd3d_descriptor_variable_info 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_variable_info *var_info) + bool is_uav_counter, struct vkd3d_descriptor_variable_info *var_info) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; struct vkd3d_descriptor_binding_address binding_address; @@ -5630,7 +5618,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); var_info->binding_base_idx = binding_address.binding_base_idx;
if (binding.count == 1 && range->first == binding_address.binding_base_idx && range->last != ~0u @@ -5720,7 +5708,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, &var_info); + reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, false, &var_info);
vkd3d_symbol_make_register(®_symbol, reg); vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, @@ -5783,7 +5771,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, &var_info); + &sampler->range, VKD3D_SHADER_RESOURCE_NONE, false, &var_info);
vkd3d_symbol_make_register(®_symbol, reg); vkd3d_symbol_set_register_info(®_symbol, var_id, storage_class, @@ -5955,6 +5943,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 = NULL; + symbol.info.resource.uav_counter_base_idx = 0; vkd3d_dxbc_compiler_put_symbol(compiler, &symbol); } } @@ -5963,12 +5953,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_variable_info var_info, counter_var_info; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; SpvStorageClass storage_class = SpvStorageClassUniformConstant; + uint32_t counter_type_id, type_id, var_id, counter_var_id = 0; const struct vkd3d_shader_register *reg = &resource->reg.reg; const struct vkd3d_spirv_resource_type *resource_type_info; - struct vkd3d_descriptor_variable_info var_info; enum vkd3d_shader_component_type sampled_type; struct vkd3d_symbol resource_symbol; bool is_uav; @@ -6013,7 +6003,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, &var_info); + &resource->range, resource_type, false, &var_info);
if (is_uav) { @@ -6034,7 +6024,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) { @@ -6049,20 +6039,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); + type_id = struct_id; } - else - { - ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, 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, &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_var_info); } }
@@ -6077,6 +6058,8 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp resource_symbol.info.resource.raw = raw; resource_symbol.info.resource.binding_base_idx = var_info.binding_base_idx; resource_symbol.info.resource.uav_counter_id = counter_var_id; + resource_symbol.info.resource.uav_counter_array = counter_var_info.array_symbol; + resource_symbol.info.resource.uav_counter_base_idx = counter_var_info.binding_base_idx; vkd3d_dxbc_compiler_put_symbol(compiler, &resource_symbol); }
@@ -8896,6 +8879,23 @@ static void vkd3d_dxbc_compiler_emit_uav_counter_instruction(struct vkd3d_dxbc_c } else { + if (resource_symbol->info.resource.uav_counter_array) + { + 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_base_idx, + 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->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,