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;