From: Józef Kucia jkucia@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- include/private/vkd3d_shader.h | 15 +++ libs/vkd3d-shader/spirv.c | 164 +++++++++++++++++++++++++++++++-- libs/vkd3d/state.c | 4 + 3 files changed, 175 insertions(+), 8 deletions(-)
diff --git a/include/private/vkd3d_shader.h b/include/private/vkd3d_shader.h index ce8de6dad388..ac163583b65a 100644 --- a/include/private/vkd3d_shader.h +++ b/include/private/vkd3d_shader.h @@ -91,6 +91,18 @@ struct vkd3d_shader_resource_binding struct vkd3d_shader_descriptor_binding binding; };
+#define VKD3D_DUMMY_SAMPLER_INDEX ~0u + +struct vkd3d_shader_combined_resource_sampler +{ + unsigned int resource_index; + unsigned int sampler_index; + enum vkd3d_shader_visibility shader_visibility; + bool is_buffer; + + struct vkd3d_shader_descriptor_binding binding; +}; + struct vkd3d_shader_uav_counter_binding { unsigned int register_index; /* u# */ @@ -116,6 +128,9 @@ struct vkd3d_shader_interface const struct vkd3d_shader_push_constant_buffer *push_constant_buffers; unsigned int push_constant_buffer_count;
+ const struct vkd3d_shader_combined_resource_sampler *combined_samplers; + unsigned int combined_sampler_count; + /* A sampler used by OpImageFetches generated for SM4 ld instructions. * * In Vulkan OpImageFetch must be used with a sampled image. diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index e964cce24677..3186c2c3c9a3 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1676,6 +1676,12 @@ struct vkd3d_symbol_resource unsigned int idx; };
+struct vkd3d_symbol_combined_sampler +{ + unsigned int resource_idx; + unsigned int sampler_idx; +}; + struct vkd3d_symbol_register_data { SpvStorageClass storage_class; @@ -1703,12 +1709,14 @@ struct vkd3d_symbol { VKD3D_SYMBOL_REGISTER, VKD3D_SYMBOL_RESOURCE, + VKD3D_SYMBOL_COMBINED_SAMPLER, } type;
union { struct vkd3d_symbol_register reg; struct vkd3d_symbol_resource resource; + struct vkd3d_symbol_combined_sampler combined_sampler; } key;
uint32_t id; @@ -1757,6 +1765,15 @@ static void vkd3d_symbol_make_resource(struct vkd3d_symbol *symbol, symbol->key.resource.idx = reg->idx[0].offset; }
+static void vkd3d_symbol_make_combined_sampler(struct vkd3d_symbol *symbol, + unsigned int resource_index, unsigned int sampler_index) +{ + symbol->type = VKD3D_SYMBOL_COMBINED_SAMPLER; + memset(&symbol->key, 0, sizeof(symbol->key)); + symbol->key.combined_sampler.resource_idx = resource_index; + symbol->key.combined_sampler.sampler_idx = sampler_index; +} + static struct vkd3d_symbol *vkd3d_symbol_dup(const struct vkd3d_symbol *symbol) { struct vkd3d_symbol *s; @@ -2009,6 +2026,31 @@ static struct vkd3d_push_constant_buffer_binding *vkd3d_dxbc_compiler_find_push_ return NULL; }
+static bool vkd3d_dxbc_compiler_have_combined_sampler(const struct vkd3d_dxbc_compiler *compiler, + const struct vkd3d_shader_register *resource, const struct vkd3d_shader_register *sampler) +{ + const struct vkd3d_shader_interface *shader_interface = &compiler->shader_interface; + const struct vkd3d_shader_combined_resource_sampler *combined_sampler; + unsigned int i; + + if (!shader_interface->combined_sampler_count) + return false; + + if (resource && resource->type == VKD3DSPR_UAV) + return false; + + for (i = 0; i < shader_interface->combined_sampler_count; ++i) + { + combined_sampler = &shader_interface->combined_samplers[i]; + + if (!(resource || combined_sampler->resource_index == resource->idx[0].offset) + && (!sampler || combined_sampler->sampler_index == sampler->idx[0].offset)) + return true; + } + + return false; +} + static struct vkd3d_shader_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_binding( struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg, enum vkd3d_shader_resource_type resource_type, bool is_uav_counter) @@ -3753,6 +3795,9 @@ static void vkd3d_dxbc_compiler_emit_dcl_sampler(struct vkd3d_dxbc_compiler *com uint32_t type_id, ptr_type_id, var_id; struct vkd3d_symbol reg_symbol;
+ if (vkd3d_dxbc_compiler_have_combined_sampler(compiler, NULL, reg)) + return; + type_id = vkd3d_spirv_get_op_type_sampler(builder); 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, @@ -3852,6 +3897,64 @@ static uint32_t vkd3d_dxbc_compiler_get_image_type_id(struct vkd3d_dxbc_compiler reg->type == VKD3DSPR_UAV ? 2 : 1, format); }
+static void vkd3d_dxbc_compiler_emit_combined_sampler_declarations(struct vkd3d_dxbc_compiler *compiler, + const struct vkd3d_shader_register *resource, enum vkd3d_shader_resource_type resource_type, + enum vkd3d_component_type sampled_type, unsigned int structure_stride, bool raw, + const struct vkd3d_spirv_resource_type *resource_type_info) +{ + const struct vkd3d_shader_interface *shader_interface = &compiler->shader_interface; + const struct vkd3d_shader_scan_info *scan_info = compiler->scan_info; + const SpvStorageClass storage_class = SpvStorageClassUniformConstant; + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_combined_resource_sampler *current; + const unsigned int resource_index = resource->idx[0].offset; + uint32_t image_type_id, type_id, ptr_type_id, var_id; + bool is_buffer_resource, depth; + struct vkd3d_symbol symbol; + unsigned int i; + + is_buffer_resource = resource_type == VKD3D_SHADER_RESOURCE_BUFFER; + + for (i = 0; i < shader_interface->combined_sampler_count; ++i) + { + current = &shader_interface->combined_samplers[i]; + + if (current->resource_index != resource_index || current->is_buffer != is_buffer_resource) + continue; + + if (!vkd3d_dxbc_compiler_check_shader_visibility(compiler, current->shader_visibility)) + continue; + + depth = current->sampler_index != VKD3D_DUMMY_SAMPLER_INDEX + && scan_info->sampler_comparison_mode_mask & (1u << current->sampler_index); + + image_type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, + resource, resource_type_info, sampled_type, structure_stride || raw, depth); + type_id = vkd3d_spirv_get_op_type_sampled_image(builder, image_type_id); + + 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, + ptr_type_id, storage_class, 0); + + vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, ¤t->binding); + + if (current->sampler_index == VKD3D_DUMMY_SAMPLER_INDEX) + vkd3d_spirv_build_op_name(builder, var_id, "t%u_dummy_sampler", resource_index); + else + vkd3d_spirv_build_op_name(builder, var_id, "t%u_s%u", resource_index, current->sampler_index); + + vkd3d_symbol_make_combined_sampler(&symbol, resource_index, current->sampler_index); + symbol.id = var_id; + symbol.info.resource.sampled_type = sampled_type; + symbol.info.resource.type_id = image_type_id; + symbol.info.resource.resource_type_info = resource_type_info; + symbol.info.resource.structure_stride = structure_stride; + symbol.info.resource.raw = raw; + symbol.info.resource.uav_counter_id = 0; + vkd3d_dxbc_compiler_put_symbol(compiler, &symbol); + } +} + static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg, enum vkd3d_shader_resource_type resource_type, enum vkd3d_data_type resource_data_type, unsigned int structure_stride, bool raw) @@ -3875,6 +3978,13 @@ static void vkd3d_dxbc_compiler_emit_resource_declaration(struct vkd3d_dxbc_comp
sampled_type = vkd3d_component_type_from_data_type(resource_data_type);
+ if (vkd3d_dxbc_compiler_have_combined_sampler(compiler, reg, NULL)) + { + vkd3d_dxbc_compiler_emit_combined_sampler_declarations(compiler, + reg, resource_type, sampled_type, structure_stride, raw, resource_type_info); + return; + } + type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, reg, resource_type_info, sampled_type, structure_stride || raw, 0); ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id); @@ -5350,27 +5460,65 @@ static const struct vkd3d_symbol *vkd3d_dxbc_compiler_find_resource(struct vkd3d return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); }
+static const struct vkd3d_symbol *vkd3d_dxbc_compiler_find_combined_sampler(struct vkd3d_dxbc_compiler *compiler, + const struct vkd3d_shader_register *resource_reg, const struct vkd3d_shader_register *sampler_reg) +{ + const struct vkd3d_shader_interface *shader_interface = &compiler->shader_interface; + unsigned int resource_index, sampler_index; + struct vkd3d_symbol key; + struct rb_entry *entry; + + if (!shader_interface->combined_sampler_count) + return NULL; + + resource_index = resource_reg->idx[0].offset; + sampler_index = sampler_reg ? sampler_reg->idx[0].offset : VKD3D_DUMMY_SAMPLER_INDEX; + + vkd3d_symbol_make_combined_sampler(&key, resource_index, sampler_index); + if ((entry = rb_get(&compiler->symbol_table, &key))) + return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); + return NULL; +} + static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compiler, struct vkd3d_shader_image *image, const struct vkd3d_shader_register *resource_reg, const struct vkd3d_shader_register *sampler_reg, unsigned int flags) { + const struct vkd3d_symbol *symbol = NULL, *combined_sampler = NULL; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t sampler_var_id, sampler_id, sampled_image_type_id; - const struct vkd3d_symbol *resource_symbol; bool load, depth_comparison;
load = !(flags & VKD3D_IMAGE_FLAG_NO_LOAD); depth_comparison = flags & VKD3D_IMAGE_FLAG_DEPTH;
- resource_symbol = vkd3d_dxbc_compiler_find_resource(compiler, resource_reg); + if (flags & VKD3D_IMAGE_FLAG_SAMPLED) + { + assert(load); + combined_sampler = vkd3d_dxbc_compiler_find_combined_sampler(compiler, + resource_reg, sampler_reg); + symbol = combined_sampler; + } + if (!symbol) + symbol = vkd3d_dxbc_compiler_find_resource(compiler, resource_reg); + + image->id = symbol->id; + image->sampled_type = symbol->info.resource.sampled_type; + image->image_type_id = symbol->info.resource.type_id; + image->resource_type_info = symbol->info.resource.resource_type_info; + image->structure_stride = symbol->info.resource.structure_stride; + image->raw = symbol->info.resource.raw;
- image->sampled_type = resource_symbol->info.resource.sampled_type; - image->image_type_id = resource_symbol->info.resource.type_id; - image->resource_type_info = resource_symbol->info.resource.resource_type_info; - image->structure_stride = resource_symbol->info.resource.structure_stride; - image->raw = resource_symbol->info.resource.raw; + if (combined_sampler) + { + sampled_image_type_id = vkd3d_spirv_get_op_type_sampled_image(builder, image->image_type_id); + image->sampled_image_id = vkd3d_spirv_build_op_load(builder, + sampled_image_type_id, image->id, SpvMemoryAccessMaskNone); + image->image_id = vkd3d_spirv_build_op_image(builder, + image->image_type_id, image->sampled_image_id); + return; + }
- image->id = resource_symbol->id; image->image_id = load ? vkd3d_spirv_build_op_load(builder, image->image_type_id, image->id, SpvMemoryAccessMaskNone) : 0;
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 82721f27b448..db761d884756 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -1434,6 +1434,8 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st shader_interface.binding_count = root_signature->descriptor_count; shader_interface.push_constant_buffers = root_signature->root_constants; shader_interface.push_constant_buffer_count = root_signature->root_constant_count; + shader_interface.combined_samplers = NULL; + shader_interface.combined_sampler_count = 0; shader_interface.dummy_sampler = root_signature->dummy_sampler; shader_interface.uav_counters = state->uav_counters; shader_interface.uav_counter_count = vkd3d_popcount(state->uav_counter_mask); @@ -2002,6 +2004,8 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s shader_interface.binding_count = root_signature->descriptor_count; shader_interface.push_constant_buffers = root_signature->root_constants; shader_interface.push_constant_buffer_count = root_signature->root_constant_count; + shader_interface.combined_samplers = NULL; + shader_interface.combined_sampler_count = 0; shader_interface.dummy_sampler = root_signature->dummy_sampler; shader_interface.uav_counters = NULL; shader_interface.uav_counter_count = 0;