glsl/linker: Count and check image resources.
authorFrancisco Jerez <currojerez@riseup.net>
Fri, 22 Nov 2013 23:53:26 +0000 (15:53 -0800)
committerFrancisco Jerez <currojerez@riseup.net>
Wed, 12 Feb 2014 17:44:06 +0000 (18:44 +0100)
v2: Add comment about the reason why image variables take up space
    from the default uniform block.

Reviewed-by: Paul Berry <stereotype441@gmail.com>
src/glsl/link_uniforms.cpp
src/glsl/linker.cpp

index 1c97e19..79f8404 100644 (file)
@@ -240,7 +240,8 @@ class count_uniform_size : public program_resource_visitor {
 public:
    count_uniform_size(struct string_to_uint_map *map)
       : num_active_uniforms(0), num_values(0), num_shader_samplers(0),
-       num_shader_uniform_components(0), is_ubo_var(false), map(map)
+        num_shader_images(0), num_shader_uniform_components(0),
+        is_ubo_var(false), map(map)
    {
       /* empty */
    }
@@ -248,6 +249,7 @@ public:
    void start_shader()
    {
       this->num_shader_samplers = 0;
+      this->num_shader_images = 0;
       this->num_shader_uniform_components = 0;
    }
 
@@ -277,6 +279,11 @@ public:
    unsigned num_shader_samplers;
 
    /**
+    * Number of images used
+    */
+   unsigned num_shader_images;
+
+   /**
     * Number of uniforms used in the current shader
     */
    unsigned num_shader_uniform_components;
@@ -303,6 +310,15 @@ private:
       if (type->contains_sampler()) {
         this->num_shader_samplers +=
            type->is_array() ? type->array_size() : 1;
+      } else if (type->contains_image()) {
+         this->num_shader_images += values;
+
+         /* As drivers are likely to represent image uniforms as
+          * scalar indices, count them against the limit of uniform
+          * components in the default block.  The spec allows image
+          * uniforms to use up no more than one scalar slot.
+          */
+         this->num_shader_uniform_components += values;
       } else {
         /* Accumulate the total number of uniform slots used by this shader.
          * Note that samplers do not count against this limit because they
@@ -782,6 +798,7 @@ link_assign_uniform_locations(struct gl_shader_program *prog)
       }
 
       sh->num_samplers = uniform_size.num_shader_samplers;
+      sh->NumImages = uniform_size.num_shader_images;
       sh->num_uniform_components = uniform_size.num_shader_uniform_components;
 
       sh->num_combined_uniform_components = sh->num_uniform_components;
index bcd7394..72a3860 100644 (file)
@@ -2031,6 +2031,46 @@ check_resources(struct gl_context *ctx, struct gl_shader_program *prog)
    }
 }
 
+/**
+ * Validate shader image resources.
+ */
+static void
+check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+   unsigned total_image_units = 0;
+   unsigned fragment_outputs = 0;
+
+   if (!ctx->Extensions.ARB_shader_image_load_store)
+      return;
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_shader *sh = prog->_LinkedShaders[i];
+
+      if (sh) {
+         if (sh->NumImages > ctx->Const.Program[i].MaxImageUniforms)
+            linker_error(prog, "Too many %s shader image uniforms",
+                         _mesa_shader_stage_to_string(i));
+
+         total_image_units += sh->NumImages;
+
+         if (i == MESA_SHADER_FRAGMENT) {
+            foreach_list(node, sh->ir) {
+               ir_variable *var = ((ir_instruction *)node)->as_variable();
+               if (var && var->data.mode == ir_var_shader_out)
+                  fragment_outputs += var->type->count_attribute_slots();
+            }
+         }
+      }
+   }
+
+   if (total_image_units > ctx->Const.MaxCombinedImageUniforms)
+      linker_error(prog, "Too many combined image uniforms");
+
+   if (total_image_units + fragment_outputs >
+       ctx->Const.MaxCombinedImageUnitsAndFragmentOutputs)
+      linker_error(prog, "Too many combined image uniforms and fragment outputs");
+}
+
 void
 link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 {
@@ -2394,6 +2434,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    store_fragdepth_layout(prog);
 
    check_resources(ctx, prog);
+   check_image_resources(ctx, prog);
    link_check_atomic_counter_resources(ctx, prog);
 
    if (!prog->LinkStatus)