glsl: Count shader inputs and outputs separately
authorIan Romanick <ian.d.romanick@intel.com>
Tue, 10 Sep 2013 17:00:34 +0000 (12:00 -0500)
committerIan Romanick <ian.d.romanick@intel.com>
Mon, 7 Oct 2013 16:59:23 +0000 (09:59 -0700)
Starting with OpenGL 3.2 input limits and output limits for stages may
not match.  This means they need to be accounted separately.

No piglit regressions.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
src/glsl/link_varyings.cpp
src/glsl/link_varyings.h
src/glsl/linker.cpp

index 905621daf8ee542e72bd16600b3d1b4fdafc9b52..9d633e8202069df6cb8cd013d38ef28f3bc7d9fa 100644 (file)
@@ -1220,39 +1220,98 @@ assign_varying_locations(struct gl_context *ctx,
 }
 
 bool
-check_against_varying_limit(struct gl_context *ctx,
-                            struct gl_shader_program *prog,
-                            gl_shader *consumer)
+check_against_output_limit(struct gl_context *ctx,
+                           struct gl_shader_program *prog,
+                           gl_shader *producer)
 {
-   unsigned varying_vectors = 0;
+   unsigned output_vectors = 0;
+
+   foreach_list(node, producer->ir) {
+      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+      if (var && var->mode == ir_var_shader_out &&
+          is_varying_var(producer->Type, var)) {
+         output_vectors += var->type->count_attribute_slots();
+      }
+   }
+
+   unsigned max_output_components;
+   switch (producer->Type) {
+   case GL_VERTEX_SHADER:
+      max_output_components = ctx->Const.VertexProgram.MaxOutputComponents;
+      break;
+   case GL_GEOMETRY_SHADER:
+      max_output_components = ctx->Const.GeometryProgram.MaxOutputComponents;
+      break;
+   case GL_FRAGMENT_SHADER:
+   default:
+      assert(!"Should not get here.");
+      return false;
+   }
+
+   const unsigned output_components = output_vectors * 4;
+   if (output_components > max_output_components) {
+      if (ctx->API == API_OPENGLES2 || prog->IsES)
+         linker_error(prog, "shader uses too many output vectors "
+                      "(%u > %u)\n",
+                      output_vectors,
+                      max_output_components / 4);
+      else
+         linker_error(prog, "shader uses too many output components "
+                      "(%u > %u)\n",
+                      output_components,
+                      max_output_components);
+
+      return false;
+   }
+
+   return true;
+}
+
+bool
+check_against_input_limit(struct gl_context *ctx,
+                          struct gl_shader_program *prog,
+                          gl_shader *consumer)
+{
+   unsigned input_vectors = 0;
 
    foreach_list(node, consumer->ir) {
       ir_variable *const var = ((ir_instruction *) node)->as_variable();
 
       if (var && var->mode == ir_var_shader_in &&
           is_varying_var(consumer->Type, var)) {
-         /* The packing rules used for vertex shader inputs are also
-          * used for fragment shader inputs.
-          */
-         varying_vectors += var->type->count_attribute_slots();
+         input_vectors += var->type->count_attribute_slots();
       }
    }
 
-   if (ctx->API == API_OPENGLES2 || prog->IsES) {
-      if (varying_vectors > ctx->Const.MaxVarying) {
-         linker_error(prog, "shader uses too many varying vectors "
+   unsigned max_input_components;
+   switch (consumer->Type) {
+   case GL_GEOMETRY_SHADER:
+      max_input_components = ctx->Const.GeometryProgram.MaxInputComponents;
+      break;
+   case GL_FRAGMENT_SHADER:
+      max_input_components = ctx->Const.FragmentProgram.MaxInputComponents;
+      break;
+   case GL_VERTEX_SHADER:
+   default:
+      assert(!"Should not get here.");
+      return false;
+   }
+
+   const unsigned input_components = input_vectors * 4;
+   if (input_components > max_input_components) {
+      if (ctx->API == API_OPENGLES2 || prog->IsES)
+         linker_error(prog, "shader uses too many input vectors "
                       "(%u > %u)\n",
-                      varying_vectors, ctx->Const.MaxVarying);
-         return false;
-      }
-   } else {
-      const unsigned float_components = varying_vectors * 4;
-      if (float_components > ctx->Const.MaxVarying * 4) {
-         linker_error(prog, "shader uses too many varying components "
+                      input_vectors,
+                      max_input_components / 4);
+      else
+         linker_error(prog, "shader uses too many input components "
                       "(%u > %u)\n",
-                      float_components, ctx->Const.MaxVarying * 4);
-         return false;
-      }
+                      input_components,
+                      max_input_components);
+
+      return false;
    }
 
    return true;
index 6264ef05b2a00fec2079869964c32f7d43e3b25b..6fa26817677c2b6206bf2eec5a318793ea5ed9f5 100644 (file)
@@ -237,8 +237,13 @@ assign_varying_locations(struct gl_context *ctx,
                          unsigned gs_input_vertices);
 
 bool
-check_against_varying_limit(struct gl_context *ctx,
-                            struct gl_shader_program *prog,
-                            gl_shader *consumer);
+check_against_output_limit(struct gl_context *ctx,
+                           struct gl_shader_program *prog,
+                           gl_shader *producer);
+
+bool
+check_against_input_limit(struct gl_context *ctx,
+                          struct gl_shader_program *prog,
+                          gl_shader *consumer);
 
 #endif /* GLSL_LINK_VARYINGS_H */
index c54b7049bbeda256e3ddd189c4978f7ae4c05eda..61904dc0ed54390d3a06c291c21af29cfb5a3558 100644 (file)
@@ -2203,7 +2203,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
          ;
 
       /* This must be done after all dead varyings are eliminated. */
-      if (!check_against_varying_limit(ctx, prog, sh_next))
+      if (!check_against_output_limit(ctx, prog, sh_i))
+         goto done;
+      if (!check_against_input_limit(ctx, prog, sh_next))
          goto done;
 
       next = i;