diff options
-rw-r--r-- | src/glsl/ast_array_index.cpp | 3 | ||||
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 74 | ||||
-rw-r--r-- | src/glsl/ir.cpp | 1 | ||||
-rw-r--r-- | src/glsl/ir.h | 14 | ||||
-rw-r--r-- | src/glsl/linker.cpp | 107 |
5 files changed, 150 insertions, 49 deletions
diff --git a/src/glsl/ast_array_index.cpp b/src/glsl/ast_array_index.cpp index ae399f03a9b..dfb31073f82 100644 --- a/src/glsl/ast_array_index.cpp +++ b/src/glsl/ast_array_index.cpp @@ -226,7 +226,8 @@ _mesa_ast_array_index_to_hir(void *mem_ctx, * by the linker. */ } - else { + else if (array->variable_referenced()->data.mode != + ir_var_shader_storage) { _mesa_glsl_error(&loc, state, "unsized array index must be constant"); } } else if (array->type->fields.array->is_interface() diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index b67ae704bb0..92038a62d81 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -5880,6 +5880,19 @@ private: bool found; }; +static bool +is_unsized_array_last_element(ir_variable *v) +{ + const glsl_type *interface_type = v->get_interface_type(); + int length = interface_type->length; + + assert(v->type->is_unsized_array()); + + /* Check if it is the last element of the interface */ + if (strcmp(interface_type->fields.structure[length-1].name, v->name) == 0) + return true; + return false; +} ir_rvalue * ast_interface_block::hir(exec_list *instructions, @@ -6253,18 +6266,29 @@ ast_interface_block::hir(exec_list *instructions, handle_tess_ctrl_shader_output_decl(state, loc, var); for (unsigned i = 0; i < num_variables; i++) { - /* From GLSL ES 3.10 spec, section 4.1.9 "Arrays": - * - * "If an array is declared as the last member of a shader storage - * block and the size is not specified at compile-time, it is - * sized at run-time. In all other cases, arrays are sized only - * at compile-time." - */ - if (state->es_shader && fields[i].type->is_unsized_array()) { - _mesa_glsl_error(&loc, state, "unsized array `%s' definition: " - "only last member of a shader storage block " - "can be defined as unsized array", - fields[i].name); + if (fields[i].type->is_unsized_array()) { + if (var_mode == ir_var_shader_storage) { + if (i != (num_variables - 1)) { + _mesa_glsl_error(&loc, state, "unsized array `%s' definition: " + "only last member of a shader storage block " + "can be defined as unsized array", + fields[i].name); + } + } else { + /* From GLSL ES 3.10 spec, section 4.1.9 "Arrays": + * + * "If an array is declared as the last member of a shader storage + * block and the size is not specified at compile-time, it is + * sized at run-time. In all other cases, arrays are sized only + * at compile-time." + */ + if (state->es_shader) { + _mesa_glsl_error(&loc, state, "unsized array `%s' definition: " + "only last member of a shader storage block " + "can be defined as unsized array", + fields[i].name); + } + } } } @@ -6359,6 +6383,32 @@ ast_interface_block::hir(exec_list *instructions, var->data.explicit_binding = this->layout.flags.q.explicit_binding; var->data.binding = this->layout.binding; + if (var->type->is_unsized_array()) { + if (var->is_in_shader_storage_block()) { + if (!is_unsized_array_last_element(var)) { + _mesa_glsl_error(&loc, state, "unsized array `%s' definition: " + "only last member of a shader storage block " + "can be defined as unsized array", + var->name); + } + var->data.from_ssbo_unsized_array = true; + } else { + /* From GLSL ES 3.10 spec, section 4.1.9 "Arrays": + * + * "If an array is declared as the last member of a shader storage + * block and the size is not specified at compile-time, it is + * sized at run-time. In all other cases, arrays are sized only + * at compile-time." + */ + if (state->es_shader) { + _mesa_glsl_error(&loc, state, "unsized array `%s' definition: " + "only last member of a shader storage block " + "can be defined as unsized array", + var->name); + } + } + } + state->symbols->add_variable(var); instructions->push_tail(var); } diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index fb58c3b4ef6..b9df9761920 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -1658,6 +1658,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name, this->data.image_coherent = false; this->data.image_volatile = false; this->data.image_restrict = false; + this->data.from_ssbo_unsized_array = false; if (type != NULL) { if (type->base_type == GLSL_TYPE_SAMPLER) diff --git a/src/glsl/ir.h b/src/glsl/ir.h index cf1954b1257..48b6795cc09 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -453,6 +453,15 @@ public: } /** + * Determine whether or not a variable is part of a shader storage block. + */ + inline bool is_in_shader_storage_block() const + { + return this->data.mode == ir_var_shader_storage && + this->interface_type != NULL; + } + + /** * Determine whether or not a variable is the declaration of an interface * block * @@ -778,6 +787,11 @@ public: unsigned image_restrict:1; /** + * ARB_shader_storage_buffer_object + */ + unsigned from_ssbo_unsized_array:1; /**< unsized array buffer variable. */ + + /** * Emit a warning if this variable is accessed. */ private: diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 53e276cc589..47d8b5ad1bf 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -877,30 +877,40 @@ validate_intrastage_arrays(struct gl_shader_program *prog, * In addition, set the type of the linked variable to the * explicitly sized array. */ - if (var->type->is_array() && existing->type->is_array() && - (var->type->fields.array == existing->type->fields.array) && - ((var->type->length == 0)|| (existing->type->length == 0))) { - if (var->type->length != 0) { - if (var->type->length <= existing->data.max_array_access) { - linker_error(prog, "%s `%s' declared as type " - "`%s' but outermost dimension has an index" - " of `%i'\n", - mode_string(var), - var->name, var->type->name, - existing->data.max_array_access); - } - existing->type = var->type; - return true; - } else if (existing->type->length != 0) { - if(existing->type->length <= var->data.max_array_access) { - linker_error(prog, "%s `%s' declared as type " - "`%s' but outermost dimension has an index" - " of `%i'\n", - mode_string(var), - var->name, existing->type->name, - var->data.max_array_access); + if (var->type->is_array() && existing->type->is_array()) { + if ((var->type->fields.array == existing->type->fields.array) && + ((var->type->length == 0)|| (existing->type->length == 0))) { + if (var->type->length != 0) { + if (var->type->length <= existing->data.max_array_access) { + linker_error(prog, "%s `%s' declared as type " + "`%s' but outermost dimension has an index" + " of `%i'\n", + mode_string(var), + var->name, var->type->name, + existing->data.max_array_access); + } + existing->type = var->type; + return true; + } else if (existing->type->length != 0) { + if(existing->type->length <= var->data.max_array_access && + !existing->data.from_ssbo_unsized_array) { + linker_error(prog, "%s `%s' declared as type " + "`%s' but outermost dimension has an index" + " of `%i'\n", + mode_string(var), + var->name, existing->type->name, + var->data.max_array_access); + } + return true; } - return true; + } else { + /* The arrays of structs could have different glsl_type pointers but + * they are actually the same type. Use record_compare() to check that. + */ + if (existing->type->fields.array->is_record() && + var->type->fields.array->is_record() && + existing->type->fields.array->record_compare(var->type->fields.array)) + return true; } } return false; @@ -959,12 +969,24 @@ cross_validate_globals(struct gl_shader_program *prog, && existing->type->record_compare(var->type)) { existing->type = var->type; } else { - linker_error(prog, "%s `%s' declared as type " - "`%s' and type `%s'\n", - mode_string(var), - var->name, var->type->name, - existing->type->name); - return; + /* If it is an unsized array in a Shader Storage Block, + * two different shaders can access to different elements. + * Because of that, they might be converted to different + * sized arrays, then check that they are compatible but + * ignore the array size. + */ + if (!(var->data.mode == ir_var_shader_storage && + var->data.from_ssbo_unsized_array && + existing->data.mode == ir_var_shader_storage && + existing->data.from_ssbo_unsized_array && + var->type->gl_type == existing->type->gl_type)) { + linker_error(prog, "%s `%s' declared as type " + "`%s' and type `%s'\n", + mode_string(var), + var->name, var->type->name, + existing->type->name); + return; + } } } } @@ -1364,12 +1386,14 @@ public: virtual ir_visitor_status visit(ir_variable *var) { - fixup_type(&var->type, var->data.max_array_access); + fixup_type(&var->type, var->data.max_array_access, + var->data.from_ssbo_unsized_array); if (var->type->is_interface()) { if (interface_contains_unsized_arrays(var->type)) { const glsl_type *new_type = resize_interface_members(var->type, - var->get_max_ifc_array_access()); + var->get_max_ifc_array_access(), + var->is_in_shader_storage_block()); var->type = new_type; var->change_interface_type(new_type); } @@ -1378,7 +1402,8 @@ public: if (interface_contains_unsized_arrays(var->type->fields.array)) { const glsl_type *new_type = resize_interface_members(var->type->fields.array, - var->get_max_ifc_array_access()); + var->get_max_ifc_array_access(), + var->is_in_shader_storage_block()); var->change_interface_type(new_type); var->type = update_interface_members_array(var->type, new_type); } @@ -1419,9 +1444,10 @@ 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) + static void fixup_type(const glsl_type **type, unsigned max_array_access, + bool from_ssbo_unsized_array) { - if ((*type)->is_unsized_array()) { + if (!from_ssbo_unsized_array && (*type)->is_unsized_array()) { *type = glsl_type::get_array_instance((*type)->fields.array, max_array_access + 1); assert(*type != NULL); @@ -1464,14 +1490,23 @@ private: */ static const glsl_type * resize_interface_members(const glsl_type *type, - const unsigned *max_ifc_array_access) + const unsigned *max_ifc_array_access, + bool is_ssbo) { 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]); + /* If SSBO last member is unsized array, we don't replace it by a sized + * array. + */ + if (is_ssbo && i == (num_fields - 1)) + fixup_type(&fields[i].type, max_ifc_array_access[i], + true); + else + fixup_type(&fields[i].type, max_ifc_array_access[i], + false); } glsl_interface_packing packing = (glsl_interface_packing) type->interface_packing; |