[Mesa-dev] [PATCH 2/3] glsl: translate transform feedback varyings into low-level representation
Marek Olšák
maraeo at gmail.com
Tue Nov 1 12:48:01 PDT 2011
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 <maraeo at 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
More information about the mesa-dev
mailing list