blob: 15738a817d342e562a0c60719f0e9a00572c9859 [file] [log] [blame]
/*
* 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 <iosfwd>
/* 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