[Mesa-dev] [PATCH] TransformFeedback: Assign transform feedback varying slots in linker.

Dan McCabe zen3d.linux at gmail.com
Fri Oct 21 17:14:22 PDT 2011


Modify the linker to assign additional slots for varying
variables used by transform feedback. This is done after other
varyings are already assigned slots.

Since this is done after previous varying slot assignments,
the code needs to know how many varyings are already assigned
slots. A new function "max_varying()" is introduced to examine a
previously processed shader to find the largest varying already
assigned a slot. All new varyings will be assigned slots after
this one. If varyings are found, -1 is returned.
---
 src/glsl/linker.cpp |   84 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index a7c38a3..81f2658 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -207,6 +207,25 @@ invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,
    }
 }
 
+ 
+int
+max_varying(gl_shader *sh, enum ir_variable_mode mode)
+{
+   int max_varying = -1;
+
+   foreach_list(node, sh->ir) {
+      ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+      if ((var == NULL) || (var->mode != (unsigned) mode))
+	 continue;
+
+      if (var->location > max_varying)
+	 max_varying = var->location;
+   }
+
+   return max_varying;
+}
+
 
 /**
  * Determine the number of attribute slots required for a particular type
@@ -1597,6 +1616,69 @@ assign_varying_locations(struct gl_context *ctx,
 
 
 void
+assign_transform_feedback_varying_locations(struct gl_context *ctx,
+					    struct gl_shader_program *prog)
+{
+   struct gl_shader *vs = prog->_LinkedShaders[MESA_SHADER_VERTEX];
+
+   if (vs == NULL)
+      return;
+
+   char **names = prog->TransformFeedback.VaryingNames;
+   int num_names = prog->TransformFeedback.NumVarying;
+
+   if (num_names <= 0)
+      return;
+
+   int num_varying = max_varying(vs, ir_var_out) + 1;
+   unsigned output_index =
+     (num_varying > VERT_RESULT_VAR0)
+        ? num_varying
+        : VERT_RESULT_VAR0;
+
+   foreach_list(node, vs->ir) {
+      ir_variable *const output_var = ((ir_instruction *) node)->as_variable();
+
+      if (output_var == NULL
+      ||  output_var->mode != ir_var_out
+      ||  output_var->location != -1)
+	 continue;
+
+      /* Find a transform feedback varying variable that has
+       * the same name as the shader variable.
+       */
+      int varying_index = -1;
+      for (int num_name = 0; num_name < num_names; num_name++) {
+         char *name = *names++;
+         if (strcmp(output_var->name, name) == 0) {
+            varying_index = num_name;
+            break;
+         }
+      }
+
+      if (varying_index == -1)
+	 continue;
+
+      output_var->location = output_index;
+
+      /* FINISHME: Support for "varying" records in GLSL 1.50. */
+      assert(!output_var->type->is_record());
+
+      if (output_var->type->is_array()) {
+	 const unsigned slots = output_var->type->length
+	    * output_var->type->fields.array->matrix_columns;
+
+	 output_index += slots;
+      } else {
+	 const unsigned slots = output_var->type->matrix_columns;
+
+	 output_index += slots;
+      }
+   }
+}
+
+
+void
 link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 {
    void *mem_ctx = ralloc_context(NULL); // temporary linker context
@@ -1782,6 +1864,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       prev = i;
    }
 
+   assign_transform_feedback_varying_locations(ctx, prog);
+
    if (prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL) {
       demote_shader_inputs_and_outputs(prog->_LinkedShaders[MESA_SHADER_VERTEX],
 				       ir_var_out);
-- 
1.7.4.1



More information about the mesa-dev mailing list