mesa/src/compiler/glsl/link_interface_blocks.cpp

442 lines
15 KiB
C++
Raw Normal View History

/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* \file link_interface_blocks.cpp
* Linker support for GLSL's interface blocks.
*/
#include "ir.h"
#include "glsl_symbol_table.h"
#include "linker.h"
#include "main/macros.h"
#include "util/hash_table.h"
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
namespace {
/**
* Return true if interface members mismatch and its not allowed by GLSL.
*/
static bool
interstage_member_mismatch(struct gl_shader_program *prog,
const glsl_type *c, const glsl_type *p) {
if (c->length != p->length)
return true;
for (unsigned i = 0; i < c->length; i++) {
if (c->fields.structure[i].type != p->fields.structure[i].type)
return true;
if (strcmp(c->fields.structure[i].name,
p->fields.structure[i].name) != 0)
return true;
if (c->fields.structure[i].location !=
p->fields.structure[i].location)
return true;
if (c->fields.structure[i].patch !=
p->fields.structure[i].patch)
return true;
/* From Section 4.5 (Interpolation Qualifiers) of the GLSL 4.40 spec:
*
* "It is a link-time error if, within the same stage, the
* interpolation qualifiers of variables of the same name do not
* match."
*/
if (prog->IsES || prog->Version < 440)
if (c->fields.structure[i].interpolation !=
p->fields.structure[i].interpolation)
return true;
/* From Section 4.3.4 (Input Variables) of the GLSL ES 3.0 spec:
*
* "The output of the vertex shader and the input of the fragment
* shader form an interface. For this interface, vertex shader
* output variables and fragment shader input variables of the same
* name must match in type and qualification (other than precision
* and out matching to in).
*
* The table in Section 9.2.1 Linked Shaders of the GLSL ES 3.1 spec
* says that centroid no longer needs to match for varyings.
*
* The table in Section 9.2.1 Linked Shaders of the GLSL ES 3.2 spec
* says that sample need not match for varyings.
*/
if (!prog->IsES || prog->Version < 310)
if (c->fields.structure[i].centroid !=
p->fields.structure[i].centroid)
return true;
if (!prog->IsES)
if (c->fields.structure[i].sample !=
p->fields.structure[i].sample)
return true;
}
return false;
}
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
/**
* Check if two interfaces match, according to intrastage interface matching
* rules. If they do, and the first interface uses an unsized array, it will
* be updated to reflect the array size declared in the second interface.
*/
bool
intrastage_match(ir_variable *a,
ir_variable *b,
struct gl_shader_program *prog)
{
/* Types must match. */
if (a->get_interface_type() != b->get_interface_type()) {
/* Exception: if both the interface blocks are implicitly declared,
* don't force their types to match. They might mismatch due to the two
* shaders using different GLSL versions, and that's ok.
*/
if ((a->data.how_declared != ir_var_declared_implicitly ||
b->data.how_declared != ir_var_declared_implicitly) &&
(!prog->IsES || prog->Version != 310 ||
interstage_member_mismatch(prog, a->get_interface_type(),
b->get_interface_type())))
return false;
}
/* Presence/absence of interface names must match. */
if (a->is_interface_instance() != b->is_interface_instance())
return false;
/* For uniforms, instance names need not match. For shader ins/outs,
* it's not clear from the spec whether they need to match, but
* Mesa's implementation relies on them matching.
*/
if (a->is_interface_instance() && b->data.mode != ir_var_uniform &&
b->data.mode != ir_var_shader_storage &&
strcmp(a->name, b->name) != 0) {
return false;
}
/* If a block is an array then it must match across the shader.
* Unsized arrays are also processed and matched agaist sized arrays.
*/
if (b->type != a->type &&
(b->is_interface_instance() || a->is_interface_instance()) &&
!validate_intrastage_arrays(prog, b, a))
return false;
return true;
}
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
/**
* Check if two interfaces match, according to interstage (in/out) interface
* matching rules.
*
* If \c extra_array_level is true, the consumer interface is required to be
* an array and the producer interface is required to be a non-array.
* This is used for tessellation control and geometry shader consumers.
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
*/
static bool
interstage_match(struct gl_shader_program *prog, ir_variable *producer,
ir_variable *consumer, bool extra_array_level)
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
{
/* Types must match. */
if (consumer->get_interface_type() != producer->get_interface_type()) {
/* Exception: if both the interface blocks are implicitly declared,
* don't force their types to match. They might mismatch due to the two
* shaders using different GLSL versions, and that's ok.
*
* Also we store some member information such as interpolation in
* glsl_type that doesn't always have to match across shader stages.
* Therefore we make a pass over the members glsl_struct_field to make
* sure we don't reject shaders where fields don't need to match.
*/
if ((consumer->data.how_declared != ir_var_declared_implicitly ||
producer->data.how_declared != ir_var_declared_implicitly) &&
interstage_member_mismatch(prog, consumer->get_interface_type(),
producer->get_interface_type()))
return false;
}
/* Ignore outermost array if geom shader */
const glsl_type *consumer_instance_type;
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
if (extra_array_level) {
consumer_instance_type = consumer->type->fields.array;
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
} else {
consumer_instance_type = consumer->type;
}
/* If a block is an array then it must match across shaders.
* Since unsized arrays have been ruled out, we can check this by just
* making sure the types are equal.
*/
if ((consumer->is_interface_instance() &&
consumer_instance_type->is_array()) ||
(producer->is_interface_instance() &&
producer->type->is_array())) {
if (consumer_instance_type != producer->type)
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
return false;
}
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
return true;
}
/**
* This class keeps track of a mapping from an interface block name to the
* necessary information about that interface block to determine whether to
* generate a link error.
*
* Note: this class is expected to be short lived, so it doesn't make copies
* of the strings it references; it simply borrows the pointers from the
* ir_variable class.
*/
class interface_block_definitions
{
public:
interface_block_definitions()
: mem_ctx(ralloc_context(NULL)),
ht(_mesa_hash_table_create(NULL, _mesa_key_hash_string,
_mesa_key_string_equal))
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
{
}
~interface_block_definitions()
{
ralloc_free(mem_ctx);
_mesa_hash_table_destroy(ht, NULL);
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
}
/**
* Lookup the interface definition. Return NULL if none is found.
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
*/
ir_variable *lookup(ir_variable *var)
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
{
if (var->data.explicit_location &&
var->data.location >= VARYING_SLOT_VAR0) {
char location_str[11];
snprintf(location_str, 11, "%d", var->data.location);
const struct hash_entry *entry =
_mesa_hash_table_search(ht, location_str);
return entry ? (ir_variable *) entry->data : NULL;
} else {
const struct hash_entry *entry =
_mesa_hash_table_search(ht,
var->get_interface_type()->without_array()->name);
return entry ? (ir_variable *) entry->data : NULL;
}
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
}
/**
* Add a new interface definition.
*/
void store(ir_variable *var)
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
{
if (var->data.explicit_location &&
var->data.location >= VARYING_SLOT_VAR0) {
/* If explicit location is given then lookup the variable by location.
* We turn the location into a string and use this as the hash key
* rather than the name. Note: We allocate enough space for a 32-bit
* unsigned location value which is overkill but future proof.
*/
char location_str[11];
snprintf(location_str, 11, "%d", var->data.location);
_mesa_hash_table_insert(ht, ralloc_strdup(mem_ctx, location_str), var);
} else {
_mesa_hash_table_insert(ht,
var->get_interface_type()->without_array()->name, var);
}
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
}
private:
/**
* Ralloc context for data structures allocated by this class.
*/
void *mem_ctx;
/**
* Hash table mapping interface block name to an \c
* ir_variable.
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
*/
hash_table *ht;
};
}; /* anonymous namespace */
void
validate_intrastage_interface_blocks(struct gl_shader_program *prog,
const gl_shader **shader_list,
unsigned num_shaders)
{
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
interface_block_definitions in_interfaces;
interface_block_definitions out_interfaces;
interface_block_definitions uniform_interfaces;
interface_block_definitions buffer_interfaces;
for (unsigned int i = 0; i < num_shaders; i++) {
if (shader_list[i] == NULL)
continue;
foreach_in_list(ir_instruction, node, shader_list[i]->ir) {
ir_variable *var = node->as_variable();
if (!var)
continue;
const glsl_type *iface_type = var->get_interface_type();
if (iface_type == NULL)
continue;
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
interface_block_definitions *definitions;
switch (var->data.mode) {
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
case ir_var_shader_in:
definitions = &in_interfaces;
break;
case ir_var_shader_out:
definitions = &out_interfaces;
break;
case ir_var_uniform:
definitions = &uniform_interfaces;
break;
case ir_var_shader_storage:
definitions = &buffer_interfaces;
break;
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
default:
/* Only in, out, and uniform interfaces are legal, so we should
* never get here.
*/
assert(!"illegal interface type");
continue;
}
ir_variable *prev_def = definitions->lookup(var);
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
if (prev_def == NULL) {
/* This is the first time we've seen the interface, so save
glsl: Rework interface block linking. Previously, when doing intrastage and interstage interface block linking, we only checked the interface type; this prevented us from catching some link errors. We now check the following additional constraints: - For intrastage linking, the presence/absence of interface names must match. - For shader ins/outs, the interface names themselves must match when doing intrastage linking (note: it's not clear from the spec whether this is necessary, but Mesa's implementation currently relies on it). - Array vs. nonarray must be consistent, taking into account the special rules for vertex-geometry linkage. - Array sizes must be consistent (exception: during intrastage linking, an unsized array matches a sized array). Note: validate_interstage_interface_blocks currently handles both uniforms and in/out variables. As a result, if all three shader types are present (VS, GS, and FS), and a uniform interface block is mentioned in the VS and FS but not the GS, it won't be validated. I plan to address this in later patches. Fixes the following piglit tests in spec/glsl-1.50/linker: - interface-blocks-vs-fs-array-size-mismatch - interface-vs-array-to-fs-unnamed - interface-vs-unnamed-to-fs-array - intrastage-interface-unnamed-array v2: Simplify logic in intrastage_match() for handling array sizes. Make extra_array_level const. Use an unnamed temporary interface_block_definition in validate_interstage_interface_blocks()'s first call to definitions->store(). Cc: "10.0" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2013-10-29 14:41:32 -07:00
* it into the appropriate data structure.
*/
definitions->store(var);
} else if (!intrastage_match(prev_def, var, prog)) {
linker_error(prog, "definitions of interface block `%s' do not"
" match\n", iface_type->name);
return;
}
}
}
}
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
static bool
is_builtin_gl_in_block(ir_variable *var, int consumer_stage)
{
return !strcmp(var->name, "gl_in") &&
(consumer_stage == MESA_SHADER_TESS_CTRL ||
consumer_stage == MESA_SHADER_TESS_EVAL ||
consumer_stage == MESA_SHADER_GEOMETRY);
}
void
validate_interstage_inout_blocks(struct gl_shader_program *prog,
const gl_linked_shader *producer,
const gl_linked_shader *consumer)
{
interface_block_definitions definitions;
/* VS -> GS, VS -> TCS, VS -> TES, TES -> GS */
const bool extra_array_level = (producer->Stage == MESA_SHADER_VERTEX &&
consumer->Stage != MESA_SHADER_FRAGMENT) ||
consumer->Stage == MESA_SHADER_GEOMETRY;
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
/* Add output interfaces from the producer to the symbol table. */
foreach_in_list(ir_instruction, node, producer->ir) {
ir_variable *var = node->as_variable();
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_out)
continue;
definitions.store(var);
}
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
/* Verify that the consumer's input interfaces match. */
foreach_in_list(ir_instruction, node, consumer->ir) {
ir_variable *var = node->as_variable();
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_in)
continue;
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
ir_variable *producer_def = definitions.lookup(var);
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
/* The producer doesn't generate this input: fail to link. Skip built-in
* 'gl_in[]' since that may not be present if the producer does not
* write to any of the pre-defined outputs (e.g. if the vertex shader
* does not write to gl_Position, etc), which is allowed and results in
* undefined behavior.
*/
if (producer_def == NULL &&
!is_builtin_gl_in_block(var, consumer->Stage)) {
linker_error(prog, "Input block `%s' is not an output of "
"the previous stage\n", var->get_interface_type()->name);
return;
}
glsl: validate output blocks against input blocks Until now were validating in/out blocks by listing the inputs in the consumer stage and then, for each output of the producer, we checked that it was a match if it was consumed. This method does not catch the case where the consumer has an input that is not present as an output in the producer stage, because it only generates link errors for outputs present in the producer stage that don't match the inputs in the consumer stage. The current method does catch the case were an output from the producer stage is not consumed, which is irrelevant and is ignored. By reversing the way we do this, we can detect this situation, so this patch lists the outputs of the producer stage and then validates inputs of the consumer stage against them. If we see an input in the consumer for which there is no associated output in the producer, we produce a link error. The only exception to this is the special built-in input block gl_in[], since this is implicitly generated for geometry and tessellation stages, but we don't generate it if the producer stage does not write to any of the pre-defined outputs (for example, if the vertex shader does not write to gl_Position, etc). Since writing to these is not mandatory, do not produce a link error in that case. There is a CTS tessellation test (GL45-CTS.tessellation_shader.program_object_properties) that has an empty vertex shader (so it does not produce gl_in[]) and would fail to link if we don't do this. This fixes the following dEQP test: dEQP-GLES31.functional.shaders.linkage.io_block.missing_output_block Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98245 Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
2016-11-04 13:37:58 +01:00
if (producer_def &&
!interstage_match(prog, producer_def, var, extra_array_level)) {
linker_error(prog, "definitions of interface block `%s' do not "
"match\n", var->get_interface_type()->name);
return;
}
}
}
void
validate_interstage_uniform_blocks(struct gl_shader_program *prog,
gl_linked_shader **stages)
{
interface_block_definitions definitions;
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
if (stages[i] == NULL)
continue;
const gl_linked_shader *stage = stages[i];
foreach_in_list(ir_instruction, node, stage->ir) {
ir_variable *var = node->as_variable();
if (!var || !var->get_interface_type() ||
(var->data.mode != ir_var_uniform &&
var->data.mode != ir_var_shader_storage))
continue;
ir_variable *old_def = definitions.lookup(var);
if (old_def == NULL) {
definitions.store(var);
} else {
/* Interstage uniform matching rules are the same as intrastage
* uniform matchin rules (for uniforms, it is as though all
* shaders are in the same shader stage).
*/
if (!intrastage_match(old_def, var, prog)) {
linker_error(prog, "definitions of uniform block `%s' do not "
"match\n", var->get_interface_type()->name);
return;
}
}
}
}
}