summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glsl/ast_array_index.cpp3
-rw-r--r--src/glsl/ast_to_hir.cpp74
-rw-r--r--src/glsl/ir.cpp1
-rw-r--r--src/glsl/ir.h14
-rw-r--r--src/glsl/linker.cpp107
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;