From: Francisco Casas fcasas@codeweavers.com
Errors lose precision on which part of the variable is missing the semantics, but this is necessary in order to avoid printing the same error many times, when arrays are involved. It seems that the native compiler also makes this compromise. --- libs/vkd3d-shader/hlsl.h | 1 + libs/vkd3d-shader/hlsl_codegen.c | 126 +++++++++++++++++++----- tests/entry-point-semantics.shader_test | 30 +++--- 3 files changed, 116 insertions(+), 41 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 38a7715e..1b8a2f55 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -392,6 +392,7 @@ struct hlsl_ir_var uint32_t is_output_semantic : 1; uint32_t is_uniform : 1; uint32_t is_param : 1; + uint32_t is_missing_semantics : 1; };
/* Sized array of variables representing a function's parameters. */ diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index e250dd0b..03430069 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -257,7 +257,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, const struct hlsl_semantic *semantic) + unsigned int modifiers, struct hlsl_semantic *semantic) { struct hlsl_type *type = lhs->node.data_type, *vector_type; struct hlsl_ir_var *var = lhs->src.var; @@ -270,6 +270,10 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct return; hlsl_fixme(ctx, &var->loc, "Input semantics for type %s.", string->buffer); hlsl_release_string_buffer(ctx, string); + } + if (!semantic->name) + { + var->is_missing_semantics = 1; return; }
@@ -277,16 +281,14 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
for (i = 0; i < hlsl_type_major_size(type); ++i) { - struct hlsl_semantic semantic_copy = *semantic; struct hlsl_ir_store *store; struct hlsl_ir_constant *c; struct hlsl_ir_var *input; struct hlsl_ir_load *load;
- semantic_copy.index = semantic->index + i; - - if (!(input = add_semantic_var(ctx, var, vector_type, modifiers, &semantic_copy, false))) + if (!(input = add_semantic_var(ctx, var, vector_type, modifiers, semantic, false))) return; + semantic->index += 1;
if (!(load = hlsl_new_var_load(ctx, input, var->loc))) return; @@ -313,6 +315,37 @@ 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); + +static void prepend_input_array_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *lhs, + unsigned int modifiers, struct hlsl_semantic *semantic) +{ + struct hlsl_type *type = lhs->node.data_type; + struct hlsl_type *element_type = type->e.array.type; + struct hlsl_ir_var *var = lhs->src.var; + struct hlsl_ir_constant *c; + struct hlsl_ir_load *load; + unsigned int i; + + for (i = 0; i < hlsl_type_element_count(type); ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) + return; + list_add_after(&lhs->node.entry, &c->node.entry); + + if (!(load = hlsl_new_load_index(ctx, &lhs->src, &c->node, &var->loc))) + return; + list_add_after(&c->node.entry, &load->node.entry); + + if (element_type->class == HLSL_CLASS_STRUCT) + prepend_input_struct_copy(ctx, instrs, load); + else if (element_type->class == HLSL_CLASS_ARRAY) + prepend_input_array_copy(ctx, instrs, load, modifiers, semantic); + else + prepend_input_copy(ctx, instrs, load, modifiers, semantic); + } +} + 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; @@ -322,6 +355,7 @@ static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, for (i = 0; i < type->e.record.field_count; ++i) { const struct hlsl_struct_field *field = &type->e.record.fields[i]; + struct hlsl_semantic semantic_copy = field->semantic; struct hlsl_ir_load *field_load; struct hlsl_ir_constant *c;
@@ -336,11 +370,10 @@ static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs,
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 if (field->type->class == HLSL_CLASS_ARRAY) + prepend_input_array_copy(ctx, instrs, field_load, field->storage_modifiers, &semantic_copy); else - hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, - "Field '%s' is missing a semantic.", field->name); + prepend_input_copy(ctx, instrs, field_load, field->storage_modifiers, &semantic_copy); } }
@@ -348,6 +381,7 @@ static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, * and copy the former to the latter, so that writes to input variables work. */ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) { + struct hlsl_semantic semantic_copy = var->semantic; struct hlsl_ir_load *load;
/* This redundant load is expected to be deleted later by DCE. */ @@ -357,12 +391,14 @@ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st
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); + else if (var->data_type->class == HLSL_CLASS_ARRAY) + prepend_input_array_copy(ctx, instrs, load, var->storage_modifiers, &semantic_copy); + else + prepend_input_copy(ctx, instrs, load, var->storage_modifiers, &semantic_copy); }
static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *rhs, - unsigned int modifiers, const struct hlsl_semantic *semantic) + unsigned int modifiers, struct hlsl_semantic *semantic) { struct hlsl_type *type = rhs->node.data_type, *vector_type; struct hlsl_ir_var *var = rhs->src.var; @@ -375,6 +411,10 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct return; hlsl_fixme(ctx, &var->loc, "Output semantics for type %s.", string->buffer); hlsl_release_string_buffer(ctx, string); + } + if (!semantic->name) + { + var->is_missing_semantics = 1; return; }
@@ -382,16 +422,14 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
for (i = 0; i < hlsl_type_major_size(type); ++i) { - struct hlsl_semantic semantic_copy = *semantic; struct hlsl_ir_store *store; struct hlsl_ir_constant *c; struct hlsl_ir_var *output; struct hlsl_ir_load *load;
- semantic_copy.index = semantic->index + i; - - if (!(output = add_semantic_var(ctx, var, vector_type, modifiers, &semantic_copy, true))) + if (!(output = add_semantic_var(ctx, var, vector_type, modifiers, semantic, true))) return; + semantic->index += 1;
if (type->class == HLSL_CLASS_MATRIX) { @@ -418,6 +456,37 @@ 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); + +static void append_output_array_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *rhs, + unsigned int modifiers, struct hlsl_semantic *semantic) +{ + struct hlsl_type *type = rhs->node.data_type; + struct hlsl_type *element_type = type->e.array.type; + struct hlsl_ir_var *var = rhs->src.var; + struct hlsl_ir_constant *c; + struct hlsl_ir_load *load; + unsigned int i; + + for (i = 0; i < hlsl_type_element_count(type); ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) + return; + list_add_tail(instrs, &c->node.entry); + + if (!(load = hlsl_new_load_index(ctx, &rhs->src, &c->node, &var->loc))) + return; + list_add_tail(instrs, &load->node.entry); + + if (element_type->class == HLSL_CLASS_STRUCT) + append_output_struct_copy(ctx, instrs, load); + else if (element_type->class == HLSL_CLASS_ARRAY) + append_output_array_copy(ctx, instrs, load, modifiers, semantic); + else + append_output_copy(ctx, instrs, load, modifiers, semantic); + } +} + 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; @@ -427,6 +496,7 @@ static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, for (i = 0; i < type->e.record.field_count; ++i) { const struct hlsl_struct_field *field = &type->e.record.fields[i]; + struct hlsl_semantic semantic_copy = field->semantic; struct hlsl_ir_load *field_load; struct hlsl_ir_constant *c;
@@ -441,11 +511,10 @@ static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs,
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 if (field->type->class == HLSL_CLASS_ARRAY) + append_output_array_copy(ctx, instrs, field_load, field->storage_modifiers, &semantic_copy); else - hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, - "Field '%s' is missing a semantic.", field->name); + append_output_copy(ctx, instrs, field_load, field->storage_modifiers, &semantic_copy); } }
@@ -454,6 +523,7 @@ static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, * variables work. */ static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) { + struct hlsl_semantic semantic_copy = var->semantic; struct hlsl_ir_load *load;
/* This redundant load is expected to be deleted later by DCE. */ @@ -463,8 +533,10 @@ static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st
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); + else if (var->data_type->class == HLSL_CLASS_ARRAY) + append_output_array_copy(ctx, instrs, load, var->storage_modifiers, &semantic_copy); + else + append_output_copy(ctx, instrs, load, var->storage_modifiers, &semantic_copy); }
static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), @@ -3402,14 +3474,16 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry } else { - if (var->data_type->class != HLSL_CLASS_STRUCT && !var->semantic.name) - hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, - "Parameter "%s" is missing a semantic.", var->name); - if (var->storage_modifiers & HLSL_STORAGE_IN) prepend_input_var_copy(ctx, &body->instrs, var); if (var->storage_modifiers & HLSL_STORAGE_OUT) append_output_var_copy(ctx, &body->instrs, var); + + if (var->is_missing_semantics) + { + hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, + "Parameter "%s" is missing semantics.", var->name); + } } } if (entry_func->return_var) diff --git a/tests/entry-point-semantics.shader_test b/tests/entry-point-semantics.shader_test index 8c5fed58..a1dc2283 100644 --- a/tests/entry-point-semantics.shader_test +++ b/tests/entry-point-semantics.shader_test @@ -51,7 +51,7 @@ float4 main(float tex : bogus) : bogus; draw quad probe (0, 0) rgba (0.2, 0.2, 0.2, 0.2)
-[vertex shader todo] +[vertex shader] void main(out float2 tex[4] : texcoord, inout float4 pos : sv_position) { tex[0] = float2(1.0, 2.0); @@ -70,7 +70,7 @@ float4 main(in float2 arr[2]) : sv_target
% Array elements with a semantic get successive indexes -[pixel shader todo] +[pixel shader] struct apple { float2 tp[4] : TEXCOORD0; @@ -82,12 +82,12 @@ float4 main(in apple a) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (13.0, 24.0, 57.0, 68.0) +draw quad +probe (0, 0) rgba (13.0, 24.0, 57.0, 68.0)
% Arrays of matrices get successive indexes -[pixel shader todo] +[pixel shader] struct apple { float2x2 tp[2] : TEXCOORD0; @@ -99,13 +99,13 @@ float4 main(in apple a) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (12.0, 34.0, 56.0, 78.0) +draw quad +probe (0, 0) rgba (12.0, 34.0, 56.0, 78.0)
% Arrays (even multi-dimensional) of struct elements are allowed. The fields in the different struct % elements get the same indexes. -[pixel shader todo] +[pixel shader] struct apple { float2 texcoord : TEXCOORD0; float4 arb : UNUSED; @@ -117,11 +117,11 @@ float4 main(in apple aps[2][2]) : sv_target }
[test] -todo draw quad +draw quad todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0)
-[pixel shader todo] +[pixel shader] struct apple { float2 texcoord : TEXCOORD0; }; @@ -137,7 +137,7 @@ float4 main(in banana bans[2]) : sv_target }
[test] -todo draw quad +draw quad todo probe (0, 0) rgba (1.0, 2.0, 1.0, 2.0)
@@ -174,7 +174,7 @@ void main(out banana bans[2])
% Output semmantics cannot be mapped to more than one value -[vertex shader fail] +[vertex shader fail todo] struct apple { float2 tex : TEXCOORD0; }; @@ -186,7 +186,7 @@ void main(out apple apls[2], inout float4 pos : sv_position) }
-[vertex shader todo] +[vertex shader] struct apple { float2 tex[2] : TEXCOORD0; }; @@ -204,5 +204,5 @@ float4 main(in float2 tex0 : TEXCOORD0, in float2 tex1 : TEXCOORD1) : sv_target }
[test] -todo draw quad -todo probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0) +draw quad +probe (0, 0) rgba (1.0, 2.0, 10.0, 20.0)