[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