This is required by https://bugs.winehq.org/show_bug.cgi?id=54660 .
-- v2: vkd3d-shader/hlsl: Error out when a semantic is used with multiple types. vkd3d-shader/hlsl: Error out when an output semantic is used more than once. vkd3d-shader/hlsl: Don't create semantic vars more than once. vkd3d-shader/hlsl: Report missing semantics in struct fields. vkd3d-shader/hlsl: Move get_array_size() and get_array_type() to hlsl.c. vkd3d-shader/hlsl: Support semantics for array types. tests: Test array types with semantics.
From: Francisco Casas fcasas@codeweavers.com
--- tests/shader_runner.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 9922496b..680a2856 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1026,6 +1026,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o else if (!strcmp(line, "[vertex shader]\n")) { state = STATE_SHADER_VERTEX; + expect_hr = S_OK; } else if (!strcmp(line, "[input layout]\n")) {
From: Francisco Casas fcasas@codeweavers.com
--- tests/shader_runner.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 680a2856..da5548bc 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -87,6 +87,7 @@ enum parse_state STATE_SHADER_PIXEL, STATE_SHADER_PIXEL_TODO, STATE_SHADER_VERTEX, + STATE_SHADER_VERTEX_TODO, STATE_TEST, };
@@ -824,7 +825,9 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o break;
case STATE_SHADER_VERTEX: - compile_shader(runner, shader_source, shader_source_len, "vs", expect_hr); + case STATE_SHADER_VERTEX_TODO: + todo_if (state == STATE_SHADER_VERTEX_TODO) + compile_shader(runner, shader_source, shader_source_len, "vs", expect_hr); free(runner->vs_source); runner->vs_source = shader_source; shader_source = NULL; @@ -1028,6 +1031,21 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o state = STATE_SHADER_VERTEX; expect_hr = S_OK; } + else if (!strcmp(line, "[vertex shader todo]\n")) + { + state = STATE_SHADER_VERTEX_TODO; + expect_hr = S_OK; + } + else if (!strcmp(line, "[vertex shader fail]\n")) + { + state = STATE_SHADER_VERTEX; + expect_hr = E_FAIL; + } + else if (!strcmp(line, "[vertex shader fail todo]\n")) + { + state = STATE_SHADER_VERTEX_TODO; + expect_hr = E_FAIL; + } else if (!strcmp(line, "[input layout]\n")) { state = STATE_INPUT_LAYOUT; @@ -1058,6 +1076,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_o case STATE_SHADER_PIXEL: case STATE_SHADER_PIXEL_TODO: case STATE_SHADER_VERTEX: + case STATE_SHADER_VERTEX_TODO: { size_t len = strlen(line);
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl_codegen.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 5d7e426f..e250dd0b 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -263,6 +263,16 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct struct hlsl_ir_var *var = lhs->src.var; unsigned int i;
+ if (type->class > HLSL_CLASS_LAST_NUMERIC) + { + struct vkd3d_string_buffer *string; + if (!(string = hlsl_type_to_string(ctx, type))) + return; + hlsl_fixme(ctx, &var->loc, "Input semantics for type %s.", string->buffer); + hlsl_release_string_buffer(ctx, string); + return; + } + vector_type = hlsl_get_vector_type(ctx, type->base_type, hlsl_type_minor_size(type));
for (i = 0; i < hlsl_type_major_size(type); ++i) @@ -358,6 +368,16 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct struct hlsl_ir_var *var = rhs->src.var; unsigned int i;
+ if (type->class > HLSL_CLASS_LAST_NUMERIC) + { + struct vkd3d_string_buffer *string; + if (!(string = hlsl_type_to_string(ctx, type))) + return; + hlsl_fixme(ctx, &var->loc, "Output semantics for type %s.", string->buffer); + hlsl_release_string_buffer(ctx, string); + return; + } + vector_type = hlsl_get_vector_type(ctx, type->base_type, hlsl_type_minor_size(type));
for (i = 0; i < hlsl_type_major_size(type); ++i)
From: Francisco Casas fcasas@codeweavers.com
--- tests/entry-point-semantics.shader_test | 240 ++++++++++++++++++++++++ 1 file changed, 240 insertions(+)
diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index a32a0e7b..e1080955 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -50,3 +50,243 @@ float4 main(float tex : bogus) : bogus; [test] draw quad probe (0, 0) rgba (0.2, 0.2, 0.2, 0.2) + +[vertex shader todo] +void main(out float2 tex[4] : texcoord, inout float4 pos : sv_position) +{ + tex[0] = float2(1.0, 2.0); + tex[1] = float2(3.0, 4.0); + tex[2] = float2(5.0, 6.0); + tex[3] = float2(7.0, 8.0); +} + + +% Array parameters of non-struct elements must have a semantic. +[pixel shader fail] +float4 main(in float2 arr[2]) : sv_target +{ + return 0.0; +} + + +% Array elements with a semantic get successive indexes. +[pixel shader todo] +struct apple +{ + float2 tp[4] : TEXCOORD0; +}; + +float4 main(in apple a) : sv_target +{ + return float4(a.tp[0].x, a.tp[1].x, a.tp[2].x, a.tp[3].x); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (1.0, 3.0, 5.0, 7.0) + + +% Arrays of matrices get successive indexes. +[pixel shader todo] +struct apple +{ + float2x2 tp[2] : TEXCOORD0; +}; + +float4 main(in apple a) : sv_target +{ + return float4(a.tp[0][0].x, a.tp[0][1].x, a.tp[1][0].x, a.tp[1][1].x); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (1.0, 2.0, 5.0, 6.0) + + +% Arrays (even multi-dimensional) of struct elements are allowed. The fields in the different struct +% elements get the same indexes. +[pixel shader todo] +struct apple { + float2 texcoord : TEXCOORD0; + float4 arb : UNUSED; +}; + +float4 main(in apple aps[2][2]) : sv_target +{ + return float4(aps[0][0].texcoord, aps[1][1].texcoord); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0) + + +[pixel shader todo] +struct apple { + float2 texcoord : TEXCOORD0; +}; + +struct banana { + apple apl; + float4 arb : UNUSED; +}; + +float4 main(in banana bans[2]) : sv_target +{ + return float4(bans[0].apl.texcoord, bans[1].apl.texcoord); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0) + + +% Arguments with the same semantic aren't aliased. +[pixel shader] +float4 main(in float2 t1 : TEXCOORD0, in float2 t2 : TEXCOORD0) : sv_target +{ + t1 = float2(10, 20); + return float4(t1, t2); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (10.0, 20.0, 1.0, 2.0) + + +[pixel shader fail] +struct apple { + float2 miss; // missing semantic. +}; + +struct banana { + apple apl[2]; + float4 arb : UNUSED; +}; + +float4 main(in banana bans[2]) : sv_target +{ + return 0.0; +} + + +% Different indexes of the same semantic can have different types. +[pixel shader] +float4 main(in float2 a : TEXCOORD0, in float b : TEXCOORD1) : sv_target +{ + return float4(a, b, 0); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (1.0, 2.0, 3.0, 0.0) + + +% Duplicated input semantics can only have different types if they have the same layout and register types. +[pixel shader fail todo] +float4 main(in float2 a : TEXCOORD0, in float3 b : TEXCOORD0) : sv_target +{ + return 0.0; +} + + +[pixel shader fail todo] +float4 main(in float2 a : TEXCOORD0, in int2 b : TEXCOORD0) : sv_target +{ + return 0.0; +} + + +[pixel shader] +float4 main(in float2 a : TEXCOORD0, in half2 b : TEXCOORD0, in float2x1 c: TEXCOORD0) : sv_target +{ + return 0.0; +} + + +[pixel shader] +float4 main(in uint2 a : TEXCOORD0, in int2 b : TEXCOORD0, in int2x1 c : TEXCOORD0, in bool2 d : TEXCOORD0) : sv_target +{ + return 0.0; +} + + +% For some reason, vectors from row_major matrices are not considered has having the same layout as +% regular vectors. +[pixel shader fail todo] +float4 main(in float2 a : TEXCOORD0, row_major float1x2 b : TEXCOORD0) : sv_target +{ + return 0.0; +} + +[pixel shader fail todo] +float4 main(in float2 a : TEXCOORD0, row_major float2x1 b : TEXCOORD0) : sv_target +{ + return 0.0; +} + +[pixel shader fail todo] +float4 main(in float4 a : TEXCOORD0, row_major float1x4 b : TEXCOORD0) : sv_target +{ + return 0.0; +} + + +[vertex shader fail] +struct apple { + float2 miss; // missing semantic. +}; + +struct banana { + apple apl[2]; + float4 arb : UNUSED; +}; + +void main(out banana bans[2]) +{ + return 0.0; +} + + +% Output semantics cannot be mapped to more than one value. +[vertex shader fail] +struct apple { + float2 tex : TEXCOORD0; +}; + +void main(out apple apls[2], inout float4 pos : sv_position) +{ + apls[0].tex = float2(1, 2); + apls[1].tex = float2(3, 4); +} + + +% Semantic names are case-insensitive. +[vertex shader fail todo] +void main(out float2 a : sem0, out float2 b : SEM, inout float4 pos : sv_position) +{ + a = float2(1, 2); + b = float2(3, 4); +} + + +[vertex shader todo] +struct apple { + float2 tex[2] : TEXCOORD0; +}; + +void main(out apple apl, inout float4 pos : sv_position) +{ + apl.tex[0] = float2(1, 2); + apl.tex[1] = float2(10, 20); +} + +[pixel shader] +float4 main(in float2 tex0 : TEXCOORD0, in float2 tex1 : TEXCOORD1) : sv_target +{ + return float4(tex0, tex1); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0)
From: Francisco Casas fcasas@codeweavers.com
Errors lose precision on which part of the variable is missing the semantics, but this will be fixed in a couple of commits ahead. --- libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl_codegen.c | 169 ++++++++++++------------ tests/entry-point-semantics.shader_test | 36 ++--- 3 files changed, 102 insertions(+), 104 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 38a7715e..1b8a2f55 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -392,6 +392,7 @@ struct hlsl_ir_var uint32_t is_output_semantic : 1; uint32_t is_uniform : 1; uint32_t is_param : 1; + uint32_t is_missing_semantics : 1; };
/* Sized array of variables representing a function's parameters. */ diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index e250dd0b..479abc1d 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -257,12 +257,42 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir }
static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *lhs, - unsigned int modifiers, const struct hlsl_semantic *semantic) + unsigned int modifiers, struct hlsl_semantic *semantic) { struct hlsl_type *type = lhs->node.data_type, *vector_type; struct hlsl_ir_var *var = lhs->src.var; + struct hlsl_ir_constant *c; unsigned int i;
+ if (type->class == HLSL_CLASS_ARRAY || type->class == HLSL_CLASS_STRUCT) + { + struct hlsl_semantic field_semantic_copy; + struct hlsl_ir_load *element_load; + struct hlsl_struct_field *field; + + for (i = 0; i < hlsl_type_element_count(type); ++i) + { + if (type->class == HLSL_CLASS_STRUCT) + { + field = &type->e.record.fields[i]; + field_semantic_copy = field->semantic; + semantic = &field_semantic_copy; + } + + if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) + return; + list_add_after(&lhs->node.entry, &c->node.entry); + + /* This redundant load is expected to be deleted later by DCE. */ + if (!(element_load = hlsl_new_load_index(ctx, &lhs->src, &c->node, &var->loc))) + return; + list_add_after(&c->node.entry, &element_load->node.entry); + + prepend_input_copy(ctx, instrs, element_load, modifiers, semantic); + } + return; + } + if (type->class > HLSL_CLASS_LAST_NUMERIC) { struct vkd3d_string_buffer *string; @@ -270,6 +300,10 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct return; hlsl_fixme(ctx, &var->loc, "Input semantics for type %s.", string->buffer); hlsl_release_string_buffer(ctx, string); + } + if (!semantic->name) + { + var->is_missing_semantics = 1; return; }
@@ -277,16 +311,13 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
for (i = 0; i < hlsl_type_major_size(type); ++i) { - struct hlsl_semantic semantic_copy = *semantic; struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; struct hlsl_ir_var *input; struct hlsl_ir_load *load;
- semantic_copy.index = semantic->index + i; - - if (!(input = add_semantic_var(ctx, var, vector_type, modifiers, &semantic_copy, false))) + if (!(input = add_semantic_var(ctx, var, vector_type, modifiers, semantic, false))) return; + semantic->index += 1;
if (!(load = hlsl_new_var_load(ctx, input, var->loc))) return; @@ -313,41 +344,11 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct } }
-static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *lhs) -{ - struct hlsl_type *type = lhs->node.data_type; - struct hlsl_ir_var *var = lhs->src.var; - size_t i; - - for (i = 0; i < type->e.record.field_count; ++i) - { - const struct hlsl_struct_field *field = &type->e.record.fields[i]; - struct hlsl_ir_load *field_load; - struct hlsl_ir_constant *c; - - if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) - return; - list_add_after(&lhs->node.entry, &c->node.entry); - - /* This redundant load is expected to be deleted later by DCE. */ - if (!(field_load = hlsl_new_load_index(ctx, &lhs->src, &c->node, &var->loc))) - return; - list_add_after(&c->node.entry, &field_load->node.entry); - - if (field->type->class == HLSL_CLASS_STRUCT) - prepend_input_struct_copy(ctx, instrs, field_load); - else if (field->semantic.name) - prepend_input_copy(ctx, instrs, field_load, field->storage_modifiers, &field->semantic); - else - hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, - "Field '%s' is missing a semantic.", field->name); - } -} - /* Split inputs into two variables representing the semantic and temp registers, * and copy the former to the latter, so that writes to input variables work. */ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) { + struct hlsl_semantic semantic_copy = var->semantic; struct hlsl_ir_load *load;
/* This redundant load is expected to be deleted later by DCE. */ @@ -355,19 +356,45 @@ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st return; list_add_head(instrs, &load->node.entry);
- if (var->data_type->class == HLSL_CLASS_STRUCT) - prepend_input_struct_copy(ctx, instrs, load); - else if (var->semantic.name) - prepend_input_copy(ctx, instrs, load, var->storage_modifiers, &var->semantic); + prepend_input_copy(ctx, instrs, load, var->storage_modifiers, &semantic_copy); }
static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *rhs, - unsigned int modifiers, const struct hlsl_semantic *semantic) + unsigned int modifiers, struct hlsl_semantic *semantic) { struct hlsl_type *type = rhs->node.data_type, *vector_type; struct hlsl_ir_var *var = rhs->src.var; + struct hlsl_ir_constant *c; unsigned int i;
+ if (type->class == HLSL_CLASS_ARRAY || type->class == HLSL_CLASS_STRUCT) + { + struct hlsl_semantic field_semantic_copy; + struct hlsl_ir_load *element_load; + struct hlsl_struct_field *field; + + for (i = 0; i < hlsl_type_element_count(type); ++i) + { + if (type->class == HLSL_CLASS_STRUCT) + { + field = &type->e.record.fields[i]; + field_semantic_copy = field->semantic; + semantic = &field_semantic_copy; + } + + if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) + return; + list_add_tail(instrs, &c->node.entry); + + if (!(element_load = hlsl_new_load_index(ctx, &rhs->src, &c->node, &var->loc))) + return; + list_add_tail(instrs, &element_load->node.entry); + + append_output_copy(ctx, instrs, element_load, modifiers, semantic); + } + return; + } + if (type->class > HLSL_CLASS_LAST_NUMERIC) { struct vkd3d_string_buffer *string; @@ -375,6 +402,10 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct return; hlsl_fixme(ctx, &var->loc, "Output semantics for type %s.", string->buffer); hlsl_release_string_buffer(ctx, string); + } + if (!semantic->name) + { + var->is_missing_semantics = 1; return; }
@@ -382,16 +413,13 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
for (i = 0; i < hlsl_type_major_size(type); ++i) { - struct hlsl_semantic semantic_copy = *semantic; struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; struct hlsl_ir_var *output; struct hlsl_ir_load *load;
- semantic_copy.index = semantic->index + i; - - if (!(output = add_semantic_var(ctx, var, vector_type, modifiers, &semantic_copy, true))) + if (!(output = add_semantic_var(ctx, var, vector_type, modifiers, semantic, true))) return; + semantic->index += 1;
if (type->class == HLSL_CLASS_MATRIX) { @@ -418,42 +446,12 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct } }
-static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *rhs) -{ - struct hlsl_type *type = rhs->node.data_type; - struct hlsl_ir_var *var = rhs->src.var; - size_t i; - - for (i = 0; i < type->e.record.field_count; ++i) - { - const struct hlsl_struct_field *field = &type->e.record.fields[i]; - struct hlsl_ir_load *field_load; - struct hlsl_ir_constant *c; - - if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) - return; - list_add_tail(instrs, &c->node.entry); - - /* This redundant load is expected to be deleted later by DCE. */ - if (!(field_load = hlsl_new_load_index(ctx, &rhs->src, &c->node, &var->loc))) - return; - list_add_tail(instrs, &field_load->node.entry); - - if (field->type->class == HLSL_CLASS_STRUCT) - append_output_struct_copy(ctx, instrs, field_load); - else if (field->semantic.name) - append_output_copy(ctx, instrs, field_load, field->storage_modifiers, &field->semantic); - else - hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, - "Field '%s' is missing a semantic.", field->name); - } -} - /* Split outputs into two variables representing the temp and semantic * registers, and copy the former to the latter, so that reads from output * variables work. */ static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) { + struct hlsl_semantic semantic_copy = var->semantic; struct hlsl_ir_load *load;
/* This redundant load is expected to be deleted later by DCE. */ @@ -461,10 +459,7 @@ static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st return; list_add_tail(instrs, &load->node.entry);
- if (var->data_type->class == HLSL_CLASS_STRUCT) - append_output_struct_copy(ctx, instrs, load); - else if (var->semantic.name) - append_output_copy(ctx, instrs, load, var->storage_modifiers, &var->semantic); + append_output_copy(ctx, instrs, load, var->storage_modifiers, &semantic_copy); }
static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), @@ -3402,14 +3397,16 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry } else { - if (var->data_type->class != HLSL_CLASS_STRUCT && !var->semantic.name) - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, - "Parameter "%s" is missing a semantic.", var->name); - if (var->storage_modifiers & HLSL_STORAGE_IN) prepend_input_var_copy(ctx, &body->instrs, var); if (var->storage_modifiers & HLSL_STORAGE_OUT) append_output_var_copy(ctx, &body->instrs, var); + + if (var->is_missing_semantics) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, + "Parameter "%s" is missing semantics.", var->name); + } } } if (entry_func->return_var) diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index e1080955..460e64b2 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -51,7 +51,7 @@ float4 main(float tex : bogus) : bogus; draw quad probe (0, 0) rgba (0.2, 0.2, 0.2, 0.2)
-[vertex shader todo] +[vertex shader] void main(out float2 tex[4] : texcoord, inout float4 pos : sv_position) { tex[0] = float2(1.0, 2.0); @@ -70,7 +70,7 @@ float4 main(in float2 arr[2]) : sv_target
% Array elements with a semantic get successive indexes. -[pixel shader todo] +[pixel shader] struct apple { float2 tp[4] : TEXCOORD0; @@ -82,12 +82,12 @@ float4 main(in apple a) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (1.0, 3.0, 5.0, 7.0) +draw quad +probe (0, 0) rgba (1.0, 3.0, 5.0, 7.0)
% Arrays of matrices get successive indexes. -[pixel shader todo] +[pixel shader] struct apple { float2x2 tp[2] : TEXCOORD0; @@ -99,13 +99,13 @@ float4 main(in apple a) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (1.0, 2.0, 5.0, 6.0) +draw quad +probe (0, 0) rgba (1.0, 2.0, 5.0, 6.0)
% Arrays (even multi-dimensional) of struct elements are allowed. The fields in the different struct % elements get the same indexes. -[pixel shader todo] +[pixel shader] struct apple { float2 texcoord : TEXCOORD0; float4 arb : UNUSED; @@ -117,11 +117,11 @@ float4 main(in apple aps[2][2]) : sv_target }
[test] -todo draw quad +draw quad todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0)
-[pixel shader todo] +[pixel shader] struct apple { float2 texcoord : TEXCOORD0; }; @@ -137,7 +137,7 @@ float4 main(in banana bans[2]) : sv_target }
[test] -todo draw quad +draw quad todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0)
@@ -150,7 +150,7 @@ float4 main(in float2 t1 : TEXCOORD0, in float2 t2 : TEXCOORD0) : sv_target }
[test] -todo draw quad +draw quad todo probe (0, 0) rgba (10.0, 20.0, 1.0, 2.0)
@@ -178,8 +178,8 @@ float4 main(in float2 a : TEXCOORD0, in float b : TEXCOORD1) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (1.0, 2.0, 3.0, 0.0) +draw quad +probe (0, 0) rgba (1.0, 2.0, 3.0, 0.0)
% Duplicated input semantics can only have different types if they have the same layout and register types. @@ -249,7 +249,7 @@ void main(out banana bans[2])
% Output semantics cannot be mapped to more than one value. -[vertex shader fail] +[vertex shader fail todo] struct apple { float2 tex : TEXCOORD0; }; @@ -270,7 +270,7 @@ void main(out float2 a : sem0, out float2 b : SEM, inout float4 pos : sv_positio }
-[vertex shader todo] +[vertex shader] struct apple { float2 tex[2] : TEXCOORD0; }; @@ -288,5 +288,5 @@ float4 main(in float2 tex0 : TEXCOORD0, in float2 tex1 : TEXCOORD1) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0) +draw quad +probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0)
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.c | 23 +++++++++++++++-------- libs/vkd3d-shader/hlsl.h | 3 +++ libs/vkd3d-shader/hlsl_sm1.c | 18 ++---------------- libs/vkd3d-shader/hlsl_sm4.c | 18 ++---------------- 4 files changed, 22 insertions(+), 40 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 6d015c20..427c113e 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -157,13 +157,6 @@ unsigned int hlsl_type_element_count(const struct hlsl_type *type) } }
-static unsigned int get_array_size(const struct hlsl_type *type) -{ - if (type->class == HLSL_CLASS_ARRAY) - return get_array_size(type->e.array.type) * type->e.array.elements_count; - return 1; -} - bool hlsl_type_is_resource(const struct hlsl_type *type) { if (type->class == HLSL_CLASS_OBJECT) @@ -278,7 +271,7 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type type->reg_size[k] += field->type->reg_size[k]; }
- type->dimx += field->type->dimx * field->type->dimy * get_array_size(field->type); + type->dimx += field->type->dimx * field->type->dimy * hlsl_get_multiarray_size(field->type); } break; } @@ -757,6 +750,20 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2 return true; }
+const struct hlsl_type *hlsl_get_multiarray_type(const struct hlsl_type *type) +{ + if (type->class == HLSL_CLASS_ARRAY) + return hlsl_get_multiarray_type(type->e.array.type); + return type; +} + +unsigned int hlsl_get_multiarray_size(const struct hlsl_type *type) +{ + if (type->class == HLSL_CLASS_ARRAY) + return hlsl_get_multiarray_size(type->e.array.type) * type->e.array.elements_count; + return 1; +} + struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, unsigned int default_majority, unsigned int modifiers) { diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 1b8a2f55..b3092550 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1109,6 +1109,9 @@ enum hlsl_regset hlsl_type_get_regset(const struct hlsl_type *type); unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset); bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2);
+const struct hlsl_type *hlsl_get_multiarray_type(const struct hlsl_type *type); +unsigned int hlsl_get_multiarray_size(const struct hlsl_type *type); + unsigned int hlsl_combine_swizzles(unsigned int first, unsigned int second, unsigned int dim); unsigned int hlsl_combine_writemasks(unsigned int first, unsigned int second); unsigned int hlsl_map_swizzle(unsigned int swizzle, unsigned int writemask); diff --git a/libs/vkd3d-shader/hlsl_sm1.c b/libs/vkd3d-shader/hlsl_sm1.c index be32c8db..a3e9e779 100644 --- a/libs/vkd3d-shader/hlsl_sm1.c +++ b/libs/vkd3d-shader/hlsl_sm1.c @@ -224,24 +224,10 @@ static D3DXPARAMETER_TYPE sm1_base_type(const struct hlsl_type *type) } }
-static const struct hlsl_type *get_array_type(const struct hlsl_type *type) -{ - if (type->class == HLSL_CLASS_ARRAY) - return get_array_type(type->e.array.type); - return type; -} - -static unsigned int get_array_size(const struct hlsl_type *type) -{ - if (type->class == HLSL_CLASS_ARRAY) - return get_array_size(type->e.array.type) * type->e.array.elements_count; - return 1; -} - static void write_sm1_type(struct vkd3d_bytecode_buffer *buffer, struct hlsl_type *type, unsigned int ctab_start) { - const struct hlsl_type *array_type = get_array_type(type); - unsigned int array_size = get_array_size(type); + const struct hlsl_type *array_type = hlsl_get_multiarray_type(type); + unsigned int array_size = hlsl_get_multiarray_size(type); unsigned int field_count = 0; size_t fields_offset = 0; size_t i; diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c index 8551cfd8..a8f30eb2 100644 --- a/libs/vkd3d-shader/hlsl_sm4.c +++ b/libs/vkd3d-shader/hlsl_sm4.c @@ -255,20 +255,6 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, dxbc_writer_add_section(dxbc, output ? TAG_OSGN : TAG_ISGN, buffer.data, buffer.size); }
-static const struct hlsl_type *get_array_type(const struct hlsl_type *type) -{ - if (type->class == HLSL_CLASS_ARRAY) - return get_array_type(type->e.array.type); - return type; -} - -static unsigned int get_array_size(const struct hlsl_type *type) -{ - if (type->class == HLSL_CLASS_ARRAY) - return get_array_size(type->e.array.type) * type->e.array.elements_count; - return 1; -} - static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type) { switch (type->class) @@ -359,7 +345,7 @@ static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type)
static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, struct hlsl_type *type) { - const struct hlsl_type *array_type = get_array_type(type); + const struct hlsl_type *array_type = hlsl_get_multiarray_type(type); const char *name = array_type->name ? array_type->name : "<unnamed>"; const struct hlsl_profile_info *profile = ctx->profile; unsigned int field_count = 0, array_size = 0; @@ -373,7 +359,7 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b name_offset = put_string(buffer, name);
if (type->class == HLSL_CLASS_ARRAY) - array_size = get_array_size(type); + array_size = hlsl_get_multiarray_size(type);
if (array_type->class == HLSL_CLASS_STRUCT) {
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.h | 2 ++ libs/vkd3d-shader/hlsl_codegen.c | 13 +++++++++++++ 2 files changed, 15 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index b3092550..1ec802ea 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -226,6 +226,8 @@ struct hlsl_struct_field
/* Offset where the field name starts in the output bytecode, in bytes. */ size_t name_bytecode_offset; + + bool is_missing_semantic; };
/* Information of the register allocated for an instruction node or variable. diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 479abc1d..82ac2b98 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -221,6 +221,17 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct list *instrs, stru list_add_after(&load->node.entry, &store->node.entry); }
+static void validate_field_semantic(struct hlsl_ctx *ctx, struct hlsl_struct_field *field) +{ + if (!field->semantic.name && hlsl_get_multiarray_type(field->type)->class <= HLSL_CLASS_LAST_NUMERIC + && !field->is_missing_semantic) + { + hlsl_note(ctx, &field->loc, VKD3D_SHADER_LOG_ERROR, + "Field '%s' is missing a semantic.", field->name); + field->is_missing_semantic = true; + } +} + static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, struct hlsl_type *type, unsigned int modifiers, const struct hlsl_semantic *semantic, bool output) { @@ -275,6 +286,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct if (type->class == HLSL_CLASS_STRUCT) { field = &type->e.record.fields[i]; + validate_field_semantic(ctx, field); field_semantic_copy = field->semantic; semantic = &field_semantic_copy; } @@ -378,6 +390,7 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct if (type->class == HLSL_CLASS_STRUCT) { field = &type->e.record.fields[i]; + validate_field_semantic(ctx, field); field_semantic_copy = field->semantic; semantic = &field_semantic_copy; }
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl_codegen.c | 10 ++++++++++ tests/entry-point-semantics.shader_test | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 82ac2b98..8991e9f0 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -242,6 +242,16 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir if (!(name = hlsl_get_string_buffer(ctx))) return NULL; vkd3d_string_buffer_printf(name, "<%s-%s%u>", output ? "output" : "input", semantic->name, semantic->index); + + LIST_FOR_EACH_ENTRY(ext_var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) + { + if (!strcmp(ext_var->name, name->buffer)) + { + hlsl_release_string_buffer(ctx, name); + return ext_var; + } + } + if (!(new_semantic.name = hlsl_strdup(ctx, semantic->name))) { hlsl_release_string_buffer(ctx, name); diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index 460e64b2..cb565b00 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -118,7 +118,7 @@ float4 main(in apple aps[2][2]) : sv_target
[test] draw quad -todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0) +probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0)
[pixel shader] @@ -138,7 +138,7 @@ float4 main(in banana bans[2]) : sv_target
[test] draw quad -todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0) +probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0)
% Arguments with the same semantic aren't aliased. @@ -151,7 +151,7 @@ float4 main(in float2 t1 : TEXCOORD0, in float2 t2 : TEXCOORD0) : sv_target
[test] draw quad -todo probe (0, 0) rgba (10.0, 20.0, 1.0, 2.0) +probe (0, 0) rgba (10.0, 20.0, 1.0, 2.0)
[pixel shader fail]
From: Francisco Casas fcasas@codeweavers.com
--
v2: * Only report error once when an output semantic has been used multiple times. * Use ascii_strcasecmp() because semantic names are case-insensitive. --- libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl_codegen.c | 7 ++++++- tests/entry-point-semantics.shader_test | 4 ++-- tests/matrix-semantics.shader_test | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 1ec802ea..f4dc468f 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -395,6 +395,7 @@ struct hlsl_ir_var uint32_t is_uniform : 1; uint32_t is_param : 1; uint32_t is_missing_semantics : 1; + uint32_t semantic_has_multiple_uses : 1; };
/* Sized array of variables representing a function's parameters. */ diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 8991e9f0..47d89d53 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -245,8 +245,13 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
LIST_FOR_EACH_ENTRY(ext_var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (!strcmp(ext_var->name, name->buffer)) + if (!ascii_strcasecmp(ext_var->name, name->buffer)) { + if (output && !ext_var->semantic_has_multiple_uses) + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Output semantic "%s%u" is used multiple times.", semantic->name, semantic->index); + ext_var->semantic_has_multiple_uses = 1; + hlsl_release_string_buffer(ctx, name); return ext_var; } diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index cb565b00..c9d0d9cc 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -249,7 +249,7 @@ void main(out banana bans[2])
% Output semantics cannot be mapped to more than one value. -[vertex shader fail todo] +[vertex shader fail] struct apple { float2 tex : TEXCOORD0; }; @@ -262,7 +262,7 @@ void main(out apple apls[2], inout float4 pos : sv_position)
% Semantic names are case-insensitive. -[vertex shader fail todo] +[vertex shader fail] void main(out float2 a : sem0, out float2 b : SEM, inout float4 pos : sv_position) { a = float2(1, 2); diff --git a/tests/matrix-semantics.shader_test b/tests/matrix-semantics.shader_test index 43f467ec..b704dc1a 100644 --- a/tests/matrix-semantics.shader_test +++ b/tests/matrix-semantics.shader_test @@ -63,7 +63,7 @@ probe render target 1 all r (2.0) probe render target 2 all r (3.0) probe render target 3 all r (4.0)
-[pixel shader fail todo] +[pixel shader fail] void main(out float1x2 x : sv_target0, out float1x2 y : sv_target1) { x = float2(1.0, 2.0);
On Mon Apr 10 22:09:08 2023 +0000, Francisco Casas wrote:
changed this line in [version 2 of the diff](/wine/vkd3d/-/merge_requests/148/diffs?diff_id=41673&start_sha=2c82e889e565098e1bf3e9170499c055869c3dc1#3cf804f245af47d51595ff932bf817c50967eea2_359_401)
Good observation. It was possible to put everything in `prepend_input_copy()` and `append_output_copy()` and even overlap the handling of arrays with the handling of structs to avoid the boilerplate.
On Mon Apr 10 22:09:15 2023 +0000, Zebediah Figura wrote:
Errors lose precision on which part of the variable is missing the semantics, but this is necessary in order to avoid printing the same error many times, when arrays are involved. It seems that the native compiler also makes this compromise.
I think we can do better, though. We could add a bool field to struct hlsl_field denoting whether the missing-semantic warning has been reported yet, and then just do it in prepend_input_var_copy() / append_output_var_copy(). [Side note: we may want to add a helper, even though it's a one-liner, just to make sure the error messages are always in sync.]
Okay, I am reporting that as an `hlsl_note()` though, since the error will be emitted by the `if (var->is_missing_semantics)` check at the level of `hlsl_emit_bytecode()`.
It was necessary to use `get_array_type()` whose definition we have repeated in many places, so I renamed and moved it to `hlsl.c` in a new commit. Same for `get_array_size()`.
On Thu Apr 6 01:03:37 2023 +0000, Zebediah Figura wrote:
Can we hlsl_note() with the previous variable's location?
This made me realize that I am emitting this error `n - 1` times when the semantic is used `n` times. I fixed that using a new flag for the semantic variable.
Now, regarding the reporting the previous variable's location. It begs the question of what to do when there are more than 2 repetitions. If we do this, we probably would want to report all locations where the semantic is used, and also find a way of reporting when a semantic is used more than once in a single location that doesn't imply printing the location as many times as it is repeated (consider a very large array of structs with the semantic in a field).
I spent some time thinking about this, but I can't see a way that wouldn't require storing all the reported locations. So, IMO, the additional complexity doesn't overweight the benefit. But if you think that it is important enough, I will do it.
From: Francisco Casas fcasas@codeweavers.com
Considering row vectors from row_major matrices as having a different layout as regular vectors, and error out in that case, is left as todo. --- libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl_codegen.c | 27 +++++++++++++++++++++++++ tests/entry-point-semantics.shader_test | 6 +++--- 3 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index f4dc468f..a69bdbb4 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -396,6 +396,7 @@ struct hlsl_ir_var uint32_t is_param : 1; uint32_t is_missing_semantics : 1; uint32_t semantic_has_multiple_uses : 1; + uint32_t semantic_uses_have_different_types : 1; };
/* Sized array of variables representing a function's parameters. */ diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 47d89d53..2bbbebc7 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -232,6 +232,25 @@ static void validate_field_semantic(struct hlsl_ctx *ctx, struct hlsl_struct_fie } }
+static enum hlsl_base_type base_type_get_equivalent_layout(enum hlsl_base_type base) +{ + if (base == HLSL_TYPE_BOOL) + return HLSL_TYPE_UINT; + if (base == HLSL_TYPE_INT) + return HLSL_TYPE_UINT; + if (base == HLSL_TYPE_HALF) + return HLSL_TYPE_FLOAT; + return base; +} + +static bool types_have_same_layout(const struct hlsl_type *type1, const struct hlsl_type *type2) +{ + if (type1->dimx != type2->dimx) + return false; + + return base_type_get_equivalent_layout(type1->base_type) == base_type_get_equivalent_layout(type2->base_type); +} + static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, struct hlsl_type *type, unsigned int modifiers, const struct hlsl_semantic *semantic, bool output) { @@ -252,6 +271,14 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir "Output semantic "%s%u" is used multiple times.", semantic->name, semantic->index); ext_var->semantic_has_multiple_uses = 1;
+ if (!types_have_same_layout(ext_var->data_type, type) && !ext_var->semantic_uses_have_different_types) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Semantic "%s%u" is used multiple times with different layout types.", + semantic->name, semantic->index); + ext_var->semantic_uses_have_different_types = 1; + } + hlsl_release_string_buffer(ctx, name); return ext_var; } diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index c9d0d9cc..7983f309 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -183,14 +183,14 @@ probe (0, 0) rgba (1.0, 2.0, 3.0, 0.0)
% Duplicated input semantics can only have different types if they have the same layout and register types. -[pixel shader fail todo] +[pixel shader fail] float4 main(in float2 a : TEXCOORD0, in float3 b : TEXCOORD0) : sv_target { return 0.0; }
-[pixel shader fail todo] +[pixel shader fail] float4 main(in float2 a : TEXCOORD0, in int2 b : TEXCOORD0) : sv_target { return 0.0; @@ -219,7 +219,7 @@ float4 main(in float2 a : TEXCOORD0, row_major float1x2 b : TEXCOORD0) : sv_targ return 0.0; }
-[pixel shader fail todo] +[pixel shader fail] float4 main(in float2 a : TEXCOORD0, row_major float2x1 b : TEXCOORD0) : sv_target { return 0.0;
It's also legal even without using arrays, *but* only if the types match—otherwise there's an error. We could probably add some extra tests for that.
Okay. After making some tests, I concluded that some types are exchangeable and others not (uint <=> bool <=> int) and (half <=> float). I also realized that row vectors from row_major matrices aren't considered as equivalent to regular vectors, but since that case is really specific, I think we should be permissive. I left the associated tests as a `todo`.
Also a test that the variables don't really alias each other might be warranted. (I.e. assigning to one only affects that one.)
I added a test to check that arguments with the same semantic are not aliased. They have to be input arguments because duplicated output arguments are not allowed.
Okay, I am reporting that as an `hlsl_note()` though, since the error will be emitted by the `if (var->is_missing_semantics)` check at the level of `hlsl_emit_bytecode()`.
My idea was that you'd report the error in prepend_input_var_copy() or whatever, and then you don't need the is_missing_semantics error.
Now, regarding the reporting the previous variable's location. It begs the question of what to do when there are more than 2 repetitions. If we do this, we probably would want to report all locations where the semantic is used, and also find a way of reporting when a semantic is used more than once in a single location that doesn't imply printing the location as many times as it is repeated (consider a very large array of structs with the semantic in a field).
I spent some time thinking about this, but I can't see a way that wouldn't require storing all the reported locations. So, IMO, the additional complexity doesn't overweight the benefit. But if you think that it is important enough, I will do it.
I don't think you need to do that. Rather, you just want to do it like a normal redefinition error: every time there's a definition which conflicts with an earlier definition, you "note" the first earlier definition that conflicts.
I also don't see why you'd want to report the previous location more than once for an array?