glsl: Fix uniform buffer object counting.
authorEric Anholt <eric@anholt.net>
Thu, 23 May 2013 18:10:15 +0000 (11:10 -0700)
committerEric Anholt <eric@anholt.net>
Thu, 6 Jun 2013 21:37:41 +0000 (14:37 -0700)
We were counting uniforms located in UBOs against the default uniform
block limit, while not doing any counting against the specific combined
limit.

Note that I couldn't quite find justification for the way I did this, but
I think it's the only sensible thing: The spec talks about components, so
each "float" in a std140 block would count as 1 component and a "vec4"
would count as 4, though they occupy the same amount of space.  Since GPU
limits on uniform buffer loads are surely going to be about the size of
the blocks, I just counted them that way.

Fixes link failures in piglit
arb_uniform_buffer_object/maxuniformblocksize when ported to geometry
shaders on Paul's GS branch, since in that case the max block size is
bigger than the default uniform block component limit.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/glsl/link_uniforms.cpp
src/glsl/linker.cpp
src/mesa/main/mtypes.h

index 7a3a2ebde0363dabff0a5d29e8ec8983e9482b1e..010296b6b69bdd772cc05d608bd96ee238baa1a4 100644 (file)
@@ -170,6 +170,7 @@ public:
 
    void process(ir_variable *var)
    {
+      this->is_ubo_var = var->is_in_uniform_block();
       if (var->is_interface_instance())
          program_resource_visitor::process(var->interface_type,
                                            var->interface_type->name);
@@ -197,6 +198,8 @@ public:
     */
    unsigned num_shader_uniform_components;
 
+   bool is_ubo_var;
+
 private:
    virtual void visit_field(const glsl_type *type, const char *name,
                             bool row_major)
@@ -222,7 +225,8 @@ private:
          * Note that samplers do not count against this limit because they
          * don't use any storage on current hardware.
          */
-        this->num_shader_uniform_components += values;
+        if (!is_ubo_var)
+           this->num_shader_uniform_components += values;
       }
 
       /* If the uniform is already in the map, there's nothing more to do.
@@ -681,6 +685,12 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
 
       sh->num_samplers = uniform_size.num_shader_samplers;
       sh->num_uniform_components = uniform_size.num_shader_uniform_components;
+
+      sh->num_combined_uniform_components = sh->num_uniform_components;
+      for (unsigned i = 0; i < sh->NumUniformBlocks; i++) {
+        sh->num_combined_uniform_components +=
+           sh->UniformBlocks[i].UniformBufferSize / 4;
+      }
    }
 
    const unsigned num_user_uniforms = uniform_size.num_active_uniforms;
index 982fe46bd73b07112610c3cbabcc87b476bca45f..cd8d680aec48875df22f44035305d1c4a7b677ec 100644 (file)
@@ -1523,12 +1523,18 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
       ctx->Const.GeometryProgram.MaxTextureImageUnits
    };
 
-   const unsigned max_uniform_components[MESA_SHADER_TYPES] = {
+   const unsigned max_default_uniform_components[MESA_SHADER_TYPES] = {
       ctx->Const.VertexProgram.MaxUniformComponents,
       ctx->Const.FragmentProgram.MaxUniformComponents,
       ctx->Const.GeometryProgram.MaxUniformComponents
    };
 
+   const unsigned max_combined_uniform_components[MESA_SHADER_TYPES] = {
+      ctx->Const.VertexProgram.MaxCombinedUniformComponents,
+      ctx->Const.FragmentProgram.MaxCombinedUniformComponents,
+      ctx->Const.GeometryProgram.MaxCombinedUniformComponents
+   };
+
    const unsigned max_uniform_blocks[MESA_SHADER_TYPES] = {
       ctx->Const.VertexProgram.MaxUniformBlocks,
       ctx->Const.FragmentProgram.MaxUniformBlocks,
@@ -1546,7 +1552,22 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
                      shader_names[i]);
       }
 
-      if (sh->num_uniform_components > max_uniform_components[i]) {
+      if (sh->num_uniform_components > max_default_uniform_components[i]) {
+         if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
+            linker_warning(prog, "Too many %s shader default uniform block "
+                           "components, but the driver will try to optimize "
+                           "them out; this is non-portable out-of-spec "
+                          "behavior\n",
+                           shader_names[i]);
+         } else {
+            linker_error(prog, "Too many %s shader default uniform block "
+                        "components",
+                         shader_names[i]);
+         }
+      }
+
+      if (sh->num_combined_uniform_components >
+         max_combined_uniform_components[i]) {
          if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
             linker_warning(prog, "Too many %s shader uniform components, "
                            "but the driver will try to optimize them out; "
index aae2876fb93e131b998e57ceac8fa87dce262b9b..92a70f416d31de185cb72d104f8ac2d9c88cfcd8 100644 (file)
@@ -2140,12 +2140,20 @@ struct gl_shader
    gl_texture_index SamplerTargets[MAX_SAMPLERS];
 
    /**
-    * Number of uniform components used by this shader.
+    * Number of default uniform block components used by this shader.
     *
     * This field is only set post-linking.
     */
    unsigned num_uniform_components;
 
+   /**
+    * Number of combined uniform components used by this shader.
+    *
+    * This field is only set post-linking.  It is the sum of the uniform block
+    * sizes divided by sizeof(float), and num_uniform_compoennts.
+    */
+   unsigned num_combined_uniform_components;
+
    /**
     * This shader's uniform block information.
     *