This adds a function that takes an array of varyings from glTranformFeedbackVaryingsEXT and generates gl_transform_feedback_info, which is supposed to be consumed by drivers. Useful for ir_to_mesa and glsl_to_tgsi.
v2: - changes per Kenneth Graunke's comment - expose the TFB varying parser in ir.h --- src/glsl/Makefile | 1 + src/glsl/SConscript | 1 + src/glsl/ir.h | 35 ++++ src/glsl/ir_set_transform_feedback_outs.cpp | 268 +++++++++++++++++++++++++++ src/mesa/main/mtypes.h | 12 ++ 5 files changed, 317 insertions(+), 0 deletions(-) create mode 100644 src/glsl/ir_set_transform_feedback_outs.cpp diff --git a/src/glsl/Makefile b/src/glsl/Makefile index 504f1fb..f3b8e2e 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -48,6 +48,7 @@ CXX_SOURCES = \ ir_reader.cpp \ ir_rvalue_visitor.cpp \ ir_set_program_inouts.cpp \ + ir_set_transform_feedback_outs.cpp \ ir_validate.cpp \ ir_variable.cpp \ ir_variable_refcount.cpp \ diff --git a/src/glsl/SConscript b/src/glsl/SConscript index 09c7edb..ccd93fe 100644 --- a/src/glsl/SConscript +++ b/src/glsl/SConscript @@ -59,6 +59,7 @@ glsl_sources = [ 'ir_reader.cpp', 'ir_rvalue_visitor.cpp', 'ir_set_program_inouts.cpp', + 'ir_set_transform_feedback_outs.cpp', 'ir_validate.cpp', 'ir_variable.cpp', 'ir_variable_refcount.cpp', diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 404d4cf..f7eaa0a 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -1696,4 +1696,39 @@ extern char * prototype_string(const glsl_type *return_type, const char *name, exec_list *parameters); +/** + * Set transform feedback output locations and other related info + * in gl_program. + * + * \param shaderprog The inputs are the parameters + * from glTransformFeedbackVaryings expected + * to be in gl_shader_program::TransformFeedback. + * + * \param info Where the resulting info is stored. + */ +extern void +do_set_transform_feedback_outs(exec_list *instructions, + struct gl_shader_program *shaderprog, + struct gl_transform_feedback_info *info); + +/** + * The result of parse_tfeedback_decl. + */ +struct tfeedback_decl { + char *name; + bool is_array; + unsigned array_index; +}; + +/** + * This expects expressions of the form "var" and "var[i]", + * where i is a literal. + * + * \param mem_ctx Ralloc context. + * \param input Input string to be parsed. + * \param decl Output structure. + */ +bool parse_tfeedback_decl(const void *mem_ctx, const char *input, + struct tfeedback_decl *decl); + #endif /* IR_H */ diff --git a/src/glsl/ir_set_transform_feedback_outs.cpp b/src/glsl/ir_set_transform_feedback_outs.cpp new file mode 100644 index 0000000..ec20108 --- /dev/null +++ b/src/glsl/ir_set_transform_feedback_outs.cpp @@ -0,0 +1,268 @@ +/* + * Copyright © 2010 Intel Corporation + * Copyright © 2011 Marek Olšák <mar...@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_set_transform_feedback_outs.cpp + * + * Used to obtain info about shader outputs from the GLSL IR + * for transform feedback. + * The driver codegen backend needs to know locations of the outputs + * which are to be stored in transform feedback buffers and the number + * of components each such output has. + * + * This is similar to ir_set_program_inouts. + */ + +extern "C" { +#include "program/hash_table.h" +} +#include "main/core.h" +#include "ir.h" +#include "ir_visitor.h" +#include "glsl_types.h" +#include <cmath> + + +bool parse_tfeedback_decl(const void *mem_ctx, const char *input, + struct tfeedback_decl *decl) +{ + /* We don't have to be pedantic about what is a valid GLSL variable name, + * because any variable with an invalid name can't exist in the IR anyway. + */ + + const char *bracket = strrchr(input, '['); + + if (bracket) { + decl->name = ralloc_strndup(mem_ctx, input, bracket - input); + if (sscanf(bracket, "[%u]", &decl->array_index) == 1) { + decl->is_array = true; + return true; /* Found: "var[i]" */ + } + } else { + decl->name = ralloc_strdup(mem_ctx, input); + return true; + } + + return false; +} + + +class ir_set_transform_feedback_outs : public ir_hierarchical_visitor { +public: + ir_set_transform_feedback_outs(struct gl_shader_program *shaderprog, + struct gl_transform_feedback_info *info); + + ~ir_set_transform_feedback_outs() + { + hash_table_dtor(this->ht); + ralloc_free(this->mem_ctx); + } + + void finalize(); + + virtual ir_visitor_status visit_enter(ir_dereference_array *); + virtual ir_visitor_status visit_enter(ir_function_signature *); + virtual ir_visitor_status visit(ir_dereference_variable *); + virtual ir_visitor_status visit(ir_variable *); + +private: + void get_output(ir_variable *var, unsigned start_index, + unsigned matrix_cols, unsigned length); + + void *mem_ctx; + struct hash_table *ht; + struct gl_transform_feedback_info *info; + GLenum buffer_mode; + + unsigned num_outputs; + struct { + struct tfeedback_decl decl; + unsigned location; + unsigned num_components; + unsigned num_vectors; /* location+0 up to location+(num_vectors-1) + should be stored. */ + } output[MAX_PROGRAM_OUTPUTS]; +}; + + +ir_set_transform_feedback_outs::ir_set_transform_feedback_outs( + struct gl_shader_program *shaderprog, + struct gl_transform_feedback_info *info) + : info(info), buffer_mode(shaderprog->TransformFeedback.BufferMode), + num_outputs(0) +{ + GLuint num_names = shaderprog->TransformFeedback.NumVarying; + GLchar **names = shaderprog->TransformFeedback.VaryingNames; + unsigned i; + + this->mem_ctx = ralloc_context(NULL); + this->ht = hash_table_ctor(0, + hash_table_pointer_hash, + hash_table_pointer_compare); + + /* Parse names. */ + for (i = 0; i < num_names; i++) { + if (!parse_tfeedback_decl(this->mem_ctx, names[i], + &this->output[i].decl)) { + /* shouldn't happen, the linker should have validated + * all the inputs */ + assert(0); + memset(&this->output[i].decl, 0, sizeof(struct tfeedback_decl)); + } + } + this->num_outputs = num_names; +} + +void +ir_set_transform_feedback_outs::finalize() +{ + unsigned i, v, final_num_outs = 0; + + for (i = 0; i < this->num_outputs; i++) { + for (v = 0; v < this->output[i].num_vectors; v++) { + info->Outputs[final_num_outs].OutputRegister = + this->output[i].location + v; + info->Outputs[final_num_outs].NumComponents = + this->output[i].num_components; + info->Outputs[final_num_outs].OutputBuffer = + this->buffer_mode == GL_SEPARATE_ATTRIBS ? i : 0; + final_num_outs++; + } + } + + info->NumOutputs = final_num_outs; +} + +void +ir_set_transform_feedback_outs::get_output(ir_variable *var, + unsigned start_index, + unsigned matrix_cols, + unsigned length) +{ + unsigned i; + + assert(var->mode == ir_var_out); + + for (i = 0; i < this->num_outputs; i++) { + if (strcmp(var->name, this->output[i].decl.name) == 0) { + if (var->type->is_array()) { + /* Array variable */ + if (this->output[i].decl.is_array && + this->output[i].decl.array_index >= start_index && + this->output[i].decl.array_index < start_index+length) { + this->output[i].location = + var->location + + this->output[i].decl.array_index * matrix_cols; + this->output[i].num_components = + var->type->fields.array->vector_elements; + this->output[i].num_vectors = matrix_cols; + } + } else { + /* Regular variable (scalar, vector, or matrix) */ + this->output[i].location = var->location + start_index * matrix_cols; + this->output[i].num_components = var->type->vector_elements; + this->output[i].num_vectors = length * matrix_cols; + } + } + } +} + + +ir_visitor_status +ir_set_transform_feedback_outs::visit(ir_dereference_variable *ir) +{ + if (hash_table_find(this->ht, ir->var) == NULL) + return visit_continue; + + if (ir->type->is_array()) { + this->get_output(ir->var, 0, ir->type->fields.array->matrix_columns, + ir->type->length); + } else { + this->get_output(ir->var, 0, ir->type->matrix_columns, 1); + } + + return visit_continue; +} + + +ir_visitor_status +ir_set_transform_feedback_outs::visit_enter(ir_dereference_array *ir) +{ + ir_dereference_variable *deref_var; + ir_constant *index = ir->array_index->as_constant(); + deref_var = ir->array->as_dereference_variable(); + ir_variable *var = NULL; + + /* Check that we're dereferencing a shader out */ + if (deref_var) + var = (ir_variable *)hash_table_find(this->ht, deref_var->var); + + if (index && var) { + int mat_col = 1; + + if (deref_var->type->is_array() && + deref_var->type->fields.array->is_matrix()) { + mat_col = deref_var->type->fields.array->matrix_columns; + } + + this->get_output(var, index->value.i[0], mat_col, 1); + return visit_continue_with_parent; + } + + return visit_continue; +} + + +ir_visitor_status +ir_set_transform_feedback_outs::visit(ir_variable *ir) +{ + if (ir->mode == ir_var_out) { + hash_table_insert(this->ht, ir, ir); + } + + return visit_continue; +} + + +ir_visitor_status +ir_set_transform_feedback_outs::visit_enter(ir_function_signature *ir) +{ + /* We don't want to descend into the function parameters and + * consider them as shader inputs or outputs. + */ + visit_list_elements(this, &ir->body); + return visit_continue_with_parent; +} + + +void +do_set_transform_feedback_outs(exec_list *instructions, + struct gl_shader_program *shaderprog, + struct gl_transform_feedback_info *info) +{ + ir_set_transform_feedback_outs v(shaderprog, info); + + visit_list_elements(&v, instructions); + v.finalize(); +} diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 3f3bc4e..1dadfdd 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1813,6 +1813,16 @@ struct prog_instruction; struct gl_program_parameter_list; struct gl_uniform_list; +/** Post-link transform feedback info. */ +struct gl_transform_feedback_info { + unsigned NumOutputs; + + struct { + unsigned OutputRegister; + unsigned OutputBuffer; + unsigned NumComponents; + } Outputs[MAX_PROGRAM_OUTPUTS]; +}; /** * Base class for any kind of program object @@ -1837,6 +1847,8 @@ struct gl_program GLbitfield SamplersUsed; /**< Bitfield of which samplers are used */ GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */ + /** Post-link transform feedback info. */ + struct gl_transform_feedback_info TransformFeedback; /** Named parameters, constants, etc. from program text */ struct gl_program_parameter_list *Parameters; -- 1.7.4.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev