[PATCH vkd3d v2 4/5] vkd3d-shader/spirv: Support runtime descriptor array offsets using push constants.
Conor McCarthy
cmccarthy at codeweavers.com
Tue Nov 23 08:41:36 CST 2021
Signed-off-by: Conor McCarthy <cmccarthy at 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;
--
2.33.0
More information about the wine-devel
mailing list