[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