Commit 378653f8 by Xinghua Cao Committed by Commit Bot

D3D: throw a perf warning for uniform block

We had translated an uniform block only containing a large array member into StructuredBuffer instead of cbuffer on D3D backend for slow fxc compile performance issue with dynamic uniform indexing. This patch throw a warning if a uniform block containing a large array member fails to hit the optimization. Bug: angleproject:3682 Change-Id: I33459b559923f16a8dfb70c6f46ec52f68d96e06 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2552365 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJiajia Qin <jiajia.qin@intel.com>
parent f0f79e08
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 245 #define ANGLE_SH_VERSION 246
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -759,6 +759,7 @@ bool GetUniformBlockRegister(const ShHandle handle, ...@@ -759,6 +759,7 @@ bool GetUniformBlockRegister(const ShHandle handle,
bool ShouldUniformBlockUseStructuredBuffer(const ShHandle handle, bool ShouldUniformBlockUseStructuredBuffer(const ShHandle handle,
const std::string &uniformBlockName); const std::string &uniformBlockName);
const std::set<std::string> *GetSlowCompilingUniformBlockSet(const ShHandle handle);
// Gives a map from uniform names to compiler-assigned registers in the default uniform block. // Gives a map from uniform names to compiler-assigned registers in the default uniform block.
// Note that the map contains also registers of samplers that have been extracted from structs. // Note that the map contains also registers of samplers that have been extracted from structs.
......
...@@ -150,8 +150,8 @@ angle_translator_sources = [ ...@@ -150,8 +150,8 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/PruneNoOps.h", "src/compiler/translator/tree_ops/PruneNoOps.h",
"src/compiler/translator/tree_ops/RecordConstantPrecision.cpp", "src/compiler/translator/tree_ops/RecordConstantPrecision.cpp",
"src/compiler/translator/tree_ops/RecordConstantPrecision.h", "src/compiler/translator/tree_ops/RecordConstantPrecision.h",
"src/compiler/translator/tree_ops/RecordUniformBlocksTranslatedToStructuredBuffers.cpp", "src/compiler/translator/tree_ops/RecordUniformBlocksWithLargeArrayMember.cpp",
"src/compiler/translator/tree_ops/RecordUniformBlocksTranslatedToStructuredBuffers.h", "src/compiler/translator/tree_ops/RecordUniformBlocksWithLargeArrayMember.h",
"src/compiler/translator/tree_ops/RegenerateStructNames.cpp", "src/compiler/translator/tree_ops/RegenerateStructNames.cpp",
"src/compiler/translator/tree_ops/RegenerateStructNames.h", "src/compiler/translator/tree_ops/RegenerateStructNames.h",
"src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp", "src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp",
......
...@@ -297,8 +297,7 @@ const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out, ...@@ -297,8 +297,7 @@ const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
return constUnionIterated; return constUnionIterated;
} }
OutputHLSL::OutputHLSL( OutputHLSL::OutputHLSL(sh::GLenum shaderType,
sh::GLenum shaderType,
ShShaderSpec shaderSpec, ShShaderSpec shaderSpec,
int shaderVersion, int shaderVersion,
const TExtensionBehavior &extensionBehavior, const TExtensionBehavior &extensionBehavior,
...@@ -311,7 +310,7 @@ OutputHLSL::OutputHLSL( ...@@ -311,7 +310,7 @@ OutputHLSL::OutputHLSL(
sh::WorkGroupSize workGroupSize, sh::WorkGroupSize workGroupSize,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
PerformanceDiagnostics *perfDiagnostics, PerformanceDiagnostics *perfDiagnostics,
const std::map<int, const TInterfaceBlock *> &uniformBlocksTranslatedToStructuredBuffers, const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap,
const std::vector<InterfaceBlock> &shaderStorageBlocks) const std::vector<InterfaceBlock> &shaderStorageBlocks)
: TIntermTraverser(true, true, true, symbolTable), : TIntermTraverser(true, true, true, symbolTable),
mShaderType(shaderType), mShaderType(shaderType),
...@@ -323,7 +322,7 @@ OutputHLSL::OutputHLSL( ...@@ -323,7 +322,7 @@ OutputHLSL::OutputHLSL(
mCompileOptions(compileOptions), mCompileOptions(compileOptions),
mInsideFunction(false), mInsideFunction(false),
mInsideMain(false), mInsideMain(false),
mUniformBlocksTranslatedToStructuredBuffers(uniformBlocksTranslatedToStructuredBuffers), mUniformBlockOptimizedMap(uniformBlockOptimizedMap),
mNumRenderTargets(numRenderTargets), mNumRenderTargets(numRenderTargets),
mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers), mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers),
mCurrentFunctionMetadata(nullptr), mCurrentFunctionMetadata(nullptr),
...@@ -661,8 +660,7 @@ void OutputHLSL::header(TInfoSinkBase &out, ...@@ -661,8 +660,7 @@ void OutputHLSL::header(TInfoSinkBase &out,
out << mStructureHLSL->structsHeader(); out << mStructureHLSL->structsHeader();
mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable); mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable);
out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks, out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks, mUniformBlockOptimizedMap);
mUniformBlocksTranslatedToStructuredBuffers);
mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out); mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
if (!mEqualityFunctions.empty()) if (!mEqualityFunctions.empty())
...@@ -1650,8 +1648,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1650,8 +1648,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{ {
const TInterfaceBlock *interfaceBlock = const TInterfaceBlock *interfaceBlock =
GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft()); GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
if (interfaceBlock && mUniformBlocksTranslatedToStructuredBuffers.count( if (interfaceBlock &&
interfaceBlock->uniqueId().get()) != 0) mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
{ {
// If the uniform block member's type is not structure, we had explicitly // If the uniform block member's type is not structure, we had explicitly
// packed the member into a structure, so need to add an operator of field // packed the member into a structure, so need to add an operator of field
...@@ -1685,8 +1683,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1685,8 +1683,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{ {
const TInterfaceBlock *interfaceBlock = const TInterfaceBlock *interfaceBlock =
GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft()); GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
if (interfaceBlock && mUniformBlocksTranslatedToStructuredBuffers.count( if (interfaceBlock &&
interfaceBlock->uniqueId().get()) != 0) mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
{ {
// If the uniform block member's type is not structure, we had explicitly // If the uniform block member's type is not structure, we had explicitly
// packed the member into a structure, so need to add an operator of field // packed the member into a structure, so need to add an operator of field
...@@ -1757,8 +1755,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1757,8 +1755,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
node->getLeft()->getType().getInterfaceBlock(); node->getLeft()->getType().getInterfaceBlock();
const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
const TField *field = interfaceBlock->fields()[index->getIConst(0)]; const TField *field = interfaceBlock->fields()[index->getIConst(0)];
if (structInStd140UniformBlock || mUniformBlocksTranslatedToStructuredBuffers.count( if (structInStd140UniformBlock ||
interfaceBlock->uniqueId().get()) != 0) mUniformBlockOptimizedMap.count(interfaceBlock->uniqueId().get()) != 0)
{ {
out << "_"; out << "_";
} }
......
...@@ -37,8 +37,7 @@ using ReferencedVariables = std::map<int, const TVariable *>; ...@@ -37,8 +37,7 @@ using ReferencedVariables = std::map<int, const TVariable *>;
class OutputHLSL : public TIntermTraverser class OutputHLSL : public TIntermTraverser
{ {
public: public:
OutputHLSL( OutputHLSL(sh::GLenum shaderType,
sh::GLenum shaderType,
ShShaderSpec shaderSpec, ShShaderSpec shaderSpec,
int shaderVersion, int shaderVersion,
const TExtensionBehavior &extensionBehavior, const TExtensionBehavior &extensionBehavior,
...@@ -51,7 +50,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -51,7 +50,7 @@ class OutputHLSL : public TIntermTraverser
sh::WorkGroupSize workGroupSize, sh::WorkGroupSize workGroupSize,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
PerformanceDiagnostics *perfDiagnostics, PerformanceDiagnostics *perfDiagnostics,
const std::map<int, const TInterfaceBlock *> &uniformBlocksTranslatedToStructuredBuffers, const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap,
const std::vector<InterfaceBlock> &shaderStorageBlocks); const std::vector<InterfaceBlock> &shaderStorageBlocks);
~OutputHLSL() override; ~OutputHLSL() override;
...@@ -181,7 +180,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -181,7 +180,7 @@ class OutputHLSL : public TIntermTraverser
// Indexed by block id, not instance id. // Indexed by block id, not instance id.
ReferencedInterfaceBlocks mReferencedUniformBlocks; ReferencedInterfaceBlocks mReferencedUniformBlocks;
std::map<int, const TInterfaceBlock *> mUniformBlocksTranslatedToStructuredBuffers; std::map<int, const TInterfaceBlock *> mUniformBlockOptimizedMap;
ReferencedVariables mReferencedAttributes; ReferencedVariables mReferencedAttributes;
ReferencedVariables mReferencedVaryings; ReferencedVariables mReferencedVaryings;
......
...@@ -697,7 +697,7 @@ void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIn ...@@ -697,7 +697,7 @@ void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIn
TString ResourcesHLSL::uniformBlocksHeader( TString ResourcesHLSL::uniformBlocksHeader(
const ReferencedInterfaceBlocks &referencedInterfaceBlocks, const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
const std::map<int, const TInterfaceBlock *> &uniformBlockTranslatedToStructuredBuffer) const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap)
{ {
TString interfaceBlocks; TString interfaceBlocks;
...@@ -712,7 +712,7 @@ TString ResourcesHLSL::uniformBlocksHeader( ...@@ -712,7 +712,7 @@ TString ResourcesHLSL::uniformBlocksHeader(
// In order to avoid compile performance issue, translate uniform block to structured // In order to avoid compile performance issue, translate uniform block to structured
// buffer. anglebug.com/3682. // buffer. anglebug.com/3682.
if (uniformBlockTranslatedToStructuredBuffer.count(interfaceBlock.uniqueId().get()) != 0) if (uniformBlockOptimizedMap.count(interfaceBlock.uniqueId().get()) != 0)
{ {
unsigned int structuredBufferRegister = mSRVRegister; unsigned int structuredBufferRegister = mSRVRegister;
if (instanceVariable != nullptr && instanceVariable->getType().isArray()) if (instanceVariable != nullptr && instanceVariable->getType().isArray())
......
...@@ -40,7 +40,7 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -40,7 +40,7 @@ class ResourcesHLSL : angle::NonCopyable
void imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex); void imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex);
TString uniformBlocksHeader( TString uniformBlocksHeader(
const ReferencedInterfaceBlocks &referencedInterfaceBlocks, const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
const std::map<int, const TInterfaceBlock *> &uniformBlockTranslatedToStructuredBuffer); const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap);
TString shaderStorageBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks); TString shaderStorageBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks);
// Used for direct index references // Used for direct index references
......
...@@ -629,6 +629,18 @@ const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle ...@@ -629,6 +629,18 @@ const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle
#endif // ANGLE_ENABLE_HLSL #endif // ANGLE_ENABLE_HLSL
} }
const std::set<std::string> *GetSlowCompilingUniformBlockSet(const ShHandle handle)
{
#ifdef ANGLE_ENABLE_HLSL
TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
ASSERT(translator);
return translator->getSlowCompilingUniformBlockSet();
#else
return nullptr;
#endif // ANGLE_ENABLE_HLSL
}
unsigned int GetReadonlyImage2DRegisterIndex(const ShHandle handle) unsigned int GetReadonlyImage2DRegisterIndex(const ShHandle handle)
{ {
#ifdef ANGLE_ENABLE_HLSL #ifdef ANGLE_ENABLE_HLSL
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include "compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h" #include "compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h"
#include "compiler/translator/tree_ops/ExpandIntegerPowExpressions.h" #include "compiler/translator/tree_ops/ExpandIntegerPowExpressions.h"
#include "compiler/translator/tree_ops/PruneEmptyCases.h" #include "compiler/translator/tree_ops/PruneEmptyCases.h"
#include "compiler/translator/tree_ops/RecordUniformBlocksTranslatedToStructuredBuffers.h" #include "compiler/translator/tree_ops/RecordUniformBlocksWithLargeArrayMember.h"
#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h" #include "compiler/translator/tree_ops/RemoveDynamicIndexing.h"
#include "compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h" #include "compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h"
#include "compiler/translator/tree_ops/RewriteElseBlocks.h" #include "compiler/translator/tree_ops/RewriteElseBlocks.h"
...@@ -184,25 +184,26 @@ bool TranslatorHLSL::translate(TIntermBlock *root, ...@@ -184,25 +184,26 @@ bool TranslatorHLSL::translate(TIntermBlock *root,
} }
} }
mUniformBlocksTranslatedToStructuredBuffers.clear(); mUniformBlockOptimizedMap.clear();
mSlowCompilingUniformBlockSet.clear();
// In order to get the exact maximum of slots are available for shader resources, which would // In order to get the exact maximum of slots are available for shader resources, which would
// been bound with StructuredBuffer, we only translate uniform block with a large array member // been bound with StructuredBuffer, we only translate uniform block with a large array member
// into StructuredBuffer when shader version is 300. // into StructuredBuffer when shader version is 300.
if (getShaderVersion() == 300 && if (getShaderVersion() == 300 &&
(compileOptions & SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER) != 0) (compileOptions & SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER) != 0)
{ {
if (!sh::RecordUniformBlocksTranslatedToStructuredBuffers( if (!sh::RecordUniformBlocksWithLargeArrayMember(root, mUniformBlockOptimizedMap,
root, mUniformBlocksTranslatedToStructuredBuffers)) mSlowCompilingUniformBlockSet))
{ {
return false; return false;
} }
} }
sh::OutputHLSL outputHLSL( sh::OutputHLSL outputHLSL(getShaderType(), getShaderSpec(), getShaderVersion(),
getShaderType(), getShaderSpec(), getShaderVersion(), getExtensionBehavior(), getExtensionBehavior(), getSourcePath(), getOutputType(),
getSourcePath(), getOutputType(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(),
compileOptions, getComputeShaderLocalSize(), &getSymbolTable(), perfDiagnostics, compileOptions, getComputeShaderLocalSize(), &getSymbolTable(),
mUniformBlocksTranslatedToStructuredBuffers, mShaderStorageBlocks); perfDiagnostics, mUniformBlockOptimizedMap, mShaderStorageBlocks);
outputHLSL.output(root, getInfoSink().obj); outputHLSL.output(root, getInfoSink().obj);
...@@ -251,6 +252,11 @@ const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap ...@@ -251,6 +252,11 @@ const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap
return &mUniformRegisterMap; return &mUniformRegisterMap;
} }
const std::set<std::string> *TranslatorHLSL::getSlowCompilingUniformBlockSet() const
{
return &mSlowCompilingUniformBlockSet;
}
unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const
{ {
return mReadonlyImage2DRegisterIndex; return mReadonlyImage2DRegisterIndex;
......
...@@ -24,6 +24,7 @@ class TranslatorHLSL : public TCompiler ...@@ -24,6 +24,7 @@ class TranslatorHLSL : public TCompiler
bool hasUniformBlock(const std::string &interfaceBlockName) const; bool hasUniformBlock(const std::string &interfaceBlockName) const;
unsigned int getUniformBlockRegister(const std::string &interfaceBlockName) const; unsigned int getUniformBlockRegister(const std::string &interfaceBlockName) const;
bool shouldUniformBlockUseStructuredBuffer(const std::string &uniformBlockName) const; bool shouldUniformBlockUseStructuredBuffer(const std::string &uniformBlockName) const;
const std::set<std::string> *getSlowCompilingUniformBlockSet() const;
const std::map<std::string, unsigned int> *getUniformRegisterMap() const; const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
unsigned int getReadonlyImage2DRegisterIndex() const; unsigned int getReadonlyImage2DRegisterIndex() const;
...@@ -46,7 +47,8 @@ class TranslatorHLSL : public TCompiler ...@@ -46,7 +47,8 @@ class TranslatorHLSL : public TCompiler
unsigned int mReadonlyImage2DRegisterIndex; unsigned int mReadonlyImage2DRegisterIndex;
unsigned int mImage2DRegisterIndex; unsigned int mImage2DRegisterIndex;
std::set<std::string> mUsedImage2DFunctionNames; std::set<std::string> mUsedImage2DFunctionNames;
std::map<int, const TInterfaceBlock *> mUniformBlocksTranslatedToStructuredBuffers; std::map<int, const TInterfaceBlock *> mUniformBlockOptimizedMap;
std::set<std::string> mSlowCompilingUniformBlockSet;
}; };
} // namespace sh } // namespace sh
......
//
// 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.
//
// RecordUniformBlocksTranslatedToStructuredBuffers.h:
// Collect all uniform blocks which will been translated to StructuredBuffers on Direct3D
// backend.
//
#ifndef COMPILER_TRANSLATOR_TREEOPS_RECORDUNIFORMBLOCKSTRANSLATEDTOSTRUCTUREDBUFFERS_H_
#define COMPILER_TRANSLATOR_TREEOPS_RECORDUNIFORMBLOCKSTRANSLATEDTOSTRUCTUREDBUFFERS_H_
#include "compiler/translator/IntermNode.h"
namespace sh
{
class TIntermNode;
ANGLE_NO_DISCARD bool RecordUniformBlocksTranslatedToStructuredBuffers(
TIntermNode *root,
std::map<int, const TInterfaceBlock *> &uniformBlockTranslatedToStructuredBuffer);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_RECORDACCESSUNIFORMBLOCKENTIREARRAYMEMBER_H_
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// RecordUniformBlocksTranslatedToStructuredBuffers.cpp: // RecordUniformBlocksWithLargeArrayMember.h:
// Collect all uniform blocks which will been translated to StructuredBuffers on Direct3D // Collect all uniform blocks which have one or more large array members,
// backend. // 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/RecordUniformBlocksTranslatedToStructuredBuffers.h" #include "compiler/translator/tree_ops/RecordUniformBlocksWithLargeArrayMember.h"
#include "compiler/translator/Compiler.h" #include "compiler/translator/Compiler.h"
#include "compiler/translator/tree_util/IntermNode_util.h" #include "compiler/translator/tree_util/IntermNode_util.h"
...@@ -24,18 +26,18 @@ namespace ...@@ -24,18 +26,18 @@ namespace
// to a StructuredBuffer on Direct3D backend. // to a StructuredBuffer on Direct3D backend.
const unsigned int kMinArraySizeUseStructuredBuffer = 50u; const unsigned int kMinArraySizeUseStructuredBuffer = 50u;
// There is a maximum of D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT(128) slots that are available // There is a maximum of D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT(128) slots that are
// for shader resources on Direct3D 11. When shader version is 300, we only use // 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 // D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT(16) slots for texture units. We allow StructuredBuffer
// use the maximum of 60 slots, that is enough here. // to use the maximum of 60 slots, that is enough here.
const unsigned int kMaxAllowToUseRegisterCount = 60u; const unsigned int kMaxAllowToUseRegisterCount = 60u;
// Traverser that collects all uniform blocks which will been translated to StructuredBuffer on // Traverser that all uniform blocks which have one or more large array members, and the array
// Direct3D backend. // sizes are greater than or equal to 50.
class UniformBlockTranslatedToStructuredBufferTraverser : public TIntermTraverser class UniformBlocksWithLargeArrayMemberTraverser : public TIntermTraverser
{ {
public: public:
UniformBlockTranslatedToStructuredBufferTraverser(); UniformBlocksWithLargeArrayMemberTraverser();
void visitSymbol(TIntermSymbol *node) override; void visitSymbol(TIntermSymbol *node) override;
bool visitBinary(Visit visit, TIntermBinary *node) override; bool visitBinary(Visit visit, TIntermBinary *node) override;
...@@ -51,42 +53,50 @@ class UniformBlockTranslatedToStructuredBufferTraverser : public TIntermTraverse ...@@ -51,42 +53,50 @@ class UniformBlockTranslatedToStructuredBufferTraverser : public TIntermTraverse
{ {
return mUniformBlockUsedRegisterCount; return mUniformBlockUsedRegisterCount;
} }
std::map<int, const TInterfaceBlock *> &getUniformBlockWithLargeArrayMember()
{
return mUniformBlockWithLargeArrayMember;
}
private: private:
void parseAccessWholeUniformBlock(TIntermTyped *node);
std::map<int, const TInterfaceBlock *> mUniformBlockMayTranslation; std::map<int, const TInterfaceBlock *> mUniformBlockMayTranslation;
std::map<int, const TInterfaceBlock *> mUniformBlockNotAllowTranslation; std::map<int, const TInterfaceBlock *> mUniformBlockNotAllowTranslation;
std::map<int, unsigned int> mUniformBlockUsedRegisterCount; std::map<int, unsigned int> mUniformBlockUsedRegisterCount;
std::map<int, const TInterfaceBlock *> mUniformBlockWithLargeArrayMember;
}; };
UniformBlockTranslatedToStructuredBufferTraverser:: UniformBlocksWithLargeArrayMemberTraverser::UniformBlocksWithLargeArrayMemberTraverser()
UniformBlockTranslatedToStructuredBufferTraverser()
: TIntermTraverser(true, true, false) : TIntermTraverser(true, true, false)
{} {}
static bool IsSupportedTypeForStructuredBuffer(const TType &type) static bool IsSupportedTypeForStructuredBuffer(const TType &type)
{ {
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
const TLayoutMatrixPacking matrixPacking = type.getLayoutQualifier().matrixPacking;
if (structure) if (structure)
{ {
const TFieldList &fields = structure->fields(); const TFieldList &fields = structure->fields();
for (size_t i = 0; i < fields.size(); i++) 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. // Do not allow the structure's member is array or structure.
if (fields[i]->type()->isArray() || fields[i]->type()->getStruct() || if (!fieldType.isArray() && !fieldType.getStruct() &&
!IsSupportedTypeForStructuredBuffer(*fields[i]->type())) (fieldType.isScalar() || fieldType.isVector() ||
(fieldType.isMatrix() &&
((matrixPacking != EmpRowMajor && fieldType.getRows() == 4) ||
(matrixPacking == EmpRowMajor && fieldType.getCols() == 4)))))
{ {
return false; return true;
} }
} }
return true; return false;
} }
else if (type.isMatrix()) else if (type.isMatrix())
{ {
// Only supports the matrix types that we do not need to pad in a structure or an array // Only supports the matrix types that we do not need to pad in a structure or an array
// explicitly. // explicitly.
return (type.getLayoutQualifier().matrixPacking != EmpRowMajor && type.getRows() == 4) || return (matrixPacking != EmpRowMajor && type.getRows() == 4) ||
(type.getLayoutQualifier().matrixPacking == EmpRowMajor && type.getCols() == 4); (matrixPacking == EmpRowMajor && type.getCols() == 4);
} }
else else
{ {
...@@ -112,7 +122,50 @@ static bool CanTranslateUniformBlockToStructuredBuffer(const TInterfaceBlock &in ...@@ -112,7 +122,50 @@ static bool CanTranslateUniformBlockToStructuredBuffer(const TInterfaceBlock &in
return false; return false;
} }
void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbol *node) 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 TVariable &variable = node->variable();
const TType &variableType = variable.getType(); const TType &variableType = variable.getType();
...@@ -121,7 +174,9 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo ...@@ -121,7 +174,9 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo
if (qualifier == EvqUniform) if (qualifier == EvqUniform)
{ {
const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock(); const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock();
if (interfaceBlock && CanTranslateUniformBlockToStructuredBuffer(*interfaceBlock)) if (interfaceBlock)
{
if (CanTranslateUniformBlockToStructuredBuffer(*interfaceBlock))
{ {
if (mUniformBlockMayTranslation.count(interfaceBlock->uniqueId().get()) == 0) if (mUniformBlockMayTranslation.count(interfaceBlock->uniqueId().get()) == 0)
{ {
...@@ -132,15 +187,15 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo ...@@ -132,15 +187,15 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo
{ {
TIntermNode *accessor = getAncestorNode(0); TIntermNode *accessor = getAncestorNode(0);
TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode(); TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode();
// The uniform block variable is array type, only indexing operator is allowed to // The uniform block variable is array type, only indexing operator is allowed
// operate on the variable, otherwise do not translate the uniform block to HLSL // to operate on the variable, otherwise do not translate the uniform block to
// StructuredBuffer. // HLSL StructuredBuffer.
if (!accessorAsBinary || if (!accessorAsBinary ||
!(accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect || !(accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect ||
accessorAsBinary->getOp() == EOpIndexIndirect))) accessorAsBinary->getOp() == EOpIndexIndirect)))
{ {
if (mUniformBlockNotAllowTranslation.count(interfaceBlock->uniqueId().get()) == if (mUniformBlockNotAllowTranslation.count(
0) interfaceBlock->uniqueId().get()) == 0)
{ {
mUniformBlockNotAllowTranslation[interfaceBlock->uniqueId().get()] = mUniformBlockNotAllowTranslation[interfaceBlock->uniqueId().get()] =
interfaceBlock; interfaceBlock;
...@@ -148,9 +203,11 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo ...@@ -148,9 +203,11 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo
} }
else else
{ {
if (mUniformBlockUsedRegisterCount.count(interfaceBlock->uniqueId().get()) == 0) if (mUniformBlockUsedRegisterCount.count(
interfaceBlock->uniqueId().get()) == 0)
{ {
// The uniform block is not an instanced one, so it only uses one register. // The uniform block is not an instanced one, so it only uses one
// register.
mUniformBlockUsedRegisterCount[interfaceBlock->uniqueId().get()] = 1; mUniformBlockUsedRegisterCount[interfaceBlock->uniqueId().get()] = 1;
} }
} }
...@@ -159,18 +216,38 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo ...@@ -159,18 +216,38 @@ void UniformBlockTranslatedToStructuredBufferTraverser::visitSymbol(TIntermSymbo
{ {
if (mUniformBlockUsedRegisterCount.count(interfaceBlock->uniqueId().get()) == 0) if (mUniformBlockUsedRegisterCount.count(interfaceBlock->uniqueId().get()) == 0)
{ {
// The uniform block is an instanced one, the count of used registers depends on // The uniform block is an instanced one, the count of used registers
// the array size of variable. // depends on the array size of variable.
mUniformBlockUsedRegisterCount[interfaceBlock->uniqueId().get()] = mUniformBlockUsedRegisterCount[interfaceBlock->uniqueId().get()] =
variableType.isArray() ? variableType.getOutermostArraySize() : 1; 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 UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit, bool UniformBlocksWithLargeArrayMemberTraverser::visitBinary(Visit visit, TIntermBinary *node)
TIntermBinary *node)
{ {
switch (node->getOp()) switch (node->getOp())
{ {
...@@ -197,6 +274,17 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit, ...@@ -197,6 +274,17 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit,
} }
return false; return false;
} }
if (interfaceBlock->blockStorage() == EbsStd140 &&
IsInterfaceBlockWithLargeArrayField(*interfaceBlock))
{
if (mUniformBlockWithLargeArrayMember.count(
interfaceBlock->uniqueId().get()) == 0)
{
mUniformBlockWithLargeArrayMember[interfaceBlock->uniqueId().get()] =
interfaceBlock;
}
}
} }
} }
break; break;
...@@ -212,9 +300,8 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit, ...@@ -212,9 +300,8 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit,
TIntermNode *accessor = getAncestorNode(0); TIntermNode *accessor = getAncestorNode(0);
TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode(); TIntermBinary *accessorAsBinary = accessor->getAsBinaryNode();
// The uniform block variable is array type, only indexing operator is allowed // The uniform block variable is array type, only indexing operator is allowed
// to operate on the // to operate on the variable, otherwise do not translate the uniform block to
// variable, otherwise do not translate the uniform block to HLSL // HLSL StructuredBuffer.
// StructuredBuffer.
if ((!accessorAsBinary || if ((!accessorAsBinary ||
!(accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect || !(accessorAsBinary && (accessorAsBinary->getOp() == EOpIndexDirect ||
accessorAsBinary->getOp() == EOpIndexIndirect))) && accessorAsBinary->getOp() == EOpIndexIndirect))) &&
...@@ -226,6 +313,23 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit, ...@@ -226,6 +313,23 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit,
return false; 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; break;
} }
...@@ -237,11 +341,12 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit, ...@@ -237,11 +341,12 @@ bool UniformBlockTranslatedToStructuredBufferTraverser::visitBinary(Visit visit,
} }
} // namespace } // namespace
bool RecordUniformBlocksTranslatedToStructuredBuffers( bool RecordUniformBlocksWithLargeArrayMember(
TIntermNode *root, TIntermNode *root,
std::map<int, const TInterfaceBlock *> &uniformBlockTranslatedToStructuredBuffer) std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap,
std::set<std::string> &slowCompilingUniformBlockSet)
{ {
UniformBlockTranslatedToStructuredBufferTraverser traverser; UniformBlocksWithLargeArrayMemberTraverser traverser;
root->traverse(&traverser); root->traverse(&traverser);
std::map<int, const TInterfaceBlock *> &uniformBlockMayTranslation = std::map<int, const TInterfaceBlock *> &uniformBlockMayTranslation =
traverser.getUniformBlockMayTranslation(); traverser.getUniformBlockMayTranslation();
...@@ -249,6 +354,8 @@ bool RecordUniformBlocksTranslatedToStructuredBuffers( ...@@ -249,6 +354,8 @@ bool RecordUniformBlocksTranslatedToStructuredBuffers(
traverser.getUniformBlockNotAllowTranslation(); traverser.getUniformBlockNotAllowTranslation();
std::map<int, unsigned int> &uniformBlockUsedRegisterCount = std::map<int, unsigned int> &uniformBlockUsedRegisterCount =
traverser.getUniformBlockUsedRegisterCount(); traverser.getUniformBlockUsedRegisterCount();
std::map<int, const TInterfaceBlock *> &uniformBlockWithLargeArrayMember =
traverser.getUniformBlockWithLargeArrayMember();
unsigned int usedRegisterCount = 0; unsigned int usedRegisterCount = 0;
for (auto &uniformBlock : uniformBlockMayTranslation) for (auto &uniformBlock : uniformBlockMayTranslation)
...@@ -260,9 +367,18 @@ bool RecordUniformBlocksTranslatedToStructuredBuffers( ...@@ -260,9 +367,18 @@ bool RecordUniformBlocksTranslatedToStructuredBuffers(
{ {
break; break;
} }
uniformBlockTranslatedToStructuredBuffer[uniformBlock.first] = uniformBlock.second; uniformBlockOptimizedMap[uniformBlock.first] = uniformBlock.second;
}
} }
for (auto &uniformBlock : uniformBlockWithLargeArrayMember)
{
if (uniformBlockOptimizedMap.count(uniformBlock.first) == 0)
{
slowCompilingUniformBlockSet.insert(uniformBlock.second->name().data());
} }
}
return true; return true;
} }
......
//
// 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.
//
#ifndef COMPILER_TRANSLATOR_TREEOPS_RECORDUNIFORMBLOCKSWITHLARGEARRAYMEMBER_H_
#define COMPILER_TRANSLATOR_TREEOPS_RECORDUNIFORMBLOCKSWITHLARGEARRAYMEMBER_H_
#include "compiler/translator/IntermNode.h"
namespace sh
{
class TIntermNode;
ANGLE_NO_DISCARD bool RecordUniformBlocksWithLargeArrayMember(
TIntermNode *root,
std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap,
std::set<std::string> &slowCompilingUniformBlockSet);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_RECORDUNIFORMBLOCKSWITHLARGEARRAYMEMBER_H_
...@@ -2078,6 +2078,27 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context, ...@@ -2078,6 +2078,27 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
shadersD3D[shaderType]->generateWorkarounds(&mShaderWorkarounds[shaderType]); shadersD3D[shaderType]->generateWorkarounds(&mShaderWorkarounds[shaderType]);
mShaderUniformsDirty.set(shaderType); mShaderUniformsDirty.set(shaderType);
const std::set<std::string> &slowCompilingUniformBlockSet =
shadersD3D[shaderType]->getSlowCompilingUniformBlockSet();
if (slowCompilingUniformBlockSet.size() > 0)
{
std::ostringstream stream;
stream << "You could get a better shader compiling performance if you re-write"
<< " the uniform block(s)\n[ ";
for (const std::string &str : slowCompilingUniformBlockSet)
{
stream << str << " ";
}
stream << "]\nin the " << gl::GetShaderTypeString(shaderType) << " shader.\n";
stream << "You could get more details from "
"https://chromium.googlesource.com/angle/angle/+/refs/heads/master/"
"src/libANGLE/renderer/d3d/d3d11/"
"UniformBlockToStructuredBufferTranslation.md\n";
ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_MEDIUM,
stream.str().c_str());
}
} }
} }
......
...@@ -240,6 +240,11 @@ bool ShaderD3D::useImage2DFunction(const std::string &functionName) const ...@@ -240,6 +240,11 @@ bool ShaderD3D::useImage2DFunction(const std::string &functionName) const
return mUsedImage2DFunctionNames.find(functionName) != mUsedImage2DFunctionNames.end(); return mUsedImage2DFunctionNames.find(functionName) != mUsedImage2DFunctionNames.end();
} }
const std::set<std::string> &ShaderD3D::getSlowCompilingUniformBlockSet() const
{
return mSlowCompilingUniformBlockSet;
}
const std::map<std::string, unsigned int> &GetUniformRegisterMap( const std::map<std::string, unsigned int> &GetUniformRegisterMap(
const std::map<std::string, unsigned int> *uniformRegisterMap) const std::map<std::string, unsigned int> *uniformRegisterMap)
{ {
...@@ -247,6 +252,13 @@ const std::map<std::string, unsigned int> &GetUniformRegisterMap( ...@@ -247,6 +252,13 @@ const std::map<std::string, unsigned int> &GetUniformRegisterMap(
return *uniformRegisterMap; return *uniformRegisterMap;
} }
const std::set<std::string> &GetSlowCompilingUniformBlockSet(
const std::set<std::string> *slowCompilingUniformBlockSet)
{
ASSERT(slowCompilingUniformBlockSet);
return *slowCompilingUniformBlockSet;
}
const std::set<std::string> &GetUsedImage2DFunctionNames( const std::set<std::string> &GetUsedImage2DFunctionNames(
const std::set<std::string> *usedImage2DFunctionNames) const std::set<std::string> *usedImage2DFunctionNames)
{ {
...@@ -330,6 +342,9 @@ std::shared_ptr<WaitableCompileEvent> ShaderD3D::compile(const gl::Context *cont ...@@ -330,6 +342,9 @@ std::shared_ptr<WaitableCompileEvent> ShaderD3D::compile(const gl::Context *cont
} }
} }
mSlowCompilingUniformBlockSet =
GetSlowCompilingUniformBlockSet(sh::GetSlowCompilingUniformBlockSet(compilerHandle));
for (const sh::InterfaceBlock &interfaceBlock : mState.getShaderStorageBlocks()) for (const sh::InterfaceBlock &interfaceBlock : mState.getShaderStorageBlocks())
{ {
if (interfaceBlock.active) if (interfaceBlock.active)
......
...@@ -59,6 +59,7 @@ class ShaderD3D : public ShaderImpl ...@@ -59,6 +59,7 @@ class ShaderD3D : public ShaderImpl
unsigned int getReadonlyImage2DRegisterIndex() const { return mReadonlyImage2DRegisterIndex; } unsigned int getReadonlyImage2DRegisterIndex() const { return mReadonlyImage2DRegisterIndex; }
unsigned int getImage2DRegisterIndex() const { return mImage2DRegisterIndex; } unsigned int getImage2DRegisterIndex() const { return mImage2DRegisterIndex; }
bool useImage2DFunction(const std::string &functionName) const; bool useImage2DFunction(const std::string &functionName) const;
const std::set<std::string> &getSlowCompilingUniformBlockSet() const;
void appendDebugInfo(const std::string &info) const { mDebugInfo += info; } void appendDebugInfo(const std::string &info) const { mDebugInfo += info; }
void generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const; void generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const;
...@@ -104,6 +105,7 @@ class ShaderD3D : public ShaderImpl ...@@ -104,6 +105,7 @@ class ShaderD3D : public ShaderImpl
std::map<std::string, unsigned int> mUniformRegisterMap; std::map<std::string, unsigned int> mUniformRegisterMap;
std::map<std::string, unsigned int> mUniformBlockRegisterMap; std::map<std::string, unsigned int> mUniformBlockRegisterMap;
std::map<std::string, bool> mUniformBlockUseStructuredBufferMap; std::map<std::string, bool> mUniformBlockUseStructuredBufferMap;
std::set<std::string> mSlowCompilingUniformBlockSet;
std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap; std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap;
unsigned int mReadonlyImage2DRegisterIndex; unsigned int mReadonlyImage2DRegisterIndex;
unsigned int mImage2DRegisterIndex; unsigned int mImage2DRegisterIndex;
......
...@@ -3093,6 +3093,51 @@ void main(void){ ...@@ -3093,6 +3093,51 @@ void main(void){
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Test to throw a warning if a uniform block with a large array member
// fails to hit the optimization on D3D backend.
TEST_P(UniformBlockWithOneLargeArrayMemberTest, ThrowPerfWarningInD3D)
{
constexpr char kFS[] = R"(#version 300 es
precision highp float;
struct S1 {
vec2 a[2];
};
struct S2 {
mat2x4 b;
};
layout(std140, row_major) uniform UBO1{
mat3x2 buf1[128];
};
layout(std140, row_major) uniform UBO2{
mat4x3 buf2[128];
} instance1;
layout(std140, row_major) uniform UBO3{
S1 buf3[128];
};
layout(std140, row_major) uniform UBO4{
S2 buf4[128];
} instance2[2];
out vec4 my_FragColor;
void main(void){
uvec2 coord = uvec2(floor(gl_FragCoord.xy));
uint x = coord.x % 64u;
uint y = coord.y;
my_FragColor = vec4(buf1[y]*instance1.buf2[y]*instance2[0].buf4[y].b*buf3[y].a[x], 0.0f, 1.0);
})";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
EXPECT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES3(UniformBufferTest); ANGLE_INSTANTIATE_TEST_ES3(UniformBufferTest);
......
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