From 8334386d99c720ca52afb67b52c7ef3e6c9e361c Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Sun, 10 Aug 2025 19:58:02 +0200 Subject: [PATCH] vkd3d-shader/spirv: Avoid emitting duplicate built-in inputs in spirv_compiler_emit_input(). This works around an issue introduced by commit 66cb2815f0662713c3255113255cfd7cf5e406fb. SV_PRIMITIVE_ID inputs in geometry shaders use VKD3DSPR_PRIMID registers, and we create the corresponding SPIR-V inputs using spirv_compiler_emit_io_register(). Unfortunately we also have an input signature element for the same input, and simply creating another PrimitiveId input would run into VUID-StandaloneSpirv-OpEntryPoint-09658. Before the commit mentioned above, we'd use DCL_INPUT instructions to emit input declarations, and these would help to distinguish whether VKD3DSPR_INPUT or VKD3DSPR_PRIMID registers were used for primitive ID inputs. Note that we can't simply ignore input signature element with SIGNATURE_TARGET_LOCATION_UNUSED; the DXIL parser emits SV_SAMPLE_INDEX inputs with that target location, but does require them to use a VKD3DSPR_INPUT register. --- libs/vkd3d-shader/spirv.c | 100 +++++++++++++---------- libs/vkd3d-shader/vkd3d_shader_private.h | 14 ++++ 2 files changed, 73 insertions(+), 41 deletions(-) diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index be549d74e..661d98c88 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5676,6 +5676,48 @@ static unsigned int shader_signature_next_location(const struct shader_signature return max_row; } +static const struct vkd3d_symbol *spirv_compiler_emit_io_register(struct spirv_compiler *compiler, + const struct vkd3d_shader_dst_param *dst) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_register *reg = &dst->reg; + const struct vkd3d_spirv_builtin *builtin; + struct vkd3d_symbol reg_symbol; + SpvStorageClass storage_class; + uint32_t write_mask, id; + struct rb_entry *entry; + + VKD3D_ASSERT(!reg->idx_count || !reg->idx[0].rel_addr); + VKD3D_ASSERT(reg->idx_count < 2); + + if (reg->type == VKD3DSPR_RASTOUT && reg->idx[0].offset == VSIR_RASTOUT_POINT_SIZE) + { + builtin = &vkd3d_output_point_size_builtin; + storage_class = SpvStorageClassOutput; + } + else if (!(builtin = get_spirv_builtin_for_register(reg->type, &storage_class))) + { + FIXME("Unhandled register %#x.\n", reg->type); + return NULL; + } + + /* vPrim may be declared in multiple hull shader phases. */ + vkd3d_symbol_make_register(®_symbol, reg); + if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) + return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry); + + id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, 0); + spirv_compiler_emit_register_execution_mode(compiler, reg->type); + spirv_compiler_emit_register_debug_name(builder, id, reg); + + write_mask = vkd3d_write_mask_from_component_count(builtin->component_count); + vkd3d_symbol_set_register_info(®_symbol, id, + storage_class, builtin->component_type, write_mask); + reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size; + + return spirv_compiler_put_symbol(compiler, ®_symbol); +} + static void spirv_compiler_emit_input(struct spirv_compiler *compiler, enum vkd3d_shader_register_type reg_type, unsigned int element_idx) { @@ -5684,6 +5726,7 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler, const struct signature_element *signature_element; const struct shader_signature *shader_signature; enum vkd3d_shader_component_type component_type; + enum vkd3d_shader_register_type sysval_reg_type; const struct vkd3d_spirv_builtin *builtin; enum vkd3d_shader_sysval_semantic sysval; uint32_t write_mask, reg_write_mask; @@ -5708,6 +5751,22 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler, if (!signature_element->used_mask) return; + sysval_reg_type = vsir_register_type_from_sysval_input(signature_element->sysval_semantic); + if (sysval_reg_type != VKD3DSPR_INPUT) + { + struct vkd3d_shader_dst_param dst; + const struct vkd3d_symbol *symbol; + + vsir_dst_param_init(&dst, sysval_reg_type, VSIR_DATA_F32, 0); + symbol = spirv_compiler_emit_io_register(compiler, &dst); + + vkd3d_symbol_make_io(®_symbol, reg_type, element_idx); + reg_symbol.id = symbol->id; + reg_symbol.info.reg = symbol->info.reg; + spirv_compiler_put_symbol(compiler, ®_symbol); + return; + } + builtin = get_spirv_builtin_for_sysval(compiler, sysval); array_sizes[0] = signature_element->register_count; @@ -5829,47 +5888,6 @@ static void spirv_compiler_emit_input(struct spirv_compiler *compiler, } } -static void spirv_compiler_emit_io_register(struct spirv_compiler *compiler, - const struct vkd3d_shader_dst_param *dst) -{ - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_register *reg = &dst->reg; - const struct vkd3d_spirv_builtin *builtin; - struct vkd3d_symbol reg_symbol; - SpvStorageClass storage_class; - uint32_t write_mask, id; - struct rb_entry *entry; - - VKD3D_ASSERT(!reg->idx_count || !reg->idx[0].rel_addr); - VKD3D_ASSERT(reg->idx_count < 2); - - if (reg->type == VKD3DSPR_RASTOUT && reg->idx[0].offset == VSIR_RASTOUT_POINT_SIZE) - { - builtin = &vkd3d_output_point_size_builtin; - storage_class = SpvStorageClassOutput; - } - else if (!(builtin = get_spirv_builtin_for_register(reg->type, &storage_class))) - { - FIXME("Unhandled register %#x.\n", reg->type); - return; - } - - /* vPrim may be declared in multiple hull shader phases. */ - vkd3d_symbol_make_register(®_symbol, reg); - if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) - return; - - id = spirv_compiler_emit_builtin_variable(compiler, builtin, storage_class, 0); - - write_mask = vkd3d_write_mask_from_component_count(builtin->component_count); - vkd3d_symbol_set_register_info(®_symbol, id, - storage_class, builtin->component_type, write_mask); - reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size; - spirv_compiler_put_symbol(compiler, ®_symbol); - spirv_compiler_emit_register_execution_mode(compiler, reg->type); - spirv_compiler_emit_register_debug_name(builder, id, reg); -} - static unsigned int get_shader_output_swizzle(const struct spirv_compiler *compiler, unsigned int register_idx) { diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 8ac035d2f..1dbd91cd5 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1023,6 +1023,20 @@ static inline bool vsir_register_is_descriptor(const struct vkd3d_shader_registe } } +static inline enum vkd3d_shader_register_type vsir_register_type_from_sysval_input( + enum vkd3d_shader_sysval_semantic sysval) +{ + switch (sysval) + { + case VKD3D_SHADER_SV_PRIMITIVE_ID: + return VKD3DSPR_PRIMID; + case VKD3D_SHADER_SV_COVERAGE: + return VKD3DSPR_COVERAGE; + default: + return VKD3DSPR_INPUT; + } +} + struct vkd3d_shader_dst_param { struct vkd3d_shader_register reg;