[Mesa-dev] [PATCH 11/17] glsl: Linker generates std140 layout

Vincent Lejeune vljn at ovi.com
Sun Dec 25 10:20:06 PST 2011


UBO data can be packed using 3 different strategies : packed, shader and std140.
The spec defines in a non ambigous way the std140 strategy, this patch implements
it.
---
 src/glsl/linker.cpp |  121 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 121 insertions(+), 0 deletions(-)

diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index 0c8a2c2..34bc537 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -1216,6 +1216,127 @@ static void expand_gl_ubo(struct gl_shader_program *sh, const struct gl_uniform_
    dest->ReferencedByFS = dest->ReferencedByGS = dest->ReferencedByVS = 0;
 }
 
+
+static
+unsigned align_offset(unsigned& base_offset,unsigned base_alignement)
+{
+   unsigned result = base_offset + base_alignement - 1;
+   result /= base_alignement;
+   result *= base_alignement;
+   base_offset = result;
+   return result;
+}
+
+/**
+ * This function sets offset of UBO elements according to
+ * standard packing rule from GL_ARB_Uniform_Buffer_Object spec.
+ */
+static void set_standard_uniform_block_layout_recursive(union gl_variable_storage *storage_tree, const struct glsl_type *type,
+                                                        unsigned& next_position)
+{
+   /** Rule 1 */
+   if (type->is_scalar()) {
+      storage_tree->AsLeaf.Offset = align_offset(next_position,4);
+      next_position += 4;
+      return;
+   }
+
+   /** Rule 2 and 3 */
+   if (type->is_vector()) {
+      switch(type->vector_elements) {
+      case 4:
+      case 3:
+         storage_tree->AsLeaf.Offset = align_offset(next_position,16);
+         break;
+      case 2:
+         storage_tree->AsLeaf.Offset = align_offset(next_position,8);
+         break;
+      default:
+         break;
+      }
+
+      next_position += 4 * type->vector_elements;
+      return;
+   }
+
+   /** Rule 9 */
+   if (type->is_record()) {
+      align_offset(next_position,16);
+      for (unsigned i = 0; i < type->length; i++) {
+         set_standard_uniform_block_layout_recursive(storage_tree->AsRecord.Fields[i],
+                                                     type->fields.structure[i].type,
+                                                     next_position);
+      }
+      return;
+   }
+
+   /** Rule 5 */
+   if (type->is_matrix()) {
+      storage_tree->AsMatrix.Offset = align_offset(next_position,16);
+      for (unsigned i = 0; i < type->matrix_columns; i++) {
+         align_offset(next_position,16);
+         next_position += 4 * type->vector_elements;
+      }
+      return;
+   }
+
+   if (type->is_array()) {
+      const glsl_type* base_type = type->fields.array;
+      /** Rule 4 */
+      if (base_type->is_scalar() || base_type->is_vector()) {
+         storage_tree->AsArray.FirstElement->AsLeaf.Offset = align_offset(next_position,16);
+         storage_tree->AsArray.Stride = 16;
+         next_position += type->length * storage_tree->AsArray.Stride;
+         align_offset(next_position,16);
+         return;
+      }
+      /** Rule 6 and 7 */
+      if (base_type->is_matrix()) {
+         storage_tree->AsArray.FirstElement->AsMatrix.Offset = align_offset(next_position,16);
+         next_position += 4 * base_type->vector_elements;
+         storage_tree->AsArray.Stride = next_position - storage_tree->AsArray.FirstElement->AsMatrix.Offset;
+
+         for (unsigned i = 1; i < base_type->matrix_columns * type->array_size(); i++) {
+            align_offset(next_position,16);
+            next_position += 4 * base_type->vector_elements;
+         }
+         return;
+      }
+      /** Rule 10 */
+      else if (base_type->is_record()){
+         unsigned offset = align_offset(next_position,16);
+         set_standard_uniform_block_layout_recursive(storage_tree->AsArray.FirstElement,
+                                                      base_type,
+                                                      next_position);
+         align_offset(next_position,16);
+
+         storage_tree->AsArray.Stride = next_position - offset;
+         next_position = offset +  type->length * storage_tree->AsArray.Stride;
+         align_offset(next_position,16);
+         return;
+      }
+      return;
+   }
+
+
+}
+
+static void set_standard_uniform_block_layout(struct gl_uniform_buffer_object& prog_ubo)
+{
+   unsigned next_position = 0;
+
+   for(unsigned i=0;i<prog_ubo.NumberOfVariables;i++) {
+      struct gl_shader_ubo_variable& var = prog_ubo.Variables[i];
+      union gl_variable_storage *var_storage = create_storage_type(var.Type);
+      set_standard_uniform_block_layout_recursive( var_storage, var.Type, next_position);
+      var.Storage = var_storage;
+   }
+
+   prog_ubo.Size = align_offset(next_position,16);
+
+   return;
+}
+
 /**
  * At interstage this function extract UBOs from shaders to populate programs UBOs
  * It also performs checks coherency between UBOs with same name.
-- 
1.7.7



More information about the mesa-dev mailing list