[Mesa-dev] [PATCH v4 (part2) 12/59] glsl: Add parser/compiler support for unsized array's length()

Iago Toral Quiroga itoral at igalia.com
Wed Aug 5 01:30:09 PDT 2015


From: Samuel Iglesias Gonsalvez <siglesias at igalia.com>

It also creates unop and triop expressions to tell the driver to
calculate the unsized array length.

Two expressions are needed to do the calculation:

* The unop expression saves the ir_rvalue* whose length should be
  calculated.
* Afterwards, this unop is going to be processed by a lowering pass
  that will convert it to a triop that includes the block index,
  offset of the variable inside the shader storage block and the array
  stride. All of them are needed for length() calculation following
  GL_ARB_shader_storage_buffer spec:

   array.length() =
      max((buffer_object_size - offset_of_array) / stride_of_array, 0)

Signed-off-by: Samuel Iglesias Gonsalvez <siglesias at igalia.com>
Reviewed-by: Jordan Justen <jordan.l.justen at intel.com>
---
 src/glsl/ast_function.cpp                           | 13 +++++++++----
 src/glsl/ir.cpp                                     |  9 +++++++++
 src/glsl/ir.h                                       | 21 ++++++++++++++++++++-
 src/glsl/ir_validate.cpp                            | 13 +++++++++++++
 src/glsl/link_uniforms.cpp                          |  8 +++++++-
 .../drivers/dri/i965/brw_fs_channel_expressions.cpp |  2 ++
 src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp      |  8 ++++++++
 src/mesa/program/ir_to_mesa.cpp                     |  2 ++
 src/mesa/state_tracker/st_glsl_to_tgsi.cpp          |  5 +++++
 9 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
index 803edf5..0fb8928 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->ARB_shader_storage_buffer_object_enable) {
+               _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 594fc33..5b8882b 100644
--- a/src/glsl/ir.cpp
+++ b/src/glsl/ir.cpp
@@ -341,6 +341,9 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
       this->type = glsl_type::get_instance(GLSL_TYPE_INT,
 					   op0->type->vector_elements, 1);
       break;
+   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");
@@ -472,6 +475,10 @@ ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1,
       this->type = op1->type;
       break;
 
+   case ir_triop_ssbo_unsized_array_length:
+      this->type = glsl_type::int_type;
+      break;
+
    default:
       assert(!"not reached: missing automatic type setup for ir_expression");
       this->type = glsl_type::float_type;
@@ -571,6 +578,7 @@ static const char *const operator_strs[] = {
    "noise",
    "subroutine_to_int",
    "interpolate_at_centroid",
+   "ssbo_unsized_array_length_parser",
    "+",
    "-",
    "*",
@@ -611,6 +619,7 @@ static const char *const operator_strs[] = {
    "csel",
    "bfi",
    "bitfield_extract",
+   "ssbo_unsized_array_length",
    "vector_insert",
    "bitfield_insert",
    "vector",
diff --git a/src/glsl/ir.h b/src/glsl/ir.h
index 822a8a3..487a755 100644
--- a/src/glsl/ir.h
+++ b/src/glsl/ir.h
@@ -1423,9 +1423,19 @@ enum ir_expression_operation {
    ir_unop_interpolate_at_centroid,
 
    /**
+    * 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,
@@ -1597,6 +1607,15 @@ enum ir_expression_operation {
    ir_triop_bitfield_extract,
 
    /**
+    * Calculate length of an unsized array inside a buffer block.
+    *
+    * operand0 is the ir_constant buffer block index in the linked shader.
+    * operand1 is a byte offset of the unsized array inside the buffer block
+    * operand2 is the array stride if the unsized array were sized.
+    */
+   ir_triop_ssbo_unsized_array_length,
+
+   /**
     * Generate a value with one field of a vector changed
     *
     * operand0 is the vector
diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp
index 3f0dea7..5afd1b0 100644
--- a/src/glsl/ir_validate.cpp
+++ b/src/glsl/ir_validate.cpp
@@ -409,6 +409,12 @@ ir_validate::visit_leave(ir_expression *ir)
       assert(ir->operands[0]->type->is_float());
       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);
@@ -658,6 +664,13 @@ ir_validate::visit_leave(ir_expression *ir)
       assert(ir->operands[3]->type == glsl_type::int_type);
       break;
 
+   case ir_triop_ssbo_unsized_array_length:
+      assert(ir->type == glsl_type::int_type);
+      assert(ir->operands[0]->type == glsl_type::uint_type);
+      assert(ir->operands[1]->type == glsl_type::uint_type);
+      assert(ir->operands[2]->type == glsl_type::uint_type);
+      break;
+
    case ir_quadop_vector:
       /* The vector operator collects some number of scalars and generates a
        * vector from them.
diff --git a/src/glsl/link_uniforms.cpp b/src/glsl/link_uniforms.cpp
index 254086d..4dcb2fb 100644
--- a/src/glsl/link_uniforms.cpp
+++ b/src/glsl/link_uniforms.cpp
@@ -222,7 +222,13 @@ program_resource_visitor::recursion(const glsl_type *t, char **name,
       if (record_type == NULL && t->fields.array->is_record())
          record_type = t->fields.array;
 
-      for (unsigned i = 0; i < t->length; i++) {
+      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 < length; i++) {
 	 size_t new_length = name_length;
 
 	 /* Append the subscript to the current variable name */
diff --git a/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp
index a8883a3..2864651 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp
@@ -379,6 +379,7 @@ ir_channel_expressions_visitor::visit_leave(ir_assignment *ir)
    }
 
    case ir_binop_ubo_load:
+   case ir_triop_ssbo_unsized_array_length:
       unreachable("not yet supported");
 
    case ir_triop_fma:
@@ -430,6 +431,7 @@ ir_channel_expressions_visitor::visit_leave(ir_assignment *ir)
    case ir_triop_vector_insert:
    case ir_quadop_bitfield_insert:
    case ir_quadop_vector:
+   case ir_unop_ssbo_unsized_array_length:
       unreachable("should have been lowered");
 
    case ir_unop_unpack_half_2x16_split_x:
diff --git a/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp b/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp
index 748853c..1bf2e1b 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp
@@ -1579,6 +1579,10 @@ vec4_visitor::visit(ir_expression *ir)
       emit(MOV(result_dst, op[0]));
       break;
 
+   case ir_unop_ssbo_unsized_array_length:
+      unreachable("not reached: should be handled by lower_ubo_reference");
+      break;
+
    case ir_binop_add:
       emit(ADD(result_dst, op[0], op[1]));
       break;
@@ -1936,6 +1940,10 @@ vec4_visitor::visit(ir_expression *ir)
       emit(BFE(result_dst, op[2], op[1], op[0]));
       break;
 
+   case ir_triop_ssbo_unsized_array_length:
+      unreachable("not reached: not implemented");
+      break;
+
    case ir_triop_vector_insert:
       unreachable("should have been lowered by lower_vector_insert");
 
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
index 8f58f3e..f9baa80 100644
--- a/src/mesa/program/ir_to_mesa.cpp
+++ b/src/mesa/program/ir_to_mesa.cpp
@@ -1344,9 +1344,11 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
    case ir_unop_dFdy_coarse:
    case ir_unop_dFdy_fine:
    case ir_unop_subroutine_to_int:
+   case ir_triop_ssbo_unsized_array_length:
       assert(!"not supported");
       break;
 
+   case ir_unop_ssbo_unsized_array_length:
    case ir_quadop_vector:
       /* This operation should have already been handled.
        */
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 6f00727..a8d2592 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -2194,10 +2194,15 @@ glsl_to_tgsi_visitor::visit(ir_expression *ir)
    case ir_triop_vector_insert:
    case ir_binop_carry:
    case ir_binop_borrow:
+   case ir_unop_ssbo_unsized_array_length:
       /* This operation is not supported, or should have already been handled.
        */
       assert(!"Invalid ir opcode in glsl_to_tgsi_visitor::visit()");
       break;
+
+   case ir_triop_ssbo_unsized_array_length:
+      assert(!"Not implemented yet");
+      break;
    }
 
    this->result = result_src;
-- 
1.9.1



More information about the mesa-dev mailing list