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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev