summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp667
1 files changed, 667 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp
new file mode 100644
index 0000000000..2ff01e439e
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp
@@ -0,0 +1,667 @@
+//
+// Copyright 2018 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.
+//
+// ShaderStorageBlockOutputHLSL: A traverser to translate a ssbo_access_chain to an offset of
+// RWByteAddressBuffer.
+// //EOpIndexDirectInterfaceBlock
+// ssbo_variable :=
+// | the name of the SSBO
+// | the name of a variable in an SSBO backed interface block
+
+// // EOpIndexInDirect
+// // EOpIndexDirect
+// ssbo_array_indexing := ssbo_access_chain[expr_no_ssbo]
+
+// // EOpIndexDirectStruct
+// ssbo_structure_access := ssbo_access_chain.identifier
+
+// ssbo_access_chain :=
+// | ssbo_variable
+// | ssbo_array_indexing
+// | ssbo_structure_access
+//
+
+#include "compiler/translator/ShaderStorageBlockOutputHLSL.h"
+
+#include "compiler/translator/ResourcesHLSL.h"
+#include "compiler/translator/blocklayoutHLSL.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const char kShaderStorageDeclarationString[] =
+ "// @@ SHADER STORAGE DECLARATION STRING @@";
+
+void GetBlockLayoutInfo(TIntermTyped *node,
+ bool rowMajorAlreadyAssigned,
+ TLayoutBlockStorage *storage,
+ bool *rowMajor)
+{
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ return GetBlockLayoutInfo(swizzleNode->getOperand(), rowMajorAlreadyAssigned, storage,
+ rowMajor);
+ }
+
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirectInterfaceBlock:
+ {
+ // The column_major/row_major qualifier of a field member overrides the interface
+ // block's row_major/column_major. So we can assign rowMajor here and don't need to
+ // assign it again. But we still need to call recursively to get the storage's
+ // value.
+ const TType &type = node->getType();
+ *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
+ return GetBlockLayoutInfo(binaryNode->getLeft(), true, storage, rowMajor);
+ }
+ case EOpIndexIndirect:
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ return GetBlockLayoutInfo(binaryNode->getLeft(), rowMajorAlreadyAssigned, storage,
+ rowMajor);
+ default:
+ UNREACHABLE();
+ return;
+ }
+ }
+
+ const TType &type = node->getType();
+ ASSERT(type.getQualifier() == EvqBuffer);
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ ASSERT(interfaceBlock);
+ *storage = interfaceBlock->blockStorage();
+ // If the block doesn't have an instance name, rowMajorAlreadyAssigned will be false. In
+ // this situation, we still need to set rowMajor's value.
+ if (!rowMajorAlreadyAssigned)
+ {
+ *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
+ }
+}
+
+// It's possible that the current type has lost the original layout information. So we should pass
+// the right layout information to GetBlockMemberInfoByType.
+const BlockMemberInfo GetBlockMemberInfoByType(const TType &type,
+ TLayoutBlockStorage storage,
+ bool rowMajor)
+{
+ sh::Std140BlockEncoder std140Encoder;
+ sh::Std430BlockEncoder std430Encoder;
+ sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
+ sh::BlockLayoutEncoder *encoder = nullptr;
+
+ if (storage == EbsStd140)
+ {
+ encoder = &std140Encoder;
+ }
+ else if (storage == EbsStd430)
+ {
+ encoder = &std430Encoder;
+ }
+ else
+ {
+ encoder = &hlslEncoder;
+ }
+
+ std::vector<unsigned int> arraySizes;
+ const TSpan<const unsigned int> &typeArraySizes = type.getArraySizes();
+ if (!typeArraySizes.empty())
+ {
+ arraySizes.assign(typeArraySizes.begin(), typeArraySizes.end());
+ }
+ return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
+}
+
+const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock,
+ const ImmutableString &variableName)
+{
+ for (const TField *field : interfaceBlock->fields())
+ {
+ if (field->name() == variableName)
+ {
+ return field;
+ }
+ }
+ return nullptr;
+}
+
+const InterfaceBlock *FindInterfaceBlock(const TInterfaceBlock *needle,
+ const std::vector<InterfaceBlock> &haystack)
+{
+ for (const InterfaceBlock &block : haystack)
+ {
+ if (strcmp(block.name.c_str(), needle->name().data()) == 0)
+ {
+ ASSERT(block.fields.size() == needle->fields().size());
+ return &block;
+ }
+ }
+
+ UNREACHABLE();
+ return nullptr;
+}
+
+std::string StripArrayIndices(const std::string &nameIn)
+{
+ std::string name = nameIn;
+ size_t pos = name.find('[');
+ while (pos != std::string::npos)
+ {
+ size_t closePos = name.find(']', pos);
+ ASSERT(closePos != std::string::npos);
+ name.erase(pos, closePos - pos + 1);
+ pos = name.find('[', pos);
+ }
+ ASSERT(name.find(']') == std::string::npos);
+ return name;
+}
+
+// Does not include any array indices.
+void MapVariableToField(const ShaderVariable &variable,
+ const TField *field,
+ std::string currentName,
+ ShaderVarToFieldMap *shaderVarToFieldMap)
+{
+ ASSERT((field->type()->getStruct() == nullptr) == variable.fields.empty());
+ (*shaderVarToFieldMap)[currentName] = field;
+
+ if (!variable.fields.empty())
+ {
+ const TStructure *subStruct = field->type()->getStruct();
+ ASSERT(variable.fields.size() == subStruct->fields().size());
+
+ for (size_t index = 0; index < variable.fields.size(); ++index)
+ {
+ const TField *subField = subStruct->fields()[index];
+ const ShaderVariable &subVariable = variable.fields[index];
+ std::string subName = currentName + "." + subVariable.name;
+ MapVariableToField(subVariable, subField, subName, shaderVarToFieldMap);
+ }
+ }
+}
+
+class BlockInfoVisitor final : public BlockEncoderVisitor
+{
+ public:
+ BlockInfoVisitor(const std::string &prefix,
+ TLayoutBlockStorage storage,
+ const ShaderVarToFieldMap &shaderVarToFieldMap,
+ BlockMemberInfoMap *blockInfoOut)
+ : BlockEncoderVisitor(prefix, "", getEncoder(storage)),
+ mShaderVarToFieldMap(shaderVarToFieldMap),
+ mBlockInfoOut(blockInfoOut),
+ mHLSLEncoder(HLSLBlockEncoder::ENCODE_PACKED, false),
+ mStorage(storage)
+ {}
+
+ BlockLayoutEncoder *getEncoder(TLayoutBlockStorage storage)
+ {
+ switch (storage)
+ {
+ case EbsStd140:
+ return &mStd140Encoder;
+ case EbsStd430:
+ return &mStd430Encoder;
+ default:
+ return &mHLSLEncoder;
+ }
+ }
+
+ void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override
+ {
+ BlockEncoderVisitor::enterStructAccess(structVar, isRowMajor);
+
+ std::string variableName = StripArrayIndices(collapseNameStack());
+
+ // Remove the trailing "."
+ variableName.pop_back();
+
+ BlockInfoVisitor childVisitor(variableName, mStorage, mShaderVarToFieldMap, mBlockInfoOut);
+ childVisitor.getEncoder(mStorage)->enterAggregateType(structVar);
+ TraverseShaderVariables(structVar.fields, isRowMajor, &childVisitor);
+ childVisitor.getEncoder(mStorage)->exitAggregateType(structVar);
+
+ int offset = static_cast<int>(getEncoder(mStorage)->getCurrentOffset());
+ int arrayStride = static_cast<int>(childVisitor.getEncoder(mStorage)->getCurrentOffset());
+
+ auto iter = mShaderVarToFieldMap.find(variableName);
+ if (iter == mShaderVarToFieldMap.end())
+ return;
+
+ const TField *structField = iter->second;
+ if (mBlockInfoOut->count(structField) == 0)
+ {
+ mBlockInfoOut->emplace(structField, BlockMemberInfo(offset, arrayStride, -1, false));
+ }
+ }
+
+ void encodeVariable(const ShaderVariable &variable,
+ const BlockMemberInfo &variableInfo,
+ const std::string &name,
+ const std::string &mappedName) override
+ {
+ auto iter = mShaderVarToFieldMap.find(StripArrayIndices(name));
+ if (iter == mShaderVarToFieldMap.end())
+ return;
+
+ const TField *field = iter->second;
+ if (mBlockInfoOut->count(field) == 0)
+ {
+ mBlockInfoOut->emplace(field, variableInfo);
+ }
+ }
+
+ private:
+ const ShaderVarToFieldMap &mShaderVarToFieldMap;
+ BlockMemberInfoMap *mBlockInfoOut;
+ Std140BlockEncoder mStd140Encoder;
+ Std430BlockEncoder mStd430Encoder;
+ HLSLBlockEncoder mHLSLEncoder;
+ TLayoutBlockStorage mStorage;
+};
+
+void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock,
+ const std::vector<InterfaceBlock> &shaderStorageBlocks,
+ BlockMemberInfoMap *blockInfoOut)
+{
+ // Find the sh::InterfaceBlock.
+ const InterfaceBlock *block = FindInterfaceBlock(interfaceBlock, shaderStorageBlocks);
+ ASSERT(block);
+
+ // Map ShaderVariable to TField.
+ ShaderVarToFieldMap shaderVarToFieldMap;
+ for (size_t index = 0; index < block->fields.size(); ++index)
+ {
+ const TField *field = interfaceBlock->fields()[index];
+ const ShaderVariable &variable = block->fields[index];
+ MapVariableToField(variable, field, variable.name, &shaderVarToFieldMap);
+ }
+
+ BlockInfoVisitor visitor("", interfaceBlock->blockStorage(), shaderVarToFieldMap, blockInfoOut);
+ TraverseShaderVariables(block->fields, false, &visitor);
+}
+
+TIntermTyped *Mul(TIntermTyped *left, TIntermTyped *right)
+{
+ return left && right ? new TIntermBinary(EOpMul, left, right) : nullptr;
+}
+
+TIntermTyped *Add(TIntermTyped *left, TIntermTyped *right)
+{
+ return left ? right ? new TIntermBinary(EOpAdd, left, right) : left : right;
+}
+
+} // anonymous namespace
+
+ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL(
+ OutputHLSL *outputHLSL,
+ ResourcesHLSL *resourcesHLSL,
+ const std::vector<InterfaceBlock> &shaderStorageBlocks)
+ : mOutputHLSL(outputHLSL),
+ mResourcesHLSL(resourcesHLSL),
+ mShaderStorageBlocks(shaderStorageBlocks)
+{
+ mSSBOFunctionHLSL = new ShaderStorageBlockFunctionHLSL;
+}
+
+ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL()
+{
+ SafeDelete(mSSBOFunctionHLSL);
+}
+
+void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node)
+{
+ traverseSSBOAccess(node, SSBOMethod::STORE);
+}
+
+void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node)
+{
+ traverseSSBOAccess(node, SSBOMethod::LOAD);
+ mOutputHLSL->getInfoSink() << ")";
+}
+
+void ShaderStorageBlockOutputHLSL::outputLengthFunctionCall(TIntermTyped *node)
+{
+ traverseSSBOAccess(node, SSBOMethod::LENGTH);
+ mOutputHLSL->getInfoSink() << ")";
+}
+
+void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node,
+ TOperator op)
+{
+ switch (op)
+ {
+ case EOpAtomicAdd:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_ADD);
+ break;
+ case EOpAtomicMin:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_MIN);
+ break;
+ case EOpAtomicMax:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_MAX);
+ break;
+ case EOpAtomicAnd:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_AND);
+ break;
+ case EOpAtomicOr:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_OR);
+ break;
+ case EOpAtomicXor:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_XOR);
+ break;
+ case EOpAtomicExchange:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_EXCHANGE);
+ break;
+ case EOpAtomicCompSwap:
+ traverseSSBOAccess(node, SSBOMethod::ATOMIC_COMPSWAP);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+// 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
+// lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL.
+int ShaderStorageBlockOutputHLSL::getMatrixStride(TIntermTyped *node,
+ TLayoutBlockStorage storage,
+ bool rowMajor,
+ bool *isRowMajorMatrix) const
+{
+ if (node->getType().isMatrix())
+ {
+ *isRowMajorMatrix = rowMajor;
+ return GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride;
+ }
+
+ if (node->getType().isVector())
+ {
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ return getMatrixStride(binaryNode->getLeft(), storage, rowMajor, isRowMajorMatrix);
+ }
+ else
+ {
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ return getMatrixStride(swizzleNode->getOperand(), storage, rowMajor,
+ isRowMajorMatrix);
+ }
+ }
+ }
+ return 0;
+}
+
+void ShaderStorageBlockOutputHLSL::collectShaderStorageBlocks(TIntermTyped *node)
+{
+ TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
+ if (swizzleNode)
+ {
+ return collectShaderStorageBlocks(swizzleNode->getOperand());
+ }
+
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirectInterfaceBlock:
+ case EOpIndexIndirect:
+ case EOpIndexDirect:
+ case EOpIndexDirectStruct:
+ return collectShaderStorageBlocks(binaryNode->getLeft());
+ default:
+ UNREACHABLE();
+ return;
+ }
+ }
+
+ const TIntermSymbol *symbolNode = node->getAsSymbolNode();
+ const TType &type = symbolNode->getType();
+ ASSERT(type.getQualifier() == EvqBuffer);
+ const TVariable &variable = symbolNode->variable();
+
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ ASSERT(interfaceBlock);
+ if (mReferencedShaderStorageBlocks.count(interfaceBlock->uniqueId().get()) == 0)
+ {
+ const TVariable *instanceVariable = nullptr;
+ if (type.isInterfaceBlock())
+ {
+ instanceVariable = &variable;
+ }
+ mReferencedShaderStorageBlocks[interfaceBlock->uniqueId().get()] =
+ new TReferencedBlock(interfaceBlock, instanceVariable);
+ GetShaderStorageBlockMembersInfo(interfaceBlock, mShaderStorageBlocks,
+ &mBlockMemberInfoMap);
+ }
+}
+
+void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method)
+{
+ // TODO: Merge collectShaderStorageBlocks and GetBlockLayoutInfo to simplify the code.
+ collectShaderStorageBlocks(node);
+
+ // 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
+ // to calculate them again.
+ TLayoutBlockStorage storage;
+ bool rowMajor;
+ GetBlockLayoutInfo(node, false, &storage, &rowMajor);
+ int unsizedArrayStride = 0;
+ if (node->getType().isUnsizedArray())
+ {
+ // The unsized array member must be the last member of a shader storage block.
+ TIntermBinary *binaryNode = node->getAsBinaryNode();
+ if (binaryNode)
+ {
+ const TInterfaceBlock *interfaceBlock =
+ binaryNode->getLeft()->getType().getInterfaceBlock();
+ ASSERT(interfaceBlock);
+ const TIntermConstantUnion *index = binaryNode->getRight()->getAsConstantUnion();
+ const TField *field = interfaceBlock->fields()[index->getIConst(0)];
+ auto fieldInfoIter = mBlockMemberInfoMap.find(field);
+ ASSERT(fieldInfoIter != mBlockMemberInfoMap.end());
+ unsizedArrayStride = fieldInfoIter->second.arrayStride;
+ }
+ else
+ {
+ const TIntermSymbol *symbolNode = node->getAsSymbolNode();
+ const TVariable &variable = symbolNode->variable();
+ const TInterfaceBlock *interfaceBlock = symbolNode->getType().getInterfaceBlock();
+ ASSERT(interfaceBlock);
+ const TField *field =
+ GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name());
+ auto fieldInfoIter = mBlockMemberInfoMap.find(field);
+ ASSERT(fieldInfoIter != mBlockMemberInfoMap.end());
+ unsizedArrayStride = fieldInfoIter->second.arrayStride;
+ }
+ }
+ bool isRowMajorMatrix = false;
+ int matrixStride = getMatrixStride(node, storage, rowMajor, &isRowMajorMatrix);
+
+ const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction(
+ node->getType(), method, storage, isRowMajorMatrix, matrixStride, unsizedArrayStride,
+ node->getAsSwizzleNode());
+ TInfoSinkBase &out = mOutputHLSL->getInfoSink();
+ out << functionName;
+ out << "(";
+ BlockMemberInfo blockMemberInfo;
+ TIntermNode *loc = traverseNode(out, node, &blockMemberInfo);
+ out << ", ";
+ loc->traverse(mOutputHLSL);
+}
+
+void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(GLenum shaderType,
+ TInfoSinkBase &out) const
+{
+ if (mReferencedShaderStorageBlocks.empty())
+ {
+ return;
+ }
+
+ mResourcesHLSL->allocateShaderStorageBlockRegisters(mReferencedShaderStorageBlocks);
+ out << "// Shader Storage Blocks\n\n";
+ if (shaderType == GL_COMPUTE_SHADER)
+ {
+ out << mResourcesHLSL->shaderStorageBlocksHeader(mReferencedShaderStorageBlocks);
+ }
+ else
+ {
+ out << kShaderStorageDeclarationString << "\n";
+ }
+ mSSBOFunctionHLSL->shaderStorageBlockFunctionHeader(out);
+}
+
+TIntermTyped *ShaderStorageBlockOutputHLSL::traverseNode(TInfoSinkBase &out,
+ TIntermTyped *node,
+ BlockMemberInfo *blockMemberInfo)
+{
+ if (TIntermSymbol *symbolNode = node->getAsSymbolNode())
+ {
+ const TVariable &variable = symbolNode->variable();
+ const TType &type = variable.getType();
+ if (type.isInterfaceBlock())
+ {
+ out << DecorateVariableIfNeeded(variable);
+ }
+ else
+ {
+ const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+ out << Decorate(interfaceBlock->name());
+ const TField *field =
+ GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name());
+ return createFieldOffset(field, blockMemberInfo);
+ }
+ }
+ else if (TIntermSwizzle *swizzleNode = node->getAsSwizzleNode())
+ {
+ return traverseNode(out, swizzleNode->getOperand(), blockMemberInfo);
+ }
+ else if (TIntermBinary *binaryNode = node->getAsBinaryNode())
+ {
+ switch (binaryNode->getOp())
+ {
+ case EOpIndexDirect:
+ {
+ const TType &leftType = binaryNode->getLeft()->getType();
+ if (leftType.isInterfaceBlock())
+ {
+ ASSERT(leftType.getQualifier() == EvqBuffer);
+ TIntermSymbol *instanceArraySymbol = binaryNode->getLeft()->getAsSymbolNode();
+
+ const int arrayIndex =
+ binaryNode->getRight()->getAsConstantUnion()->getIConst(0);
+ out << mResourcesHLSL->InterfaceBlockInstanceString(
+ instanceArraySymbol->getName(), arrayIndex);
+ }
+ else
+ {
+ return writeEOpIndexDirectOrIndirectOutput(out, binaryNode, blockMemberInfo);
+ }
+ break;
+ }
+ case EOpIndexIndirect:
+ {
+ // We do not currently support indirect references to interface blocks
+ ASSERT(binaryNode->getLeft()->getBasicType() != EbtInterfaceBlock);
+ return writeEOpIndexDirectOrIndirectOutput(out, binaryNode, blockMemberInfo);
+ }
+ case EOpIndexDirectStruct:
+ {
+ // We do not currently support direct references to interface blocks
+ ASSERT(binaryNode->getLeft()->getBasicType() != EbtInterfaceBlock);
+ 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)];
+ return Add(createFieldOffset(field, blockMemberInfo), left);
+ }
+ case EOpIndexDirectInterfaceBlock:
+ {
+ ASSERT(IsInShaderStorageBlock(binaryNode->getLeft()));
+ traverseNode(out, binaryNode->getLeft(), blockMemberInfo);
+ const TInterfaceBlock *interfaceBlock =
+ binaryNode->getLeft()->getType().getInterfaceBlock();
+ const TIntermConstantUnion *index = binaryNode->getRight()->getAsConstantUnion();
+ const TField *field = interfaceBlock->fields()[index->getIConst(0)];
+ return createFieldOffset(field, blockMemberInfo);
+ }
+ default:
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
+TIntermTyped *ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(
+ TInfoSinkBase &out,
+ TIntermBinary *node,
+ BlockMemberInfo *blockMemberInfo)
+{
+ ASSERT(IsInShaderStorageBlock(node->getLeft()));
+ 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 TSpan<const unsigned int> &arraySizes = type.getArraySizes();
+ for (unsigned int i = 0; i < arraySizes.size() - 1; i++)
+ {
+ right = Mul(CreateUIntNode(arraySizes[i]), right);
+ }
+ right = Mul(CreateUIntNode(blockMemberInfo->arrayStride), right);
+ }
+ else if (type.isMatrix())
+ {
+ if (rowMajor)
+ {
+ right = Mul(CreateUIntNode(BlockLayoutEncoder::kBytesPerComponent), right);
+ }
+ else
+ {
+ right = Mul(CreateUIntNode(blockMemberInfo->matrixStride), right);
+ }
+ }
+ else if (type.isVector())
+ {
+ if (blockMemberInfo->isRowMajorMatrix)
+ {
+ right = Mul(CreateUIntNode(blockMemberInfo->matrixStride), right);
+ }
+ else
+ {
+ right = Mul(CreateUIntNode(BlockLayoutEncoder::kBytesPerComponent), right);
+ }
+ }
+ return Add(left, right);
+}
+
+TIntermTyped *ShaderStorageBlockOutputHLSL::createFieldOffset(const TField *field,
+ BlockMemberInfo *blockMemberInfo)
+{
+ auto fieldInfoIter = mBlockMemberInfoMap.find(field);
+ ASSERT(fieldInfoIter != mBlockMemberInfoMap.end());
+ *blockMemberInfo = fieldInfoIter->second;
+ return CreateUIntNode(blockMemberInfo->offset);
+}
+
+} // namespace sh