This is required by https://bugs.winehq.org/show_bug.cgi?id=54660 .
-- v9: 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: Map unindentified hrs on compilation. 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 8e66948e..961d2fe0 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -1029,6 +1029,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 961d2fe0..214b1213 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; @@ -1031,6 +1034,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; @@ -1061,6 +1079,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
--- tests/shader_runner.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/tests/shader_runner.c b/tests/shader_runner.c index 214b1213..f1d93457 100644 --- a/tests/shader_runner.c +++ b/tests/shader_runner.c @@ -716,6 +716,16 @@ unsigned int get_vb_stride(const struct shader_runner *runner, unsigned int slot return stride; }
+static HRESULT map_unidentified_hrs(HRESULT hr) +{ + if (hr == 0x80010064) + { + trace("Mapping unindentified hr %#x as %#x.\n", hr, E_FAIL); + return E_FAIL; + } + return hr; +} + static void compile_shader(struct shader_runner *runner, const char *source, size_t len, const char *type, HRESULT expect) { ID3D10Blob *blob = NULL, *errors = NULL; @@ -733,6 +743,7 @@ static void compile_shader(struct shader_runner *runner, const char *source, siz
sprintf(profile, "%s_%s", type, shader_models[runner->minimum_shader_model]); hr = D3DCompile(source, len, NULL, NULL, NULL, "main", profile, 0, 0, &blob, &errors); + hr = map_unidentified_hrs(hr); ok(hr == expect, "Got unexpected hr %#x.\n", hr); if (hr == S_OK) {
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 42f8ab3b..314ef4ff 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 | 152 ++++++++++++++++++++++++ 1 file changed, 152 insertions(+)
diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index a32a0e7b..5b28b54a 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -50,3 +50,155 @@ 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 tc0 : TEXCOORD0; + float4 tc1 : TEXCOORD1; +}; + +float4 main(in apple aps[2][2]) : sv_target +{ + return float4(aps[0][0].tc0.x, aps[1][1].tc0.x, aps[0][0].tc1.x, aps[1][1].tc1.x); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (10.0, 10.0, 20.0, 20.0) + + +[pixel shader todo] +struct apple +{ + float4 tc0 : TEXCOORD0; +}; + +struct banana +{ + apple apl; + float4 tc1 : TEXCOORD1; +}; + +float4 main(in banana bans[2]) : sv_target +{ + return float4(bans[0].apl.tc0.xy, bans[1].tc1.xy); +} + +[test] +todo draw quad +todo probe (0, 0) rgba (10.0, 11.0, 20.0, 21.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 5b28b54a..0c59c9eb 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -202,3 +202,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/d3dbc.c | 18 ++---------------- libs/vkd3d-shader/hlsl.c | 13 ++++++++++--- libs/vkd3d-shader/hlsl.h | 3 +++ libs/vkd3d-shader/tpf.c | 18 ++---------------- 4 files changed, 17 insertions(+), 35 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 14268440..fba7e5ad 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1198,24 +1198,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.c b/libs/vkd3d-shader/hlsl.c index 32511590..5de56284 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -157,10 +157,17 @@ unsigned int hlsl_type_element_count(const struct hlsl_type *type) } }
-static unsigned int get_array_size(const struct hlsl_type *type) +const struct hlsl_type *hlsl_get_multiarray_element_type(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 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; }
@@ -279,7 +286,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; } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 974252d4..5991ed24 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1145,6 +1145,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/tpf.c b/libs/vkd3d-shader/tpf.c index e76cf8c9..31e84b5e 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -2448,20 +2448,6 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, add_section(dxbc, output ? TAG_OSGN : TAG_ISGN, &buffer); }
-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) @@ -2552,7 +2538,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; @@ -2566,7 +2552,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 314ef4ff..3ee20b2a 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 5991ed24..e4f4358e 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -209,6 +209,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 194d21f4..6ab3194e 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4631,7 +4631,7 @@ var_identifier: colon_attribute: %empty { - $$.semantic.name = NULL; + $$.semantic = (struct hlsl_semantic){0}; $$.reg_reservation.reg_type = 0; $$.reg_reservation.offset_type = 0; } @@ -4643,12 +4643,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; }
@@ -4661,6 +4661,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 3ee20b2a..25754e56 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 *), @@ -3492,15 +3501,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 0c59c9eb..7819d3e2 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -52,7 +52,7 @@ 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); @@ -71,7 +71,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; @@ -83,12 +83,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; @@ -100,13 +100,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 tc0 : TEXCOORD0; @@ -119,11 +119,11 @@ float4 main(in apple aps[2][2]) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (10.0, 10.0, 20.0, 20.0) +draw quad +probe (0, 0) rgba (10.0, 10.0, 20.0, 20.0)
-[pixel shader todo] +[pixel shader] struct apple { float4 tc0 : TEXCOORD0; @@ -141,8 +141,8 @@ float4 main(in banana bans[2]) : 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)
[pixel shader fail] @@ -181,7 +181,7 @@ void main(out banana bans[2]) }
-[vertex shader todo] +[vertex shader] struct apple { float4 tex[2] : TEXCOORD0; @@ -200,12 +200,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; @@ -240,7 +240,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); @@ -259,8 +259,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. @@ -271,8 +271,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 | 36 ++++++++++++++++++------- tests/entry-point-semantics.shader_test | 6 ++--- tests/matrix-semantics.shader_test | 2 +- 5 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index e4f4358e..0c96a744 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -212,6 +212,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 6ab3194e..9a2de35e 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4662,6 +4662,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 25754e56..ef8efc8d 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; } @@ -259,8 +271,8 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir return NULL; } new_semantic.index = index; - if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), - type, &var->loc, &new_semantic, modifiers, NULL))) + if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), 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 7819d3e2..66dcd6ee 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -205,7 +205,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; @@ -218,7 +218,7 @@ void main(out apple apls[2], inout float4 pos : sv_position) }
-[vertex shader fail todo] +[vertex shader fail] struct apple { float2 f : SEMANTIC; @@ -232,7 +232,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 0c96a744..3dcc3be7 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -215,6 +215,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 9a2de35e..6a47262a 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -4663,6 +4663,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 ef8efc8d..844c7bd9 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 66dcd6ee..32cd43c2 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -295,14 +295,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; @@ -317,7 +317,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 844c7bd9..48260cb9 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_node *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->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->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, 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, 0, &var->loc))) return; - list_add_after(&load->node.entry, &store->node.entry); + list_add_after(&cast->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 48260cb9..aa2c2484 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: Rebased on top of master.
This merge request was approved by Zebediah Figura.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/hlsl_codegen.c:
}
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)
I don't completely like this control flow structure. I'd rather have `prepend_input_copy()` call one or more times (as appropriate) another helper (like `prepend_single_input_copy()`), rather than reenter itself to pick a different path.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/hlsl_codegen.c:
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)
Same here.
Commit message for "vkd3d-shader/hlsl: Error out when an output semantic is used more than once." has a typo ("overalps").
This merge request was approved by Giovanni Mascellani.
On Thu Apr 27 13:07:07 2023 +0000, Giovanni Mascellani wrote:
I don't completely like this control flow structure. I'd rather have `prepend_input_copy()` call one or more times (as appropriate) another helper (like `prepend_single_input_copy()`), rather than reenter itself to pick a different path.
I don't disagree with adding another helper function for the sake of reducing the function's size, but I'm not sure I see the point of doing it to avoid direct recursion? We're recursing either way...