glsl/linker: Modify array_sizing_visitor to handle named interface blocks.

Unsized arrays appearing inside named interface blocks now get a
proper size assigned by the array_sizing_visitor.

Fixes piglit tests:
- spec/glsl-1.50/execution/unsized-in-named-interface-block
- spec/glsl-1.50/execution/unsized-in-named-interface-block-gs
- spec/glsl-1.50/linker/unsized-in-named-interface-block
- spec/glsl-1.50/linker/unsized-in-named-interface-block-gs
- spec/glsl-1.50/linker/unsized-in-unnamed-interface-block-gs (*)

(*) is fixed by dumb luck--support for unsized arrays in unnamed
interface blocks will come in a later patch.

Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
Paul Berry
2013-09-23 10:44:19 -07:00
parent f878d2060c
commit e226669eea
2 changed files with 87 additions and 6 deletions
+16
View File
@@ -404,6 +404,22 @@ public:
}
}
/**
* Change this->interface_type on a variable that previously had a
* different interface_type. This is used during linking to set the size
* of arrays in interface blocks.
*/
void change_interface_type(const struct glsl_type *type)
{
if (this->max_ifc_array_access != NULL) {
/* max_ifc_array_access has already been allocated, so make sure the
* new interface has the same number of fields as the old one.
*/
assert(this->interface_type->length == type->length);
}
this->interface_type = type;
}
const glsl_type *get_interface_type() const
{
return this->interface_type;
+71 -6
View File
@@ -1035,15 +1035,80 @@ class array_sizing_visitor : public ir_hierarchical_visitor {
public:
virtual ir_visitor_status visit(ir_variable *var)
{
if (var->type->is_array() && (var->type->length == 0)) {
const glsl_type *type =
glsl_type::get_array_instance(var->type->fields.array,
var->max_array_access + 1);
assert(type != NULL);
var->type = type;
fixup_type(&var->type, var->max_array_access);
if (var->type->is_interface()) {
if (interface_contains_unsized_arrays(var->type)) {
const glsl_type *new_type =
resize_interface_members(var->type, var->max_ifc_array_access);
var->type = new_type;
var->change_interface_type(new_type);
}
} else if (var->type->is_array() &&
var->type->fields.array->is_interface()) {
if (interface_contains_unsized_arrays(var->type->fields.array)) {
const glsl_type *new_type =
resize_interface_members(var->type->fields.array,
var->max_ifc_array_access);
var->change_interface_type(new_type);
var->type =
glsl_type::get_array_instance(new_type, var->type->length);
}
}
return visit_continue;
}
private:
/**
* If the type pointed to by \c type represents an unsized array, replace
* it with a sized array whose size is determined by max_array_access.
*/
static void fixup_type(const glsl_type **type, unsigned max_array_access)
{
if ((*type)->is_array() && (*type)->length == 0) {
*type = glsl_type::get_array_instance((*type)->fields.array,
max_array_access + 1);
assert(*type != NULL);
}
}
/**
* Determine whether the given interface type contains unsized arrays (if
* it doesn't, array_sizing_visitor doesn't need to process it).
*/
static bool interface_contains_unsized_arrays(const glsl_type *type)
{
for (unsigned i = 0; i < type->length; i++) {
const glsl_type *elem_type = type->fields.structure[i].type;
if (elem_type->is_array() && elem_type->length == 0)
return true;
}
return false;
}
/**
* Create a new interface type based on the given type, with unsized arrays
* replaced by sized arrays whose size is determined by
* max_ifc_array_access.
*/
static const glsl_type *
resize_interface_members(const glsl_type *type,
const unsigned *max_ifc_array_access)
{
unsigned num_fields = type->length;
glsl_struct_field *fields = new glsl_struct_field[num_fields];
memcpy(fields, type->fields.structure,
num_fields * sizeof(*fields));
for (unsigned i = 0; i < num_fields; i++) {
fixup_type(&fields[i].type, max_ifc_array_access[i]);
}
glsl_interface_packing packing =
(glsl_interface_packing) type->interface_packing;
const glsl_type *new_ifc_type =
glsl_type::get_interface_instance(fields, num_fields,
packing, type->name);
delete [] fields;
return new_ifc_type;
}
};
/**