Source code
Revision control
Copy as Markdown
Other Tools
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
//
// ReplaceArrayOfMatrixVarying: Find any references to array of matrices varying
// and replace it with array of vectors.
//
#include "compiler/translator/tree_util/ReplaceArrayOfMatrixVarying.h"
#include <vector>
#include "common/bitset_utils.h"
#include "common/debug.h"
#include "common/utilities.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/BuiltIn.h"
#include "compiler/translator/tree_util/FindMain.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/tree_util/ReplaceVariable.h"
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
#include "compiler/translator/util.h"
namespace sh
{
// We create two variables to replace the given varying:
// - The new varying which is an array of vectors to be used at input/ouput only.
// - The new global variable which is a same type as given variable, to temporarily be used
// as replacements for assignments, arithmetic ops and so on. During input/ouput phrase, this temp
// variable will be copied from/to the array of vectors variable above.
// NOTE(hqle): Consider eliminating the need for using temp variable.
namespace
{
class CollectVaryingTraverser : public TIntermTraverser
{
public:
CollectVaryingTraverser(std::vector<const TVariable *> *varyingsOut)
: TIntermTraverser(true, false, false), mVaryingsOut(varyingsOut)
{}
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
{
const TIntermSequence &sequence = *(node->getSequence());
if (sequence.size() != 1)
{
return false;
}
TIntermTyped *variableType = sequence.front()->getAsTyped();
if (!variableType || !IsVarying(variableType->getQualifier()) ||
!variableType->isMatrix() || !variableType->isArray())
{
return false;
}
TIntermSymbol *variableSymbol = variableType->getAsSymbolNode();
if (!variableSymbol)
{
return false;
}
mVaryingsOut->push_back(&variableSymbol->variable());
return false;
}
private:
std::vector<const TVariable *> *mVaryingsOut;
};
} // namespace
[[nodiscard]] bool ReplaceArrayOfMatrixVarying(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable,
const TVariable *varying)
{
const TType &type = varying->getType();
// Create global variable to temporarily acts as the given variable in places such as
// arithmetic, assignments an so on.
TType *tmpReplacementType = new TType(type);
tmpReplacementType->setQualifier(EvqGlobal);
TVariable *tempReplaceVar = new TVariable(
symbolTable, ImmutableString(std::string("ANGLE_AOM_Temp_") + varying->name().data()),
tmpReplacementType, SymbolType::AngleInternal);
if (!ReplaceVariable(compiler, root, varying, tempReplaceVar))
{
return false;
}
// Create array of vectors type
TType *varyingReplaceType = new TType(type);
varyingReplaceType->toMatrixColumnType();
varyingReplaceType->toArrayElementType();
varyingReplaceType->makeArray(type.getCols() * type.getOutermostArraySize());
TVariable *varyingReplaceVar =
new TVariable(symbolTable, varying->name(), varyingReplaceType, SymbolType::UserDefined);
TIntermSymbol *varyingReplaceDeclarator = new TIntermSymbol(varyingReplaceVar);
TIntermDeclaration *varyingReplaceDecl = new TIntermDeclaration;
varyingReplaceDecl->appendDeclarator(varyingReplaceDeclarator);
root->insertStatement(0, varyingReplaceDecl);
// Copy from/to the temp variable
TIntermBlock *reassignBlock = new TIntermBlock;
TIntermSymbol *tempReplaceSymbol = new TIntermSymbol(tempReplaceVar);
TIntermSymbol *varyingReplaceSymbol = new TIntermSymbol(varyingReplaceVar);
bool isInput = IsVaryingIn(type.getQualifier());
for (unsigned int i = 0; i < type.getOutermostArraySize(); ++i)
{
TIntermBinary *tempMatrixIndexed =
new TIntermBinary(EOpIndexDirect, tempReplaceSymbol->deepCopy(), CreateIndexNode(i));
for (uint8_t col = 0; col < type.getCols(); ++col)
{
TIntermBinary *tempMatrixColIndexed = new TIntermBinary(
EOpIndexDirect, tempMatrixIndexed->deepCopy(), CreateIndexNode(col));
TIntermBinary *vectorIndexed =
new TIntermBinary(EOpIndexDirect, varyingReplaceSymbol->deepCopy(),
CreateIndexNode(i * type.getCols() + col));
TIntermBinary *assignment;
if (isInput)
{
assignment = new TIntermBinary(EOpAssign, tempMatrixColIndexed, vectorIndexed);
}
else
{
assignment = new TIntermBinary(EOpAssign, vectorIndexed, tempMatrixColIndexed);
}
reassignBlock->appendStatement(assignment);
}
}
if (isInput)
{
TIntermFunctionDefinition *main = FindMain(root);
main->getBody()->insertStatement(0, reassignBlock);
return compiler->validateAST(root);
}
else
{
return RunAtTheEndOfShader(compiler, root, reassignBlock, symbolTable);
}
}
[[nodiscard]] bool ReplaceArrayOfMatrixVaryings(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable)
{
std::vector<const TVariable *> arrayOfMatrixVars;
CollectVaryingTraverser varCollector(&arrayOfMatrixVars);
root->traverse(&varCollector);
for (const TVariable *var : arrayOfMatrixVars)
{
if (!ReplaceArrayOfMatrixVarying(compiler, root, symbolTable, var))
{
return false;
}
}
return true;
}
} // namespace sh