* represents either the interface instance (for named interfaces), or a
* member of the interface (for unnamed interfaces).
*/
- explicit interface_block_definition(const ir_variable *var)
- : type(var->get_interface_type()),
- instance_name(NULL),
- array_size(-1)
+ explicit interface_block_definition(ir_variable *var)
+ : var(var),
+ type(var->get_interface_type()),
+ instance_name(NULL)
{
if (var->is_interface_instance()) {
instance_name = var->name;
- if (var->type->is_array())
- array_size = var->type->length;
}
explicitly_declared = (var->data.how_declared != ir_var_declared_implicitly);
}
+ /**
+ * Interface block ir_variable
+ */
+ ir_variable *var;
/**
* Interface block type
*/
const char *instance_name;
- /**
- * For an interface block array, the array size (or 0 if unsized).
- * 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
intrastage_match(interface_block_definition *a,
const interface_block_definition *b,
- ir_variable_mode mode)
+ ir_variable_mode mode,
+ struct gl_shader_program *prog)
{
/* Types must match. */
if (a->type != b->type) {
* it's not clear from the spec whether they need to match, but
* Mesa's implementation relies on them matching.
*/
- if (a->instance_name != NULL && mode != ir_var_uniform &&
+ if (a->instance_name != NULL &&
+ mode != ir_var_uniform && mode != ir_var_shader_storage &&
strcmp(a->instance_name, b->instance_name) != 0) {
return false;
}
- /* Array vs. nonarray must be consistent, and sizes must be
- * consistent, with the exception that unsized arrays match sized
- * arrays.
+ /* If a block is an array then it must match across the shader.
+ * Unsized arrays are also processed and matched agaist sized arrays.
*/
- if ((a->array_size == -1) != (b->array_size == -1))
+ if (b->var->type != a->var->type &&
+ (b->instance_name != NULL || a->instance_name != NULL) &&
+ !validate_intrastage_arrays(prog, b->var, a->var))
return false;
- if (b->array_size != 0) {
- if (a->array_size == 0)
- a->array_size = b->array_size;
- else if (a->array_size != b->array_size)
- return false;
- }
return true;
}
* Check if two interfaces match, according to interstage (in/out) interface
* matching rules.
*
- * If \c extra_array_level is true, then vertex-to-geometry shader matching
- * rules are enforced (i.e. a successful match requires the consumer interface
- * to be an array and the producer interface to be a non-array).
+ * 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.
*/
bool
interstage_match(const interface_block_definition *producer,
/* Unsized arrays should not occur during interstage linking. They
* should have all been assigned a size by link_intrastage_shaders.
*/
- assert(consumer->array_size != 0);
- assert(producer->array_size != 0);
+ assert(!consumer->var->type->is_unsized_array());
+ assert(!producer->var->type->is_unsized_array());
/* Types must match. */
if (consumer->type != producer->type) {
if (consumer->explicitly_declared || producer->explicitly_declared)
return false;
}
+
+ /* Ignore outermost array if geom shader */
+ const glsl_type *consumer_instance_type;
if (extra_array_level) {
- /* Consumer must be an array, and producer must not. */
- if (consumer->array_size == -1)
- return false;
- if (producer->array_size != -1)
- return false;
+ consumer_instance_type = consumer->var->type->fields.array;
} else {
- /* Array vs. nonarray must be consistent, and sizes must be consistent.
- * Since unsized arrays have been ruled out, we can check this by just
- * making sure the sizes are equal.
- */
- if (consumer->array_size != producer->array_size)
+ consumer_instance_type = consumer->var->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->instance_name != NULL &&
+ consumer_instance_type->is_array()) ||
+ (producer->instance_name != NULL &&
+ producer->var->type->is_array())) {
+ if (consumer_instance_type != producer->var->type)
return false;
}
+
return true;
}
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_list(node, shader_list[i]->ir) {
- ir_variable *var = ((ir_instruction *) node)->as_variable();
+ foreach_in_list(ir_instruction, node, shader_list[i]->ir) {
+ ir_variable *var = node->as_variable();
if (!var)
continue;
case ir_var_uniform:
definitions = &uniform_interfaces;
break;
+ case ir_var_shader_storage:
+ definitions = &buffer_interfaces;
+ break;
default:
/* Only in, out, and uniform interfaces are legal, so we should
* never get here.
*/
definitions->store(def);
} else if (!intrastage_match(prev_def, &def,
- (ir_variable_mode) var->data.mode)) {
+ (ir_variable_mode) var->data.mode,
+ prog)) {
linker_error(prog, "definitions of interface block `%s' do not"
" match\n", iface_type->name);
return;
const gl_shader *consumer)
{
interface_block_definitions definitions;
- const bool extra_array_level = consumer->Type == GL_GEOMETRY_SHADER;
+ /* 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;
/* Add input interfaces from the consumer to the symbol table. */
- foreach_list(node, consumer->ir) {
- ir_variable *var = ((ir_instruction *) node)->as_variable();
+ 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_in)
continue;
}
/* Verify that the producer's output interfaces match. */
- foreach_list(node, producer->ir) {
- ir_variable *var = ((ir_instruction *) node)->as_variable();
+ 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_out)
continue;
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->data.mode != ir_var_uniform)
+ 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;
interface_block_definition *old_def =
* 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)) {
+ if (!intrastage_match(old_def, &new_def,
+ (ir_variable_mode) var->data.mode,
+ prog)) {
linker_error(prog, "definitions of interface block `%s' do not "
"match\n", var->get_interface_type()->name);
return;