#include "glsl_symbol_table.h"
#include "linker.h"
#include "main/macros.h"
+#include "main/mtypes.h"
#include "util/hash_table.h"
namespace {
-/**
- * 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)
- 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;
-}
-
/**
* Return true if interface members mismatch and its not allowed by GLSL.
*/
* interpolation qualifiers of variables of the same name do not
* match."
*/
- if (prog->IsES || prog->Version < 440)
+ if (prog->IsES || prog->data->Version < 440)
if (c->fields.structure[i].interpolation !=
p->fields.structure[i].interpolation)
return true;
* 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 (!prog->IsES || prog->data->Version < 310)
if (c->fields.structure[i].centroid !=
p->fields.structure[i].centroid)
return true;
return false;
}
+/**
+ * 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 ||
+ 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->type->is_array() || a->type->is_array()) &&
+ (b->is_interface_instance() || a->is_interface_instance()) &&
+ !validate_intrastage_arrays(prog, b, a))
+ return false;
+
+ return true;
+}
+
/**
* Check if two interfaces match, according to interstage (in/out) interface
* matching rules.
}
}
+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_shader *producer,
- const gl_shader *consumer)
+ const gl_linked_shader *producer,
+ const gl_linked_shader *consumer)
{
interface_block_definitions definitions;
/* VS -> GS, VS -> TCS, VS -> TES, TES -> GS */
consumer->Stage != MESA_SHADER_FRAGMENT) ||
consumer->Stage == MESA_SHADER_GEOMETRY;
- /* Add input interfaces from the consumer to the symbol table. */
- foreach_in_list(ir_instruction, node, consumer->ir) {
+ /* Check that block re-declarations of gl_PerVertex are compatible
+ * across shaders: From OpenGL Shading Language 4.5, section
+ * "7.1 Built-In Language Variables", page 130 of the PDF:
+ *
+ * "If multiple shaders using members of a built-in block belonging
+ * to the same interface are linked together in the same program,
+ * they must all redeclare the built-in block in the same way, as
+ * described in section 4.3.9 “Interface Blocks” for interface-block
+ * matching, or a link-time error will result."
+ *
+ * This is done explicitly outside of iterating the member variable
+ * declarations because it is possible that the variables are not used and
+ * so they would have been optimised out.
+ */
+ const glsl_type *consumer_iface =
+ consumer->symbols->get_interface("gl_PerVertex",
+ ir_var_shader_in);
+
+ const glsl_type *producer_iface =
+ producer->symbols->get_interface("gl_PerVertex",
+ ir_var_shader_out);
+
+ if (producer_iface && consumer_iface &&
+ interstage_member_mismatch(prog, consumer_iface, producer_iface)) {
+ linker_error(prog, "Incompatible or missing gl_PerVertex re-declaration "
+ "in consecutive shaders");
+ return;
+ }
+
+ /* Add output interfaces from the producer to the symbol table. */
+ foreach_in_list(ir_instruction, node, producer->ir) {
ir_variable *var = node->as_variable();
- if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_in)
+ if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_out)
continue;
definitions.store(var);
}
- /* Verify that the producer's output interfaces match. */
- foreach_in_list(ir_instruction, node, producer->ir) {
+ /* Verify that the consumer's input interfaces match. */
+ foreach_in_list(ir_instruction, node, consumer->ir) {
ir_variable *var = node->as_variable();
- if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_out)
+ if (!var || !var->get_interface_type() || var->data.mode != ir_var_shader_in)
continue;
- ir_variable *consumer_def = definitions.lookup(var);
+ ir_variable *producer_def = definitions.lookup(var);
- /* The consumer doesn't use this output block. Ignore it. */
- if (consumer_def == NULL)
- continue;
+ /* 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;
+ }
- if (!interstage_match(prog, var, consumer_def, extra_array_level)) {
+ 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_shader **stages, int num_stages)
+ gl_linked_shader **stages)
{
interface_block_definitions definitions;
- for (int i = 0; i < num_stages; i++) {
+ for (int i = 0; i < MESA_SHADER_STAGES; i++) {
if (stages[i] == NULL)
continue;
- const gl_shader *stage = stages[i];
+ 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() ||
* shaders are in the same shader stage).
*/
if (!intrastage_match(old_def, var, prog)) {
- linker_error(prog, "definitions of interface block `%s' do not "
+ linker_error(prog, "definitions of uniform block `%s' do not "
"match\n", var->get_interface_type()->name);
return;
}