Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d-shader/spirv.c | 145 +++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 136 insertions(+), 10 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 61f0d903..25936849 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1,5 +1,6 @@ /* * Copyright 2017 Józef Kucia for CodeWeavers + * Copyright 2021 Conor McCarthy for Codeweavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1918,6 +1919,13 @@ struct vkd3d_symbol_combined_sampler unsigned int sampler_index; };
+struct vkd3d_symbol_descriptor_array +{ + uint32_t ptr_type_id; + unsigned int set; + unsigned int binding; +}; + struct vkd3d_symbol_register_data { SpvStorageClass storage_class; @@ -1946,6 +1954,13 @@ struct vkd3d_symbol_sampler_data struct vkd3d_shader_register_range range; };
+struct vkd3d_symbol_descriptor_array_data +{ + SpvStorageClass storage_class; + uint32_t contained_type_id; + unsigned int binding_base_idx; +}; + struct vkd3d_symbol { struct rb_entry entry; @@ -1956,6 +1971,7 @@ struct vkd3d_symbol VKD3D_SYMBOL_RESOURCE, VKD3D_SYMBOL_SAMPLER, VKD3D_SYMBOL_COMBINED_SAMPLER, + VKD3D_SYMBOL_DESCRIPTOR_ARRAY, } type;
union @@ -1964,14 +1980,19 @@ struct vkd3d_symbol struct vkd3d_symbol_resource resource; struct vkd3d_symbol_sampler sampler; struct vkd3d_symbol_combined_sampler combined_sampler; + struct vkd3d_symbol_descriptor_array descriptor_array; } key;
uint32_t id; + /* The array declaration which this symbol maps to, or NULL. */ + const struct vkd3d_symbol *descriptor_array; + union { struct vkd3d_symbol_register_data reg; struct vkd3d_symbol_resource_data resource; struct vkd3d_symbol_sampler_data sampler; + struct vkd3d_symbol_descriptor_array_data descriptor_array; } info; };
@@ -2009,6 +2030,7 @@ static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol, enum vkd3d_shader_component_type component_type, DWORD write_mask) { symbol->id = val_id; + symbol->descriptor_array = NULL; symbol->info.reg.storage_class = storage_class; symbol->info.reg.member_idx = 0; symbol->info.reg.component_type = component_type; @@ -2610,7 +2632,7 @@ static void vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(struct vkd3d_dxb vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding); }
-static void vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler, +static const struct vkd3d_symbol *vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_symbol *symbol) { struct vkd3d_symbol *s; @@ -2620,7 +2642,9 @@ static void vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler, { ERR("Failed to insert symbol entry (%s).\n", debug_vkd3d_symbol(symbol)); vkd3d_free(s); + return NULL; } + return s; }
static uint32_t vkd3d_dxbc_compiler_get_constant(struct vkd3d_dxbc_compiler *compiler, @@ -3011,6 +3035,7 @@ static uint32_t vkd3d_dxbc_compiler_emit_register_addressing(struct vkd3d_dxbc_c struct vkd3d_shader_register_info { uint32_t id; + const struct vkd3d_symbol *descriptor_array; SpvStorageClass storage_class; enum vkd3d_shader_component_type component_type; unsigned int write_mask; @@ -3033,6 +3058,7 @@ static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compil assert(reg->idx[0].offset < compiler->temp_count); register_info->id = compiler->temp_id + reg->idx[0].offset; register_info->storage_class = SpvStorageClassFunction; + register_info->descriptor_array = NULL; register_info->member_idx = 0; register_info->component_type = VKD3D_SHADER_COMPONENT_FLOAT; register_info->write_mask = VKD3DSP_WRITEMASK_ALL; @@ -3052,6 +3078,7 @@ static bool vkd3d_dxbc_compiler_get_register_info(const struct vkd3d_dxbc_compil
symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); register_info->id = symbol->id; + register_info->descriptor_array = symbol->descriptor_array; register_info->storage_class = symbol->info.reg.storage_class; register_info->member_idx = symbol->info.reg.member_idx; register_info->component_type = symbol->info.reg.component_type; @@ -3078,17 +3105,42 @@ static bool register_is_descriptor(const struct vkd3d_shader_register *reg) } }
+static uint32_t vkd3d_dxbc_compiler_get_resource_index(struct vkd3d_dxbc_compiler *compiler, + const struct vkd3d_shader_register *reg, unsigned int binding_base_idx, + enum vkd3d_shader_resource_type resource_type) +{ + struct vkd3d_shader_register_index index = reg->idx[1]; + uint32_t index_id; + + if (index.rel_addr) + { + FIXME("Descriptor dynamic indexing is not supported.\n"); + vkd3d_dxbc_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED, + "Cannot dynamically index a descriptor array of type %#x, id %u. " + "Dynamic indexing is not supported.", reg->type, reg->idx[0].offset); + } + + index.offset -= binding_base_idx; + index_id = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &index); + + return index_id; +} + static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg, struct vkd3d_shader_register_info *register_info) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; unsigned int component_count, index_count = 0; uint32_t type_id, ptr_type_id; - uint32_t indexes[2]; + uint32_t indexes[3];
if (reg->type == VKD3DSPR_CONSTBUFFER) { assert(!reg->idx[0].rel_addr); + if (register_info->descriptor_array) + indexes[index_count++] = vkd3d_dxbc_compiler_get_resource_index(compiler, reg, + register_info->descriptor_array->info.descriptor_array.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]); } @@ -5282,16 +5334,91 @@ static void vkd3d_dxbc_compiler_emit_push_constant_buffers(struct vkd3d_dxbc_com } }
+static uint32_t vkd3d_dxbc_compiler_get_resource_variable(struct vkd3d_dxbc_compiler *compiler, + const struct vkd3d_symbol_descriptor_array_data *array_data, uint32_t ptr_type_id, + const struct vkd3d_shader_register *reg, const struct vkd3d_shader_descriptor_binding *binding, + const struct vkd3d_symbol **array_symbol) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + + if (array_data->contained_type_id) + { + struct vkd3d_symbol *array_symbol_entry; + struct vkd3d_symbol symbol; + struct rb_entry *entry; + + /* Declare one array variable per Vulkan binding, and use it for all array declarations + * which map to it. In this case ptr_type_id must point to an array type. */ + symbol.type = VKD3D_SYMBOL_DESCRIPTOR_ARRAY; + memset(&symbol.key, 0, sizeof(symbol.key)); + symbol.key.descriptor_array.ptr_type_id = ptr_type_id; + symbol.key.descriptor_array.set = binding->set; + symbol.key.descriptor_array.binding = binding->binding; + if ((entry = rb_get(&compiler->symbol_table, &symbol))) + { + array_symbol_entry = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); + *array_symbol = array_symbol_entry; + return array_symbol_entry->id; + } + + symbol.id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, + ptr_type_id, array_data->storage_class, 0); + symbol.descriptor_array = NULL; + vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, symbol.id, binding); + vkd3d_dxbc_compiler_emit_register_debug_name(builder, symbol.id, reg); + + symbol.info.descriptor_array = *array_data; + *array_symbol = vkd3d_dxbc_compiler_put_symbol(compiler, &symbol); + + return symbol.id; + } + else + { + uint32_t var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, + ptr_type_id, array_data->storage_class, 0); + vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, binding); + vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg); + *array_symbol = NULL; + return var_id; + } +} + +static uint32_t vkd3d_dxbc_compiler_build_resource_variable(struct vkd3d_dxbc_compiler *compiler, + SpvStorageClass storage_class, uint32_t type_id, const struct vkd3d_shader_register *reg, + const struct vkd3d_shader_descriptor_binding *binding, unsigned int binding_base_idx, + bool array_variable, const struct vkd3d_symbol **array_symbol) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + struct vkd3d_symbol_descriptor_array_data array_data; + uint32_t ptr_type_id; + + array_data.storage_class = storage_class; + array_data.contained_type_id = 0; + array_data.binding_base_idx = binding_base_idx; + if (array_variable) + { + array_data.contained_type_id = type_id; + type_id = vkd3d_spirv_get_op_type_array(builder, type_id, + vkd3d_dxbc_compiler_get_constant_uint(compiler, binding->count)); + } + ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, array_data.storage_class, type_id); + + return vkd3d_dxbc_compiler_get_resource_variable(compiler, &array_data, ptr_type_id, reg, binding, array_symbol); +} + static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - uint32_t vec4_id, array_type_id, length_id, struct_id, pointer_type_id, var_id; const struct vkd3d_shader_constant_buffer *cb = &instruction->declaration.cb; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + uint32_t vec4_id, array_type_id, length_id, struct_id, var_id; const SpvStorageClass storage_class = SpvStorageClassUniform; const struct vkd3d_shader_register *reg = &cb->src.reg; struct vkd3d_push_constant_buffer_binding *push_cb; + struct vkd3d_shader_descriptor_binding binding; + const struct vkd3d_symbol *array_symbol; struct vkd3d_symbol reg_symbol; + unsigned int binding_base_idx;
assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC));
@@ -5321,18 +5448,16 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0); vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", cb->size);
- 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); - - vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(compiler, - var_id, reg, &cb->range, VKD3D_SHADER_RESOURCE_BUFFER, false); + binding = vkd3d_dxbc_compiler_get_descriptor_binding(compiler, reg, &cb->range, + VKD3D_SHADER_RESOURCE_BUFFER, false, &binding_base_idx);
- vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg); + var_id = vkd3d_dxbc_compiler_build_resource_variable(compiler, storage_class, struct_id, + reg, &binding, binding_base_idx, binding.count != 1 || cb->range.last == ~0u, &array_symbol);
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; vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol); }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index c5d1372a..f62d2d48 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -74,6 +74,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_BINDING_NOT_FOUND = 2000, VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE = 2001, VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING = 2002, + VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED = 2003,
VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY = 3000, VKD3D_SHADER_ERROR_RS_INVALID_VERSION = 3001,