aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl/link_interface_blocks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl/link_interface_blocks.cpp')
-rw-r--r--mesalib/src/glsl/link_interface_blocks.cpp102
1 files changed, 71 insertions, 31 deletions
diff --git a/mesalib/src/glsl/link_interface_blocks.cpp b/mesalib/src/glsl/link_interface_blocks.cpp
index a7fceb9ba..6900fa94e 100644
--- a/mesalib/src/glsl/link_interface_blocks.cpp
+++ b/mesalib/src/glsl/link_interface_blocks.cpp
@@ -60,6 +60,7 @@ struct interface_block_definition
if (var->type->is_array())
array_size = var->type->length;
}
+ explicitly_declared = (var->how_declared != ir_var_declared_implicitly);
}
/**
@@ -77,6 +78,12 @@ struct interface_block_definition
* Otherwise -1.
*/
int array_size;
+
+ /**
+ * True if this interface block was explicitly declared in the shader;
+ * false if it was an implicitly declared built-in interface block.
+ */
+ bool explicitly_declared;
};
@@ -91,8 +98,14 @@ intrastage_match(interface_block_definition *a,
ir_variable_mode mode)
{
/* Types must match. */
- if (a->type != b->type)
- return false;
+ if (a->type != b->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->explicitly_declared || b->explicitly_declared)
+ return false;
+ }
/* Presence/absence of interface names must match. */
if ((a->instance_name == NULL) != (b->instance_name == NULL))
@@ -144,8 +157,14 @@ interstage_match(const interface_block_definition *producer,
assert(producer->array_size != 0);
/* Types must match. */
- if (consumer->type != producer->type)
- return false;
+ if (consumer->type != producer->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 (consumer->explicitly_declared || producer->explicitly_declared)
+ return false;
+ }
if (extra_array_level) {
/* Consumer must be an array, and producer must not. */
if (consumer->array_size == -1)
@@ -289,57 +308,78 @@ validate_intrastage_interface_blocks(struct gl_shader_program *prog,
}
void
-validate_interstage_interface_blocks(struct gl_shader_program *prog,
- const gl_shader *producer,
- const gl_shader *consumer)
+validate_interstage_inout_blocks(struct gl_shader_program *prog,
+ const gl_shader *producer,
+ const gl_shader *consumer)
{
- interface_block_definitions inout_interfaces;
- interface_block_definitions uniform_interfaces;
+ interface_block_definitions definitions;
const bool extra_array_level = consumer->Type == GL_GEOMETRY_SHADER;
- /* Add non-output interfaces from the consumer to the symbol table. */
+ /* Add input interfaces from the consumer to the symbol table. */
foreach_list(node, consumer->ir) {
ir_variable *var = ((ir_instruction *) node)->as_variable();
- if (!var || !var->get_interface_type() || var->mode == ir_var_shader_out)
+ if (!var || !var->get_interface_type() || var->mode != ir_var_shader_in)
continue;
- interface_block_definitions *definitions = var->mode == ir_var_uniform ?
- &uniform_interfaces : &inout_interfaces;
- definitions->store(interface_block_definition(var));
+ definitions.store(interface_block_definition(var));
}
- /* Verify that the producer's interfaces match. */
+ /* Verify that the producer's output interfaces match. */
foreach_list(node, producer->ir) {
ir_variable *var = ((ir_instruction *) node)->as_variable();
- if (!var || !var->get_interface_type() || var->mode == ir_var_shader_in)
+ if (!var || !var->get_interface_type() || var->mode != ir_var_shader_out)
continue;
- interface_block_definitions *definitions = var->mode == ir_var_uniform ?
- &uniform_interfaces : &inout_interfaces;
interface_block_definition *consumer_def =
- definitions->lookup(var->get_interface_type()->name);
+ definitions.lookup(var->get_interface_type()->name);
/* The consumer doesn't use this output block. Ignore it. */
if (consumer_def == NULL)
continue;
const interface_block_definition producer_def(var);
- bool match;
- if (var->mode == ir_var_uniform) {
- /* Uniform matching rules are the same for interstage and intrastage
- * linking.
- */
- match = intrastage_match(consumer_def, &producer_def,
- (ir_variable_mode) var->mode);
- } else {
- match = interstage_match(&producer_def, consumer_def,
- extra_array_level);
- }
- if (!match) {
+ if (!interstage_match(&producer_def, consumer_def, 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)
+{
+ interface_block_definitions definitions;
+
+ for (int i = 0; i < num_stages; i++) {
+ if (stages[i] == NULL)
+ continue;
+
+ const gl_shader *stage = stages[i];
+ foreach_list(node, stage->ir) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (!var || !var->get_interface_type() || var->mode != ir_var_uniform)
+ continue;
+
+ interface_block_definition *old_def =
+ definitions.lookup(var->get_interface_type()->name);
+ const interface_block_definition new_def(var);
+ if (old_def == NULL) {
+ definitions.store(new_def);
+ } 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, &new_def, ir_var_uniform)) {
+ linker_error(prog, "definitions of interface block `%s' do not "
+ "match\n", var->get_interface_type()->name);
+ return;
+ }
+ }
+ }
+ }
+}