/* * Copyright © 2017 Gert Wollny * * 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 MESA_GLSL_TO_TGSI_ARRAY_MERGE_H #define MESA_GLSL_TO_TGSI_ARRAY_MERGE_H #include "st_glsl_to_tgsi_private.h" #include /* Until mesa/st officialy requires c++11 */ #if __cplusplus < 201103L #define nullptr 0 #endif /* Helper class to merge the live ranges of an arrays. * * For arrays the array length, live range, and component access needs to * be kept, because when live ranges are merged or arrays are interleaved * one can only merge or interleave an array into another with equal or more * elements. For interleaving it is also required that the sum of used swizzles * is at most four. */ class array_live_range { public: array_live_range(); array_live_range(unsigned aid, unsigned alength); array_live_range(unsigned aid, unsigned alength, int first_access, int last_access, int mask); void set_live_range(int first_access, int last_access); void set_begin(int _begin){first_access = _begin;} void set_end(int _end){last_access = _end;} void set_access_mask(int s); static void merge(array_live_range *a, array_live_range *b); static void interleave(array_live_range *a, array_live_range *b); int array_id() const {return id;} int target_array_id() const {return target_array ? target_array->id : 0;} const array_live_range *final_target() const {return target_array ? target_array->final_target() : this;} unsigned array_length() const { return length;} int begin() const { return first_access;} int end() const { return last_access;} int access_mask() const { return component_access_mask;} int used_components() const {return used_component_count;} bool time_doesnt_overlap(const array_live_range& other) const; void print(std::ostream& os) const; bool is_mapped() const { return target_array != nullptr;} int8_t remap_one_swizzle(int8_t idx) const; private: void init_swizzles(); void set_target(array_live_range *target); void merge_live_range_from(array_live_range *other); void interleave_into(array_live_range *other); unsigned id; unsigned length; int first_access; int last_access; uint8_t component_access_mask; uint8_t used_component_count; array_live_range *target_array; int8_t swizzle_map[4]; }; inline std::ostream& operator << (std::ostream& os, const array_live_range& lt) { lt.print(os); return os; } namespace tgsi_array_merge { /* Helper class to apply array merge and interleav to the shader. * The interface is exposed here to make unit tests possible. */ class array_remapping { public: /** Create an invalid mapping that is used as place-holder for * arrays that are not mapped at all. */ array_remapping(); /* Predefined remapping, needed for testing */ array_remapping(int trgt_array_id, const int8_t swizzle[]); /* Initialiaze the mapping from an array_live_range that has been * processed by the array merge and interleave algorithm. */ void init_from(const array_live_range& range); /* (Re)-set target id, needed when the mapping is resolved */ void set_target_id(int tid) {target_id = tid;} /* Defines a valid remapping */ bool is_valid() const {return target_id > 0;} /* Translates the write mask to the new, interleaved component * position */ int map_writemask(int original_write_mask) const; /* Translates all read swizzles to the new, interleaved component * swizzles */ uint16_t map_swizzles(uint16_t original_swizzle) const; /* Move the read swizzles to the positiones that correspond to * a changed write mask. */ uint16_t move_read_swizzles(uint16_t original_swizzle) const; unsigned target_array_id() const {return target_id;} void print(std::ostream& os) const; friend bool operator == (const array_remapping& lhs, const array_remapping& rhs); private: void interleave(int trgt_access_mask, int src_access_mask); unsigned target_id; int8_t read_swizzle_map[4]; }; inline std::ostream& operator << (std::ostream& os, const array_remapping& am) { am.print(os); return os; } /* Apply the array remapping (internal use, exposed here for testing) */ bool get_array_remapping(int narrays, array_live_range *array_live_ranges, array_remapping *remapping); /* Apply the array remapping (internal use, exposed here for testing) */ int remap_arrays(int narrays, unsigned *array_sizes, exec_list *instructions, array_remapping *map); } /** Remap the array access to finalize the array merging and interleaving. * @param[in] narrays number of input arrays, * @param[in,out] array_sizes length array of input arrays, on output the * array sizes will be updated according to the remapping, * @param[in,out] instructions TGSI program, on output the arrays access is * remapped to the new array layout, * @param[in] array_live_ranges live ranges and access information of the * arrays. * @returns number of remaining arrays */ int merge_arrays(int narrays, unsigned *array_sizes, exec_list *instructions, class array_live_range *arr_live_ranges); #endif