summaryrefslogtreecommitdiffstats
path: root/src/glsl
diff options
context:
space:
mode:
authorSamuel Iglesias Gonsalvez <[email protected]>2015-04-13 16:17:07 +0200
committerSamuel Iglesias Gonsalvez <[email protected]>2015-09-25 08:39:21 +0200
commit273f61a0051a794d1a39d70fb1dbf46a3ca3c63f (patch)
tree85258cb644dccb440d29429d71dcbb7850f385d7 /src/glsl
parent1440d2a6833902d9c966fe8ad7db46a7f787391c (diff)
glsl: Add parser/compiler support for unsized array's length()
The unsized array length is computed with the following formula: array.length() = max((buffer_object_size - offset_of_array) / stride_of_array, 0) Of these, only the buffer size needs to be provided by the backends, the frontend already knows the values of the two other variables. This patch identifies the cases where we need to get the length of an unsized array, injecting ir_unop_ssbo_unsized_array_length expressions that will be lowered (in a later patch) to inject the formula mentioned above. It also adds the ir_unop_get_buffer_size expression that drivers will implement to provide the buffer length. v2: - Do not define a triop that will force backends to implement the entire formula, they should only need to provide the buffer size since the other values are known by the frontend (Curro). v3: - Call state->has_shader_storage_buffer_objects() in ast_function.cpp instead of using state->ARB_shader_storage_buffer_object_enable (Tapani). Signed-off-by: Samuel Iglesias Gonsalvez <[email protected]> Reviewed-by: Kristian Høgsberg <[email protected]>
Diffstat (limited to 'src/glsl')
-rw-r--r--src/glsl/ast_function.cpp13
-rw-r--r--src/glsl/ir.cpp7
-rw-r--r--src/glsl/ir.h19
-rw-r--r--src/glsl/ir_validate.cpp11
-rw-r--r--src/glsl/link_uniforms.cpp10
5 files changed, 53 insertions, 7 deletions
diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
index 803edf5a14d..ff5ecb954f0 100644
--- a/src/glsl/ast_function.cpp
+++ b/src/glsl/ast_function.cpp
@@ -1593,11 +1593,16 @@ ast_function_expression::handle_method(exec_list *instructions,
if (op->type->is_array()) {
if (op->type->is_unsized_array()) {
- _mesa_glsl_error(&loc, state, "length called on unsized array");
- goto fail;
+ if (!state->has_shader_storage_buffer_objects()) {
+ _mesa_glsl_error(&loc, state, "length called on unsized array"
+ " only available with "
+ "ARB_shader_storage_buffer_object");
+ }
+ /* Calculate length of an unsized array in run-time */
+ result = new(ctx) ir_expression(ir_unop_ssbo_unsized_array_length, op);
+ } else {
+ result = new(ctx) ir_constant(op->type->array_size());
}
-
- result = new(ctx) ir_constant(op->type->array_size());
} else if (op->type->is_vector()) {
if (state->ARB_shading_language_420pack_enable) {
/* .length() returns int. */
diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp
index b9df9761920..2c45b9edc0f 100644
--- a/src/glsl/ir.cpp
+++ b/src/glsl/ir.cpp
@@ -342,6 +342,11 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
op0->type->vector_elements, 1);
break;
+ case ir_unop_get_buffer_size:
+ case ir_unop_ssbo_unsized_array_length:
+ this->type = glsl_type::int_type;
+ break;
+
default:
assert(!"not reached: missing automatic type setup for ir_expression");
this->type = op0->type;
@@ -571,6 +576,8 @@ static const char *const operator_strs[] = {
"noise",
"subroutine_to_int",
"interpolate_at_centroid",
+ "get_buffer_size",
+ "ssbo_unsized_array_length",
"+",
"-",
"*",
diff --git a/src/glsl/ir.h b/src/glsl/ir.h
index 48b6795cc09..43a2bf0ae1c 100644
--- a/src/glsl/ir.h
+++ b/src/glsl/ir.h
@@ -1425,9 +1425,26 @@ enum ir_expression_operation {
ir_unop_interpolate_at_centroid,
/**
+ * Ask the driver for the total size of a buffer block.
+ *
+ * operand0 is the ir_constant buffer block index in the linked shader.
+ */
+ ir_unop_get_buffer_size,
+
+ /**
+ * Calculate length of an unsized array inside a buffer block.
+ * This opcode is going to be replaced in a lowering pass inside
+ * the linker.
+ *
+ * operand0 is the unsized array's ir_value for the calculation
+ * of its length.
+ */
+ ir_unop_ssbo_unsized_array_length,
+
+ /**
* A sentinel marking the last of the unary operations.
*/
- ir_last_unop = ir_unop_interpolate_at_centroid,
+ ir_last_unop = ir_unop_ssbo_unsized_array_length,
ir_binop_add,
ir_binop_sub,
diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp
index 3f0dea74e27..935571ae1d6 100644
--- a/src/glsl/ir_validate.cpp
+++ b/src/glsl/ir_validate.cpp
@@ -409,6 +409,17 @@ ir_validate::visit_leave(ir_expression *ir)
assert(ir->operands[0]->type->is_float());
break;
+ case ir_unop_get_buffer_size:
+ assert(ir->type == glsl_type::int_type);
+ assert(ir->operands[0]->type == glsl_type::uint_type);
+ break;
+
+ case ir_unop_ssbo_unsized_array_length:
+ assert(ir->type == glsl_type::int_type);
+ assert(ir->operands[0]->type->is_array());
+ assert(ir->operands[0]->type->is_unsized_array());
+ break;
+
case ir_unop_d2f:
assert(ir->operands[0]->type->base_type == GLSL_TYPE_DOUBLE);
assert(ir->type->base_type == GLSL_TYPE_FLOAT);
diff --git a/src/glsl/link_uniforms.cpp b/src/glsl/link_uniforms.cpp
index 238546ba22e..67a6e1bea17 100644
--- a/src/glsl/link_uniforms.cpp
+++ b/src/glsl/link_uniforms.cpp
@@ -231,9 +231,15 @@ program_resource_visitor::recursion(const glsl_type *t, char **name,
if (record_type == NULL && t->fields.array->is_record())
record_type = t->fields.array;
- record_array_count *= t->length;
+ unsigned length = t->length;
+ /* Shader storage block unsized arrays: add subscript [0] to variable
+ * names */
+ if (t->is_unsized_array())
+ length = 1;
- for (unsigned i = 0; i < t->length; i++) {
+ record_array_count *= length;
+
+ for (unsigned i = 0; i < length; i++) {
size_t new_length = name_length;
/* Append the subscript to the current variable name */