mesa/st: Remove st_glsl_to_tgsi.

It is no longer called, and can be retired.

Fixes: #1924, #822, #6073

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8044>
This commit is contained in:
Emma Anholt 2022-04-08 10:56:17 -07:00 committed by Marge Bot
parent b167203cfe
commit 214c774ba6
19 changed files with 57 additions and 14861 deletions

View file

@ -567,14 +567,12 @@ struct gl_program
GLubyte SamplerUnits[MAX_SAMPLERS]; GLubyte SamplerUnits[MAX_SAMPLERS];
struct pipe_shader_state state; struct pipe_shader_state state;
struct glsl_to_tgsi_visitor* glsl_to_tgsi;
struct ati_fragment_shader *ati_fs; struct ati_fragment_shader *ati_fs;
uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */ uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */
void *serialized_nir; void *serialized_nir;
unsigned serialized_nir_size; unsigned serialized_nir_size;
/* used when bypassing glsl_to_tgsi: */
struct gl_shader_program *shader_program; struct gl_shader_program *shader_program;
struct st_variant *variants; struct st_variant *variants;

View file

@ -363,14 +363,6 @@ files_libmesa = files(
'state_tracker/st_glsl_to_ir.cpp', 'state_tracker/st_glsl_to_ir.cpp',
'state_tracker/st_glsl_to_ir.h', 'state_tracker/st_glsl_to_ir.h',
'state_tracker/st_glsl_to_nir.cpp', 'state_tracker/st_glsl_to_nir.cpp',
'state_tracker/st_glsl_to_tgsi.cpp',
'state_tracker/st_glsl_to_tgsi.h',
'state_tracker/st_glsl_to_tgsi_array_merge.cpp',
'state_tracker/st_glsl_to_tgsi_array_merge.h',
'state_tracker/st_glsl_to_tgsi_private.cpp',
'state_tracker/st_glsl_to_tgsi_private.h',
'state_tracker/st_glsl_to_tgsi_temprename.cpp',
'state_tracker/st_glsl_to_tgsi_temprename.h',
'state_tracker/st_manager.c', 'state_tracker/st_manager.c',
'state_tracker/st_manager.h', 'state_tracker/st_manager.h',
'state_tracker/st_nir.h', 'state_tracker/st_nir.h',

View file

@ -45,7 +45,6 @@
#include "util/u_atomic.h" #include "util/u_atomic.h"
#include "state_tracker/st_program.h" #include "state_tracker/st_program.h"
#include "state_tracker/st_glsl_to_tgsi.h"
#include "state_tracker/st_context.h" #include "state_tracker/st_context.h"
/** /**
@ -250,9 +249,6 @@ _mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
st_release_variants(st, prog); st_release_variants(st, prog);
if (prog->glsl_to_tgsi)
free_glsl_to_tgsi_visitor(prog->glsl_to_tgsi);
free(prog->serialized_nir); free(prog->serialized_nir);
if (prog == &_mesa_DummyProgram) if (prog == &_mesa_DummyProgram)

View file

@ -173,15 +173,6 @@ st_nir_lookup_parameter_index(struct gl_program *prog, nir_variable *var)
* fails. In this case just find the first matching "color.*".. * fails. In this case just find the first matching "color.*"..
* *
* Note for arrays you could end up w/ color[n].f, for example. * Note for arrays you could end up w/ color[n].f, for example.
*
* glsl_to_tgsi works slightly differently in this regard. It is
* emitting something more low level, so it just translates the
* params list 1:1 to CONST[] regs. Going from GLSL IR to TGSI,
* it just calculates the additional offset of struct field members
* in glsl_to_tgsi_visitor::visit(ir_dereference_record *ir) or
* glsl_to_tgsi_visitor::visit(ir_dereference_array *ir). It never
* needs to work backwards to get base var loc from the param-list
* which already has them separated out.
*/ */
if (!prog->sh.data->spirv) { if (!prog->sh.data->spirv) {
int namelen = strlen(var->name); int namelen = strlen(var->name);

File diff suppressed because it is too large Load diff

View file

@ -1,71 +0,0 @@
/*
* Copyright © 2010 Intel Corporation
* Copyright © 2011 Bryan Cain
*
* 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 ST_GLSL_TO_TGSI_H
#define ST_GLSL_TO_TGSI_H
#include "main/glheader.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#ifdef __cplusplus
extern "C" {
#endif
struct gl_context;
struct gl_shader;
struct gl_shader_program;
struct glsl_to_tgsi_visitor;
struct ureg_program;
enum pipe_error st_translate_program(
struct gl_context *ctx,
enum pipe_shader_type procType,
struct ureg_program *ureg,
struct glsl_to_tgsi_visitor *program,
const struct gl_program *proginfo,
GLuint numInputs,
const ubyte inputMapping[],
const ubyte inputSlotToAttr[],
const ubyte inputSemanticName[],
const ubyte inputSemanticIndex[],
const ubyte interpMode[],
GLuint numOutputs,
const ubyte outputMapping[],
const ubyte outputSemanticName[],
const ubyte outputSemanticIndex[]);
void free_glsl_to_tgsi_visitor(struct glsl_to_tgsi_visitor *v);
GLboolean
st_link_tgsi(struct gl_context *ctx, struct gl_shader_program *prog);
enum tgsi_semantic
_mesa_sysval_to_semantic(unsigned sysval);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,698 +0,0 @@
/*
* 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.
*/
/* A short overview on how the array merging works:
*
* Inputs:
* - per array information: live range, access mask, size
* - the program
*
* Output:
* - the program with updated array addressing
*
* Pseudo algorithm:
*
* repeat
* for all pairs of arrays:
* if they have non-overlapping live ranges and equal access masks:
* - pick shorter array
* - merge its live range into the longer array
* - set its merge target array to the longer array
* - mark the shorter array as processed
*
* for all pairs of arrays:
* if they have overlapping live ranges use in sum at most four components:
* - pick shorter array
* - evaluate reswizzle map to move its components into the components
* that are not used by the longer array
* - set its merge target array to the longer array
* - mark the shorter array as processed
* - bail out loop
* until no more successfull merges were found
*
* for all pairs of arrays:
* if they have non-overlapping live ranges:
* - pick shorter array
* - merge its live range into the longer array
* - set its merge target array to the longer array
* - mark the shorter array as processed
*
* Finalize remapping map so that target arrays are always final, i.e. have
* themselfes no merge target set.
*
* Example:
* ID | Length | Live range | access mask | target id | reswizzle
* ================================================================
* 1 3 3-10 x___ 0 ____
* 2 4 13-20 x___ 0 ____
* 3 8 3-20 x___ 0 ____
* 4 6 21-40 xy__ 0 ____
* 5 7 12-30 xy__ 0 ____
*
* 1. merge live ranges 1 and 2
*
* ID | Length | Live range | access mask | target id | reswizzle
* ================================================================
* 1 - - x___ 2 ____
* 2 4 3-20 x___ 0 ____
* 3 8 3-20 x___ 0 ____
* 4 6 21-40 xy__ 0 ____
* 5 7 12-30 xy__ 0 ____
*
*
* 3. interleave 2 and 3
*
* ID | Length | Live range | access mask | target id | reswizzle
* ================================================================
* 1 - - x___ 2 ____
* 2 - - x___ 3 _x__
* 3 8 3-20 xy__ 0 ____
* 4 6 21-40 xy__ 0 ____
* 5 7 12-30 xy__ 0 ____
*
* 3. merge live ranges 3 and 4
*
* ID | Length | Live range | access mask | target id | reswizzle
* ================================================================
* 1 - - x___ 2 ____
* 2 - - x___ 3 _x__
* 3 8 3-40 xy__ 0 ____
* 4 - - xy__ 3 ____
* 5 7 3-21 xy__ 0 ____
*
* 4. interleave 3 and 5
*
* ID | Length | Live range | access mask | target id | reswizzle
* ================================================================
* 1 - - x___ 2 ____
* 2 - - x___ 3 _x__
* 3 8 3-40 xy__ 0 ____
* 4 - - xy__ 3 ____
* 5 - - xy__ 3 __xy
*
* 5. finalize remapping
* (Array 1 has been merged with 2 that was later interleaved, so
* the reswizzeling must be propagated.
*
* ID | Length | Live range | new access mask | target id | reswizzle
* ================================================================
* 1 - - _y__ 3 _x__
* 2 - - _y__ 3 _x__
* 3 8 3-40 xy__ 0 ____
* 4 - - xy__ 3 ____
* 5 - - __zw 3 __xy
*
*/
#include "program/prog_instruction.h"
#include "util/u_math.h"
#include <ostream>
#include <cassert>
#include <algorithm>
#include <iostream>
#include "st_glsl_to_tgsi_array_merge.h"
#if __cplusplus >= 201402L
#include <memory>
using std::unique_ptr;
using std::make_unique;
#endif
#define ARRAY_MERGE_DEBUG 0
#if ARRAY_MERGE_DEBUG > 0
#define ARRAY_MERGE_DUMP(x) do std::cerr << x; while (0)
#define ARRAY_MERGE_DUMP_BLOCK(x) do { x } while (0)
#else
#define ARRAY_MERGE_DUMP(x)
#define ARRAY_MERGE_DUMP_BLOCK(x)
#endif
static const char xyzw[] = "xyzw";
array_live_range::array_live_range():
id(0),
length(0),
first_access(0),
last_access(0),
component_access_mask(0),
used_component_count(0),
target_array(nullptr)
{
init_swizzles();
}
array_live_range::array_live_range(unsigned aid, unsigned alength):
id(aid),
length(alength),
first_access(0),
last_access(0),
component_access_mask(0),
used_component_count(0),
target_array(nullptr)
{
init_swizzles();
}
array_live_range::array_live_range(unsigned aid, unsigned alength, int begin,
int end, int sw):
id(aid),
length(alength),
first_access(begin),
last_access(end),
component_access_mask(sw),
used_component_count(util_bitcount(sw)),
target_array(nullptr)
{
init_swizzles();
}
void array_live_range::init_swizzles()
{
for (int i = 0; i < 4; ++i)
swizzle_map[i] = i;
}
void array_live_range::set_live_range(int _begin, int _end)
{
set_begin(_begin);
set_end(_end);
}
void array_live_range::set_access_mask(int mask)
{
component_access_mask = mask;
used_component_count = util_bitcount(mask);
}
void array_live_range::merge(array_live_range *a, array_live_range *b)
{
if (a->array_length() < b->array_length())
b->merge_live_range_from(a);
else
a->merge_live_range_from(b);
}
void array_live_range::interleave(array_live_range *a, array_live_range *b)
{
if (a->array_length() < b->array_length())
a->interleave_into(b);
else
b->interleave_into(a);
}
void array_live_range::interleave_into(array_live_range *other)
{
for (int i = 0; i < 4; ++i) {
swizzle_map[i] = -1;
}
int trgt_access_mask = other->access_mask();
int summary_access_mask = trgt_access_mask;
int src_swizzle_bit = 1;
int next_free_swizzle_bit = 1;
int k = 0;
unsigned i;
unsigned last_src_bit = util_last_bit(component_access_mask);
for (i = 0; i <= last_src_bit ; ++i, src_swizzle_bit <<= 1) {
/* Jump over empty src component slots (e.g. x__w). This is just a
* safety measure and it is tested for, but it is very likely that the
* emitted code always uses slots staring from x without leaving holes
* (i.e. always xy__ not x_z_ or _yz_ etc).
*/
if (!(src_swizzle_bit & component_access_mask))
continue;
/* Find the next free access slot in the target. */
while ((trgt_access_mask & next_free_swizzle_bit) &&
k < 4) {
next_free_swizzle_bit <<= 1;
++k;
}
assert(k < 4 &&
"Interleaved array would have more then four components");
/* Set the mapping for this component. */
swizzle_map[i] = k;
trgt_access_mask |= next_free_swizzle_bit;
/* Update the joined access mask if we didn't just fill the mapping.*/
if (src_swizzle_bit & component_access_mask)
summary_access_mask |= next_free_swizzle_bit;
}
other->set_access_mask(summary_access_mask);
other->merge_live_range_from(this);
ARRAY_MERGE_DUMP_BLOCK(
std::cerr << "Interleave " << id << " into " << other->id << ", swz:";
for (unsigned i = 0; i < 4; ++i) {
std::cerr << ((swizzle_map[i] >= 0) ? xyzw[swizzle_map[i]] : '_');
}
std::cerr << '\n';
);
}
void array_live_range::merge_live_range_from(array_live_range *other)
{
other->set_target(this);
if (other->begin() < first_access)
first_access = other->begin();
if (other->end() > last_access)
last_access = other->end();
}
int8_t array_live_range::remap_one_swizzle(int8_t idx) const
{
// needs testing
if (target_array) {
idx = swizzle_map[idx];
if (idx >= 0)
idx = target_array->remap_one_swizzle(idx);
}
return idx;
}
void array_live_range::set_target(array_live_range *target)
{
target_array = target;
}
void array_live_range::print(std::ostream& os) const
{
os << "[id:" << id
<< ", length:" << length
<< ", (b:" << first_access
<< ", e:" << last_access
<< "), sw:" << (int)component_access_mask
<< ", nc:" << (int)used_component_count
<< "]";
}
bool array_live_range::time_doesnt_overlap(const array_live_range& other) const
{
return (other.last_access < first_access ||
last_access < other.first_access);
}
namespace tgsi_array_merge {
array_remapping::array_remapping():
target_id(0)
{
for (int i = 0; i < 4; ++i) {
read_swizzle_map[i] = i;
}
}
array_remapping::array_remapping(int trgt_array_id, const int8_t swizzle[]):
target_id(trgt_array_id)
{
for (int i = 0; i < 4; ++i) {
read_swizzle_map[i] = swizzle[i];
}
}
void array_remapping::init_from(const array_live_range& range)
{
target_id = range.is_mapped() ? range.final_target()->array_id(): 0;
for (int i = 0; i < 4; ++i)
read_swizzle_map[i] = range.remap_one_swizzle(i);
}
int array_remapping::map_writemask(int write_mask) const
{
assert(is_valid());
int result_write_mask = 0;
for (int i = 0; i < 4; ++i) {
if (1 << i & write_mask) {
assert(read_swizzle_map[i] >= 0);
result_write_mask |= 1 << read_swizzle_map[i];
}
}
return result_write_mask;
}
uint16_t array_remapping::move_read_swizzles(uint16_t original_swizzle) const
{
assert(is_valid());
/* Since
*
* dst.zw = src.xy in glsl actually is MOV dst.__zw src.__xy
*
* when interleaving the arrays the source swizzles must be moved
* according to the changed dst write mask.
*/
uint16_t out_swizzle = 0;
for (int idx = 0; idx < 4; ++idx) {
uint16_t orig_swz = GET_SWZ(original_swizzle, idx);
int new_idx = read_swizzle_map[idx];
if (new_idx >= 0)
out_swizzle |= orig_swz << 3 * new_idx;
}
return out_swizzle;
}
uint16_t array_remapping::map_swizzles(uint16_t old_swizzle) const
{
uint16_t out_swizzle = 0;
for (int idx = 0; idx < 4; ++idx) {
uint16_t swz = read_swizzle_map[GET_SWZ(old_swizzle, idx)];
out_swizzle |= swz << 3 * idx;
}
return out_swizzle;
}
void array_remapping::print(std::ostream& os) const
{
if (is_valid()) {
os << "[aid: " << target_id << " swz: ";
for (int i = 0; i < 4; ++i)
os << (read_swizzle_map[i] >= 0 ? xyzw[read_swizzle_map[i]] : '_');
os << "]";
} else {
os << "[unused]";
}
}
/* Required by the unit tests */
bool operator == (const array_remapping& lhs, const array_remapping& rhs)
{
if (lhs.target_id != rhs.target_id)
return false;
if (lhs.target_id == 0)
return true;
for (int i = 0; i < 4; ++i) {
if (lhs.read_swizzle_map[i] != rhs.read_swizzle_map[i])
return false;
}
return true;
}
static
bool sort_by_begin(const array_live_range& lhs, const array_live_range& rhs) {
return lhs.begin() < rhs.begin();
}
/* Helper class to evaluate merging and interleaving of arrays */
class array_merge_evaluator {
public:
typedef int (*array_merger)(array_live_range& range_1,
array_live_range& range_2);
array_merge_evaluator(int _narrays, array_live_range *_ranges,
bool _restart);
/** Run the merge strategy on all arrays
* @returns number of successfull merges
*/
int run();
private:
virtual int do_run(array_live_range& range_1, array_live_range& range_2) = 0;
int narrays;
array_live_range *ranges;
bool restart;
};
array_merge_evaluator::array_merge_evaluator(int _narrays,
array_live_range *_ranges,
bool _restart):
narrays(_narrays),
ranges(_ranges),
restart(_restart)
{
}
int array_merge_evaluator::run()
{
int remaps = 0;
for (int i = 0; i < narrays; ++i) {
if (ranges[i].is_mapped())
continue;
for (int j = i + 1; j < narrays; ++j) {
if (!ranges[j].is_mapped()) {
ARRAY_MERGE_DUMP("try merge " << i << " id:" << ranges[i].array_id()
<< " and " << j << " id: "<< ranges[j].array_id()
<< "\n");
int n = do_run(ranges[i], ranges[j]);
if (restart && n)
return n;
remaps += n;
}
}
}
return remaps;
}
/* Merge live ranges if possible at all */
class merge_live_range_always: public array_merge_evaluator {
public:
merge_live_range_always(int _narrays, array_live_range *_ranges):
array_merge_evaluator(_narrays, _ranges, false) {
}
protected:
int do_run(array_live_range& range_1, array_live_range& range_2){
if (range_2.time_doesnt_overlap(range_1)) {
ARRAY_MERGE_DUMP("merge " << range_2 << " into " << range_1 << "\n");
array_live_range::merge(&range_1,&range_2);
return 1;
}
return 0;
}
};
/* Merge live ranges only if they use the same swizzle */
class merge_live_range_equal_swizzle: public merge_live_range_always {
public:
merge_live_range_equal_swizzle(int _narrays, array_live_range *_ranges):
merge_live_range_always(_narrays, _ranges) {
}
private:
int do_run(array_live_range& range_1, array_live_range& range_2){
if (range_1.access_mask() == range_2.access_mask()) {
return merge_live_range_always::do_run(range_1, range_2);
}
return 0;
}
};
/* Interleave arrays if possible */
class interleave_live_range: public array_merge_evaluator {
public:
interleave_live_range(int _narrays, array_live_range *_ranges):
array_merge_evaluator(_narrays, _ranges, true) {
}
private:
int do_run(array_live_range& range_1, array_live_range& range_2){
if ((range_2.used_components() + range_1.used_components() <= 4) &&
!range_1.time_doesnt_overlap(range_2)) {
ARRAY_MERGE_DUMP("Interleave " << range_2 << " into " << range_1 << "\n");
array_live_range::interleave(&range_1, &range_2);
return 1;
}
return 0;
}
};
/* Estimate the array merging: First in a loop, arrays with equal access mask
* are merged, then interleave arrays that together use at most four components,
* and have overlapping live ranges. Finally arrays are merged regardless of
* access mask.
* @param[in] narrays number of arrays
* @param[in,out] alt array life times, the merge target life time will be
* updated with the new life time.
* @param[in,out] remapping track the arraay index remapping and reswizzeling.
* @returns number of merged arrays
*/
bool get_array_remapping(int narrays, array_live_range *ranges,
array_remapping *remapping)
{
int total_remapped = 0;
int n_remapped;
/* Sort by "begin of live range" so that we don't have to restart searching
* after every merge.
*/
std::sort(ranges, ranges + narrays, sort_by_begin);
merge_live_range_equal_swizzle merge_evaluator_es(narrays, ranges);
interleave_live_range interleave_lr(narrays, ranges);
do {
n_remapped = merge_evaluator_es.run();
/* try only one array interleave, if successfull, another
* live_range merge is tried. The test MergeAndInterleave5
* (mesa/st/tests/test_glsl_to_tgsi_array_merge.cpp)
* shows that this can result in more arrays being merged/interleaved.
*/
n_remapped += interleave_lr.run();
total_remapped += n_remapped;
ARRAY_MERGE_DUMP("Remapped " << n_remapped << " arrays\n");
} while (n_remapped > 0);
total_remapped += merge_live_range_always(narrays, ranges).run();
ARRAY_MERGE_DUMP("Remapped a total of " << total_remapped << " arrays\n");
/* Resolve the remapping chain */
for (int i = 1; i <= narrays; ++i) {
ARRAY_MERGE_DUMP("Map " << i << ":");
remapping[ranges[i-1].array_id()].init_from(ranges[i-1]);
}
return total_remapped > 0;
}
/* Remap the arrays in a TGSI program according to the given mapping.
* @param narrays number of arrays
* @param array_sizes array of arrays sizes
* @param map the array remapping information
* @param instructions TGSI program
* @returns number of arrays after remapping
*/
int remap_arrays(int narrays, unsigned *array_sizes,
exec_list *instructions,
array_remapping *map)
{
/* re-calculate arrays */
#if __cplusplus < 201402L
int *idx_map = new int[narrays + 1];
unsigned *old_sizes = new unsigned[narrays];
#else
unique_ptr<int[]> idx_map = make_unique<int[]>(narrays + 1);
unique_ptr<unsigned[]> old_sizes = make_unique<unsigned[]>(narrays);
#endif
memcpy(&old_sizes[0], &array_sizes[0], sizeof(unsigned) * narrays);
/* Evaluate mapping for the array indices and update array sizes */
int new_narrays = 0;
for (int i = 1; i <= narrays; ++i) {
if (!map[i].is_valid()) {
++new_narrays;
array_sizes[new_narrays-1] = old_sizes[i-1];
idx_map[i] = new_narrays;
}
}
/* Map the array ids of merged arrays. */
for (int i = 1; i <= narrays; ++i) {
if (map[i].is_valid()) {
map[i].set_target_id(idx_map[map[i].target_array_id()]);
}
}
/* Map the array ids of merge targets that got only renumbered. */
for (int i = 1; i <= narrays; ++i) {
if (!map[i].is_valid()) {
map[i].set_target_id(idx_map[i]);
}
}
/* Update the array ids and swizzles in the registers */
foreach_in_list(glsl_to_tgsi_instruction, inst, instructions) {
for (unsigned j = 0; j < num_inst_src_regs(inst); j++) {
st_src_reg& src = inst->src[j];
if (src.file == PROGRAM_ARRAY && src.array_id > 0) {
array_remapping& m = map[src.array_id];
if (m.is_valid()) {
src.array_id = m.target_array_id();
src.swizzle = m.map_swizzles(src.swizzle);
}
}
}
for (unsigned j = 0; j < inst->tex_offset_num_offset; j++) {
st_src_reg& src = inst->tex_offsets[j];
if (src.file == PROGRAM_ARRAY && src.array_id > 0) {
array_remapping& m = map[src.array_id];
if (m.is_valid()) {
src.array_id = m.target_array_id();
src.swizzle = m.map_swizzles(src.swizzle);
}
}
}
for (unsigned j = 0; j < num_inst_dst_regs(inst); j++) {
st_dst_reg& dst = inst->dst[j];
if (dst.file == PROGRAM_ARRAY && dst.array_id > 0) {
array_remapping& m = map[dst.array_id];
if (m.is_valid()) {
assert(j == 0 &&
"remapping can only be done for single dest ops");
dst.array_id = m.target_array_id();
dst.writemask = m.map_writemask(dst.writemask);
/* If the target component is moved, then the source swizzles
* must be moved accordingly.
*/
for (unsigned j = 0; j < num_inst_src_regs(inst); j++) {
st_src_reg& src = inst->src[j];
src.swizzle = m.move_read_swizzles(src.swizzle);
}
}
}
}
st_src_reg& res = inst->resource;
if (res.file == PROGRAM_ARRAY && res.array_id > 0) {
array_remapping& m = map[res.array_id];
if (m.is_valid()) {
res.array_id = m.target_array_id();
res.swizzle = m.map_swizzles(res.swizzle);
}
}
}
#if __cplusplus < 201402L
delete[] old_sizes;
delete[] idx_map;
#endif
return new_narrays;
}
}
using namespace tgsi_array_merge;
int merge_arrays(int narrays,
unsigned *array_sizes,
exec_list *instructions,
class array_live_range *arr_live_ranges)
{
array_remapping *map= new array_remapping[narrays + 1];
if (get_array_remapping(narrays, arr_live_ranges, map))
narrays = remap_arrays(narrays, array_sizes, instructions, map);
delete[] map;
return narrays;
}

View file

@ -1,188 +0,0 @@
/*
* 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

View file

@ -1,423 +0,0 @@
/*
* Copyright © 2010 Intel Corporation
* Copyright © 2011 Bryan Cain
* 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.
*/
#include "st_glsl_to_tgsi_private.h"
#include "tgsi/tgsi_info.h"
#include "mesa/program/prog_instruction.h"
#include "mesa/program/prog_print.h"
static int swizzle_for_type(const glsl_type *type, int component = 0)
{
unsigned num_elements = 4;
if (type) {
type = type->without_array();
if (type->is_scalar() || type->is_vector() || type->is_matrix())
num_elements = type->vector_elements;
}
int swizzle = swizzle_for_size(num_elements);
assert(num_elements + component <= 4);
swizzle += component * MAKE_SWIZZLE4(1, 1, 1, 1);
return swizzle;
}
static st_src_reg *
dup_reladdr(const st_src_reg *input)
{
if (!input)
return NULL;
st_src_reg *reg = ralloc(input, st_src_reg);
if (!reg) {
assert(!"can't create reladdr, expect shader breakage");
return NULL;
}
*reg = *input;
return reg;
}
st_src_reg::st_src_reg(gl_register_file file, int index, const glsl_type *type,
int component, unsigned array_id)
{
assert(file != PROGRAM_ARRAY || array_id != 0);
this->file = file;
this->index = index;
this->swizzle = swizzle_for_type(type, component);
this->negate = 0;
this->abs = 0;
this->index2D = 0;
this->type = type ? type->base_type : GLSL_TYPE_ERROR;
this->reladdr = NULL;
this->reladdr2 = NULL;
this->has_index2 = false;
this->double_reg2 = false;
this->array_id = array_id;
this->is_double_vertex_input = false;
}
st_src_reg::st_src_reg(gl_register_file file, int index, enum glsl_base_type type)
{
assert(file != PROGRAM_ARRAY); /* need array_id > 0 */
this->type = type;
this->file = file;
this->index = index;
this->index2D = 0;
this->swizzle = SWIZZLE_XYZW;
this->negate = 0;
this->abs = 0;
this->reladdr = NULL;
this->reladdr2 = NULL;
this->has_index2 = false;
this->double_reg2 = false;
this->array_id = 0;
this->is_double_vertex_input = false;
}
st_src_reg::st_src_reg(gl_register_file file, int index, enum glsl_base_type type, int index2D)
{
assert(file != PROGRAM_ARRAY); /* need array_id > 0 */
this->type = type;
this->file = file;
this->index = index;
this->index2D = index2D;
this->swizzle = SWIZZLE_XYZW;
this->negate = 0;
this->abs = 0;
this->reladdr = NULL;
this->reladdr2 = NULL;
this->has_index2 = false;
this->double_reg2 = false;
this->array_id = 0;
this->is_double_vertex_input = false;
}
void st_src_reg::reset()
{
this->type = GLSL_TYPE_ERROR;
this->file = PROGRAM_UNDEFINED;
this->index = 0;
this->index2D = 0;
this->swizzle = 0;
this->negate = 0;
this->abs = 0;
this->reladdr = NULL;
this->reladdr2 = NULL;
this->has_index2 = false;
this->double_reg2 = false;
this->array_id = 0;
this->is_double_vertex_input = false;
}
st_src_reg::st_src_reg()
{
reset();
}
st_src_reg::st_src_reg(const st_src_reg &reg)
{
*this = reg;
}
void st_src_reg::operator=(const st_src_reg &reg)
{
this->type = reg.type;
this->file = reg.file;
this->index = reg.index;
this->index2D = reg.index2D;
this->swizzle = reg.swizzle;
this->negate = reg.negate;
this->abs = reg.abs;
this->reladdr = dup_reladdr(reg.reladdr);
this->reladdr2 = dup_reladdr(reg.reladdr2);
this->has_index2 = reg.has_index2;
this->double_reg2 = reg.double_reg2;
this->array_id = reg.array_id;
this->is_double_vertex_input = reg.is_double_vertex_input;
}
st_src_reg::st_src_reg(st_dst_reg reg)
{
this->type = reg.type;
this->file = reg.file;
this->index = reg.index;
this->swizzle = SWIZZLE_XYZW;
this->negate = 0;
this->abs = 0;
this->reladdr = dup_reladdr(reg.reladdr);
this->index2D = reg.index2D;
this->reladdr2 = dup_reladdr(reg.reladdr2);
this->has_index2 = reg.has_index2;
this->double_reg2 = false;
this->array_id = reg.array_id;
this->is_double_vertex_input = false;
}
st_src_reg st_src_reg::get_abs()
{
st_src_reg reg = *this;
reg.negate = 0;
reg.abs = 1;
return reg;
}
bool operator == (const st_src_reg& lhs, const st_src_reg& rhs)
{
bool result;
if (lhs.type != rhs.type ||
lhs.file != rhs.file ||
lhs.index != rhs.index ||
lhs.swizzle != rhs.swizzle ||
lhs.index2D != rhs.index2D ||
lhs.has_index2 != rhs.has_index2 ||
lhs.array_id != rhs.array_id ||
lhs.negate != rhs.negate ||
lhs.abs != rhs.abs ||
lhs.double_reg2 != rhs.double_reg2 ||
lhs.is_double_vertex_input != rhs.is_double_vertex_input)
return false;
if (lhs.reladdr) {
if (!rhs.reladdr)
return false;
result = (*lhs.reladdr == *rhs.reladdr);
} else {
result = !rhs.reladdr;
}
if (lhs.reladdr2) {
if (!rhs.reladdr2)
return false;
result &= (*lhs.reladdr2 == *rhs.reladdr2);
} else {
result &= !rhs.reladdr2;
}
return result;
}
static const char swz_txt[] = "xyzw";
std::ostream& operator << (std::ostream& os, const st_src_reg& reg)
{
if (reg.negate)
os << "-";
if (reg.abs)
os << "|";
os << _mesa_register_file_name(reg.file);
if (reg.file == PROGRAM_ARRAY) {
os << "(" << reg.array_id << ")";
}
if (reg.has_index2) {
os << "[";
if (reg.reladdr2) {
os << *reg.reladdr2;
}
os << "+" << reg.index2D << "]";
}
os << "[";
if (reg.reladdr) {
os << *reg.reladdr;
}
os << reg.index << "].";
for (int i = 0; i < 4; ++i) {
int swz = GET_SWZ(reg.swizzle, i);
if (swz < 4)
os << swz_txt[swz];
else
os << "_";
}
if (reg.abs)
os << "|";
return os;
}
st_dst_reg::st_dst_reg(st_src_reg reg)
{
this->type = reg.type;
this->file = reg.file;
this->index = reg.index;
this->writemask = WRITEMASK_XYZW;
this->reladdr = dup_reladdr(reg.reladdr);
this->index2D = reg.index2D;
this->reladdr2 = dup_reladdr(reg.reladdr2);
this->has_index2 = reg.has_index2;
this->array_id = reg.array_id;
}
st_dst_reg::st_dst_reg(gl_register_file file, int writemask, enum glsl_base_type type, int index)
{
assert(file != PROGRAM_ARRAY); /* need array_id > 0 */
this->file = file;
this->index = index;
this->index2D = 0;
this->writemask = writemask;
this->reladdr = NULL;
this->reladdr2 = NULL;
this->has_index2 = false;
this->type = type;
this->array_id = 0;
}
st_dst_reg::st_dst_reg(gl_register_file file, int writemask, enum glsl_base_type type)
{
assert(file != PROGRAM_ARRAY); /* need array_id > 0 */
this->file = file;
this->index = 0;
this->index2D = 0;
this->writemask = writemask;
this->reladdr = NULL;
this->reladdr2 = NULL;
this->has_index2 = false;
this->type = type;
this->array_id = 0;
}
st_dst_reg::st_dst_reg()
{
this->type = GLSL_TYPE_ERROR;
this->file = PROGRAM_UNDEFINED;
this->index = 0;
this->index2D = 0;
this->writemask = 0;
this->reladdr = NULL;
this->reladdr2 = NULL;
this->has_index2 = false;
this->array_id = 0;
}
st_dst_reg::st_dst_reg(const st_dst_reg &reg)
{
*this = reg;
}
void st_dst_reg::operator=(const st_dst_reg &reg)
{
this->type = reg.type;
this->file = reg.file;
this->index = reg.index;
this->writemask = reg.writemask;
this->reladdr = dup_reladdr(reg.reladdr);
this->index2D = reg.index2D;
this->reladdr2 = dup_reladdr(reg.reladdr2);
this->has_index2 = reg.has_index2;
this->array_id = reg.array_id;
}
bool operator == (const st_dst_reg& lhs, const st_dst_reg& rhs)
{
bool result;
if (lhs.type != rhs.type ||
lhs.file != rhs.file ||
lhs.index != rhs.index ||
lhs.writemask != rhs.writemask ||
lhs.index2D != rhs.index2D ||
lhs.has_index2 != rhs.has_index2 ||
lhs.array_id != rhs.array_id)
return false;
if (lhs.reladdr) {
if (!rhs.reladdr)
return false;
result = (*lhs.reladdr == *rhs.reladdr);
} else {
result = !rhs.reladdr;
}
if (lhs.reladdr2) {
if (!rhs.reladdr2)
return false;
result &= (*lhs.reladdr2 == *rhs.reladdr2);
} else {
result &= !rhs.reladdr2;
}
return result;
}
std::ostream& operator << (std::ostream& os, const st_dst_reg& reg)
{
os << _mesa_register_file_name(reg.file);
if (reg.file == PROGRAM_ARRAY) {
os << "(" << reg.array_id << ")";
}
if (reg.has_index2) {
os << "[";
if (reg.reladdr2) {
os << *reg.reladdr2;
}
os << "+" << reg.index2D << "]";
}
os << "[";
if (reg.reladdr) {
os << *reg.reladdr;
}
os << reg.index << "].";
for (int i = 0; i < 4; ++i) {
if (1 << i & reg.writemask)
os << swz_txt[i];
else
os << "_";
}
return os;
}
void glsl_to_tgsi_instruction::print(std::ostream& os) const
{
os << tgsi_get_opcode_name(info->opcode) << " ";
bool has_operators = false;
for (unsigned j = 0; j < num_inst_dst_regs(this); j++) {
has_operators = true;
if (j > 0)
os << ", ";
os << dst[j];
}
if (has_operators)
os << " := ";
for (unsigned j = 0; j < num_inst_src_regs(this); j++) {
if (j > 0)
os << ", ";
os << src[j];
}
if (tex_offset_num_offset > 0) {
os << ", TEXOFS: ";
for (unsigned j = 0; j < tex_offset_num_offset; j++) {
if (j > 0)
os << ", ";
os << tex_offsets[j];
}
}
}

View file

@ -1,207 +0,0 @@
/*
* Copyright © 2010 Intel Corporation
* Copyright © 2011 Bryan Cain
* 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 ST_GLSL_TO_TGSI_PRIVATE_H
#define ST_GLSL_TO_TGSI_PRIVATE_H
#include "mesa/main/mtypes.h"
#include "program/prog_parameter.h"
#include "compiler/glsl_types.h"
#include "compiler/glsl/ir.h"
#include "tgsi/tgsi_info.h"
#include <ostream>
int swizzle_for_size(int size);
class st_dst_reg;
/**
* This struct is a corresponding struct to TGSI ureg_src.
*/
class st_src_reg {
public:
st_src_reg(gl_register_file file, int index, const glsl_type *type,
int component = 0, unsigned array_id = 0);
st_src_reg(gl_register_file file, int index, enum glsl_base_type type);
st_src_reg(gl_register_file file, int index, enum glsl_base_type type, int index2D);
st_src_reg();
st_src_reg(const st_src_reg &reg);
void operator=(const st_src_reg &reg);
void reset();
explicit st_src_reg(st_dst_reg reg);
st_src_reg get_abs();
int32_t index; /**< temporary index, VERT_ATTRIB_*, VARYING_SLOT_*, etc. */
int16_t index2D;
uint16_t swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
int negate:4; /**< NEGATE_XYZW mask from mesa */
unsigned abs:1;
enum glsl_base_type type:6; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */
unsigned has_index2:1;
gl_register_file file:6; /**< PROGRAM_* from Mesa */
/*
* Is this the second half of a double register pair?
* currently used for input mapping only.
*/
unsigned double_reg2:1;
unsigned is_double_vertex_input:1;
unsigned array_id:10;
/** Register index should be offset by the integer in this reg. */
st_src_reg *reladdr;
st_src_reg *reladdr2;
bool is_legal_tgsi_address_operand() const
{
/* 2D registers can't be used as an address operand, or if the address
* operand itself is a result of indirect addressing.
*/
return (type == GLSL_TYPE_INT || type == GLSL_TYPE_UINT) &&
!has_index2 && !reladdr && !reladdr2;
}
};
bool operator == (const st_src_reg& lhs, const st_src_reg& rhs);
std::ostream& operator << (std::ostream& os, const st_src_reg& reg);
class st_dst_reg {
public:
st_dst_reg(gl_register_file file, int writemask, enum glsl_base_type type, int index);
st_dst_reg(gl_register_file file, int writemask, enum glsl_base_type type);
st_dst_reg();
st_dst_reg(const st_dst_reg &reg);
void operator=(const st_dst_reg &reg);
explicit st_dst_reg(st_src_reg reg);
int32_t index; /**< temporary index, VERT_ATTRIB_*, VARYING_SLOT_*, etc. */
int16_t index2D;
gl_register_file file:6; /**< PROGRAM_* from Mesa */
unsigned writemask:4; /**< Bitfield of WRITEMASK_[XYZW] */
enum glsl_base_type type:6; /** GLSL_TYPE_* from GLSL IR (enum glsl_base_type) */
unsigned has_index2:1;
unsigned array_id:10;
/** Register index should be offset by the integer in this reg. */
st_src_reg *reladdr;
st_src_reg *reladdr2;
};
bool operator == (const st_dst_reg& lhs, const st_dst_reg& rhs);
std::ostream& operator << (std::ostream& os, const st_dst_reg& reg);
class glsl_to_tgsi_instruction : public exec_node {
public:
DECLARE_RALLOC_CXX_OPERATORS(glsl_to_tgsi_instruction)
st_dst_reg dst[2];
st_src_reg src[4];
st_src_reg resource; /**< sampler or buffer register */
st_src_reg *tex_offsets;
/** Pointer to the ir source this tree came fe02549fdrom for debugging */
ir_instruction *ir;
enum tgsi_opcode op:10; /**< TGSI opcode */
unsigned precise:1;
unsigned saturate:1;
unsigned is_64bit_expanded:1;
unsigned sampler_base:5;
unsigned sampler_array_size:6; /**< 1-based size of sampler array, 1 if not array */
gl_texture_index tex_target:5;
glsl_base_type tex_type:6;
unsigned tex_shadow:1;
enum pipe_format image_format:10;
unsigned tex_offset_num_offset:3;
unsigned dead_mask:4; /**< Used in dead code elimination */
unsigned buffer_access:3; /**< bitmask of TGSI_MEMORY_x bits */
unsigned read_only:1;
unsigned gather_component:2; /* 0, 1, 2, 3 */
const struct tgsi_opcode_info *info;
void print(std::ostream& os) const;
};
inline std::ostream&
operator << (std::ostream& os, const glsl_to_tgsi_instruction& instr)
{
instr.print(os);
return os;
}
struct rename_reg_pair {
bool valid;
int new_reg;
};
inline static bool
is_resource_instruction(unsigned opcode)
{
switch (opcode) {
case TGSI_OPCODE_RESQ:
case TGSI_OPCODE_LOAD:
case TGSI_OPCODE_ATOMUADD:
case TGSI_OPCODE_ATOMXCHG:
case TGSI_OPCODE_ATOMCAS:
case TGSI_OPCODE_ATOMAND:
case TGSI_OPCODE_ATOMOR:
case TGSI_OPCODE_ATOMXOR:
case TGSI_OPCODE_ATOMUMIN:
case TGSI_OPCODE_ATOMUMAX:
case TGSI_OPCODE_ATOMIMIN:
case TGSI_OPCODE_ATOMIMAX:
case TGSI_OPCODE_ATOMFADD:
case TGSI_OPCODE_ATOMINC_WRAP:
case TGSI_OPCODE_ATOMDEC_WRAP:
case TGSI_OPCODE_IMG2HND:
return true;
default:
return false;
}
}
inline static unsigned
num_inst_dst_regs(const glsl_to_tgsi_instruction *op)
{
return op->info->num_dst;
}
inline static unsigned
num_inst_src_regs(const glsl_to_tgsi_instruction *op)
{
return op->info->is_tex || is_resource_instruction(op->op) ?
op->info->num_src - 1 : op->info->num_src;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,80 +0,0 @@
/*
* 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_TEMPRENAME_H
#define MESA_GLSL_TO_TGSI_TEMPRENAME_H
#include "st_glsl_to_tgsi_array_merge.h"
/** Storage to record the required live range of a temporary register
* begin == end == -1 indicates that the register can be reused without
* limitations. Otherwise, "begin" indicates the first instruction in which
* a write operation may target this temporary, and end indicates the
* last instruction in which a value can be read from this temporary.
* Hence, a register R2 can be merged with a register R1 if R1.end <= R2.begin.
*/
struct register_live_range {
int begin;
int end;
};
/** Evaluates the required live ranges of temporary registers in a shader.
* The live range estimation can only be run sucessfully if the shader doesn't
* call a subroutine.
* @param[in] mem_ctx a memory context that can be used with the ralloc_*
* functions
* @param[in] instructions the shader to be anlzyed
* @param[in] ntemps number of temporaries reserved for this shader
* @param[in,out] reg_live_ranges memory location to store the estimated
* required live ranges for each temporary register. The parameter must
* point to allocated memory that can hold ntemps register_live_range
* structures. On output the live ranges contains the live ranges for
* the registers with the exception of TEMP[0]
* @param[in] narrays number of array sreserved for this shader
* @param[in,out] arr_live_ranges memory location to store the estimated required
* live ranges for each array. The parameter must point to allocated memory
* that can hold narrays array_live_range structures. On output the live
* ranges contains the live ranges for the registers with the exception of
* ARRAY[0].
* @returns: true if the lifetimes were estimated, false if not (i.e. if a
* subroutine was called).
*/
bool
get_temp_registers_required_live_ranges(void *mem_ctx, exec_list *instructions,
int ntemps, struct register_live_range *register_live_ranges,
int narrays, array_live_range *array_live_ranges);
/** Estimate the merge remapping of the registers.
* @param[in] mem_ctx a memory context that can be used with the ralloc_*
* functions
* @param[in] ntemps number of temporaries reserved for this shader
* @param[in] reg_live_ranges required live range for each temporary register.
* @param[in,out] result memory location to store the register remapping table.
* On input the parameter must point to allocated memory that can hold the
* renaming information for ntemps registers, on output the mapping is stored.
* Note that TEMP[0] is not considered for register renaming.
*/
void get_temp_registers_remapping(void *mem_ctx, int ntemps,
const struct register_live_range* reg_live_ranges,
struct rename_reg_pair *result);
#endif

View file

@ -588,115 +588,37 @@ static bool
st_translate_vertex_program(struct st_context *st, st_translate_vertex_program(struct st_context *st,
struct gl_program *prog) struct gl_program *prog)
{ {
struct ureg_program *ureg;
enum pipe_error error;
unsigned num_outputs = 0;
unsigned attr;
ubyte output_semantic_name[VARYING_SLOT_MAX] = {0};
ubyte output_semantic_index[VARYING_SLOT_MAX] = {0};
/* ARB_vp: */ /* ARB_vp: */
if (!prog->glsl_to_tgsi) { if (prog->arb.IsPositionInvariant)
if (prog->arb.IsPositionInvariant) _mesa_insert_mvp_code(st->ctx, prog);
_mesa_insert_mvp_code(st->ctx, prog);
_mesa_remove_output_reads(prog, PROGRAM_OUTPUT); _mesa_remove_output_reads(prog, PROGRAM_OUTPUT);
/* This determines which states will be updated when the assembly /* This determines which states will be updated when the assembly
* shader is bound. * shader is bound.
*/ */
prog->affected_states = ST_NEW_VS_STATE | prog->affected_states = ST_NEW_VS_STATE |
ST_NEW_RASTERIZER | ST_NEW_RASTERIZER |
ST_NEW_VERTEX_ARRAYS; ST_NEW_VERTEX_ARRAYS;
if (prog->Parameters->NumParameters) if (prog->Parameters->NumParameters)
prog->affected_states |= ST_NEW_VS_CONSTANTS; prog->affected_states |= ST_NEW_VS_CONSTANTS;
if (prog->nir) if (prog->nir)
ralloc_free(prog->nir); ralloc_free(prog->nir);
if (prog->serialized_nir) { if (prog->serialized_nir) {
free(prog->serialized_nir); free(prog->serialized_nir);
prog->serialized_nir = NULL; prog->serialized_nir = NULL;
}
prog->state.type = PIPE_SHADER_IR_NIR;
prog->nir = st_translate_prog_to_nir(st, prog,
MESA_SHADER_VERTEX);
prog->info = prog->nir->info;
st_prepare_vertex_program(prog, NULL);
return true;
} }
uint8_t input_to_index[VERT_ATTRIB_MAX]; prog->state.type = PIPE_SHADER_IR_NIR;
st_prepare_vertex_program(prog, input_to_index); prog->nir = st_translate_prog_to_nir(st, prog,
MESA_SHADER_VERTEX);
prog->info = prog->nir->info;
/* Get semantic names and indices. */ st_prepare_vertex_program(prog, NULL);
for (attr = 0; attr < VARYING_SLOT_MAX; attr++) { return true;
if (prog->info.outputs_written & BITFIELD64_BIT(attr)) {
unsigned slot = num_outputs++;
unsigned semantic_name, semantic_index;
tgsi_get_gl_varying_semantic(attr, st->needs_texcoord_semantic,
&semantic_name, &semantic_index);
output_semantic_name[slot] = semantic_name;
output_semantic_index[slot] = semantic_index;
}
}
/* pre-setup potentially unused edgeflag output */
output_semantic_name[num_outputs] = TGSI_SEMANTIC_EDGEFLAG;
output_semantic_index[num_outputs] = 0;
ureg = ureg_create_with_screen(PIPE_SHADER_VERTEX, st->screen);
if (ureg == NULL)
return false;
ureg_setup_shader_info(ureg, &prog->info);
if (ST_DEBUG & DEBUG_MESA) {
_mesa_print_program(prog);
_mesa_print_program_parameters(st->ctx, prog);
debug_printf("\n");
}
struct gl_vertex_program *vp = (struct gl_vertex_program *)prog;
error = st_translate_program(st->ctx,
PIPE_SHADER_VERTEX,
ureg,
prog->glsl_to_tgsi,
prog,
/* inputs */
vp->num_inputs,
input_to_index,
NULL, /* inputSlotToAttr */
NULL, /* input semantic name */
NULL, /* input semantic index */
NULL, /* interp mode */
/* outputs */
num_outputs,
vp->result_to_output,
output_semantic_name,
output_semantic_index);
st_translate_stream_output_info(prog);
free_glsl_to_tgsi_visitor(prog->glsl_to_tgsi);
if (error) {
debug_printf("%s: failed to translate GLSL IR program:\n", __func__);
_mesa_print_program(prog);
debug_assert(0);
return false;
}
prog->state.tokens = ureg_get_tokens(ureg, NULL);
ureg_destroy(ureg);
prog->glsl_to_tgsi = NULL;
st_store_ir_in_disk_cache(st, prog, false);
return prog->state.tokens != NULL;
} }
static struct nir_shader * static struct nir_shader *
@ -981,330 +903,53 @@ st_get_common_variant(struct st_context *st,
/** /**
* Translate a Mesa fragment shader into a TGSI shader. * Translate a non-GLSL Mesa fragment shader into a NIR shader.
*/ */
static bool static bool
st_translate_fragment_program(struct st_context *st, st_translate_fragment_program(struct st_context *st,
struct gl_program *fp) struct gl_program *fp)
{ {
/* Non-GLSL programs: */ /* Non-GLSL programs: */
if (!fp->glsl_to_tgsi) { _mesa_remove_output_reads(fp, PROGRAM_OUTPUT);
_mesa_remove_output_reads(fp, PROGRAM_OUTPUT); if (st->ctx->Const.GLSLFragCoordIsSysVal)
if (st->ctx->Const.GLSLFragCoordIsSysVal) _mesa_program_fragment_position_to_sysval(fp);
_mesa_program_fragment_position_to_sysval(fp);
/* This determines which states will be updated when the assembly /* This determines which states will be updated when the assembly
* shader is bound. * shader is bound.
* *
* fragment.position and glDrawPixels always use constants. * fragment.position and glDrawPixels always use constants.
*/ */
fp->affected_states = ST_NEW_FS_STATE | fp->affected_states = ST_NEW_FS_STATE |
ST_NEW_SAMPLE_SHADING | ST_NEW_SAMPLE_SHADING |
ST_NEW_FS_CONSTANTS; ST_NEW_FS_CONSTANTS;
if (fp->ati_fs) { if (fp->ati_fs) {
/* Just set them for ATI_fs unconditionally. */ /* Just set them for ATI_fs unconditionally. */
fp->affected_states |= ST_NEW_FS_SAMPLER_VIEWS |
ST_NEW_FS_SAMPLERS;
} else {
/* ARB_fp */
if (fp->SamplersUsed)
fp->affected_states |= ST_NEW_FS_SAMPLER_VIEWS | fp->affected_states |= ST_NEW_FS_SAMPLER_VIEWS |
ST_NEW_FS_SAMPLERS; ST_NEW_FS_SAMPLERS;
} else { }
/* ARB_fp */
if (fp->SamplersUsed) /* Translate to NIR. ATI_fs translates at variant time. */
fp->affected_states |= ST_NEW_FS_SAMPLER_VIEWS | if (!fp->ati_fs) {
ST_NEW_FS_SAMPLERS; nir_shader *nir =
st_translate_prog_to_nir(st, fp, MESA_SHADER_FRAGMENT);
if (fp->nir)
ralloc_free(fp->nir);
if (fp->serialized_nir) {
free(fp->serialized_nir);
fp->serialized_nir = NULL;
} }
fp->state.type = PIPE_SHADER_IR_NIR;
/* Translate to NIR. ATI_fs translates at variant time. */ fp->nir = nir;
if (!fp->ati_fs) {
nir_shader *nir =
st_translate_prog_to_nir(st, fp, MESA_SHADER_FRAGMENT);
if (fp->nir)
ralloc_free(fp->nir);
if (fp->serialized_nir) {
free(fp->serialized_nir);
fp->serialized_nir = NULL;
}
fp->state.type = PIPE_SHADER_IR_NIR;
fp->nir = nir;
}
return true;
} }
ubyte outputMapping[2 * FRAG_RESULT_MAX]; return true;
ubyte inputMapping[VARYING_SLOT_MAX];
ubyte inputSlotToAttr[VARYING_SLOT_MAX];
ubyte interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */
GLuint attr;
GLbitfield64 inputsRead;
struct ureg_program *ureg;
GLboolean write_all = GL_FALSE;
ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS];
ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
uint fs_num_inputs = 0;
ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
uint fs_num_outputs = 0;
memset(inputSlotToAttr, ~0, sizeof(inputSlotToAttr));
/*
* Convert Mesa program inputs to TGSI input register semantics.
*/
inputsRead = fp->info.inputs_read;
for (attr = 0; attr < VARYING_SLOT_MAX; attr++) {
if ((inputsRead & BITFIELD64_BIT(attr)) != 0) {
const GLuint slot = fs_num_inputs++;
inputMapping[attr] = slot;
inputSlotToAttr[slot] = attr;
switch (attr) {
case VARYING_SLOT_POS:
input_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
break;
case VARYING_SLOT_COL0:
input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
input_semantic_index[slot] = 0;
interpMode[slot] = fp->glsl_to_tgsi ?
TGSI_INTERPOLATE_COUNT : TGSI_INTERPOLATE_COLOR;
break;
case VARYING_SLOT_COL1:
input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
input_semantic_index[slot] = 1;
interpMode[slot] = fp->glsl_to_tgsi ?
TGSI_INTERPOLATE_COUNT : TGSI_INTERPOLATE_COLOR;
break;
case VARYING_SLOT_FOGC:
input_semantic_name[slot] = TGSI_SEMANTIC_FOG;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
break;
case VARYING_SLOT_FACE:
input_semantic_name[slot] = TGSI_SEMANTIC_FACE;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
break;
case VARYING_SLOT_PRIMITIVE_ID:
input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
break;
case VARYING_SLOT_LAYER:
input_semantic_name[slot] = TGSI_SEMANTIC_LAYER;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
break;
case VARYING_SLOT_VIEWPORT:
input_semantic_name[slot] = TGSI_SEMANTIC_VIEWPORT_INDEX;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
break;
case VARYING_SLOT_CLIP_DIST0:
input_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
break;
case VARYING_SLOT_CLIP_DIST1:
input_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST;
input_semantic_index[slot] = 1;
interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
break;
case VARYING_SLOT_CULL_DIST0:
case VARYING_SLOT_CULL_DIST1:
/* these should have been lowered by GLSL */
assert(0);
break;
/* In most cases, there is nothing special about these
* inputs, so adopt a convention to use the generic
* semantic name and the mesa VARYING_SLOT_ number as the
* index.
*
* All that is required is that the vertex shader labels
* its own outputs similarly, and that the vertex shader
* generates at least every output required by the
* fragment shader plus fixed-function hardware (such as
* BFC).
*
* However, some drivers may need us to identify the PNTC and TEXi
* varyings if, for example, their capability to replace them with
* sprite coordinates is limited.
*/
case VARYING_SLOT_PNTC:
if (st->needs_texcoord_semantic) {
input_semantic_name[slot] = TGSI_SEMANTIC_PCOORD;
input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
break;
}
FALLTHROUGH;
case VARYING_SLOT_TEX0:
case VARYING_SLOT_TEX1:
case VARYING_SLOT_TEX2:
case VARYING_SLOT_TEX3:
case VARYING_SLOT_TEX4:
case VARYING_SLOT_TEX5:
case VARYING_SLOT_TEX6:
case VARYING_SLOT_TEX7:
if (st->needs_texcoord_semantic) {
input_semantic_name[slot] = TGSI_SEMANTIC_TEXCOORD;
input_semantic_index[slot] = attr - VARYING_SLOT_TEX0;
interpMode[slot] = fp->glsl_to_tgsi ?
TGSI_INTERPOLATE_COUNT : TGSI_INTERPOLATE_PERSPECTIVE;
break;
}
FALLTHROUGH;
case VARYING_SLOT_VAR0:
default:
/* Semantic indices should be zero-based because drivers may choose
* to assign a fixed slot determined by that index.
* This is useful because ARB_separate_shader_objects uses location
* qualifiers for linkage, and if the semantic index corresponds to
* these locations, linkage passes in the driver become unecessary.
*
* If needs_texcoord_semantic is true, no semantic indices will be
* consumed for the TEXi varyings, and we can base the locations of
* the user varyings on VAR0. Otherwise, we use TEX0 as base index.
*/
assert(attr >= VARYING_SLOT_VAR0 || attr == VARYING_SLOT_PNTC ||
(attr >= VARYING_SLOT_TEX0 && attr <= VARYING_SLOT_TEX7));
input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
input_semantic_index[slot] = st_get_generic_varying_index(st, attr);
if (attr == VARYING_SLOT_PNTC)
interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
else {
interpMode[slot] = fp->glsl_to_tgsi ?
TGSI_INTERPOLATE_COUNT : TGSI_INTERPOLATE_PERSPECTIVE;
}
break;
}
}
else {
inputMapping[attr] = -1;
}
}
/*
* Semantics and mapping for outputs
*/
GLbitfield64 outputsWritten = fp->info.outputs_written;
/* if z is written, emit that first */
if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION;
fs_output_semantic_index[fs_num_outputs] = 0;
outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs;
fs_num_outputs++;
outputsWritten &= ~(1 << FRAG_RESULT_DEPTH);
}
if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) {
fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL;
fs_output_semantic_index[fs_num_outputs] = 0;
outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs;
fs_num_outputs++;
outputsWritten &= ~(1 << FRAG_RESULT_STENCIL);
}
if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_SAMPLE_MASK)) {
fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_SAMPLEMASK;
fs_output_semantic_index[fs_num_outputs] = 0;
outputMapping[FRAG_RESULT_SAMPLE_MASK] = fs_num_outputs;
fs_num_outputs++;
outputsWritten &= ~(1 << FRAG_RESULT_SAMPLE_MASK);
}
/* handle remaining outputs (color) */
for (attr = 0; attr < ARRAY_SIZE(outputMapping); attr++) {
const GLbitfield64 written = attr < FRAG_RESULT_MAX ? outputsWritten :
fp->SecondaryOutputsWritten;
const unsigned loc = attr % FRAG_RESULT_MAX;
if (written & BITFIELD64_BIT(loc)) {
switch (loc) {
case FRAG_RESULT_DEPTH:
case FRAG_RESULT_STENCIL:
case FRAG_RESULT_SAMPLE_MASK:
/* handled above */
assert(0);
break;
case FRAG_RESULT_COLOR:
write_all = GL_TRUE;
FALLTHROUGH;
default: {
int index;
assert(loc == FRAG_RESULT_COLOR ||
(FRAG_RESULT_DATA0 <= loc && loc < FRAG_RESULT_MAX));
index = (loc == FRAG_RESULT_COLOR) ? 0 : (loc - FRAG_RESULT_DATA0);
if (attr >= FRAG_RESULT_MAX) {
/* Secondary color for dual source blending. */
assert(index == 0);
index++;
}
fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR;
fs_output_semantic_index[fs_num_outputs] = index;
outputMapping[attr] = fs_num_outputs;
break;
}
}
fs_num_outputs++;
}
}
ureg = ureg_create_with_screen(PIPE_SHADER_FRAGMENT, st->screen);
if (ureg == NULL)
return false;
ureg_setup_shader_info(ureg, &fp->info);
if (ST_DEBUG & DEBUG_MESA) {
_mesa_print_program(fp);
_mesa_print_program_parameters(st->ctx, fp);
debug_printf("\n");
}
if (write_all == GL_TRUE)
ureg_property(ureg, TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS, 1);
if (fp->glsl_to_tgsi) {
st_translate_program(st->ctx,
PIPE_SHADER_FRAGMENT,
ureg,
fp->glsl_to_tgsi,
fp,
/* inputs */
fs_num_inputs,
inputMapping,
inputSlotToAttr,
input_semantic_name,
input_semantic_index,
interpMode,
/* outputs */
fs_num_outputs,
outputMapping,
fs_output_semantic_name,
fs_output_semantic_index);
free_glsl_to_tgsi_visitor(fp->glsl_to_tgsi);
}
fp->state.tokens = ureg_get_tokens(ureg, NULL);
ureg_destroy(ureg);
if (fp->glsl_to_tgsi) {
fp->glsl_to_tgsi = NULL;
st_store_ir_in_disk_cache(st, fp, false);
}
return fp->state.tokens != NULL;
} }
static struct st_fp_variant * static struct st_fp_variant *
@ -1670,146 +1315,6 @@ st_get_fp_variant(struct st_context *st,
return fpv; return fpv;
} }
/**
* Translate a program. This is common code for geometry and tessellation
* shaders.
*/
static bool
st_translate_common_program(struct st_context *st,
struct gl_program *prog)
{
enum pipe_shader_type stage =
pipe_shader_type_from_mesa(prog->info.stage);
struct ureg_program *ureg = ureg_create_with_screen(stage, st->screen);
if (ureg == NULL)
return false;
ureg_setup_shader_info(ureg, &prog->info);
ubyte inputSlotToAttr[VARYING_SLOT_TESS_MAX];
ubyte inputMapping[VARYING_SLOT_TESS_MAX];
ubyte outputMapping[VARYING_SLOT_TESS_MAX];
GLuint attr;
ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS];
ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
uint num_inputs = 0;
ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
ubyte output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
uint num_outputs = 0;
GLint i;
memset(inputSlotToAttr, 0, sizeof(inputSlotToAttr));
memset(inputMapping, 0, sizeof(inputMapping));
memset(outputMapping, 0, sizeof(outputMapping));
memset(&prog->state, 0, sizeof(prog->state));
/*
* Convert Mesa program inputs to TGSI input register semantics.
*/
for (attr = 0; attr < VARYING_SLOT_MAX; attr++) {
if ((prog->info.inputs_read & BITFIELD64_BIT(attr)) == 0)
continue;
unsigned slot = num_inputs++;
inputMapping[attr] = slot;
inputSlotToAttr[slot] = attr;
unsigned semantic_name, semantic_index;
tgsi_get_gl_varying_semantic(attr, st->needs_texcoord_semantic,
&semantic_name, &semantic_index);
input_semantic_name[slot] = semantic_name;
input_semantic_index[slot] = semantic_index;
}
/* Also add patch inputs. */
for (attr = 0; attr < 32; attr++) {
if (prog->info.patch_inputs_read & (1u << attr)) {
GLuint slot = num_inputs++;
GLuint patch_attr = VARYING_SLOT_PATCH0 + attr;
inputMapping[patch_attr] = slot;
inputSlotToAttr[slot] = patch_attr;
input_semantic_name[slot] = TGSI_SEMANTIC_PATCH;
input_semantic_index[slot] = attr;
}
}
/* initialize output semantics to defaults */
for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) {
output_semantic_name[i] = TGSI_SEMANTIC_GENERIC;
output_semantic_index[i] = 0;
}
/*
* Determine number of outputs, the (default) output register
* mapping and the semantic information for each output.
*/
for (attr = 0; attr < VARYING_SLOT_MAX; attr++) {
if (prog->info.outputs_written & BITFIELD64_BIT(attr)) {
GLuint slot = num_outputs++;
outputMapping[attr] = slot;
unsigned semantic_name, semantic_index;
tgsi_get_gl_varying_semantic(attr, st->needs_texcoord_semantic,
&semantic_name, &semantic_index);
output_semantic_name[slot] = semantic_name;
output_semantic_index[slot] = semantic_index;
}
}
/* Also add patch outputs. */
for (attr = 0; attr < 32; attr++) {
if (prog->info.patch_outputs_written & (1u << attr)) {
GLuint slot = num_outputs++;
GLuint patch_attr = VARYING_SLOT_PATCH0 + attr;
outputMapping[patch_attr] = slot;
output_semantic_name[slot] = TGSI_SEMANTIC_PATCH;
output_semantic_index[slot] = attr;
}
}
st_translate_program(st->ctx,
stage,
ureg,
prog->glsl_to_tgsi,
prog,
/* inputs */
num_inputs,
inputMapping,
inputSlotToAttr,
input_semantic_name,
input_semantic_index,
NULL,
/* outputs */
num_outputs,
outputMapping,
output_semantic_name,
output_semantic_index);
prog->state.tokens = ureg_get_tokens(ureg, NULL);
ureg_destroy(ureg);
st_translate_stream_output_info(prog);
st_store_ir_in_disk_cache(st, prog, false);
if (ST_DEBUG & DEBUG_PRINT_IR && ST_DEBUG & DEBUG_MESA)
_mesa_print_program(prog);
free_glsl_to_tgsi_visitor(prog->glsl_to_tgsi);
prog->glsl_to_tgsi = NULL;
return true;
}
/** /**
* Vert/Geom/Frag programs have per-context variants. Free all the * Vert/Geom/Frag programs have per-context variants. Free all the
* variants attached to the given program which match the given context. * variants attached to the given program which match the given context.
@ -2067,9 +1572,6 @@ st_program_string_notify( struct gl_context *ctx,
prog->skip_pointsize_xfb = true; prog->skip_pointsize_xfb = true;
NIR_PASS_V(prog->nir, st_nir_add_point_size); NIR_PASS_V(prog->nir, st_nir_add_point_size);
} }
} else {
if (!st_translate_common_program(st, prog))
return false;
} }
st_finalize_program(st, prog); st_finalize_program(st, prog);

View file

@ -40,7 +40,6 @@
#include "tgsi/tgsi_from_mesa.h" #include "tgsi/tgsi_from_mesa.h"
#include "st_context.h" #include "st_context.h"
#include "st_texture.h" #include "st_texture.h"
#include "st_glsl_to_tgsi.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View file

@ -20,7 +20,6 @@
libmesa_st_test_common = static_library( libmesa_st_test_common = static_library(
'mesa_st_test_common', 'mesa_st_test_common',
['st_tests_common.cpp', ir_expression_operation_h],
include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux], include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux],
dependencies : [idep_gtest, idep_mesautil], dependencies : [idep_gtest, idep_mesautil],
) )
@ -38,33 +37,3 @@ test(
), ),
suite : ['st_mesa'], suite : ['st_mesa'],
) )
test(
'st_renumerate_test',
executable(
'st_renumerate_test',
['test_glsl_to_tgsi_lifetime.cpp', ir_expression_operation_h],
include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux],
link_with : [
libmesa_st_test_common, libmesa, libglapi, libgallium,
],
dependencies : [idep_mesautil, idep_gtest],
),
suite : ['st_mesa'],
protocol : gtest_test_protocol,
)
test(
'st-array-merge-test',
executable(
'st_array_merge_test',
['test_glsl_to_tgsi_array_merge.cpp', ir_expression_operation_h],
include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux],
link_with : [
libmesa_st_test_common, libmesa, libglapi, libgallium,
],
dependencies : [idep_mesautil, idep_gtest],
),
suite : ['st_mesa'],
protocol : gtest_test_protocol,
)

View file

@ -1,619 +0,0 @@
/*
* 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.
*/
#include "st_tests_common.h"
#include "mesa/program/prog_instruction.h"
#include "tgsi/tgsi_info.h"
#include "tgsi/tgsi_ureg.h"
#include "compiler/glsl/list.h"
#include "gtest/gtest.h"
#include <utility>
#include <algorithm>
using std::vector;
using std::pair;
using std::make_pair;
using std::transform;
using std::copy;
using std::tuple;
/* Implementation of helper and test classes */
void *FakeCodeline::mem_ctx = nullptr;
FakeCodeline::FakeCodeline(tgsi_opcode _op, const vector<int>& _dst,
const vector<int>& _src, const vector<int>&_to):
op(_op),
max_temp_id(0),
max_array_id(0)
{
transform(_dst.begin(), _dst.end(), std::back_inserter(dst),
[this](int i) { return create_dst_register(i);});
transform(_src.begin(), _src.end(), std::back_inserter(src),
[this](int i) { return create_src_register(i);});
transform(_to.begin(), _to.end(), std::back_inserter(tex_offsets),
[this](int i) { return create_src_register(i);});
}
FakeCodeline::FakeCodeline(tgsi_opcode _op, const vector<pair<int,int>>& _dst,
const vector<pair<int, const char *>>& _src,
const vector<pair<int, const char *>>&_to,
SWZ with_swizzle):
op(_op),
max_temp_id(0),
max_array_id(0)
{
(void)with_swizzle;
transform(_dst.begin(), _dst.end(), std::back_inserter(dst),
[this](pair<int,int> r) {
return create_dst_register(r.first, r.second);
});
transform(_src.begin(), _src.end(), std::back_inserter(src),
[this](const pair<int,const char *>& r) {
return create_src_register(r.first, r.second);
});
transform(_to.begin(), _to.end(), std::back_inserter(tex_offsets),
[this](const pair<int,const char *>& r) {
return create_src_register(r.first, r.second);
});
}
FakeCodeline::FakeCodeline(tgsi_opcode _op, const vector<tuple<int,int,int>>& _dst,
const vector<tuple<int,int,int>>& _src,
const vector<tuple<int,int,int>>&_to, RA with_reladdr):
op(_op),
max_temp_id(0),
max_array_id(0)
{
(void)with_reladdr;
transform(_dst.begin(), _dst.end(), std::back_inserter(dst),
[this](const tuple<int,int,int>& r) {
return create_dst_register(r);
});
transform(_src.begin(), _src.end(), std::back_inserter(src),
[this](const tuple<int,int,int>& r) {
return create_src_register(r);
});
transform(_to.begin(), _to.end(), std::back_inserter(tex_offsets),
[this](const tuple<int,int,int>& r) {
return create_src_register(r);
});
}
FakeCodeline::FakeCodeline(tgsi_opcode _op, const vector<tuple<int,int,int>>& _dst,
const vector<tuple<int,int, const char*>>& _src,
const vector<tuple<int,int, const char*>>&_to,
ARR with_array):
FakeCodeline(_op)
{
(void)with_array;
transform(_dst.begin(), _dst.end(), std::back_inserter(dst),
[this](const tuple<int,int,int>& r) {
return create_array_dst_register(r);
});
transform(_src.begin(), _src.end(), std::back_inserter(src),
[this](const tuple<int,int,const char*>& r) {
return create_array_src_register(r);
});
transform(_to.begin(), _to.end(), std::back_inserter(tex_offsets),
[this](const tuple<int,int,const char*>& r) {
return create_array_src_register(r);
});
}
FakeCodeline::FakeCodeline(const glsl_to_tgsi_instruction& instr):
op(instr.op),
max_temp_id(0),
max_array_id(0)
{
int nsrc = num_inst_src_regs(&instr);
int ndst = num_inst_dst_regs(&instr);
copy(instr.src, instr.src + nsrc, std::back_inserter(src));
copy(instr.dst, instr.dst + ndst, std::back_inserter(dst));
for (auto& s: src)
read_reg(s);
for (auto& d: dst)
read_reg(d);
}
template <typename st_reg>
void FakeCodeline::read_reg(const st_reg& s)
{
if (s.file == PROGRAM_ARRAY) {
if (s.array_id > max_array_id)
max_array_id = s.array_id;
if (s.reladdr)
read_reg(*s.reladdr);
if (s.reladdr2)
read_reg(*s.reladdr2);
} else if (s.file == PROGRAM_TEMPORARY) {
if (s.index > max_temp_id)
max_temp_id = s.index;
}
}
void FakeCodeline::print(std::ostream& os) const
{
const struct tgsi_opcode_info *info = tgsi_get_opcode_info(op);
os << tgsi_get_opcode_name(info->opcode) << " ";
for (auto d: dst) {
os << d << " ";
}
os << " <- ";
for (auto s: src) {
os << s << " ";
}
os << "\n";
}
bool operator == (const FakeCodeline& lhs, const FakeCodeline& rhs)
{
if ((lhs.op != rhs.op) ||
(lhs.src.size() != rhs.src.size()) ||
(lhs.dst.size() != rhs.dst.size()))
return false;
return std::equal(lhs.src.begin(), lhs.src.end(), rhs.src.begin()) &&
std::equal(lhs.dst.begin(), lhs.dst.end(), rhs.dst.begin());
}
st_src_reg FakeCodeline::create_src_register(int src_idx)
{
return create_src_register(src_idx,
src_idx < 0 ? PROGRAM_INPUT : PROGRAM_TEMPORARY);
}
static int swizzle_from_char(const char *sw)
{
int swizzle = 0;
if (!sw || sw[0] == 0)
return SWIZZLE_XYZW;
const char *isw = sw;
for (int i = 0; i < 4; ++i) {
switch (*isw) {
case 'x': break; /* is zero */
case 'y': swizzle |= SWIZZLE_Y << 3 * i; break;
case 'z': swizzle |= SWIZZLE_Z << 3 * i; break;
case 'w': swizzle |= SWIZZLE_W << 3 * i; break;
default:
assert(!"This test uses an unknown swizzle character");
}
if (isw[1] != 0)
++isw;
}
return swizzle;
}
st_src_reg FakeCodeline::create_src_register(int src_idx, const char *sw)
{
st_src_reg result = create_src_register(src_idx);
result.swizzle = swizzle_from_char(sw);
return result;
}
st_src_reg FakeCodeline::create_src_register(int src_idx, gl_register_file file)
{
st_src_reg retval;
retval.file = file;
retval.index = src_idx >= 0 ? src_idx : 1 - src_idx;
if (file == PROGRAM_TEMPORARY) {
if (max_temp_id < src_idx)
max_temp_id = src_idx;
} else if (file == PROGRAM_ARRAY) {
retval.array_id = 1;
if (max_array_id < 1)
max_array_id = 1;
}
retval.swizzle = SWIZZLE_XYZW;
retval.type = GLSL_TYPE_INT;
return retval;
}
st_src_reg *FakeCodeline::create_rel_src_register(int idx)
{
st_src_reg *retval = ralloc(mem_ctx, st_src_reg);
*retval = st_src_reg(PROGRAM_TEMPORARY, idx, GLSL_TYPE_INT);
if (max_temp_id < idx)
max_temp_id = idx;
return retval;
}
st_src_reg FakeCodeline::create_array_src_register(const tuple<int,int, const char*>& r)
{
int array_id = std::get<0>(r);
int idx = std::get<1>(r);
st_src_reg retval = create_src_register(idx, std::get<2>(r));
if (array_id > 0) {
retval.file = PROGRAM_ARRAY;
retval.array_id = array_id;
if (max_array_id < array_id)
max_array_id = array_id;
} else {
if (max_temp_id < idx)
max_temp_id = idx;
}
return retval;
}
st_dst_reg FakeCodeline::create_array_dst_register(const tuple<int,int,int>& r)
{
int array_id = std::get<0>(r);
int idx = std::get<1>(r);
st_dst_reg retval = create_dst_register(idx, std::get<2>(r));
if (array_id > 0) {
retval.file = PROGRAM_ARRAY;
retval.array_id = array_id;
if (max_array_id < array_id)
max_array_id = array_id;
} else {
if (max_temp_id < idx)
max_temp_id = idx;
}
return retval;
}
st_src_reg FakeCodeline::create_src_register(const tuple<int,int,int>& src)
{
int src_idx = std::get<0>(src);
int relidx1 = std::get<1>(src);
int relidx2 = std::get<2>(src);
gl_register_file file = PROGRAM_TEMPORARY;
if (src_idx < 0)
file = PROGRAM_OUTPUT;
else if (relidx1 || relidx2) {
file = PROGRAM_ARRAY;
}
st_src_reg retval = create_src_register(src_idx, file);
if (src_idx >= 0) {
if (relidx1 || relidx2) {
retval.array_id = 1;
if (relidx1)
retval.reladdr = create_rel_src_register(relidx1);
if (relidx2) {
retval.reladdr2 = create_rel_src_register(relidx2);
retval.has_index2 = true;
retval.index2D = 10;
}
}
}
return retval;
}
st_dst_reg FakeCodeline::create_dst_register(int dst_idx,int writemask)
{
gl_register_file file;
int idx = 0;
if (dst_idx >= 0) {
file = PROGRAM_TEMPORARY;
idx = dst_idx;
if (max_temp_id < idx)
max_temp_id = idx;
} else {
file = PROGRAM_OUTPUT;
idx = 1 - dst_idx;
}
return st_dst_reg(file, writemask, GLSL_TYPE_INT, idx);
}
st_dst_reg FakeCodeline::create_dst_register(int dst_idx)
{
return create_dst_register(dst_idx, dst_idx < 0 ?
PROGRAM_OUTPUT : PROGRAM_TEMPORARY);
}
st_dst_reg FakeCodeline::create_dst_register(int dst_idx, gl_register_file file)
{
st_dst_reg retval;
retval.file = file;
retval.index = dst_idx >= 0 ? dst_idx : 1 - dst_idx;
if (file == PROGRAM_TEMPORARY) {
if (max_temp_id < dst_idx)
max_temp_id = dst_idx;
} else if (file == PROGRAM_ARRAY) {
retval.array_id = 1;
if (max_array_id < 1)
max_array_id = 1;
}
retval.writemask = 0xF;
retval.type = GLSL_TYPE_INT;
return retval;
}
st_dst_reg FakeCodeline::create_dst_register(const tuple<int,int,int>& dst)
{
int dst_idx = std::get<0>(dst);
int relidx1 = std::get<1>(dst);
int relidx2 = std::get<2>(dst);
gl_register_file file = PROGRAM_TEMPORARY;
if (dst_idx < 0)
file = PROGRAM_OUTPUT;
else if (relidx1 || relidx2) {
file = PROGRAM_ARRAY;
}
st_dst_reg retval = create_dst_register(dst_idx, file);
if (relidx1 || relidx2) {
if (relidx1)
retval.reladdr = create_rel_src_register(relidx1);
if (relidx2) {
retval.reladdr2 = create_rel_src_register(relidx2);
retval.has_index2 = true;
retval.index2D = 10;
}
}
return retval;
}
glsl_to_tgsi_instruction *FakeCodeline::get_codeline() const
{
glsl_to_tgsi_instruction *next_instr = new(mem_ctx) glsl_to_tgsi_instruction();
next_instr->op = op;
next_instr->info = tgsi_get_opcode_info(op);
assert(src.size() == num_inst_src_regs(next_instr));
assert(dst.size() == num_inst_dst_regs(next_instr));
assert(tex_offsets.size() < 3);
copy(src.begin(), src.end(), next_instr->src);
copy(dst.begin(), dst.end(), next_instr->dst);
next_instr->tex_offset_num_offset = tex_offsets.size();
if (next_instr->tex_offset_num_offset > 0) {
next_instr->tex_offsets = ralloc_array(mem_ctx, st_src_reg, tex_offsets.size());
copy(tex_offsets.begin(), tex_offsets.end(), next_instr->tex_offsets);
} else {
next_instr->tex_offsets = nullptr;
}
return next_instr;
}
void FakeCodeline::set_mem_ctx(void *ctx)
{
mem_ctx = ctx;
}
FakeShader::FakeShader(const vector<FakeCodeline>& source):
program(source),
num_temps(0),
num_arrays(0)
{
for (const FakeCodeline& i: source) {
int t = i.get_max_reg_id();
if (t > num_temps)
num_temps = t;
int a = i.get_max_array_id();
if (a > num_arrays)
num_arrays = a;
}
++num_temps;
}
FakeShader::FakeShader(exec_list *tgsi_prog):
num_temps(0),
num_arrays(0)
{
FakeCodeline nop(TGSI_OPCODE_NOP);
FakeCodeline& last = nop;
foreach_in_list(glsl_to_tgsi_instruction, inst, tgsi_prog) {
program.push_back(last = FakeCodeline(*inst));
if (last.get_max_array_id() > num_arrays)
num_arrays = last.get_max_array_id();
if (num_temps < last.get_max_reg_id())
num_temps = last.get_max_reg_id();
}
++num_temps;
}
int FakeShader::get_num_arrays() const
{
return num_arrays;
}
int FakeShader::get_num_temps() const
{
return num_temps;
}
exec_list* FakeShader::get_program(void *ctx) const
{
exec_list *prog = new(ctx) exec_list();
for (const FakeCodeline& i: program) {
prog->push_tail(i.get_codeline());
}
return prog;
}
size_t FakeShader::length() const
{
return program.size();
}
const FakeCodeline& FakeShader::line(unsigned i) const
{
return program[i];
}
void MesaTestWithMemCtx::SetUp()
{
mem_ctx = ralloc_context(nullptr);
FakeCodeline::set_mem_ctx(mem_ctx);
}
void MesaTestWithMemCtx::TearDown()
{
ralloc_free(mem_ctx);
FakeCodeline::set_mem_ctx(nullptr);
mem_ctx = nullptr;
}
LifetimeEvaluatorTest::life_range_result
LifetimeEvaluatorTest::run(const vector<FakeCodeline>& code, bool& success)
{
FakeShader shader(code);
life_range_result result = make_pair(life_range_result::first_type(shader.get_num_temps()),
life_range_result::second_type(shader.get_num_arrays()));
success =
get_temp_registers_required_live_ranges(mem_ctx, shader.get_program(mem_ctx),
shader.get_num_temps(),&result.first[0],
shader.get_num_arrays(), &result.second[0]);
return result;
}
void LifetimeEvaluatorTest::run(const vector<FakeCodeline>& code, const temp_lt_expect& e)
{
bool success = false;
auto result = run(code, success);
ASSERT_TRUE(success);
ASSERT_EQ(result.first.size(), e.size());
check(result.first, e);
}
void LifetimeEvaluatorTest::run(const vector<FakeCodeline>& code, const array_lt_expect& e)
{
bool success = false;
auto result = run(code, success);
ASSERT_TRUE(success);
ASSERT_EQ(result.second.size(), e.size());
check(result.second, e);
}
void LifetimeEvaluatorExactTest::check( const vector<register_live_range>& lifetimes,
const temp_lt_expect& e)
{
for (unsigned i = 1; i < lifetimes.size(); ++i) {
EXPECT_EQ(lifetimes[i].begin, e[i][0]);
EXPECT_EQ(lifetimes[i].end, e[i][1]);
}
}
void LifetimeEvaluatorExactTest::check(const vector<array_live_range>& lifetimes,
const array_lt_expect& e)
{
for (unsigned i = 0; i < lifetimes.size(); ++i) {
EXPECT_EQ(lifetimes[i].begin(), e[i].begin());
EXPECT_EQ(lifetimes[i].end(), e[i].end());
EXPECT_EQ(lifetimes[i].access_mask(), e[i].access_mask());
}
}
void LifetimeEvaluatorAtLeastTest::check( const vector<register_live_range>& lifetimes,
const temp_lt_expect& e)
{
for (unsigned i = 1; i < lifetimes.size(); ++i) {
EXPECT_LE(lifetimes[i].begin, e[i][0]);
EXPECT_GE(lifetimes[i].end, e[i][1]);
}
}
void LifetimeEvaluatorAtLeastTest::check(const vector<array_live_range>& lifetimes,
const array_lt_expect& e)
{
for (unsigned i = 0; i < lifetimes.size(); ++i) {
EXPECT_LE(lifetimes[i].begin(), e[i].begin());
EXPECT_GE(lifetimes[i].end(), e[i].end());
/* Tests that lifetimes doesn't add unexpected swizzles */
EXPECT_EQ(lifetimes[i].access_mask()| e[i].access_mask(),
e[i].access_mask());
}
}
void RegisterRemappingTest::run(const vector<register_live_range>& lt,
const vector<int>& expect)
{
rename_reg_pair proto{false,0};
vector<rename_reg_pair> result(lt.size(), proto);
get_temp_registers_remapping(mem_ctx, lt.size(), &lt[0], &result[0]);
vector<int> remap(lt.size());
for (unsigned i = 0; i < lt.size(); ++i) {
remap[i] = result[i].valid ? result[i].new_reg : i;
}
std::transform(remap.begin(), remap.end(), result.begin(), remap.begin(),
[](int x, const rename_reg_pair& rn) {
return rn.valid ? rn.new_reg : x;
});
for(unsigned i = 1; i < remap.size(); ++i) {
EXPECT_EQ(remap[i], expect[i]);
}
}
void RegisterLifetimeAndRemappingTest::run(const vector<FakeCodeline>& code,
const vector<int>& expect)
{
FakeShader shader(code);
std::vector<register_live_range> lt(shader.get_num_temps());
std::vector<array_live_range> alt(shader.get_num_arrays());
get_temp_registers_required_live_ranges(mem_ctx, shader.get_program(mem_ctx),
shader.get_num_temps(), &lt[0],
shader.get_num_arrays(), &alt[0]);
this->run(lt, expect);
}

View file

@ -1,203 +0,0 @@
/*
* 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_st_tests_h
#define mesa_st_tests_h
#include "state_tracker/st_glsl_to_tgsi_temprename.h"
#include "state_tracker/st_glsl_to_tgsi_array_merge.h"
#include "gtest/gtest.h"
#include <utility>
#define MP(X, W) std::make_pair(X, W)
#define MT(X,Y,Z) std::make_tuple(X,Y,Z)
/* Use this to make the compiler pick the swizzle constructor below */
struct SWZ {};
/* Use this to make the compiler pick the constructor with reladdr below */
struct RA {};
/* Use this to make the compiler pick the constructor with array below */
struct ARR {};
/* A line to describe a TGSI instruction for building mock shaders. */
struct FakeCodeline {
FakeCodeline(tgsi_opcode _op): op(_op), max_temp_id(0), max_array_id(0) {}
FakeCodeline(tgsi_opcode _op, const std::vector<int>& _dst, const std::vector<int>& _src,
const std::vector<int>&_to);
FakeCodeline(tgsi_opcode _op, const std::vector<std::pair<int,int>>& _dst,
const std::vector<std::pair<int, const char *>>& _src,
const std::vector<std::pair<int, const char *>>&_to, SWZ with_swizzle);
FakeCodeline(tgsi_opcode _op, const std::vector<std::tuple<int,int,int>>& _dst,
const std::vector<std::tuple<int,int,int>>& _src,
const std::vector<std::tuple<int,int,int>>&_to, RA with_reladdr);
FakeCodeline(tgsi_opcode _op, const std::vector<std::tuple<int, int, int> > &_dst,
const std::vector<std::tuple<int,int, const char*>>& _src,
const std::vector<std::tuple<int,int, const char*>>&_to, ARR with_array);
FakeCodeline(const glsl_to_tgsi_instruction& inst);
int get_max_reg_id() const { return max_temp_id;}
int get_max_array_id() const { return max_array_id;}
glsl_to_tgsi_instruction *get_codeline() const;
static void set_mem_ctx(void *ctx);
friend bool operator == (const FakeCodeline& lsh, const FakeCodeline& rhs);
void print(std::ostream& os) const;
private:
st_src_reg create_src_register(int src_idx);
st_src_reg create_src_register(int src_idx, const char *swizzle);
st_src_reg create_src_register(int src_idx, gl_register_file file);
st_src_reg create_src_register(const std::tuple<int,int,int>& src);
st_src_reg *create_rel_src_register(int idx);
st_src_reg create_array_src_register(const std::tuple<int,int,const char*>& r);
st_dst_reg create_array_dst_register(const std::tuple<int,int,int>& r);
st_dst_reg create_dst_register(int dst_idx);
st_dst_reg create_dst_register(int dst_idx, int writemask);
st_dst_reg create_dst_register(int dst_idx, gl_register_file file);
st_dst_reg create_dst_register(const std::tuple<int,int,int>& dest);
template <typename st_reg>
void read_reg(const st_reg& s);
tgsi_opcode op;
std::vector<st_dst_reg> dst;
std::vector<st_src_reg> src;
std::vector<st_src_reg> tex_offsets;
int max_temp_id;
int max_array_id;
static void *mem_ctx;
};
inline std::ostream& operator << (std::ostream& os, const FakeCodeline& line)
{
line.print(os);
return os;
}
/* A few constants that will not be tracked as temporary registers
by the fake shader.
*/
const int in0 = -1;
const int in1 = -2;
const int in2 = -3;
const int out0 = -1;
const int out1 = -2;
const int out2 = -3;
class FakeShader {
public:
FakeShader(const std::vector<FakeCodeline>& source);
FakeShader(exec_list *tgsi_prog);
exec_list* get_program(void *ctx) const;
int get_num_temps() const;
int get_num_arrays() const;
size_t length() const;
const FakeCodeline& line(unsigned i) const;
private:
std::vector<FakeCodeline> program;
int num_temps;
int num_arrays;
};
using temp_lt_expect = std::vector<std::vector<int>>;
using array_lt_expect = std::vector<array_live_range>;
class MesaTestWithMemCtx : public testing::Test {
void SetUp();
void TearDown();
protected:
void *mem_ctx;
};
class LifetimeEvaluatorTest : public MesaTestWithMemCtx {
protected:
void run(const std::vector<FakeCodeline>& code, const temp_lt_expect& e);
void run(const std::vector<FakeCodeline>& code, const array_lt_expect& e);
private:
using life_range_result=std::pair<std::vector<register_live_range>,
std::vector<array_live_range>>;
life_range_result run(const std::vector<FakeCodeline>& code, bool& success);
virtual void check(const std::vector<register_live_range>& result,
const temp_lt_expect& e) = 0;
virtual void check(const std::vector<array_live_range>& lifetimes,
const array_lt_expect& e) = 0;
};
/* This is a test class to check the exact life times of
* registers. */
class LifetimeEvaluatorExactTest : public LifetimeEvaluatorTest {
protected:
void check(const std::vector<register_live_range>& result,
const temp_lt_expect& e);
void check(const std::vector<array_live_range>& result,
const array_lt_expect& e);
};
/* This test class checks that the life time covers at least
* in the expected range. It is used for cases where we know that
* a the implementation could be improved on estimating the minimal
* life time.
*/
class LifetimeEvaluatorAtLeastTest : public LifetimeEvaluatorTest {
protected:
void check(const std::vector<register_live_range>& result, const temp_lt_expect& e);
void check(const std::vector<array_live_range>& result,
const array_lt_expect& e);
};
/* With this test class the renaming mapping estimation is tested */
class RegisterRemappingTest : public MesaTestWithMemCtx {
protected:
void run(const std::vector<register_live_range>& lt,
const std::vector<int> &expect);
};
/* With this test class the combined lifetime estimation and renaming
* mepping estimation is tested
*/
class RegisterLifetimeAndRemappingTest : public RegisterRemappingTest {
protected:
using RegisterRemappingTest::run;
void run(const std::vector<FakeCodeline>& code, const std::vector<int> &expect);
};
#endif

View file

@ -1,962 +0,0 @@
/*
* 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.
*/
#include "st_tests_common.h"
#include "tgsi/tgsi_ureg.h"
#include "tgsi/tgsi_info.h"
#include "mesa/program/prog_instruction.h"
#include "gtest/gtest.h"
#include <utility>
#include <algorithm>
#include <iostream>
using std::vector;
using namespace tgsi_array_merge;
using ArrayLiveRangeMerge=testing::Test;
TEST_F(ArrayLiveRangeMerge, SimpleLiveRange)
{
array_live_range a1(1, 10, 1, 5, WRITEMASK_X);
array_live_range a2(2, 5, 6, 10, WRITEMASK_X);
array_live_range::merge(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 10);
EXPECT_EQ(a1.target_array_id(), 0);
EXPECT_EQ(a1.used_components(), 1);
EXPECT_EQ(a1.access_mask(), WRITEMASK_X);
EXPECT_EQ(a1.remap_one_swizzle(0), 0);
EXPECT_EQ(a1.remap_one_swizzle(1), 1);
EXPECT_EQ(a1.remap_one_swizzle(2), 2);
EXPECT_EQ(a1.remap_one_swizzle(3), 3);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 6);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 1);
EXPECT_EQ(a2.used_components(), 1);
EXPECT_EQ(a2.access_mask(), WRITEMASK_X);
EXPECT_EQ(a2.remap_one_swizzle(0), 0);
EXPECT_EQ(a2.remap_one_swizzle(1), 1);
EXPECT_EQ(a2.remap_one_swizzle(2), 2);
EXPECT_EQ(a2.remap_one_swizzle(3), 3);
}
TEST_F(ArrayLiveRangeMerge, SimpleLiveRangeInverse)
{
array_live_range a1(1, 5, 1, 5, WRITEMASK_X);
array_live_range a2(2, 10, 6, 10, WRITEMASK_X);
array_live_range::merge(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 5);
EXPECT_EQ(a1.target_array_id(), 2);
EXPECT_EQ(a1.used_components(), 1);
EXPECT_EQ(a1.access_mask(), WRITEMASK_X);
EXPECT_EQ(a1.remap_one_swizzle(0), 0);
EXPECT_EQ(a1.remap_one_swizzle(1), 1);
EXPECT_EQ(a1.remap_one_swizzle(2), 2);
EXPECT_EQ(a1.remap_one_swizzle(3), 3);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 0);
EXPECT_EQ(a2.used_components(), 1);
EXPECT_EQ(a2.access_mask(), WRITEMASK_X);
EXPECT_EQ(a2.remap_one_swizzle(0), 0);
EXPECT_EQ(a2.remap_one_swizzle(1), 1);
EXPECT_EQ(a2.remap_one_swizzle(2), 2);
EXPECT_EQ(a2.remap_one_swizzle(3), 3);
}
TEST_F(ArrayLiveRangeMerge, Interleave_x_xyz)
{
array_live_range a1(1, 10, 1, 10, WRITEMASK_X);
array_live_range a2(2, 9, 1, 10, WRITEMASK_XYZ);
array_live_range::interleave(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 10);
EXPECT_EQ(a1.array_length(), 10u);
EXPECT_EQ(a1.target_array_id(), 0);
EXPECT_EQ(a1.used_components(), 4);
EXPECT_EQ(a1.access_mask(), WRITEMASK_XYZW);
EXPECT_EQ(a1.remap_one_swizzle(0), 0);
EXPECT_EQ(a1.remap_one_swizzle(1), 1);
EXPECT_EQ(a1.remap_one_swizzle(2), 2);
EXPECT_EQ(a1.remap_one_swizzle(3), 3);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 1);
EXPECT_EQ(a2.remap_one_swizzle(0), 1);
EXPECT_EQ(a2.remap_one_swizzle(1), 2);
EXPECT_EQ(a2.remap_one_swizzle(2), 3);
EXPECT_EQ(a2.remap_one_swizzle(3), -1);
}
TEST_F(ArrayLiveRangeMerge, Interleave_xyz_x)
{
array_live_range a1(1, 10, 1, 10, WRITEMASK_XYZ);
array_live_range a2(2, 9, 1, 10, WRITEMASK_X);
array_live_range::interleave(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 10);
EXPECT_EQ(a1.array_length(), 10u);
EXPECT_EQ(a1.target_array_id(), 0);
EXPECT_EQ(a1.used_components(), 4);
EXPECT_EQ(a1.access_mask(), WRITEMASK_XYZW);
EXPECT_EQ(a1.remap_one_swizzle(0), 0);
EXPECT_EQ(a1.remap_one_swizzle(1), 1);
EXPECT_EQ(a1.remap_one_swizzle(2), 2);
EXPECT_EQ(a1.remap_one_swizzle(3), 3);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 1);
EXPECT_EQ(a2.remap_one_swizzle(0), 3);
EXPECT_EQ(a2.remap_one_swizzle(1), -1);
EXPECT_EQ(a2.remap_one_swizzle(2), -1);
EXPECT_EQ(a2.remap_one_swizzle(3), -1);
}
TEST_F(ArrayLiveRangeMerge, SimpleInterleave)
{
array_live_range a1(1, 10, 1, 10, WRITEMASK_X);
array_live_range a2(2, 9, 1, 10, WRITEMASK_X);
array_live_range::interleave(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 10);
EXPECT_EQ(a1.array_length(), 10u);
EXPECT_EQ(a1.target_array_id(), 0);
EXPECT_EQ(a1.used_components(), 2);
EXPECT_EQ(a1.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a1.remap_one_swizzle(0), 0);
EXPECT_EQ(a1.remap_one_swizzle(1), 1);
EXPECT_EQ(a1.remap_one_swizzle(2), 2);
EXPECT_EQ(a1.remap_one_swizzle(3), 3);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 1);
EXPECT_EQ(a2.remap_one_swizzle(0), 1);
EXPECT_EQ(a2.remap_one_swizzle(1), -1);
EXPECT_EQ(a2.remap_one_swizzle(2), -1);
EXPECT_EQ(a2.remap_one_swizzle(3), -1);
}
TEST_F(ArrayLiveRangeMerge, SimpleInterleaveInverse)
{
array_live_range a1(1, 8, 1, 10, WRITEMASK_X);
array_live_range a2(2, 9, 1, 10, WRITEMASK_X);
array_live_range::interleave(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 10);
EXPECT_EQ(a1.target_array_id(), 2);
EXPECT_EQ(a1.remap_one_swizzle(0), 1);
EXPECT_EQ(a1.remap_one_swizzle(1), -1);
EXPECT_EQ(a1.remap_one_swizzle(2), -1);
EXPECT_EQ(a1.remap_one_swizzle(3), -1);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.target_array_id(), 0);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.array_length(), 9u);
EXPECT_EQ(a2.used_components(), 2);
EXPECT_EQ(a2.access_mask(), WRITEMASK_XY);
}
TEST_F(ArrayLiveRangeMerge, InterleaveRiveRangeExtend)
{
array_live_range a1(1, 10, 2, 9, WRITEMASK_X);
array_live_range a2(2, 9, 1, 10, WRITEMASK_X);
array_live_range::interleave(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 10);
EXPECT_EQ(a1.array_length(), 10u);
EXPECT_EQ(a1.target_array_id(), 0);
EXPECT_EQ(a1.used_components(), 2);
EXPECT_EQ(a1.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a1.remap_one_swizzle(0), 0);
EXPECT_EQ(a1.remap_one_swizzle(1), 1);
EXPECT_EQ(a1.remap_one_swizzle(2), 2);
EXPECT_EQ(a1.remap_one_swizzle(3), 3);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 1);
EXPECT_EQ(a2.remap_one_swizzle(0), 1);
EXPECT_EQ(a2.remap_one_swizzle(1), -1);
EXPECT_EQ(a2.remap_one_swizzle(2), -1);
EXPECT_EQ(a2.remap_one_swizzle(3), -1);
}
TEST_F(ArrayLiveRangeMerge, InterleaveLiveRangeExtendInverse)
{
array_live_range a1(1, 8, 2, 11, WRITEMASK_X);
array_live_range a2(2, 9, 1, 10, WRITEMASK_X);
array_live_range::interleave(&a1, &a2);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 2);
EXPECT_EQ(a1.end(), 11);
EXPECT_EQ(a1.target_array_id(), 2);
EXPECT_EQ(a1.used_components(), 1);
EXPECT_EQ(a1.access_mask(), WRITEMASK_X);
EXPECT_EQ(a1.remap_one_swizzle(0), 1);
EXPECT_EQ(a1.remap_one_swizzle(1), -1);
EXPECT_EQ(a1.remap_one_swizzle(2), -1);
EXPECT_EQ(a1.remap_one_swizzle(3), -1);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 11);
EXPECT_EQ(a2.target_array_id(), 0);
EXPECT_EQ(a2.used_components(), 2);
EXPECT_EQ(a2.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a2.remap_one_swizzle(0), 0);
EXPECT_EQ(a2.remap_one_swizzle(1), 1);
EXPECT_EQ(a2.remap_one_swizzle(2), 2);
EXPECT_EQ(a2.remap_one_swizzle(3), 3);
}
TEST_F(ArrayLiveRangeMerge, InterleaveChained)
{
array_live_range a1(1, 8, 2, 11, WRITEMASK_X);
array_live_range a2(2, 9, 1, 10, WRITEMASK_X);
array_live_range a3(3, 10, 1, 10, WRITEMASK_X);
array_live_range::interleave(&a1, &a2);
array_live_range::interleave(&a2, &a3);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 2);
EXPECT_EQ(a1.end(), 11);
EXPECT_EQ(a1.target_array_id(), 2);
EXPECT_EQ(a1.used_components(), 1);
EXPECT_EQ(a1.access_mask(), WRITEMASK_X);
EXPECT_EQ(a1.remap_one_swizzle(0), 2);
EXPECT_EQ(a1.remap_one_swizzle(1), -1);
EXPECT_EQ(a1.remap_one_swizzle(2), -1);
EXPECT_EQ(a1.remap_one_swizzle(3), -1);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 11);
EXPECT_EQ(a2.target_array_id(), 3);
EXPECT_EQ(a2.used_components(), 2);
EXPECT_EQ(a2.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a2.remap_one_swizzle(0), 1);
EXPECT_EQ(a2.remap_one_swizzle(1), 2);
EXPECT_EQ(a2.remap_one_swizzle(2), -1);
EXPECT_EQ(a2.remap_one_swizzle(3), -1);
EXPECT_EQ(a3.array_id(), 3);
EXPECT_EQ(a3.begin(), 1);
EXPECT_EQ(a3.end(), 11);
EXPECT_EQ(a3.target_array_id(), 0);
EXPECT_EQ(a3.used_components(), 3);
EXPECT_EQ(a3.access_mask(), WRITEMASK_XYZ);
EXPECT_EQ(a3.remap_one_swizzle(0), 0);
EXPECT_EQ(a3.remap_one_swizzle(1), 1);
EXPECT_EQ(a3.remap_one_swizzle(2), 2);
EXPECT_EQ(a3.remap_one_swizzle(3), 3);
}
TEST_F(ArrayLiveRangeMerge, MergeInterleaveChained)
{
array_live_range a1(1, 8, 1, 5, WRITEMASK_X);
array_live_range a2(2, 9, 6, 10, WRITEMASK_X);
array_live_range a3(3, 10, 1, 10, WRITEMASK_X);
array_live_range::merge(&a1, &a2);
array_live_range::interleave(&a2, &a3);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 5);
EXPECT_EQ(a1.target_array_id(), 2);
EXPECT_EQ(a1.used_components(), 1);
EXPECT_EQ(a1.access_mask(), WRITEMASK_X);
EXPECT_EQ(a1.remap_one_swizzle(0), 1);
EXPECT_EQ(a1.remap_one_swizzle(1), -1);
EXPECT_EQ(a1.remap_one_swizzle(2), -1);
EXPECT_EQ(a1.remap_one_swizzle(3), -1);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 3);
EXPECT_EQ(a2.used_components(), 1);
EXPECT_EQ(a2.access_mask(), WRITEMASK_X);
EXPECT_EQ(a2.remap_one_swizzle(0), 1);
EXPECT_EQ(a2.remap_one_swizzle(1), -1);
EXPECT_EQ(a2.remap_one_swizzle(2), -1);
EXPECT_EQ(a2.remap_one_swizzle(3), -1);
EXPECT_EQ(a3.array_id(), 3);
EXPECT_EQ(a3.begin(), 1);
EXPECT_EQ(a3.end(), 10);
EXPECT_EQ(a3.target_array_id(), 0);
EXPECT_EQ(a3.used_components(), 2);
EXPECT_EQ(a3.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a3.remap_one_swizzle(0), 0);
EXPECT_EQ(a3.remap_one_swizzle(1), 1);
EXPECT_EQ(a3.remap_one_swizzle(2), 2);
EXPECT_EQ(a3.remap_one_swizzle(3), 3);
}
TEST_F(ArrayLiveRangeMerge, MergeMergeAndInterleave)
{
array_live_range a1(1, 5, 1, 5, WRITEMASK_X);
array_live_range a2(2, 4, 6, 7, WRITEMASK_X);
array_live_range a3(3, 3, 1, 5, WRITEMASK_X);
array_live_range a4(4, 2, 6, 8, WRITEMASK_X);
array_live_range::merge(&a1, &a2);
array_live_range::merge(&a3, &a4);
array_live_range::interleave(&a1, &a3);
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 8);
EXPECT_EQ(a1.target_array_id(), 0);
EXPECT_EQ(a1.used_components(), 2);
EXPECT_EQ(a1.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a1.remap_one_swizzle(0), 0);
EXPECT_EQ(a1.remap_one_swizzle(1), 1);
EXPECT_EQ(a1.remap_one_swizzle(2), 2);
EXPECT_EQ(a1.remap_one_swizzle(3), 3);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 6);
EXPECT_EQ(a2.end(), 7);
EXPECT_EQ(a2.target_array_id(), 1);
EXPECT_EQ(a2.used_components(), 1);
EXPECT_EQ(a2.access_mask(), WRITEMASK_X);
EXPECT_EQ(a2.remap_one_swizzle(0), 0);
EXPECT_EQ(a2.remap_one_swizzle(1), 1);
EXPECT_EQ(a2.remap_one_swizzle(2), 2);
EXPECT_EQ(a2.remap_one_swizzle(3), 3);
EXPECT_EQ(a3.array_id(), 3);
EXPECT_EQ(a3.begin(), 1);
EXPECT_EQ(a3.end(), 8);
EXPECT_EQ(a3.target_array_id(), 1);
EXPECT_EQ(a3.used_components(), 1);
EXPECT_EQ(a3.access_mask(), WRITEMASK_X);
EXPECT_EQ(a3.remap_one_swizzle(0), 1);
EXPECT_EQ(a3.remap_one_swizzle(1), -1);
EXPECT_EQ(a3.remap_one_swizzle(2), -1);
EXPECT_EQ(a3.remap_one_swizzle(3), -1);
EXPECT_EQ(a4.array_id(), 4);
EXPECT_EQ(a4.begin(), 6);
EXPECT_EQ(a4.end(), 8);
EXPECT_EQ(a4.target_array_id(), 3);
EXPECT_EQ(a4.used_components(), 1);
EXPECT_EQ(a4.access_mask(), WRITEMASK_X);
EXPECT_EQ(a4.remap_one_swizzle(0), 1);
EXPECT_EQ(a4.remap_one_swizzle(1), -1);
EXPECT_EQ(a4.remap_one_swizzle(2), -1);
EXPECT_EQ(a4.remap_one_swizzle(3), -1);
}
TEST_F(ArrayLiveRangeMerge, MergeInterleaveMergeInterleaveChained)
{
array_live_range a1(1, 8, 1, 5, WRITEMASK_X);
array_live_range a2(2, 9, 6, 10, WRITEMASK_X);
array_live_range a3(3, 10, 1, 10, WRITEMASK_X);
array_live_range a4(4, 11, 11, 20, WRITEMASK_XY);
array_live_range a5(5, 15, 5, 20, WRITEMASK_XY);
array_live_range::merge(&a1, &a2);
array_live_range::interleave(&a2, &a3); // a2 -> a3
array_live_range::merge(&a3, &a4);
array_live_range::interleave(&a4, &a5); // a4 -> a5
EXPECT_EQ(a1.array_id(), 1);
EXPECT_EQ(a1.begin(), 1);
EXPECT_EQ(a1.end(), 5);
EXPECT_EQ(a1.target_array_id(), 2);
EXPECT_EQ(a1.used_components(), 1);
EXPECT_EQ(a1.access_mask(), WRITEMASK_X);
EXPECT_EQ(a1.remap_one_swizzle(0), 3);
EXPECT_EQ(a1.remap_one_swizzle(1), -1);
EXPECT_EQ(a1.remap_one_swizzle(2), -1);
EXPECT_EQ(a1.remap_one_swizzle(3), -1);
EXPECT_EQ(a2.array_id(), 2);
EXPECT_EQ(a2.begin(), 1);
EXPECT_EQ(a2.end(), 10);
EXPECT_EQ(a2.target_array_id(), 3);
EXPECT_EQ(a2.used_components(), 1);
EXPECT_EQ(a2.access_mask(), WRITEMASK_X);
EXPECT_EQ(a2.remap_one_swizzle(0), 3);
EXPECT_EQ(a2.remap_one_swizzle(1), -1);
EXPECT_EQ(a2.remap_one_swizzle(2), -1);
EXPECT_EQ(a2.remap_one_swizzle(3), -1);
EXPECT_EQ(a3.array_id(), 3);
EXPECT_EQ(a3.begin(), 1);
EXPECT_EQ(a3.end(), 10);
EXPECT_EQ(a3.target_array_id(), 4);
EXPECT_EQ(a3.used_components(), 2);
EXPECT_EQ(a3.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a3.remap_one_swizzle(0), 2);
EXPECT_EQ(a3.remap_one_swizzle(1), 3);
EXPECT_EQ(a3.remap_one_swizzle(2), -1);
EXPECT_EQ(a3.remap_one_swizzle(3), -1);
EXPECT_EQ(a4.array_id(), 4);
EXPECT_EQ(a4.begin(), 1);
EXPECT_EQ(a4.end(), 20);
EXPECT_EQ(a4.target_array_id(), 5);
EXPECT_EQ(a4.used_components(), 2);
EXPECT_EQ(a4.access_mask(), WRITEMASK_XY);
EXPECT_EQ(a4.remap_one_swizzle(0), 2);
EXPECT_EQ(a4.remap_one_swizzle(1), 3);
EXPECT_EQ(a4.remap_one_swizzle(2), -1);
EXPECT_EQ(a4.remap_one_swizzle(3), -1);
EXPECT_EQ(a5.array_id(), 5);
EXPECT_EQ(a5.begin(), 1);
EXPECT_EQ(a5.end(), 20);
EXPECT_EQ(a5.target_array_id(), 0);
EXPECT_EQ(a5.used_components(), 4);
EXPECT_EQ(a5.access_mask(), WRITEMASK_XYZW);
EXPECT_EQ(a5.remap_one_swizzle(0), 0);
EXPECT_EQ(a5.remap_one_swizzle(1), 1);
EXPECT_EQ(a5.remap_one_swizzle(2), 2);
EXPECT_EQ(a5.remap_one_swizzle(3), 3);
}
using ArrayMergeTest=testing::Test;
TEST_F(ArrayMergeTest, ArrayMergeTwoSwizzles)
{
vector<array_live_range> alt = {
{1, 4, 1, 5, WRITEMASK_X},
{2, 4, 2, 5, WRITEMASK_X},
};
int8_t expect_swizzle[] = {1, -1, -1, -1};
vector<array_remapping> expect = {
{},
{1, expect_swizzle},
};
vector<array_remapping> result(alt.size() + 1);
get_array_remapping(2, &alt[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
}
TEST_F(ArrayMergeTest, ArrayMergeFourSwizzles)
{
vector<array_live_range> alt = {
{1, 8, 1, 7, WRITEMASK_X},
{2, 7, 2, 7, WRITEMASK_X},
{3, 6, 3, 7, WRITEMASK_X},
{4, 5, 4, 7, WRITEMASK_X},
};
int8_t expect_swizzle1[] = {1, -1, -1, -1};
int8_t expect_swizzle2[] = {2, -1, -1, -1};
int8_t expect_swizzle3[] = {3, -1, -1, -1};
vector<array_remapping> expect = {
{},
{1, expect_swizzle1},
{1, expect_swizzle2},
{1, expect_swizzle3},
};
vector<array_remapping> result(alt.size() + 1);
get_array_remapping(4, &alt[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
EXPECT_EQ(result[3], expect[2]);
EXPECT_EQ(result[4], expect[3]);
}
TEST_F(ArrayMergeTest, SimpleChainMerge)
{
vector<array_live_range> input = {
{1, 3, 1, 5, WRITEMASK_XYZW},
{2, 2, 6, 7, WRITEMASK_XYZW},
};
int8_t expect_swizzle[] = {0, 1, 2, 3};
vector<array_remapping> expect = {
{},
{1, expect_swizzle},
};
vector<array_remapping> result(3);
get_array_remapping(2, &input[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
}
TEST_F(ArrayMergeTest, MergeAndInterleave)
{
vector<array_live_range> input = {
{1, 5, 1, 5, WRITEMASK_X},
{2, 4, 6, 7, WRITEMASK_X},
{3, 3, 1, 5, WRITEMASK_X},
{4, 2, 6, 7, WRITEMASK_X},
};
int8_t expect_swizzle1[] = {0, 1, 2, 3};
int8_t expect_swizzle2[] = {1, -1, -1, -1};
int8_t expect_swizzle3[] = {1, -1, -1, -1};
vector<array_remapping> expect = {
{},
{1, expect_swizzle1},
{1, expect_swizzle2},
{1, expect_swizzle3}
};
vector<array_remapping> result(input.size() + 1);
get_array_remapping(input.size(), &input[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
EXPECT_EQ(result[3], expect[2]);
EXPECT_EQ(result[4], expect[3]);
}
TEST_F(ArrayMergeTest, MergeAndInterleave2)
{
vector<array_live_range> input = {
{1, 5, 1, 5, WRITEMASK_X},
{2, 4, 6, 7, WRITEMASK_X},
{3, 3, 1, 8, WRITEMASK_XY},
{4, 2, 6, 7, WRITEMASK_X},
};
int8_t expect_swizzle1[] = {0, 1, 2, 3};
int8_t expect_swizzle2[] = {1, 2, -1, -1};
int8_t expect_swizzle3[] = {3, -1, -1, -1};
vector<array_remapping> expect = {
{},
{1, expect_swizzle1},
{1, expect_swizzle2},
{1, expect_swizzle3}
};
vector<array_remapping> result(input.size() + 1);
get_array_remapping(input.size(), &input[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
EXPECT_EQ(result[3], expect[2]);
EXPECT_EQ(result[4], expect[3]);
}
TEST_F(ArrayMergeTest, MergeAndInterleave3)
{
vector<array_live_range> input = {
{1, 5, 1, 5, WRITEMASK_X},
{2, 4, 6, 7, WRITEMASK_XY},
{3, 3, 1, 5, WRITEMASK_X}
};
int8_t expect_swizzle1[] = {0, 1, 2, 3};
int8_t expect_swizzle2[] = {1, -1, -1, -1};
vector<array_remapping> expect = {
{},
{1, expect_swizzle1},
{1, expect_swizzle2}
};
vector<array_remapping> result(input.size() + 1);
get_array_remapping(input.size(), &input[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
EXPECT_EQ(result[3], expect[2]);
}
TEST_F(ArrayMergeTest, MergeAndInterleave4)
{
vector<array_live_range> input = {
{1, 7, 1, 5, WRITEMASK_X},
{2, 6, 6, 7, WRITEMASK_XY},
{3, 5, 1, 5, WRITEMASK_X},
{4, 4, 8, 9, WRITEMASK_XYZ},
{5, 3, 8, 9, WRITEMASK_W},
{6, 2, 10, 11, WRITEMASK_XYZW},
};
int8_t expect_swizzle1[] = {0, 1, 2, 3};
int8_t expect_swizzle2[] = {1, -1, -1, -1};
int8_t expect_swizzle3[] = {0, 1, 2, 3};
int8_t expect_swizzle4[] = {-1, -1, -1, 3};
int8_t expect_swizzle5[] = {0, 1, 2, 3};
vector<array_remapping> expect = {
{},
{1, expect_swizzle1},
{1, expect_swizzle2},
{1, expect_swizzle3}, /* W from below will be interleaved in */
{1, expect_swizzle4},
{1, expect_swizzle5}
};
vector<array_remapping> result(input.size() + 1);
get_array_remapping(input.size(), &input[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
EXPECT_EQ(result[3], expect[2]);
EXPECT_EQ(result[4], expect[3]);
EXPECT_EQ(result[5], expect[4]);
EXPECT_EQ(result[6], expect[5]);
}
TEST_F(ArrayMergeTest, MergeAndInterleave5)
{
vector<array_live_range> input = {
{1, 7, 1, 5, WRITEMASK_X},
{2, 6, 1, 3, WRITEMASK_X},
{3, 5, 4, 5, WRITEMASK_X},
{4, 4, 6, 10, WRITEMASK_XY},
{5, 8, 1, 10, WRITEMASK_XY}
};
/* 1. merge 3 into 2
* 2. interleave 2 into 1 (x -> y) --- (y -> w)
* 3. merge 4 into 1 /
* 4. interleave 1 into 5 (x,y - z,w)
*/
/* swizzle1 holds the summary mask */
int8_t expect_swizzle1[] = {2, 3, -1, -1};
int8_t expect_swizzle2[] = {3, -1, -1, -1};
int8_t expect_swizzle3[] = {3, -1, -1, -1};
int8_t expect_swizzle4[] = {2, 3, -1, -1};
vector<array_remapping> expect = {
{5, expect_swizzle1},
{5, expect_swizzle2},
{5, expect_swizzle3},
{5, expect_swizzle4},
{}
};
vector<array_remapping> result(input.size() + 1);
get_array_remapping(input.size(), &input[0], &result[0]);
EXPECT_EQ(result[1], expect[0]);
EXPECT_EQ(result[2], expect[1]);
EXPECT_EQ(result[3], expect[2]);
EXPECT_EQ(result[4], expect[3]);
EXPECT_EQ(result[5], expect[4]);
}
/* Test two arrays life time simple */
TEST_F(LifetimeEvaluatorExactTest, TwoArraysSimple)
{
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV , {MT(1, 1, WRITEMASK_XYZW)}, {MT(0, in0, "")}, {}, ARR()},
{ TGSI_OPCODE_MOV , {MT(2, 1, WRITEMASK_XYZW)}, {MT(0, in1, "")}, {}, ARR()},
{ TGSI_OPCODE_ADD , {MT(0,out0, WRITEMASK_XYZW)}, {MT(1,1,"xyzw"), MT(2,1,"xyzw")}, {}, ARR()},
{ TGSI_OPCODE_END}
};
run (code, array_lt_expect({{1,2,0,2, WRITEMASK_XYZW}, {2,2,1,2, WRITEMASK_XYZW}}));
}
/* Test two arrays life time simple */
TEST_F(LifetimeEvaluatorExactTest, TwoArraysSimpleSwizzleX_Y)
{
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV , {MT(1, 1, WRITEMASK_X)}, {MT(0, in0, "")}, {}, ARR()},
{ TGSI_OPCODE_MOV , {MT(2, 1, WRITEMASK_Y)}, {MT(0, in1, "")}, {}, ARR()},
{ TGSI_OPCODE_ADD , {MT(0,out0,1)}, {MT(1,1,"x"), MT(2,1,"y")}, {}, ARR()},
{ TGSI_OPCODE_END}
};
run (code, array_lt_expect({{1, 2, 0, 2, WRITEMASK_X}, {2, 2, 1, 2, WRITEMASK_Y}}));
}
/* Test array written before loop and read inside, must survive the loop */
TEST_F(LifetimeEvaluatorExactTest, ArraysWriteBeforLoopReadInside)
{
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV, {1}, {in1}, {}},
{ TGSI_OPCODE_MOV, {MT(1, 1, WRITEMASK_X)}, {MT(0, in0, "")}, {}, ARR()},
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_ADD, {MT(0,1, WRITEMASK_X)}, {MT(1,1,"x"), {MT(0,1, "x")}}, {}, ARR()},
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_MOV, {out0}, {1}, {}},
{ TGSI_OPCODE_END}
};
run (code, array_lt_expect({{1, 1, 1, 4, WRITEMASK_X}}));
}
/* Test array written conditionally in loop must survive the whole loop */
TEST_F(LifetimeEvaluatorExactTest, ArraysConditionalWriteInNestedLoop)
{
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV, {1}, {in1}, {}},
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_IF, {}, {1}, {}},
{ TGSI_OPCODE_MOV, {MT(1, 1, WRITEMASK_Z)}, {MT(0, in0, "")}, {}, ARR()},
{ TGSI_OPCODE_ENDIF },
{ TGSI_OPCODE_ADD, {MT(0,1, WRITEMASK_X)}, {MT(1,1,"z"), {MT(0,1, "x")}}, {}, ARR()},
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_MOV, {out0}, {1}, {}},
{ TGSI_OPCODE_END}
};
run (code, array_lt_expect({{1, 1, 1, 8, WRITEMASK_Z}}));
}
/* Test array read conditionally in loop before write must
* survive the whole loop
*/
TEST_F(LifetimeEvaluatorExactTest, ArraysConditionalReadBeforeWriteInNestedLoop)
{
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV, {1}, {in1}, {}},
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_IF, {}, {1}, {}},
{ TGSI_OPCODE_ADD, {MT(0,1, WRITEMASK_X)}, {MT(1,1,"z"), {MT(0,1, "x")}}, {}, ARR()},
{ TGSI_OPCODE_ENDIF },
{ TGSI_OPCODE_MOV, {MT(1, 1, WRITEMASK_Z)}, {MT(0, in0, "")}, {}, ARR()},
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_MOV, {out0}, {1}, {}},
{ TGSI_OPCODE_END}
};
run (code, array_lt_expect({{1, 1, 1, 8, WRITEMASK_Z}}));
}
/* Test array written conditionally in loop must survive the whole loop */
TEST_F(LifetimeEvaluatorExactTest, ArraysConditionalWriteInNestedLoop2)
{
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV, {1}, {in1}, {}},
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_IF, {}, {1}, {}},
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_MOV, {MT(1, 1, WRITEMASK_Z)}, {MT(0, in0, "")}, {}, ARR()},
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_ENDIF },
{ TGSI_OPCODE_ADD, {MT(0,1, WRITEMASK_X)}, {MT(1,1,"z"), {MT(0,1, "x")}}, {}, ARR()},
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_MOV, {out0}, {1}, {}},
{ TGSI_OPCODE_END}
};
run (code, array_lt_expect({{1, 1, 1, 10, WRITEMASK_Z}}));
}
/* Test distinct loops */
TEST_F(LifetimeEvaluatorExactTest, ArraysReadWriteInSeparateScopes)
{
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV, {1}, {in1}, {}},
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_MOV, {MT(1, 1, WRITEMASK_W)}, {MT(0, in0, "")}, {}, ARR()},
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_BGNLOOP },
{ TGSI_OPCODE_ADD, {MT(0,1, WRITEMASK_X)}, {MT(1,1,"w"), {MT(0,1, "x")}}, {}, ARR()},
{ TGSI_OPCODE_ENDLOOP },
{ TGSI_OPCODE_MOV, {out0}, {1}, {}},
{ TGSI_OPCODE_END}
};
run (code, array_lt_expect({{1, 1, 2, 6, WRITEMASK_W}}));
}
class ArrayRemapTest: public MesaTestWithMemCtx {
public:
void run (const vector<FakeCodeline>& code,
const vector<FakeCodeline>& expect,
vector<unsigned> array_sizes,
vector<array_remapping>& remapping) const;
};
TEST_F(ArrayRemapTest, ApplyMerge)
{
vector<unsigned> array_sizes{0, 12, 11, 10, 9, 8, 7};
int8_t set_swizzle3[] = {1, -1, -1, -1};
int8_t set_swizzle5[] = {3, -1, -1, -1};
int8_t set_no_reswizzle[] = {0, 1, 2, 3};
vector<array_remapping> remapping = {
{},
array_remapping(),
{1, set_no_reswizzle},
{1, set_swizzle3},
{1, set_no_reswizzle},
{1, set_swizzle5},
{1, set_no_reswizzle}
};
const vector<FakeCodeline> code = {
{ TGSI_OPCODE_MOV, {MT(1, 1, WRITEMASK_X)}, {MT(0, in0, "x")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(2, 2, WRITEMASK_XY)}, {MT(0, in0, "xy")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(3, 3, WRITEMASK_X)}, {MT(0, in0, "x")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(4, 4, WRITEMASK_XYZ)}, {MT(0, in0, "xyz")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(5, 5, WRITEMASK_X)}, {MT(0, in0, "x")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(6, 6, WRITEMASK_XYZW)}, {MT(0, in0, "xyzw")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out0, WRITEMASK_X)}, {MT(1, 1, "x"), MT(0, in0, "y")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out0, WRITEMASK_YZ)}, {MT(2, 2, "xy"), MT(0, in0, "yz")}, {}, ARR()},
{ TGSI_OPCODE_MUL, {MT(0, out0, WRITEMASK_W)}, {MT(3, 3, "x"), MT(0, in0, "x")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out1, WRITEMASK_XYZ)}, {MT(4, 4, "xyz"), MT(0, in0, "xyz")}, {}, ARR()},
{ TGSI_OPCODE_MAD, {MT(0, out1, WRITEMASK_W)}, {MT(5, 5, "x"), MT(3, 1, "x"), MT(1, 1, "x")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out2, WRITEMASK_XYZW)}, {MT(6, 6, "xyzw"), MT(0, in0, "xyzw")}, {}, ARR()},
{ TGSI_OPCODE_END}
};
const vector<FakeCodeline> expect = {
{ TGSI_OPCODE_MOV, {MT(1, 1, WRITEMASK_X)}, {MT(0, in0, "x")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(1, 2, WRITEMASK_XY)}, {MT(0, in0, "xy")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(1, 3, WRITEMASK_Y)}, {MT(0, in0, "xx")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(1, 4, WRITEMASK_XYZ)}, {MT(0, in0, "xyz")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(1, 5, WRITEMASK_W)}, {MT(0, in0, "xxxx")}, {}, ARR()},
{ TGSI_OPCODE_MOV, {MT(1, 6, WRITEMASK_XYZW)}, {MT(0, in0, "xyzw")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out0, WRITEMASK_X)}, {MT(1, 1, "x"), MT(0, in0, "y")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out0, WRITEMASK_YZ)}, {MT(1, 2, "xy"), MT(0, in0, "yz")}, {}, ARR()},
{ TGSI_OPCODE_MUL, {MT(0, out0, WRITEMASK_W)}, {MT(1, 3, "y"), MT(0, in0, "xx")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out1, WRITEMASK_XYZ)}, {MT(1, 4, "xyz"), MT(0, in0, "xyz")}, {}, ARR()},
{ TGSI_OPCODE_MAD, {MT(0, out1, WRITEMASK_W)}, {MT(1, 5, "w"), MT(1, 1, "yyyy"), MT(1, 1, "xxxx")}, {}, ARR()},
{ TGSI_OPCODE_ADD, {MT(0, out2, WRITEMASK_XYZW)}, {MT(1, 6, "xyzw"), MT(0, in0, "xyzw")}, {}, ARR()},
{ TGSI_OPCODE_END}
};
run(code, expect, array_sizes, remapping);
}
void ArrayRemapTest::run (const vector<FakeCodeline>& code,
const vector<FakeCodeline>& expect,
vector<unsigned> array_sizes,
vector<array_remapping>& remapping) const
{
FakeShader input(code);
FakeShader expect_shader(expect);
exec_list *program = input.get_program(mem_ctx);
int n_arrays = remap_arrays(array_sizes.size() - 1, &array_sizes[0],
program, &remapping[0]);
EXPECT_EQ(n_arrays, expect_shader.get_num_arrays());
FakeShader remapped_program(program);
ASSERT_EQ(remapped_program.length(), expect_shader.length());
for (size_t i = 0; i < expect_shader.length(); i++) {
EXPECT_EQ(remapped_program.line(i), expect_shader.line(i));
}
}

File diff suppressed because it is too large Load diff