[Mesa-dev] [PATCH 7/9] glsl : Linker support for UBO

vlj vljn at ovi.com
Sun Oct 16 15:37:20 PDT 2011


   v2 :
   - Fix format issue thank to Brian Paul comments.
   - UBOs are now sent to program correctly.
---
 src/glsl/linker.cpp |  192 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 191 insertions(+), 1 deletions(-)

diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index ba81c59..7d85d4e 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -65,6 +65,7 @@
  */
 
 #include "main/core.h"
+#include "main/hash.h"
 #include "glsl_symbol_table.h"
 #include "ir.h"
 #include "program.h"
@@ -784,6 +785,61 @@ get_main_function_signature(gl_shader *sh)
    return NULL;
 }
 
+/**
+ * TODO : write the function
+ * This function should check consistency between 2 UBO having same name
+ * from different shaders :
+ * - Same layout
+ * - Same variables (name and type) in same order
+ * - Same matrix layout (ie row/column major)
+ */
+static bool validate_separate_ubo(const ubo& first, const ubo& second)
+{
+   return true;
+}
+
+/**
+ * At intrastage, when several shaders of same type are merged in a single one,
+ * this function generates UBOs of the newly created shader from them and
+ * performs necessary check.
+ */
+static void merge_intrastage_ubo ( gl_shader_program* prog, struct gl_shader& merged_shader,
+                            struct gl_shader **shader_list, unsigned num_shaders)
+{
+   hash_table *ht = hash_table_ctor(0, hash_table_string_hash,
+                                    hash_table_string_compare);
+   merged_shader.UBOCount = 0;
+   unsigned& index = merged_shader.UBOCount;
+   if(!merged_shader.UniformBufferObjects)
+      merged_shader.UniformBufferObjects = (struct ubo*) malloc(MAX_UBO_IN_SHADER * sizeof(struct ubo));
+   for (unsigned shad_id=0; shad_id < num_shaders; shad_id++)
+   {
+      for(unsigned ubo_id=0; ubo_id < shader_list[shad_id]->UBOCount; ubo_id++)
+      {
+         ubo* current_ubo = &(shader_list[shad_id]->UniformBufferObjects[ubo_id]);
+         ubo* sh = (ubo*) hash_table_find(ht,current_ubo->Name);
+         if(!sh)
+         {
+            ubo& tmp = merged_shader.UniformBufferObjects[index];
+            tmp = *current_ubo;
+            tmp.Name = strdup(current_ubo->Name);
+            tmp.StorageLayout = (UBOVariableInfo*) malloc(tmp.NumberOfVariables * sizeof(UBOVariableInfo));
+            for (unsigned i = 0; i < current_ubo->NumberOfVariables; i++) {
+               tmp.StorageLayout[i] = current_ubo->StorageLayout[i];
+               tmp.StorageLayout[i].Name = strdup(current_ubo->StorageLayout[i].Name);
+            }
+            hash_table_insert(ht,current_ubo,current_ubo->Name);
+            index++;
+         }
+         else
+         {
+            if(!validate_separate_ubo(*current_ubo,*sh))
+               linker_error(prog,"Uniform Buffer Object '%s definition mismatch",sh->Name);
+         }
+      }
+   }
+   hash_table_dtor(ht);
+}
 
 /**
  * Combine a group of shaders for a single stage to generate a linked shader
@@ -955,6 +1011,8 @@ link_intrastage_shaders(void *mem_ctx,
       v.run(linked->ir);
    }
 
+   merge_intrastage_ubo(prog,*linked,shader_list,num_shaders);
+
    return linked;
 }
 
@@ -1134,7 +1192,7 @@ assign_uniform_locations(struct gl_shader_program *prog)
       foreach_list(node, prog->_LinkedShaders[i]->ir) {
 	 ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
-	 if ((var == NULL) || (var->mode != ir_var_uniform))
+       if ((var == NULL) || (var->mode != ir_var_uniform) || var->UBO)
 	    continue;
 
 	 if (strncmp(var->name, "gl_", 3) == 0) {
@@ -1176,12 +1234,142 @@ assign_uniform_locations(struct gl_shader_program *prog)
       free(node);
    }
 
+   /* UBO : mirror the setup to the variable and set program scope UBO variable */
+   prog->IndexedUniformsInUBO = (struct UBOVariableInfo**) malloc(MAX_UBO_IN_SHADER * MAX_VARIABLES_IN_UBO * sizeof(struct UBOVariableInfo*));
+   idx = 0;
+
+   for(unsigned i = 0; i < prog->UBOCount; i++) {
+      const ubo* current_ubo = prog->UniformBufferObject[i];
+      if(!current_ubo)
+         continue;
+      for (unsigned j = 0;j < current_ubo->NumberOfVariables; j++) {
+
+         for (unsigned k = 0; k < MESA_SHADER_TYPES; k++) {
+
+            gl_shader* shader = prog->_LinkedShaders[k];
+            if(shader==NULL)
+               continue;
+            ir_variable* var = shader->symbols->get_variable(current_ubo->StorageLayout[j].Name);
+            if(var==NULL)
+               continue;
+            var->UBO = &(current_ubo->StorageLayout[j]);
+            var->location = 0;
+
+         }
+         prog->IndexedUniformsInUBO[idx] = &(current_ubo->StorageLayout[j]);
+         current_ubo->StorageLayout[j].UBO = prog->UniformBufferObject[i];
+         idx++;
+      }
+   }
+   prog->UBOVariableCount = idx;
+
    hash_table_dtor(ht);
 
    prog->Uniforms = ul;
 }
 
 
+
+/**
+ * This function sets offset of UBO elements according to
+ * standard packing rule from GL_ARB_Uniform_Buffer_Object spec.
+ * TODO : compute stride
+ */
+static void set_standard_uniform_block_layout(ubo* prog_ubo,GLenum shaderType)
+{
+   exec_list uniforms;
+   unsigned total_uniforms = 0;
+   hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
+                                    hash_table_string_compare);
+   void *mem_ctx = ralloc_context(NULL);
+
+   unsigned next_position = 0;
+
+   for(unsigned i=0;i<prog_ubo->NumberOfVariables;i++) {
+      UBOVariableInfo& var = prog_ubo->StorageLayout[i];
+
+      add_uniform(mem_ctx, &uniforms, ht, var.Name, var.Type,
+                  shaderType,
+                  &next_position, &total_uniforms);
+   }
+
+   ralloc_free(mem_ctx);
+
+   unsigned idx = 0;
+   uniform_node *next;
+   for (uniform_node *node = (uniform_node *) uniforms.head
+        ; node->link.next != NULL
+        ; node = next) {
+      next = (uniform_node *) node->link.next;
+
+      node->link.remove();
+      switch(shaderType) {
+      case GL_VERTEX_SHADER:
+         prog_ubo->StorageLayout[idx].Offset = node->u->VertPos;
+         break;
+      case GL_FRAGMENT_SHADER:
+         prog_ubo->StorageLayout[idx].Offset = node->u->FragPos;
+         break;
+      case GL_GEOMETRY_SHADER:
+         prog_ubo->StorageLayout[idx].Offset = node->u->GeomPos;
+         break;
+      default:
+         break;
+      }
+      idx++;
+
+      free(node->u);
+      free(node);
+   }
+
+   hash_table_dtor(ht);
+}
+
+/**
+ * At interstage this function extract UBOs from shaders to populate programs UBOs
+ * It also performs checks coherency between UBOs with same name.
+ */
+static void merge_interstage_ubo(gl_shader_program* prog)
+{
+   hash_table *ht = hash_table_ctor(0, hash_table_string_hash,
+                                    hash_table_string_compare);
+   prog->UBOCount = 0;
+
+   unsigned index = 0;
+   for (unsigned k = 0; k < MESA_SHADER_TYPES; k++) {
+      gl_shader* shader = prog->_LinkedShaders[k];
+      if(shader==NULL)
+         continue;
+
+      for(unsigned ubo_idx = 0; ubo_idx < shader->UBOCount; ubo_idx++) {
+
+         ubo* current_ubo = &(shader->UniformBufferObjects[ubo_idx]);
+         ubo* ubo_model = (ubo*) hash_table_find(ht,current_ubo->Name);
+         if(!ubo_model) {
+            // Maps pointer
+            prog->UniformBufferObject[index] = current_ubo;
+            current_ubo->BoundBuffer = -1;
+            current_ubo->Index = index;
+
+            // Set variables info in current_ubo
+            // Todo : implementation dependant packing rules
+            set_standard_uniform_block_layout(current_ubo,shader->Type);
+            index++;
+
+            prog->UBOCount = index;
+            hash_table_insert(ht,current_ubo,current_ubo->Name);
+         }
+         else {
+            if(!validate_separate_ubo(*current_ubo,*ubo_model))
+               linker_error(prog,"Uniform Buffer Object '%s definition mismatch",ubo_model->Name);
+         }
+      }
+   }
+
+   hash_table_dtor(ht);
+}
+
+
 /**
  * Find a contiguous set of available bits in a bitmask.
  *
@@ -1730,6 +1918,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
    update_array_sizes(prog);
 
+   merge_interstage_ubo(prog);
+
    assign_uniform_locations(prog);
 
    /* FINISHME: The value of the max_attribute_index parameter is
-- 
1.7.6.4



More information about the mesa-dev mailing list