This is required by https://bugs.winehq.org/show_bug.cgi?id=54660 .
-- v6: vkd3d-shader/hlsl: Consider duplicated input semantic types equivalent in SM1. vkd3d-shader/hlsl: Handle possibly different types in input semantic var load. vkd3d-shader/hlsl: Error out when a semantic is used with incompatible types. vkd3d-shader/hlsl: Error out when an output semantic is used more than once. vkd3d-shader/hlsl: Support semantics for array types. vkd3d-shader/hlsl: Don't create semantic vars more than once. vkd3d-shader/hlsl: Move get_array_size() and get_array_type() to hlsl.c. tests: Test duplicated semantics. tests: Test array types with semantics. vkd3d-shader/hlsl: Avoid invalid input/output copies for non-numeric types. tests: Allow invalid vertex shader tests. tests: Expect S_OK result on [vertex shader].
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 | 151 ++++++++++++++++++++++++ 1 file changed, 151 insertions(+)
diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index a32a0e7b..5feaf78c 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -50,3 +50,154 @@ 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 float4 tex[4] : texcoord, inout float4 pos : sv_position) +{ + tex[0] = float4(10.0, 11.0, 12.0, 13.0); + tex[1] = float4(20.0, 21.0, 22.0, 23.0); + tex[2] = float4(30.0, 31.0, 32.0, 33.0); + tex[3] = float4(40.0, 41.0, 42.0, 43.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 +{ + float3 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 (10.0, 20.0, 30.0, 40.0) + + +% Arrays of matrices get successive indexes. +[pixel shader todo] +struct apple +{ + float4x2 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 (10.0, 11.0, 30.0, 31.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 +{ + float4 texcoord : TEXCOORD0; + float4 arb : UNUSED; +}; + +float4 main(in apple aps[2][2]) : sv_target +{ + return float4(aps[0][0].texcoord.xy, aps[1][1].texcoord.xy); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (10.0, 11.0, 10.0, 11.0) + + +[pixel shader todo] +struct apple +{ + float4 texcoord : TEXCOORD0; +}; + +struct banana +{ + apple apl; + float4 arb : UNUSED; +}; + +float4 main(in banana bans[2]) : sv_target +{ + return float4(bans[0].apl.texcoord.xy, bans[1].apl.texcoord.xy); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (10.0, 11.0, 10.0, 11.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; +} + + +[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; +} + + +[vertex shader todo] +struct apple +{ + float4 tex[2] : TEXCOORD0; +}; + +void main(out apple apl, inout float4 pos : sv_position) +{ + apl.tex[0] = float4(1, 2, 3, 4); + apl.tex[1] = float4(10, 20, 30, 40); +} + +[pixel shader] +float4 main(in float4 tex0 : TEXCOORD0, in float4 tex1 : TEXCOORD1) : sv_target +{ + return float4(tex0.xy, tex1.xy); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0)
From: Francisco Casas fcasas@codeweavers.com
--- tests/entry-point-semantics.shader_test | 126 ++++++++++++++++++++++++ 1 file changed, 126 insertions(+)
diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index 5feaf78c..2f3fb04b 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -201,3 +201,129 @@ float4 main(in float4 tex0 : TEXCOORD0, in float4 tex1 : TEXCOORD1) : sv_target [test] todo draw quad todo probe (0, 0) rgba (1.0, 2.0, 10.0, 20.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); +} + + +[vertex shader fail todo] +struct apple +{ + float2 f : SEMANTIC; +}; + +void main(out apple a, out apple b, inout float4 pos : sv_position) +{ + a.f = float2(1, 2); + b.f = 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] +void main(out float4 tex[4] : texcoord, inout float4 pos : sv_position) +{ + tex[0] = float4(10.0, 11.0, 12.0, 13.0); + tex[1] = float4(20.0, 21.0, 22.0, 23.0); + tex[2] = float4(30.0, 31.0, 32.0, 33.0); + tex[3] = float4(40.0, 41.0, 42.0, 43.0); +} + + +% Arguments with the same semantic aren't aliased. +[pixel shader] +float4 main(in float4 t1 : TEXCOORD0, in float4 t2 : TEXCOORD0) : sv_target +{ + t1 = 99; + return float4(t1.xy, t2.xy); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (99.0, 99.0, 10.0, 11.0) + + +% Different indexes of the same semantic can have different types. +[pixel shader] +float4 main(in float4 a : TEXCOORD0, in float3 b : TEXCOORD1) : sv_target +{ + return float4(a.xy, b.xy); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0) + + +% In SM4, duplicated input semantics can only have different types if they have the same layout and +% register types. SM1 is permissive in this regard. +[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; +} + + +[require] +shader model >= 4.0 + + +[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; +} + + +% For some reason, vectors from row_major matrices are not considered as 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; +}
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..bc411075 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_element_type(const struct hlsl_type *type) +{ + if (type->class == HLSL_CLASS_ARRAY) + return hlsl_get_multiarray_element_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 38a7715e..7acbb1e7 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1108,6 +1108,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_element_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..4ef01f99 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_element_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..5c900f90 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_element_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_codegen.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index e250dd0b..4e4ae632 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -231,6 +231,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 (!ascii_strcasecmp(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);
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl.h | 3 + libs/vkd3d-shader/hlsl.y | 7 +- libs/vkd3d-shader/hlsl_codegen.c | 191 +++++++++++++----------- tests/entry-point-semantics.shader_test | 44 +++--- 4 files changed, 131 insertions(+), 114 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 7acbb1e7..b45cd0ae 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -207,6 +207,9 @@ struct hlsl_semantic { const char *name; uint32_t index; + + /* If the variable or field that stores this hlsl_semantic has already reported that it is missing. */ + bool reported_missing; };
/* A field within a struct type declaration, used in hlsl_type.e.fields. */ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 79ec970a..27594ebe 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4545,7 +4545,7 @@ var_identifier: colon_attribute: %empty { - $$.semantic.name = NULL; + $$.semantic = (struct hlsl_semantic){0}; $$.reg_reservation.reg_type = 0; $$.reg_reservation.offset_type = 0; } @@ -4557,12 +4557,12 @@ colon_attribute: } | register_opt { - $$.semantic.name = NULL; + $$.semantic = (struct hlsl_semantic){0}; $$.reg_reservation = $1; } | packoffset_opt { - $$.semantic.name = NULL; + $$.semantic = (struct hlsl_semantic){0}; $$.reg_reservation = $1; }
@@ -4575,6 +4575,7 @@ semantic: ; $$.name = $2; $$.index = atoi(p); + $$.reported_missing = false; *p = 0; }
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 4e4ae632..b779fdc4 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -221,8 +221,20 @@ 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_element_type(field->type)->class <= HLSL_CLASS_LAST_NUMERIC + && !field->semantic.reported_missing) + { + hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, + "Field '%s' is missing a semantic.", field->name); + field->semantic.reported_missing = 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) + struct hlsl_type *type, unsigned int modifiers, const struct hlsl_semantic *semantic, + uint32_t index, bool output) { struct hlsl_semantic new_semantic; struct vkd3d_string_buffer *name; @@ -230,7 +242,7 @@ 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); + vkd3d_string_buffer_printf(name, "<%s-%s%u>", output ? "output" : "input", semantic->name, index);
LIST_FOR_EACH_ENTRY(ext_var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { @@ -246,7 +258,7 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir hlsl_release_string_buffer(ctx, name); return NULL; } - new_semantic.index = semantic->index; + new_semantic.index = index; if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), type, var->loc, &new_semantic, modifiers, NULL))) { @@ -267,12 +279,48 @@ 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, const struct hlsl_semantic *semantic, uint32_t semantic_index) { 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_ir_load *element_load; + struct hlsl_struct_field *field; + uint32_t elem_semantic_index; + + for (i = 0; i < hlsl_type_element_count(type); ++i) + { + if (type->class == HLSL_CLASS_ARRAY) + { + elem_semantic_index = semantic_index + + i * hlsl_type_get_array_element_reg_size(type->e.array.type, HLSL_REGSET_NUMERIC) / 4; + } + else + { + field = &type->e.record.fields[i]; + validate_field_semantic(ctx, field); + semantic = &field->semantic; + elem_semantic_index = semantic->index; + } + + 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, elem_semantic_index); + } + return; + } + if (type->class > HLSL_CLASS_LAST_NUMERIC) { struct vkd3d_string_buffer *string; @@ -280,22 +328,19 @@ 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); - return; } + if (!semantic->name) + 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) { - 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, semantic_index + i, false))) return;
if (!(load = hlsl_new_var_load(ctx, input, var->loc))) @@ -323,37 +368,6 @@ 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) @@ -365,19 +379,51 @@ 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, &var->semantic, var->semantic.index); }
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, const struct hlsl_semantic *semantic, uint32_t semantic_index) { 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_ir_load *element_load; + struct hlsl_struct_field *field; + uint32_t elem_semantic_index; + + for (i = 0; i < hlsl_type_element_count(type); ++i) + { + if (type->class == HLSL_CLASS_ARRAY) + { + elem_semantic_index = semantic_index + + i * hlsl_type_get_array_element_reg_size(type->e.array.type, HLSL_REGSET_NUMERIC) / 4; + } + else + { + field = &type->e.record.fields[i]; + validate_field_semantic(ctx, field); + semantic = &field->semantic; + elem_semantic_index = semantic->index; + } + + 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, elem_semantic_index); + } + return; + } + if (type->class > HLSL_CLASS_LAST_NUMERIC) { struct vkd3d_string_buffer *string; @@ -385,22 +431,19 @@ 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); - return; } + if (!semantic->name) + 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) { - 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, semantic_index + i, true))) return;
if (type->class == HLSL_CLASS_MATRIX) @@ -428,37 +471,6 @@ 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. */ @@ -471,10 +483,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, &var->semantic, var->semantic.index); }
static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), @@ -3406,15 +3415,19 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry { var = entry_func->parameters.vars[i];
- if (var->data_type->class == HLSL_CLASS_OBJECT || (var->storage_modifiers & HLSL_STORAGE_UNIFORM)) + if (hlsl_type_is_resource(var->data_type) || (var->storage_modifiers & HLSL_STORAGE_UNIFORM)) { prepend_uniform_copy(ctx, &body->instrs, var); } else { - if (var->data_type->class != HLSL_CLASS_STRUCT && !var->semantic.name) + if (hlsl_get_multiarray_element_type(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); + var->semantic.reported_missing = true; + }
if (var->storage_modifiers & HLSL_STORAGE_IN) prepend_input_var_copy(ctx, &body->instrs, var); diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index 2f3fb04b..3785b9a5 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 float4 tex[4] : texcoord, inout float4 pos : sv_position) { tex[0] = float4(10.0, 11.0, 12.0, 13.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 { float3 tp[4] : TEXCOORD0; @@ -82,12 +82,12 @@ float4 main(in apple a) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (10.0, 20.0, 30.0, 40.0) +draw quad +probe (0, 0) rgba (10.0, 20.0, 30.0, 40.0)
% Arrays of matrices get successive indexes. -[pixel shader todo] +[pixel shader] struct apple { float4x2 tp[2] : TEXCOORD0; @@ -99,13 +99,13 @@ float4 main(in apple a) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (10.0, 11.0, 30.0, 31.0) +draw quad +probe (0, 0) rgba (10.0, 11.0, 30.0, 31.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 { float4 texcoord : TEXCOORD0; @@ -118,11 +118,11 @@ float4 main(in apple aps[2][2]) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (10.0, 11.0, 10.0, 11.0) +draw quad +probe (0, 0) rgba (10.0, 11.0, 10.0, 11.0)
-[pixel shader todo] +[pixel shader] struct apple { float4 texcoord : TEXCOORD0; @@ -140,8 +140,8 @@ float4 main(in banana bans[2]) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (10.0, 11.0, 10.0, 11.0) +draw quad +probe (0, 0) rgba (10.0, 11.0, 10.0, 11.0)
[pixel shader fail] @@ -180,7 +180,7 @@ void main(out banana bans[2]) }
-[vertex shader todo] +[vertex shader] struct apple { float4 tex[2] : TEXCOORD0; @@ -199,12 +199,12 @@ float4 main(in float4 tex0 : TEXCOORD0, in float4 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)
% Output semantics cannot be mapped to more than one value. -[vertex shader fail] +[vertex shader fail todo] struct apple { float2 tex : TEXCOORD0; @@ -239,7 +239,7 @@ void main(out float2 a : sem0, out float2 b : SEM, inout float4 pos : sv_positio }
-[vertex shader todo] +[vertex shader] void main(out float4 tex[4] : texcoord, inout float4 pos : sv_position) { tex[0] = float4(10.0, 11.0, 12.0, 13.0); @@ -258,8 +258,8 @@ float4 main(in float4 t1 : TEXCOORD0, in float4 t2 : TEXCOORD0) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (99.0, 99.0, 10.0, 11.0) +draw quad +probe (0, 0) rgba (99.0, 99.0, 10.0, 11.0)
% Different indexes of the same semantic can have different types. @@ -270,8 +270,8 @@ float4 main(in float4 a : TEXCOORD0, in float3 b : TEXCOORD1) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0) +draw quad +probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0)
% In SM4, duplicated input semantics can only have different types if they have the same layout and
From: Francisco Casas fcasas@codeweavers.com
The use of the hlsl_semantic.reported_duplicated_output_next_index field allows reporting multiple overlapping indexes, such as in the following vertex shader:
void main(out float1x3 x : OVERLAP0, out float1x3 y : OVERLAP1) { x = float3(1.0, 2.0, 3.2); y = float3(5.0, 6.0, 5.0); }
apple.hlsl:1:41: E5013: Output semantic "OVERLAP1" is used multiple times. apple.hlsl:1:13: First use of "OVERLAP1" is here. apple.hlsl:1:41: E5013: Output semantic "OVERLAP2" is used multiple times. apple.hlsl:1:13: First use of "OVERLAP2" is here.
While at the same time avoiding reporting overalps more than once for large arrays:
struct apple { float2 p : sv_position; };
void main(out apple aps[4]) { }
apple.hlsl:3:8: E5013: Output semantic "sv_position0" is used multiple times. apple.hlsl:3:8: First use of "sv_position0" is here. --- libs/vkd3d-shader/hlsl.h | 3 +++ libs/vkd3d-shader/hlsl.y | 1 + libs/vkd3d-shader/hlsl_codegen.c | 34 ++++++++++++++++++------- tests/entry-point-semantics.shader_test | 6 ++--- tests/matrix-semantics.shader_test | 2 +- 5 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index b45cd0ae..968299fb 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -210,6 +210,9 @@ struct hlsl_semantic
/* If the variable or field that stores this hlsl_semantic has already reported that it is missing. */ bool reported_missing; + /* In case the variable or field that stores this semantic has already reported to use a + * duplicated output semantic, this value stores the last reported index + 1. Otherwise it is 0. */ + uint32_t reported_duplicated_output_next_index; };
/* A field within a struct type declaration, used in hlsl_type.e.fields. */ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 27594ebe..a148d207 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4576,6 +4576,7 @@ semantic: $$.name = $2; $$.index = atoi(p); $$.reported_missing = false; + $$.reported_duplicated_output_next_index = 0; *p = 0; }
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index b779fdc4..76e9a126 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -233,8 +233,8 @@ static void validate_field_semantic(struct hlsl_ctx *ctx, struct hlsl_struct_fie }
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, - uint32_t index, bool output) + struct hlsl_type *type, unsigned int modifiers, struct hlsl_semantic *semantic, + uint32_t index, bool output, const struct vkd3d_shader_location *loc) { struct hlsl_semantic new_semantic; struct vkd3d_string_buffer *name; @@ -248,6 +248,18 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir { if (!ascii_strcasecmp(ext_var->name, name->buffer)) { + if (output) + { + if (index >= semantic->reported_duplicated_output_next_index) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Output semantic "%s%u" is used multiple times.", semantic->name, index); + hlsl_note(ctx, &ext_var->loc, HLSL_LEVEL_ERROR, + "First use of "%s%u" is here.", semantic->name, index); + semantic->reported_duplicated_output_next_index = index + 1; + } + } + hlsl_release_string_buffer(ctx, name); return ext_var; } @@ -260,7 +272,7 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir } new_semantic.index = index; if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), - type, var->loc, &new_semantic, modifiers, NULL))) + type, *loc, &new_semantic, modifiers, NULL))) { hlsl_release_string_buffer(ctx, name); hlsl_cleanup_semantic(&new_semantic); @@ -279,9 +291,10 @@ 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, uint32_t semantic_index) + unsigned int modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index) { struct hlsl_type *type = lhs->node.data_type, *vector_type; + struct vkd3d_shader_location *loc = &lhs->node.loc; struct hlsl_ir_var *var = lhs->src.var; struct hlsl_ir_constant *c; unsigned int i; @@ -305,6 +318,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct validate_field_semantic(ctx, field); semantic = &field->semantic; elem_semantic_index = semantic->index; + loc = &field->loc; }
if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) @@ -312,7 +326,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct 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))) + if (!(element_load = hlsl_new_load_index(ctx, &lhs->src, &c->node, loc))) return; list_add_after(&c->node.entry, &element_load->node.entry);
@@ -340,7 +354,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct struct hlsl_ir_var *input; struct hlsl_ir_load *load;
- if (!(input = add_semantic_var(ctx, var, vector_type, modifiers, semantic, semantic_index + i, false))) + if (!(input = add_semantic_var(ctx, var, vector_type, modifiers, semantic, semantic_index + i, false, loc))) return;
if (!(load = hlsl_new_var_load(ctx, input, var->loc))) @@ -383,9 +397,10 @@ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st }
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, uint32_t semantic_index) + unsigned int modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index) { struct hlsl_type *type = rhs->node.data_type, *vector_type; + struct vkd3d_shader_location *loc = &rhs->node.loc; struct hlsl_ir_var *var = rhs->src.var; struct hlsl_ir_constant *c; unsigned int i; @@ -409,13 +424,14 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct validate_field_semantic(ctx, field); semantic = &field->semantic; elem_semantic_index = semantic->index; + loc = &field->loc; }
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))) + if (!(element_load = hlsl_new_load_index(ctx, &rhs->src, &c->node, loc))) return; list_add_tail(instrs, &element_load->node.entry);
@@ -443,7 +459,7 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct struct hlsl_ir_var *output; struct hlsl_ir_load *load;
- if (!(output = add_semantic_var(ctx, var, vector_type, modifiers, semantic, semantic_index + i, true))) + if (!(output = add_semantic_var(ctx, var, vector_type, modifiers, semantic, semantic_index + i, true, loc))) return;
if (type->class == HLSL_CLASS_MATRIX) diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index 3785b9a5..935cde96 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -204,7 +204,7 @@ probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0)
% Output semantics cannot be mapped to more than one value. -[vertex shader fail todo] +[vertex shader fail] struct apple { float2 tex : TEXCOORD0; @@ -217,7 +217,7 @@ void main(out apple apls[2], inout float4 pos : sv_position) }
-[vertex shader fail todo] +[vertex shader fail] struct apple { float2 f : SEMANTIC; @@ -231,7 +231,7 @@ void main(out apple a, out apple b, 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);
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 | 4 +++ libs/vkd3d-shader/hlsl.y | 1 + libs/vkd3d-shader/hlsl_codegen.c | 34 +++++++++++++++++++++++++ tests/entry-point-semantics.shader_test | 6 ++--- 4 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 968299fb..bca05f51 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -213,6 +213,10 @@ struct hlsl_semantic /* In case the variable or field that stores this semantic has already reported to use a * duplicated output semantic, this value stores the last reported index + 1. Otherwise it is 0. */ uint32_t reported_duplicated_output_next_index; + /* In case the variable or field that stores this semantic has already reported to use a + * duplicated input semantic with incompatible values, this value stores the last reported + * index + 1. Otherwise it is 0. */ + uint32_t reported_duplicated_input_incompatible_next_index; };
/* A field within a struct type declaration, used in hlsl_type.e.fields. */ diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index a148d207..dfef622c 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4577,6 +4577,7 @@ semantic: $$.index = atoi(p); $$.reported_missing = false; $$.reported_duplicated_output_next_index = 0; + $$.reported_duplicated_input_incompatible_next_index = 0; *p = 0; }
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 76e9a126..c9f5507a 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -232,6 +232,27 @@ static void validate_field_semantic(struct hlsl_ctx *ctx, struct hlsl_struct_fie } }
+static enum hlsl_base_type base_type_get_semantic_equivalent(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_are_semantic_equivalent(struct hlsl_ctx *ctx, const struct hlsl_type *type1, + const struct hlsl_type *type2) +{ + if (type1->dimx != type2->dimx) + return false; + + return base_type_get_semantic_equivalent(type1->base_type) + == base_type_get_semantic_equivalent(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, struct hlsl_semantic *semantic, uint32_t index, bool output, const struct vkd3d_shader_location *loc) @@ -259,6 +280,19 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir semantic->reported_duplicated_output_next_index = index + 1; } } + else + { + if (index >= semantic->reported_duplicated_input_incompatible_next_index + && !types_are_semantic_equivalent(ctx, ext_var->data_type, type)) + { + hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SEMANTIC, + "Input semantic "%s%u" is used multiple times with incompatible types.", + semantic->name, index); + hlsl_note(ctx, &ext_var->loc, HLSL_LEVEL_ERROR, + "First declaration of "%s%u" is here.", semantic->name, index); + semantic->reported_duplicated_input_incompatible_next_index = index + 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 935cde96..1cb42bc9 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -294,14 +294,14 @@ float4 main(in uint2 a : TEXCOORD0, in int2 b : TEXCOORD0, in int2x1 c : TEXCOOR shader model >= 4.0
-[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; @@ -316,7 +316,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;
From: Francisco Casas fcasas@codeweavers.com
Since in SM1 all vector types use 4 register components, and since SM1 doesn't consider vectors of different dimx incompatible, it is necessary to ensure that the semantic var is created with dimx=4, and to add a cast node. --- libs/vkd3d-shader/hlsl_codegen.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index c9f5507a..2f7ceac6 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -327,7 +327,7 @@ 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, struct hlsl_semantic *semantic, uint32_t semantic_index) { - struct hlsl_type *type = lhs->node.data_type, *vector_type; + struct hlsl_type *type = lhs->node.data_type, *vector_type_src, *vector_type_dst; struct vkd3d_shader_location *loc = &lhs->node.loc; struct hlsl_ir_var *var = lhs->src.var; struct hlsl_ir_constant *c; @@ -380,28 +380,36 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct if (!semantic->name) return;
- vector_type = hlsl_get_vector_type(ctx, type->base_type, hlsl_type_minor_size(type)); + vector_type_src = hlsl_get_vector_type(ctx, type->base_type, + (ctx->profile->major_version < 4) ? 4 : hlsl_type_minor_size(type)); + vector_type_dst = hlsl_get_vector_type(ctx, type->base_type, hlsl_type_minor_size(type));
for (i = 0; i < hlsl_type_major_size(type); ++i) { struct hlsl_ir_store *store; struct hlsl_ir_var *input; struct hlsl_ir_load *load; + struct hlsl_ir_expr *cast;
- if (!(input = add_semantic_var(ctx, var, vector_type, modifiers, semantic, semantic_index + i, false, loc))) + if (!(input = add_semantic_var(ctx, var, vector_type_src, modifiers, semantic, + semantic_index + i, false, loc))) return;
if (!(load = hlsl_new_var_load(ctx, input, var->loc))) return; list_add_after(&lhs->node.entry, &load->node.entry);
+ if (!(cast = hlsl_new_cast(ctx, &load->node, vector_type_dst, &var->loc))) + return; + list_add_after(&load->node.entry, &cast->node.entry); + if (type->class == HLSL_CLASS_MATRIX) { if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) return; - list_add_after(&load->node.entry, &c->node.entry); + list_add_after(&cast->node.entry, &c->node.entry);
- if (!(store = hlsl_new_store_index(ctx, &lhs->src, &c->node, &load->node, 0, &var->loc))) + if (!(store = hlsl_new_store_index(ctx, &lhs->src, &c->node, &cast->node, 0, &var->loc))) return; list_add_after(&c->node.entry, &store->node.entry); } @@ -409,9 +417,9 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct { assert(i == 0);
- if (!(store = hlsl_new_store_index(ctx, &lhs->src, NULL, &load->node, 0, &var->loc))) + if (!(store = hlsl_new_store_index(ctx, &lhs->src, NULL, &cast->node, 0, &var->loc))) return; - list_add_after(&load->node.entry, &store->node.entry); + list_add_after(&cast->node.entry, &store->node.entry); } } }
From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/hlsl_codegen.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 2f7ceac6..00a0783b 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -246,6 +246,9 @@ static enum hlsl_base_type base_type_get_semantic_equivalent(enum hlsl_base_type static bool types_are_semantic_equivalent(struct hlsl_ctx *ctx, const struct hlsl_type *type1, const struct hlsl_type *type2) { + if (ctx->profile->major_version < 4) + return true; + if (type1->dimx != type2->dimx) return false;
:arrow_up: I made all TEXCOORD semantics float4, or at least large enough so that no more than one input semantic can fit within the same register.
Now the tests should pass (could you check again @giomasce?), but we still have to address the problem of properly allocating input semantics and see if the shader runner/runtime is replicating the same behavior than native when matching vertex shader output semantics with pixel shader input semantics. I think that's better left for another MR though.
The overlapping semantics tests are failing for me on Windows, with what looks like a leaked internal compiler error code:
shader_runner:1193: Compiling shaders with d3dcompiler_47.dll and executing with d3d12.dll shader_runner:340: Adapter: ATI Radeon HD 5600 Series, 1002:68d8. shader_runner:736: Section [pixel shader fail], line 297: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 304: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 313: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 319: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 325: Test failed: Got unexpected hr 0x80010064. shader_runner:1163: d3dcompiler_47.dll version: 10.0.15063.674
On Mon Apr 17 20:55:08 2023 +0000, Zebediah Figura wrote:
The overlapping semantics tests are failing for me on Windows, with what looks like a leaked internal compiler error code: shader_runner:1193: Compiling shaders with d3dcompiler_47.dll and executing with d3d12.dll shader_runner:340: Adapter: ATI Radeon HD 5600 Series, 1002:68d8. shader_runner:736: Section [pixel shader fail], line 297: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 304: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 313: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 319: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 325: Test failed: Got unexpected hr 0x80010064. shader_runner:1163: d3dcompiler_47.dll version: 10.0.15063.674
I really hate Markdown; here's what I was trying to paste:
``` shader_runner:1193: Compiling shaders with d3dcompiler_47.dll and executing with d3d12.dll shader_runner:340: Adapter: ATI Radeon HD 5600 Series, 1002:68d8. shader_runner:736: Section [pixel shader fail], line 297: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 304: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 313: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 319: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 325: Test failed: Got unexpected hr 0x80010064. shader_runner:1163: d3dcompiler_47.dll version: 10.0.15063.674 ```
On Tue Apr 18 10:36:13 2023 +0000, Francisco Casas wrote:
:arrow_up: I made all TEXCOORD semantics float4, or at least large enough so that no more than one input semantic can fit within the same register. Now the tests should pass (could you check again @giomasce?), but we still have to address the problem of properly allocating input semantics and see if the shader runner/runtime is replicating the same behavior than native when matching vertex shader output semantics with pixel shader input semantics. I think that's better left for another MR though.
The `Got {1.00000000e+000, 2.00000000e+000, 1.00000000e+000, 1.00000000e+000}, expected {1.00000000e+000, 2.00000000e+000, 1.00000000e+001, 2.00000000e+001} at (0, 0).` tests are fixed, but as Zeb sees too the `0x80010064` errors are still there. I'm using `d3dcompiler_47.dll version: 10.0.19041.868`, which one do you have?
On Tue Apr 18 10:36:13 2023 +0000, Giovanni Mascellani wrote:
The `Got {1.00000000e+000, 2.00000000e+000, 1.00000000e+000, 1.00000000e+000}, expected {1.00000000e+000, 2.00000000e+000, 1.00000000e+001, 2.00000000e+001} at (0, 0).` tests are fixed, but as Zeb sees too the `0x80010064` errors are still there. I'm using `d3dcompiler_47.dll version: 10.0.19041.868`, which one do you have?
I have plain `10.1`.
On Mon Apr 17 20:55:07 2023 +0000, Zebediah Figura wrote:
I really hate Markdown; here's what I was trying to paste:
shader_runner:1193: Compiling shaders with d3dcompiler_47.dll and executing with d3d12.dll shader_runner:340: Adapter: ATI Radeon HD 5600 Series, 1002:68d8. shader_runner:736: Section [pixel shader fail], line 297: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 304: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 313: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail], line 319: Test failed: Got unexpected hr 0x80010064. shader_runner:736: Section [pixel shader fail todo], line 325: Test failed: Got unexpected hr 0x80010064. shader_runner:1163: d3dcompiler_47.dll version: 10.0.15063.674
Since all the unexpected hrs are on tests that are expected to fail, this just means that the native compiler is retrieving a different error code than E_FAIL for shaders with incompatible input semantics, right?
Since all the unexpected hrs are on tests that are expected to fail, this just means that the native compiler is retrieving a different error code than E_FAIL for shaders with incompatible input semantics, right?
Yes.
I'm not really sure how to deal with this. Possibly best is to just punt and keep these marked as todo. That said, if you're submitting them I assume they didn't fail for you?
I'm not really sure how to deal with this. Possibly best is to just punt and keep these marked as todo. That said, if you're submitting them I assume they didn't fail for you?
Er, no, that's not enough, because they'll still fail on Windows.
Yeah, this is awkward. It's obviously not great, but I wouldn't mind just inserting something like "if (hr == 0x80010064) hr = E_FAIL" in the shader runner for now. I don't think matching the internal error code is likely to be important.
On Tue Apr 18 23:40:31 2023 +0000, Zebediah Figura wrote:
I'm not really sure how to deal with this. Possibly best is to just
punt and keep these marked as todo. That said, if you're submitting them I assume they didn't fail for you? Er, no, that's not enough, because they'll still fail on Windows. Yeah, this is awkward. It's obviously not great, but I wouldn't mind just inserting something like "if (hr == 0x80010064) hr = E_FAIL" in the shader runner for now. I don't think matching the internal error code is likely to be important.
They pass for me on Unix.
Okay, I will add the check in the shader_runner.
Yeah, this is awkward. It's obviously not great, but I wouldn't mind just inserting something like "if (hr == 0x80010064) hr = E_FAIL" in the shader runner for now. I don't think matching the internal error code is likely to be important.
Yeah. Wherever that HRESULT comes from, it doesn't look it is intended. I agree we can just ignore it.
After mapping the unindentified hr 0x80010064, when I run the shader runner on Windows, this test from `entry-point-semantics.shader_test`:
``` % Arrays (even multi-dimensional) of struct elements are allowed. The fields in the different struct % elements get the same indexes. [pixel shader] struct apple { float4 texcoord : TEXCOORD0; float4 arb : UNUSED; };
float4 main(in apple aps[2][2]) : sv_target { return float4(aps[0][0].texcoord.xy, aps[1][1].texcoord.xy); } ```
results in a segmentation fault, **only** for d3d12. This is the shader runner output before the crash:
``` shader_runner:1199: Running tests from a Windows cross build shader_runner:1201: Compiling shaders with d3dcompiler_47.dll and executing with d3d9.dll shader_runner:87: Driver string: d3d10warp.dll. shader_runner:88: Device: Microsoft Basic Render Driver, 1414:008c. shader_runner:91: Using WARP device. shader_runner:1204: Compiling shaders with d3dcompiler_47.dll and executing with d3d11.dll shader_runner:161: Adapter: Microsoft Basic Render Driver, 1414:008c. shader_runner:165: Using WARP device. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:1207: Compiling shaders with d3dcompiler_47.dll and executing with d3d12.dll shader_runner:340: Adapter: Microsoft Basic Render Driver, 1414:008c. shader_runner:344: Using WARP device. shader_runner:408: Section [test], line 120: Test failed: Failed to create state, hr 0x80070057. -- segmentation fault here -- ```
I wonder if hr 0x80010064 and this new hr 0x80070057 here are related to duplicated input semantics. I will do more testing, but if that's the case, perhaps we would want a way to tell the shader runner when a shader should compiler but not it is not required to be executed properly.
On Mon Apr 24 15:14:33 2023 +0000, Francisco Casas wrote:
After mapping the unindentified hr 0x80010064, when I run the shader runner on Windows, this test from `entry-point-semantics.shader_test`:
% Arrays (even multi-dimensional) of struct elements are allowed. The fields in the different struct % elements get the same indexes. [pixel shader] struct apple { float4 texcoord : TEXCOORD0; float4 arb : UNUSED; }; float4 main(in apple aps[2][2]) : sv_target { return float4(aps[0][0].texcoord.xy, aps[1][1].texcoord.xy); }
results in a segmentation fault, **only** for d3d12. This is the shader runner output before the crash:
shader_runner:1199: Running tests from a Windows cross build shader_runner:1201: Compiling shaders with d3dcompiler_47.dll and executing with d3d9.dll shader_runner:87: Driver string: d3d10warp.dll. shader_runner:88: Device: Microsoft Basic Render Driver, 1414:008c. shader_runner:91: Using WARP device. shader_runner:1204: Compiling shaders with d3dcompiler_47.dll and executing with d3d11.dll shader_runner:161: Adapter: Microsoft Basic Render Driver, 1414:008c. shader_runner:165: Using WARP device. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:723: Mapping unindentified hr 0x80010064 as 0x80004005. shader_runner:1207: Compiling shaders with d3dcompiler_47.dll and executing with d3d12.dll shader_runner:340: Adapter: Microsoft Basic Render Driver, 1414:008c. shader_runner:344: Using WARP device. shader_runner:408: Section [test], line 120: Test failed: Failed to create state, hr 0x80070057. -- segmentation fault here --
I wonder if hr 0x80010064 and this new hr 0x80070057 here are related to duplicated input semantics. I will do more testing, but if that's the case, perhaps we would want a way to tell the shader runner when a shader should compiler but not it is not required to be executed properly.
It is worth noting that to get this output I had to disable stdout and stderr buffering with `setbuf(stdout, NULL)` and `setbuf(stderr, NULL)` in `shader_runner.c`. Otherwise, on Windows, the program is terminated before the buffer is printed.
I will do more testing, but if that's the case, perhaps we would want a way to tell the shader runner when a shader should compiler but not it is not required to be executed properly.
That's broadly what 4d17758657 was for. It was specifically meant for cases where testing syntax was interesting but testing execution wasn't, but it can work here too.
On Mon Apr 24 17:44:50 2023 +0000, Zebediah Figura wrote:
I will do more testing, but if that's the case, perhaps we would want
a way to tell the shader runner when a shader should compiler but not it is not required to be executed properly. That's broadly what 4d17758657 was for. It was specifically meant for cases where testing syntax was interesting but testing execution wasn't, but it can work here too.
I doubt that the crash has anything to do with duplicated input semantics, though, since that's not visible in the bytecode at all. Probably more likely is that the unused shader input semantic isn't output by the vertex shader. Just like merge request 159, using sv_position instead would probably work.
On Mon Apr 24 19:39:48 2023 +0000, Zebediah Figura wrote:
I doubt that the crash has anything to do with duplicated input semantics, though, since that's not visible in the bytecode at all. Probably more likely is that the unused shader input semantic isn't output by the vertex shader. Just like merge request 159, using sv_position instead would probably work.
The segfault persists even if the field with the `UNUSED` semantic is removed.
It goes away when `TEXCOORD0` is not duplicated though, for instance if we make `apple aps[1][1]`:
```hlsl struct apple { float4 texcoord : TEXCOORD0; float4 arb : UNUSED; };
float4 main(in apple aps[1][1]) : sv_target { return float4(aps[0][0].texcoord.xy, 0, 0); } ````
The segfault persists even if the field with the `UNUSED` semantic is removed.
It goes away when `TEXCOORD0` is not duplicated though, for instance if we make `apple aps[1][1]`:
That doesn't make any sense; the duplication doesn't show up in the bytecode at all. There must be something else going on.
On Mon Apr 24 20:08:52 2023 +0000, Zebediah Figura wrote:
The segfault persists even if the field with the `UNUSED` semantic is removed.
It goes away when `TEXCOORD0` is not duplicated though, for instance
if we make `apple aps[1][1]`: That doesn't make any sense; the duplication doesn't show up in the bytecode at all. There must be something else going on.
Ah, yes, ignore my comment. I got myself really confused here.
Contrary to what I said, it is the `UNUSED` semantic the one that creates the segfault, and when I delete it, the segfault goes away. Yes, there can be a duplicated `TEXCOORD0` input semantic.