diff options
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/gl')
8 files changed, 535 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/ClampFragDepth.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/ClampFragDepth.cpp new file mode 100644 index 0000000000..309cb14752 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/ClampFragDepth.cpp @@ -0,0 +1,54 @@ +// +// Copyright 2017 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. +// +// ClampFragDepth.cpp: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0]. +// The clamping is run at the very end of shader execution, and is only performed if the shader +// statically accesses gl_FragDepth. +// + +#include "compiler/translator/tree_ops/gl/ClampFragDepth.h" + +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/BuiltIn.h" +#include "compiler/translator/tree_util/FindSymbolNode.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/RunAtTheEndOfShader.h" + +namespace sh +{ + +bool ClampFragDepth(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable) +{ + // Only clamp gl_FragDepth if it's used in the shader. + if (!FindSymbolNode(root, ImmutableString("gl_FragDepth"))) + { + return true; + } + + TIntermSymbol *fragDepthNode = new TIntermSymbol(BuiltInVariable::gl_FragDepth()); + + TIntermTyped *minFragDepthNode = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); + + TConstantUnion *maxFragDepthConstant = new TConstantUnion(); + maxFragDepthConstant->setFConst(1.0); + TIntermConstantUnion *maxFragDepthNode = + new TIntermConstantUnion(maxFragDepthConstant, TType(EbtFloat, EbpHigh, EvqConst)); + + // clamp(gl_FragDepth, 0.0, 1.0) + TIntermSequence clampArguments; + clampArguments.push_back(fragDepthNode->deepCopy()); + clampArguments.push_back(minFragDepthNode); + clampArguments.push_back(maxFragDepthNode); + TIntermTyped *clampedFragDepth = + CreateBuiltInFunctionCallNode("clamp", &clampArguments, *symbolTable, 100); + + // gl_FragDepth = clamp(gl_FragDepth, 0.0, 1.0) + TIntermBinary *assignFragDepth = new TIntermBinary(EOpAssign, fragDepthNode, clampedFragDepth); + + return RunAtTheEndOfShader(compiler, root, assignFragDepth, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/ClampFragDepth.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/ClampFragDepth.h new file mode 100644 index 0000000000..70326c9a34 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/ClampFragDepth.h @@ -0,0 +1,39 @@ +// +// Copyright 2017 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. +// +// ClampFragDepth.h: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0]. +// The clamping is run at the very end of shader execution, and is only performed if the shader +// statically accesses gl_FragDepth. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_GL_CLAMPFRAGDEPTH_H_ +#define COMPILER_TRANSLATOR_TREEOPS_GL_CLAMPFRAGDEPTH_H_ + +#include "common/angleutils.h" + +namespace sh +{ + +class TCompiler; +class TIntermBlock; +class TSymbolTable; + +#ifdef ANGLE_ENABLE_GLSL +[[nodiscard]] bool ClampFragDepth(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable); +#else +[[nodiscard]] ANGLE_INLINE bool ClampFragDepth(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable) +{ + UNREACHABLE(); + return false; +} +#endif + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_GL_CLAMPFRAGDEPTH_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RegenerateStructNames.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RegenerateStructNames.cpp new file mode 100644 index 0000000000..e15ef32166 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RegenerateStructNames.cpp @@ -0,0 +1,119 @@ +// +// Copyright 2002 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. +// + +#include "compiler/translator/tree_ops/gl/RegenerateStructNames.h" + +#include "common/debug.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +#include <set> + +namespace sh +{ + +namespace +{ +constexpr const ImmutableString kPrefix("_webgl_struct_"); +} // anonymous namespace + +class RegenerateStructNamesTraverser : public TIntermTraverser +{ + public: + RegenerateStructNamesTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), mScopeDepth(0) + {} + + protected: + void visitSymbol(TIntermSymbol *) override; + bool visitBlock(Visit, TIntermBlock *block) override; + + private: + // Indicating the depth of the current scope. + // The global scope is 1. + int mScopeDepth; + + // If a struct is declared globally, push its ID in this set. + std::set<int> mDeclaredGlobalStructs; +}; + +void RegenerateStructNamesTraverser::visitSymbol(TIntermSymbol *symbol) +{ + ASSERT(symbol); + const TType &type = symbol->getType(); + const TStructure *userType = type.getStruct(); + if (!userType) + return; + + if (userType->symbolType() == SymbolType::BuiltIn || + userType->symbolType() == SymbolType::Empty) + { + // Built-in struct or nameless struct, do not touch it. + return; + } + + int uniqueId = userType->uniqueId().get(); + + ASSERT(mScopeDepth > 0); + if (mScopeDepth == 1) + { + // If a struct is defined at global scope, we don't map its name. + // This is because at global level, the struct might be used to + // declare a uniform, so the same name needs to stay the same for + // vertex/fragment shaders. However, our mapping uses internal ID, + // which will be different for the same struct in vertex/fragment + // shaders. + // This is OK because names for any structs defined in other scopes + // will begin with "_webgl", which is reserved. So there will be + // no conflicts among unmapped struct names from global scope and + // mapped struct names from other scopes. + // However, we need to keep track of these global structs, so if a + // variable is used in a local scope, we don't try to modify the + // struct name through that variable. + mDeclaredGlobalStructs.insert(uniqueId); + return; + } + if (mDeclaredGlobalStructs.count(uniqueId) > 0) + return; + // Map {name} to _webgl_struct_{uniqueId}_{name}. + if (userType->name().beginsWith(kPrefix)) + { + // The name has already been regenerated. + return; + } + ImmutableStringBuilder tmp(kPrefix.length() + sizeof(uniqueId) * 2u + 1u + + userType->name().length()); + tmp << kPrefix; + tmp.appendHex(uniqueId); + tmp << '_' << userType->name(); + + // TODO(oetuaho): Add another mechanism to change symbol names so that the const_cast is not + // needed. + const_cast<TStructure *>(userType)->setName(tmp); +} + +bool RegenerateStructNamesTraverser::visitBlock(Visit, TIntermBlock *block) +{ + ++mScopeDepth; + TIntermSequence &sequence = *(block->getSequence()); + for (TIntermNode *node : sequence) + { + node->traverse(this); + } + --mScopeDepth; + return false; +} + +bool RegenerateStructNames(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable) +{ + RegenerateStructNamesTraverser traverser(symbolTable); + root->traverse(&traverser); + return compiler->validateAST(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RegenerateStructNames.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RegenerateStructNames.h new file mode 100644 index 0000000000..04cfe6a476 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RegenerateStructNames.h @@ -0,0 +1,34 @@ +// +// Copyright 2002 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. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_GL_REGENERATESTRUCTNAMES_H_ +#define COMPILER_TRANSLATOR_TREEOPS_GL_REGENERATESTRUCTNAMES_H_ + +#include "common/angleutils.h" + +namespace sh +{ +class TCompiler; +class TIntermBlock; +class TSymbolTable; + +#if defined(ANGLE_ENABLE_GLSL) +[[nodiscard]] bool RegenerateStructNames(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable); +#else +[[nodiscard]] ANGLE_INLINE bool RegenerateStructNames(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable) +{ + UNREACHABLE(); + return false; +} +#endif + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_GL_REGENERATESTRUCTNAMES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.cpp new file mode 100644 index 0000000000..83a0f029b8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.cpp @@ -0,0 +1,97 @@ +// +// Copyright 2018 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RewriteRepeatedAssignToSwizzled.cpp: Rewrite expressions that assign an assignment to a swizzled +// vector, like: +// v.x = z = expression; +// to: +// z = expression; +// v.x = z; +// +// Note that this doesn't handle some corner cases: expressions nested inside other expressions, +// inside loop headers, or inside if conditions. + +#include "compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.h" + +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class RewriteAssignToSwizzledTraverser : public TIntermTraverser +{ + public: + [[nodiscard]] static bool rewrite(TCompiler *compiler, TIntermBlock *root); + + private: + RewriteAssignToSwizzledTraverser(); + + bool visitBinary(Visit, TIntermBinary *node) override; + + void nextIteration(); + + bool didRewrite() { return mDidRewrite; } + + bool mDidRewrite; +}; + +// static +bool RewriteAssignToSwizzledTraverser::rewrite(TCompiler *compiler, TIntermBlock *root) +{ + RewriteAssignToSwizzledTraverser rewrite; + do + { + rewrite.nextIteration(); + root->traverse(&rewrite); + if (!rewrite.updateTree(compiler, root)) + { + return false; + } + } while (rewrite.didRewrite()); + + return true; +} + +RewriteAssignToSwizzledTraverser::RewriteAssignToSwizzledTraverser() + : TIntermTraverser(true, false, false), mDidRewrite(false) +{} + +void RewriteAssignToSwizzledTraverser::nextIteration() +{ + mDidRewrite = false; +} + +bool RewriteAssignToSwizzledTraverser::visitBinary(Visit, TIntermBinary *node) +{ + TIntermBinary *rightBinary = node->getRight()->getAsBinaryNode(); + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + if (parentBlock && node->isAssignment() && node->getLeft()->getAsSwizzleNode() && rightBinary && + rightBinary->isAssignment()) + { + TIntermSequence replacements; + replacements.push_back(rightBinary); + TIntermTyped *rightAssignmentTargetCopy = rightBinary->getLeft()->deepCopy(); + TIntermBinary *lastAssign = + new TIntermBinary(EOpAssign, node->getLeft(), rightAssignmentTargetCopy); + replacements.push_back(lastAssign); + mMultiReplacements.emplace_back(parentBlock, node, std::move(replacements)); + mDidRewrite = true; + return false; + } + return true; +} + +} // anonymous namespace + +bool RewriteRepeatedAssignToSwizzled(TCompiler *compiler, TIntermBlock *root) +{ + return RewriteAssignToSwizzledTraverser::rewrite(compiler, root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.h new file mode 100644 index 0000000000..1ab9b7ebb8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/RewriteRepeatedAssignToSwizzled.h @@ -0,0 +1,40 @@ +// +// Copyright 2018 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RewriteRepeatedAssignToSwizzled.h: Rewrite expressions that assign an assignment to a swizzled +// vector, like: +// v.x = z = expression; +// to: +// z = expression; +// v.x = z; +// +// Note that this doesn't handle some corner cases: expressions nested inside other expressions, +// inside loop headers, or inside if conditions. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_GL_REWRITEREPEATEDASSIGNTOSWIZZLED_H_ +#define COMPILER_TRANSLATOR_TREEOPS_GL_REWRITEREPEATEDASSIGNTOSWIZZLED_H_ + +#include "common/angleutils.h" + +namespace sh +{ + +class TCompiler; +class TIntermBlock; + +#ifdef ANGLE_ENABLE_GLSL +[[nodiscard]] bool RewriteRepeatedAssignToSwizzled(TCompiler *compiler, TIntermBlock *root); +#else +[[nodiscard]] ANGLE_INLINE bool RewriteRepeatedAssignToSwizzled(TCompiler *compiler, + TIntermBlock *root) +{ + UNREACHABLE(); + return false; +} +#endif + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_GL_REWRITEREPEATEDASSIGNTOSWIZZLED_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.cpp new file mode 100644 index 0000000000..e94ca2fd17 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.cpp @@ -0,0 +1,108 @@ +// +// Copyright 2016 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. +// + +// UseInterfaceBlockFields.cpp: insert statements to reference all members in InterfaceBlock list at +// the beginning of main. This is to work around a Mac driver that treats unused standard/shared +// uniform blocks as inactive. + +#include "compiler/translator/tree_ops/gl/UseInterfaceBlockFields.h" + +#include "compiler/translator/Compiler.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/FindMain.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +void AddNodeUseStatements(TIntermTyped *node, TIntermSequence *sequence) +{ + if (node->isArray()) + { + for (unsigned int i = 0u; i < node->getOutermostArraySize(); ++i) + { + TIntermBinary *element = + new TIntermBinary(EOpIndexDirect, node->deepCopy(), CreateIndexNode(i)); + AddNodeUseStatements(element, sequence); + } + } + else + { + sequence->insert(sequence->begin(), node); + } +} + +void AddFieldUseStatements(const ShaderVariable &var, + TIntermSequence *sequence, + const TSymbolTable &symbolTable) +{ + ASSERT(var.name.find_last_of('[') == std::string::npos); + TIntermSymbol *symbol = ReferenceGlobalVariable(ImmutableString(var.name), symbolTable); + AddNodeUseStatements(symbol, sequence); +} + +void InsertUseCode(const InterfaceBlock &block, TIntermTyped *blockNode, TIntermSequence *sequence) +{ + for (unsigned int i = 0; i < block.fields.size(); ++i) + { + TIntermBinary *element = new TIntermBinary(EOpIndexDirectInterfaceBlock, + blockNode->deepCopy(), CreateIndexNode(i)); + sequence->insert(sequence->begin(), element); + } +} + +void InsertUseCode(TIntermSequence *sequence, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable) +{ + for (const auto &block : blocks) + { + if (block.instanceName.empty()) + { + for (const auto &var : block.fields) + { + AddFieldUseStatements(var, sequence, symbolTable); + } + } + else if (block.arraySize > 0u) + { + TIntermSymbol *arraySymbol = + ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable); + for (unsigned int i = 0u; i < block.arraySize; ++i) + { + TIntermBinary *elementSymbol = + new TIntermBinary(EOpIndexDirect, arraySymbol->deepCopy(), CreateIndexNode(i)); + InsertUseCode(block, elementSymbol, sequence); + } + } + else + { + TIntermSymbol *blockSymbol = + ReferenceGlobalVariable(ImmutableString(block.instanceName), symbolTable); + InsertUseCode(block, blockSymbol, sequence); + } + } +} + +} // namespace + +bool UseInterfaceBlockFields(TCompiler *compiler, + TIntermBlock *root, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable) +{ + TIntermBlock *mainBody = FindMainBody(root); + InsertUseCode(mainBody->getSequence(), blocks, symbolTable); + + return compiler->validateAST(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.h new file mode 100644 index 0000000000..a4f5f3e5e6 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/gl/UseInterfaceBlockFields.h @@ -0,0 +1,44 @@ +// +// Copyright 2016 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. +// + +// UseInterfaceBlockFields.h: insert statements to reference all members in InterfaceBlock list at +// the beginning of main. This is to work around a Mac driver that treats unused standard/shared +// uniform blocks as inactive. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_GL_USEINTERFACEBLOCKFIELDS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_GL_USEINTERFACEBLOCKFIELDS_H_ + +#include <GLSLANG/ShaderLang.h> +#include "common/angleutils.h" + +namespace sh +{ + +class TCompiler; +class TIntermBlock; +class TSymbolTable; + +using InterfaceBlockList = std::vector<sh::InterfaceBlock>; + +#ifdef ANGLE_ENABLE_GLSL +[[nodiscard]] bool UseInterfaceBlockFields(TCompiler *compiler, + TIntermBlock *root, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable); +#else +[[nodiscard]] ANGLE_INLINE bool UseInterfaceBlockFields(TCompiler *compiler, + TIntermBlock *root, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable) +{ + UNREACHABLE(); + return false; +} +#endif + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_GL_USEINTERFACEBLOCKFIELDS_H_ |