Commit ac8e1196 by Stephen White Committed by Commit Bot

SSBO handling rewrite.

The basic idea is to replace the current SSBO output traversal by build a new AST for the Load and Store subtrees, then traverse that AST with the regular OutputHLSL traversal. This way, all the paren balancing and state management can go away. BUG: angleproject:5734 Change-Id: I14d2fecd724d7419fbc9315fad4e9202a741b03f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2773401 Commit-Queue: Stephen White <senorblanco@chromium.org> Reviewed-by: 's avatarJiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 525fde75
...@@ -387,8 +387,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, ...@@ -387,8 +387,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
// Reserve registers for the default uniform block and driver constants // Reserve registers for the default uniform block and driver constants
mResourcesHLSL->reserveUniformBlockRegisters(2); mResourcesHLSL->reserveUniformBlockRegisters(2);
mSSBOOutputHLSL = mSSBOOutputHLSL = new ShaderStorageBlockOutputHLSL(this, mResourcesHLSL, shaderStorageBlocks);
new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL, shaderStorageBlocks);
} }
OutputHLSL::~OutputHLSL() OutputHLSL::~OutputHLSL()
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "compiler/translator/ResourcesHLSL.h" #include "compiler/translator/ResourcesHLSL.h"
#include "compiler/translator/blocklayoutHLSL.h" #include "compiler/translator/blocklayoutHLSL.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/util.h" #include "compiler/translator/util.h"
namespace sh namespace sh
...@@ -288,30 +289,23 @@ void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock, ...@@ -288,30 +289,23 @@ void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock,
TraverseShaderVariables(block->fields, false, &visitor); TraverseShaderVariables(block->fields, false, &visitor);
} }
bool IsInArrayOfArraysChain(TIntermTyped *node) TIntermTyped *Mul(TIntermTyped *left, TIntermTyped *right)
{ {
if (node->getType().isArrayOfArrays()) return left && right ? new TIntermBinary(EOpMul, left, right) : nullptr;
return true; }
TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode)
{
if (binaryNode->getLeft()->getType().isArrayOfArrays())
return true;
}
return false; TIntermTyped *Add(TIntermTyped *left, TIntermTyped *right)
{
return left ? right ? new TIntermBinary(EOpAdd, left, right) : left : right;
} }
} // anonymous namespace } // anonymous namespace
ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL( ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL(
OutputHLSL *outputHLSL, OutputHLSL *outputHLSL,
TSymbolTable *symbolTable,
ResourcesHLSL *resourcesHLSL, ResourcesHLSL *resourcesHLSL,
const std::vector<InterfaceBlock> &shaderStorageBlocks) const std::vector<InterfaceBlock> &shaderStorageBlocks)
: TIntermTraverser(true, true, true, symbolTable), : mOutputHLSL(outputHLSL),
mMatrixStride(0),
mRowMajor(false),
mOutputHLSL(outputHLSL),
mResourcesHLSL(resourcesHLSL), mResourcesHLSL(resourcesHLSL),
mShaderStorageBlocks(shaderStorageBlocks) mShaderStorageBlocks(shaderStorageBlocks)
{ {
...@@ -325,20 +319,19 @@ ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL() ...@@ -325,20 +319,19 @@ ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL()
void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node) void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node)
{ {
mMethodTypeStack.push(SSBOMethod::STORE);
traverseSSBOAccess(node, SSBOMethod::STORE); traverseSSBOAccess(node, SSBOMethod::STORE);
} }
void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node) void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
{ {
mMethodTypeStack.push(SSBOMethod::LOAD);
traverseSSBOAccess(node, SSBOMethod::LOAD); traverseSSBOAccess(node, SSBOMethod::LOAD);
mOutputHLSL->getInfoSink() << ")";
} }
void ShaderStorageBlockOutputHLSL::outputLengthFunctionCall(TIntermTyped *node) void ShaderStorageBlockOutputHLSL::outputLengthFunctionCall(TIntermTyped *node)
{ {
mMethodTypeStack.push(SSBOMethod::LENGTH);
traverseSSBOAccess(node, SSBOMethod::LENGTH); traverseSSBOAccess(node, SSBOMethod::LENGTH);
mOutputHLSL->getInfoSink() << ")";
} }
void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node, void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node,
...@@ -347,35 +340,27 @@ void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermT ...@@ -347,35 +340,27 @@ void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermT
switch (op) switch (op)
{ {
case EOpAtomicAdd: case EOpAtomicAdd:
mMethodTypeStack.push(SSBOMethod::ATOMIC_ADD);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_ADD); traverseSSBOAccess(node, SSBOMethod::ATOMIC_ADD);
break; break;
case EOpAtomicMin: case EOpAtomicMin:
mMethodTypeStack.push(SSBOMethod::ATOMIC_MIN);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_MIN); traverseSSBOAccess(node, SSBOMethod::ATOMIC_MIN);
break; break;
case EOpAtomicMax: case EOpAtomicMax:
mMethodTypeStack.push(SSBOMethod::ATOMIC_MAX);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_MAX); traverseSSBOAccess(node, SSBOMethod::ATOMIC_MAX);
break; break;
case EOpAtomicAnd: case EOpAtomicAnd:
mMethodTypeStack.push(SSBOMethod::ATOMIC_AND);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_AND); traverseSSBOAccess(node, SSBOMethod::ATOMIC_AND);
break; break;
case EOpAtomicOr: case EOpAtomicOr:
mMethodTypeStack.push(SSBOMethod::ATOMIC_OR);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_OR); traverseSSBOAccess(node, SSBOMethod::ATOMIC_OR);
break; break;
case EOpAtomicXor: case EOpAtomicXor:
mMethodTypeStack.push(SSBOMethod::ATOMIC_XOR);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_XOR); traverseSSBOAccess(node, SSBOMethod::ATOMIC_XOR);
break; break;
case EOpAtomicExchange: case EOpAtomicExchange:
mMethodTypeStack.push(SSBOMethod::ATOMIC_EXCHANGE);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_EXCHANGE); traverseSSBOAccess(node, SSBOMethod::ATOMIC_EXCHANGE);
break; break;
case EOpAtomicCompSwap: case EOpAtomicCompSwap:
mMethodTypeStack.push(SSBOMethod::ATOMIC_COMPSWAP);
traverseSSBOAccess(node, SSBOMethod::ATOMIC_COMPSWAP); traverseSSBOAccess(node, SSBOMethod::ATOMIC_COMPSWAP);
break; break;
default: default:
...@@ -387,15 +372,15 @@ void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermT ...@@ -387,15 +372,15 @@ void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermT
// Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL. // Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL.
// It's because that if the current node's type is a vector which comes from a matrix, we will // It's because that if the current node's type is a vector which comes from a matrix, we will
// lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL. // lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL.
void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node, int ShaderStorageBlockOutputHLSL::getMatrixStride(TIntermTyped *node,
TLayoutBlockStorage storage, TLayoutBlockStorage storage,
bool rowMajor) bool rowMajor,
bool *isRowMajorMatrix) const
{ {
if (node->getType().isMatrix()) if (node->getType().isMatrix())
{ {
mMatrixStride = GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride; *isRowMajorMatrix = rowMajor;
mRowMajor = rowMajor; return GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride;
return;
} }
if (node->getType().isVector()) if (node->getType().isVector())
...@@ -403,17 +388,19 @@ void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node, ...@@ -403,17 +388,19 @@ void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node,
TIntermBinary *binaryNode = node->getAsBinaryNode(); TIntermBinary *binaryNode = node->getAsBinaryNode();
if (binaryNode) if (binaryNode)
{ {
return setMatrixStride(binaryNode->getLeft(), storage, rowMajor); return getMatrixStride(binaryNode->getLeft(), storage, rowMajor, isRowMajorMatrix);
} }
else else
{ {
TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
if (swizzleNode) if (swizzleNode)
{ {
return setMatrixStride(swizzleNode->getOperand(), storage, rowMajor); return getMatrixStride(swizzleNode->getOperand(), storage, rowMajor,
isRowMajorMatrix);
} }
} }
} }
return 0;
} }
void ShaderStorageBlockOutputHLSL::collectShaderStorageBlocks(TIntermTyped *node) void ShaderStorageBlockOutputHLSL::collectShaderStorageBlocks(TIntermTyped *node)
...@@ -465,8 +452,6 @@ void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMe ...@@ -465,8 +452,6 @@ void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMe
{ {
// TODO: Merge collectShaderStorageBlocks and GetBlockLayoutInfo to simplify the code. // TODO: Merge collectShaderStorageBlocks and GetBlockLayoutInfo to simplify the code.
collectShaderStorageBlocks(node); collectShaderStorageBlocks(node);
mMatrixStride = 0;
mRowMajor = false;
// Note that we don't have correct BlockMemberInfo from mBlockMemberInfoMap at the current // Note that we don't have correct BlockMemberInfo from mBlockMemberInfoMap at the current
// point. But we must use those information to generate the right function name. So here we have // point. But we must use those information to generate the right function name. So here we have
...@@ -503,15 +488,19 @@ void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMe ...@@ -503,15 +488,19 @@ void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMe
unsizedArrayStride = fieldInfoIter->second.arrayStride; unsizedArrayStride = fieldInfoIter->second.arrayStride;
} }
} }
setMatrixStride(node, storage, rowMajor); bool isRowMajorMatrix = false;
int matrixStride = getMatrixStride(node, storage, rowMajor, &isRowMajorMatrix);
const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction( const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction(
node->getType(), method, storage, mRowMajor, mMatrixStride, unsizedArrayStride, node->getType(), method, storage, isRowMajorMatrix, matrixStride, unsizedArrayStride,
node->getAsSwizzleNode()); node->getAsSwizzleNode());
TInfoSinkBase &out = mOutputHLSL->getInfoSink(); TInfoSinkBase &out = mOutputHLSL->getInfoSink();
out << functionName; out << functionName;
out << "("; out << "(";
node->traverse(this); BlockMemberInfo blockMemberInfo;
TIntermNode *loc = traverseNode(out, node, &blockMemberInfo);
out << ", ";
loc->traverse(mOutputHLSL);
} }
void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(TInfoSinkBase &out) const void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(TInfoSinkBase &out) const
...@@ -520,315 +509,144 @@ void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(TInfoSinkBase ...@@ -520,315 +509,144 @@ void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(TInfoSinkBase
mSSBOFunctionHLSL->shaderStorageBlockFunctionHeader(out); mSSBOFunctionHLSL->shaderStorageBlockFunctionHeader(out);
} }
// Check if the current node is the end of the SSBO access chain. If true, we should output ')' for TIntermTyped *ShaderStorageBlockOutputHLSL::traverseNode(TInfoSinkBase &out,
// Load method. TIntermTyped *node,
bool ShaderStorageBlockOutputHLSL::isEndOfSSBOAccessChain() BlockMemberInfo *blockMemberInfo)
{ {
TIntermNode *parent = getParentNode(); if (TIntermSymbol *symbolNode = node->getAsSymbolNode())
if (parent)
{ {
TIntermBinary *parentBinary = parent->getAsBinaryNode(); const TVariable &variable = symbolNode->variable();
if (parentBinary != nullptr) const TType &type = variable.getType();
{ if (type.isInterfaceBlock())
switch (parentBinary->getOp())
{
case EOpIndexDirectStruct:
case EOpIndexDirect:
case EOpIndexIndirect:
{
return false;
}
default:
return true;
}
}
const TIntermSwizzle *parentSwizzle = parent->getAsSwizzleNode();
if (parentSwizzle)
{
return false;
}
}
return true;
}
void ShaderStorageBlockOutputHLSL::visitSymbol(TIntermSymbol *node)
{
TInfoSinkBase &out = mOutputHLSL->getInfoSink();
const TVariable &variable = node->variable();
TQualifier qualifier = variable.getType().getQualifier();
if (qualifier == EvqBuffer)
{
const TType &variableType = variable.getType();
const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
ASSERT(interfaceBlock);
if (variableType.isInterfaceBlock())
{ {
out << DecorateVariableIfNeeded(variable); out << DecorateVariableIfNeeded(variable);
} }
else else
{ {
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
out << Decorate(interfaceBlock->name()); out << Decorate(interfaceBlock->name());
out << ", ";
const TField *field = const TField *field =
GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name()); GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name());
writeDotOperatorOutput(out, field); return createFieldOffset(field, blockMemberInfo);
} }
} }
else else if (TIntermSwizzle *swizzleNode = node->getAsSwizzleNode())
{ {
return mOutputHLSL->visitSymbol(node); return traverseNode(out, swizzleNode->getOperand(), blockMemberInfo);
} }
} else if (TIntermBinary *binaryNode = node->getAsBinaryNode())
void ShaderStorageBlockOutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
{
mOutputHLSL->visitConstantUnion(node);
}
bool ShaderStorageBlockOutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
{
return mOutputHLSL->visitAggregate(visit, node);
}
bool ShaderStorageBlockOutputHLSL::visitTernary(Visit visit, TIntermTernary *node)
{
return mOutputHLSL->visitTernary(visit, node);
}
bool ShaderStorageBlockOutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
{
return mOutputHLSL->visitUnary(visit, node);
}
bool ShaderStorageBlockOutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node)
{
if (visit == PostVisit)
{
if (!IsInShaderStorageBlock(node))
{
return mOutputHLSL->visitSwizzle(visit, node);
}
TInfoSinkBase &out = mOutputHLSL->getInfoSink();
// TODO(jiajia.qin@intel.com): add swizzle process if the swizzle node is not the last node
// of ssbo access chain. Such as, data.xy[0]
if (isEndOfSSBOAccessChain())
{
ASSERT(!mMethodTypeStack.empty());
SSBOMethod curMethod = mMethodTypeStack.top();
if (curMethod == SSBOMethod::LENGTH || curMethod == SSBOMethod::LOAD)
{
out << ")";
}
mMethodTypeStack.pop();
}
}
return true;
}
bool ShaderStorageBlockOutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{
TInfoSinkBase &out = mOutputHLSL->getInfoSink();
switch (node->getOp())
{ {
case EOpIndexDirect: switch (binaryNode->getOp())
{ {
if (!IsInShaderStorageBlock(node->getLeft())) case EOpIndexDirect:
{
return mOutputHLSL->visitBinary(visit, node);
}
const TType &leftType = node->getLeft()->getType();
if (leftType.isInterfaceBlock())
{ {
if (visit == PreVisit) const TType &leftType = binaryNode->getLeft()->getType();
if (leftType.isInterfaceBlock())
{ {
ASSERT(leftType.getQualifier() == EvqBuffer); ASSERT(leftType.getQualifier() == EvqBuffer);
TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode(); TIntermSymbol *instanceArraySymbol = binaryNode->getLeft()->getAsSymbolNode();
const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0); const int arrayIndex =
binaryNode->getRight()->getAsConstantUnion()->getIConst(0);
out << mResourcesHLSL->InterfaceBlockInstanceString( out << mResourcesHLSL->InterfaceBlockInstanceString(
instanceArraySymbol->getName(), arrayIndex); instanceArraySymbol->getName(), arrayIndex);
return false;
} }
else
{
return writeEOpIndexDirectOrIndirectOutput(out, binaryNode, blockMemberInfo);
}
break;
} }
else case EOpIndexIndirect:
{
writeEOpIndexDirectOrIndirectOutput(out, visit, node);
}
break;
}
case EOpIndexIndirect:
{
if (!IsInShaderStorageBlock(node->getLeft()))
{
return mOutputHLSL->visitBinary(visit, node);
}
// We do not currently support indirect references to interface blocks
ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock);
writeEOpIndexDirectOrIndirectOutput(out, visit, node);
break;
}
case EOpIndexDirectStruct:
{
if (!IsInShaderStorageBlock(node->getLeft()))
{ {
return mOutputHLSL->visitBinary(visit, node); // We do not currently support indirect references to interface blocks
ASSERT(binaryNode->getLeft()->getBasicType() != EbtInterfaceBlock);
return writeEOpIndexDirectOrIndirectOutput(out, binaryNode, blockMemberInfo);
break;
} }
case EOpIndexDirectStruct:
if (visit == InVisit)
{ {
ASSERT(IsInShaderStorageBlock(node->getLeft())); // We do not currently support direct references to interface blocks
const TStructure *structure = node->getLeft()->getType().getStruct(); ASSERT(binaryNode->getLeft()->getBasicType() != EbtInterfaceBlock);
const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); TIntermTyped *left = traverseNode(out, binaryNode->getLeft(), blockMemberInfo);
const TStructure *structure = binaryNode->getLeft()->getType().getStruct();
const TIntermConstantUnion *index = binaryNode->getRight()->getAsConstantUnion();
const TField *field = structure->fields()[index->getIConst(0)]; const TField *field = structure->fields()[index->getIConst(0)];
out << " + "; return Add(createFieldOffset(field, blockMemberInfo), left);
writeDotOperatorOutput(out, field); break;
return false;
}
break;
}
case EOpIndexDirectInterfaceBlock:
if (!IsInShaderStorageBlock(node->getLeft()))
{
return mOutputHLSL->visitBinary(visit, node);
} }
case EOpIndexDirectInterfaceBlock:
if (visit == InVisit)
{ {
ASSERT(IsInShaderStorageBlock(node->getLeft())); ASSERT(IsInShaderStorageBlock(binaryNode->getLeft()));
out << ", "; traverseNode(out, binaryNode->getLeft(), blockMemberInfo);
const TInterfaceBlock *interfaceBlock = const TInterfaceBlock *interfaceBlock =
node->getLeft()->getType().getInterfaceBlock(); binaryNode->getLeft()->getType().getInterfaceBlock();
const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TIntermConstantUnion *index = binaryNode->getRight()->getAsConstantUnion();
const TField *field = interfaceBlock->fields()[index->getIConst(0)]; const TField *field = interfaceBlock->fields()[index->getIConst(0)];
writeDotOperatorOutput(out, field); return createFieldOffset(field, blockMemberInfo);
return false; break;
} }
break; default:
default: return nullptr;
// It may have other operators in EOpIndexIndirect. Such as buffer.attribs[(y * gridSize }
// + x) * 6u + 0u]
return mOutputHLSL->visitBinary(visit, node);
} }
return nullptr;
return true;
} }
void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out, TIntermTyped *ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(
Visit visit, TInfoSinkBase &out,
TIntermBinary *node) TIntermBinary *node,
BlockMemberInfo *blockMemberInfo)
{ {
ASSERT(IsInShaderStorageBlock(node->getLeft())); ASSERT(IsInShaderStorageBlock(node->getLeft()));
if (visit == InVisit) TIntermTyped *left = traverseNode(out, node->getLeft(), blockMemberInfo);
TIntermTyped *right = node->getRight()->deepCopy();
const TType &type = node->getLeft()->getType();
TLayoutBlockStorage storage;
bool rowMajor;
GetBlockLayoutInfo(node, false, &storage, &rowMajor);
if (type.isArray())
{ {
const TType &type = node->getLeft()->getType(); const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
// For array of arrays, we calculate the offset using the formula below: for (unsigned int i = 0; i < arraySizes.size() - 1; i++)
// elementStride * (a3 * a2 * a1 * i0 + a3 * a2 * i1 + a3 * i2 + i3)
// Note: assume that there are 4 dimensions.
// a0, a1, a2, a3 is the size of the array in each dimension. (S s[a0][a1][a2][a3])
// i0, i1, i2, i3 is the index of the array in each dimension. (s[i0][i1][i2][i3])
if (IsInArrayOfArraysChain(node->getLeft()))
{ {
if (type.isArrayOfArrays()) right = Mul(CreateUIntNode(arraySizes[i]), right);
{ }
const TSpan<const unsigned int> &arraySizes = type.getArraySizes(); right = Mul(CreateUIntNode(blockMemberInfo->arrayStride), right);
// Don't need to concern the tail comma which will be used to multiply the index. }
for (unsigned int i = 0; i < (arraySizes.size() - 1); i++) else if (type.isMatrix())
{ {
out << arraySizes[i]; if (rowMajor)
out << " * "; {
} right = Mul(CreateUIntNode(BlockLayoutEncoder::kBytesPerComponent), right);
}
} }
else else
{ {
if (node->getType().isVector() && type.isMatrix()) right = Mul(CreateUIntNode(blockMemberInfo->matrixStride), right);
{
if (mRowMajor)
{
out << " + " << str(BlockLayoutEncoder::kBytesPerComponent);
}
else
{
out << " + " << str(mMatrixStride);
}
}
else if (node->getType().isScalar() && !type.isArray())
{
if (mRowMajor)
{
out << " + " << str(mMatrixStride);
}
else
{
out << " + " << str(BlockLayoutEncoder::kBytesPerComponent);
}
}
out << " * ";
} }
} }
else if (visit == PostVisit) else if (type.isVector())
{ {
// This is used to output the '+' in the array of arrays formula in above. if (blockMemberInfo->isRowMajorMatrix)
if (node->getType().isArray() && !isEndOfSSBOAccessChain())
{
out << " + ";
}
// This corresponds to '(' in writeDotOperatorOutput when fieldType.isArrayOfArrays() is
// true.
if (IsInArrayOfArraysChain(node->getLeft()) && !node->getType().isArray())
{ {
out << ")"; right = Mul(CreateUIntNode(blockMemberInfo->matrixStride), right);
} }
if (isEndOfSSBOAccessChain()) else
{ {
ASSERT(!mMethodTypeStack.empty()); right = Mul(CreateUIntNode(BlockLayoutEncoder::kBytesPerComponent), right);
SSBOMethod curMethod = mMethodTypeStack.top();
if (curMethod == SSBOMethod::LENGTH || curMethod == SSBOMethod::LOAD)
{
out << ")";
}
mMethodTypeStack.pop();
} }
} }
return Add(left, right);
} }
void ShaderStorageBlockOutputHLSL::writeDotOperatorOutput(TInfoSinkBase &out, const TField *field) TIntermTyped *ShaderStorageBlockOutputHLSL::createFieldOffset(const TField *field,
BlockMemberInfo *blockMemberInfo)
{ {
auto fieldInfoIter = mBlockMemberInfoMap.find(field); auto fieldInfoIter = mBlockMemberInfoMap.find(field);
ASSERT(fieldInfoIter != mBlockMemberInfoMap.end()); ASSERT(fieldInfoIter != mBlockMemberInfoMap.end());
const BlockMemberInfo &memberInfo = fieldInfoIter->second; *blockMemberInfo = fieldInfoIter->second;
mMatrixStride = memberInfo.matrixStride; return CreateUIntNode(blockMemberInfo->offset);
mRowMajor = memberInfo.isRowMajorMatrix;
out << memberInfo.offset;
const TType &fieldType = *field->type();
if (fieldType.isArray() && !isEndOfSSBOAccessChain())
{
out << " + ";
out << memberInfo.arrayStride;
if (fieldType.isArrayOfArrays())
{
out << " * (";
}
}
if (isEndOfSSBOAccessChain())
{
ASSERT(!mMethodTypeStack.empty());
SSBOMethod curMethod = mMethodTypeStack.top();
if (curMethod == SSBOMethod::LENGTH || curMethod == SSBOMethod::LOAD)
{
out << ")";
}
mMethodTypeStack.pop();
}
} }
} // namespace sh } // namespace sh
...@@ -10,10 +10,9 @@ ...@@ -10,10 +10,9 @@
#ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_ #ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
#define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_ #define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_
#include <stack> #include "compiler/translator/IntermNode.h"
#include "compiler/translator/ShaderStorageBlockFunctionHLSL.h" #include "compiler/translator/ShaderStorageBlockFunctionHLSL.h"
#include "compiler/translator/blocklayout.h" #include "compiler/translator/blocklayout.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh namespace sh
{ {
...@@ -37,15 +36,14 @@ using BlockMemberInfoMap = std::map<const TField *, BlockMemberInfo>; ...@@ -37,15 +36,14 @@ using BlockMemberInfoMap = std::map<const TField *, BlockMemberInfo>;
using ShaderVarToFieldMap = std::map<std::string, const TField *>; using ShaderVarToFieldMap = std::map<std::string, const TField *>;
class ShaderStorageBlockOutputHLSL : public TIntermTraverser class ShaderStorageBlockOutputHLSL
{ {
public: public:
ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLSL, ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLSL,
TSymbolTable *symbolTable,
ResourcesHLSL *resourcesHLSL, ResourcesHLSL *resourcesHLSL,
const std::vector<InterfaceBlock> &shaderStorageBlocks); const std::vector<InterfaceBlock> &shaderStorageBlocks);
~ShaderStorageBlockOutputHLSL() override; ~ShaderStorageBlockOutputHLSL();
// This writes part of the function call to store a value to a SSBO to the output stream. After // This writes part of the function call to store a value to a SSBO to the output stream. After
// calling this, ", <stored value>)" should be written to the output stream to complete the // calling this, ", <stored value>)" should be written to the output stream to complete the
...@@ -60,27 +58,21 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser ...@@ -60,27 +58,21 @@ class ShaderStorageBlockOutputHLSL : public TIntermTraverser
void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const; void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const;
protected:
void visitSymbol(TIntermSymbol *) override;
void visitConstantUnion(TIntermConstantUnion *) override;
bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
bool visitBinary(Visit visit, TIntermBinary *) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitTernary(Visit visit, TIntermTernary *) override;
bool visitUnary(Visit visit, TIntermUnary *) override;
private: private:
void traverseSSBOAccess(TIntermTyped *node, SSBOMethod method); void traverseSSBOAccess(TIntermTyped *node, SSBOMethod method);
void setMatrixStride(TIntermTyped *node, TLayoutBlockStorage storage, bool rowMajor); TIntermTyped *traverseNode(TInfoSinkBase &out,
bool isEndOfSSBOAccessChain(); TIntermTyped *node,
void writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out, Visit visit, TIntermBinary *node); BlockMemberInfo *blockMemberInfo);
int getMatrixStride(TIntermTyped *node,
TLayoutBlockStorage storage,
bool rowMajor,
bool *isRowMajor) const;
TIntermTyped *writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out,
TIntermBinary *node,
BlockMemberInfo *blockMemberInfo);
// Common part in dot operations. // Common part in dot operations.
void writeDotOperatorOutput(TInfoSinkBase &out, const TField *field); TIntermTyped *createFieldOffset(const TField *field, BlockMemberInfo *blockMemberInfo);
void collectShaderStorageBlocks(TIntermTyped *node); void collectShaderStorageBlocks(TIntermTyped *node);
int mMatrixStride;
bool mRowMajor;
std::stack<SSBOMethod> mMethodTypeStack;
OutputHLSL *mOutputHLSL; OutputHLSL *mOutputHLSL;
ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL; ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL;
ResourcesHLSL *mResourcesHLSL; ResourcesHLSL *mResourcesHLSL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment