vkd3d-shader/hlsl: Error out when an output semantic is used more than once.

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 overlaps 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.
This commit is contained in:
Francisco Casas 2023-04-12 15:59:06 -04:00 committed by Alexandre Julliard
parent edc72fdefc
commit d96e9665b1
Notes: Alexandre Julliard 2023-05-01 22:24:44 +02:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Zebediah Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/148
5 changed files with 38 additions and 16 deletions

View File

@ -212,6 +212,9 @@ struct hlsl_semantic
/* If the variable or field that stores this hlsl_semantic has already reported that it is missing. */ /* If the variable or field that stores this hlsl_semantic has already reported that it is missing. */
bool reported_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. */ /* A field within a struct type declaration, used in hlsl_type.e.fields. */

View File

@ -4784,6 +4784,7 @@ semantic:
$$.name = $2; $$.name = $2;
$$.index = atoi(p); $$.index = atoi(p);
$$.reported_missing = false; $$.reported_missing = false;
$$.reported_duplicated_output_next_index = 0;
*p = 0; *p = 0;
} }

View File

@ -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, 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, struct hlsl_type *type, unsigned int modifiers, struct hlsl_semantic *semantic,
uint32_t index, bool output) uint32_t index, bool output, const struct vkd3d_shader_location *loc)
{ {
struct hlsl_semantic new_semantic; struct hlsl_semantic new_semantic;
struct vkd3d_string_buffer *name; 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 (!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); hlsl_release_string_buffer(ctx, name);
return ext_var; return ext_var;
} }
@ -259,8 +271,8 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
return NULL; return NULL;
} }
new_semantic.index = index; new_semantic.index = index;
if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), type, loc, &new_semantic,
type, &var->loc, &new_semantic, modifiers, NULL))) modifiers, NULL)))
{ {
hlsl_release_string_buffer(ctx, name); hlsl_release_string_buffer(ctx, name);
hlsl_cleanup_semantic(&new_semantic); 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, 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 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_var *var = lhs->src.var;
struct hlsl_ir_constant *c; struct hlsl_ir_constant *c;
unsigned int i; unsigned int i;
@ -305,7 +318,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
struct hlsl_ir_var *input; struct hlsl_ir_var *input;
struct hlsl_ir_load *load; 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; return;
if (!(load = hlsl_new_var_load(ctx, input, &var->loc))) if (!(load = hlsl_new_var_load(ctx, input, &var->loc)))
@ -334,8 +347,9 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
} }
static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *lhs, static void prepend_input_copy_recurse(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 vkd3d_shader_location *loc = &lhs->node.loc;
struct hlsl_type *type = lhs->node.data_type; struct hlsl_type *type = lhs->node.data_type;
struct hlsl_ir_var *var = lhs->src.var; struct hlsl_ir_var *var = lhs->src.var;
struct hlsl_ir_constant *c; struct hlsl_ir_constant *c;
@ -360,6 +374,7 @@ static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct list *instrs
validate_field_semantic(ctx, field); validate_field_semantic(ctx, field);
semantic = &field->semantic; semantic = &field->semantic;
elem_semantic_index = semantic->index; elem_semantic_index = semantic->index;
loc = &field->loc;
} }
if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc)))
@ -367,7 +382,7 @@ static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct list *instrs
list_add_after(&lhs->node.entry, &c->node.entry); list_add_after(&lhs->node.entry, &c->node.entry);
/* This redundant load is expected to be deleted later by DCE. */ /* 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; return;
list_add_after(&c->node.entry, &element_load->node.entry); list_add_after(&c->node.entry, &element_load->node.entry);
@ -395,9 +410,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, 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 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_var *var = rhs->src.var;
struct hlsl_ir_constant *c; struct hlsl_ir_constant *c;
unsigned int i; unsigned int i;
@ -421,7 +437,7 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
struct hlsl_ir_var *output; struct hlsl_ir_var *output;
struct hlsl_ir_load *load; 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; return;
if (type->class == HLSL_CLASS_MATRIX) if (type->class == HLSL_CLASS_MATRIX)
@ -450,8 +466,9 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct
} }
static void append_output_copy_recurse(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_load *rhs, static void append_output_copy_recurse(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 vkd3d_shader_location *loc = &rhs->node.loc;
struct hlsl_type *type = rhs->node.data_type; struct hlsl_type *type = rhs->node.data_type;
struct hlsl_ir_var *var = rhs->src.var; struct hlsl_ir_var *var = rhs->src.var;
struct hlsl_ir_constant *c; struct hlsl_ir_constant *c;
@ -476,13 +493,14 @@ static void append_output_copy_recurse(struct hlsl_ctx *ctx, struct list *instrs
validate_field_semantic(ctx, field); validate_field_semantic(ctx, field);
semantic = &field->semantic; semantic = &field->semantic;
elem_semantic_index = semantic->index; elem_semantic_index = semantic->index;
loc = &field->loc;
} }
if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc))) if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc)))
return; return;
list_add_tail(instrs, &c->node.entry); 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; return;
list_add_tail(instrs, &element_load->node.entry); list_add_tail(instrs, &element_load->node.entry);

View File

@ -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. % Output semantics cannot be mapped to more than one value.
[vertex shader fail todo] [vertex shader fail]
struct apple struct apple
{ {
float2 tex : TEXCOORD0; 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 struct apple
{ {
float2 f : SEMANTIC; 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. % 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) void main(out float2 a : sem0, out float2 b : SEM, inout float4 pos : sv_position)
{ {
a = float2(1, 2); a = float2(1, 2);

View File

@ -63,7 +63,7 @@ probe render target 1 all r (2.0)
probe render target 2 all r (3.0) probe render target 2 all r (3.0)
probe render target 3 all r (4.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) void main(out float1x2 x : sv_target0, out float1x2 y : sv_target1)
{ {
x = float2(1.0, 2.0); x = float2(1.0, 2.0);