glsl: use common intrastage array validation

Use common intrastage array validation for interface blocks.

This change also allows us to support interface blocks
that are arrays of arrays.

V2: Reinsert unsized array asserts in interstage_match()

Reviewed-by: Mark Janes <mark.a.janes@intel.com>
This commit is contained in:
Timothy Arceri 2015-02-22 22:52:48 +11:00
parent 50859c688c
commit c5a56a63f9

View file

@ -50,18 +50,20 @@ struct interface_block_definition
* represents either the interface instance (for named interfaces), or a * represents either the interface instance (for named interfaces), or a
* member of the interface (for unnamed interfaces). * member of the interface (for unnamed interfaces).
*/ */
explicit interface_block_definition(const ir_variable *var) explicit interface_block_definition(ir_variable *var)
: type(var->get_interface_type()), : var(var),
instance_name(NULL), type(var->get_interface_type()),
array_size(-1) instance_name(NULL)
{ {
if (var->is_interface_instance()) { if (var->is_interface_instance()) {
instance_name = var->name; instance_name = var->name;
if (var->type->is_array())
array_size = var->type->length;
} }
explicitly_declared = (var->data.how_declared != ir_var_declared_implicitly); explicitly_declared = (var->data.how_declared != ir_var_declared_implicitly);
} }
/**
* Interface block ir_variable
*/
ir_variable *var;
/** /**
* Interface block type * Interface block type
@ -73,12 +75,6 @@ struct interface_block_definition
*/ */
const char *instance_name; 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; * True if this interface block was explicitly declared in the shader;
* false if it was an implicitly declared built-in interface block. * false if it was an implicitly declared built-in interface block.
@ -95,7 +91,8 @@ struct interface_block_definition
bool bool
intrastage_match(interface_block_definition *a, intrastage_match(interface_block_definition *a,
const interface_block_definition *b, const interface_block_definition *b,
ir_variable_mode mode) ir_variable_mode mode,
struct gl_shader_program *prog)
{ {
/* Types must match. */ /* Types must match. */
if (a->type != b->type) { if (a->type != b->type) {
@ -120,18 +117,13 @@ intrastage_match(interface_block_definition *a,
return false; return false;
} }
/* Array vs. nonarray must be consistent, and sizes must be /* If a block is an array then it must match across the shader.
* consistent, with the exception that unsized arrays match sized * Unsized arrays are also processed and matched agaist sized arrays.
* 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; 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; return true;
} }
@ -153,8 +145,8 @@ interstage_match(const interface_block_definition *producer,
/* Unsized arrays should not occur during interstage linking. They /* Unsized arrays should not occur during interstage linking. They
* should have all been assigned a size by link_intrastage_shaders. * should have all been assigned a size by link_intrastage_shaders.
*/ */
assert(consumer->array_size != 0); assert(!consumer->var->type->is_unsized_array());
assert(producer->array_size != 0); assert(!producer->var->type->is_unsized_array());
/* Types must match. */ /* Types must match. */
if (consumer->type != producer->type) { if (consumer->type != producer->type) {
@ -165,20 +157,27 @@ interstage_match(const interface_block_definition *producer,
if (consumer->explicitly_declared || producer->explicitly_declared) if (consumer->explicitly_declared || producer->explicitly_declared)
return false; return false;
} }
/* Ignore outermost array if geom shader */
const glsl_type *consumer_instance_type;
if (extra_array_level) { if (extra_array_level) {
/* Consumer must be an array, and producer must not. */ consumer_instance_type = consumer->var->type->fields.array;
if (consumer->array_size == -1)
return false;
if (producer->array_size != -1)
return false;
} else { } else {
/* Array vs. nonarray must be consistent, and sizes must be consistent. 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 * Since unsized arrays have been ruled out, we can check this by just
* making sure the sizes are equal. * making sure the types are equal.
*/ */
if (consumer->array_size != producer->array_size) 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 false;
} }
return true; return true;
} }
@ -298,7 +297,8 @@ validate_intrastage_interface_blocks(struct gl_shader_program *prog,
*/ */
definitions->store(def); definitions->store(def);
} else if (!intrastage_match(prev_def, &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" linker_error(prog, "definitions of interface block `%s' do not"
" match\n", iface_type->name); " match\n", iface_type->name);
return; return;
@ -374,7 +374,7 @@ validate_interstage_uniform_blocks(struct gl_shader_program *prog,
* uniform matchin rules (for uniforms, it is as though all * uniform matchin rules (for uniforms, it is as though all
* shaders are in the same shader stage). * 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_var_uniform, prog)) {
linker_error(prog, "definitions of interface block `%s' do not " linker_error(prog, "definitions of interface block `%s' do not "
"match\n", var->get_interface_type()->name); "match\n", var->get_interface_type()->name);
return; return;