Commit e196bc85 by Kenneth Russell Committed by Commit Bot

Add driver bug workaround for rewriting row major matrices.

Joint work with syoussefi@, who wrote the RewriteRowMajorMatrices pass, and revised it for this CL to not rely on the NameNamelessUniformBuffers pass - which was breaking it on the GL backend. Hook up previously written RewriteRowMajorMatrices transformation, and enable on all GPU types on macOS. It is needed at least for AMD and Intel GPUs. Add a new test which verifies the behavior of dynamically-indexed arrays of row-major matrices. Bug: angleproject:2273 Bug: angleproject:3843 Change-Id: Id582f9cf6b9b1a59091aab1786539174f360b705 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2008717 Commit-Queue: Kenneth Russell <kbr@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent c8e486b1
......@@ -329,6 +329,10 @@ const ShCompileOptions SH_ADD_BRESENHAM_LINE_RASTER_EMULATION = UINT64_C(1) << 5
// internally but shouldn't be exposed to WebGL user code.
const ShCompileOptions SH_DISABLE_ARB_TEXTURE_RECTANGLE = UINT64_C(1) << 52;
// This flag works around a driver bug by rewriting uses of row-major matrices
// as column-major in ESSL 3.00 and greater shaders.
const ShCompileOptions SH_REWRITE_ROW_MAJOR_MATRICES = UINT64_C(1) << 53;
// Defines alternate strategies for implementing array index clamping.
enum ShArrayIndexClampingStrategy
{
......
......@@ -404,6 +404,13 @@ struct FeaturesGL : FeatureSetBase
"Some drivers track CopyTex{Sub}Image texture dependencies incorrectly. Flush"
" before glDeleteTextures in this case",
&members, "http://anglebug.com/4267"};
// Rewrite row-major matrices as column-major as a driver bug workaround if
// necessary.
Feature rewriteRowMajorMatrices = {
"rewrite_row_major_matrices", FeatureCategory::OpenGLWorkarounds,
"Rewrite row major matrices in shaders as column major as a driver bug workaround",
&members, "http://anglebug.com/2273"};
};
inline FeaturesGL::FeaturesGL() = default;
......
......@@ -17,9 +17,9 @@ angle_translator_sources = [
"include/GLES2/gl2ext.h",
"include/GLES2/gl2platform.h",
"include/GLES3/gl3.h",
"include/GLES3/gl3platform.h",
"include/GLES3/gl31.h",
"include/GLES3/gl32.h",
"include/GLES3/gl3platform.h",
"include/KHR/khrplatform.h",
"include/angle_gl.h",
"src/compiler/translator/BaseTypes.h",
......@@ -59,8 +59,8 @@ angle_translator_sources = [
"src/compiler/translator/InitializeDll.cpp",
"src/compiler/translator/InitializeDll.h",
"src/compiler/translator/InitializeGlobals.h",
"src/compiler/translator/IntermNode.h",
"src/compiler/translator/IntermNode.cpp",
"src/compiler/translator/IntermNode.h",
"src/compiler/translator/IsASTDepthBelowLimit.cpp",
"src/compiler/translator/IsASTDepthBelowLimit.h",
"src/compiler/translator/Operator.cpp",
......@@ -69,14 +69,14 @@ angle_translator_sources = [
"src/compiler/translator/OutputTree.h",
"src/compiler/translator/ParseContext.cpp",
"src/compiler/translator/ParseContext.h",
"src/compiler/translator/ParseContext_interm.h",
"src/compiler/translator/ParseContext_complete_autogen.h",
"src/compiler/translator/ParseContext_ESSL_autogen.h",
"src/compiler/translator/ParseContext_complete_autogen.h",
"src/compiler/translator/ParseContext_interm.h",
"src/compiler/translator/PoolAlloc.cpp",
"src/compiler/translator/PoolAlloc.h",
"src/compiler/translator/Pragma.h",
"src/compiler/translator/QualifierTypes.h",
"src/compiler/translator/QualifierTypes.cpp",
"src/compiler/translator/QualifierTypes.h",
"src/compiler/translator/Severity.h",
"src/compiler/translator/ShaderLang.cpp",
"src/compiler/translator/ShaderVars.cpp",
......@@ -96,8 +96,8 @@ angle_translator_sources = [
"src/compiler/translator/ValidateGlobalInitializer.h",
"src/compiler/translator/ValidateLimitations.cpp",
"src/compiler/translator/ValidateLimitations.h",
"src/compiler/translator/ValidateMaxParameters.h",
"src/compiler/translator/ValidateMaxParameters.cpp",
"src/compiler/translator/ValidateMaxParameters.h",
"src/compiler/translator/ValidateOutputs.cpp",
"src/compiler/translator/ValidateOutputs.h",
"src/compiler/translator/ValidateSwitch.cpp",
......@@ -112,8 +112,6 @@ angle_translator_sources = [
"src/compiler/translator/glslang_tab_autogen.cpp",
"src/compiler/translator/glslang_tab_autogen.h",
"src/compiler/translator/length_limits.h",
"src/compiler/translator/util.cpp",
"src/compiler/translator/util.h",
"src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp",
"src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h",
"src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp",
......@@ -122,8 +120,8 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/ClampFragDepth.h",
"src/compiler/translator/tree_ops/ClampPointSize.cpp",
"src/compiler/translator/tree_ops/ClampPointSize.h",
"src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h",
"src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp",
"src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h",
"src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp",
"src/compiler/translator/tree_ops/DeferGlobalInitializers.h",
"src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp",
......@@ -140,8 +138,6 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/InitializeVariables.h",
"src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp",
"src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h",
"src/compiler/translator/tree_ops/NameNamelessUniformBuffers.cpp",
"src/compiler/translator/tree_ops/NameNamelessUniformBuffers.h",
"src/compiler/translator/tree_ops/PruneEmptyCases.cpp",
"src/compiler/translator/tree_ops/PruneEmptyCases.h",
"src/compiler/translator/tree_ops/PruneNoOps.cpp",
......@@ -154,12 +150,12 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h",
"src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp",
"src/compiler/translator/tree_ops/RemoveDynamicIndexing.h",
"src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp",
"src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h",
"src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp",
"src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h",
"src/compiler/translator/tree_ops/RemovePow.cpp",
"src/compiler/translator/tree_ops/RemovePow.h",
"src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.cpp",
"src/compiler/translator/tree_ops/RemoveInactiveInterfaceVariables.h",
"src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp",
"src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h",
"src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp",
......@@ -174,13 +170,13 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/RewriteDoWhile.h",
"src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp",
"src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h",
"src/compiler/translator/tree_ops/RewriteStructSamplers.cpp",
"src/compiler/translator/tree_ops/RewriteStructSamplers.h",
"src/compiler/translator/tree_ops/RewriteStructSamplersOld.cpp",
"src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp",
"src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h",
"src/compiler/translator/tree_ops/RewriteRowMajorMatrices.cpp",
"src/compiler/translator/tree_ops/RewriteRowMajorMatrices.h",
"src/compiler/translator/tree_ops/RewriteStructSamplers.cpp",
"src/compiler/translator/tree_ops/RewriteStructSamplers.h",
"src/compiler/translator/tree_ops/RewriteStructSamplersOld.cpp",
"src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp",
"src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h",
"src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp",
......@@ -202,8 +198,8 @@ angle_translator_sources = [
"src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp",
"src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h",
"src/compiler/translator/tree_util/BuiltIn.h",
"src/compiler/translator/tree_util/BuiltIn_complete_autogen.h",
"src/compiler/translator/tree_util/BuiltIn_ESSL_autogen.h",
"src/compiler/translator/tree_util/BuiltIn_complete_autogen.h",
"src/compiler/translator/tree_util/FindFunction.cpp",
"src/compiler/translator/tree_util/FindFunction.h",
"src/compiler/translator/tree_util/FindMain.cpp",
......@@ -217,13 +213,15 @@ angle_translator_sources = [
"src/compiler/translator/tree_util/IntermTraverse.cpp",
"src/compiler/translator/tree_util/IntermTraverse.h",
"src/compiler/translator/tree_util/NodeSearch.h",
"src/compiler/translator/tree_util/ReplaceVariable.cpp",
"src/compiler/translator/tree_util/ReplaceVariable.h",
"src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp",
"src/compiler/translator/tree_util/ReplaceShadowingVariables.h",
"src/compiler/translator/tree_util/ReplaceVariable.cpp",
"src/compiler/translator/tree_util/ReplaceVariable.h",
"src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp",
"src/compiler/translator/tree_util/RunAtTheEndOfShader.h",
"src/compiler/translator/tree_util/Visit.h",
"src/compiler/translator/util.cpp",
"src/compiler/translator/util.h",
"src/third_party/compiler/ArrayBoundsClamper.cpp",
"src/third_party/compiler/ArrayBoundsClamper.h",
]
......@@ -254,9 +252,10 @@ angle_translator_hlsl_sources = [
"src/compiler/translator/ASTMetadataHLSL.h",
"src/compiler/translator/AtomicCounterFunctionHLSL.cpp",
"src/compiler/translator/AtomicCounterFunctionHLSL.h",
"src/compiler/translator/blocklayoutHLSL.cpp",
"src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp",
"src/compiler/translator/BuiltInFunctionEmulatorHLSL.h",
"src/compiler/translator/ImageFunctionHLSL.cpp",
"src/compiler/translator/ImageFunctionHLSL.h",
"src/compiler/translator/OutputHLSL.cpp",
"src/compiler/translator/OutputHLSL.h",
"src/compiler/translator/ResourcesHLSL.cpp",
......@@ -269,12 +268,11 @@ angle_translator_hlsl_sources = [
"src/compiler/translator/StructureHLSL.h",
"src/compiler/translator/TextureFunctionHLSL.cpp",
"src/compiler/translator/TextureFunctionHLSL.h",
"src/compiler/translator/ImageFunctionHLSL.cpp",
"src/compiler/translator/ImageFunctionHLSL.h",
"src/compiler/translator/TranslatorHLSL.cpp",
"src/compiler/translator/TranslatorHLSL.h",
"src/compiler/translator/UtilsHLSL.cpp",
"src/compiler/translator/UtilsHLSL.h",
"src/compiler/translator/blocklayoutHLSL.cpp",
"src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp",
"src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp",
"src/compiler/translator/tree_ops/AddDefaultReturnStatements.h",
......@@ -314,8 +312,8 @@ if (is_android) {
}
angle_translator_lib_metal_sources = [
"src/compiler/translator/OutputVulkanGLSLForMetal.mm",
"src/compiler/translator/OutputVulkanGLSLForMetal.h",
"src/compiler/translator/OutputVulkanGLSLForMetal.mm",
"src/compiler/translator/TranslatorMetal.cpp",
"src/compiler/translator/TranslatorMetal.h",
]
......@@ -336,8 +334,6 @@ angle_preprocessor_sources = [
"src/compiler/preprocessor/Macro.h",
"src/compiler/preprocessor/MacroExpander.cpp",
"src/compiler/preprocessor/MacroExpander.h",
"src/compiler/preprocessor/preprocessor_lex_autogen.cpp",
"src/compiler/preprocessor/preprocessor_tab_autogen.cpp",
"src/compiler/preprocessor/Preprocessor.cpp",
"src/compiler/preprocessor/Preprocessor.h",
"src/compiler/preprocessor/SourceLocation.h",
......@@ -345,4 +341,6 @@ angle_preprocessor_sources = [
"src/compiler/preprocessor/Token.h",
"src/compiler/preprocessor/Tokenizer.h",
"src/compiler/preprocessor/numeric_lex.h",
"src/compiler/preprocessor/preprocessor_lex_autogen.cpp",
"src/compiler/preprocessor/preprocessor_tab_autogen.cpp",
]
......@@ -12,6 +12,7 @@
#include "compiler/translator/OutputGLSL.h"
#include "compiler/translator/VersionGLSL.h"
#include "compiler/translator/tree_ops/EmulatePrecision.h"
#include "compiler/translator/tree_ops/RewriteRowMajorMatrices.h"
#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h"
#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h"
......@@ -109,6 +110,14 @@ bool TranslatorGLSL::translate(TIntermBlock *root,
}
}
if ((compileOptions & SH_REWRITE_ROW_MAJOR_MATRICES) != 0 && getShaderVersion() >= 300)
{
if (!RewriteRowMajorMatrices(this, root, &getSymbolTable()))
{
return false;
}
}
bool precisionEmulation =
getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
......
//
// Copyright 2019 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.
//
// NameNamelessUniformBuffers: Gives nameless uniform buffer variables internal names.
//
#include "compiler/translator/tree_ops/NameNamelessUniformBuffers.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
// Traverse uniform buffer declarations and give name to nameless declarations. Keeps track of
// the interface fields which will be used in the source without the interface block variable name
// and replaces them with name.field.
class NameUniformBufferVariablesTraverser : public TIntermTraverser
{
public:
explicit NameUniformBufferVariablesTraverser(TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable)
{}
bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
{
ASSERT(visit == PreVisit);
const TIntermSequence &sequence = *(decl->getSequence());
TIntermTyped *variableNode = sequence.front()->getAsTyped();
const TType &type = variableNode->getType();
// If it's an interface block, it may have to be converted if it contains any row-major
// fields.
if (!type.isInterfaceBlock())
{
return true;
}
// Multi declaration statements are already separated, so there can only be one variable
// here.
ASSERT(sequence.size() == 1);
const TVariable *variable = &variableNode->getAsSymbolNode()->variable();
if (variable->symbolType() != SymbolType::Empty)
{
return false;
}
TIntermDeclaration *newDeclaration = new TIntermDeclaration;
TVariable *newVariable = new TVariable(mSymbolTable, kEmptyImmutableString, &type,
SymbolType::AngleInternal, variable->extension());
newDeclaration->appendDeclarator(new TIntermSymbol(newVariable));
queueReplacement(newDeclaration, OriginalNode::IS_DROPPED);
// It's safe to key the map with the interface block, as there couldn't have been multiple
// declarations with this interface block (as the variable is nameless), so for nameless
// uniform buffers, the interface block is unique.
mNamelessUniformBuffersMap[type.getInterfaceBlock()] = newVariable;
return false;
}
void visitSymbol(TIntermSymbol *symbol) override
{
const TType &type = symbol->getType();
// The symbols we are looking for have the interface block pointer set, but are not
// interface blocks. These are references to fields of nameless uniform buffers.
if (type.isInterfaceBlock() || type.getInterfaceBlock() == nullptr)
{
return;
}
const TInterfaceBlock *block = type.getInterfaceBlock();
// If block variable is not nameless, there's nothing to do.
if (mNamelessUniformBuffersMap.count(block) == 0)
{
return;
}
const ImmutableString symbolName = symbol->getName();
// Find which field it is
const TVector<TField *> fields = block->fields();
for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
{
const TField *field = fields[fieldIndex];
if (field->name() != symbolName)
{
continue;
}
// Replace this node with a binary node that indexes the named uniform buffer.
TIntermSymbol *namedUniformBuffer =
new TIntermSymbol(mNamelessUniformBuffersMap[block]);
TIntermBinary *replacement =
new TIntermBinary(EOpIndexDirectInterfaceBlock, namedUniformBuffer,
CreateIndexNode(static_cast<uint32_t>(fieldIndex)));
queueReplacement(replacement, OriginalNode::IS_DROPPED);
return;
}
UNREACHABLE();
}
private:
// A map from nameless uniform buffers to their named replacements.
std::unordered_map<const TInterfaceBlock *, const TVariable *> mNamelessUniformBuffersMap;
};
} // anonymous namespace
bool NameNamelessUniformBuffers(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable)
{
NameUniformBufferVariablesTraverser nameUniformBufferVariables(symbolTable);
root->traverse(&nameUniformBufferVariables);
return nameUniformBufferVariables.updateTree(compiler, root);
}
} // namespace sh
//
// Copyright 2019 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.
//
// NameNamelessUniformBuffers: Gives nameless uniform buffer variables internal names.
//
// For example:
// uniform UniformBuffer { int a; };
// x = a;
// becomes:
// uniform UniformBuffer { int a; } s123;
// x = s123.a;
//
#ifndef COMPILER_TRANSLATOR_TREEOPS_NAMENAMELESSUNIFORMBUFFERS_H_
#define COMPILER_TRANSLATOR_TREEOPS_NAMENAMELESSUNIFORMBUFFERS_H_
#include "common/angleutils.h"
namespace sh
{
class TCompiler;
class TIntermBlock;
class TSymbolTable;
ANGLE_NO_DISCARD bool NameNamelessUniformBuffers(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable);
} // namespace sh
#endif // COMPILER_TRANSLATOR_TREEOPS_NAMENAMELESSUNIFORMBUFFERS_H_
......@@ -413,7 +413,7 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
: TIntermTraverser(true, true, true, symbolTable),
mCompiler(compiler),
mStructMapOut(&mOuterPass.structMap),
mInterfaceBlockMapIn(mOuterPass.interfaceBlockMap),
mInterfaceBlockMap(&mOuterPass.interfaceBlockMap),
mInterfaceBlockFieldConvertedIn(mOuterPass.interfaceBlockFieldConverted),
mCopyFunctionDefinitionsOut(&mOuterPass.copyFunctionDefinitions),
mOuterTraverser(nullptr),
......@@ -493,15 +493,24 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
return;
}
const TVariable *symbolVariable = &symbol->variable();
const TVariable *variable = &symbol->variable();
bool needsRewrite = mInterfaceBlockMap->count(variable) != 0;
// If the symbol doesn't need to be replaced, there's nothing to do.
if (mInterfaceBlockMapIn.count(symbolVariable) == 0)
// If it's a field of a nameless interface block, it may still need conversion.
if (!needsRewrite)
{
return;
// Nameless interface block field symbols have the interface block pointer set, but are
// not interface blocks.
if (symbol->getType().getInterfaceBlock() && !variable->getType().isInterfaceBlock())
{
needsRewrite = convertNamelessInterfaceBlockField(symbol);
}
}
transformExpression(symbol);
if (needsRewrite)
{
transformExpression(symbol);
}
}
bool visitBinary(Visit visit, TIntermBinary *node) override
......@@ -527,14 +536,14 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
RewriteRowMajorMatricesTraverser(
TSymbolTable *symbolTable,
RewriteRowMajorMatricesTraverser *outerTraverser,
const InterfaceBlockMap &interfaceBlockMap,
InterfaceBlockMap *interfaceBlockMap,
const InterfaceBlockFieldConverted &interfaceBlockFieldConverted,
StructMap *structMap,
TIntermSequence *copyFunctionDefinitions,
TIntermBinary *innerPassRoot)
: TIntermTraverser(true, true, true, symbolTable),
mStructMapOut(structMap),
mInterfaceBlockMapIn(interfaceBlockMap),
mInterfaceBlockMap(interfaceBlockMap),
mInterfaceBlockFieldConvertedIn(interfaceBlockFieldConverted),
mCopyFunctionDefinitionsOut(copyFunctionDefinitions),
mOuterTraverser(outerTraverser),
......@@ -623,6 +632,66 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, newDeclarations);
}
bool convertNamelessInterfaceBlockField(TIntermSymbol *symbol)
{
const TVariable *variable = &symbol->variable();
const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
// Find the variable corresponding to this interface block. If the interface block
// is not rewritten, or this refers to a field that is not rewritten, there's
// nothing to do.
for (auto iter : *mInterfaceBlockMap)
{
// Skip other rewritten nameless interface block fields.
if (!iter.first->getType().isInterfaceBlock())
{
continue;
}
// Skip if this is not a field of this rewritten interface block.
if (iter.first->getType().getInterfaceBlock() != interfaceBlock)
{
continue;
}
const ImmutableString symbolName = symbol->getName();
// Find which field it is
const TVector<TField *> fields = interfaceBlock->fields();
for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
{
const TField *field = fields[fieldIndex];
if (field->name() != symbolName)
{
continue;
}
// If this field doesn't need a rewrite, there's nothing to do.
if (mInterfaceBlockFieldConvertedIn.count(field) == 0 ||
!mInterfaceBlockFieldConvertedIn.at(field))
{
break;
}
// Create a new variable that references the replaced interface block.
TType *newType = new TType(variable->getType());
newType->setInterfaceBlock(iter.second->getType().getInterfaceBlock());
TVariable *newVariable =
new TVariable(mSymbolTable, variable->name(), newType, variable->symbolType(),
variable->extension());
(*mInterfaceBlockMap)[variable] = newVariable;
return true;
}
break;
}
return false;
}
void convertStruct(const TStructure *structure, TIntermSequence *newDeclarations)
{
ASSERT(mInnerPassRoot == nullptr);
......@@ -789,7 +858,7 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
// See http://anglebug.com/3829.
//
TIntermTyped *baseExpression =
new TIntermSymbol(mInterfaceBlockMapIn.at(&symbol->variable()));
new TIntermSymbol(mInterfaceBlockMap->at(&symbol->variable()));
const TStructure *structure = nullptr;
TIntermNode *primaryIndex = nullptr;
......@@ -806,7 +875,10 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
// transpformation is necessary.
//
// In all these cases, |baseExpression| contains all of the original expression.
bool requiresTransformation = false;
//
// If the starting symbol itself is a field of a nameless interface block, it needs
// conversion if we reach here.
bool requiresTransformation = !symbol->getType().isInterfaceBlock();
uint32_t accessorIndex = 0;
TIntermTyped *previousAncestor = symbol;
......@@ -1009,7 +1081,7 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
RewriteRowMajorMatricesTraverser *outerTraverser =
mOuterTraverser ? mOuterTraverser : this;
RewriteRowMajorMatricesTraverser rhsTraverser(
mSymbolTable, outerTraverser, mInterfaceBlockMapIn,
mSymbolTable, outerTraverser, mInterfaceBlockMap,
mInterfaceBlockFieldConvertedIn, mStructMapOut, mCopyFunctionDefinitionsOut,
assignment);
getRootNode()->traverse(&rhsTraverser);
......@@ -1482,8 +1554,11 @@ class RewriteRowMajorMatricesTraverser : public TIntermTraverser
// A map from structures with matrices to their converted version.
StructMap *mStructMapOut;
// A map from interface block instances with row-major matrices to their converted variable.
const InterfaceBlockMap &mInterfaceBlockMapIn;
// A map from interface block instances with row-major matrices to their converted variable. If
// an interface block is nameless, its fields are placed in this map instead. When a variable
// in this map is encountered, it signals the start of an expression that my need conversion,
// which is either "interfaceBlock.field..." or "field..." if nameless.
InterfaceBlockMap *mInterfaceBlockMap;
// A map from interface block fields to whether they need to be converted. If a field was
// already column-major, it shouldn't be transposed.
const InterfaceBlockFieldConverted &mInterfaceBlockFieldConvertedIn;
......
......@@ -363,6 +363,11 @@ std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *conte
additionalOptions |= SH_REGENERATE_STRUCT_NAMES;
}
if (features.rewriteRowMajorMatrices.enabled)
{
additionalOptions |= SH_REWRITE_ROW_MAJOR_MATRICES;
}
options |= additionalOptions;
auto workerThreadPool = context->getWorkerThreadPool();
......
......@@ -1642,6 +1642,11 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature
// anglebug.com/4267
ANGLE_FEATURE_CONDITION(features, flushBeforeDeleteTextureIfCopiedTo, IsApple() && isIntel);
// anglebug.com/2273
// Seems to affect both Intel and AMD GPUs. Enable workaround for all GPUs on macOS.
ANGLE_FEATURE_CONDITION(features, rewriteRowMajorMatrices,
IsApple() && functions->standard == STANDARD_GL_DESKTOP);
}
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
......
......@@ -7481,8 +7481,9 @@ TEST_P(GLSLTest_ES3, MixedRowAndColumnMajorMatrices_ReadSideEffectOrder)
// http://anglebug.com/3837
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsOpenGL());
// Fails on Mac on Intel and AMD: http://anglebug.com/3842
ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL() && (IsIntel() || IsAMD()));
// IntermTraverser::insertStatementsInParentBlock that's used to move side effects does not
// respect the order of evaluation of logical expressions. http://anglebug.com/3829.
ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
constexpr char kFS[] = R"(#version 300 es
precision highp float;
......@@ -7542,11 +7543,9 @@ TEST_P(GLSLTest_ES3, MixedRowAndColumnMajorMatrices_ReadSideEffectShortCircuit)
// Fails on Android: http://anglebug.com/3839
ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
// Fails on Mac on Intel and AMD: http://anglebug.com/3842
ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL() && (IsIntel() || IsAMD()));
// Fails on Mac on Nvidia: http://anglebug.com/3843
ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL() && IsNVIDIA());
// IntermTraverser::insertStatementsInParentBlock that's used to move side effects does not
// respect the order of evaluation of logical expressions. http://anglebug.com/3829.
ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
constexpr char kFS[] = R"(#version 300 es
precision highp float;
......
......@@ -1176,7 +1176,7 @@ TEST_P(UniformBufferTest, Std140UniformBlockWithRowMajorQualifier)
{
// AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
// http://anglebug.com/2273
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && !IsOSX());
constexpr char kFS[] =
R"(#version 300 es
......@@ -1224,7 +1224,7 @@ TEST_P(UniformBufferTest, Std140UniformBlockWithPerMemberRowMajorQualifier)
{
// AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
// http://anglebug.com/2273
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && !IsOSX());
constexpr char kFS[] =
R"(#version 300 es
......@@ -1318,7 +1318,7 @@ TEST_P(UniformBufferTest, Std140UniformBlockWithRowMajorQualifierOnStruct)
{
// AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
// http://anglebug.com/2273
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL());
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && !IsOSX());
constexpr char kFS[] =
R"(#version 300 es
......@@ -2151,6 +2151,62 @@ TEST_P(UniformBufferTest, UniformBlocksInDiffProgramShareUniformBuffer)
}
}
// Test a uniform block where an array of row-major matrices is dynamically indexed.
TEST_P(UniformBufferTest, Std140UniformBlockWithDynamicallyIndexedRowMajorArray)
{
// http://anglebug.com/3837
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsOpenGL());
constexpr char kFS[] =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
uniform int u_zero;
layout(std140, row_major) uniform matrixBuffer {
mat4 u_mats[1];
};
void main() {
float f = u_mats[u_zero + 0][2][1];
my_FragColor = vec4(1.0 - f, f, 0.0, 1.0);
})";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
const GLsizei kElementsPerMatrix = 16; // Each mat2 row gets padded into a vec4.
const GLsizei kBytesPerElement = 4;
const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
std::vector<GLubyte> v(kDataSize, 0);
float *vAsFloat = reinterpret_cast<float *>(v.data());
// Write out this initializer to make it clearer what the matrix contains.
float matrixData[kElementsPerMatrix] = {
// clang-format off
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
// clang-format on
};
for (int ii = 0; ii < kElementsPerMatrix; ++ii)
{
vAsFloat[ii] = matrixData[ii];
}
glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
glUniformBlockBinding(program, uniformBufferIndex, 0);
GLint indexLoc = glGetUniformLocation(program, "u_zero");
glUseProgram(program);
glUniform1i(indexLoc, 0);
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0, 255, 0, 255), 5);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
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