glsl: add AoA support for atomic counters
[mesa.git] / src / glsl / link_uniform_block_active_visitor.cpp
index 56a8384e9969f1c62c97c9fc8f6636bbf33a1bb9..bcf17fef75803aa98f96c0f8b13df2f5dc63c333 100644 (file)
 link_uniform_block_active *
 process_block(void *mem_ctx, struct hash_table *ht, ir_variable *var)
 {
-   const uint32_t h = _mesa_hash_string(var->interface_type->name);
    const hash_entry *const existing_block =
-      _mesa_hash_table_search(ht, h, var->interface_type->name);
+      _mesa_hash_table_search(ht, var->get_interface_type()->name);
 
    const glsl_type *const block_type = var->is_interface_instance()
-      ? var->type : var->interface_type;
+      ? var->type : var->get_interface_type();
 
 
    /* If a block with this block-name has not previously been seen, add it.
@@ -45,9 +44,17 @@ process_block(void *mem_ctx, struct hash_table *ht, ir_variable *var)
 
       b->type = block_type;
       b->has_instance_name = var->is_interface_instance();
+      b->is_shader_storage = var->data.mode == ir_var_shader_storage;
 
-      _mesa_hash_table_insert(ht, h, var->interface_type->name,
-                             (void *) b);
+      if (var->data.explicit_binding) {
+         b->has_binding = true;
+         b->binding = var->data.binding;
+      } else {
+         b->has_binding = false;
+         b->binding = 0;
+      }
+
+      _mesa_hash_table_insert(ht, var->get_interface_type()->name, (void *) b);
       return b;
    } else {
       link_uniform_block_active *const b =
@@ -64,6 +71,59 @@ process_block(void *mem_ctx, struct hash_table *ht, ir_variable *var)
    return NULL;
 }
 
+ir_visitor_status
+link_uniform_block_active_visitor::visit(ir_variable *var)
+{
+   if (!var->is_in_buffer_block())
+      return visit_continue;
+
+   /* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec says:
+    *
+    *     "All members of a named uniform block declared with a shared or
+    *     std140 layout qualifier are considered active, even if they are not
+    *     referenced in any shader in the program. The uniform block itself is
+    *     also considered active, even if no member of the block is
+    *     referenced."
+    */
+   if (var->get_interface_type()->interface_packing ==
+       GLSL_INTERFACE_PACKING_PACKED)
+      return visit_continue;
+
+   /* Process the block.  Bail if there was an error.
+    */
+   link_uniform_block_active *const b =
+      process_block(this->mem_ctx, this->ht, var);
+   if (b == NULL) {
+      linker_error(this->prog,
+                   "uniform block `%s' has mismatching definitions",
+                   var->get_interface_type()->name);
+      this->success = false;
+      return visit_stop;
+   }
+
+   assert(b->num_array_elements == 0);
+   assert(b->array_elements == NULL);
+   assert(b->type != NULL);
+   assert(!b->type->is_array() || b->has_instance_name);
+
+   /* For uniform block arrays declared with a shared or std140 layout
+    * qualifier, mark all its instances as used.
+    */
+   if (b->type->is_array() && b->type->length > 0) {
+      b->num_array_elements = b->type->length;
+      b->array_elements = reralloc(this->mem_ctx,
+                                   b->array_elements,
+                                   unsigned,
+                                   b->num_array_elements);
+
+      for (unsigned i = 0; i < b->num_array_elements; i++) {
+         b->array_elements[i] = i;
+      }
+   }
+
+   return visit_continue;
+}
+
 ir_visitor_status
 link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
 {
@@ -79,7 +139,7 @@ link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
     * function.
     */
    if (var == NULL
-       || !var->is_in_uniform_block()
+       || !var->is_in_buffer_block()
        || !var->is_interface_instance())
       return visit_continue;
 
@@ -90,7 +150,7 @@ link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
    if (b == NULL) {
       linker_error(prog,
                   "uniform block `%s' has mismatching definitions",
-                  var->interface_type->name);
+                  var->get_interface_type()->name);
       this->success = false;
       return visit_stop;
    }
@@ -101,32 +161,52 @@ link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
    assert((b->num_array_elements == 0) == (b->array_elements == NULL));
    assert(b->type != NULL);
 
-   /* Determine whether or not this array index has already been added to the
-    * list of active array indices.  At this point all constant folding must
-    * have occured, and the array index must be a constant.
+   /* If the block array was declared with a shared or
+    * std140 layout qualifier, all its instances have been already marked
+    * as used in link_uniform_block_active_visitor::visit(ir_variable *).
     */
+   if (var->get_interface_type()->interface_packing !=
+       GLSL_INTERFACE_PACKING_PACKED)
+      return visit_continue_with_parent;
+
    ir_constant *c = ir->array_index->as_constant();
-   assert(c != NULL);
 
-   const unsigned idx = c->get_uint_component(0);
+   if (c) {
+      /* Index is a constant, so mark just that element used, if not already */
+      const unsigned idx = c->get_uint_component(0);
 
-   unsigned i;
-   for (i = 0; i < b->num_array_elements; i++) {
-      if (b->array_elements[i] == idx)
-        break;
-   }
+      unsigned i;
+      for (i = 0; i < b->num_array_elements; i++) {
+         if (b->array_elements[i] == idx)
+            break;
+      }
 
-   assert(i <= b->num_array_elements);
+      assert(i <= b->num_array_elements);
 
-   if (i == b->num_array_elements) {
-      b->array_elements = reralloc(this->mem_ctx,
-                                  b->array_elements,
-                                  unsigned,
-                                  b->num_array_elements + 1);
+      if (i == b->num_array_elements) {
+         b->array_elements = reralloc(this->mem_ctx,
+                                      b->array_elements,
+                                      unsigned,
+                                      b->num_array_elements + 1);
 
-      b->array_elements[b->num_array_elements] = idx;
+         b->array_elements[b->num_array_elements] = idx;
 
-      b->num_array_elements++;
+         b->num_array_elements++;
+      }
+   } else {
+      /* The array index is not a constant, so mark the entire array used. */
+      assert(b->type->is_array());
+      if (b->num_array_elements < b->type->length) {
+         b->num_array_elements = b->type->length;
+         b->array_elements = reralloc(this->mem_ctx,
+                                      b->array_elements,
+                                      unsigned,
+                                      b->num_array_elements);
+
+         for (unsigned i = 0; i < b->num_array_elements; i++) {
+            b->array_elements[i] = i;
+         }
+      }
    }
 
    return visit_continue_with_parent;
@@ -137,7 +217,7 @@ link_uniform_block_active_visitor::visit(ir_dereference_variable *ir)
 {
    ir_variable *var = ir->var;
 
-   if (!var->is_in_uniform_block())
+   if (!var->is_in_buffer_block())
       return visit_continue;
 
    assert(!var->is_interface_instance() || !var->type->is_array());
@@ -149,7 +229,7 @@ link_uniform_block_active_visitor::visit(ir_dereference_variable *ir)
    if (b == NULL) {
       linker_error(this->prog,
                   "uniform block `%s' has mismatching definitions",
-                  var->interface_type->name);
+                  var->get_interface_type()->name);
       this->success = false;
       return visit_stop;
    }