mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-21 11:30:11 +01:00
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:
parent
b167203cfe
commit
214c774ba6
19 changed files with 57 additions and 14861 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 ®)
|
|
||||||
{
|
|
||||||
*this = reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void st_src_reg::operator=(const st_src_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 ®)
|
|
||||||
{
|
|
||||||
*this = reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void st_dst_reg::operator=(const st_dst_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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 ®);
|
|
||||||
void operator=(const st_src_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 ®);
|
|
||||||
void operator=(const st_dst_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
|
|
@ -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
|
|
||||||
|
|
@ -588,15 +588,7 @@ 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);
|
||||||
|
|
||||||
|
|
@ -627,76 +619,6 @@ st_translate_vertex_program(struct st_context *st,
|
||||||
|
|
||||||
st_prepare_vertex_program(prog, NULL);
|
st_prepare_vertex_program(prog, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t input_to_index[VERT_ATTRIB_MAX];
|
|
||||||
st_prepare_vertex_program(prog, input_to_index);
|
|
||||||
|
|
||||||
/* Get semantic names and indices. */
|
|
||||||
for (attr = 0; attr < VARYING_SLOT_MAX; attr++) {
|
|
||||||
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,14 +903,13 @@ 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);
|
||||||
|
|
@ -1029,282 +950,6 @@ st_translate_fragment_program(struct st_context *st,
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
ubyte outputMapping[2 * FRAG_RESULT_MAX];
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -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" {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -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(), <[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(), <[0],
|
|
||||||
shader.get_num_arrays(), &alt[0]);
|
|
||||||
this->run(lt, expect);
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
Loading…
Add table
Reference in a new issue