Commit dc1c1cb5 by Xinghua Cao Committed by Commit Bot

Restrict to translate uniform block to StructuredBuffer

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. Now we add more conditions to restrict the translation. Only indexing operator is allowed to operate on this uniform block variable. And we also restrict the types of uniform block's member. Bug: angleproject:3682 Change-Id: I992b7890d84fcaa6169722af6d7e14785526d48a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2351728 Commit-Queue: Xinghua Cao <xinghua.cao@intel.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJiajia Qin <jiajia.qin@intel.com>
parent 3980b1f8
...@@ -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 236 #define ANGLE_SH_VERSION 237
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -315,9 +315,8 @@ const ShCompileOptions SH_ADD_BASE_VERTEX_TO_VERTEX_ID = UINT64_C(1) << 48; ...@@ -315,9 +315,8 @@ const ShCompileOptions SH_ADD_BASE_VERTEX_TO_VERTEX_ID = UINT64_C(1) << 48;
// This works around the dynamic lvalue indexing of swizzled vectors on various platforms. // This works around the dynamic lvalue indexing of swizzled vectors on various platforms.
const ShCompileOptions SH_REMOVE_DYNAMIC_INDEXING_OF_SWIZZLED_VECTOR = UINT64_C(1) << 49; const ShCompileOptions SH_REMOVE_DYNAMIC_INDEXING_OF_SWIZZLED_VECTOR = UINT64_C(1) << 49;
// This flag works a driver bug that fails to allocate ShaderResourceView for StructuredBuffer // This flag works around a slow fxc compile performance issue with dynamic uniform indexing.
// on Windows 7 and earlier. const ShCompileOptions SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER = UINT64_C(1) << 50;
const ShCompileOptions SH_DONT_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER = UINT64_C(1) << 50;
// This flag indicates whether Bresenham line raster emulation code should be generated. This // This flag indicates whether Bresenham line raster emulation code should be generated. This
// emulation is necessary if the backend uses a differnet algorithm to draw lines. Currently only // emulation is necessary if the backend uses a differnet algorithm to draw lines. Currently only
......
...@@ -207,11 +207,13 @@ struct FeaturesD3D : FeatureSetBase ...@@ -207,11 +207,13 @@ struct FeaturesD3D : FeatureSetBase
"Some drivers corrupt texture data when clearing for robust resource initialization.", "Some drivers corrupt texture data when clearing for robust resource initialization.",
&members, "http://crbug.com/941620"}; &members, "http://crbug.com/941620"};
// Don't translate uniform block to StructuredBuffer on Windows 7 and earlier. This is targeted // Allow translating uniform block to StructuredBuffer. This is targeted to work around a slow
// to work around a bug that fails to allocate ShaderResourceView for StructuredBuffer. // fxc compile performance issue with dynamic uniform indexing. http://anglebug.com/3682
Feature dontTranslateUniformBlockToStructuredBuffer = { Feature allowTranslateUniformBlockToStructuredBuffer = {
"dont_translate_uniform_block_to_structured_buffer", FeatureCategory::D3DWorkarounds, "allow_translate_uniform_block_to_structured_buffer", FeatureCategory::D3DWorkarounds,
"Fails to allocate ShaderResourceView for StructuredBuffer on some drivers", &members}; "There is a slow fxc compile performance issue with dynamic uniform indexing if "
"translating a uniform block with a large array member to cbuffer.",
&members, "http://anglebug.com/3682"};
}; };
inline FeaturesD3D::FeaturesD3D() = default; inline FeaturesD3D::FeaturesD3D() = default;
......
...@@ -148,6 +148,8 @@ angle_translator_sources = [ ...@@ -148,6 +148,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/RecordUniformBlocksTranslatedToStructuredBuffers.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,20 +297,22 @@ const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out, ...@@ -297,20 +297,22 @@ const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out,
return constUnionIterated; return constUnionIterated;
} }
OutputHLSL::OutputHLSL(sh::GLenum shaderType, OutputHLSL::OutputHLSL(
ShShaderSpec shaderSpec, sh::GLenum shaderType,
int shaderVersion, ShShaderSpec shaderSpec,
const TExtensionBehavior &extensionBehavior, int shaderVersion,
const char *sourcePath, const TExtensionBehavior &extensionBehavior,
ShShaderOutput outputType, const char *sourcePath,
int numRenderTargets, ShShaderOutput outputType,
int maxDualSourceDrawBuffers, int numRenderTargets,
const std::vector<ShaderVariable> &uniforms, int maxDualSourceDrawBuffers,
ShCompileOptions compileOptions, const std::vector<ShaderVariable> &uniforms,
sh::WorkGroupSize workGroupSize, ShCompileOptions compileOptions,
TSymbolTable *symbolTable, sh::WorkGroupSize workGroupSize,
PerformanceDiagnostics *perfDiagnostics, TSymbolTable *symbolTable,
const std::vector<InterfaceBlock> &shaderStorageBlocks) PerformanceDiagnostics *perfDiagnostics,
const std::map<int, const TInterfaceBlock *> &uniformBlocksTranslatedToStructuredBuffers,
const std::vector<InterfaceBlock> &shaderStorageBlocks)
: TIntermTraverser(true, true, true, symbolTable), : TIntermTraverser(true, true, true, symbolTable),
mShaderType(shaderType), mShaderType(shaderType),
mShaderSpec(shaderSpec), mShaderSpec(shaderSpec),
...@@ -321,6 +323,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, ...@@ -321,6 +323,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
mCompileOptions(compileOptions), mCompileOptions(compileOptions),
mInsideFunction(false), mInsideFunction(false),
mInsideMain(false), mInsideMain(false),
mUniformBlocksTranslatedToStructuredBuffers(uniformBlocksTranslatedToStructuredBuffers),
mNumRenderTargets(numRenderTargets), mNumRenderTargets(numRenderTargets),
mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers), mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers),
mCurrentFunctionMetadata(nullptr), mCurrentFunctionMetadata(nullptr),
...@@ -371,8 +374,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, ...@@ -371,8 +374,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
unsigned int firstUniformRegister = unsigned int firstUniformRegister =
((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u; ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u;
mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, compileOptions, uniforms, mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister);
firstUniformRegister);
if (mOutputType == SH_HLSL_3_0_OUTPUT) if (mOutputType == SH_HLSL_3_0_OUTPUT)
{ {
...@@ -659,7 +661,8 @@ void OutputHLSL::header(TInfoSinkBase &out, ...@@ -659,7 +661,8 @@ 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,
mUniformBlocksTranslatedToStructuredBuffers);
mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out); mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out);
if (!mEqualityFunctions.empty()) if (!mEqualityFunctions.empty())
...@@ -1647,14 +1650,18 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1647,14 +1650,18 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{ {
const TInterfaceBlock *interfaceBlock = const TInterfaceBlock *interfaceBlock =
GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft()); GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
if (interfaceBlock && if (interfaceBlock && mUniformBlocksTranslatedToStructuredBuffers.count(
mResourcesHLSL->shouldTranslateUniformBlockToStructuredBuffer( interfaceBlock->uniqueId().get()) != 0)
*interfaceBlock))
{ {
const TField *field = interfaceBlock->fields()[0]; // If the uniform block member's type is not structure, we had explicitly
if (field->type()->isMatrix()) // packed the member into a structure, so need to add an operator of field
// slection.
const TField *field = interfaceBlock->fields()[0];
const TType *fieldType = field->type();
if (fieldType->isMatrix() || fieldType->isVectorArray() ||
fieldType->isScalarArray())
{ {
out << "._matrix_" << Decorate(field->name()); out << "." << Decorate(field->name());
} }
} }
} }
...@@ -1678,14 +1685,18 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1678,14 +1685,18 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{ {
const TInterfaceBlock *interfaceBlock = const TInterfaceBlock *interfaceBlock =
GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft()); GetInterfaceBlockOfUniformBlockNearestIndexOperator(node->getLeft());
if (interfaceBlock && if (interfaceBlock && mUniformBlocksTranslatedToStructuredBuffers.count(
mResourcesHLSL->shouldTranslateUniformBlockToStructuredBuffer( interfaceBlock->uniqueId().get()) != 0)
*interfaceBlock))
{ {
const TField *field = interfaceBlock->fields()[0]; // If the uniform block member's type is not structure, we had explicitly
if (field->type()->isMatrix()) // packed the member into a structure, so need to add an operator of field
// slection.
const TField *field = interfaceBlock->fields()[0];
const TType *fieldType = field->type();
if (fieldType->isMatrix() || fieldType->isVectorArray() ||
fieldType->isScalarArray())
{ {
out << "._matrix_" << Decorate(field->name()); out << "." << Decorate(field->name());
} }
} }
} }
...@@ -1746,8 +1757,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1746,8 +1757,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 || if (structInStd140UniformBlock || mUniformBlocksTranslatedToStructuredBuffers.count(
mResourcesHLSL->shouldTranslateUniformBlockToStructuredBuffer(*interfaceBlock)) interfaceBlock->uniqueId().get()) != 0)
{ {
out << "_"; out << "_";
} }
......
...@@ -37,20 +37,22 @@ using ReferencedVariables = std::map<int, const TVariable *>; ...@@ -37,20 +37,22 @@ using ReferencedVariables = std::map<int, const TVariable *>;
class OutputHLSL : public TIntermTraverser class OutputHLSL : public TIntermTraverser
{ {
public: public:
OutputHLSL(sh::GLenum shaderType, OutputHLSL(
ShShaderSpec shaderSpec, sh::GLenum shaderType,
int shaderVersion, ShShaderSpec shaderSpec,
const TExtensionBehavior &extensionBehavior, int shaderVersion,
const char *sourcePath, const TExtensionBehavior &extensionBehavior,
ShShaderOutput outputType, const char *sourcePath,
int numRenderTargets, ShShaderOutput outputType,
int maxDualSourceDrawBuffers, int numRenderTargets,
const std::vector<ShaderVariable> &uniforms, int maxDualSourceDrawBuffers,
ShCompileOptions compileOptions, const std::vector<ShaderVariable> &uniforms,
sh::WorkGroupSize workGroupSize, ShCompileOptions compileOptions,
TSymbolTable *symbolTable, sh::WorkGroupSize workGroupSize,
PerformanceDiagnostics *perfDiagnostics, TSymbolTable *symbolTable,
const std::vector<InterfaceBlock> &shaderStorageBlocks); PerformanceDiagnostics *perfDiagnostics,
const std::map<int, const TInterfaceBlock *> &uniformBlocksTranslatedToStructuredBuffers,
const std::vector<InterfaceBlock> &shaderStorageBlocks);
~OutputHLSL() override; ~OutputHLSL() override;
...@@ -179,6 +181,8 @@ class OutputHLSL : public TIntermTraverser ...@@ -179,6 +181,8 @@ 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;
ReferencedVariables mReferencedAttributes; ReferencedVariables mReferencedAttributes;
ReferencedVariables mReferencedVaryings; ReferencedVariables mReferencedVaryings;
ReferencedVariables mReferencedOutputVariables; ReferencedVariables mReferencedOutputVariables;
......
...@@ -24,11 +24,6 @@ namespace ...@@ -24,11 +24,6 @@ namespace
{ {
constexpr const ImmutableString kAngleDecorString("angle_"); constexpr const ImmutableString kAngleDecorString("angle_");
// D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT = 128;
const unsigned int kMaxInputResourceSlotCount = 128u;
// If uniform block member's array size is larger than kMinArraySizeUseStructuredBuffer,
// then we translate uniform block to StructuredBuffer for compiling performance.
const unsigned int kMinArraySizeUseStructuredBuffer = 50u;
static const char *UniformRegisterPrefix(const TType &type) static const char *UniformRegisterPrefix(const TType &type)
{ {
...@@ -104,46 +99,72 @@ void OutputUniformIndexArrayInitializer(TInfoSinkBase &out, ...@@ -104,46 +99,72 @@ void OutputUniformIndexArrayInitializer(TInfoSinkBase &out,
out << "}"; out << "}";
} }
// Check whether all fields match std140 storage layout, and do not need to add paddings static TString InterfaceBlockScalarVectorFieldPaddingString(const TType &type)
// when translating std140 uniform block to StructuredBuffer.
static bool ShouldPadUniformBlockMemberForStructuredBuffer(const TType &type)
{ {
const TStructure *structure = type.getStruct(); switch (type.getBasicType())
if (structure)
{ {
const TFieldList &fields = structure->fields(); case EbtFloat:
for (size_t i = 0; i < fields.size(); i++) switch (type.getNominalSize())
{
if (ShouldPadUniformBlockMemberForStructuredBuffer(*fields[i]->type()))
{ {
return true; case 1:
return "float3 padding;";
case 2:
return "float2 padding;";
case 3:
return "float padding;";
default:
break;
} }
} break;
return false; case EbtInt:
} switch (type.getNominalSize())
else if (type.isMatrix()) {
{ case 1:
if ((type.getLayoutQualifier().matrixPacking != EmpRowMajor && type.getRows() == 4) || return "int3 padding;";
(type.getLayoutQualifier().matrixPacking == EmpRowMajor && type.getCols() == 4)) case 2:
{ return "int2 padding;";
return false; case 3:
} return "int padding";
} default:
else break;
{ }
if (type.isVector() && type.getNominalSize() == 4) break;
{ case EbtUInt:
return false; switch (type.getNominalSize())
} {
case 1:
return "uint3 padding;";
case 2:
return "uint2 padding;";
case 3:
return "uint padding;";
default:
break;
}
break;
case EbtBool:
switch (type.getNominalSize())
{
case 1:
return "bool3 padding;";
case 2:
return "bool2 padding;";
case 3:
return "bool padding;";
default:
break;
}
break;
default:
break;
} }
return "";
return true;
} }
} // anonymous namespace } // anonymous namespace
ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL, ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
ShShaderOutput outputType, ShShaderOutput outputType,
ShCompileOptions compileOptions,
const std::vector<ShaderVariable> &uniforms, const std::vector<ShaderVariable> &uniforms,
unsigned int firstUniformRegister) unsigned int firstUniformRegister)
: mUniformRegister(firstUniformRegister), : mUniformRegister(firstUniformRegister),
...@@ -153,7 +174,6 @@ ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL, ...@@ -153,7 +174,6 @@ ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
mSamplerCount(0), mSamplerCount(0),
mStructureHLSL(structureHLSL), mStructureHLSL(structureHLSL),
mOutputType(outputType), mOutputType(outputType),
mCompileOptions(compileOptions),
mUniforms(uniforms) mUniforms(uniforms)
{} {}
...@@ -676,7 +696,8 @@ void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIn ...@@ -676,7 +696,8 @@ 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)
{ {
TString interfaceBlocks; TString interfaceBlocks;
...@@ -691,7 +712,7 @@ TString ResourcesHLSL::uniformBlocksHeader( ...@@ -691,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 (shouldTranslateUniformBlockToStructuredBuffer(interfaceBlock)) if (uniformBlockTranslatedToStructuredBuffer.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())
...@@ -820,10 +841,22 @@ TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString( ...@@ -820,10 +841,22 @@ TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
{ {
if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0) if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
{ {
hlsl += "struct matrix" + Decorate(field.name()) + " { " + typeString + " _matrix_" + hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
Decorate(field.name()) + "; };\n"; Decorate(field.name()) + "; };\n";
} }
typeString = "matrix" + Decorate(field.name()); typeString = "pack" + Decorate(interfaceBlock.name());
}
else if (fieldType.isVectorArray() || fieldType.isScalarArray())
{
// If the member is an array of scalars or vectors, std140 rules require the base array
// stride are rounded up to the base alignment of a vec4.
if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
{
hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
Decorate(field.name()) + ";\n";
hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n";
}
typeString = "pack" + Decorate(interfaceBlock.name());
} }
if (instanceVariable != nullptr) if (instanceVariable != nullptr)
...@@ -890,7 +923,7 @@ TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfac ...@@ -890,7 +923,7 @@ TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfac
if (blockStorage == EbsStd140) if (blockStorage == EbsStd140)
{ {
// 2 and 3 component vector types in some cases need pre-padding // 2 and 3 component vector types in some cases need pre-padding
hlsl += padHelper.prePaddingString(fieldType); hlsl += padHelper.prePaddingString(fieldType, false);
} }
hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " + hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " +
...@@ -918,18 +951,4 @@ TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interface ...@@ -918,18 +951,4 @@ TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interface
"{\n" + "{\n" +
uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n"; uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
} }
bool ResourcesHLSL::shouldTranslateUniformBlockToStructuredBuffer(
const TInterfaceBlock &interfaceBlock)
{
const TType &fieldType = *interfaceBlock.fields()[0]->type();
// Restrict field and sub-fields types match std140 storage layout rules, even the uniform
// does not use std140 qualifier.
bool shouldPadUniformBlockMember = ShouldPadUniformBlockMemberForStructuredBuffer(fieldType);
return (mCompileOptions & SH_DONT_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER) == 0 &&
mSRVRegister < kMaxInputResourceSlotCount && interfaceBlock.fields().size() == 1u &&
!shouldPadUniformBlockMember && fieldType.getNumArraySizes() == 1u &&
fieldType.getOutermostArraySize() >= kMinArraySizeUseStructuredBuffer;
}
} // namespace sh } // namespace sh
...@@ -24,7 +24,6 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -24,7 +24,6 @@ class ResourcesHLSL : angle::NonCopyable
public: public:
ResourcesHLSL(StructureHLSL *structureHLSL, ResourcesHLSL(StructureHLSL *structureHLSL,
ShShaderOutput outputType, ShShaderOutput outputType,
ShCompileOptions compileOptions,
const std::vector<ShaderVariable> &uniforms, const std::vector<ShaderVariable> &uniforms,
unsigned int firstUniformRegister); unsigned int firstUniformRegister);
...@@ -39,7 +38,9 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -39,7 +38,9 @@ class ResourcesHLSL : angle::NonCopyable
void samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex); void samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex);
unsigned int getSamplerCount() const { return mSamplerCount; } unsigned int getSamplerCount() const { return mSamplerCount; }
void imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex); void imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex);
TString uniformBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks); TString uniformBlocksHeader(
const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
const std::map<int, const TInterfaceBlock *> &uniformBlockTranslatedToStructuredBuffer);
TString shaderStorageBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks); TString shaderStorageBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks);
// Used for direct index references // Used for direct index references
...@@ -68,7 +69,6 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -68,7 +69,6 @@ class ResourcesHLSL : angle::NonCopyable
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 shouldTranslateUniformBlockToStructuredBuffer(const TInterfaceBlock &interfaceBlock);
private: private:
TString uniformBlockString(const TInterfaceBlock &interfaceBlock, TString uniformBlockString(const TInterfaceBlock &interfaceBlock,
...@@ -138,7 +138,6 @@ class ResourcesHLSL : angle::NonCopyable ...@@ -138,7 +138,6 @@ class ResourcesHLSL : angle::NonCopyable
unsigned int mImageCount; unsigned int mImageCount;
StructureHLSL *mStructureHLSL; StructureHLSL *mStructureHLSL;
ShShaderOutput mOutputType; ShShaderOutput mOutputType;
ShCompileOptions mCompileOptions;
const std::vector<ShaderVariable> &mUniforms; const std::vector<ShaderVariable> &mUniforms;
std::map<std::string, unsigned int> mUniformBlockRegisterMap; std::map<std::string, unsigned int> mUniformBlockRegisterMap;
......
...@@ -23,13 +23,13 @@ namespace ...@@ -23,13 +23,13 @@ namespace
TString Define(const TStructure &structure, TString Define(const TStructure &structure,
bool useHLSLRowMajorPacking, bool useHLSLRowMajorPacking,
bool useStd140Packing, bool useStd140Packing,
bool forcePackingEnd, bool forcePadding,
Std140PaddingHelper *padHelper) Std140PaddingHelper *padHelper)
{ {
const TFieldList &fields = structure.fields(); const TFieldList &fields = structure.fields();
const bool isNameless = (structure.symbolType() == SymbolType::Empty); const bool isNameless = (structure.symbolType() == SymbolType::Empty);
const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
useStd140Packing, forcePackingEnd); useStd140Packing, forcePadding);
const TString declareString = (isNameless ? "struct" : "struct " + structName); const TString declareString = (isNameless ? "struct" : "struct " + structName);
TString string; TString string;
...@@ -52,7 +52,8 @@ TString Define(const TStructure &structure, ...@@ -52,7 +52,8 @@ TString Define(const TStructure &structure,
if (padHelper) if (padHelper)
{ {
string += padHelper->prePaddingString(fieldType); string += padHelper->prePaddingString(
fieldType, (memberSize != fields.size() - 1) && forcePadding);
} }
string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) + string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) +
...@@ -61,7 +62,7 @@ TString Define(const TStructure &structure, ...@@ -61,7 +62,7 @@ TString Define(const TStructure &structure,
if (padHelper) if (padHelper)
{ {
string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking, string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking,
memberSize == 0 && forcePackingEnd); memberSize == 0 && forcePadding);
} }
} }
} }
...@@ -118,7 +119,7 @@ TString Std140PaddingHelper::next() ...@@ -118,7 +119,7 @@ TString Std140PaddingHelper::next()
return str(value); return str(value);
} }
int Std140PaddingHelper::prePadding(const TType &type) int Std140PaddingHelper::prePadding(const TType &type, bool forcePadding)
{ {
if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray()) if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
{ {
...@@ -139,9 +140,20 @@ int Std140PaddingHelper::prePadding(const TType &type) ...@@ -139,9 +140,20 @@ int Std140PaddingHelper::prePadding(const TType &type)
if (mElementIndex + numComponents > 4) if (mElementIndex + numComponents > 4)
{ {
// no padding needed, HLSL will align the field to a new register if (forcePadding)
mElementIndex = numComponents; {
return 0; // If this structure will be used as HLSL StructuredBuffer member's type, we should add
// padding between the structure's members to follow the std140 rules manually.
const int forcePaddingCount = 4 - mElementIndex;
mElementIndex = numComponents;
return forcePaddingCount;
}
else
{
// no padding needed, HLSL will align the field to a new register
mElementIndex = numComponents;
return 0;
}
} }
const int alignment = numComponents == 3 ? 4 : numComponents; const int alignment = numComponents == 3 ? 4 : numComponents;
...@@ -155,9 +167,9 @@ int Std140PaddingHelper::prePadding(const TType &type) ...@@ -155,9 +167,9 @@ int Std140PaddingHelper::prePadding(const TType &type)
return paddingCount; return paddingCount;
} }
TString Std140PaddingHelper::prePaddingString(const TType &type) TString Std140PaddingHelper::prePaddingString(const TType &type, bool forcePadding)
{ {
int paddingCount = prePadding(type); int paddingCount = prePadding(type, forcePadding);
TString padding; TString padding;
...@@ -173,8 +185,21 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, ...@@ -173,8 +185,21 @@ TString Std140PaddingHelper::postPaddingString(const TType &type,
bool useHLSLRowMajorPacking, bool useHLSLRowMajorPacking,
bool forcePadding) bool forcePadding)
{ {
if (!forcePadding && !type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct) if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
{ {
if (forcePadding)
{
// If this structure will be used as HLSL StructuredBuffer member's type, we
// should force to pad the end of the structure to follow the std140 rules.
TString forcePaddingStr;
const int paddingOffset = mElementIndex % 4;
const int paddingCount = paddingOffset != 0 ? (4 - paddingOffset) : 0;
for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
{
forcePaddingStr += " float pad_" + next() + ";\n";
}
return forcePaddingStr;
}
return ""; return "";
} }
...@@ -229,12 +254,12 @@ Std140PaddingHelper StructureHLSL::getPaddingHelper() ...@@ -229,12 +254,12 @@ Std140PaddingHelper StructureHLSL::getPaddingHelper()
TString StructureHLSL::defineQualified(const TStructure &structure, TString StructureHLSL::defineQualified(const TStructure &structure,
bool useHLSLRowMajorPacking, bool useHLSLRowMajorPacking,
bool useStd140Packing, bool useStd140Packing,
bool forcePackingEnd) bool forcePadding)
{ {
if (useStd140Packing) if (useStd140Packing)
{ {
Std140PaddingHelper padHelper = getPaddingHelper(); Std140PaddingHelper padHelper = getPaddingHelper();
return Define(structure, useHLSLRowMajorPacking, useStd140Packing, forcePackingEnd, return Define(structure, useHLSLRowMajorPacking, useStd140Packing, forcePadding,
&padHelper); &padHelper);
} }
else else
...@@ -282,19 +307,19 @@ StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStr ...@@ -282,19 +307,19 @@ StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStr
defineQualified(structure, true, true, false) + defineQualified(structure, true, true, false) +
"#pragma pack_matrix(column_major)\n"; "#pragma pack_matrix(column_major)\n";
// Must use packed structure for StructuredBuffer element type, if qualifier of structure is // Must force to pad the structure's elements for StructuredBuffer's element type, if qualifier
// std140. // of structure is std140.
TString std140PackingEndString = defineQualified(structure, false, true, true); TString std140ForcePaddingString = defineQualified(structure, false, true, true);
TString std140RowMajorPackEndingString = "#pragma pack_matrix(row_major)\n" + TString std140RowMajorForcePaddingString = "#pragma pack_matrix(row_major)\n" +
defineQualified(structure, true, true, true) + defineQualified(structure, true, true, true) +
"#pragma pack_matrix(column_major)\n"; "#pragma pack_matrix(column_major)\n";
mStructDeclarations.push_back(structString); mStructDeclarations.push_back(structString);
mStructDeclarations.push_back(rowMajorString); mStructDeclarations.push_back(rowMajorString);
mStructDeclarations.push_back(std140String); mStructDeclarations.push_back(std140String);
mStructDeclarations.push_back(std140RowMajorString); mStructDeclarations.push_back(std140RowMajorString);
mStructDeclarations.push_back(std140PackingEndString); mStructDeclarations.push_back(std140ForcePaddingString);
mStructDeclarations.push_back(std140RowMajorPackEndingString); mStructDeclarations.push_back(std140RowMajorForcePaddingString);
return addedStruct; return addedStruct;
} }
...@@ -596,7 +621,7 @@ void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, ...@@ -596,7 +621,7 @@ void StructureHLSL::storeStd140ElementIndex(const TStructure &structure,
for (const TField *field : fields) for (const TField *field : fields)
{ {
padHelper.prePadding(*field->type()); padHelper.prePadding(*field->type(), false);
} }
// Add remaining element index to the global map, for use with nested structs in standard // Add remaining element index to the global map, for use with nested structs in standard
......
...@@ -32,8 +32,8 @@ class Std140PaddingHelper ...@@ -32,8 +32,8 @@ class Std140PaddingHelper
Std140PaddingHelper &operator=(const Std140PaddingHelper &other); Std140PaddingHelper &operator=(const Std140PaddingHelper &other);
int elementIndex() const { return mElementIndex; } int elementIndex() const { return mElementIndex; }
int prePadding(const TType &type); int prePadding(const TType &type, bool forcePadding);
TString prePaddingString(const TType &type); TString prePaddingString(const TType &type, bool forcePadding);
TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking, bool forcePadding); TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking, bool forcePadding);
private: private:
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +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/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"
...@@ -183,11 +184,25 @@ bool TranslatorHLSL::translate(TIntermBlock *root, ...@@ -183,11 +184,25 @@ bool TranslatorHLSL::translate(TIntermBlock *root,
} }
} }
sh::OutputHLSL outputHLSL(getShaderType(), getShaderSpec(), getShaderVersion(), mUniformBlocksTranslatedToStructuredBuffers.clear();
getExtensionBehavior(), getSourcePath(), getOutputType(), // In order to get the exact maximum of slots are available for shader resources, which would
numRenderTargets, maxDualSourceDrawBuffers, getUniforms(), // been bound with StructuredBuffer, we only translate uniform block with a large array member
compileOptions, getComputeShaderLocalSize(), &getSymbolTable(), // into StructuredBuffer when shader version is 300.
perfDiagnostics, mShaderStorageBlocks); if (getShaderVersion() == 300 &&
(compileOptions & SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER) != 0)
{
if (!sh::RecordUniformBlocksTranslatedToStructuredBuffers(
root, mUniformBlocksTranslatedToStructuredBuffers))
{
return false;
}
}
sh::OutputHLSL outputHLSL(
getShaderType(), getShaderSpec(), getShaderVersion(), getExtensionBehavior(),
getSourcePath(), getOutputType(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(),
compileOptions, getComputeShaderLocalSize(), &getSymbolTable(), perfDiagnostics,
mUniformBlocksTranslatedToStructuredBuffers, mShaderStorageBlocks);
outputHLSL.output(root, getInfoSink().obj); outputHLSL.output(root, getInfoSink().obj);
......
...@@ -46,6 +46,7 @@ class TranslatorHLSL : public TCompiler ...@@ -46,6 +46,7 @@ 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;
}; };
} // namespace sh } // namespace sh
......
...@@ -231,10 +231,15 @@ class TType ...@@ -231,10 +231,15 @@ class TType
bool isInterfaceBlock() const { return type == EbtInterfaceBlock; } bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
bool isVector() const { return primarySize > 1 && secondarySize == 1; } bool isVector() const { return primarySize > 1 && secondarySize == 1; }
bool isVectorArray() const { return primarySize > 1 && secondarySize == 1 && isArray(); }
bool isScalar() const bool isScalar() const
{ {
return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray(); return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray();
} }
bool isScalarArray() const
{
return primarySize == 1 && secondarySize == 1 && !mStructure && isArray();
}
bool isScalarFloat() const { return isScalar() && type == EbtFloat; } bool isScalarFloat() const { return isScalar() && type == EbtFloat; }
bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); } bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); }
......
...@@ -1009,7 +1009,7 @@ TString StructNameString(const TStructure &structure) ...@@ -1009,7 +1009,7 @@ TString StructNameString(const TStructure &structure)
TString QualifiedStructNameString(const TStructure &structure, TString QualifiedStructNameString(const TStructure &structure,
bool useHLSLRowMajorPacking, bool useHLSLRowMajorPacking,
bool useStd140Packing, bool useStd140Packing,
bool forcePackingEnd) bool forcePadding)
{ {
if (structure.symbolType() == SymbolType::Empty) if (structure.symbolType() == SymbolType::Empty)
{ {
...@@ -1031,9 +1031,9 @@ TString QualifiedStructNameString(const TStructure &structure, ...@@ -1031,9 +1031,9 @@ TString QualifiedStructNameString(const TStructure &structure,
prefix += "rm_"; prefix += "rm_";
} }
if (forcePackingEnd) if (forcePadding)
{ {
prefix += "pe_"; prefix += "fp_";
} }
return prefix + StructNameString(structure); return prefix + StructNameString(structure);
......
//
// 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.cpp:
// Collect all uniform blocks which will been translated to StructuredBuffers on Direct3D
// backend.
//
#include "compiler/translator/tree_ops/RecordUniformBlocksTranslatedToStructuredBuffers.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 collects all uniform blocks which will been translated to StructuredBuffer on
// Direct3D backend.
class UniformBlockTranslatedToStructuredBufferTraverser : public TIntermTraverser
{
public:
UniformBlockTranslatedToStructuredBufferTraverser();
void visitSymbol(TIntermSymbol *node) override;
bool visitBinary(Visit visit, TIntermBinary *node) override;
std::map<int, const TInterfaceBlock *> &getUniformBlockMayTranslation()
{
return mUniformBlockMayTranslation;
}
std::map<int, const TInterfaceBlock *> &getUniformBlockNotAllowTranslation()
{
return mUniformBlockNotAllowTranslation;
}
std::map<int, unsigned int> &getUniformBlockUsedRegisterCount()
{
return mUniformBlockUsedRegisterCount;
}
private:
void parseAccessWholeUniformBlock(TIntermTyped *node);
std::map<int, const TInterfaceBlock *> mUniformBlockMayTranslation;
std::map<int, const TInterfaceBlock *> mUniformBlockNotAllowTranslation;
std::map<int, unsigned int> mUniformBlockUsedRegisterCount;
};
UniformBlockTranslatedToStructuredBufferTraverser::
UniformBlockTranslatedToStructuredBufferTraverser()
: TIntermTraverser(true, false, false)
{}
static bool IsSupportedTypeForStructuredBuffer(const TType &type)
{
const TStructure *structure = type.getStruct();
if (structure)
{
const TFieldList &fields = structure->fields();
for (size_t i = 0; i < fields.size(); i++)
{
// Do not allow the structure's member is array or structure.
if (fields[i]->type()->isArray() || fields[i]->type()->getStruct() ||
!IsSupportedTypeForStructuredBuffer(*fields[i]->type()))
{
return false;
}
}
return true;
}
else if (type.isMatrix())
{
// Only supports the matrix types that we do not need to pad in a structure or an array
// explicitly.
return (type.getLayoutQualifier().matrixPacking != EmpRowMajor && type.getRows() == 4) ||
(type.getLayoutQualifier().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;
}
void UniformBlockTranslatedToStructuredBufferTraverser::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 && 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;
}
}
}
}
}
bool UniformBlockTranslatedToStructuredBufferTraverser::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;
}
}
}
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;
}
}
}
break;
}
default:
break;
}
return true;
}
} // namespace
bool RecordUniformBlocksTranslatedToStructuredBuffers(
TIntermNode *root,
std::map<int, const TInterfaceBlock *> &uniformBlockTranslatedToStructuredBuffer)
{
UniformBlockTranslatedToStructuredBufferTraverser traverser;
root->traverse(&traverser);
std::map<int, const TInterfaceBlock *> &uniformBlockMayTranslation =
traverser.getUniformBlockMayTranslation();
std::map<int, const TInterfaceBlock *> &uniformBlockNotAllowTranslation =
traverser.getUniformBlockNotAllowTranslation();
std::map<int, unsigned int> &uniformBlockUsedRegisterCount =
traverser.getUniformBlockUsedRegisterCount();
unsigned int usedRegisterCount = 0;
for (auto &uniformBlock : uniformBlockMayTranslation)
{
if (uniformBlockNotAllowTranslation.count(uniformBlock.first) == 0)
{
usedRegisterCount += uniformBlockUsedRegisterCount[uniformBlock.first];
if (usedRegisterCount > kMaxAllowToUseRegisterCount)
{
break;
}
uniformBlockTranslatedToStructuredBuffer[uniformBlock.first] = uniformBlock.second;
}
}
return true;
}
} // 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_
...@@ -125,9 +125,9 @@ ShaderD3D::ShaderD3D(const gl::ShaderState &state, ...@@ -125,9 +125,9 @@ ShaderD3D::ShaderD3D(const gl::ShaderState &state,
{ {
mAdditionalOptions |= SH_FORCE_ATOMIC_VALUE_RESOLUTION; mAdditionalOptions |= SH_FORCE_ATOMIC_VALUE_RESOLUTION;
} }
if (features.dontTranslateUniformBlockToStructuredBuffer.enabled) if (features.allowTranslateUniformBlockToStructuredBuffer.enabled)
{ {
mAdditionalOptions |= SH_DONT_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER; mAdditionalOptions |= SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER;
} }
if (extensions.multiview || extensions.multiview2) if (extensions.multiview || extensions.multiview2)
{ {
......
...@@ -2482,9 +2482,10 @@ void InitializeFeatures(const Renderer11DeviceCaps &deviceCaps, ...@@ -2482,9 +2482,10 @@ void InitializeFeatures(const Renderer11DeviceCaps &deviceCaps,
// Intel, they've been blocklisted to the DX9 runtime. // Intel, they've been blocklisted to the DX9 runtime.
ANGLE_FEATURE_CONDITION(features, allowClearForRobustResourceInit, true); ANGLE_FEATURE_CONDITION(features, allowClearForRobustResourceInit, true);
// There is an issue(crbug.com/1112112) when translating uniform block to StructuredBuffer, // Allow translating uniform block to StructuredBuffer on Windows 10. This is targeted
// so disable this feature temporarily. // to work around a slow fxc compile performance issue with dynamic uniform indexing.
ANGLE_FEATURE_CONDITION(features, dontTranslateUniformBlockToStructuredBuffer, true); ANGLE_FEATURE_CONDITION(features, allowTranslateUniformBlockToStructuredBuffer,
IsWin10OrGreater());
// Call platform hooks for testing overrides. // Call platform hooks for testing overrides.
auto *platform = ANGLEPlatformCurrent(); auto *platform = ANGLEPlatformCurrent();
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
# include <sys/utsname.h> # include <sys/utsname.h>
#endif #endif
#if defined(ANGLE_PLATFORM_WINDOWS)
# include <versionhelpers.h>
#endif
namespace rx namespace rx
{ {
// Intel // Intel
...@@ -284,4 +288,15 @@ bool IsWayland() ...@@ -284,4 +288,15 @@ bool IsWayland()
return isWayland; return isWayland;
} }
bool IsWin10OrGreater()
{
#if defined(ANGLE_ENABLE_WINDOWS_UWP)
return true;
#elif defined(ANGLE_PLATFORM_WINDOWS)
return IsWindows10OrGreater();
#else
return false;
#endif
}
} // namespace rx } // namespace rx
...@@ -186,6 +186,7 @@ inline bool IsIOS() ...@@ -186,6 +186,7 @@ inline bool IsIOS()
} }
bool IsWayland(); bool IsWayland();
bool IsWin10OrGreater();
struct OSVersion struct OSVersion
{ {
......
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