glsl/linker: Refactor in preparation for adding more shader stages.
authorPaul Berry <stereotype441@gmail.com>
Tue, 7 Jan 2014 16:56:57 +0000 (08:56 -0800)
committerPaul Berry <stereotype441@gmail.com>
Wed, 22 Jan 2014 04:24:59 +0000 (20:24 -0800)
Rather than maintain separately named arrays and counts for vertex,
geometry, and fragment shaders, just maintain these as arrays indexed
by the gl_shader_type enum.

v2: When there is neither a vertex nor a geometry shader, set
prog->LastClipDistanceArraySize = 0, and clarify that the values is
not used.

Reviewed-by: Chris Forbes <chrisf@ijw.co.nz>
Reviewed-by: Brian Paul <brianp@vmware.com>
src/glsl/linker.cpp

index 38a6560d1b508d2eae47a9b8d987b1ff8289ec8d..93b4754970c74829326664479fe8fa3395b3a0b2 100644 (file)
@@ -1996,19 +1996,14 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
    /* Separate the shaders into groups based on their type.
     */
-   struct gl_shader **vert_shader_list;
-   unsigned num_vert_shaders = 0;
-   struct gl_shader **frag_shader_list;
-   unsigned num_frag_shaders = 0;
-   struct gl_shader **geom_shader_list;
-   unsigned num_geom_shaders = 0;
-
-   vert_shader_list = (struct gl_shader **)
-      calloc(prog->NumShaders, sizeof(struct gl_shader *));
-   frag_shader_list = (struct gl_shader **)
-      calloc(prog->NumShaders, sizeof(struct gl_shader *));
-   geom_shader_list = (struct gl_shader **)
-      calloc(prog->NumShaders, sizeof(struct gl_shader *));
+   struct gl_shader **shader_list[MESA_SHADER_STAGES];
+   unsigned num_shaders[MESA_SHADER_STAGES];
+
+   for (int i = 0; i < MESA_SHADER_STAGES; i++) {
+      shader_list[i] = (struct gl_shader **)
+         calloc(prog->NumShaders, sizeof(struct gl_shader *));
+      num_shaders[i] = 0;
+   }
 
    unsigned min_version = UINT_MAX;
    unsigned max_version = 0;
@@ -2024,20 +2019,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
         goto done;
       }
 
-      switch (prog->Shaders[i]->Stage) {
-      case MESA_SHADER_VERTEX:
-        vert_shader_list[num_vert_shaders] = prog->Shaders[i];
-        num_vert_shaders++;
-        break;
-      case MESA_SHADER_FRAGMENT:
-        frag_shader_list[num_frag_shaders] = prog->Shaders[i];
-        num_frag_shaders++;
-        break;
-      case MESA_SHADER_GEOMETRY:
-        geom_shader_list[num_geom_shaders] = prog->Shaders[i];
-        num_geom_shaders++;
-        break;
-      }
+      gl_shader_stage shader_type = prog->Shaders[i]->Stage;
+      shader_list[shader_type][num_shaders[shader_type]] = prog->Shaders[i];
+      num_shaders[shader_type]++;
    }
 
    /* In desktop GLSL, different shader versions may be linked together.  In
@@ -2054,7 +2038,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
    /* Geometry shaders have to be linked with vertex shaders.
     */
-   if (num_geom_shaders > 0 && num_vert_shaders == 0) {
+   if (num_shaders[MESA_SHADER_GEOMETRY] > 0 &&
+       num_shaders[MESA_SHADER_VERTEX] == 0) {
       linker_error(prog, "Geometry shader must be linked with "
                   "vertex shader\n");
       goto done;
@@ -2069,55 +2054,39 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
    /* Link all shaders for a particular stage and validate the result.
     */
-   if (num_vert_shaders > 0) {
-      gl_shader *const sh =
-        link_intrastage_shaders(mem_ctx, ctx, prog, vert_shader_list,
-                                num_vert_shaders);
-
-      if (!prog->LinkStatus)
-        goto done;
-
-      validate_vertex_shader_executable(prog, sh);
-      if (!prog->LinkStatus)
-        goto done;
-      prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize;
+   for (int stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+      if (num_shaders[stage] > 0) {
+         gl_shader *const sh =
+            link_intrastage_shaders(mem_ctx, ctx, prog, shader_list[stage],
+                                    num_shaders[stage]);
 
-      _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_VERTEX],
-                            sh);
-   }
-
-   if (num_frag_shaders > 0) {
-      gl_shader *const sh =
-        link_intrastage_shaders(mem_ctx, ctx, prog, frag_shader_list,
-                                num_frag_shaders);
-
-      if (!prog->LinkStatus)
-        goto done;
+         if (!prog->LinkStatus)
+            goto done;
 
-      validate_fragment_shader_executable(prog, sh);
-      if (!prog->LinkStatus)
-        goto done;
+         switch (stage) {
+         case MESA_SHADER_VERTEX:
+            validate_vertex_shader_executable(prog, sh);
+            break;
+         case MESA_SHADER_GEOMETRY:
+            validate_geometry_shader_executable(prog, sh);
+            break;
+         case MESA_SHADER_FRAGMENT:
+            validate_fragment_shader_executable(prog, sh);
+            break;
+         }
+         if (!prog->LinkStatus)
+            goto done;
 
-      _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_FRAGMENT],
-                            sh);
+         _mesa_reference_shader(ctx, &prog->_LinkedShaders[stage], sh);
+      }
    }
 
-   if (num_geom_shaders > 0) {
-      gl_shader *const sh =
-        link_intrastage_shaders(mem_ctx, ctx, prog, geom_shader_list,
-                                num_geom_shaders);
-
-      if (!prog->LinkStatus)
-        goto done;
-
-      validate_geometry_shader_executable(prog, sh);
-      if (!prog->LinkStatus)
-        goto done;
+   if (num_shaders[MESA_SHADER_GEOMETRY] > 0)
       prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize;
-
-      _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
-                            sh);
-   }
+   else if (num_shaders[MESA_SHADER_VERTEX] > 0)
+      prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize;
+   else
+      prog->LastClipDistanceArraySize = 0; /* Not used */
 
    /* Here begins the inter-stage linking phase.  Some initial validation is
     * performed, then locations are assigned for uniforms, attributes, and
@@ -2375,11 +2344,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
    /* FINISHME: Assign fragment shader output locations. */
 
 done:
-   free(vert_shader_list);
-   free(frag_shader_list);
-   free(geom_shader_list);
-
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      free(shader_list[i]);
       if (prog->_LinkedShaders[i] == NULL)
         continue;