glsl: Fix input/output structure matching across shader stages

Section 7.4.1 (Shader Interface Matching) of the OpenGL 4.30 spec says:

    "Variables or block members declared as structures are considered
     to match in type if and only if structure members match in name,
     type, qualification, and declaration order."

Fixes:
     * layout-location-struct.shader_test

v2: rebased against master and small fixes

Signed-off-by: Vadym Shovkoplias <vadym.shovkoplias@globallogic.com>
Reviewed-by: Anuj Phogat <anuj.phogat@gmail.com>
Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=108250
This commit is contained in:
Sergii Romantsov
2019-01-24 14:33:55 +02:00
committed by Timothy Arceri
parent 738921afd9
commit a7d40a13ec
4 changed files with 56 additions and 26 deletions

View File

@@ -7594,7 +7594,7 @@ ast_struct_specifier::hir(exec_list *instructions,
if (!type->is_anonymous() && !state->symbols->add_type(name, type)) { if (!type->is_anonymous() && !state->symbols->add_type(name, type)) {
const glsl_type *match = state->symbols->get_type(name); const glsl_type *match = state->symbols->get_type(name);
/* allow struct matching for desktop GL - older UE4 does this */ /* allow struct matching for desktop GL - older UE4 does this */
if (match != NULL && state->is_version(130, 0) && match->record_compare(type, false)) if (match != NULL && state->is_version(130, 0) && match->record_compare(type, true, false))
_mesa_glsl_warning(& loc, state, "struct `%s' previously defined", name); _mesa_glsl_warning(& loc, state, "struct `%s' previously defined", name);
else else
_mesa_glsl_error(& loc, state, "struct `%s' previously defined", name); _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name);

View File

@@ -214,25 +214,42 @@ cross_validate_types_and_qualifiers(struct gl_context *ctx,
} }
if (type_to_match != output->type) { if (type_to_match != output->type) {
/* There is a bit of a special case for gl_TexCoord. This if (output->type->is_struct()) {
* built-in is unsized by default. Applications that variable /* Structures across shader stages can have different name
* access it must redeclare it with a size. There is some * and considered to match in type if and only if structure
* language in the GLSL spec that implies the fragment shader * members match in name, type, qualification, and declaration
* and vertex shader do not have to agree on this size. Other * order.
* driver behave this way, and one or two applications seem to */
* rely on it. if (!output->type->record_compare(type_to_match, false, true)) {
* linker_error(prog,
* Neither declaration needs to be modified here because the array "%s shader output `%s' declared as struct `%s', "
* sizes are fixed later when update_array_sizes is called. "doesn't match in type with %s shader input "
* "declared as struct `%s'\n",
* From page 48 (page 54 of the PDF) of the GLSL 1.10 spec: _mesa_shader_stage_to_string(producer_stage),
* output->name,
* "Unlike user-defined varying variables, the built-in output->type->name,
* varying variables don't have a strict one-to-one _mesa_shader_stage_to_string(consumer_stage),
* correspondence between the vertex language and the input->type->name);
* fragment language." }
*/ } else if (!output->type->is_array() || !is_gl_identifier(output->name)) {
if (!output->type->is_array() || !is_gl_identifier(output->name)) { /* There is a bit of a special case for gl_TexCoord. This
* built-in is unsized by default. Applications that variable
* access it must redeclare it with a size. There is some
* language in the GLSL spec that implies the fragment shader
* and vertex shader do not have to agree on this size. Other
* driver behave this way, and one or two applications seem to
* rely on it.
*
* Neither declaration needs to be modified here because the array
* sizes are fixed later when update_array_sizes is called.
*
* From page 48 (page 54 of the PDF) of the GLSL 1.10 spec:
*
* "Unlike user-defined varying variables, the built-in
* varying variables don't have a strict one-to-one
* correspondence between the vertex language and the
* fragment language."
*/
linker_error(prog, linker_error(prog,
"%s shader output `%s' declared as type `%s', " "%s shader output `%s' declared as type `%s', "
"but %s shader input declared as type `%s'\n", "but %s shader input declared as type `%s'\n",

View File

@@ -1008,7 +1008,8 @@ glsl_type::get_array_instance(const glsl_type *base,
bool bool
glsl_type::record_compare(const glsl_type *b, bool match_locations) const glsl_type::record_compare(const glsl_type *b, bool match_name,
bool match_locations) const
{ {
if (this->length != b->length) if (this->length != b->length)
return false; return false;
@@ -1025,9 +1026,16 @@ glsl_type::record_compare(const glsl_type *b, bool match_locations) const
* type definitions, and field names to be considered the same type." * type definitions, and field names to be considered the same type."
* *
* GLSL ES behaves the same (Ver 1.00 Sec 4.2.4, Ver 3.00 Sec 4.2.5). * GLSL ES behaves the same (Ver 1.00 Sec 4.2.4, Ver 3.00 Sec 4.2.5).
*
* Section 7.4.1 (Shader Interface Matching) of the OpenGL 4.30 spec says:
*
* "Variables or block members declared as structures are considered
* to match in type if and only if structure members match in name,
* type, qualification, and declaration order."
*/ */
if (strcmp(this->name, b->name) != 0) if (match_name)
return false; if (strcmp(this->name, b->name) != 0)
return false;
for (unsigned i = 0; i < this->length; i++) { for (unsigned i = 0; i < this->length; i++) {
if (this->fields.structure[i].type != b->fields.structure[i].type) if (this->fields.structure[i].type != b->fields.structure[i].type)
@@ -1098,7 +1106,8 @@ glsl_type::record_key_compare(const void *a, const void *b)
const glsl_type *const key1 = (glsl_type *) a; const glsl_type *const key1 = (glsl_type *) a;
const glsl_type *const key2 = (glsl_type *) b; const glsl_type *const key2 = (glsl_type *) b;
return strcmp(key1->name, key2->name) == 0 && key1->record_compare(key2); return strcmp(key1->name, key2->name) == 0 &&
key1->record_compare(key2, true);
} }

View File

@@ -934,11 +934,15 @@ public:
/** /**
* Compare a record type against another record type. * Compare a record type against another record type.
* *
* This is useful for matching record types declared across shader stages. * This is useful for matching record types declared on the same shader
* stage as well as across different shader stages.
* The option to not match name is needed for matching record types
* declared across different shader stages.
* The option to not match locations is to deal with places where the * The option to not match locations is to deal with places where the
* same struct is defined in a block which has a location set on it. * same struct is defined in a block which has a location set on it.
*/ */
bool record_compare(const glsl_type *b, bool match_locations = true) const; bool record_compare(const glsl_type *b, bool match_name,
bool match_locations = true) const;
/** /**
* Get the type interface packing. * Get the type interface packing.