glsl: Fix incorrect hard-coded location of the gl_SecondaryFragColorEXT built-in.
[mesa.git] / src / compiler / glsl / link_uniform_blocks.cpp
index 586363d4f123d4f94da346a6155f6e16e7bf10db..5b0dff6aa19f20d30da3a4ed22adc52d3f41b936 100644 (file)
@@ -34,9 +34,10 @@ namespace {
 class ubo_visitor : public program_resource_visitor {
 public:
    ubo_visitor(void *mem_ctx, gl_uniform_buffer_variable *variables,
-               unsigned num_variables)
+               unsigned num_variables, struct gl_shader_program *prog)
       : index(0), offset(0), buffer_size(0), variables(variables),
-        num_variables(num_variables), mem_ctx(mem_ctx), is_array_instance(false)
+        num_variables(num_variables), mem_ctx(mem_ctx), is_array_instance(false),
+        prog(prog)
    {
       /* empty */
    }
@@ -56,6 +57,7 @@ public:
    unsigned num_variables;
    void *mem_ctx;
    bool is_array_instance;
+   struct gl_shader_program *prog;
 
 private:
    virtual void visit_field(const glsl_type *type, const char *name,
@@ -68,7 +70,7 @@ private:
    }
 
    virtual void enter_record(const glsl_type *type, const char *,
-                             bool row_major, const unsigned packing) {
+                             bool row_major, const enum glsl_interface_packing packing) {
       assert(type->is_record());
       if (packing == GLSL_INTERFACE_PACKING_STD430)
          this->offset = glsl_align(
@@ -79,7 +81,7 @@ private:
    }
 
    virtual void leave_record(const glsl_type *type, const char *,
-                             bool row_major, const unsigned packing) {
+                             bool row_major, const enum glsl_interface_packing packing) {
       assert(type->is_record());
 
       /* If this is the last field of a structure, apply rule #9.  The
@@ -104,7 +106,7 @@ private:
 
    virtual void visit_field(const glsl_type *type, const char *name,
                             bool row_major, const glsl_type *,
-                            const unsigned packing,
+                            const enum glsl_interface_packing packing,
                             bool last_field)
    {
       assert(this->index < this->num_variables);
@@ -148,7 +150,13 @@ private:
        */
       const glsl_type *type_for_size = type;
       if (type->is_unsized_array()) {
-         assert(last_field);
+         if (!last_field) {
+            linker_error(prog, "unsized array `%s' definition: "
+                         "only last member of a shader storage block "
+                         "can be defined as unsized array",
+                         name);
+         }
+
          type_for_size = type->without_array();
       }
 
@@ -216,7 +224,7 @@ process_block_array(struct uniform_block_array_elements *ub_array, char **name,
 {
    if (ub_array) {
       for (unsigned j = 0; j < ub_array->num_array_elements; j++) {
-        size_t new_length = name_length;
+         size_t new_length = name_length;
 
          /* Append the subscript to the current variable name */
          ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]",
@@ -261,7 +269,6 @@ process_block_array(struct uniform_block_array_elements *ub_array, char **name,
       }
       blocks[i].NumUniforms =
          (unsigned)(ptrdiff_t)(&variables[parcel->index] - blocks[i].Uniforms);
-      blocks[i].IsShaderStorage = b->is_shader_storage;
 
       *block_index = *block_index + 1;
       *binding_offset = *binding_offset + 1;
@@ -315,7 +322,7 @@ create_buffer_blocks(void *mem_ctx, struct gl_context *ctx,
    /* Add each variable from each uniform block to the API tracking
     * structures.
     */
-   ubo_visitor parcel(blocks, variables, num_variables);
+   ubo_visitor parcel(blocks, variables, num_variables, prog);
 
    STATIC_ASSERT(unsigned(GLSL_INTERFACE_PACKING_STD140)
                  == unsigned(ubo_packing_std140));
@@ -384,8 +391,7 @@ void
 link_uniform_blocks(void *mem_ctx,
                     struct gl_context *ctx,
                     struct gl_shader_program *prog,
-                    struct gl_shader **shader_list,
-                    unsigned num_shaders,
+                    struct gl_linked_shader *shader,
                     struct gl_uniform_block **ubo_blocks,
                     unsigned *num_ubo_blocks,
                     struct gl_uniform_block **ssbo_blocks,
@@ -408,9 +414,7 @@ link_uniform_blocks(void *mem_ctx,
    /* Determine which uniform blocks are active.
     */
    link_uniform_block_active_visitor v(mem_ctx, block_hash, prog);
-   for (unsigned i = 0; i < num_shaders; i++) {
-      visit_list_elements(&v, shader_list[i]->ir);
-   }
+   visit_list_elements(&v, shader->ir);
 
    /* Count the number of active uniform blocks.  Count the total number of
     * active slots in those uniform blocks.
@@ -465,9 +469,9 @@ link_uniform_blocks(void *mem_ctx,
    _mesa_hash_table_destroy(block_hash, NULL);
 }
 
-bool
+static bool
 link_uniform_blocks_are_compatible(const gl_uniform_block *a,
-                                  const gl_uniform_block *b)
+                                   const gl_uniform_block *b)
 {
    assert(strcmp(a->Name, b->Name) == 0);
 
@@ -490,14 +494,67 @@ link_uniform_blocks_are_compatible(const gl_uniform_block *a,
 
    for (unsigned i = 0; i < a->NumUniforms; i++) {
       if (strcmp(a->Uniforms[i].Name, b->Uniforms[i].Name) != 0)
-        return false;
+         return false;
 
       if (a->Uniforms[i].Type != b->Uniforms[i].Type)
-        return false;
+         return false;
 
       if (a->Uniforms[i].RowMajor != b->Uniforms[i].RowMajor)
-        return false;
+         return false;
    }
 
    return true;
 }
+
+/**
+ * Merges a uniform block into an array of uniform blocks that may or
+ * may not already contain a copy of it.
+ *
+ * Returns the index of the new block in the array.
+ */
+int
+link_cross_validate_uniform_block(void *mem_ctx,
+                                  struct gl_uniform_block **linked_blocks,
+                                  unsigned int *num_linked_blocks,
+                                  struct gl_uniform_block *new_block)
+{
+   for (unsigned int i = 0; i < *num_linked_blocks; i++) {
+      struct gl_uniform_block *old_block = &(*linked_blocks)[i];
+
+      if (strcmp(old_block->Name, new_block->Name) == 0)
+         return link_uniform_blocks_are_compatible(old_block, new_block)
+            ? i : -1;
+   }
+
+   *linked_blocks = reralloc(mem_ctx, *linked_blocks,
+                             struct gl_uniform_block,
+                             *num_linked_blocks + 1);
+   int linked_block_index = (*num_linked_blocks)++;
+   struct gl_uniform_block *linked_block = &(*linked_blocks)[linked_block_index];
+
+   memcpy(linked_block, new_block, sizeof(*new_block));
+   linked_block->Uniforms = ralloc_array(*linked_blocks,
+                                         struct gl_uniform_buffer_variable,
+                                         linked_block->NumUniforms);
+
+   memcpy(linked_block->Uniforms,
+          new_block->Uniforms,
+          sizeof(*linked_block->Uniforms) * linked_block->NumUniforms);
+
+   linked_block->Name = ralloc_strdup(*linked_blocks, linked_block->Name);
+
+   for (unsigned int i = 0; i < linked_block->NumUniforms; i++) {
+      struct gl_uniform_buffer_variable *ubo_var =
+         &linked_block->Uniforms[i];
+
+      if (ubo_var->Name == ubo_var->IndexName) {
+         ubo_var->Name = ralloc_strdup(*linked_blocks, ubo_var->Name);
+         ubo_var->IndexName = ubo_var->Name;
+      } else {
+         ubo_var->Name = ralloc_strdup(*linked_blocks, ubo_var->Name);
+         ubo_var->IndexName = ralloc_strdup(*linked_blocks, ubo_var->IndexName);
+      }
+   }
+
+   return linked_block_index;
+}