GL_ARB_uniform_buffer_object spec defines standard layout rules to define how data are packed in a uniform buffer object, using offset and stride. A single ir_variable::location is not enough to hold every possible case and thus we defined a new type whose structure mirror the one of associated glsl_type of stored variable.
Conflicts: src/mesa/main/mtypes.h --- 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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev