[Mesa-dev] [PATCH 1/5] glsl: Add a union location_tree * type to hold more storage information.

Vincent Lejeune vljn at ovi.com
Tue Jan 24 13:05:10 PST 2012


Ir_variable::location field is currently represented by a single int.
Datas of composite type (arrays, records) is assumed to be stored in a
linear fashion from this base location. In some situation this assumption
is not optimal : struct fields cannot be stored in a custom order and a
 single location (which is often used to identify a vec4-like register in
hardware) cannot be shared by several datas.
Location_tree data structure is a tree datatype that can store information
for every fields of a record (allowing to reorder them) and store the
location of the leaf type (float, int, veci, everything that can be hold
in a hardware reg) in a byte-aligned way, so that 2 datas/fields can be
stored in a same reg using different components.
---
 src/glsl/Makefile.sources  |    1 +
 src/glsl/location_tree.cpp |  226 ++++++++++++++++++++++++++++++++++++++++++++
 src/glsl/location_tree.h   |  150 +++++++++++++++++++++++++++++
 3 files changed, 377 insertions(+), 0 deletions(-)
 create mode 100644 src/glsl/location_tree.cpp
 create mode 100644 src/glsl/location_tree.h

diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
index 5e80af2..db46322 100644
--- a/src/glsl/Makefile.sources
+++ b/src/glsl/Makefile.sources
@@ -45,6 +45,7 @@ LIBGLSL_CXX_SOURCES := \
 	linker.cpp \
 	link_functions.cpp \
 	link_uniforms.cpp \
+	location_tree.cpp \
 	loop_analysis.cpp \
 	loop_controls.cpp \
 	loop_unroll.cpp \
diff --git a/src/glsl/location_tree.cpp b/src/glsl/location_tree.cpp
new file mode 100644
index 0000000..84d3945
--- /dev/null
+++ b/src/glsl/location_tree.cpp
@@ -0,0 +1,226 @@
+#include "location_tree.h"
+#include "ralloc.h"
+#include "ir.h"
+
+
+void
+set_vanilla_location_to_variable(union location_tree *lt, const glsl_type *const type, int &index)
+{
+   if (type->is_record()) {
+      for (unsigned i = 0; i < type->length; i++) {
+         set_vanilla_location_to_variable(lt->AsRecord.Fields[i], type->fields.structure[i].type, index);
+      }
+   }
+
+   if (type->is_array()) {
+      unsigned old_index = index;
+      set_vanilla_location_to_variable(lt->AsArray.FirstElement, type->fields.array, index);
+      unsigned new_index = index;
+      unsigned stride = new_index - old_index;
+      lt->AsArray.Stride = 16 * stride;
+      index += (type->length - 1) * stride;
+   }
+
+   if (type->is_matrix()) {
+      lt->AsArray.Stride = 16;
+      lt->AsArray.FirstElement->AsLeaf.Offset = 16 * index;
+      index += type->matrix_columns;
+   }
+
+   if (type->is_scalar() || type->is_vector()) {
+      lt->AsLeaf.Offset = 16 * index;
+      index++;
+   }
+}
+
+union location_tree *
+location_tree_create(void *ctx, const glsl_type *const type)
+{
+   unsigned i;
+   union location_tree *result = rzalloc(ctx, union location_tree);
+
+   if (type->is_array())
+      result->AsArray.FirstElement = location_tree_create(ctx, type->fields.array);
+   if (type->is_matrix())
+      result->AsArray.FirstElement = location_tree_create(ctx, glsl_type::vec4_type);
+   if (type->is_record()) {
+      result->AsRecord.Fields = rzalloc_array(ctx, union location_tree *, type->length);
+      for (i = 0; i < type->length; i++) {
+         result->AsRecord.Fields[i] = location_tree_create(ctx, type->fields.structure[i].type);
+      }
+   }
+
+   return result;
+}
+
+union location_tree *
+location_tree_duplicate(void *ctx, const location_tree *src, const glsl_type *const type)
+{
+   unsigned i;
+   union location_tree *result = rzalloc(ctx, union location_tree);
+   memcpy(result, src, sizeof(union location_tree));
+
+   if (type->is_array())
+      result->AsArray.FirstElement = location_tree_duplicate(ctx, src->AsArray.FirstElement, type->fields.array);
+   if (type->is_record()) {
+      result->AsRecord.Fields = rzalloc_array(result, union location_tree *, type->length);
+      for (i = 0; i < type->length; i++) {
+         result->AsRecord.Fields[i] = location_tree_duplicate(ctx, src->AsRecord.Fields[i], type->fields.structure[i].type);
+      }
+   }
+
+   return result;
+}
+
+struct register_info*
+get_reg_info_recursive(void *ctx, struct register_info* partial_result, unsigned &size, unsigned &shadow_size,
+   const union location_tree *storage, const glsl_type *const type, unsigned offset = 0)
+{
+   if (type->is_record()) {
+      for (unsigned i = 0; i < type->length; i++) {
+         partial_result = get_reg_info_recursive(ctx, partial_result, size, shadow_size, storage->AsRecord.Fields[i], type->fields.structure[i].type, offset);
+      }
+   }
+
+   if (type->is_array()) {
+      for (unsigned i = 0; i < type->length; i++) {
+         partial_result = get_reg_info_recursive(ctx, partial_result, size, shadow_size, storage->AsArray.FirstElement, type->fields.array, offset + i * storage->AsArray.Stride);
+      }
+   }
+
+   if (type->is_matrix()) {
+      unsigned matrix_columns = type->matrix_columns;
+      while (size + matrix_columns > shadow_size) {
+         shadow_size *= 2;
+         partial_result = reralloc(ctx, partial_result, struct register_info, shadow_size);
+      }
+      unsigned total_offset = storage->AsArray.FirstElement->AsLeaf.Offset + offset;
+      unsigned writemask;
+
+      switch(type->vector_elements) {
+         case 4:
+            writemask = 15;
+            break;
+         case 3:
+            writemask = 7;
+            break;
+         case 2:
+            writemask = 3;
+            break;
+         default:
+            writemask = 1;
+            break;
+      }
+      unsigned writemask_offset = (total_offset/4) % 4;
+      writemask = writemask << writemask_offset;
+      for (unsigned i = 0; i < matrix_columns; i++) {
+         partial_result[size-1 + i].index = total_offset / 16 + i;
+         partial_result[size-1 + i].writemask_offset = writemask_offset;
+      }
+      size += matrix_columns;
+
+   }
+
+   if (type->is_vector() || type->is_scalar()) {
+      if (size + 1 > shadow_size) {
+         shadow_size *= 2;
+         partial_result = reralloc(ctx, partial_result, struct register_info, shadow_size);
+      }
+
+      unsigned total_offset = storage->AsLeaf.Offset + offset;
+      partial_result[size-1].index = total_offset / 16;
+      unsigned &writemask_offset = partial_result[size-1].writemask_offset;
+      writemask_offset = (total_offset/4) % 4;
+
+
+      size ++;
+   }
+
+   return partial_result;
+}
+
+const struct register_info *
+get_register_info(union location_tree *storage, const glsl_type *const type, unsigned &size)
+{
+   void *ctx = ralloc_context(NULL);
+   unsigned one = size = 1;
+   struct register_info *result = rzalloc_array(ctx, struct register_info, one);
+   result = get_reg_info_recursive(ctx, result, size, one, storage, type);
+   size --;
+   return result;
+}
+
+const struct range_info
+get_varying_range_info (union location_tree *storage, const glsl_type *const type)
+{
+   unsigned size, min, max;
+   const struct register_info *tmp = get_register_info(storage, type, size);
+   min = tmp[0].index;
+   max = tmp[0].index;
+   for (unsigned i = 1; i < size; i++ ) {
+      min = (min < tmp[i].index) ? min : tmp[i].index;
+      max = (max > tmp[i].index) ? max : tmp[i].index;
+   }
+   ralloc_free((void *) tmp);
+   const range_info result= { min, max - min + 1 };
+
+   return result;
+}
+
+location_tree_visitor::location_tree_visitor() :
+   static_offset(0), indirect_strides_count(0), ctx(ralloc_context(NULL))
+{
+   indirections = rzalloc_array(ctx, struct indirect_stride, 1);
+   indirect_strides_shadow_count = 1;
+}
+
+location_tree_visitor::~location_tree_visitor()
+{
+   ralloc_free(ctx);
+}
+
+ir_visitor_status
+location_tree_visitor::visit(ir_dereference_variable *ir)
+{
+   tree = ir->var->complete_location;
+
+   return visit_continue;
+}
+
+ir_visitor_status
+location_tree_visitor::visit_leave(ir_dereference_record *ir)
+{
+   for (unsigned i = 0; i < ir->type->length; i++) {
+	if (strcmp(ir->field, ir->type->fields.structure[i].name) == 0) {
+	   tree = tree->AsRecord.Fields[i];
+	}
+   }
+   return visit_continue;
+}
+
+ir_visitor_status
+location_tree_visitor::visit_enter(ir_dereference_array *ir)
+{
+   ir->array->accept(this);
+
+   ir_constant *cst = ir->array_index->as_constant();
+   unsigned stride = tree->AsArray.Stride / 16;
+   if (cst) {
+      static_offset += cst->value.i[0] * stride;
+   } else {
+      indirect_strides_count ++;
+      DYNAMIC_RESIZE(ctx, indirections, struct indirect_stride, indirect_strides_count, indirect_strides_shadow_count);
+
+      indirections[indirect_strides_count - 1].rvalue = ir->array_index;
+      indirections[indirect_strides_count - 1].stride = stride;
+   }
+   tree = tree->AsArray.FirstElement;
+
+   return visit_continue_with_parent;
+}
+
+const register_info *
+location_tree_visitor::get_result_registers(const glsl_type *const type, unsigned &size) const
+{
+   return get_register_info(tree, type, size);
+}
diff --git a/src/glsl/location_tree.h b/src/glsl/location_tree.h
new file mode 100644
index 0000000..f99385b
--- /dev/null
+++ b/src/glsl/location_tree.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright © 2012 Vincent Lejeune
+ *
+ * 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.
+ */
+
+#ifndef LOCATION_TREE_H
+#define LOCATION_TREE_H
+
+#include "glsl_types.h"
+#include "ir_hierarchical_visitor.h"
+
+#define DYNAMIC_RESIZE(ctx, ptr, type, target_size, shadow_size) \
+   { \
+      while ((target_size) > (shadow_size)) { \
+         (shadow_size) *= 2; \
+         (ptr) = reralloc((ctx), (ptr), type, (shadow_size)); \
+      } \
+   }
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Holds storage information (offset and stride) about complex data type
+ */
+union location_tree
+{
+   struct {
+      GLuint Offset; /** Offset in bytes from start of buffer */
+   } AsLeaf; /** Associated type is scalar or vector not in an array */
+   struct {
+      union location_tree **Fields; /** Array of location_tree * associated with each fields */
+   } AsRecord; /** Associated type is record */
+   struct {
+      GLuint Stride; /** Stride in bytes between elements */
+      union location_tree *FirstElement; /** Array of location_tree * that holds storage info for
+      the first element of the array ; info about others element are deducable using this and Stride */
+   } AsArray;
+};
+
+
+/**
+ * Assign location_tree values the "traditionnal" way : Follow declaration order,
+ * every fields/array elements/... takes a single register.
+ * - First param is location_tree to modify
+ * - Second param is type
+ * - Third one is index to set as input, next free index as output
+ */
+void
+set_vanilla_location_to_variable(union location_tree *, const glsl_type *const, int &);
+
+/**
+ * Create a ralloced location tree.
+ * - First param is ralloc context
+ * - Second param is type to follow
+ */
+union location_tree *
+location_tree_create(void *, const glsl_type *const);
+
+/**
+ * Dupplicate a ralloced location tree.
+ * - First param is context of new tree
+ * - Second param is source
+ * - Third one is type to follow for both tree
+ */
+union location_tree *
+location_tree_duplicate(void *, const union location_tree *, const glsl_type *const);
+
+
+
+/**
+ * This function returns the range of registers involved to store a single varying.
+ * The involved registers can store others varyings if there is varying packing.
+ */
+
+struct range_info {
+   unsigned index;
+   unsigned involved_reg_counts;
+};
+
+const struct range_info
+get_varying_range_info (union location_tree *, const glsl_type *const);
+
+
+/**
+ * This function returns an array store location of a single varying, in the declaration order.
+ * The last param returns the size of the array.
+ */
+struct register_info {
+   unsigned index;
+   unsigned writemask_offset;
+};
+
+
+const struct register_info *
+get_register_info(union location_tree *, const glsl_type *const, unsigned &);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+class location_tree_visitor : public ir_hierarchical_visitor
+{
+protected:
+   union location_tree *tree;
+   void *ctx;
+
+public:
+   struct indirect_stride {
+      class ir_rvalue *rvalue;
+      unsigned stride;
+   };
+
+   struct indirect_stride *indirections;
+
+   unsigned indirect_strides_count;
+   unsigned indirect_strides_shadow_count;
+   unsigned static_offset;
+
+   location_tree_visitor();
+   ~location_tree_visitor();
+   ir_visitor_status visit(ir_dereference_variable *);
+   ir_visitor_status visit_enter(ir_dereference_array *);
+   ir_visitor_status visit_leave(ir_dereference_record *);
+   const register_info *get_result_registers(const glsl_type *const, unsigned &) const;
+};
+
+#endif
+
+#endif // LOCATION_TREE_H
-- 
1.7.7



More information about the mesa-dev mailing list