On Sat, 2015-06-20 at 22:33 +1000, Timothy Arceri wrote: > From Section 4.1.9 of the GLSL ES 3.10 spec: > > "Arrays are sized either at compile-time or at run-time. > To size an array at compile-time, either the size > must be specified within the brackets as above or > must be inferred from the type of the initializer." > --- > src/glsl/ast.h | 21 +++--------- > src/glsl/ast_array_index.cpp | 7 ++-- > src/glsl/ast_function.cpp | 33 +++++++++++++++++- > src/glsl/ast_to_hir.cpp | 80 > ++++++++++++++++++++++++++++++++++---------- > src/glsl/glsl_parser.yy | 11 +++--- > 5 files changed, 107 insertions(+), 45 deletions(-) > > diff --git a/src/glsl/ast.h b/src/glsl/ast.h > index 3f67907..0f9dbf9 100644 > --- a/src/glsl/ast.h > +++ b/src/glsl/ast.h > @@ -181,6 +181,7 @@ enum ast_operators { > ast_post_dec, > ast_field_selection, > ast_array_index, > + ast_unsized_array_dim, > > ast_function_call, > > @@ -308,16 +309,7 @@ private: > > class ast_array_specifier : public ast_node { > public: > - /** Unsized array specifier ([]) */ > - explicit ast_array_specifier(const struct YYLTYPE &locp) > - : is_unsized_array(true) > - { > - set_location(locp); > - } > - > - /** Sized array specifier ([dim]) */ > ast_array_specifier(const struct YYLTYPE &locp, ast_expression *dim) > - : is_unsized_array(false) > { > set_location(locp); > array_dimensions.push_tail(&dim->link); > @@ -330,19 +322,14 @@ public: > > bool is_single_dimension() > { > - return (this->is_unsized_array && this->array_dimensions.is_empty()) || > - (!this->is_unsized_array && > - this->array_dimensions.tail_pred->prev != NULL && > - this->array_dimensions.tail_pred->prev->is_head_sentinel()); > + return this->array_dimensions.tail_pred->prev != NULL && > + this->array_dimensions.tail_pred->prev->is_head_sentinel(); > } > > virtual void print(void) const; > > - /* If true, this means that the array has an unsized outermost dimension. > */ > - bool is_unsized_array; > - > /* This list contains objects of type ast_node containing the > - * sized dimensions only, in outermost-to-innermost order. > + * array dimensions in outermost-to-innermost order. > */ > exec_list array_dimensions; > }; > diff --git a/src/glsl/ast_array_index.cpp b/src/glsl/ast_array_index.cpp > index 752d86f..89c08d8 100644 > --- a/src/glsl/ast_array_index.cpp > +++ b/src/glsl/ast_array_index.cpp > @@ -28,13 +28,10 @@ > void > ast_array_specifier::print(void) const > { > - if (this->is_unsized_array) { > - printf("[ ] "); > - } > - > foreach_list_typed (ast_node, array_dimension, link, > &this->array_dimensions) { > printf("[ "); > - array_dimension->print(); > + if (((ast_expression*)array_dimension)->oper != ast_unsized_array_dim) > + array_dimension->print(); > printf("] "); > } > } > diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp > index 92e26bf..0906040 100644 > --- a/src/glsl/ast_function.cpp > +++ b/src/glsl/ast_function.cpp > @@ -870,6 +870,7 @@ process_array_constructor(exec_list *instructions, > } > > bool all_parameters_are_constant = true; > + const glsl_type *element_type = constructor_type->fields.array; > > /* Type cast each parameter and, if possible, fold constants. */ > foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) { > @@ -896,12 +897,34 @@ process_array_constructor(exec_list *instructions, > } > } > > - if (result->type != constructor_type->fields.array) { > + if (constructor_type->fields.array->is_unsized_array()) { > + /* As the inner parameters of the constructor are created without > + * knowledge of each other we need to check to make sure unsized > + * parameters of unsized constructors all end up with the same size. > + * > + * e.g we make sure to fail for a constructor like this: > + * vec4[][] a = vec4[][](vec4[](vec4(0.0), vec4(1.0)), > + * vec4[](vec4(0.0), vec4(1.0), vec4(1.0)), > + * vec4[](vec4(0.0), vec4(1.0))); > + */ > + if (element_type->is_unsized_array()) { > + /* This is the first parameter so just get the type */ > + element_type = result->type; > + } else if (element_type != result->type) { > + _mesa_glsl_error(loc, state, "type error in array constructor: " > + "expected: %s, found %s", > + element_type->name, > + result->type->name); > + return ir_rvalue::error_value(ctx); > + } > + } else if (result->type != constructor_type->fields.array) { > _mesa_glsl_error(loc, state, "type error in array constructor: " > "expected: %s, found %s", > constructor_type->fields.array->name, > result->type->name); > return ir_rvalue::error_value(ctx); > + } else { > + element_type = result->type; > } > > /* Attempt to convert the parameter to a constant valued expression. > @@ -918,6 +941,14 @@ process_array_constructor(exec_list *instructions, > ir->replace_with(result); > } > > + if (constructor_type->fields.array->is_unsized_array()) { > + constructor_type = > + glsl_type::get_array_instance(element_type, > + parameter_count); > + assert(constructor_type != NULL); > + assert(constructor_type->length == parameter_count); > + } > + > if (all_parameters_are_constant) > return new(ctx) ir_constant(constructor_type, &actual_parameters); > > diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp > index de13060..6d2dc2e 100644 > --- a/src/glsl/ast_to_hir.cpp > +++ b/src/glsl/ast_to_hir.cpp > @@ -677,8 +677,30 @@ validate_assignment(struct _mesa_glsl_parse_state *state, > * Note: Whole-array assignments are not permitted in GLSL 1.10, but this > * is handled by ir_dereference::is_lvalue. > */ > - if (lhs_type->is_unsized_array() && rhs->type->is_array() > - && (lhs_type->fields.array == rhs->type->fields.array)) { > + const glsl_type *lhs_t = lhs_type; > + const glsl_type *rhs_t = rhs->type; > + bool unsized_array = false; > + while(lhs_t->is_array()) { > + if (rhs_t == lhs_t) > + break; /* the rest of the inner arrays match so break out early */ > + if (!rhs_t->is_array()) { > + unsized_array = false; > + break; /* number of dimensions mismatch */ > + } > + if (lhs_t->length == rhs_t->length) { > + lhs_t = lhs_t->fields.array; > + rhs_t = rhs_t->fields.array; > + continue; > + } else if (lhs_t->is_unsized_array()) { > + unsized_array = true; > + } else { > + unsized_array = false; > + break; /* sized array mismatch */ > + } > + lhs_t = lhs_t->fields.array; > + rhs_t = rhs_t->fields.array; > + } > + if (unsized_array) { > if (is_initializer) { > return rhs; > } else { > @@ -1682,6 +1704,10 @@ ast_expression::do_hir(exec_list *instructions, > break; > } > > + case ast_unsized_array_dim: > + assert(!"ast_unsized_array_dim: Should never get here."); > + break; > + > case ast_function_call: > /* Should *NEVER* get here. ast_function_call should always be handled > * by ast_function_expression::hir. > @@ -1845,6 +1871,14 @@ process_array_size(exec_node *node, > exec_list dummy_instructions; > > ast_node *array_size = exec_node_data(ast_node, node, link); > + > + /** > + * Dimensions other than the outermost dimension can by unsized if they > + * are immediately sized by a constructor or initializer. > + */ > + if (((ast_expression*)array_size)->oper == ast_unsized_array_dim) > + return 0; > + > ir_rvalue *const ir = array_size->hir(& dummy_instructions, state); > YYLTYPE loc = array_size->get_location(); > > @@ -1913,14 +1947,6 @@ process_array_type(YYLTYPE *loc, const glsl_type *base, > base->name); > return glsl_type::error_type; > } > - > - if (base->length == 0) { > - _mesa_glsl_error(loc, state, > - "only the outermost array dimension can " > - "be unsized", > - base->name); > - return glsl_type::error_type; > - } > } > > for (exec_node *node = array_specifier->array_dimensions.tail_pred; > @@ -1928,9 +1954,6 @@ process_array_type(YYLTYPE *loc, const glsl_type *base, > unsigned array_size = process_array_size(node, state); > array_type = glsl_type::get_array_instance(array_type, array_size); > } > - > - if (array_specifier->is_unsized_array) > - array_type = glsl_type::get_array_instance(array_type, 0); > } > > return array_type; > @@ -2407,6 +2430,25 @@ is_conflicting_fragcoord_redeclaration(struct > _mesa_glsl_parse_state *state, > return false; > } > > +static inline void > +validate_array_dimensions(const glsl_type *t, > + struct _mesa_glsl_parse_state *state, > + YYLTYPE *loc) { > + if (t->is_array()) { > + t = t->fields.array; > + while (t->is_array()) { > + if (t->is_unsized_array()) { > + _mesa_glsl_error(loc, state, > + "only the outermost array dimension can " > + "be unsized", > + t->name); > + break; > + } > + t = t->fields.array; > + } > + } > +} > + > static void > apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, > ir_variable *var, > @@ -3927,6 +3969,8 @@ ast_declarator_list::hir(exec_list *instructions, > result = process_initializer((earlier == NULL) ? var : earlier, > decl, this->type, > &initializer_instructions, state); > + } else { > + validate_array_dimensions(var_type, state, &loc); > } > > /* From page 23 (page 29 of the PDF) of the GLSL 1.10 spec: > @@ -5384,6 +5428,7 @@ ast_process_structure_or_interface_block(exec_list > *instructions, > > field_type = process_array_type(&loc, decl_type, > decl->array_specifier, state); > + validate_array_dimensions(field_type, state, &loc); > fields[i].type = field_type; > fields[i].name = decl->identifier; > fields[i].location = -1; > @@ -5810,6 +5855,9 @@ ast_interface_block::hir(exec_list *instructions, > ir_variable *var; > > if (this->array_specifier != NULL) { > + const glsl_type *block_array_type = > + process_array_type(&loc, block_type, this->array_specifier, > state); > + > /* Section 4.3.7 (Interface Blocks) of the GLSL 1.50 spec says: > * > * For uniform blocks declared an array, each individual array > @@ -5829,16 +5877,14 @@ ast_interface_block::hir(exec_list *instructions, > * interface array size *doesn't* need to be specified is on a > * geometry shader input. > */ > - if (this->array_specifier->is_unsized_array && > + if (block_array_type->is_unsized_array() && > (state->stage != MESA_SHADER_GEOMETRY || > !this->layout.flags.q.in)) { > _mesa_glsl_error(&loc, state, > "only geometry shader inputs may be unsized " > "instance block arrays"); > > } > - > - const glsl_type *block_array_type = > - process_array_type(&loc, block_type, this->array_specifier, > state); > +//TODO: make sure no other array dimensions are unsized arrays ??
Just noticed I left this comment in, will remove it. I will need to add extra validation here for desktop support but not for the ES as interface blocks can't be AoA in ES. > > /* From section 4.3.9 (Interface Blocks) of the GLSL ES 3.10 spec: > * > diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy > index 3ce9e10..1f08893 100644 > --- a/src/glsl/glsl_parser.yy > +++ b/src/glsl/glsl_parser.yy > @@ -1840,7 +1840,9 @@ array_specifier: > '[' ']' > { > void *ctx = state; > - $$ = new(ctx) ast_array_specifier(@1); > + $$ = new(ctx) ast_array_specifier(@1, new(ctx) ast_expression( > + ast_unsized_array_dim, > NULL, > + NULL, NULL)); > $$->set_location_range(@1, @2); > } > | '[' constant_expression ']' > @@ -1851,17 +1853,16 @@ array_specifier: > } > | array_specifier '[' ']' > { > + void *ctx = state; > $$ = $1; > > if (!state->ARB_arrays_of_arrays_enable) { > _mesa_glsl_error(& @1, state, > "GL_ARB_arrays_of_arrays " > "required for defining arrays of arrays"); > - } else { > - _mesa_glsl_error(& @1, state, > - "only the outermost array dimension can " > - "be unsized"); > } > + $$->add_dimension(new(ctx) ast_expression(ast_unsized_array_dim, NULL, > + NULL, NULL)); > } > | array_specifier '[' constant_expression ']' > { _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev