diff options
Diffstat (limited to 'mesalib/src/glsl/link_interface_blocks.cpp')
-rw-r--r-- | mesalib/src/glsl/link_interface_blocks.cpp | 102 |
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; + } + } + } + } +} |