From 25ed3bef9b84c06cda06c9e77ff733d1ba863bf5 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 4 Dec 2012 10:34:45 -0800 Subject: [PATCH] glsl/linker: Defer recording transform feedback locations. This patch subdivides the loop that assigns varying locations into two phases: one phase to match up varyings between shader stages (and assign them varying locations), and a second phase to record the varying assignments for use by transform feedback. This paves the way for varying packing, which will require us to further subdivide the first phase. In addition, it lets us avoid a clumsy O(n^2) algorithm, since we can now record the locations of all transform feedback varyings in a single pass through the tfeedback_decls array, rather than have to iterate through the array after assigning each varying. Reviewed-by: Eric Anholt --- src/glsl/linker.cpp | 103 +++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index b13a6aa1ab6..e4d31d79d69 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -1537,18 +1537,12 @@ public: static bool is_same(const tfeedback_decl &x, const tfeedback_decl &y); bool assign_location(struct gl_context *ctx, struct gl_shader_program *prog, ir_variable *output_var); - bool accumulate_num_outputs(struct gl_shader_program *prog, unsigned *count); + unsigned get_num_outputs() const; bool store(struct gl_context *ctx, struct gl_shader_program *prog, struct gl_transform_feedback_info *info, unsigned buffer, const unsigned max_outputs) const; - - /** - * True if assign_location() has been called for this object. - */ - bool is_assigned() const - { - return this->location != -1; - } + ir_variable *find_output_var(gl_shader_program *prog, + gl_shader *producer) const; bool is_next_buffer_separator() const { @@ -1560,20 +1554,9 @@ public: return !this->next_buffer_separator && !this->skip_components; } - /** - * Determine whether this object refers to the variable var. - */ - bool matches_var(ir_variable *var) const - { - if (this->is_clip_distance_mesa) - return strcmp(var->name, "gl_ClipDistanceMESA") == 0; - else - return strcmp(var->name, this->var_name) == 0; - } - /** * The total number of varying components taken up by this variable. Only - * valid if is_assigned() is true. + * valid if assign_location() has been called. */ unsigned num_components() const { @@ -1822,34 +1805,18 @@ tfeedback_decl::assign_location(struct gl_context *ctx, } -bool -tfeedback_decl::accumulate_num_outputs(struct gl_shader_program *prog, - unsigned *count) +unsigned +tfeedback_decl::get_num_outputs() const { if (!this->is_varying()) { - return true; - } - - if (!this->is_assigned()) { - /* From GL_EXT_transform_feedback: - * A program will fail to link if: - * - * * any variable name specified in the array is not - * declared as an output in the geometry shader (if present) or - * the vertex shader (if no geometry shader is present); - */ - linker_error(prog, "Transform feedback varying %s undeclared.", - this->orig_name); - return false; + return 0; } unsigned translated_size = this->size; if (this->is_clip_distance_mesa) translated_size = (translated_size + 3) / 4; - *count += translated_size * this->matrix_columns; - - return true; + return translated_size * this->matrix_columns; } @@ -1926,6 +1893,29 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, } +ir_variable * +tfeedback_decl::find_output_var(gl_shader_program *prog, + gl_shader *producer) const +{ + const char *name = this->is_clip_distance_mesa + ? "gl_ClipDistanceMESA" : this->var_name; + ir_variable *var = producer->symbols->get_variable(name); + if (var && var->mode == ir_var_out) + return var; + + /* From GL_EXT_transform_feedback: + * A program will fail to link if: + * + * * any variable name specified in the array is not + * declared as an output in the geometry shader (if present) or + * the vertex shader (if no geometry shader is present); + */ + linker_error(prog, "Transform feedback varying %s undeclared.", + this->orig_name); + return NULL; +} + + /** * Parse all the transform feedback declarations that were passed to * glTransformFeedbackVaryings() and store them in tfeedback_decl objects. @@ -2110,21 +2100,25 @@ assign_varying_locations(struct gl_context *ctx, assign_varying_location(input_var, output_var, &input_index, &output_index); } + } - for (unsigned i = 0; i < num_tfeedback_decls; ++i) { - if (!tfeedback_decls[i].is_varying()) - continue; + for (unsigned i = 0; i < num_tfeedback_decls; ++i) { + if (!tfeedback_decls[i].is_varying()) + continue; - if (!tfeedback_decls[i].is_assigned() && - tfeedback_decls[i].matches_var(output_var)) { - if (output_var->is_unmatched_generic_inout) { - assign_varying_location(input_var, output_var, &input_index, - &output_index); - } - if (!tfeedback_decls[i].assign_location(ctx, prog, output_var)) - return false; - } + ir_variable *output_var + = tfeedback_decls[i].find_output_var(prog, producer); + + if (output_var == NULL) + return false; + + if (output_var->is_unmatched_generic_inout) { + assign_varying_location(NULL, output_var, &input_index, + &output_index); } + + if (!tfeedback_decls[i].assign_location(ctx, prog, output_var)) + return false; } unsigned varying_vectors = 0; @@ -2233,8 +2227,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, unsigned num_outputs = 0; for (unsigned i = 0; i < num_tfeedback_decls; ++i) - if (!tfeedback_decls[i].accumulate_num_outputs(prog, &num_outputs)) - return false; + num_outputs += tfeedback_decls[i].get_num_outputs(); prog->LinkedTransformFeedback.Outputs = rzalloc_array(prog, -- 2.30.2