glsl: Do not eliminate 'shared' or 'std140' blocks or block members
authorIan Romanick <ian.d.romanick@intel.com>
Wed, 25 Jun 2014 03:15:47 +0000 (20:15 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Mon, 4 Aug 2014 21:40:06 +0000 (14:40 -0700)
Commit 32f32292 (glsl: Allow elimination of uniform block members)
enabled elimination of unused uniform block members to fix a gles3
conformance test failure.  This went too far the other way.

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."

Fixes gles3conform failures in:

ES3-CTS.shaders.uniform_block.single_nested_struct.per_block_buffer_shared
ES3-CTS.shaders.uniform_block.single_nested_struct.per_block_buffer_std140
ES3-CTS.shaders.uniform_block.single_nested_struct_array.per_block_buffer_shared
ES3-CTS.shaders.uniform_block.single_nested_struct_array.per_block_buffer_std140
ES3-CTS.shaders.uniform_block.random.scalar_types.2
ES3-CTS.shaders.uniform_block.random.scalar_types.9
ES3-CTS.shaders.uniform_block.random.vector_types.1
ES3-CTS.shaders.uniform_block.random.vector_types.3
ES3-CTS.shaders.uniform_block.random.vector_types.7
ES3-CTS.shaders.uniform_block.random.vector_types.9
ES3-CTS.shaders.uniform_block.random.basic_types.5
ES3-CTS.shaders.uniform_block.random.basic_types.6
ES3-CTS.shaders.uniform_block.random.basic_arrays.0
ES3-CTS.shaders.uniform_block.random.basic_arrays.2
ES3-CTS.shaders.uniform_block.random.basic_arrays.5
ES3-CTS.shaders.uniform_block.random.basic_arrays.8
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.0
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.4
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.5
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.6
ES3-CTS.shaders.uniform_block.random.basic_instance_arrays.9
ES3-CTS.shaders.uniform_block.random.nested_structs.0
ES3-CTS.shaders.uniform_block.random.nested_structs.1
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays.4
ES3-CTS.shaders.uniform_block.random.nested_structs_instance_arrays.8
ES3-CTS.shaders.uniform_block.random.nested_structs_arrays_instance_arrays.7
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.3
ES3-CTS.shaders.uniform_block.random.all_per_block_buffers.6
ES3-CTS.shaders.uniform_block.random.all_shared_buffer.18

v2: Whitespace and other minor fixes suggested by Matt.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
src/glsl/link_uniform_block_active_visitor.cpp
src/glsl/link_uniform_block_active_visitor.h
src/glsl/opt_dead_code.cpp

index 854309f9baa186c33090d50a55b60928a1aba23a..9da6a4bba48b3e740d2a326b96ec60ab0bc455ed 100644 (file)
@@ -72,6 +72,45 @@ 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_uniform_block())
+      return visit_continue;
+
+   const glsl_type *const block_type = var->is_interface_instance()
+      ? var->type : var->get_interface_type();
+
+   /* 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 (block_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);
+
+   return visit_continue;
+}
+
 ir_visitor_status
 link_uniform_block_active_visitor::visit_enter(ir_dereference_array *ir)
 {
index 64de826800708126827dbe0338076a8fe4a012bc..e5ea501553ce76c3e334d2da9623ac920b2384e8 100644 (file)
@@ -51,6 +51,7 @@ public:
 
    virtual ir_visitor_status visit_enter(ir_dereference_array *);
    virtual ir_visitor_status visit(ir_dereference_variable *);
+   virtual ir_visitor_status visit(ir_variable *);
 
    bool success;
 
index 3df01b4137d054d41c01ea6bbcf15446c1971f53..f45bf5dfdf817434f03a3e723fafc56bca1b9d83 100644 (file)
@@ -99,10 +99,31 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned)
          * stage.  Also, once uniform locations have been assigned, the
          * declaration cannot be deleted.
          */
-        if (entry->var->data.mode == ir_var_uniform &&
-            (uniform_locations_assigned ||
-             entry->var->constant_value))
-           continue;
+         if (entry->var->data.mode == ir_var_uniform) {
+            if (uniform_locations_assigned || entry->var->constant_value)
+               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 the variable is in a uniform block with one of those
+             * layouts, do not eliminate it.
+             */
+            if (entry->var->is_in_uniform_block()) {
+               const glsl_type *const block_type =
+                  entry->var->is_interface_instance()
+                  ? entry->var->type : entry->var->get_interface_type();
+
+               if (block_type->interface_packing != GLSL_INTERFACE_PACKING_PACKED)
+                  continue;
+            }
+         }
 
         entry->var->remove();
         progress = true;