From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../RecordUniformBlocksWithLargeArrayMember.cpp | 385 +++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.cpp (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.cpp') diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.cpp new file mode 100644 index 0000000000..18d49814ac --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.cpp @@ -0,0 +1,385 @@ +// +// 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. +// +// RecordUniformBlocksWithLargeArrayMember.h: +// Collect all uniform blocks which have one or more large array members, +// and the array sizes are greater than or equal to 50. If some of them +// satify some conditions, we will translate them to StructuredBuffers +// on Direct3D backend. +// + +#include "compiler/translator/tree_ops/d3d/RecordUniformBlocksWithLargeArrayMember.h" + +#include "compiler/translator/Compiler.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ +// Only when a uniform block member's array size is greater than or equal to +// kMinArraySizeUseStructuredBuffer, then we may translate the uniform block +// to a StructuredBuffer on Direct3D backend. +const unsigned int kMinArraySizeUseStructuredBuffer = 50u; + +// There is a maximum of D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT(128) slots that are +// available for shader resources on Direct3D 11. When shader version is 300, we only use +// D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT(16) slots for texture units. We allow StructuredBuffer +// to use the maximum of 60 slots, that is enough here. +const unsigned int kMaxAllowToUseRegisterCount = 60u; + +// Traverser that all uniform blocks which have one or more large array members, and the array +// sizes are greater than or equal to 50. +class UniformBlocksWithLargeArrayMemberTraverser : public TIntermTraverser +{ + public: + UniformBlocksWithLargeArrayMemberTraverser(); + + void visitSymbol(TIntermSymbol *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + std::map &getUniformBlockMayTranslation() + { + return mUniformBlockMayTranslation; + } + std::map &getUniformBlockNotAllowTranslation() + { + return mUniformBlockNotAllowTranslation; + } + std::map &getUniformBlockUsedRegisterCount() + { + return mUniformBlockUsedRegisterCount; + } + std::map &getUniformBlockWithLargeArrayMember() + { + return mUniformBlockWithLargeArrayMember; + } + + private: + std::map mUniformBlockMayTranslation; + std::map mUniformBlockNotAllowTranslation; + std::map mUniformBlockUsedRegisterCount; + std::map mUniformBlockWithLargeArrayMember; +}; + +UniformBlocksWithLargeArrayMemberTraverser::UniformBlocksWithLargeArrayMemberTraverser() + : TIntermTraverser(true, true, false) +{} + +static bool IsSupportedTypeForStructuredBuffer(const TType &type) +{ + const TStructure *structure = type.getStruct(); + const TLayoutMatrixPacking matrixPacking = type.getLayoutQualifier().matrixPacking; + if (structure) + { + const TFieldList &fields = structure->fields(); + for (size_t i = 0; i < fields.size(); i++) + { + const TType &fieldType = *fields[i]->type(); + // Do not allow the structure's member is array or structure. + if (!fieldType.isArray() && !fieldType.getStruct() && + (fieldType.isScalar() || fieldType.isVector() || + (fieldType.isMatrix() && + ((matrixPacking != EmpRowMajor && fieldType.getRows() == 4) || + (matrixPacking == EmpRowMajor && fieldType.getCols() == 4))))) + { + return true; + } + } + return false; + } + else if (type.isMatrix()) + { + // Only supports the matrix types that we do not need to pad in a structure or an array + // explicitly. + return (matrixPacking != EmpRowMajor && type.getRows() == 4) || + (matrixPacking == EmpRowMajor && type.getCols() == 4); + } + else + { + // Supports vector and scalar types in a structure or an array. + return true; + } +} + +static bool CanTranslateUniformBlockToStructuredBuffer(const TInterfaceBlock &interfaceBlock) +{ + const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); + + if (blockStorage == EbsStd140 && interfaceBlock.fields().size() == 1u) + { + const TType &fieldType = *interfaceBlock.fields()[0]->type(); + if (fieldType.getNumArraySizes() == 1u && + fieldType.getOutermostArraySize() >= kMinArraySizeUseStructuredBuffer) + { + return IsSupportedTypeForStructuredBuffer(fieldType); + } + } + + return false; +} + +static bool FieldIsOrHasLargeArrayField(const TField &field) +{ + const TType *type = field.type(); + if (type->getArraySizeProduct() >= kMinArraySizeUseStructuredBuffer) + { + return true; + } + + const TStructure *structure = type->getStruct(); + if (structure) + { + const TFieldList &fields = structure->fields(); + bool hasLargeArrayField = false; + for (size_t i = 0; i < fields.size(); i++) + { + hasLargeArrayField = FieldIsOrHasLargeArrayField(*fields[i]); + if (hasLargeArrayField) + { + break; + } + } + return hasLargeArrayField; + } + + return false; +} + +static bool IsInterfaceBlockWithLargeArrayField(const TInterfaceBlock &interfaceBlock) +{ + const TFieldList &fields = interfaceBlock.fields(); + bool isLargeArrayField = false; + for (size_t i = 0; i < fields.size(); i++) + { + isLargeArrayField = FieldIsOrHasLargeArrayField(*fields[i]); + if (isLargeArrayField) + { + break; + } + } + + return isLargeArrayField; +} + +void UniformBlocksWithLargeArrayMemberTraverser::visitSymbol(TIntermSymbol *node) +{ + const TVariable &variable = node->variable(); + const TType &variableType = variable.getType(); + TQualifier qualifier = variable.getType().getQualifier(); + + if (qualifier == EvqUniform) + { + const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock(); + if (interfaceBlock) + { + if (CanTranslateUniformBlockToStructuredBuffer(*interfaceBlock)) + { + if (mUniformBlockMayTranslation.count(interfaceBlock->uniqueId().get()) == 0) + { + mUniformBlockMayTranslation[interfaceBlock->uniqueId().get()] = interfaceBlock; + } + + if (!variableType.isInterfaceBlock()) + { + TIntermNode *accessor = getAncestorNode(0); + TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode(); + // The uniform block variable is array type, only indexing operator is allowed + // to operate on the variable, otherwise do not translate the uniform block to + // HLSL StructuredBuffer. + if (!accessorAsBinary || + !(accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect || + accessorAsBinary->getOp() == EOpIndexIndirect))) + { + if (mUniformBlockNotAllowTranslation.count( + interfaceBlock->uniqueId().get()) == 0) + { + mUniformBlockNotAllowTranslation[interfaceBlock->uniqueId().get()] = + interfaceBlock; + } + } + else + { + if (mUniformBlockUsedRegisterCount.count( + interfaceBlock->uniqueId().get()) == 0) + { + // The uniform block is not an instanced one, so it only uses one + // register. + mUniformBlockUsedRegisterCount[interfaceBlock->uniqueId().get()] = 1; + } + } + } + else + { + if (mUniformBlockUsedRegisterCount.count(interfaceBlock->uniqueId().get()) == 0) + { + // The uniform block is an instanced one, the count of used registers + // depends on the array size of variable. + mUniformBlockUsedRegisterCount[interfaceBlock->uniqueId().get()] = + variableType.isArray() ? variableType.getOutermostArraySize() : 1; + } + } + } + + if (interfaceBlock->blockStorage() == EbsStd140 && + IsInterfaceBlockWithLargeArrayField(*interfaceBlock)) + { + if (!variableType.isInterfaceBlock()) + { + TIntermNode *accessor = getAncestorNode(0); + TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode(); + if (accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect || + accessorAsBinary->getOp() == EOpIndexIndirect)) + { + if (mUniformBlockWithLargeArrayMember.count( + interfaceBlock->uniqueId().get()) == 0) + { + mUniformBlockWithLargeArrayMember[interfaceBlock->uniqueId().get()] = + interfaceBlock; + } + } + } + } + } + } +} + +bool UniformBlocksWithLargeArrayMemberTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + switch (node->getOp()) + { + case EOpIndexDirect: + { + if (visit == PreVisit) + { + const TType &leftType = node->getLeft()->getType(); + if (leftType.isInterfaceBlock()) + { + const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock(); + if (CanTranslateUniformBlockToStructuredBuffer(*interfaceBlock) && + mUniformBlockMayTranslation.count(interfaceBlock->uniqueId().get()) == 0) + { + mUniformBlockMayTranslation[interfaceBlock->uniqueId().get()] = + interfaceBlock; + if (mUniformBlockUsedRegisterCount.count( + interfaceBlock->uniqueId().get()) == 0) + { + // The uniform block is an instanced one, the count of used registers + // depends on the array size of variable. + mUniformBlockUsedRegisterCount[interfaceBlock->uniqueId().get()] = + leftType.isArray() ? leftType.getOutermostArraySize() : 1; + } + return false; + } + + if (interfaceBlock->blockStorage() == EbsStd140 && + IsInterfaceBlockWithLargeArrayField(*interfaceBlock)) + { + if (mUniformBlockWithLargeArrayMember.count( + interfaceBlock->uniqueId().get()) == 0) + { + mUniformBlockWithLargeArrayMember[interfaceBlock->uniqueId().get()] = + interfaceBlock; + } + } + } + } + break; + } + case EOpIndexDirectInterfaceBlock: + { + if (visit == InVisit) + { + const TInterfaceBlock *interfaceBlock = + node->getLeft()->getType().getInterfaceBlock(); + if (CanTranslateUniformBlockToStructuredBuffer(*interfaceBlock)) + { + TIntermNode *accessor = getAncestorNode(0); + TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode(); + // The uniform block variable is array type, only indexing operator is allowed + // to operate on the variable, otherwise do not translate the uniform block to + // HLSL StructuredBuffer. + if ((!accessorAsBinary || + !(accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect || + accessorAsBinary->getOp() == EOpIndexIndirect))) && + mUniformBlockNotAllowTranslation.count(interfaceBlock->uniqueId().get()) == + 0) + { + mUniformBlockNotAllowTranslation[interfaceBlock->uniqueId().get()] = + interfaceBlock; + return false; + } + } + + if (interfaceBlock->blockStorage() == EbsStd140 && + IsInterfaceBlockWithLargeArrayField(*interfaceBlock)) + { + TIntermNode *accessor = getAncestorNode(0); + TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode(); + if (accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect || + accessorAsBinary->getOp() == EOpIndexIndirect)) + { + if (mUniformBlockWithLargeArrayMember.count( + interfaceBlock->uniqueId().get()) == 0) + { + mUniformBlockWithLargeArrayMember[interfaceBlock->uniqueId().get()] = + interfaceBlock; + } + } + } + } + break; + } + default: + break; + } + + return true; +} +} // namespace + +bool RecordUniformBlocksWithLargeArrayMember( + TIntermNode *root, + std::map &uniformBlockOptimizedMap, + std::set &slowCompilingUniformBlockSet) +{ + UniformBlocksWithLargeArrayMemberTraverser traverser; + root->traverse(&traverser); + std::map &uniformBlockMayTranslation = + traverser.getUniformBlockMayTranslation(); + std::map &uniformBlockNotAllowTranslation = + traverser.getUniformBlockNotAllowTranslation(); + std::map &uniformBlockUsedRegisterCount = + traverser.getUniformBlockUsedRegisterCount(); + std::map &uniformBlockWithLargeArrayMember = + traverser.getUniformBlockWithLargeArrayMember(); + + unsigned int usedRegisterCount = 0; + for (auto &uniformBlock : uniformBlockMayTranslation) + { + if (uniformBlockNotAllowTranslation.count(uniformBlock.first) == 0) + { + usedRegisterCount += uniformBlockUsedRegisterCount[uniformBlock.first]; + if (usedRegisterCount > kMaxAllowToUseRegisterCount) + { + break; + } + uniformBlockOptimizedMap[uniformBlock.first] = uniformBlock.second; + } + } + + for (auto &uniformBlock : uniformBlockWithLargeArrayMember) + { + if (uniformBlockOptimizedMap.count(uniformBlock.first) == 0) + { + slowCompilingUniformBlockSet.insert(uniformBlock.second->name().data()); + } + } + + return true; +} + +} // namespace sh -- cgit v1.2.3