diff options
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator')
253 files changed, 90338 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp new file mode 100644 index 0000000000..e2d4df3d5a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp @@ -0,0 +1,461 @@ +// +// Copyright (c) 2002-2015 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. +// + +// Analysis of the AST needed for HLSL generation + +#include "compiler/translator/ASTMetadataHLSL.h" + +#include "compiler/translator/CallDAG.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// Class used to traverse the AST of a function definition, checking if the +// function uses a gradient, and writing the set of control flow using gradients. +// It assumes that the analysis has already been made for the function's +// callees. +class PullGradient : public TIntermTraverser +{ + public: + PullGradient(MetadataList *metadataList, size_t index, const CallDAG &dag) + : TIntermTraverser(true, false, true), + mMetadataList(metadataList), + mMetadata(&(*metadataList)[index]), + mIndex(index), + mDag(dag) + { + ASSERT(index < metadataList->size()); + + // ESSL 100 builtin gradient functions + mGradientBuiltinFunctions.insert(ImmutableString("texture2D")); + mGradientBuiltinFunctions.insert(ImmutableString("texture2DProj")); + mGradientBuiltinFunctions.insert(ImmutableString("textureCube")); + + // ESSL 300 builtin gradient functions + mGradientBuiltinFunctions.insert(ImmutableString("texture")); + mGradientBuiltinFunctions.insert(ImmutableString("textureProj")); + mGradientBuiltinFunctions.insert(ImmutableString("textureOffset")); + mGradientBuiltinFunctions.insert(ImmutableString("textureProjOffset")); + + // ESSL 310 doesn't add builtin gradient functions + } + + void traverse(TIntermFunctionDefinition *node) + { + node->traverse(this); + ASSERT(mParents.empty()); + } + + // Called when a gradient operation or a call to a function using a gradient is found. + void onGradient() + { + mMetadata->mUsesGradient = true; + // Mark the latest control flow as using a gradient. + if (!mParents.empty()) + { + mMetadata->mControlFlowsContainingGradient.insert(mParents.back()); + } + } + + void visitControlFlow(Visit visit, TIntermNode *node) + { + if (visit == PreVisit) + { + mParents.push_back(node); + } + else if (visit == PostVisit) + { + ASSERT(mParents.back() == node); + mParents.pop_back(); + // A control flow's using a gradient means its parents are too. + if (mMetadata->mControlFlowsContainingGradient.count(node) > 0 && !mParents.empty()) + { + mMetadata->mControlFlowsContainingGradient.insert(mParents.back()); + } + } + } + + bool visitLoop(Visit visit, TIntermLoop *loop) override + { + visitControlFlow(visit, loop); + return true; + } + + bool visitIfElse(Visit visit, TIntermIfElse *ifElse) override + { + visitControlFlow(visit, ifElse); + return true; + } + + bool visitUnary(Visit visit, TIntermUnary *node) override + { + if (visit == PreVisit) + { + switch (node->getOp()) + { + case EOpDFdx: + case EOpDFdy: + case EOpFwidth: + onGradient(); + break; + default: + break; + } + } + + return true; + } + + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + if (visit == PreVisit) + { + if (node->getOp() == EOpCallFunctionInAST) + { + size_t calleeIndex = mDag.findIndex(node->getFunction()->uniqueId()); + ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); + + if ((*mMetadataList)[calleeIndex].mUsesGradient) + { + onGradient(); + } + } + else if (node->getOp() == EOpCallBuiltInFunction) + { + if (mGradientBuiltinFunctions.find(node->getFunction()->name()) != + mGradientBuiltinFunctions.end()) + { + onGradient(); + } + } + } + + return true; + } + + private: + MetadataList *mMetadataList; + ASTMetadataHLSL *mMetadata; + size_t mIndex; + const CallDAG &mDag; + + // Contains a stack of the control flow nodes that are parents of the node being + // currently visited. It is used to mark control flows using a gradient. + std::vector<TIntermNode *> mParents; + + // A list of builtin functions that use gradients + std::set<ImmutableString> mGradientBuiltinFunctions; +}; + +// Traverses the AST of a function definition to compute the the discontinuous loops +// and the if statements containing gradient loops. It assumes that the gradient loops +// (loops that contain a gradient) have already been computed and that it has already +// traversed the current function's callees. +class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser +{ + public: + PullComputeDiscontinuousAndGradientLoops(MetadataList *metadataList, + size_t index, + const CallDAG &dag) + : TIntermTraverser(true, false, true), + mMetadataList(metadataList), + mMetadata(&(*metadataList)[index]), + mIndex(index), + mDag(dag) + {} + + void traverse(TIntermFunctionDefinition *node) + { + node->traverse(this); + ASSERT(mLoopsAndSwitches.empty()); + ASSERT(mIfs.empty()); + } + + // Called when traversing a gradient loop or a call to a function with a + // gradient loop in its call graph. + void onGradientLoop() + { + mMetadata->mHasGradientLoopInCallGraph = true; + // Mark the latest if as using a discontinuous loop. + if (!mIfs.empty()) + { + mMetadata->mIfsContainingGradientLoop.insert(mIfs.back()); + } + } + + bool visitLoop(Visit visit, TIntermLoop *loop) override + { + if (visit == PreVisit) + { + mLoopsAndSwitches.push_back(loop); + + if (mMetadata->hasGradientInCallGraph(loop)) + { + onGradientLoop(); + } + } + else if (visit == PostVisit) + { + ASSERT(mLoopsAndSwitches.back() == loop); + mLoopsAndSwitches.pop_back(); + } + + return true; + } + + bool visitIfElse(Visit visit, TIntermIfElse *node) override + { + if (visit == PreVisit) + { + mIfs.push_back(node); + } + else if (visit == PostVisit) + { + ASSERT(mIfs.back() == node); + mIfs.pop_back(); + // An if using a discontinuous loop means its parents ifs are also discontinuous. + if (mMetadata->mIfsContainingGradientLoop.count(node) > 0 && !mIfs.empty()) + { + mMetadata->mIfsContainingGradientLoop.insert(mIfs.back()); + } + } + + return true; + } + + bool visitBranch(Visit visit, TIntermBranch *node) override + { + if (visit == PreVisit) + { + switch (node->getFlowOp()) + { + case EOpBreak: + { + ASSERT(!mLoopsAndSwitches.empty()); + TIntermLoop *loop = mLoopsAndSwitches.back()->getAsLoopNode(); + if (loop != nullptr) + { + mMetadata->mDiscontinuousLoops.insert(loop); + } + } + break; + case EOpContinue: + { + ASSERT(!mLoopsAndSwitches.empty()); + TIntermLoop *loop = nullptr; + size_t i = mLoopsAndSwitches.size(); + while (loop == nullptr && i > 0) + { + --i; + loop = mLoopsAndSwitches.at(i)->getAsLoopNode(); + } + ASSERT(loop != nullptr); + mMetadata->mDiscontinuousLoops.insert(loop); + } + break; + case EOpKill: + case EOpReturn: + // A return or discard jumps out of all the enclosing loops + if (!mLoopsAndSwitches.empty()) + { + for (TIntermNode *intermNode : mLoopsAndSwitches) + { + TIntermLoop *loop = intermNode->getAsLoopNode(); + if (loop) + { + mMetadata->mDiscontinuousLoops.insert(loop); + } + } + } + break; + default: + UNREACHABLE(); + } + } + + return true; + } + + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + if (visit == PreVisit && node->getOp() == EOpCallFunctionInAST) + { + size_t calleeIndex = mDag.findIndex(node->getFunction()->uniqueId()); + ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); + + if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph) + { + onGradientLoop(); + } + } + + return true; + } + + bool visitSwitch(Visit visit, TIntermSwitch *node) override + { + if (visit == PreVisit) + { + mLoopsAndSwitches.push_back(node); + } + else if (visit == PostVisit) + { + ASSERT(mLoopsAndSwitches.back() == node); + mLoopsAndSwitches.pop_back(); + } + return true; + } + + private: + MetadataList *mMetadataList; + ASTMetadataHLSL *mMetadata; + size_t mIndex; + const CallDAG &mDag; + + std::vector<TIntermNode *> mLoopsAndSwitches; + std::vector<TIntermIfElse *> mIfs; +}; + +// Tags all the functions called in a discontinuous loop +class PushDiscontinuousLoops : public TIntermTraverser +{ + public: + PushDiscontinuousLoops(MetadataList *metadataList, size_t index, const CallDAG &dag) + : TIntermTraverser(true, true, true), + mMetadataList(metadataList), + mMetadata(&(*metadataList)[index]), + mIndex(index), + mDag(dag), + mNestedDiscont(mMetadata->mCalledInDiscontinuousLoop ? 1 : 0) + {} + + void traverse(TIntermFunctionDefinition *node) + { + node->traverse(this); + ASSERT(mNestedDiscont == (mMetadata->mCalledInDiscontinuousLoop ? 1 : 0)); + } + + bool visitLoop(Visit visit, TIntermLoop *loop) override + { + bool isDiscontinuous = mMetadata->mDiscontinuousLoops.count(loop) > 0; + + if (visit == PreVisit && isDiscontinuous) + { + mNestedDiscont++; + } + else if (visit == PostVisit && isDiscontinuous) + { + mNestedDiscont--; + } + + return true; + } + + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + switch (node->getOp()) + { + case EOpCallFunctionInAST: + if (visit == PreVisit && mNestedDiscont > 0) + { + size_t calleeIndex = mDag.findIndex(node->getFunction()->uniqueId()); + ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex); + + (*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true; + } + break; + default: + break; + } + return true; + } + + private: + MetadataList *mMetadataList; + ASTMetadataHLSL *mMetadata; + size_t mIndex; + const CallDAG &mDag; + + int mNestedDiscont; +}; +} // namespace + +bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node) +{ + return mControlFlowsContainingGradient.count(node) > 0; +} + +bool ASTMetadataHLSL::hasGradientLoop(TIntermIfElse *node) +{ + return mIfsContainingGradientLoop.count(node) > 0; +} + +MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag) +{ + MetadataList metadataList(callDag.size()); + + // Compute all the information related to when gradient operations are used. + // We want to know for each function and control flow operation if they have + // a gradient operation in their call graph (shortened to "using a gradient" + // in the rest of the file). + // + // This computation is logically split in three steps: + // 1 - For each function compute if it uses a gradient in its body, ignoring + // calls to other user-defined functions. + // 2 - For each function determine if it uses a gradient in its call graph, + // using the result of step 1 and the CallDAG to know its callees. + // 3 - For each control flow statement of each function, check if it uses a + // gradient in the function's body, or if it calls a user-defined function that + // uses a gradient. + // + // We take advantage of the call graph being a DAG and instead compute 1, 2 and 3 + // for leaves first, then going down the tree. This is correct because 1 doesn't + // depend on other functions, and 2 and 3 depend only on callees. + for (size_t i = 0; i < callDag.size(); i++) + { + PullGradient pull(&metadataList, i, callDag); + pull.traverse(callDag.getRecordFromIndex(i).node); + } + + // Compute which loops are discontinuous and which function are called in + // these loops. The same way computing gradient usage is a "pull" process, + // computing "bing used in a discont. loop" is a push process. However we also + // need to know what ifs have a discontinuous loop inside so we do the same type + // of callgraph analysis as for the gradient. + + // First compute which loops are discontinuous (no specific order) and pull + // the ifs and functions using a gradient loop. + for (size_t i = 0; i < callDag.size(); i++) + { + PullComputeDiscontinuousAndGradientLoops pull(&metadataList, i, callDag); + pull.traverse(callDag.getRecordFromIndex(i).node); + } + + // Then push the information to callees, either from the a local discontinuous + // loop or from the caller being called in a discontinuous loop already + for (size_t i = callDag.size(); i-- > 0;) + { + PushDiscontinuousLoops push(&metadataList, i, callDag); + push.traverse(callDag.getRecordFromIndex(i).node); + } + + // We create "Lod0" version of functions with the gradient operations replaced + // by non-gradient operations so that the D3D compiler is happier with discont + // loops. + for (auto &metadata : metadataList) + { + metadata.mNeedsLod0 = metadata.mCalledInDiscontinuousLoop && metadata.mUsesGradient; + } + + return metadataList; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.h b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.h new file mode 100644 index 0000000000..da00faabeb --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2002-2015 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. +// + +// Defines analyses of the AST needed for HLSL generation + +#ifndef COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_ +#define COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_ + +#include <set> +#include <vector> + +namespace sh +{ + +class CallDAG; +class TIntermNode; +class TIntermIfElse; +class TIntermLoop; + +struct ASTMetadataHLSL +{ + ASTMetadataHLSL() + : mUsesGradient(false), + mCalledInDiscontinuousLoop(false), + mHasGradientLoopInCallGraph(false), + mNeedsLod0(false) + {} + + // Here "something uses a gradient" means here that it either contains a + // gradient operation, or a call to a function that uses a gradient. + bool hasGradientInCallGraph(TIntermLoop *node); + bool hasGradientLoop(TIntermIfElse *node); + + // Does the function use a gradient. + bool mUsesGradient; + + // Even if usesGradient is true, some control flow might not use a gradient + // so we store the set of all gradient-using control flows. + std::set<TIntermNode *> mControlFlowsContainingGradient; + + // Remember information about the discontinuous loops and which functions + // are called in such loops. + bool mCalledInDiscontinuousLoop; + bool mHasGradientLoopInCallGraph; + std::set<TIntermLoop *> mDiscontinuousLoops; + std::set<TIntermIfElse *> mIfsContainingGradientLoop; + + // Will we need to generate a Lod0 version of the function. + bool mNeedsLod0; +}; + +typedef std::vector<ASTMetadataHLSL> MetadataList; + +// Return the AST analysis result, in the order defined by the call DAG +MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.cpp new file mode 100644 index 0000000000..52b8b878c3 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.cpp @@ -0,0 +1,112 @@ +// +// Copyright (c) 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. +// +// AtomicCounterFunctionHLSL: Class for writing implementation of atomic counter functions into HLSL +// output. +// + +#include "compiler/translator/AtomicCounterFunctionHLSL.h" + +#include "compiler/translator/Common.h" +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +namespace +{ +constexpr ImmutableString kAtomicCounter("atomicCounter"); +constexpr ImmutableString kAtomicCounterIncrement("atomicCounterIncrement"); +constexpr ImmutableString kAtomicCounterDecrement("atomicCounterDecrement"); +constexpr ImmutableString kAtomicCounterBaseName("_acbase_"); +} // namespace + +AtomicCounterFunctionHLSL::AtomicCounterFunctionHLSL(bool forceResolution) + : mForceResolution(forceResolution) +{} + +ImmutableString AtomicCounterFunctionHLSL::useAtomicCounterFunction(const ImmutableString &name) +{ + // The largest string that will be create created is "_acbase_increment" or "_acbase_decrement" + ImmutableStringBuilder hlslFunctionNameSB(kAtomicCounterBaseName.length() + + strlen("increment")); + hlslFunctionNameSB << kAtomicCounterBaseName; + + AtomicCounterFunction atomicMethod; + if (kAtomicCounter == name) + { + atomicMethod = AtomicCounterFunction::LOAD; + hlslFunctionNameSB << "load"; + } + else if (kAtomicCounterIncrement == name) + { + atomicMethod = AtomicCounterFunction::INCREMENT; + hlslFunctionNameSB << "increment"; + } + else if (kAtomicCounterDecrement == name) + { + atomicMethod = AtomicCounterFunction::DECREMENT; + hlslFunctionNameSB << "decrement"; + } + else + { + atomicMethod = AtomicCounterFunction::INVALID; + UNREACHABLE(); + } + + ImmutableString hlslFunctionName(hlslFunctionNameSB); + mAtomicCounterFunctions[hlslFunctionName] = atomicMethod; + + return hlslFunctionName; +} + +void AtomicCounterFunctionHLSL::atomicCounterFunctionHeader(TInfoSinkBase &out) +{ + for (auto &atomicFunction : mAtomicCounterFunctions) + { + out << "uint " << atomicFunction.first + << "(in RWByteAddressBuffer counter, int address)\n" + "{\n" + " uint ret;\n"; + + switch (atomicFunction.second) + { + case AtomicCounterFunction::INCREMENT: + out << " counter.InterlockedAdd(address, 1u, ret);\n"; + break; + case AtomicCounterFunction::DECREMENT: + out << " counter.InterlockedAdd(address, 0u - 1u, ret);\n" + " ret -= 1u;\n"; // atomicCounterDecrement is a post-decrement op + break; + case AtomicCounterFunction::LOAD: + out << " ret = counter.Load(address);\n"; + break; + default: + UNREACHABLE(); + break; + } + + if (mForceResolution && atomicFunction.second != AtomicCounterFunction::LOAD) + { + out << " if (ret == 0) {\n" + " ret = 0 - ret;\n" + " }\n"; + } + + out << " return ret;\n" + "}\n\n"; + } +} + +ImmutableString getAtomicCounterNameForBinding(int binding) +{ + std::stringstream counterName = sh::InitializeStream<std::stringstream>(); + counterName << kAtomicCounterBaseName << binding; + return ImmutableString(counterName.str()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.h new file mode 100644 index 0000000000..e658df3c20 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/AtomicCounterFunctionHLSL.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 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. +// +// AtomicCounterFunctionHLSL: Class for writing implementation of atomic counter functions into HLSL +// output. +// + +#ifndef COMPILER_TRANSLATOR_ATOMICCOUNTERFUNCTIONHLSL_H_ +#define COMPILER_TRANSLATOR_ATOMICCOUNTERFUNCTIONHLSL_H_ + +#include <map> + +#include "compiler/translator/Common.h" +#include "compiler/translator/ImmutableString.h" + +namespace sh +{ + +class TInfoSinkBase; +struct TLayoutQualifier; + +class AtomicCounterFunctionHLSL final : angle::NonCopyable +{ + public: + AtomicCounterFunctionHLSL(bool forceResolution); + + ImmutableString useAtomicCounterFunction(const ImmutableString &name); + + void atomicCounterFunctionHeader(TInfoSinkBase &out); + + private: + enum class AtomicCounterFunction + { + LOAD, + INCREMENT, + DECREMENT, + INVALID + }; + + std::map<ImmutableString, AtomicCounterFunction> mAtomicCounterFunctions; + bool mForceResolution; +}; + +ImmutableString getAtomicCounterNameForBinding(int binding); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ATOMICCOUNTERFUNCTIONHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/BaseTypes.h b/gfx/angle/checkout/src/compiler/translator/BaseTypes.h new file mode 100644 index 0000000000..555910fa72 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/BaseTypes.h @@ -0,0 +1,1086 @@ +// +// Copyright (c) 2002-2013 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_BASETYPES_H_ +#define COMPILER_TRANSLATOR_BASETYPES_H_ + +#include <algorithm> +#include <array> + +#include "GLSLANG/ShaderLang.h" +#include "common/debug.h" +#include "compiler/translator/ImmutableString.h" + +namespace sh +{ + +// +// Precision qualifiers +// +enum TPrecision +{ + // These need to be kept sorted + EbpUndefined, + EbpLow, + EbpMedium, + EbpHigh, + + // end of list + EbpLast +}; + +inline const char *getPrecisionString(TPrecision p) +{ + switch (p) + { + case EbpHigh: + return "highp"; + case EbpMedium: + return "mediump"; + case EbpLow: + return "lowp"; + default: + return "mediump"; // Safest fallback + } +} + +// +// Basic type. Arrays, vectors, etc., are orthogonal to this. +// +enum TBasicType +{ + EbtVoid, + EbtFloat, + EbtInt, + EbtUInt, + EbtBool, + + EbtAtomicCounter, + EbtYuvCscStandardEXT, // Only valid if EXT_YUV_target exists. + + EbtGuardSamplerBegin, // non type: see implementation of IsSampler() + EbtSampler2D = EbtGuardSamplerBegin, + EbtSampler3D, + EbtSamplerCube, + EbtSampler2DArray, + EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists. + EbtSamplerExternal2DY2YEXT, // Only valid if GL_EXT_YUV_target exists. + EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists. + EbtSampler2DMS, + EbtSampler2DMSArray, + EbtISampler2D, + EbtISampler3D, + EbtISamplerCube, + EbtISampler2DArray, + EbtISampler2DMS, + EbtISampler2DMSArray, + EbtUSampler2D, + EbtUSampler3D, + EbtUSamplerCube, + EbtUSampler2DArray, + EbtUSampler2DMS, + EbtUSampler2DMSArray, + EbtSampler2DShadow, + EbtSamplerCubeShadow, + EbtSampler2DArrayShadow, + EbtGuardSamplerEnd = EbtSampler2DArrayShadow, // non type: see implementation of IsSampler() + + // images + EbtGuardImageBegin, + EbtImage2D = EbtGuardImageBegin, + EbtIImage2D, + EbtUImage2D, + EbtImage3D, + EbtIImage3D, + EbtUImage3D, + EbtImage2DArray, + EbtIImage2DArray, + EbtUImage2DArray, + EbtImageCube, + EbtIImageCube, + EbtUImageCube, + EbtGuardImageEnd = EbtUImageCube, + + EbtLastSimpleType = EbtGuardImageEnd, + + EbtStruct, + EbtInterfaceBlock, + + // end of list + EbtLast = EbtInterfaceBlock +}; + +constexpr char GetBasicMangledName(TBasicType t) +{ + if (t > EbtLastSimpleType) + { + return '{'; + } + static_assert(EbtLastSimpleType < 52, "We only use alphabetic characters for mangled names"); + if (t < 26) + { + return static_cast<char>('A' + t); + } + return static_cast<char>('a' - 26 + t); +} + +const char *getBasicString(TBasicType t); + +inline bool IsSampler(TBasicType type) +{ + return type >= EbtGuardSamplerBegin && type <= EbtGuardSamplerEnd; +} + +inline bool IsImage(TBasicType type) +{ + return type >= EbtGuardImageBegin && type <= EbtGuardImageEnd; +} + +inline bool IsAtomicCounter(TBasicType type) +{ + return type == EbtAtomicCounter; +} + +inline bool IsOpaqueType(TBasicType type) +{ + return IsSampler(type) || IsImage(type) || IsAtomicCounter(type); +} + +inline bool IsIntegerSampler(TBasicType type) +{ + switch (type) + { + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtISampler2DMSArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtUSampler2DMSArray: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + case EbtSampler2DMS: + case EbtSampler2DMSArray: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsIntegerSamplerUnsigned(TBasicType type) +{ + switch (type) + { + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtISampler2DMSArray: + return false; + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtUSampler2DMSArray: + return true; + default: + assert(!IsIntegerSampler(type)); + } + + return false; +} + +inline bool IsSampler2DMS(TBasicType type) +{ + switch (type) + { + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return true; + default: + return false; + } +} + +inline bool IsSampler2DMSArray(TBasicType type) +{ + switch (type) + { + case EbtSampler2DMSArray: + case EbtISampler2DMSArray: + case EbtUSampler2DMSArray: + return true; + default: + return false; + } +} + +inline bool IsFloatImage(TBasicType type) +{ + switch (type) + { + case EbtImage2D: + case EbtImage3D: + case EbtImage2DArray: + case EbtImageCube: + return true; + default: + break; + } + + return false; +} + +inline bool IsIntegerImage(TBasicType type) +{ + + switch (type) + { + case EbtIImage2D: + case EbtIImage3D: + case EbtIImage2DArray: + case EbtIImageCube: + return true; + default: + break; + } + + return false; +} + +inline bool IsUnsignedImage(TBasicType type) +{ + + switch (type) + { + case EbtUImage2D: + case EbtUImage3D: + case EbtUImage2DArray: + case EbtUImageCube: + return true; + default: + break; + } + + return false; +} + +// Samplers are divided into 4 disjoint categories: 2D, cube, 3D, and array. +// Array samplers are not 2D samplers. +inline bool IsSampler2D(TBasicType type) +{ + switch (type) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DShadow: + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return true; + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DMSArray: + case EbtISampler2DMSArray: + case EbtUSampler2DMSArray: + case EbtSampler2DArrayShadow: + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSamplerCubeShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSamplerCube(TBasicType type) +{ + switch (type) + { + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DMS: + case EbtSampler2DMSArray: + case EbtISampler2D: + case EbtISampler3D: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtISampler2DMSArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtUSampler2DMSArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSampler3D(TBasicType type) +{ + switch (type) + { + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + return true; + case EbtSampler2D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DMS: + case EbtSampler2DMSArray: + case EbtISampler2D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtISampler2DMSArray: + case EbtUSampler2D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtUSampler2DMSArray: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSamplerArray(TBasicType type) +{ + switch (type) + { + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DMSArray: + case EbtISampler2DMSArray: + case EbtUSampler2DMSArray: + case EbtSampler2DArrayShadow: + return true; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsShadowSampler(TBasicType type) +{ + switch (type) + { + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return true; + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtISampler2DMS: + case EbtISampler2DMSArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtUSampler2DMS: + case EbtUSampler2DMSArray: + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSamplerExternal2DY2YEXT: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DMS: + case EbtSampler2DMSArray: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsImage2D(TBasicType type) +{ + switch (type) + { + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + return true; + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return false; + default: + assert(!IsImage(type)); + } + + return false; +} + +inline bool IsImage3D(TBasicType type) +{ + switch (type) + { + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + return true; + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return false; + default: + assert(!IsImage(type)); + } + + return false; +} + +inline bool IsImage2DArray(TBasicType type) +{ + switch (type) + { + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + return true; + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return false; + default: + assert(!IsImage(type)); + } + + return false; +} + +inline bool IsImageCube(TBasicType type) +{ + switch (type) + { + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return true; + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + return false; + default: + assert(!IsImage(type)); + } + + return false; +} + +inline bool IsInteger(TBasicType type) +{ + return type == EbtInt || type == EbtUInt; +} + +inline bool SupportsPrecision(TBasicType type) +{ + return type == EbtFloat || type == EbtInt || type == EbtUInt || IsOpaqueType(type); +} + +// +// Qualifiers and built-ins. These are mainly used to see what can be read +// or written, and by the machine dependent translator to know which registers +// to allocate variables in. Since built-ins tend to go to different registers +// than varying or uniform, it makes sense they are peers, not sub-classes. +// +enum TQualifier +{ + EvqTemporary, // For temporaries (within a function), read/write + EvqGlobal, // For globals read/write + EvqConst, // User defined constants and non-output parameters in functions + EvqAttribute, // Readonly + EvqVaryingIn, // readonly, fragment shaders only + EvqVaryingOut, // vertex shaders only read/write + EvqUniform, // Readonly, vertex and fragment + EvqBuffer, // read/write, vertex, fragment and compute shader + + EvqVertexIn, // Vertex shader input + EvqFragmentOut, // Fragment shader output + EvqVertexOut, // Vertex shader output + EvqFragmentIn, // Fragment shader input + + // parameters + EvqIn, + EvqOut, + EvqInOut, + EvqConstReadOnly, + + // built-ins read by vertex shader + EvqInstanceID, + EvqVertexID, + + // built-ins written by vertex shader + EvqPosition, + EvqPointSize, + + EvqDrawID, // ANGLE_multi_draw + + EvqBaseVertex, // ANGLE_base_vertex_base_instance + EvqBaseInstance, // ANGLE_base_vertex_base_instance + + // built-ins read by fragment shader + EvqFragCoord, + EvqFrontFacing, + EvqPointCoord, + + // built-ins written by fragment shader + EvqFragColor, + EvqFragData, + + EvqFragDepth, // gl_FragDepth for ESSL300. + EvqFragDepthEXT, // gl_FragDepthEXT for ESSL100, EXT_frag_depth. + + EvqSecondaryFragColorEXT, // EXT_blend_func_extended + EvqSecondaryFragDataEXT, // EXT_blend_func_extended + + EvqViewIDOVR, // OVR_multiview + EvqViewportIndex, // gl_ViewportIndex + + // built-ins written by the shader_framebuffer_fetch extension(s) + EvqLastFragColor, + EvqLastFragData, + + // GLSL ES 3.0 vertex output and fragment input + EvqSmooth, // Incomplete qualifier, smooth is the default + EvqFlat, // Incomplete qualifier + EvqCentroid, // Incomplete qualifier + EvqSmoothOut, + EvqFlatOut, + EvqCentroidOut, // Implies smooth + EvqSmoothIn, + EvqFlatIn, + EvqCentroidIn, // Implies smooth + + // GLSL ES 3.1 compute shader special variables + EvqShared, + EvqComputeIn, + EvqNumWorkGroups, + EvqWorkGroupSize, + EvqWorkGroupID, + EvqLocalInvocationID, + EvqGlobalInvocationID, + EvqLocalInvocationIndex, + + // GLSL ES 3.1 memory qualifiers + EvqReadOnly, + EvqWriteOnly, + EvqCoherent, + EvqRestrict, + EvqVolatile, + + // GLSL ES 3.1 extension EXT_geometry_shader qualifiers + EvqGeometryIn, + EvqGeometryOut, + EvqPerVertexIn, // gl_in + EvqPrimitiveIDIn, // gl_PrimitiveIDIn + EvqInvocationID, // gl_InvocationID + EvqPrimitiveID, // gl_PrimitiveID + EvqLayer, // gl_Layer + + // end of list + EvqLast +}; + +inline bool IsQualifierUnspecified(TQualifier qualifier) +{ + return (qualifier == EvqTemporary || qualifier == EvqGlobal); +} + +inline bool IsStorageBuffer(TQualifier qualifier) +{ + return qualifier == EvqBuffer; +} + +enum TLayoutImageInternalFormat +{ + EiifUnspecified, + EiifRGBA32F, + EiifRGBA16F, + EiifR32F, + EiifRGBA32UI, + EiifRGBA16UI, + EiifRGBA8UI, + EiifR32UI, + EiifRGBA32I, + EiifRGBA16I, + EiifRGBA8I, + EiifR32I, + EiifRGBA8, + EiifRGBA8_SNORM +}; + +enum TLayoutMatrixPacking +{ + EmpUnspecified, + EmpRowMajor, + EmpColumnMajor +}; + +enum TLayoutBlockStorage +{ + EbsUnspecified, + EbsShared, + EbsPacked, + EbsStd140, + EbsStd430 +}; + +enum TYuvCscStandardEXT +{ + EycsUndefined, + EycsItu601, + EycsItu601FullRange, + EycsItu709 +}; + +enum TLayoutPrimitiveType +{ + EptUndefined, + EptPoints, + EptLines, + EptLinesAdjacency, + EptTriangles, + EptTrianglesAdjacency, + EptLineStrip, + EptTriangleStrip +}; + +struct TLayoutQualifier +{ + // Must have a trivial default constructor since it is used in YYSTYPE. + TLayoutQualifier() = default; + + constexpr static TLayoutQualifier Create() { return TLayoutQualifier(0); } + + bool isEmpty() const + { + return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false && + matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified && + !localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified && + primitiveType == EptUndefined && invocations == 0 && maxVertices == -1 && + index == -1; + } + + bool isCombinationValid() const + { + bool workSizeSpecified = localSize.isAnyValueSet(); + bool numViewsSet = (numViews != -1); + bool geometryShaderSpecified = + (primitiveType != EptUndefined) || (invocations != 0) || (maxVertices != -1); + bool otherLayoutQualifiersSpecified = + (location != -1 || binding != -1 || index != -1 || matrixPacking != EmpUnspecified || + blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified); + + // we can have either the work group size specified, or number of views, + // or yuv layout qualifier, or the other layout qualifiers. + return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) + (yuv ? 1 : 0) + + (otherLayoutQualifiersSpecified ? 1 : 0) + (geometryShaderSpecified ? 1 : 0) <= + 1; + } + + bool isLocalSizeEqual(const WorkGroupSize &localSizeIn) const + { + return localSize.isWorkGroupSizeMatching(localSizeIn); + } + + int location; + unsigned int locationsSpecified; + TLayoutMatrixPacking matrixPacking; + TLayoutBlockStorage blockStorage; + + // Compute shader layout qualifiers. + WorkGroupSize localSize; + + int binding; + int offset; + + // Image format layout qualifier + TLayoutImageInternalFormat imageInternalFormat; + + // OVR_multiview num_views. + int numViews; + + // EXT_YUV_target yuv layout qualifier. + bool yuv; + + // OES_geometry_shader layout qualifiers. + TLayoutPrimitiveType primitiveType; + int invocations; + int maxVertices; + + // EXT_blend_func_extended fragment output layout qualifier + int index; + + private: + explicit constexpr TLayoutQualifier(int /*placeholder*/) + : location(-1), + locationsSpecified(0), + matrixPacking(EmpUnspecified), + blockStorage(EbsUnspecified), + localSize(-1), + binding(-1), + offset(-1), + imageInternalFormat(EiifUnspecified), + numViews(-1), + yuv(false), + primitiveType(EptUndefined), + invocations(0), + maxVertices(-1), + index(-1) + {} +}; + +struct TMemoryQualifier +{ + // Must have a trivial default constructor since it is used in YYSTYPE. + TMemoryQualifier() = default; + + bool isEmpty() const + { + return !readonly && !writeonly && !coherent && !restrictQualifier && !volatileQualifier; + } + + constexpr static TMemoryQualifier Create() { return TMemoryQualifier(0); } + + // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers + // An image can be qualified as both readonly and writeonly. It still can be can be used with + // imageSize(). + bool readonly; + bool writeonly; + bool coherent; + + // restrict and volatile are reserved keywords in C/C++ + bool restrictQualifier; + bool volatileQualifier; + + private: + explicit constexpr TMemoryQualifier(int /*placeholder*/) + : readonly(false), + writeonly(false), + coherent(false), + restrictQualifier(false), + volatileQualifier(false) + {} +}; + +inline const char *getWorkGroupSizeString(size_t dimension) +{ + switch (dimension) + { + case 0u: + return "local_size_x"; + case 1u: + return "local_size_y"; + case 2u: + return "local_size_z"; + default: + UNREACHABLE(); + return "dimension out of bounds"; + } +} + +// +// This is just for debug and error message print out, carried along with the definitions above. +// +inline const char *getQualifierString(TQualifier q) +{ + // clang-format off + switch(q) + { + case EvqTemporary: return "Temporary"; + case EvqGlobal: return "Global"; + case EvqConst: return "const"; + case EvqAttribute: return "attribute"; + case EvqVaryingIn: return "varying"; + case EvqVaryingOut: return "varying"; + case EvqUniform: return "uniform"; + case EvqBuffer: return "buffer"; + case EvqVertexIn: return "in"; + case EvqFragmentOut: return "out"; + case EvqVertexOut: return "out"; + case EvqFragmentIn: return "in"; + case EvqIn: return "in"; + case EvqOut: return "out"; + case EvqInOut: return "inout"; + case EvqConstReadOnly: return "const"; + case EvqInstanceID: return "InstanceID"; + case EvqVertexID: return "VertexID"; + case EvqPosition: return "Position"; + case EvqPointSize: return "PointSize"; + case EvqDrawID: return "DrawID"; + case EvqBaseVertex: return "BaseVertex"; + case EvqBaseInstance: return "BaseInstance"; + case EvqFragCoord: return "FragCoord"; + case EvqFrontFacing: return "FrontFacing"; + case EvqPointCoord: return "PointCoord"; + case EvqFragColor: return "FragColor"; + case EvqFragData: return "FragData"; + case EvqFragDepthEXT: return "FragDepth"; + case EvqFragDepth: return "FragDepth"; + case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT"; + case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT"; + case EvqViewIDOVR: return "ViewIDOVR"; + case EvqViewportIndex: return "ViewportIndex"; + case EvqLayer: return "Layer"; + case EvqLastFragColor: return "LastFragColor"; + case EvqLastFragData: return "LastFragData"; + case EvqSmoothOut: return "smooth out"; + case EvqCentroidOut: return "smooth centroid out"; + case EvqFlatOut: return "flat out"; + case EvqSmoothIn: return "smooth in"; + case EvqFlatIn: return "flat in"; + case EvqCentroidIn: return "smooth centroid in"; + case EvqCentroid: return "centroid"; + case EvqFlat: return "flat"; + case EvqSmooth: return "smooth"; + case EvqShared: return "shared"; + case EvqComputeIn: return "in"; + case EvqNumWorkGroups: return "NumWorkGroups"; + case EvqWorkGroupSize: return "WorkGroupSize"; + case EvqWorkGroupID: return "WorkGroupID"; + case EvqLocalInvocationID: return "LocalInvocationID"; + case EvqGlobalInvocationID: return "GlobalInvocationID"; + case EvqLocalInvocationIndex: return "LocalInvocationIndex"; + case EvqReadOnly: return "readonly"; + case EvqWriteOnly: return "writeonly"; + case EvqGeometryIn: return "in"; + case EvqGeometryOut: return "out"; + case EvqPerVertexIn: return "gl_in"; + default: UNREACHABLE(); return "unknown qualifier"; + } + // clang-format on +} + +inline const char *getMatrixPackingString(TLayoutMatrixPacking mpq) +{ + switch (mpq) + { + case EmpUnspecified: + return "mp_unspecified"; + case EmpRowMajor: + return "row_major"; + case EmpColumnMajor: + return "column_major"; + default: + UNREACHABLE(); + return "unknown matrix packing"; + } +} + +inline const char *getBlockStorageString(TLayoutBlockStorage bsq) +{ + switch (bsq) + { + case EbsUnspecified: + return "bs_unspecified"; + case EbsShared: + return "shared"; + case EbsPacked: + return "packed"; + case EbsStd140: + return "std140"; + case EbsStd430: + return "std430"; + default: + UNREACHABLE(); + return "unknown block storage"; + } +} + +inline const char *getImageInternalFormatString(TLayoutImageInternalFormat iifq) +{ + switch (iifq) + { + case EiifRGBA32F: + return "rgba32f"; + case EiifRGBA16F: + return "rgba16f"; + case EiifR32F: + return "r32f"; + case EiifRGBA32UI: + return "rgba32ui"; + case EiifRGBA16UI: + return "rgba16ui"; + case EiifRGBA8UI: + return "rgba8ui"; + case EiifR32UI: + return "r32ui"; + case EiifRGBA32I: + return "rgba32i"; + case EiifRGBA16I: + return "rgba16i"; + case EiifRGBA8I: + return "rgba8i"; + case EiifR32I: + return "r32i"; + case EiifRGBA8: + return "rgba8"; + case EiifRGBA8_SNORM: + return "rgba8_snorm"; + default: + UNREACHABLE(); + return "unknown internal image format"; + } +} + +inline TYuvCscStandardEXT getYuvCscStandardEXT(const ImmutableString &str) +{ + if (str == "itu_601") + return EycsItu601; + else if (str == "itu_601_full_range") + return EycsItu601FullRange; + else if (str == "itu_709") + return EycsItu709; + return EycsUndefined; +} + +inline const char *getYuvCscStandardEXTString(TYuvCscStandardEXT ycsq) +{ + switch (ycsq) + { + case EycsItu601: + return "itu_601"; + case EycsItu601FullRange: + return "itu_601_full_range"; + case EycsItu709: + return "itu_709"; + default: + UNREACHABLE(); + return "unknown color space conversion standard"; + } +} + +inline const char *getGeometryShaderPrimitiveTypeString(TLayoutPrimitiveType primitiveType) +{ + switch (primitiveType) + { + case EptPoints: + return "points"; + case EptLines: + return "lines"; + case EptTriangles: + return "triangles"; + case EptLinesAdjacency: + return "lines_adjacency"; + case EptTrianglesAdjacency: + return "triangles_adjacency"; + case EptLineStrip: + return "line_strip"; + case EptTriangleStrip: + return "triangle_strip"; + default: + UNREACHABLE(); + return "unknown geometry shader primitive type"; + } +} + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_BASETYPES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp new file mode 100644 index 0000000000..290f84df68 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp @@ -0,0 +1,162 @@ +// +// Copyright (c) 2002-2011 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/BuiltInFunctionEmulator.h" +#include "angle_gl.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/Symbol.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser +{ + public: + BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator) + : TIntermTraverser(true, false, false), mEmulator(emulator) + {} + + bool visitUnary(Visit visit, TIntermUnary *node) override + { + if (node->getFunction()) + { + bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction()); + if (needToEmulate) + node->setUseEmulatedFunction(); + } + return true; + } + + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + // Here we handle all the built-in functions mapped to ops, not just the ones that are + // currently identified as problematic. + if (node->isConstructor() || node->isFunctionCall()) + { + return true; + } + bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction()); + if (needToEmulate) + node->setUseEmulatedFunction(); + return true; + } + + private: + BuiltInFunctionEmulator &mEmulator; +}; + +BuiltInFunctionEmulator::BuiltInFunctionEmulator() {} + +void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId, + const char *emulatedFunctionDefinition) +{ + mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition); +} + +void BuiltInFunctionEmulator::addEmulatedFunctionWithDependency( + const TSymbolUniqueId &dependency, + const TSymbolUniqueId &uniqueId, + const char *emulatedFunctionDefinition) +{ + mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition); + mFunctionDependencies[uniqueId.get()] = dependency.get(); +} + +bool BuiltInFunctionEmulator::isOutputEmpty() const +{ + return (mFunctions.size() == 0); +} + +void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const +{ + for (const auto &function : mFunctions) + { + const char *body = findEmulatedFunction(function); + ASSERT(body); + out << body; + out << "\n\n"; + } +} + +const char *BuiltInFunctionEmulator::findEmulatedFunction(int uniqueId) const +{ + for (const auto &queryFunction : mQueryFunctions) + { + const char *result = queryFunction(uniqueId); + if (result) + { + return result; + } + } + + const auto &result = mEmulatedFunctions.find(uniqueId); + if (result != mEmulatedFunctions.end()) + { + return result->second.c_str(); + } + + return nullptr; +} + +bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function) +{ + ASSERT(function != nullptr); + return setFunctionCalled(function->uniqueId().get()); +} + +bool BuiltInFunctionEmulator::setFunctionCalled(int uniqueId) +{ + if (!findEmulatedFunction(uniqueId)) + { + return false; + } + + for (size_t i = 0; i < mFunctions.size(); ++i) + { + if (mFunctions[i] == uniqueId) + return true; + } + // If the function depends on another, mark the dependency as called. + auto dependency = mFunctionDependencies.find(uniqueId); + if (dependency != mFunctionDependencies.end()) + { + setFunctionCalled((*dependency).second); + } + mFunctions.push_back(uniqueId); + return true; +} + +void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root) +{ + ASSERT(root); + + if (mEmulatedFunctions.empty() && mQueryFunctions.empty()) + return; + + BuiltInFunctionEmulationMarker marker(*this); + root->traverse(&marker); +} + +void BuiltInFunctionEmulator::cleanup() +{ + mFunctions.clear(); + mFunctionDependencies.clear(); +} + +void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc) +{ + mQueryFunctions.push_back(queryFunc); +} + +// static +void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name) +{ + ASSERT(name[strlen(name) - 1] != '('); + out << name << "_emu"; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h new file mode 100644 index 0000000000..d15e83d75c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 2011 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_BUILTINFUNCTIONEMULATOR_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ + +#include "compiler/translator/InfoSink.h" + +namespace sh +{ + +class TIntermNode; +class TFunction; +class TSymbolUniqueId; + +using BuiltinQueryFunc = const char *(int); + +// +// This class decides which built-in functions need to be replaced with the emulated ones. It can be +// used to work around driver bugs or implement functions that are not natively implemented on a +// specific platform. +// +class BuiltInFunctionEmulator +{ + public: + BuiltInFunctionEmulator(); + + void markBuiltInFunctionsForEmulation(TIntermNode *root); + + void cleanup(); + + // "name" gets written as "name_emu". + static void WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name); + + bool isOutputEmpty() const; + + // Output function emulation definition. This should be before any other shader source. + void outputEmulatedFunctions(TInfoSinkBase &out) const; + + // Add functions that need to be emulated. + void addEmulatedFunction(const TSymbolUniqueId &uniqueId, + const char *emulatedFunctionDefinition); + + void addEmulatedFunctionWithDependency(const TSymbolUniqueId &dependency, + const TSymbolUniqueId &uniqueId, + const char *emulatedFunctionDefinition); + + void addFunctionMap(BuiltinQueryFunc queryFunc); + + private: + class BuiltInFunctionEmulationMarker; + + // Records that a function is called by the shader and might need to be emulated. If the + // function is not in mEmulatedFunctions, this becomes a no-op. Returns true if the function + // call needs to be replaced with an emulated one. + bool setFunctionCalled(const TFunction *function); + bool setFunctionCalled(int uniqueId); + + const char *findEmulatedFunction(int uniqueId) const; + + // Map from function unique id to emulated function definition + std::map<int, std::string> mEmulatedFunctions; + + // Map from dependent functions to their dependencies. This structure allows each function to + // have at most one dependency. + std::map<int, int> mFunctionDependencies; + + // Called function ids + std::vector<int> mFunctions; + + // Constexpr function tables. + std::vector<BuiltinQueryFunc *> mQueryFunctions; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp new file mode 100644 index 0000000000..dc48527480 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp @@ -0,0 +1,284 @@ +// +// Copyright (c) 2002-2011 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/BuiltInFunctionEmulatorGLSL.h" + +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/VersionGLSL.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.h" + +namespace sh +{ + +void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType) +{ + if (shaderType == GL_VERTEX_SHADER) + { + emu->addEmulatedFunction(BuiltInId::abs_Int1, "int abs_emu(int x) { return x * sign(x); }"); + } +} + +void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion) +{ + // isnan() is supported since GLSL 1.3. + if (targetGLSLVersion < GLSL_VERSION_130) + return; + + // !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false. + emu->addEmulatedFunction( + BuiltInId::isnan_Float1, + "bool isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }"); + emu->addEmulatedFunction( + BuiltInId::isnan_Float2, + "bvec2 isnan_emu(vec2 x)\n" + "{\n" + " bvec2 isnan;\n" + " for (int i = 0; i < 2; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); + emu->addEmulatedFunction( + BuiltInId::isnan_Float3, + "bvec3 isnan_emu(vec3 x)\n" + "{\n" + " bvec3 isnan;\n" + " for (int i = 0; i < 3; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); + emu->addEmulatedFunction( + BuiltInId::isnan_Float4, + "bvec4 isnan_emu(vec4 x)\n" + "{\n" + " bvec4 isnan;\n" + " for (int i = 0; i < 4; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); +} + +void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu) +{ + emu->addEmulatedFunction(BuiltInId::atan_Float1_Float1, + "emu_precision float atan_emu(emu_precision float y, emu_precision " + "float x)\n" + "{\n" + " if (x > 0.0) return atan(y / x);\n" + " else if (x < 0.0 && y >= 0.0) return atan(y / x) + 3.14159265;\n" + " else if (x < 0.0 && y < 0.0) return atan(y / x) - 3.14159265;\n" + " else return 1.57079632 * sign(y);\n" + "}\n"); + static const std::array<TSymbolUniqueId, 4> ids = { + BuiltInId::atan_Float1_Float1, + BuiltInId::atan_Float2_Float2, + BuiltInId::atan_Float3_Float3, + BuiltInId::atan_Float4_Float4, + }; + for (int dim = 2; dim <= 4; ++dim) + { + std::stringstream ss = sh::InitializeStream<std::stringstream>(); + ss << "emu_precision vec" << dim << " atan_emu(emu_precision vec" << dim + << " y, emu_precision vec" << dim << " x)\n" + << "{\n" + " return vec" + << dim << "("; + for (int i = 0; i < dim; ++i) + { + ss << "atan_emu(y[" << i << "], x[" << i << "])"; + if (i < dim - 1) + { + ss << ", "; + } + } + ss << ");\n" + "}\n"; + emu->addEmulatedFunctionWithDependency(BuiltInId::atan_Float1_Float1, ids[dim - 1], + ss.str().c_str()); + } +} + +// Emulate built-in functions missing from GLSL 1.30 and higher +void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType, + int targetGLSLVersion) +{ + // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10) + if (targetGLSLVersion < GLSL_VERSION_410) + { + // clang-format off + emu->addEmulatedFunction(BuiltInId::packUnorm2x16_Float2, + "uint packUnorm2x16_emu(vec2 v)\n" + "{\n" + " int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n" + " int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n" + " return uint((y << 16) | (x & 0xFFFF));\n" + "}\n"); + + emu->addEmulatedFunction(BuiltInId::unpackUnorm2x16_UInt1, + "vec2 unpackUnorm2x16_emu(uint u)\n" + "{\n" + " float x = float(u & 0xFFFFu) / 65535.0;\n" + " float y = float(u >> 16) / 65535.0;\n" + " return vec2(x, y);\n" + "}\n"); + // clang-format on + } + + // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20) + // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30). + if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420) + { + // clang-format off + emu->addEmulatedFunction(BuiltInId::packSnorm2x16_Float2, + "uint packSnorm2x16_emu(vec2 v)\n" + "{\n" + " #if defined(GL_ARB_shading_language_packing)\n" + " return packSnorm2x16(v);\n" + " #else\n" + " int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n" + " int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n" + " return uint((y << 16) | (x & 0xFFFF));\n" + " #endif\n" + "}\n"); + emu->addEmulatedFunction(BuiltInId::unpackSnorm2x16_UInt1, + "#if !defined(GL_ARB_shading_language_packing)\n" + " float fromSnorm(uint x)\n" + " {\n" + " int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n" + " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n" + " }\n" + "#endif\n" + "\n" + "vec2 unpackSnorm2x16_emu(uint u)\n" + "{\n" + " #if defined(GL_ARB_shading_language_packing)\n" + " return unpackSnorm2x16(u);\n" + " #else\n" + " uint y = (u >> 16);\n" + " uint x = u;\n" + " return vec2(fromSnorm(x), fromSnorm(y));\n" + " #endif\n" + "}\n"); + // Functions uint f32tof16(float val) and float f16tof32(uint val) are + // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL". + emu->addEmulatedFunction(BuiltInId::packHalf2x16_Float2, + "#if !defined(GL_ARB_shading_language_packing)\n" + " uint f32tof16(float val)\n" + " {\n" + " uint f32 = floatBitsToUint(val);\n" + " uint f16 = 0u;\n" + " uint sign = (f32 >> 16) & 0x8000u;\n" + " int exponent = int((f32 >> 23) & 0xFFu) - 127;\n" + " uint mantissa = f32 & 0x007FFFFFu;\n" + " if (exponent == 128)\n" + " {\n" + " // Infinity or NaN\n" + " // NaN bits that are masked out by 0x3FF get discarded.\n" + " // This can turn some NaNs to infinity, but this is allowed by the spec.\n" + " f16 = sign | (0x1Fu << 10);\n" + " f16 |= (mantissa & 0x3FFu);\n" + " }\n" + " else if (exponent > 15)\n" + " {\n" + " // Overflow - flush to Infinity\n" + " f16 = sign | (0x1Fu << 10);\n" + " }\n" + " else if (exponent > -15)\n" + " {\n" + " // Representable value\n" + " exponent += 15;\n" + " mantissa >>= 13;\n" + " f16 = sign | uint(exponent << 10) | mantissa;\n" + " }\n" + " else\n" + " {\n" + " f16 = sign;\n" + " }\n" + " return f16;\n" + " }\n" + "#endif\n" + "\n" + "uint packHalf2x16_emu(vec2 v)\n" + "{\n" + " #if defined(GL_ARB_shading_language_packing)\n" + " return packHalf2x16(v);\n" + " #else\n" + " uint x = f32tof16(v.x);\n" + " uint y = f32tof16(v.y);\n" + " return (y << 16) | x;\n" + " #endif\n" + "}\n"); + emu->addEmulatedFunction(BuiltInId::unpackHalf2x16_UInt1, + "#if !defined(GL_ARB_shading_language_packing)\n" + " float f16tof32(uint val)\n" + " {\n" + " uint sign = (val & 0x8000u) << 16;\n" + " int exponent = int((val & 0x7C00u) >> 10);\n" + " uint mantissa = val & 0x03FFu;\n" + " float f32 = 0.0;\n" + " if(exponent == 0)\n" + " {\n" + " if (mantissa != 0u)\n" + " {\n" + " const float scale = 1.0 / (1 << 24);\n" + " f32 = scale * mantissa;\n" + " }\n" + " }\n" + " else if (exponent == 31)\n" + " {\n" + " return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n" + " }\n" + " else\n" + " {\n" + " exponent -= 15;\n" + " float scale;\n" + " if(exponent < 0)\n" + " {\n" + " // The negative unary operator is buggy on OSX.\n" + " // Work around this by using abs instead.\n" + " scale = 1.0 / (1 << abs(exponent));\n" + " }\n" + " else\n" + " {\n" + " scale = 1 << exponent;\n" + " }\n" + " float decimal = 1.0 + float(mantissa) / float(1 << 10);\n" + " f32 = scale * decimal;\n" + " }\n" + "\n" + " if (sign != 0u)\n" + " {\n" + " f32 = -f32;\n" + " }\n" + "\n" + " return f32;\n" + " }\n" + "#endif\n" + "\n" + "vec2 unpackHalf2x16_emu(uint u)\n" + "{\n" + " #if defined(GL_ARB_shading_language_packing)\n" + " return unpackHalf2x16(u);\n" + " #else\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xFFFFu;\n" + " return vec2(f16tof32(x), f16tof32(y));\n" + " #endif\n" + "}\n"); + // clang-format on + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h new file mode 100644 index 0000000000..e1b4779bd5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2011 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_BUILTINFUNCTIONEMULATORGLSL_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ + +#include "GLSLANG/ShaderLang.h" + +namespace sh +{ +class BuiltInFunctionEmulator; + +// +// This works around bug in Intel Mac drivers. +// +void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType); + +// +// This works around isnan() bug in Intel Mac drivers +// +void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion); +// +// This works around atan(y, x) bug in NVIDIA drivers. +// +void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu); + +// +// This function is emulating built-in functions missing from GLSL 1.30 and higher. +// +void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType, + int targetGLSLVersion); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp new file mode 100644 index 0000000000..b4bca0d36d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2014 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/BuiltInFunctionEmulatorHLSL.h" +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/VersionGLSL.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.h" + +namespace sh +{ + +// Defined in emulated_builtin_functions_hlsl_autogen.cpp. +const char *FindHLSLFunction(int uniqueId); + +void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion) +{ + if (targetGLSLVersion < GLSL_VERSION_130) + return; + + emu->addEmulatedFunction(BuiltInId::isnan_Float1, + "bool isnan_emu(float x)\n" + "{\n" + " return (x > 0.0 || x < 0.0) ? false : x != 0.0;\n" + "}\n" + "\n"); + + emu->addEmulatedFunction( + BuiltInId::isnan_Float2, + "bool2 isnan_emu(float2 x)\n" + "{\n" + " bool2 isnan;\n" + " for (int i = 0; i < 2; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); + + emu->addEmulatedFunction( + BuiltInId::isnan_Float3, + "bool3 isnan_emu(float3 x)\n" + "{\n" + " bool3 isnan;\n" + " for (int i = 0; i < 3; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); + + emu->addEmulatedFunction( + BuiltInId::isnan_Float4, + "bool4 isnan_emu(float4 x)\n" + "{\n" + " bool4 isnan;\n" + " for (int i = 0; i < 4; i++)\n" + " {\n" + " isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n" + " }\n" + " return isnan;\n" + "}\n"); +} + +void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) +{ + emu->addFunctionMap(FindHLSLFunction); + + // (a + b2^16) * (c + d2^16) = ac + (ad + bc) * 2^16 + bd * 2^32 + // Also note that below, a * d + ((a * c) >> 16) is guaranteed not to overflow, because: + // a <= 0xffff, d <= 0xffff, ((a * c) >> 16) <= 0xffff and 0xffff * 0xffff + 0xffff = 0xffff0000 + emu->addEmulatedFunction(BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1, + "void umulExtended_emu(uint x, uint y, out uint msb, out uint lsb)\n" + "{\n" + " lsb = x * y;\n" + " uint a = (x & 0xffffu);\n" + " uint b = (x >> 16);\n" + " uint c = (y & 0xffffu);\n" + " uint d = (y >> 16);\n" + " uint ad = a * d + ((a * c) >> 16);\n" + " uint bc = b * c;\n" + " uint carry = uint(ad > (0xffffffffu - bc));\n" + " msb = ((ad + bc) >> 16) + (carry << 16) + b * d;\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1, + BuiltInId::umulExtended_UInt2_UInt2_UInt2_UInt2, + "void umulExtended_emu(uint2 x, uint2 y, out uint2 msb, out uint2 lsb)\n" + "{\n" + " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1, + BuiltInId::umulExtended_UInt3_UInt3_UInt3_UInt3, + "void umulExtended_emu(uint3 x, uint3 y, out uint3 msb, out uint3 lsb)\n" + "{\n" + " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1, + BuiltInId::umulExtended_UInt4_UInt4_UInt4_UInt4, + "void umulExtended_emu(uint4 x, uint4 y, out uint4 msb, out uint4 lsb)\n" + "{\n" + " umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" + " umulExtended_emu(x.w, y.w, msb.w, lsb.w);\n" + "}\n"); + + // The imul emulation does two's complement negation on the lsb and msb manually in case the + // result needs to be negative. + // TODO(oetuaho): Note that this code doesn't take one edge case into account, where x or y is + // -2^31. abs(-2^31) is undefined. + emu->addEmulatedFunctionWithDependency( + BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1, + BuiltInId::imulExtended_Int1_Int1_Int1_Int1, + "void imulExtended_emu(int x, int y, out int msb, out int lsb)\n" + "{\n" + " uint unsignedMsb;\n" + " uint unsignedLsb;\n" + " bool negative = (x < 0) != (y < 0);\n" + " umulExtended_emu(uint(abs(x)), uint(abs(y)), unsignedMsb, unsignedLsb);\n" + " lsb = asint(unsignedLsb);\n" + " msb = asint(unsignedMsb);\n" + " if (negative)\n" + " {\n" + " lsb = ~lsb;\n" + " msb = ~msb;\n" + " if (lsb == 0xffffffff)\n" + " {\n" + " lsb = 0;\n" + " msb += 1;\n" + " }\n" + " else\n" + " {\n" + " lsb += 1;\n" + " }\n" + " }\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int2_Int2_Int2_Int2, + "void imulExtended_emu(int2 x, int2 y, out int2 msb, out int2 lsb)\n" + "{\n" + " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int3_Int3_Int3_Int3, + "void imulExtended_emu(int3 x, int3 y, out int3 msb, out int3 lsb)\n" + "{\n" + " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" + "}\n"); + emu->addEmulatedFunctionWithDependency( + BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int4_Int4_Int4_Int4, + "void imulExtended_emu(int4 x, int4 y, out int4 msb, out int4 lsb)\n" + "{\n" + " imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n" + " imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n" + " imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n" + " imulExtended_emu(x.w, y.w, msb.w, lsb.w);\n" + "}\n"); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h new file mode 100644 index 0000000000..48da73f58e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 2014 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_BUILTINFUNCTIONEMULATORHLSL_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ + +#include "GLSLANG/ShaderLang.h" + +namespace sh +{ + +class BuiltInFunctionEmulator; + +void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu); + +// +// This works around isnan() bug on some Intel drivers. +// +void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp b/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp new file mode 100644 index 0000000000..63c8cd0f92 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp @@ -0,0 +1,316 @@ +// +// Copyright (c) 2002-2015 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. +// + +// CallDAG.h: Implements a call graph DAG of functions to be re-used accross +// analyses, allows to efficiently traverse the functions in topological +// order. + +#include "compiler/translator/CallDAG.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +// The CallDAGCreator does all the processing required to create the CallDAG +// structure so that the latter contains only the necessary variables. +class CallDAG::CallDAGCreator : public TIntermTraverser +{ + public: + CallDAGCreator(TDiagnostics *diagnostics) + : TIntermTraverser(true, false, false), + mDiagnostics(diagnostics), + mCurrentFunction(nullptr), + mCurrentIndex(0) + {} + + InitResult assignIndices() + { + int skipped = 0; + for (auto &it : mFunctions) + { + // Skip unimplemented functions + if (it.second.definitionNode) + { + InitResult result = assignIndicesInternal(&it.second); + if (result != INITDAG_SUCCESS) + { + return result; + } + } + else + { + skipped++; + } + } + + ASSERT(mFunctions.size() == mCurrentIndex + skipped); + return INITDAG_SUCCESS; + } + + void fillDataStructures(std::vector<Record> *records, std::map<int, int> *idToIndex) + { + ASSERT(records->empty()); + ASSERT(idToIndex->empty()); + + records->resize(mCurrentIndex); + + for (auto &it : mFunctions) + { + CreatorFunctionData &data = it.second; + // Skip unimplemented functions + if (!data.definitionNode) + { + continue; + } + ASSERT(data.index < records->size()); + Record &record = (*records)[data.index]; + + record.node = data.definitionNode; + + record.callees.reserve(data.callees.size()); + for (auto &callee : data.callees) + { + record.callees.push_back(static_cast<int>(callee->index)); + } + + (*idToIndex)[it.first] = static_cast<int>(data.index); + } + } + + private: + struct CreatorFunctionData + { + CreatorFunctionData() + : definitionNode(nullptr), name(""), index(0), indexAssigned(false), visiting(false) + {} + + std::set<CreatorFunctionData *> callees; + TIntermFunctionDefinition *definitionNode; + ImmutableString name; + size_t index; + bool indexAssigned; + bool visiting; + }; + + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override + { + // Create the record if need be and remember the definition node. + mCurrentFunction = &mFunctions[node->getFunction()->uniqueId().get()]; + // Name will be overwritten here. If we've already traversed the prototype of this function, + // it should have had the same name. + ASSERT(mCurrentFunction->name == "" || + mCurrentFunction->name == node->getFunction()->name()); + mCurrentFunction->name = node->getFunction()->name(); + mCurrentFunction->definitionNode = node; + + node->getBody()->traverse(this); + mCurrentFunction = nullptr; + return false; + } + + void visitFunctionPrototype(TIntermFunctionPrototype *node) override + { + ASSERT(mCurrentFunction == nullptr); + + // Function declaration, create an empty record. + auto &record = mFunctions[node->getFunction()->uniqueId().get()]; + record.name = node->getFunction()->name(); + } + + // Track functions called from another function. + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + if (node->getOp() == EOpCallFunctionInAST) + { + // Function call, add the callees + auto it = mFunctions.find(node->getFunction()->uniqueId().get()); + ASSERT(it != mFunctions.end()); + + // We might be traversing the initializer of a global variable. Even though function + // calls in global scope are forbidden by the parser, some subsequent AST + // transformations can add them to emulate particular features. + if (mCurrentFunction) + { + mCurrentFunction->callees.insert(&it->second); + } + } + return true; + } + + // Recursively assigns indices to a sub DAG + InitResult assignIndicesInternal(CreatorFunctionData *root) + { + // Iterative implementation of the index assignment algorithm. A recursive version + // would be prettier but since the CallDAG creation runs before the limiting of the + // call depth, we might get stack overflows (computation of the call depth uses the + // CallDAG). + + ASSERT(root); + + if (root->indexAssigned) + { + return INITDAG_SUCCESS; + } + + // If we didn't have to detect recursion, functionsToProcess could be a simple queue + // in which we add the function being processed's callees. However in order to detect + // recursion we need to know which functions we are currently visiting. For that reason + // functionsToProcess will look like a concatenation of segments of the form + // [F visiting = true, subset of F callees with visiting = false] and the following + // segment (if any) will be start with a callee of F. + // This way we can remember when we started visiting a function, to put visiting back + // to false. + TVector<CreatorFunctionData *> functionsToProcess; + functionsToProcess.push_back(root); + + InitResult result = INITDAG_SUCCESS; + + std::stringstream errorStream = sh::InitializeStream<std::stringstream>(); + + while (!functionsToProcess.empty()) + { + CreatorFunctionData *function = functionsToProcess.back(); + + if (function->visiting) + { + function->visiting = false; + function->index = mCurrentIndex++; + function->indexAssigned = true; + + functionsToProcess.pop_back(); + continue; + } + + if (!function->definitionNode) + { + errorStream << "Undefined function '" << function->name + << ")' used in the following call chain:"; + result = INITDAG_UNDEFINED; + break; + } + + if (function->indexAssigned) + { + functionsToProcess.pop_back(); + continue; + } + + function->visiting = true; + + for (auto callee : function->callees) + { + functionsToProcess.push_back(callee); + + // Check if the callee is already being visited after pushing it so that it appears + // in the chain printed in the info log. + if (callee->visiting) + { + errorStream << "Recursive function call in the following call chain:"; + result = INITDAG_RECURSION; + break; + } + } + + if (result != INITDAG_SUCCESS) + { + break; + } + } + + // The call chain is made of the function we were visiting when the error was detected. + if (result != INITDAG_SUCCESS) + { + bool first = true; + for (auto function : functionsToProcess) + { + if (function->visiting) + { + if (!first) + { + errorStream << " -> "; + } + errorStream << function->name << ")"; + first = false; + } + } + if (mDiagnostics) + { + std::string errorStr = errorStream.str(); + mDiagnostics->globalError(errorStr.c_str()); + } + } + + return result; + } + + TDiagnostics *mDiagnostics; + + std::map<int, CreatorFunctionData> mFunctions; + CreatorFunctionData *mCurrentFunction; + size_t mCurrentIndex; +}; + +// CallDAG + +CallDAG::CallDAG() {} + +CallDAG::~CallDAG() {} + +const size_t CallDAG::InvalidIndex = std::numeric_limits<size_t>::max(); + +size_t CallDAG::findIndex(const TSymbolUniqueId &id) const +{ + auto it = mFunctionIdToIndex.find(id.get()); + + if (it == mFunctionIdToIndex.end()) + { + return InvalidIndex; + } + else + { + return it->second; + } +} + +const CallDAG::Record &CallDAG::getRecordFromIndex(size_t index) const +{ + ASSERT(index != InvalidIndex && index < mRecords.size()); + return mRecords[index]; +} + +size_t CallDAG::size() const +{ + return mRecords.size(); +} + +void CallDAG::clear() +{ + mRecords.clear(); + mFunctionIdToIndex.clear(); +} + +CallDAG::InitResult CallDAG::init(TIntermNode *root, TDiagnostics *diagnostics) +{ + CallDAGCreator creator(diagnostics); + + // Creates the mapping of functions to callees + root->traverse(&creator); + + // Does the topological sort and detects recursions + InitResult result = creator.assignIndices(); + if (result != INITDAG_SUCCESS) + { + return result; + } + + creator.fillDataStructures(&mRecords, &mFunctionIdToIndex); + return INITDAG_SUCCESS; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/CallDAG.h b/gfx/angle/checkout/src/compiler/translator/CallDAG.h new file mode 100644 index 0000000000..813fc75573 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/CallDAG.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 2002-2015 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. +// + +// CallDAG.h: Defines a call graph DAG of functions to be re-used accross +// analyses, allows to efficiently traverse the functions in topological +// order. + +#ifndef COMPILER_TRANSLATOR_CALLDAG_H_ +#define COMPILER_TRANSLATOR_CALLDAG_H_ + +#include <map> + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +// The translator needs to analyze the the graph of the function calls +// to run checks and analyses; since in GLSL recursion is not allowed +// that graph is a DAG. +// This class is used to precompute that function call DAG so that it +// can be reused by multiple analyses. +// +// It stores a vector of function records, with one record per defined function. +// Records are accessed by index but a function symbol id can be converted +// to the index of the corresponding record. The records contain the AST node +// of the function definition and the indices of the function's callees. +// +// In addition, records are in reverse topological order: a function F being +// called by a function G will have index index(F) < index(G), that way +// depth-first analysis becomes analysis in the order of indices. + +class CallDAG : angle::NonCopyable +{ + public: + CallDAG(); + ~CallDAG(); + + struct Record + { + TIntermFunctionDefinition *node; // Guaranteed to be non-null. + std::vector<int> callees; + }; + + enum InitResult + { + INITDAG_SUCCESS, + INITDAG_RECURSION, + INITDAG_UNDEFINED, + }; + + // Returns INITDAG_SUCCESS if it was able to create the DAG, otherwise prints + // the initialization error in diagnostics, if present. + InitResult init(TIntermNode *root, TDiagnostics *diagnostics); + + // Returns InvalidIndex if the function wasn't found + size_t findIndex(const TSymbolUniqueId &id) const; + + const Record &getRecordFromIndex(size_t index) const; + size_t size() const; + void clear(); + + const static size_t InvalidIndex; + + private: + std::vector<Record> mRecords; + std::map<int, int> mFunctionIdToIndex; + + class CallDAGCreator; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_CALLDAG_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/CodeGen.cpp b/gfx/angle/checkout/src/compiler/translator/CodeGen.cpp new file mode 100644 index 0000000000..6dc9485589 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/CodeGen.cpp @@ -0,0 +1,75 @@ +// +// Copyright (c) 2013 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. +// + +#ifdef ANGLE_ENABLE_ESSL +# include "compiler/translator/TranslatorESSL.h" +#endif // ANGLE_ENABLE_ESSL + +#ifdef ANGLE_ENABLE_GLSL +# include "compiler/translator/TranslatorGLSL.h" +#endif // ANGLE_ENABLE_GLSL + +#ifdef ANGLE_ENABLE_HLSL +# include "compiler/translator/TranslatorHLSL.h" +#endif // ANGLE_ENABLE_HLSL + +#ifdef ANGLE_ENABLE_VULKAN +# include "compiler/translator/TranslatorVulkan.h" +#endif // ANGLE_ENABLE_VULKAN + +#include "compiler/translator/util.h" + +namespace sh +{ + +// +// This function must be provided to create the actual +// compile object used by higher level code. It returns +// a subclass of TCompiler. +// +TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) +{ +#ifdef ANGLE_ENABLE_ESSL + if (IsOutputESSL(output)) + { + return new TranslatorESSL(type, spec); + } +#endif // ANGLE_ENABLE_ESSL + +#ifdef ANGLE_ENABLE_GLSL + if (IsOutputGLSL(output)) + { + return new TranslatorGLSL(type, spec, output); + } +#endif // ANGLE_ENABLE_GLSL + +#ifdef ANGLE_ENABLE_HLSL + if (IsOutputHLSL(output)) + { + return new TranslatorHLSL(type, spec, output); + } +#endif // ANGLE_ENABLE_HLSL + +#ifdef ANGLE_ENABLE_VULKAN + if (IsOutputVulkan(output)) + { + return new TranslatorVulkan(type, spec); + } +#endif // ANGLE_ENABLE_VULKAN + + // Unsupported compiler or unknown format. Return nullptr per the sh::ConstructCompiler API. + return nullptr; +} + +// +// Delete the compiler made by ConstructCompiler +// +void DeleteCompiler(TCompiler *compiler) +{ + SafeDelete(compiler); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp b/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp new file mode 100644 index 0000000000..e8bc6edd16 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp @@ -0,0 +1,970 @@ +// +// Copyright (c) 2002-2013 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. +// +// CollectVariables.cpp: Collect lists of shader interface variables based on the AST. + +#include "compiler/translator/CollectVariables.h" + +#include "angle_gl.h" +#include "common/utilities.h" +#include "compiler/translator/HashNames.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage) +{ + switch (blockStorage) + { + case EbsPacked: + return BLOCKLAYOUT_PACKED; + case EbsShared: + return BLOCKLAYOUT_SHARED; + case EbsStd140: + return BLOCKLAYOUT_STD140; + case EbsStd430: + return BLOCKLAYOUT_STD430; + default: + UNREACHABLE(); + return BLOCKLAYOUT_SHARED; + } +} + +// TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks. +BlockType GetBlockType(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqUniform: + return BlockType::BLOCK_UNIFORM; + case EvqBuffer: + return BlockType::BLOCK_BUFFER; + case EvqPerVertexIn: + return BlockType::BLOCK_IN; + default: + UNREACHABLE(); + return BlockType::BLOCK_UNIFORM; + } +} + +template <class VarT> +VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList) +{ + // TODO(zmo): optimize this function. + for (size_t ii = 0; ii < infoList->size(); ++ii) + { + if (name == (*infoList)[ii].name) + return &((*infoList)[ii]); + } + + return nullptr; +} + +// Note that this shouldn't be called for interface blocks - active information is collected for +// individual fields in case of interface blocks. +void MarkActive(ShaderVariable *variable) +{ + if (!variable->active) + { + if (variable->isStruct()) + { + // Conservatively assume all fields are statically used as well. + for (auto &field : variable->fields) + { + MarkActive(&field); + } + } + ASSERT(variable->staticUse); + variable->active = true; + } +} + +ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name, + const TInterfaceBlock *interfaceBlock, + std::vector<InterfaceBlock> *infoList) +{ + ASSERT(interfaceBlock); + InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList); + ASSERT(namedBlock); + + // Set static use on the parent interface block here + namedBlock->staticUse = true; + namedBlock->active = true; + return FindVariable(name, &namedBlock->fields); +} + +// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs, +// and interface blocks. +class CollectVariablesTraverser : public TIntermTraverser +{ + public: + CollectVariablesTraverser(std::vector<Attribute> *attribs, + std::vector<OutputVariable> *outputVariables, + std::vector<Uniform> *uniforms, + std::vector<Varying> *inputVaryings, + std::vector<Varying> *outputVaryings, + std::vector<InterfaceBlock> *uniformBlocks, + std::vector<InterfaceBlock> *shaderStorageBlocks, + std::vector<InterfaceBlock> *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior); + + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + void visitSymbol(TIntermSymbol *symbol) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; + bool visitBinary(Visit visit, TIntermBinary *binaryNode) override; + + private: + std::string getMappedName(const TSymbol *symbol) const; + + void setFieldOrVariableProperties(const TType &type, + bool staticUse, + ShaderVariable *variableOut) const; + void setFieldProperties(const TType &type, + const ImmutableString &name, + bool staticUse, + ShaderVariable *variableOut) const; + void setCommonVariableProperties(const TType &type, + const TVariable &variable, + ShaderVariable *variableOut) const; + + Attribute recordAttribute(const TIntermSymbol &variable) const; + OutputVariable recordOutputVariable(const TIntermSymbol &variable) const; + Varying recordVarying(const TIntermSymbol &variable) const; + void recordInterfaceBlock(const char *instanceName, + const TType &interfaceBlockType, + InterfaceBlock *interfaceBlock) const; + Uniform recordUniform(const TIntermSymbol &variable) const; + + void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info); + + void recordBuiltInVaryingUsed(const TVariable &variable, + bool *addedFlag, + std::vector<Varying> *varyings); + void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag); + void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag); + InterfaceBlock *recordGLInUsed(const TType &glInType); + InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const; + + std::vector<Attribute> *mAttribs; + std::vector<OutputVariable> *mOutputVariables; + std::vector<Uniform> *mUniforms; + std::vector<Varying> *mInputVaryings; + std::vector<Varying> *mOutputVaryings; + std::vector<InterfaceBlock> *mUniformBlocks; + std::vector<InterfaceBlock> *mShaderStorageBlocks; + std::vector<InterfaceBlock> *mInBlocks; + + std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields; + + // Shader uniforms + bool mDepthRangeAdded; + + // Vertex Shader builtins + bool mInstanceIDAdded; + bool mVertexIDAdded; + bool mPointSizeAdded; + bool mDrawIDAdded; + bool mBaseVertexAdded; + bool mBaseInstanceAdded; + + // Vertex Shader and Geometry Shader builtins + bool mPositionAdded; + + // Fragment Shader builtins + bool mPointCoordAdded; + bool mFrontFacingAdded; + bool mFragCoordAdded; + bool mLastFragDataAdded; + bool mFragColorAdded; + bool mFragDataAdded; + bool mFragDepthEXTAdded; + bool mFragDepthAdded; + bool mSecondaryFragColorEXTAdded; + bool mSecondaryFragDataEXTAdded; + + // Geometry Shader builtins + bool mPerVertexInAdded; + bool mPrimitiveIDInAdded; + bool mInvocationIDAdded; + + // Geometry Shader and Fragment Shader builtins + bool mPrimitiveIDAdded; + bool mLayerAdded; + + ShHashFunction64 mHashFunction; + + GLenum mShaderType; + const TExtensionBehavior &mExtensionBehavior; +}; + +CollectVariablesTraverser::CollectVariablesTraverser( + std::vector<sh::Attribute> *attribs, + std::vector<sh::OutputVariable> *outputVariables, + std::vector<sh::Uniform> *uniforms, + std::vector<sh::Varying> *inputVaryings, + std::vector<sh::Varying> *outputVaryings, + std::vector<sh::InterfaceBlock> *uniformBlocks, + std::vector<sh::InterfaceBlock> *shaderStorageBlocks, + std::vector<sh::InterfaceBlock> *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior) + : TIntermTraverser(true, false, false, symbolTable), + mAttribs(attribs), + mOutputVariables(outputVariables), + mUniforms(uniforms), + mInputVaryings(inputVaryings), + mOutputVaryings(outputVaryings), + mUniformBlocks(uniformBlocks), + mShaderStorageBlocks(shaderStorageBlocks), + mInBlocks(inBlocks), + mDepthRangeAdded(false), + mInstanceIDAdded(false), + mVertexIDAdded(false), + mPointSizeAdded(false), + mDrawIDAdded(false), + mBaseVertexAdded(false), + mBaseInstanceAdded(false), + mPositionAdded(false), + mPointCoordAdded(false), + mFrontFacingAdded(false), + mFragCoordAdded(false), + mLastFragDataAdded(false), + mFragColorAdded(false), + mFragDataAdded(false), + mFragDepthEXTAdded(false), + mFragDepthAdded(false), + mSecondaryFragColorEXTAdded(false), + mSecondaryFragDataEXTAdded(false), + mPerVertexInAdded(false), + mPrimitiveIDInAdded(false), + mInvocationIDAdded(false), + mPrimitiveIDAdded(false), + mLayerAdded(false), + mHashFunction(hashFunction), + mShaderType(shaderType), + mExtensionBehavior(extensionBehavior) +{} + +std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const +{ + return HashName(symbol, mHashFunction, nullptr).data(); +} + +void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable, + ShaderVariable *info) +{ + const TType &type = variable.getType(); + + info->name = variable.name().data(); + info->mappedName = variable.name().data(); + info->type = GLVariableType(type); + info->precision = GLVariablePrecision(type); + if (auto *arraySizes = type.getArraySizes()) + { + info->arraySizes.assign(arraySizes->begin(), arraySizes->end()); + } +} + +void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable, + bool *addedFlag, + std::vector<Varying> *varyings) +{ + ASSERT(varyings); + if (!(*addedFlag)) + { + Varying info; + setBuiltInInfoFromSymbol(variable, &info); + info.staticUse = true; + info.active = true; + info.isInvariant = mSymbolTable->isVaryingInvariant(variable); + varyings->push_back(info); + (*addedFlag) = true; + } +} + +void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable, + bool *addedFlag) +{ + if (!(*addedFlag)) + { + OutputVariable info; + setBuiltInInfoFromSymbol(variable, &info); + info.staticUse = true; + info.active = true; + mOutputVariables->push_back(info); + (*addedFlag) = true; + } +} + +void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable, + bool *addedFlag) +{ + if (!(*addedFlag)) + { + Attribute info; + setBuiltInInfoFromSymbol(variable, &info); + info.staticUse = true; + info.active = true; + info.location = -1; + mAttribs->push_back(info); + (*addedFlag) = true; + } +} + +InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType) +{ + if (!mPerVertexInAdded) + { + ASSERT(glInType.getQualifier() == EvqPerVertexIn); + InterfaceBlock info; + recordInterfaceBlock("gl_in", glInType, &info); + + mPerVertexInAdded = true; + mInBlocks->push_back(info); + return &mInBlocks->back(); + } + else + { + return FindVariable(ImmutableString("gl_PerVertex"), mInBlocks); + } +} + +bool CollectVariablesTraverser::visitInvariantDeclaration(Visit visit, + TIntermInvariantDeclaration *node) +{ + // We should not mark variables as active just based on an invariant declaration, so we don't + // traverse the symbols declared invariant. + return false; +} + +// We want to check whether a uniform/varying is active because we need to skip updating inactive +// ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord, +// and gl_FrontFacing count toward varying counting if they are active in a fragment shader. +void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) +{ + ASSERT(symbol != nullptr); + + if (symbol->variable().symbolType() == SymbolType::AngleInternal || + symbol->variable().symbolType() == SymbolType::Empty) + { + // Internal variables or nameless variables are not collected. + return; + } + + ShaderVariable *var = nullptr; + + const ImmutableString &symbolName = symbol->getName(); + + // Check the qualifier from the variable, not from the symbol node. The node may have a + // different qualifier if it's the result of a folded ternary node. + TQualifier qualifier = symbol->variable().getType().getQualifier(); + + if (IsVaryingIn(qualifier)) + { + var = FindVariable(symbolName, mInputVaryings); + } + else if (IsVaryingOut(qualifier)) + { + var = FindVariable(symbolName, mOutputVaryings); + } + else if (symbol->getType().getBasicType() == EbtInterfaceBlock) + { + UNREACHABLE(); + } + else if (symbolName == "gl_DepthRange") + { + ASSERT(qualifier == EvqUniform); + + if (!mDepthRangeAdded) + { + Uniform info; + const char kName[] = "gl_DepthRange"; + info.name = kName; + info.mappedName = kName; + info.type = GL_NONE; + info.precision = GL_NONE; + info.staticUse = true; + info.active = true; + + ShaderVariable nearInfo(GL_FLOAT); + const char kNearName[] = "near"; + nearInfo.name = kNearName; + nearInfo.mappedName = kNearName; + nearInfo.precision = GL_HIGH_FLOAT; + nearInfo.staticUse = true; + nearInfo.active = true; + + ShaderVariable farInfo(GL_FLOAT); + const char kFarName[] = "far"; + farInfo.name = kFarName; + farInfo.mappedName = kFarName; + farInfo.precision = GL_HIGH_FLOAT; + farInfo.staticUse = true; + farInfo.active = true; + + ShaderVariable diffInfo(GL_FLOAT); + const char kDiffName[] = "diff"; + diffInfo.name = kDiffName; + diffInfo.mappedName = kDiffName; + diffInfo.precision = GL_HIGH_FLOAT; + diffInfo.staticUse = true; + diffInfo.active = true; + + info.fields.push_back(nearInfo); + info.fields.push_back(farInfo); + info.fields.push_back(diffInfo); + + mUniforms->push_back(info); + mDepthRangeAdded = true; + } + } + else + { + switch (qualifier) + { + case EvqAttribute: + case EvqVertexIn: + var = FindVariable(symbolName, mAttribs); + break; + case EvqFragmentOut: + var = FindVariable(symbolName, mOutputVariables); + break; + case EvqUniform: + { + const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); + if (interfaceBlock) + { + var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks); + } + else + { + var = FindVariable(symbolName, mUniforms); + } + + // It's an internal error to reference an undefined user uniform + ASSERT(!symbolName.beginsWith("gl_") || var); + } + break; + case EvqBuffer: + { + const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); + var = + FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks); + } + break; + case EvqFragCoord: + recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings); + return; + case EvqFrontFacing: + recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings); + return; + case EvqPointCoord: + recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings); + return; + case EvqInstanceID: + // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set, + // gl_InstanceID is added inside expressions to initialize ViewID_OVR and + // InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1 + // shaders. + recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded); + return; + case EvqVertexID: + recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded); + return; + case EvqPosition: + recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings); + return; + case EvqPointSize: + recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings); + return; + case EvqDrawID: + recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded); + return; + case EvqBaseVertex: + recordBuiltInAttributeUsed(symbol->variable(), &mBaseVertexAdded); + return; + case EvqBaseInstance: + recordBuiltInAttributeUsed(symbol->variable(), &mBaseInstanceAdded); + return; + case EvqLastFragData: + recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings); + return; + case EvqFragColor: + recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded); + return; + case EvqFragData: + if (!mFragDataAdded) + { + OutputVariable info; + setBuiltInInfoFromSymbol(symbol->variable(), &info); + if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers)) + { + ASSERT(info.arraySizes.size() == 1u); + info.arraySizes.back() = 1u; + } + info.staticUse = true; + info.active = true; + mOutputVariables->push_back(info); + mFragDataAdded = true; + } + return; + case EvqFragDepthEXT: + recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthEXTAdded); + return; + case EvqFragDepth: + recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded); + return; + case EvqSecondaryFragColorEXT: + recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded); + return; + case EvqSecondaryFragDataEXT: + recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded); + return; + case EvqInvocationID: + recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings); + break; + case EvqPrimitiveIDIn: + recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings); + break; + case EvqPrimitiveID: + if (mShaderType == GL_GEOMETRY_SHADER_EXT) + { + recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded, + mOutputVaryings); + } + else + { + ASSERT(mShaderType == GL_FRAGMENT_SHADER); + recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded, + mInputVaryings); + } + break; + case EvqLayer: + if (mShaderType == GL_GEOMETRY_SHADER_EXT) + { + recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings); + } + else if (mShaderType == GL_FRAGMENT_SHADER) + { + recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings); + } + else + { + ASSERT(mShaderType == GL_VERTEX_SHADER && + (IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) || + IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview))); + } + break; + default: + break; + } + } + if (var) + { + MarkActive(var); + } +} + +void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type, + bool staticUse, + ShaderVariable *variableOut) const +{ + ASSERT(variableOut); + + variableOut->staticUse = staticUse; + + const TStructure *structure = type.getStruct(); + if (!structure) + { + variableOut->type = GLVariableType(type); + variableOut->precision = GLVariablePrecision(type); + } + else + { + // Structures use a NONE type that isn't exposed outside ANGLE. + variableOut->type = GL_NONE; + if (structure->symbolType() != SymbolType::Empty) + { + variableOut->structName = structure->name().data(); + } + + const TFieldList &fields = structure->fields(); + + for (const TField *field : fields) + { + // Regardless of the variable type (uniform, in/out etc.) its fields are always plain + // ShaderVariable objects. + ShaderVariable fieldVariable; + setFieldProperties(*field->type(), field->name(), staticUse, &fieldVariable); + variableOut->fields.push_back(fieldVariable); + } + } + if (auto *arraySizes = type.getArraySizes()) + { + variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end()); + } +} + +void CollectVariablesTraverser::setFieldProperties(const TType &type, + const ImmutableString &name, + bool staticUse, + ShaderVariable *variableOut) const +{ + ASSERT(variableOut); + setFieldOrVariableProperties(type, staticUse, variableOut); + variableOut->name.assign(name.data(), name.length()); + variableOut->mappedName = HashName(name, mHashFunction, nullptr).data(); +} + +void CollectVariablesTraverser::setCommonVariableProperties(const TType &type, + const TVariable &variable, + ShaderVariable *variableOut) const +{ + ASSERT(variableOut); + + variableOut->staticUse = mSymbolTable->isStaticallyUsed(variable); + setFieldOrVariableProperties(type, variableOut->staticUse, variableOut); + ASSERT(variable.symbolType() != SymbolType::Empty); + variableOut->name.assign(variable.name().data(), variable.name().length()); + variableOut->mappedName = getMappedName(&variable); +} + +Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const +{ + const TType &type = variable.getType(); + ASSERT(!type.getStruct()); + + Attribute attribute; + setCommonVariableProperties(type, variable.variable(), &attribute); + + attribute.location = type.getLayoutQualifier().location; + return attribute; +} + +OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const +{ + const TType &type = variable.getType(); + ASSERT(!type.getStruct()); + + OutputVariable outputVariable; + setCommonVariableProperties(type, variable.variable(), &outputVariable); + + outputVariable.location = type.getLayoutQualifier().location; + outputVariable.index = type.getLayoutQualifier().index; + return outputVariable; +} + +Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const +{ + const TType &type = variable.getType(); + + Varying varying; + setCommonVariableProperties(type, variable.variable(), &varying); + varying.location = type.getLayoutQualifier().location; + + switch (type.getQualifier()) + { + case EvqVaryingIn: + case EvqVaryingOut: + case EvqVertexOut: + case EvqSmoothOut: + case EvqFlatOut: + case EvqCentroidOut: + case EvqGeometryOut: + if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant()) + { + varying.isInvariant = true; + } + break; + default: + break; + } + + varying.interpolation = GetInterpolationType(type.getQualifier()); + return varying; +} + +// TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks. +void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName, + const TType &interfaceBlockType, + InterfaceBlock *interfaceBlock) const +{ + ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock); + ASSERT(interfaceBlock); + + const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock(); + ASSERT(blockType); + + interfaceBlock->name = blockType->name().data(); + interfaceBlock->mappedName = getMappedName(blockType); + if (instanceName != nullptr) + { + interfaceBlock->instanceName = instanceName; + const TSymbol *blockSymbol = nullptr; + if (strncmp(instanceName, "gl_in", 5u) == 0) + { + blockSymbol = mSymbolTable->getGlInVariableWithArraySize(); + } + else + { + blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName)); + } + ASSERT(blockSymbol && blockSymbol->isVariable()); + interfaceBlock->staticUse = + mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol)); + } + ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9 + interfaceBlock->arraySize = + interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0; + + interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier()); + if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM || + interfaceBlock->blockType == BlockType::BLOCK_BUFFER) + { + // TODO(oetuaho): Remove setting isRowMajorLayout. + interfaceBlock->isRowMajorLayout = false; + interfaceBlock->binding = blockType->blockBinding(); + interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage()); + } + + // Gather field information + bool anyFieldStaticallyUsed = false; + for (const TField *field : blockType->fields()) + { + const TType &fieldType = *field->type(); + + bool staticUse = false; + if (instanceName == nullptr) + { + // Static use of individual fields has been recorded, since they are present in the + // symbol table as variables. + const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name()); + ASSERT(fieldSymbol && fieldSymbol->isVariable()); + staticUse = + mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol)); + if (staticUse) + { + anyFieldStaticallyUsed = true; + } + } + + InterfaceBlockField fieldVariable; + setFieldProperties(fieldType, field->name(), staticUse, &fieldVariable); + fieldVariable.isRowMajorLayout = + (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); + interfaceBlock->fields.push_back(fieldVariable); + } + if (anyFieldStaticallyUsed) + { + interfaceBlock->staticUse = true; + } +} + +Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const +{ + Uniform uniform; + setCommonVariableProperties(variable.getType(), variable.variable(), &uniform); + uniform.binding = variable.getType().getLayoutQualifier().binding; + uniform.imageUnitFormat = + GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat); + uniform.location = variable.getType().getLayoutQualifier().location; + uniform.offset = variable.getType().getLayoutQualifier().offset; + uniform.readonly = variable.getType().getMemoryQualifier().readonly; + uniform.writeonly = variable.getType().getMemoryQualifier().writeonly; + return uniform; +} + +bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + const TIntermSequence &sequence = *(node->getSequence()); + ASSERT(!sequence.empty()); + + const TIntermTyped &typedNode = *(sequence.front()->getAsTyped()); + TQualifier qualifier = typedNode.getQualifier(); + + bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn || + qualifier == EvqFragmentOut || qualifier == EvqUniform || + IsVarying(qualifier); + + if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable) + { + return true; + } + + for (TIntermNode *variableNode : sequence) + { + // The only case in which the sequence will not contain a TIntermSymbol node is + // initialization. It will contain a TInterBinary node in that case. Since attributes, + // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we + // must have only TIntermSymbol nodes in the sequence in the cases we are interested in. + const TIntermSymbol &variable = *variableNode->getAsSymbolNode(); + if (variable.variable().symbolType() == SymbolType::AngleInternal) + { + // Internal variables are not collected. + continue; + } + + // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks. + if (typedNode.getBasicType() == EbtInterfaceBlock) + { + InterfaceBlock interfaceBlock; + recordInterfaceBlock(variable.variable().symbolType() != SymbolType::Empty + ? variable.getName().data() + : nullptr, + variable.getType(), &interfaceBlock); + + switch (qualifier) + { + case EvqUniform: + mUniformBlocks->push_back(interfaceBlock); + break; + case EvqBuffer: + mShaderStorageBlocks->push_back(interfaceBlock); + break; + default: + UNREACHABLE(); + } + } + else + { + ASSERT(variable.variable().symbolType() != SymbolType::Empty); + switch (qualifier) + { + case EvqAttribute: + case EvqVertexIn: + mAttribs->push_back(recordAttribute(variable)); + break; + case EvqFragmentOut: + mOutputVariables->push_back(recordOutputVariable(variable)); + break; + case EvqUniform: + mUniforms->push_back(recordUniform(variable)); + break; + default: + if (IsVaryingIn(qualifier)) + { + mInputVaryings->push_back(recordVarying(variable)); + } + else + { + ASSERT(IsVaryingOut(qualifier)); + mOutputVaryings->push_back(recordVarying(variable)); + } + break; + } + } + } + + // None of the recorded variables can have initializers, so we don't need to traverse the + // declarators. + return false; +} + +// TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing +// GL_EXT_shader_io_blocks. +InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock( + const ImmutableString &blockName) const +{ + InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks); + if (!namedBlock) + { + namedBlock = FindVariable(blockName, mShaderStorageBlocks); + } + return namedBlock; +} + +bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode) +{ + if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock) + { + // NOTE: we do not determine static use / activeness for individual blocks of an array. + TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped(); + ASSERT(blockNode); + + TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion(); + ASSERT(constantUnion); + + InterfaceBlock *namedBlock = nullptr; + + bool traverseIndexExpression = false; + TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode(); + if (interfaceIndexingNode) + { + TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped(); + ASSERT(interfaceNode); + + const TType &interfaceType = interfaceNode->getType(); + if (interfaceType.getQualifier() == EvqPerVertexIn) + { + namedBlock = recordGLInUsed(interfaceType); + ASSERT(namedBlock); + + // We need to continue traversing to collect useful variables in the index + // expression of gl_in. + traverseIndexExpression = true; + } + } + + const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock(); + if (!namedBlock) + { + namedBlock = findNamedInterfaceBlock(interfaceBlock->name()); + } + ASSERT(namedBlock); + ASSERT(namedBlock->staticUse); + namedBlock->active = true; + unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0)); + ASSERT(fieldIndex < namedBlock->fields.size()); + // TODO(oetuaho): Would be nicer to record static use of fields of named interface blocks + // more accurately at parse time - now we only mark the fields statically used if they are + // active. http://anglebug.com/2440 + namedBlock->fields[fieldIndex].staticUse = true; + namedBlock->fields[fieldIndex].active = true; + + if (traverseIndexExpression) + { + ASSERT(interfaceIndexingNode); + interfaceIndexingNode->getRight()->traverse(this); + } + return false; + } + + return true; +} + +} // anonymous namespace + +void CollectVariables(TIntermBlock *root, + std::vector<Attribute> *attributes, + std::vector<OutputVariable> *outputVariables, + std::vector<Uniform> *uniforms, + std::vector<Varying> *inputVaryings, + std::vector<Varying> *outputVaryings, + std::vector<InterfaceBlock> *uniformBlocks, + std::vector<InterfaceBlock> *shaderStorageBlocks, + std::vector<InterfaceBlock> *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior) +{ + CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings, + outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks, + hashFunction, symbolTable, shaderType, extensionBehavior); + root->traverse(&collect); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/CollectVariables.h b/gfx/angle/checkout/src/compiler/translator/CollectVariables.h new file mode 100644 index 0000000000..84494a1433 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/CollectVariables.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2002-2011 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. +// +// CollectVariables.h: Collect lists of shader interface variables based on the AST. + +#ifndef COMPILER_TRANSLATOR_COLLECTVARIABLES_H_ +#define COMPILER_TRANSLATOR_COLLECTVARIABLES_H_ + +#include <GLSLANG/ShaderLang.h> + +#include "compiler/translator/ExtensionBehavior.h" + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void CollectVariables(TIntermBlock *root, + std::vector<Attribute> *attributes, + std::vector<OutputVariable> *outputVariables, + std::vector<Uniform> *uniforms, + std::vector<Varying> *inputVaryings, + std::vector<Varying> *outputVaryings, + std::vector<InterfaceBlock> *uniformBlocks, + std::vector<InterfaceBlock> *shaderStorageBlocks, + std::vector<InterfaceBlock> *inBlocks, + ShHashFunction64 hashFunction, + TSymbolTable *symbolTable, + GLenum shaderType, + const TExtensionBehavior &extensionBehavior); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_COLLECTVARIABLES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Common.h b/gfx/angle/checkout/src/compiler/translator/Common.h new file mode 100644 index 0000000000..179cfe21ee --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Common.h @@ -0,0 +1,151 @@ +// +// Copyright (c) 2002-2010 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_COMMON_H_ +#define COMPILER_TRANSLATOR_COMMON_H_ + +#include <stdio.h> +#include <limits> +#include <map> +#include <sstream> +#include <string> +#include <unordered_map> +#include <vector> + +#include "common/angleutils.h" +#include "common/debug.h" +#include "common/third_party/smhasher/src/PMurHash.h" +#include "compiler/translator/PoolAlloc.h" + +namespace sh +{ + +struct TSourceLoc +{ + int first_file; + int first_line; + int last_file; + int last_line; +}; + +// +// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme. +// +#define POOL_ALLOCATOR_NEW_DELETE \ + void *operator new(size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ + void *operator new(size_t, void *_Where) { return (_Where); } \ + void operator delete(void *) {} \ + void operator delete(void *, void *) {} \ + void *operator new[](size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ + void *operator new[](size_t, void *_Where) { return (_Where); } \ + void operator delete[](void *) {} \ + void operator delete[](void *, void *) {} + +// +// Pool version of string. +// +typedef pool_allocator<char> TStringAllocator; +typedef std::basic_string<char, std::char_traits<char>, TStringAllocator> TString; +typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream; + +// +// Persistent string memory. Should only be used for strings that survive +// across compiles. +// +#define TPersistString std::string +#define TPersistStringStream std::ostringstream + +// +// Pool allocator versions of vectors, lists, and maps +// +template <class T> +class TVector : public std::vector<T, pool_allocator<T>> +{ + public: + POOL_ALLOCATOR_NEW_DELETE + + typedef typename std::vector<T, pool_allocator<T>>::size_type size_type; + TVector() : std::vector<T, pool_allocator<T>>() {} + TVector(const pool_allocator<T> &a) : std::vector<T, pool_allocator<T>>(a) {} + TVector(size_type i) : std::vector<T, pool_allocator<T>>(i) {} +}; + +template <class K, class D, class H = std::hash<K>, class CMP = std::equal_to<K>> +class TUnorderedMap : public std::unordered_map<K, D, H, CMP, pool_allocator<std::pair<const K, D>>> +{ + public: + POOL_ALLOCATOR_NEW_DELETE + typedef pool_allocator<std::pair<const K, D>> tAllocator; + + TUnorderedMap() : std::unordered_map<K, D, H, CMP, tAllocator>() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TUnorderedMap(const tAllocator &a) + : std::unordered_map<K, D, H, CMP, tAllocator>( + std::unordered_map<K, D, H, CMP, tAllocator>::key_compare(), + a) + {} +}; + +template <class K, class D, class CMP = std::less<K>> +class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D>>> +{ + public: + POOL_ALLOCATOR_NEW_DELETE + typedef pool_allocator<std::pair<const K, D>> tAllocator; + + TMap() : std::map<K, D, CMP, tAllocator>() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TMap(const tAllocator &a) + : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) + {} +}; + +// Integer to TString conversion +template <typename T> +inline TString str(T i) +{ + ASSERT(std::numeric_limits<T>::is_integer); + char buffer[((8 * sizeof(T)) / 3) + 3]; + const char *formatStr = std::numeric_limits<T>::is_signed ? "%d" : "%u"; + snprintf(buffer, sizeof(buffer), formatStr, i); + return buffer; +} + +// Allocate a char array in the global memory pool. str must be a null terminated string. strLength +// is the length without the null terminator. +inline const char *AllocatePoolCharArray(const char *str, size_t strLength) +{ + size_t requiredSize = strLength + 1; + char *buffer = static_cast<char *>(GetGlobalPoolAllocator()->allocate(requiredSize)); + memcpy(buffer, str, requiredSize); + ASSERT(buffer[strLength] == '\0'); + return buffer; +} + +// Initialize a new stream which must be imbued with the classic locale +template <typename T> +T InitializeStream() +{ + T stream; + stream.imbue(std::locale::classic()); + return stream; +} + +} // namespace sh + +namespace std +{ +template <> +struct hash<sh::TString> +{ + size_t operator()(const sh::TString &s) const + { + return angle::PMurHash32(0, s.data(), static_cast<int>(s.length())); + } +}; +} // namespace std + +#endif // COMPILER_TRANSLATOR_COMMON_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Compiler.cpp b/gfx/angle/checkout/src/compiler/translator/Compiler.cpp new file mode 100644 index 0000000000..42a556f363 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Compiler.cpp @@ -0,0 +1,1478 @@ +// +// Copyright (c) 2002-2014 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/Compiler.h" + +#include <sstream> + +#include "angle_gl.h" +#include "common/utilities.h" +#include "compiler/translator/CallDAG.h" +#include "compiler/translator/CollectVariables.h" +#include "compiler/translator/Initialize.h" +#include "compiler/translator/IsASTDepthBelowLimit.h" +#include "compiler/translator/OutputTree.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/translator/ValidateLimitations.h" +#include "compiler/translator/ValidateMaxParameters.h" +#include "compiler/translator/ValidateOutputs.h" +#include "compiler/translator/ValidateVaryingLocations.h" +#include "compiler/translator/VariablePacker.h" +#include "compiler/translator/tree_ops/AddAndTrueToLoopCondition.h" +#include "compiler/translator/tree_ops/ClampFragDepth.h" +#include "compiler/translator/tree_ops/ClampPointSize.h" +#include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h" +#include "compiler/translator/tree_ops/DeferGlobalInitializers.h" +#include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h" +#include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h" +#include "compiler/translator/tree_ops/EmulatePrecision.h" +#include "compiler/translator/tree_ops/FoldExpressions.h" +#include "compiler/translator/tree_ops/InitializeVariables.h" +#include "compiler/translator/tree_ops/PruneEmptyCases.h" +#include "compiler/translator/tree_ops/PruneNoOps.h" +#include "compiler/translator/tree_ops/RegenerateStructNames.h" +#include "compiler/translator/tree_ops/RemoveArrayLengthMethod.h" +#include "compiler/translator/tree_ops/RemoveInvariantDeclaration.h" +#include "compiler/translator/tree_ops/RemovePow.h" +#include "compiler/translator/tree_ops/RemoveUnreferencedVariables.h" +#include "compiler/translator/tree_ops/RewriteDoWhile.h" +#include "compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h" +#include "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h" +#include "compiler/translator/tree_ops/SeparateDeclarations.h" +#include "compiler/translator/tree_ops/SimplifyLoopConditions.h" +#include "compiler/translator/tree_ops/SplitSequenceOperator.h" +#include "compiler/translator/tree_ops/UnfoldShortCircuitAST.h" +#include "compiler/translator/tree_ops/UseInterfaceBlockFields.h" +#include "compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.h" +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/ReplaceShadowingVariables.h" +#include "compiler/translator/util.h" +#include "third_party/compiler/ArrayBoundsClamper.h" + +namespace sh +{ + +namespace +{ + +#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) +void DumpFuzzerCase(char const *const *shaderStrings, + size_t numStrings, + uint32_t type, + uint32_t spec, + uint32_t output, + uint64_t options) +{ + static int fileIndex = 0; + + std::ostringstream o = sh::InitializeStream<std::ostringstream>(); + o << "corpus/" << fileIndex++ << ".sample"; + std::string s = o.str(); + + // Must match the input format of the fuzzer + FILE *f = fopen(s.c_str(), "w"); + fwrite(&type, sizeof(type), 1, f); + fwrite(&spec, sizeof(spec), 1, f); + fwrite(&output, sizeof(output), 1, f); + fwrite(&options, sizeof(options), 1, f); + + char zero[128 - 20] = {0}; + fwrite(&zero, 128 - 20, 1, f); + + for (size_t i = 0; i < numStrings; i++) + { + fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f); + } + fwrite(&zero, 1, 1, f); + + fclose(f); +} +#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) +} // anonymous namespace + +bool IsGLSL130OrNewer(ShShaderOutput output) +{ + return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT || + output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT || + output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT || + output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT || + output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT); +} + +bool IsGLSL420OrNewer(ShShaderOutput output) +{ + return (output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT || + output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT); +} + +bool IsGLSL410OrOlder(ShShaderOutput output) +{ + return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT || + output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT || + output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT); +} + +bool RemoveInvariant(sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput outputType, + ShCompileOptions compileOptions) +{ + if (shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType)) + return true; + + if ((compileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0 && + shaderVersion >= 300 && shaderType == GL_VERTEX_SHADER) + return true; + + return false; +} + +size_t GetGlobalMaxTokenSize(ShShaderSpec spec) +{ + // WebGL defines a max token length of 256, while ES2 leaves max token + // size undefined. ES3 defines a max size of 1024 characters. + switch (spec) + { + case SH_WEBGL_SPEC: + return 256; + default: + return 1024; + } +} + +int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResources &resources) +{ + switch (shaderType) + { + case GL_VERTEX_SHADER: + return resources.MaxVertexUniformVectors; + case GL_FRAGMENT_SHADER: + return resources.MaxFragmentUniformVectors; + + // TODO (jiawei.shao@intel.com): check if we need finer-grained component counting + case GL_COMPUTE_SHADER: + return resources.MaxComputeUniformComponents / 4; + case GL_GEOMETRY_SHADER_EXT: + return resources.MaxGeometryUniformComponents / 4; + default: + UNREACHABLE(); + return -1; + } +} + +namespace +{ + +class TScopedPoolAllocator +{ + public: + TScopedPoolAllocator(angle::PoolAllocator *allocator) : mAllocator(allocator) + { + mAllocator->push(); + SetGlobalPoolAllocator(mAllocator); + } + ~TScopedPoolAllocator() + { + SetGlobalPoolAllocator(nullptr); + mAllocator->pop(); + } + + private: + angle::PoolAllocator *mAllocator; +}; + +class TScopedSymbolTableLevel +{ + public: + TScopedSymbolTableLevel(TSymbolTable *table) : mTable(table) + { + ASSERT(mTable->isEmpty()); + mTable->push(); + } + ~TScopedSymbolTableLevel() + { + while (!mTable->isEmpty()) + mTable->pop(); + } + + private: + TSymbolTable *mTable; +}; + +int MapSpecToShaderVersion(ShShaderSpec spec) +{ + switch (spec) + { + case SH_GLES2_SPEC: + case SH_WEBGL_SPEC: + return 100; + case SH_GLES3_SPEC: + case SH_WEBGL2_SPEC: + return 300; + case SH_GLES3_1_SPEC: + case SH_WEBGL3_SPEC: + return 310; + case SH_GL3_3_SPEC: + return 330; + default: + UNREACHABLE(); + return 0; + } +} + +bool ValidateFragColorAndFragData(GLenum shaderType, + int shaderVersion, + const TSymbolTable &symbolTable, + TDiagnostics *diagnostics) +{ + if (shaderVersion > 100 || shaderType != GL_FRAGMENT_SHADER) + { + return true; + } + + bool usesFragColor = false; + bool usesFragData = false; + // This validation is a bit stricter than the spec - it's only an error to write to + // both FragData and FragColor. But because it's better not to have reads from undefined + // variables, we always return an error if they are both referenced, rather than only if they + // are written. + if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_FragColor()) || + symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT())) + { + usesFragColor = true; + } + // Extension variables may not always be initialized (saves some time at symbol table init). + bool secondaryFragDataUsed = + symbolTable.gl_SecondaryFragDataEXT() != nullptr && + symbolTable.isStaticallyUsed(*symbolTable.gl_SecondaryFragDataEXT()); + if (symbolTable.isStaticallyUsed(*symbolTable.gl_FragData()) || secondaryFragDataUsed) + { + usesFragData = true; + } + if (usesFragColor && usesFragData) + { + const char *errorMessage = "cannot use both gl_FragData and gl_FragColor"; + if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()) || + secondaryFragDataUsed) + { + errorMessage = + "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)" + " and (gl_FragColor, gl_SecondaryFragColorEXT)"; + } + diagnostics->globalError(errorMessage); + return false; + } + return true; +} + +} // namespace + +TShHandleBase::TShHandleBase() +{ + allocator.push(); + SetGlobalPoolAllocator(&allocator); +} + +TShHandleBase::~TShHandleBase() +{ + SetGlobalPoolAllocator(nullptr); + allocator.popAll(); +} + +TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) + : mVariablesCollected(false), + mGLPositionInitialized(false), + mShaderType(type), + mShaderSpec(spec), + mOutputType(output), + mBuiltInFunctionEmulator(), + mDiagnostics(mInfoSink.info), + mSourcePath(nullptr), + mComputeShaderLocalSizeDeclared(false), + mComputeShaderLocalSize(1), + mGeometryShaderMaxVertices(-1), + mGeometryShaderInvocations(0), + mGeometryShaderInputPrimitiveType(EptUndefined), + mGeometryShaderOutputPrimitiveType(EptUndefined) +{} + +TCompiler::~TCompiler() {} + +bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const +{ + // If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API, + // validate loop and indexing as well (to verify that the shader only uses minimal functionality + // of ESSL 1.00 as in Appendix A of the spec). + return (IsWebGLBasedSpec(mShaderSpec) && mShaderVersion == 100) || + (compileOptions & SH_VALIDATE_LOOP_INDEXING); +} + +bool TCompiler::Init(const ShBuiltInResources &resources) +{ + SetGlobalPoolAllocator(&allocator); + + // Generate built-in symbol table. + if (!initBuiltInSymbolTable(resources)) + return false; + + mResources = resources; + setResourceString(); + + InitExtensionBehavior(resources, mExtensionBehavior); + mArrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy); + return true; +} + +TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions) +{ + return compileTreeImpl(shaderStrings, numStrings, compileOptions); +} + +TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], + size_t numStrings, + const ShCompileOptions compileOptions) +{ + clearResults(); + + ASSERT(numStrings > 0); + ASSERT(GetGlobalPoolAllocator()); + + // Reset the extension behavior for each compilation unit. + ResetExtensionBehavior(mExtensionBehavior); + + // If gl_DrawID is not supported, remove it from the available extensions + // Currently we only allow emulation of gl_DrawID + const bool glDrawIDSupported = (compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u; + if (!glDrawIDSupported) + { + auto it = mExtensionBehavior.find(TExtension::ANGLE_multi_draw); + if (it != mExtensionBehavior.end()) + { + mExtensionBehavior.erase(it); + } + } + + const bool glBaseVertexBaseInstanceSupported = + (compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u; + if (!glBaseVertexBaseInstanceSupported) + { + auto it = mExtensionBehavior.find(TExtension::ANGLE_base_vertex_base_instance); + if (it != mExtensionBehavior.end()) + { + mExtensionBehavior.erase(it); + } + } + + // First string is path of source file if flag is set. The actual source follows. + size_t firstSource = 0; + if (compileOptions & SH_SOURCE_PATH) + { + mSourcePath = shaderStrings[0]; + ++firstSource; + } + + TParseContext parseContext(mSymbolTable, mExtensionBehavior, mShaderType, mShaderSpec, + compileOptions, !IsDesktopGLSpec(mShaderSpec), &mDiagnostics, + getResources()); + + parseContext.setFragmentPrecisionHighOnESSL1(mResources.FragmentPrecisionHigh == 1); + + // We preserve symbols at the built-in level from compile-to-compile. + // Start pushing the user-defined symbols at global level. + TScopedSymbolTableLevel globalLevel(&mSymbolTable); + ASSERT(mSymbolTable.atGlobalLevel()); + + // Parse shader. + if (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, + &parseContext) != 0) + { + return nullptr; + } + + if (parseContext.getTreeRoot() == nullptr) + { + return nullptr; + } + + setASTMetadata(parseContext); + + if (!checkShaderVersion(&parseContext)) + { + return nullptr; + } + + TIntermBlock *root = parseContext.getTreeRoot(); + if (!checkAndSimplifyAST(root, parseContext, compileOptions)) + { + return nullptr; + } + + return root; +} + +bool TCompiler::checkShaderVersion(TParseContext *parseContext) +{ + if (MapSpecToShaderVersion(mShaderSpec) < mShaderVersion) + { + mDiagnostics.globalError("unsupported shader version"); + return false; + } + + ASSERT(parseContext); + switch (mShaderType) + { + case GL_COMPUTE_SHADER: + if (mShaderVersion < 310) + { + mDiagnostics.globalError("Compute shader is not supported in this shader version."); + return false; + } + break; + + case GL_GEOMETRY_SHADER_EXT: + if (mShaderVersion < 310) + { + mDiagnostics.globalError( + "Geometry shader is not supported in this shader version."); + return false; + } + else + { + ASSERT(mShaderVersion == 310); + if (!parseContext->checkCanUseExtension(sh::TSourceLoc(), + TExtension::EXT_geometry_shader)) + { + return false; + } + } + break; + + default: + break; + } + + return true; +} + +void TCompiler::setASTMetadata(const TParseContext &parseContext) +{ + mShaderVersion = parseContext.getShaderVersion(); + + mPragma = parseContext.pragma(); + mSymbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll); + + mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared(); + mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize(); + + mNumViews = parseContext.getNumViews(); + + if (mShaderType == GL_GEOMETRY_SHADER_EXT) + { + mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType(); + mGeometryShaderOutputPrimitiveType = parseContext.getGeometryShaderOutputPrimitiveType(); + mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices(); + mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations(); + } +} + +bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, + const TParseContext &parseContext, + ShCompileOptions compileOptions) +{ + // Disallow expressions deemed too complex. + if ((compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY) && !limitExpressionComplexity(root)) + { + return false; + } + + if (shouldRunLoopAndIndexingValidation(compileOptions) && + !ValidateLimitations(root, mShaderType, &mSymbolTable, &mDiagnostics)) + { + return false; + } + + if (!ValidateFragColorAndFragData(mShaderType, mShaderVersion, mSymbolTable, &mDiagnostics)) + { + return false; + } + + // Fold expressions that could not be folded before validation that was done as a part of + // parsing. + FoldExpressions(root, &mDiagnostics); + // Folding should only be able to generate warnings. + ASSERT(mDiagnostics.numErrors() == 0); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + // We prune no-ops to work around driver bugs and to keep AST processing and output simple. + // The following kinds of no-ops are pruned: + // 1. Empty declarations "int;". + // 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision + // for float, so float literal statements would end up with no precision which is + // invalid ESSL. + // After this empty declarations are not allowed in the AST. + PruneNoOps(root, &mSymbolTable); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + // Create the function DAG and check there is no recursion + if (!initCallDag(root)) + { + return false; + } + + if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth()) + { + return false; + } + + // Checks which functions are used and if "main" exists + mFunctionMetadata.clear(); + mFunctionMetadata.resize(mCallDag.size()); + if (!tagUsedFunctions()) + { + return false; + } + + if (!(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS)) + { + pruneUnusedFunctions(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + if (IsSpecWithFunctionBodyNewScope(mShaderSpec, mShaderVersion)) + { + ReplaceShadowingVariables(root, &mSymbolTable); + } + + if (mShaderVersion >= 310 && !ValidateVaryingLocations(root, &mDiagnostics, mShaderType)) + { + return false; + } + + if (mShaderVersion >= 300 && mShaderType == GL_FRAGMENT_SHADER && + !ValidateOutputs(root, getExtensionBehavior(), mResources.MaxDrawBuffers, &mDiagnostics)) + { + return false; + } + + // Fail compilation if precision emulation not supported. + if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision && + !EmulatePrecision::SupportedInLanguage(mOutputType)) + { + mDiagnostics.globalError("Precision emulation not supported for this output type."); + return false; + } + + // Clamping uniform array bounds needs to happen after validateLimitations pass. + if (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS) + { + mArrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); + } + + if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) && + (parseContext.isExtensionEnabled(TExtension::OVR_multiview2) || + parseContext.isExtensionEnabled(TExtension::OVR_multiview)) && + getShaderType() != GL_COMPUTE_SHADER) + { + DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, mShaderType, compileOptions, + mOutputType, &mSymbolTable); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + // This pass might emit short circuits so keep it before the short circuit unfolding + if (compileOptions & SH_REWRITE_DO_WHILE_LOOPS) + { + RewriteDoWhile(root, &mSymbolTable); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION) + { + AddAndTrueToLoopCondition(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT) + { + UnfoldShortCircuitAST(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT) + { + RemovePow(root, &mSymbolTable); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (compileOptions & SH_REGENERATE_STRUCT_NAMES) + { + RegenerateStructNames gen(&mSymbolTable); + root->traverse(&gen); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (mShaderType == GL_VERTEX_SHADER && + IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_multi_draw)) + { + if ((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u) + { + EmulateGLDrawID(root, &mSymbolTable, &mUniforms, + shouldCollectVariables(compileOptions)); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + } + + if (mShaderType == GL_VERTEX_SHADER && + IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_base_vertex_base_instance)) + { + if ((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u) + { + EmulateGLBaseVertex(root, &mSymbolTable, &mUniforms, + shouldCollectVariables(compileOptions)); + EmulateGLBaseInstance(root, &mSymbolTable, &mUniforms, + shouldCollectVariables(compileOptions)); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + } + + if (mShaderType == GL_FRAGMENT_SHADER && mShaderVersion == 100 && mResources.EXT_draw_buffers && + mResources.MaxDrawBuffers > 1 && + IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers)) + { + EmulateGLFragColorBroadcast(root, mResources.MaxDrawBuffers, &mOutputVariables, + &mSymbolTable, mShaderVersion); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + int simplifyScalarized = (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS) + ? IntermNodePatternMatcher::kScalarizedVecOrMatConstructor + : 0; + + // Split multi declarations and remove calls to array length(). + // Note that SimplifyLoopConditions needs to be run before any other AST transformations + // that may need to generate new statements from loop conditions or loop expressions. + SimplifyLoopConditions(root, + IntermNodePatternMatcher::kMultiDeclaration | + IntermNodePatternMatcher::kArrayLengthMethod | simplifyScalarized, + &getSymbolTable()); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + // Note that separate declarations need to be run before other AST transformations that + // generate new statements from expressions. + SeparateDeclarations(root); + mValidateASTOptions.validateMultiDeclarations = true; + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod | simplifyScalarized, + &getSymbolTable()); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + RemoveArrayLengthMethod(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + RemoveUnreferencedVariables(root, &mSymbolTable); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + // In case the last case inside a switch statement is a certain type of no-op, GLSL compilers in + // drivers may not accept it. In this case we clean up the dead code from the end of switch + // statements. This is also required because PruneNoOps or RemoveUnreferencedVariables may have + // left switch statements that only contained an empty declaration inside the final case in an + // invalid state. Relies on that PruneNoOps and RemoveUnreferencedVariables have already been + // run. + PruneEmptyCases(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + // Built-in function emulation needs to happen after validateLimitations pass. + // TODO(jmadill): Remove global pool allocator. + GetGlobalPoolAllocator()->lock(); + initBuiltInFunctionEmulator(&mBuiltInFunctionEmulator, compileOptions); + GetGlobalPoolAllocator()->unlock(); + mBuiltInFunctionEmulator.markBuiltInFunctionsForEmulation(root); + + bool highPrecisionSupported = mShaderVersion > 100 || mShaderType != GL_FRAGMENT_SHADER || + mResources.FragmentPrecisionHigh == 1; + if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS) + { + ScalarizeVecAndMatConstructorArgs(root, mShaderType, highPrecisionSupported, &mSymbolTable); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (shouldCollectVariables(compileOptions)) + { + ASSERT(!mVariablesCollected); + CollectVariables(root, &mAttributes, &mOutputVariables, &mUniforms, &mInputVaryings, + &mOutputVaryings, &mUniformBlocks, &mShaderStorageBlocks, &mInBlocks, + mResources.HashFunction, &mSymbolTable, mShaderType, mExtensionBehavior); + collectInterfaceBlocks(); + mVariablesCollected = true; + if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS) + { + useAllMembersInUnusedStandardAndSharedBlocks(root); + } + if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) + { + int maxUniformVectors = GetMaxUniformVectorsForShaderType(mShaderType, mResources); + // Returns true if, after applying the packing rules in the GLSL ES 1.00.17 spec + // Appendix A, section 7, the shader does not use too many uniforms. + if (!CheckVariablesInPackingLimits(maxUniformVectors, mUniforms)) + { + mDiagnostics.globalError("too many uniforms"); + return false; + } + } + if ((compileOptions & SH_INIT_OUTPUT_VARIABLES) && (mShaderType != GL_COMPUTE_SHADER)) + { + initializeOutputVariables(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + } + + // Removing invariant declarations must be done after collecting variables. + // Otherwise, built-in invariant declarations don't apply. + if (RemoveInvariant(mShaderType, mShaderVersion, mOutputType, compileOptions)) + { + RemoveInvariantDeclaration(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + // gl_Position is always written in compatibility output mode. + // It may have been already initialized among other output variables, in that case we don't + // need to initialize it twice. + if (mShaderType == GL_VERTEX_SHADER && !mGLPositionInitialized && + ((compileOptions & SH_INIT_GL_POSITION) || (mOutputType == SH_GLSL_COMPATIBILITY_OUTPUT))) + { + initializeGLPosition(root); + mGLPositionInitialized = true; + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + // DeferGlobalInitializers needs to be run before other AST transformations that generate new + // statements from expressions. But it's fine to run DeferGlobalInitializers after the above + // SplitSequenceOperator and RemoveArrayLengthMethod since they only have an effect on the AST + // on ESSL >= 3.00, and the initializers that need to be deferred can only exist in ESSL < 3.00. + bool initializeLocalsAndGlobals = + (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && !IsOutputHLSL(getOutputType()); + bool canUseLoopsToInitialize = !(compileOptions & SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES); + DeferGlobalInitializers(root, initializeLocalsAndGlobals, canUseLoopsToInitialize, + highPrecisionSupported, &mSymbolTable); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + + if (initializeLocalsAndGlobals) + { + // Initialize uninitialized local variables. + // In some cases initializing can generate extra statements in the parent block, such as + // when initializing nameless structs or initializing arrays in ESSL 1.00. In that case + // we need to first simplify loop conditions. We've already separated declarations + // earlier, which is also required. If we don't follow the Appendix A limitations, loop + // init statements can declare arrays or nameless structs and have multiple + // declarations. + + if (!shouldRunLoopAndIndexingValidation(compileOptions)) + { + SimplifyLoopConditions(root, + IntermNodePatternMatcher::kArrayDeclaration | + IntermNodePatternMatcher::kNamelessStructDeclaration, + &getSymbolTable()); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + InitializeUninitializedLocals(root, getShaderVersion(), canUseLoopsToInitialize, + highPrecisionSupported, &getSymbolTable()); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE)) + { + ClampPointSize(root, mResources.MaxPointSize, &getSymbolTable()); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (getShaderType() == GL_FRAGMENT_SHADER && (compileOptions & SH_CLAMP_FRAG_DEPTH)) + { + ClampFragDepth(root, &getSymbolTable()); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (compileOptions & SH_REWRITE_REPEATED_ASSIGN_TO_SWIZZLED) + { + sh::RewriteRepeatedAssignToSwizzled(root); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC) + { + VectorizeVectorScalarArithmetic(root, &getSymbolTable()); + if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions)) + { + return false; + } + } + + return true; +} + +bool TCompiler::compile(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptionsIn) +{ +#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) + DumpFuzzerCase(shaderStrings, numStrings, mShaderType, mShaderSpec, mOutputType, + compileOptionsIn); +#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT) + + if (numStrings == 0) + return true; + + ShCompileOptions compileOptions = compileOptionsIn; + + // Apply key workarounds. + if (shouldFlattenPragmaStdglInvariantAll()) + { + // This should be harmless to do in all cases, but for the moment, do it only conditionally. + compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL; + } + + TScopedPoolAllocator scopedAlloc(&allocator); + TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); + + if (root) + { + if (compileOptions & SH_INTERMEDIATE_TREE) + OutputTree(root, mInfoSink.info); + + if (compileOptions & SH_OBJECT_CODE) + { + PerformanceDiagnostics perfDiagnostics(&mDiagnostics); + translate(root, compileOptions, &perfDiagnostics); + } + + if (mShaderType == GL_VERTEX_SHADER) + { + bool lookForDrawID = + IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_multi_draw) && + ((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u); + bool lookForBaseVertexBaseInstance = + IsExtensionEnabled(mExtensionBehavior, + TExtension::ANGLE_base_vertex_base_instance) && + ((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u); + + if (lookForDrawID || lookForBaseVertexBaseInstance) + { + for (auto &uniform : mUniforms) + { + if (lookForDrawID && uniform.name == "angle_DrawID" && + uniform.mappedName == "angle_DrawID") + { + uniform.name = "gl_DrawID"; + } + else if (lookForBaseVertexBaseInstance && uniform.name == "angle_BaseVertex" && + uniform.mappedName == "angle_BaseVertex") + { + uniform.name = "gl_BaseVertex"; + } + else if (lookForBaseVertexBaseInstance && + uniform.name == "angle_BaseInstance" && + uniform.mappedName == "angle_BaseInstance") + { + uniform.name = "gl_BaseInstance"; + } + } + } + } + + // The IntermNode tree doesn't need to be deleted here, since the + // memory will be freed in a big chunk by the PoolAllocator. + return true; + } + return false; +} + +bool TCompiler::initBuiltInSymbolTable(const ShBuiltInResources &resources) +{ + if (resources.MaxDrawBuffers < 1) + { + return false; + } + if (resources.EXT_blend_func_extended && resources.MaxDualSourceDrawBuffers < 1) + { + return false; + } + + mSymbolTable.initializeBuiltIns(mShaderType, mShaderSpec, resources); + + return true; +} + +void TCompiler::setResourceString() +{ + std::ostringstream strstream = sh::InitializeStream<std::ostringstream>(); + + // clang-format off + strstream << ":MaxVertexAttribs:" << mResources.MaxVertexAttribs + << ":MaxVertexUniformVectors:" << mResources.MaxVertexUniformVectors + << ":MaxVaryingVectors:" << mResources.MaxVaryingVectors + << ":MaxVertexTextureImageUnits:" << mResources.MaxVertexTextureImageUnits + << ":MaxCombinedTextureImageUnits:" << mResources.MaxCombinedTextureImageUnits + << ":MaxTextureImageUnits:" << mResources.MaxTextureImageUnits + << ":MaxFragmentUniformVectors:" << mResources.MaxFragmentUniformVectors + << ":MaxDrawBuffers:" << mResources.MaxDrawBuffers + << ":OES_standard_derivatives:" << mResources.OES_standard_derivatives + << ":OES_EGL_image_external:" << mResources.OES_EGL_image_external + << ":OES_EGL_image_external_essl3:" << mResources.OES_EGL_image_external_essl3 + << ":NV_EGL_stream_consumer_external:" << mResources.NV_EGL_stream_consumer_external + << ":ARB_texture_rectangle:" << mResources.ARB_texture_rectangle + << ":EXT_draw_buffers:" << mResources.EXT_draw_buffers + << ":FragmentPrecisionHigh:" << mResources.FragmentPrecisionHigh + << ":MaxExpressionComplexity:" << mResources.MaxExpressionComplexity + << ":MaxCallStackDepth:" << mResources.MaxCallStackDepth + << ":MaxFunctionParameters:" << mResources.MaxFunctionParameters + << ":EXT_blend_func_extended:" << mResources.EXT_blend_func_extended + << ":EXT_frag_depth:" << mResources.EXT_frag_depth + << ":EXT_shader_texture_lod:" << mResources.EXT_shader_texture_lod + << ":EXT_shader_framebuffer_fetch:" << mResources.EXT_shader_framebuffer_fetch + << ":NV_shader_framebuffer_fetch:" << mResources.NV_shader_framebuffer_fetch + << ":ARM_shader_framebuffer_fetch:" << mResources.ARM_shader_framebuffer_fetch + << ":OVR_multiview2:" << mResources.OVR_multiview2 + << ":OVR_multiview:" << mResources.OVR_multiview + << ":EXT_YUV_target:" << mResources.EXT_YUV_target + << ":EXT_geometry_shader:" << mResources.EXT_geometry_shader + << ":OES_texture_3D:" << mResources.OES_texture_3D + << ":MaxVertexOutputVectors:" << mResources.MaxVertexOutputVectors + << ":MaxFragmentInputVectors:" << mResources.MaxFragmentInputVectors + << ":MinProgramTexelOffset:" << mResources.MinProgramTexelOffset + << ":MaxProgramTexelOffset:" << mResources.MaxProgramTexelOffset + << ":MaxDualSourceDrawBuffers:" << mResources.MaxDualSourceDrawBuffers + << ":MaxViewsOVR:" << mResources.MaxViewsOVR + << ":NV_draw_buffers:" << mResources.NV_draw_buffers + << ":WEBGL_debug_shader_precision:" << mResources.WEBGL_debug_shader_precision + << ":ANGLE_multi_draw:" << mResources.ANGLE_multi_draw + << ":ANGLE_base_vertex_base_instance:" << mResources.ANGLE_base_vertex_base_instance + << ":MinProgramTextureGatherOffset:" << mResources.MinProgramTextureGatherOffset + << ":MaxProgramTextureGatherOffset:" << mResources.MaxProgramTextureGatherOffset + << ":MaxImageUnits:" << mResources.MaxImageUnits + << ":MaxVertexImageUniforms:" << mResources.MaxVertexImageUniforms + << ":MaxFragmentImageUniforms:" << mResources.MaxFragmentImageUniforms + << ":MaxComputeImageUniforms:" << mResources.MaxComputeImageUniforms + << ":MaxCombinedImageUniforms:" << mResources.MaxCombinedImageUniforms + << ":MaxCombinedShaderOutputResources:" << mResources.MaxCombinedShaderOutputResources + << ":MaxComputeWorkGroupCountX:" << mResources.MaxComputeWorkGroupCount[0] + << ":MaxComputeWorkGroupCountY:" << mResources.MaxComputeWorkGroupCount[1] + << ":MaxComputeWorkGroupCountZ:" << mResources.MaxComputeWorkGroupCount[2] + << ":MaxComputeWorkGroupSizeX:" << mResources.MaxComputeWorkGroupSize[0] + << ":MaxComputeWorkGroupSizeY:" << mResources.MaxComputeWorkGroupSize[1] + << ":MaxComputeWorkGroupSizeZ:" << mResources.MaxComputeWorkGroupSize[2] + << ":MaxComputeUniformComponents:" << mResources.MaxComputeUniformComponents + << ":MaxComputeTextureImageUnits:" << mResources.MaxComputeTextureImageUnits + << ":MaxComputeAtomicCounters:" << mResources.MaxComputeAtomicCounters + << ":MaxComputeAtomicCounterBuffers:" << mResources.MaxComputeAtomicCounterBuffers + << ":MaxVertexAtomicCounters:" << mResources.MaxVertexAtomicCounters + << ":MaxFragmentAtomicCounters:" << mResources.MaxFragmentAtomicCounters + << ":MaxCombinedAtomicCounters:" << mResources.MaxCombinedAtomicCounters + << ":MaxAtomicCounterBindings:" << mResources.MaxAtomicCounterBindings + << ":MaxVertexAtomicCounterBuffers:" << mResources.MaxVertexAtomicCounterBuffers + << ":MaxFragmentAtomicCounterBuffers:" << mResources.MaxFragmentAtomicCounterBuffers + << ":MaxCombinedAtomicCounterBuffers:" << mResources.MaxCombinedAtomicCounterBuffers + << ":MaxAtomicCounterBufferSize:" << mResources.MaxAtomicCounterBufferSize + << ":MaxGeometryUniformComponents:" << mResources.MaxGeometryUniformComponents + << ":MaxGeometryUniformBlocks:" << mResources.MaxGeometryUniformBlocks + << ":MaxGeometryInputComponents:" << mResources.MaxGeometryInputComponents + << ":MaxGeometryOutputComponents:" << mResources.MaxGeometryOutputComponents + << ":MaxGeometryOutputVertices:" << mResources.MaxGeometryOutputVertices + << ":MaxGeometryTotalOutputComponents:" << mResources.MaxGeometryTotalOutputComponents + << ":MaxGeometryTextureImageUnits:" << mResources.MaxGeometryTextureImageUnits + << ":MaxGeometryAtomicCounterBuffers:" << mResources.MaxGeometryAtomicCounterBuffers + << ":MaxGeometryAtomicCounters:" << mResources.MaxGeometryAtomicCounters + << ":MaxGeometryShaderStorageBlocks:" << mResources.MaxGeometryShaderStorageBlocks + << ":MaxGeometryShaderInvocations:" << mResources.MaxGeometryShaderInvocations + << ":MaxGeometryImageUniforms:" << mResources.MaxGeometryImageUniforms; + // clang-format on + + mBuiltInResourcesString = strstream.str(); +} + +void TCompiler::collectInterfaceBlocks() +{ + ASSERT(mInterfaceBlocks.empty()); + mInterfaceBlocks.reserve(mUniformBlocks.size() + mShaderStorageBlocks.size() + + mInBlocks.size()); + mInterfaceBlocks.insert(mInterfaceBlocks.end(), mUniformBlocks.begin(), mUniformBlocks.end()); + mInterfaceBlocks.insert(mInterfaceBlocks.end(), mShaderStorageBlocks.begin(), + mShaderStorageBlocks.end()); + mInterfaceBlocks.insert(mInterfaceBlocks.end(), mInBlocks.begin(), mInBlocks.end()); +} + +void TCompiler::clearResults() +{ + mArrayBoundsClamper.Cleanup(); + mInfoSink.info.erase(); + mInfoSink.obj.erase(); + mInfoSink.debug.erase(); + mDiagnostics.resetErrorCount(); + + mAttributes.clear(); + mOutputVariables.clear(); + mUniforms.clear(); + mInputVaryings.clear(); + mOutputVaryings.clear(); + mInterfaceBlocks.clear(); + mUniformBlocks.clear(); + mShaderStorageBlocks.clear(); + mInBlocks.clear(); + mVariablesCollected = false; + mGLPositionInitialized = false; + + mNumViews = -1; + + mGeometryShaderInputPrimitiveType = EptUndefined; + mGeometryShaderOutputPrimitiveType = EptUndefined; + mGeometryShaderInvocations = 0; + mGeometryShaderMaxVertices = -1; + + mBuiltInFunctionEmulator.cleanup(); + + mNameMap.clear(); + + mSourcePath = nullptr; + + mSymbolTable.clearCompilationResults(); +} + +bool TCompiler::initCallDag(TIntermNode *root) +{ + mCallDag.clear(); + + switch (mCallDag.init(root, &mDiagnostics)) + { + case CallDAG::INITDAG_SUCCESS: + return true; + case CallDAG::INITDAG_RECURSION: + case CallDAG::INITDAG_UNDEFINED: + // Error message has already been written out. + ASSERT(mDiagnostics.numErrors() > 0); + return false; + } + + UNREACHABLE(); + return true; +} + +bool TCompiler::checkCallDepth() +{ + std::vector<int> depths(mCallDag.size()); + + for (size_t i = 0; i < mCallDag.size(); i++) + { + int depth = 0; + const CallDAG::Record &record = mCallDag.getRecordFromIndex(i); + + for (const int &calleeIndex : record.callees) + { + depth = std::max(depth, depths[calleeIndex] + 1); + } + + depths[i] = depth; + + if (depth >= mResources.MaxCallStackDepth) + { + // Trace back the function chain to have a meaningful info log. + std::stringstream errorStream = sh::InitializeStream<std::stringstream>(); + errorStream << "Call stack too deep (larger than " << mResources.MaxCallStackDepth + << ") with the following call chain: " + << record.node->getFunction()->name(); + + int currentFunction = static_cast<int>(i); + int currentDepth = depth; + + while (currentFunction != -1) + { + errorStream + << " -> " + << mCallDag.getRecordFromIndex(currentFunction).node->getFunction()->name(); + + int nextFunction = -1; + for (const int &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees) + { + if (depths[calleeIndex] == currentDepth - 1) + { + currentDepth--; + nextFunction = calleeIndex; + } + } + + currentFunction = nextFunction; + } + + std::string errorStr = errorStream.str(); + mDiagnostics.globalError(errorStr.c_str()); + + return false; + } + } + + return true; +} + +bool TCompiler::tagUsedFunctions() +{ + // Search from main, starting from the end of the DAG as it usually is the root. + for (size_t i = mCallDag.size(); i-- > 0;) + { + if (mCallDag.getRecordFromIndex(i).node->getFunction()->isMain()) + { + internalTagUsedFunction(i); + return true; + } + } + + mDiagnostics.globalError("Missing main()"); + return false; +} + +void TCompiler::internalTagUsedFunction(size_t index) +{ + if (mFunctionMetadata[index].used) + { + return; + } + + mFunctionMetadata[index].used = true; + + for (int calleeIndex : mCallDag.getRecordFromIndex(index).callees) + { + internalTagUsedFunction(calleeIndex); + } +} + +// A predicate for the stl that returns if a top-level node is unused +class TCompiler::UnusedPredicate +{ + public: + UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas) + : mCallDag(callDag), mMetadatas(metadatas) + {} + + bool operator()(TIntermNode *node) + { + const TIntermFunctionPrototype *asFunctionPrototype = node->getAsFunctionPrototypeNode(); + const TIntermFunctionDefinition *asFunctionDefinition = node->getAsFunctionDefinition(); + + const TFunction *func = nullptr; + + if (asFunctionDefinition) + { + func = asFunctionDefinition->getFunction(); + } + else if (asFunctionPrototype) + { + func = asFunctionPrototype->getFunction(); + } + if (func == nullptr) + { + return false; + } + + size_t callDagIndex = mCallDag->findIndex(func->uniqueId()); + if (callDagIndex == CallDAG::InvalidIndex) + { + // This happens only for unimplemented prototypes which are thus unused + ASSERT(asFunctionPrototype); + return true; + } + + ASSERT(callDagIndex < mMetadatas->size()); + return !(*mMetadatas)[callDagIndex].used; + } + + private: + const CallDAG *mCallDag; + const std::vector<FunctionMetadata> *mMetadatas; +}; + +void TCompiler::pruneUnusedFunctions(TIntermBlock *root) +{ + UnusedPredicate isUnused(&mCallDag, &mFunctionMetadata); + TIntermSequence *sequence = root->getSequence(); + + if (!sequence->empty()) + { + sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), + sequence->end()); + } +} + +bool TCompiler::limitExpressionComplexity(TIntermBlock *root) +{ + if (!IsASTDepthBelowLimit(root, mResources.MaxExpressionComplexity)) + { + mDiagnostics.globalError("Expression too complex."); + return false; + } + + if (!ValidateMaxParameters(root, mResources.MaxFunctionParameters)) + { + mDiagnostics.globalError("Function has too many parameters."); + return false; + } + + return true; +} + +bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions) +{ + return (compileOptions & SH_VARIABLES) != 0; +} + +bool TCompiler::wereVariablesCollected() const +{ + return mVariablesCollected; +} + +void TCompiler::initializeGLPosition(TIntermBlock *root) +{ + InitVariableList list; + sh::ShaderVariable var(GL_FLOAT_VEC4); + var.name = "gl_Position"; + list.push_back(var); + InitializeVariables(root, list, &mSymbolTable, mShaderVersion, mExtensionBehavior, false, + false); +} + +void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root) +{ + sh::InterfaceBlockList list; + + for (const sh::InterfaceBlock &block : mUniformBlocks) + { + if (!block.staticUse && + (block.layout == sh::BLOCKLAYOUT_STD140 || block.layout == sh::BLOCKLAYOUT_SHARED)) + { + list.push_back(block); + } + } + + sh::UseInterfaceBlockFields(root, list, mSymbolTable); +} + +void TCompiler::initializeOutputVariables(TIntermBlock *root) +{ + InitVariableList list; + if (mShaderType == GL_VERTEX_SHADER || mShaderType == GL_GEOMETRY_SHADER_EXT) + { + for (const sh::Varying &var : mOutputVaryings) + { + list.push_back(var); + if (var.name == "gl_Position") + { + ASSERT(!mGLPositionInitialized); + mGLPositionInitialized = true; + } + } + } + else + { + ASSERT(mShaderType == GL_FRAGMENT_SHADER); + for (const sh::OutputVariable &var : mOutputVariables) + { + list.push_back(var); + } + } + InitializeVariables(root, list, &mSymbolTable, mShaderVersion, mExtensionBehavior, false, + false); +} + +const TExtensionBehavior &TCompiler::getExtensionBehavior() const +{ + return mExtensionBehavior; +} + +const char *TCompiler::getSourcePath() const +{ + return mSourcePath; +} + +const ShBuiltInResources &TCompiler::getResources() const +{ + return mResources; +} + +const ArrayBoundsClamper &TCompiler::getArrayBoundsClamper() const +{ + return mArrayBoundsClamper; +} + +ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const +{ + return mResources.ArrayIndexClampingStrategy; +} + +const BuiltInFunctionEmulator &TCompiler::getBuiltInFunctionEmulator() const +{ + return mBuiltInFunctionEmulator; +} + +void TCompiler::writePragma(ShCompileOptions compileOptions) +{ + if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL)) + { + TInfoSinkBase &sink = mInfoSink.obj; + if (mPragma.stdgl.invariantAll) + sink << "#pragma STDGL invariant(all)\n"; + } +} + +bool TCompiler::isVaryingDefined(const char *varyingName) +{ + ASSERT(mVariablesCollected); + for (size_t ii = 0; ii < mInputVaryings.size(); ++ii) + { + if (mInputVaryings[ii].name == varyingName) + { + return true; + } + } + for (size_t ii = 0; ii < mOutputVaryings.size(); ++ii) + { + if (mOutputVaryings[ii].name == varyingName) + { + return true; + } + } + + return false; +} + +void EmitWorkGroupSizeGLSL(const TCompiler &compiler, TInfoSinkBase &sink) +{ + if (compiler.isComputeShaderLocalSizeDeclared()) + { + const sh::WorkGroupSize &localSize = compiler.getComputeShaderLocalSize(); + sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1] + << ", local_size_z=" << localSize[2] << ") in;\n"; + } +} + +void EmitMultiviewGLSL(const TCompiler &compiler, + const ShCompileOptions &compileOptions, + const TBehavior behavior, + TInfoSinkBase &sink) +{ + ASSERT(behavior != EBhUndefined); + if (behavior == EBhDisable) + return; + + const bool isVertexShader = (compiler.getShaderType() == GL_VERTEX_SHADER); + if (compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) + { + // Emit ARB_shader_viewport_layer_array/NV_viewport_array2 in a vertex shader if the + // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the + // OVR_multiview(2) extension is requested. + if (isVertexShader && (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER)) + { + sink << "#if defined(GL_ARB_shader_viewport_layer_array)\n" + << "#extension GL_ARB_shader_viewport_layer_array : require\n" + << "#elif defined(GL_NV_viewport_array2)\n" + << "#extension GL_NV_viewport_array2 : require\n" + << "#endif\n"; + } + } + else + { + sink << "#extension GL_OVR_multiview2 : " << GetBehaviorString(behavior) << "\n"; + + const auto &numViews = compiler.getNumViews(); + if (isVertexShader && numViews != -1) + { + sink << "layout(num_views=" << numViews << ") in;\n"; + } + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/Compiler.h b/gfx/angle/checkout/src/compiler/translator/Compiler.h new file mode 100644 index 0000000000..70c02855f1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Compiler.h @@ -0,0 +1,304 @@ +// +// Copyright (c) 2002-2013 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_COMPILER_H_ +#define COMPILER_TRANSLATOR_COMPILER_H_ + +// +// Machine independent part of the compiler private objects +// sent as ShHandle to the driver. +// +// This should not be included by driver code. +// + +#include <GLSLANG/ShaderVars.h> + +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/CallDAG.h" +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/HashNames.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/Pragma.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/ValidateAST.h" +#include "third_party/compiler/ArrayBoundsClamper.h" + +namespace sh +{ + +class TCompiler; +class TParseContext; +#ifdef ANGLE_ENABLE_HLSL +class TranslatorHLSL; +#endif // ANGLE_ENABLE_HLSL + +// +// Helper function to check if the shader type is GLSL. +// +bool IsGLSL130OrNewer(ShShaderOutput output); +bool IsGLSL420OrNewer(ShShaderOutput output); +bool IsGLSL410OrOlder(ShShaderOutput output); + +// +// Helper function to check if the invariant qualifier can be removed. +// +bool RemoveInvariant(sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput outputType, + ShCompileOptions compileOptions); + +// +// The base class used to back handles returned to the driver. +// +class TShHandleBase +{ + public: + TShHandleBase(); + virtual ~TShHandleBase(); + virtual TCompiler *getAsCompiler() { return 0; } +#ifdef ANGLE_ENABLE_HLSL + virtual TranslatorHLSL *getAsTranslatorHLSL() { return 0; } +#endif // ANGLE_ENABLE_HLSL + + protected: + // Memory allocator. Allocates and tracks memory required by the compiler. + // Deallocates all memory when compiler is destructed. + angle::PoolAllocator allocator; +}; + +// +// The base class for the machine dependent compiler to derive from +// for managing object code from the compile. +// +class TCompiler : public TShHandleBase +{ + public: + TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); + ~TCompiler() override; + TCompiler *getAsCompiler() override { return this; } + + bool Init(const ShBuiltInResources &resources); + + // compileTreeForTesting should be used only when tests require access to + // the AST. Users of this function need to manually manage the global pool + // allocator. Returns nullptr whenever there are compilation errors. + TIntermBlock *compileTreeForTesting(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions); + + bool compile(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions); + + // Get results of the last compilation. + int getShaderVersion() const { return mShaderVersion; } + TInfoSink &getInfoSink() { return mInfoSink; } + + bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } + const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } + int getNumViews() const { return mNumViews; } + + // Clears the results from the previous compilation. + void clearResults(); + + const std::vector<sh::Attribute> &getAttributes() const { return mAttributes; } + const std::vector<sh::OutputVariable> &getOutputVariables() const { return mOutputVariables; } + const std::vector<sh::Uniform> &getUniforms() const { return mUniforms; } + const std::vector<sh::Varying> &getInputVaryings() const { return mInputVaryings; } + const std::vector<sh::Varying> &getOutputVaryings() const { return mOutputVaryings; } + const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const { return mInterfaceBlocks; } + const std::vector<sh::InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; } + const std::vector<sh::InterfaceBlock> &getShaderStorageBlocks() const + { + return mShaderStorageBlocks; + } + const std::vector<sh::InterfaceBlock> &getInBlocks() const { return mInBlocks; } + + ShHashFunction64 getHashFunction() const { return mResources.HashFunction; } + NameMap &getNameMap() { return mNameMap; } + TSymbolTable &getSymbolTable() { return mSymbolTable; } + ShShaderSpec getShaderSpec() const { return mShaderSpec; } + ShShaderOutput getOutputType() const { return mOutputType; } + const std::string &getBuiltInResourcesString() const { return mBuiltInResourcesString; } + + bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const; + + // Get the resources set by InitBuiltInSymbolTable + const ShBuiltInResources &getResources() const; + + int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; } + int getGeometryShaderInvocations() const { return mGeometryShaderInvocations; } + TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const + { + return mGeometryShaderInputPrimitiveType; + } + TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const + { + return mGeometryShaderOutputPrimitiveType; + } + + sh::GLenum getShaderType() const { return mShaderType; } + + protected: + // Add emulated functions to the built-in function emulator. + virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) + {} + // Translate to object code. May generate performance warnings through the diagnostics. + virtual void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) = 0; + // Get built-in extensions with default behavior. + const TExtensionBehavior &getExtensionBehavior() const; + const char *getSourcePath() const; + const TPragma &getPragma() const { return mPragma; } + void writePragma(ShCompileOptions compileOptions); + // Relies on collectVariables having been called. + bool isVaryingDefined(const char *varyingName); + + const ArrayBoundsClamper &getArrayBoundsClamper() const; + ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; + const BuiltInFunctionEmulator &getBuiltInFunctionEmulator() const; + + virtual bool shouldFlattenPragmaStdglInvariantAll() = 0; + virtual bool shouldCollectVariables(ShCompileOptions compileOptions); + + bool wereVariablesCollected() const; + std::vector<sh::Attribute> mAttributes; + std::vector<sh::OutputVariable> mOutputVariables; + std::vector<sh::Uniform> mUniforms; + std::vector<sh::Varying> mInputVaryings; + std::vector<sh::Varying> mOutputVaryings; + std::vector<sh::InterfaceBlock> mInterfaceBlocks; + std::vector<sh::InterfaceBlock> mUniformBlocks; + std::vector<sh::InterfaceBlock> mShaderStorageBlocks; + std::vector<sh::InterfaceBlock> mInBlocks; + + private: + // Initialize symbol-table with built-in symbols. + bool initBuiltInSymbolTable(const ShBuiltInResources &resources); + // Compute the string representation of the built-in resources + void setResourceString(); + // Return false if the call depth is exceeded. + bool checkCallDepth(); + // Insert statements to reference all members in unused uniform blocks with standard and shared + // layout. This is to work around a Mac driver that treats unused standard/shared + // uniform blocks as inactive. + void useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root); + // Insert statements to initialize output variables in the beginning of main(). + // This is to avoid undefined behaviors. + void initializeOutputVariables(TIntermBlock *root); + // Insert gl_Position = vec4(0,0,0,0) to the beginning of main(). + // It is to work around a Linux driver bug where missing this causes compile failure + // while spec says it is allowed. + // This function should only be applied to vertex shaders. + void initializeGLPosition(TIntermBlock *root); + // Return true if the maximum expression complexity is below the limit. + bool limitExpressionComplexity(TIntermBlock *root); + // Creates the function call DAG for further analysis, returning false if there is a recursion + bool initCallDag(TIntermNode *root); + // Return false if "main" doesn't exist + bool tagUsedFunctions(); + void internalTagUsedFunction(size_t index); + + void collectInterfaceBlocks(); + + bool mVariablesCollected; + + bool mGLPositionInitialized; + + // Removes unused function declarations and prototypes from the AST + class UnusedPredicate; + void pruneUnusedFunctions(TIntermBlock *root); + + TIntermBlock *compileTreeImpl(const char *const shaderStrings[], + size_t numStrings, + const ShCompileOptions compileOptions); + + // Fetches and stores shader metadata that is not stored within the AST itself, such as shader + // version. + void setASTMetadata(const TParseContext &parseContext); + + // Check if shader version meets the requirement. + bool checkShaderVersion(TParseContext *parseContext); + + // Does checks that need to be run after parsing is complete and returns true if they pass. + bool checkAndSimplifyAST(TIntermBlock *root, + const TParseContext &parseContext, + ShCompileOptions compileOptions); + + sh::GLenum mShaderType; + ShShaderSpec mShaderSpec; + ShShaderOutput mOutputType; + + struct FunctionMetadata + { + FunctionMetadata() : used(false) {} + bool used; + }; + + CallDAG mCallDag; + std::vector<FunctionMetadata> mFunctionMetadata; + + ShBuiltInResources mResources; + std::string mBuiltInResourcesString; + + // Built-in symbol table for the given language, spec, and resources. + // It is preserved from compile-to-compile. + TSymbolTable mSymbolTable; + // Built-in extensions with default behavior. + TExtensionBehavior mExtensionBehavior; + + ArrayBoundsClamper mArrayBoundsClamper; + BuiltInFunctionEmulator mBuiltInFunctionEmulator; + + // Results of compilation. + int mShaderVersion; + TInfoSink mInfoSink; // Output sink. + TDiagnostics mDiagnostics; + const char *mSourcePath; // Path of source file or NULL + + // compute shader local group size + bool mComputeShaderLocalSizeDeclared; + sh::WorkGroupSize mComputeShaderLocalSize; + + // GL_OVR_multiview num_views. + int mNumViews; + + // geometry shader parameters. + int mGeometryShaderMaxVertices; + int mGeometryShaderInvocations; + TLayoutPrimitiveType mGeometryShaderInputPrimitiveType; + TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType; + + // name hashing. + NameMap mNameMap; + + TPragma mPragma; + + // Track what should be validated given passes currently applied. + ValidateASTOptions mValidateASTOptions; +}; + +// +// This is the interface between the machine independent code +// and the machine dependent code. +// +// The machine dependent code should derive from the classes +// above. Then Construct*() and Delete*() will create and +// destroy the machine dependent objects, which contain the +// above machine independent information. +// +TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); +void DeleteCompiler(TCompiler *); + +void EmitWorkGroupSizeGLSL(const TCompiler &, TInfoSinkBase &sink); +void EmitMultiviewGLSL(const TCompiler &, const ShCompileOptions &, TBehavior, TInfoSinkBase &sink); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_COMPILER_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ConstantUnion.cpp b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.cpp new file mode 100644 index 0000000000..fe22a2d9b9 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.cpp @@ -0,0 +1,772 @@ +// +// 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. +// +// ConstantUnion: Constant folding helper class. + +#include "compiler/translator/ConstantUnion.h" + +#include "common/mathutil.h" +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) +{ + float result = lhs + rhs; + if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) + { + diag->warning(line, "Constant folded undefined addition generated NaN", "+"); + } + else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) + { + diag->warning(line, "Constant folded addition overflowed to infinity", "+"); + } + return result; +} + +float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) +{ + float result = lhs - rhs; + if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) + { + diag->warning(line, "Constant folded undefined subtraction generated NaN", "-"); + } + else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) + { + diag->warning(line, "Constant folded subtraction overflowed to infinity", "-"); + } + return result; +} + +float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line) +{ + float result = lhs * rhs; + if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs)) + { + diag->warning(line, "Constant folded undefined multiplication generated NaN", "*"); + } + else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs)) + { + diag->warning(line, "Constant folded multiplication overflowed to infinity", "*"); + } + return result; +} + +bool IsValidShiftOffset(const TConstantUnion &rhs) +{ + return (rhs.getType() == EbtInt && (rhs.getIConst() >= 0 && rhs.getIConst() <= 31)) || + (rhs.getType() == EbtUInt && rhs.getUConst() <= 31u); +} + +} // anonymous namespace + +TConstantUnion::TConstantUnion() +{ + iConst = 0; + type = EbtVoid; +} + +int TConstantUnion::getIConst() const +{ + ASSERT(type == EbtInt); + return iConst; +} + +unsigned int TConstantUnion::getUConst() const +{ + ASSERT(type == EbtUInt); + return uConst; +} + +float TConstantUnion::getFConst() const +{ + switch (type) + { + case EbtInt: + return static_cast<float>(iConst); + case EbtUInt: + return static_cast<float>(uConst); + default: + ASSERT(type == EbtFloat); + return fConst; + } +} + +bool TConstantUnion::getBConst() const +{ + ASSERT(type == EbtBool); + return bConst; +} + +TYuvCscStandardEXT TConstantUnion::getYuvCscStandardEXTConst() const +{ + ASSERT(type == EbtYuvCscStandardEXT); + return yuvCscStandardEXTConst; +} + +bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant) +{ + switch (newType) + { + case EbtFloat: + switch (constant.type) + { + case EbtInt: + setFConst(static_cast<float>(constant.getIConst())); + break; + case EbtUInt: + setFConst(static_cast<float>(constant.getUConst())); + break; + case EbtBool: + setFConst(static_cast<float>(constant.getBConst())); + break; + case EbtFloat: + setFConst(static_cast<float>(constant.getFConst())); + break; + default: + return false; + } + break; + case EbtInt: + switch (constant.type) + { + case EbtInt: + setIConst(static_cast<int>(constant.getIConst())); + break; + case EbtUInt: + setIConst(static_cast<int>(constant.getUConst())); + break; + case EbtBool: + setIConst(static_cast<int>(constant.getBConst())); + break; + case EbtFloat: + setIConst(static_cast<int>(constant.getFConst())); + break; + default: + return false; + } + break; + case EbtUInt: + switch (constant.type) + { + case EbtInt: + setUConst(static_cast<unsigned int>(constant.getIConst())); + break; + case EbtUInt: + setUConst(static_cast<unsigned int>(constant.getUConst())); + break; + case EbtBool: + setUConst(static_cast<unsigned int>(constant.getBConst())); + break; + case EbtFloat: + if (constant.getFConst() < 0.0f) + { + // Avoid undefined behavior in C++ by first casting to signed int. + setUConst( + static_cast<unsigned int>(static_cast<int>(constant.getFConst()))); + } + else + { + setUConst(static_cast<unsigned int>(constant.getFConst())); + } + break; + default: + return false; + } + break; + case EbtBool: + switch (constant.type) + { + case EbtInt: + setBConst(constant.getIConst() != 0); + break; + case EbtUInt: + setBConst(constant.getUConst() != 0); + break; + case EbtBool: + setBConst(constant.getBConst()); + break; + case EbtFloat: + setBConst(constant.getFConst() != 0.0f); + break; + default: + return false; + } + break; + case EbtStruct: // Struct fields don't get cast + switch (constant.type) + { + case EbtInt: + setIConst(constant.getIConst()); + break; + case EbtUInt: + setUConst(constant.getUConst()); + break; + case EbtBool: + setBConst(constant.getBConst()); + break; + case EbtFloat: + setFConst(constant.getFConst()); + break; + default: + return false; + } + break; + default: + return false; + } + + return true; +} + +bool TConstantUnion::operator==(const int i) const +{ + switch (type) + { + case EbtFloat: + return static_cast<float>(i) == fConst; + default: + return i == iConst; + } +} + +bool TConstantUnion::operator==(const unsigned int u) const +{ + switch (type) + { + case EbtFloat: + return static_cast<float>(u) == fConst; + default: + return u == uConst; + } +} + +bool TConstantUnion::operator==(const float f) const +{ + switch (type) + { + case EbtInt: + return f == static_cast<float>(iConst); + case EbtUInt: + return f == static_cast<float>(uConst); + default: + return f == fConst; + } +} + +bool TConstantUnion::operator==(const bool b) const +{ + return b == bConst; +} + +bool TConstantUnion::operator==(const TYuvCscStandardEXT s) const +{ + return s == yuvCscStandardEXTConst; +} + +bool TConstantUnion::operator==(const TConstantUnion &constant) const +{ + ImplicitTypeConversion conversion = GetConversion(constant.type, type); + if (conversion == ImplicitTypeConversion::Same) + { + switch (type) + { + case EbtInt: + return constant.iConst == iConst; + case EbtUInt: + return constant.uConst == uConst; + case EbtFloat: + return constant.fConst == fConst; + case EbtBool: + return constant.bConst == bConst; + case EbtYuvCscStandardEXT: + return constant.yuvCscStandardEXTConst == yuvCscStandardEXTConst; + default: + return false; + } + } + else if (conversion == ImplicitTypeConversion::Invalid) + { + return false; + } + else + { + return constant.getFConst() == getFConst(); + } +} + +bool TConstantUnion::operator!=(const int i) const +{ + return !operator==(i); +} + +bool TConstantUnion::operator!=(const unsigned int u) const +{ + return !operator==(u); +} + +bool TConstantUnion::operator!=(const float f) const +{ + return !operator==(f); +} + +bool TConstantUnion::operator!=(const bool b) const +{ + return !operator==(b); +} + +bool TConstantUnion::operator!=(const TYuvCscStandardEXT s) const +{ + return !operator==(s); +} + +bool TConstantUnion::operator!=(const TConstantUnion &constant) const +{ + return !operator==(constant); +} + +bool TConstantUnion::operator>(const TConstantUnion &constant) const +{ + + ImplicitTypeConversion conversion = GetConversion(constant.type, type); + if (conversion == ImplicitTypeConversion::Same) + { + switch (type) + { + case EbtInt: + return iConst > constant.iConst; + case EbtUInt: + return uConst > constant.uConst; + case EbtFloat: + return fConst > constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + } + else + { + ASSERT(conversion != ImplicitTypeConversion::Invalid); + return getFConst() > constant.getFConst(); + } +} + +bool TConstantUnion::operator<(const TConstantUnion &constant) const +{ + ImplicitTypeConversion conversion = GetConversion(constant.type, type); + if (conversion == ImplicitTypeConversion::Same) + { + switch (type) + { + case EbtInt: + return iConst < constant.iConst; + case EbtUInt: + return uConst < constant.uConst; + case EbtFloat: + return fConst < constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + } + else + { + ASSERT(conversion != ImplicitTypeConversion::Invalid); + return getFConst() < constant.getFConst(); + } +} + +// static +TConstantUnion TConstantUnion::add(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + + ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type); + if (conversion == ImplicitTypeConversion::Same) + { + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst)); + break; + case EbtUInt: + returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst)); + break; + case EbtFloat: + returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line)); + break; + default: + UNREACHABLE(); + } + } + else + { + ASSERT(conversion != ImplicitTypeConversion::Invalid); + returnValue.setFConst(CheckedSum(lhs.getFConst(), rhs.getFConst(), diag, line)); + } + + return returnValue; +} + +// static +TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + + ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type); + if (conversion == ImplicitTypeConversion::Same) + { + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst)); + break; + case EbtUInt: + returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst)); + break; + case EbtFloat: + returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line)); + break; + default: + UNREACHABLE(); + } + } + else + { + ASSERT(conversion != ImplicitTypeConversion::Invalid); + returnValue.setFConst(CheckedDiff(lhs.getFConst(), rhs.getFConst(), diag, line)); + } + + return returnValue; +} + +// static +TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + + ImplicitTypeConversion conversion = GetConversion(lhs.type, rhs.type); + if (conversion == ImplicitTypeConversion::Same) + { + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst)); + break; + case EbtUInt: + // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely + // on that to implement wrapping multiplication. + returnValue.setUConst(lhs.uConst * rhs.uConst); + break; + case EbtFloat: + returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line)); + break; + default: + UNREACHABLE(); + } + } + else + { + ASSERT(conversion != ImplicitTypeConversion::Invalid); + returnValue.setFConst(CheckedMul(lhs.getFConst(), rhs.getFConst(), diag, line)); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst % constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst % constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +// static +TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt); + ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt); + if (!IsValidShiftOffset(rhs)) + { + diag->warning(line, "Undefined shift (operand out of range)", ">>"); + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(0); + break; + case EbtUInt: + returnValue.setUConst(0u); + break; + default: + UNREACHABLE(); + } + return returnValue; + } + + switch (lhs.type) + { + case EbtInt: + { + unsigned int shiftOffset = 0; + switch (rhs.type) + { + case EbtInt: + shiftOffset = static_cast<unsigned int>(rhs.iConst); + break; + case EbtUInt: + shiftOffset = rhs.uConst; + break; + default: + UNREACHABLE(); + } + if (shiftOffset > 0) + { + // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend + // the sign bit." In C++ shifting negative integers is undefined, so we implement + // extending the sign bit manually. + int lhsSafe = lhs.iConst; + if (lhsSafe == std::numeric_limits<int>::min()) + { + // The min integer needs special treatment because only bit it has set is the + // sign bit, which we clear later to implement safe right shift of negative + // numbers. + lhsSafe = -0x40000000; + --shiftOffset; + } + if (shiftOffset > 0) + { + bool extendSignBit = false; + if (lhsSafe < 0) + { + extendSignBit = true; + // Clear the sign bit so that bitshift right is defined in C++. + lhsSafe &= 0x7fffffff; + ASSERT(lhsSafe > 0); + } + returnValue.setIConst(lhsSafe >> shiftOffset); + + // Manually fill in the extended sign bit if necessary. + if (extendSignBit) + { + int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset)); + returnValue.setIConst(returnValue.getIConst() | extendedSignBit); + } + } + else + { + returnValue.setIConst(lhsSafe); + } + } + else + { + returnValue.setIConst(lhs.iConst); + } + break; + } + case EbtUInt: + switch (rhs.type) + { + case EbtInt: + returnValue.setUConst(lhs.uConst >> rhs.iConst); + break; + case EbtUInt: + returnValue.setUConst(lhs.uConst >> rhs.uConst); + break; + default: + UNREACHABLE(); + } + break; + + default: + UNREACHABLE(); + } + return returnValue; +} + +// static +TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line) +{ + TConstantUnion returnValue; + ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt); + ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt); + if (!IsValidShiftOffset(rhs)) + { + diag->warning(line, "Undefined shift (operand out of range)", "<<"); + switch (lhs.type) + { + case EbtInt: + returnValue.setIConst(0); + break; + case EbtUInt: + returnValue.setUConst(0u); + break; + default: + UNREACHABLE(); + } + return returnValue; + } + + switch (lhs.type) + { + case EbtInt: + switch (rhs.type) + { + // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that + // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed + // integer overflow or undefined shift of a negative integer. + case EbtInt: + returnValue.setIConst( + static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst)); + break; + case EbtUInt: + returnValue.setIConst( + static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst)); + break; + default: + UNREACHABLE(); + } + break; + + case EbtUInt: + switch (rhs.type) + { + case EbtInt: + returnValue.setUConst(lhs.uConst << rhs.iConst); + break; + case EbtUInt: + returnValue.setUConst(lhs.uConst << rhs.uConst); + break; + default: + UNREACHABLE(); + } + break; + + default: + UNREACHABLE(); + } + return returnValue; +} + +TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(constant.type == EbtInt || constant.type == EbtUInt); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst & constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst & constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst | constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst | constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtInt: + returnValue.setIConst(iConst ^ constant.iConst); + break; + case EbtUInt: + returnValue.setUConst(uConst ^ constant.uConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtBool: + returnValue.setBConst(bConst && constant.bConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const +{ + TConstantUnion returnValue; + ASSERT(type == constant.type); + switch (type) + { + case EbtBool: + returnValue.setBConst(bConst || constant.bConst); + break; + default: + UNREACHABLE(); + } + + return returnValue; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ConstantUnion.h b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.h new file mode 100644 index 0000000000..155fcd44b0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ConstantUnion.h @@ -0,0 +1,119 @@ +// +// Copyright (c) 2002-2014 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_CONSTANTUNION_H_ +#define COMPILER_TRANSLATOR_CONSTANTUNION_H_ + +#include <assert.h> + +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" + +namespace sh +{ + +class TDiagnostics; + +class TConstantUnion +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TConstantUnion(); + + bool cast(TBasicType newType, const TConstantUnion &constant); + + void setIConst(int i) + { + iConst = i; + type = EbtInt; + } + void setUConst(unsigned int u) + { + uConst = u; + type = EbtUInt; + } + void setFConst(float f) + { + fConst = f; + type = EbtFloat; + } + void setBConst(bool b) + { + bConst = b; + type = EbtBool; + } + + void setYuvCscStandardEXTConst(TYuvCscStandardEXT s) + { + yuvCscStandardEXTConst = s; + type = EbtYuvCscStandardEXT; + } + + int getIConst() const; + unsigned int getUConst() const; + float getFConst() const; + bool getBConst() const; + TYuvCscStandardEXT getYuvCscStandardEXTConst() const; + + bool operator==(const int i) const; + bool operator==(const unsigned int u) const; + bool operator==(const float f) const; + bool operator==(const bool b) const; + bool operator==(const TYuvCscStandardEXT s) const; + bool operator==(const TConstantUnion &constant) const; + bool operator!=(const int i) const; + bool operator!=(const unsigned int u) const; + bool operator!=(const float f) const; + bool operator!=(const bool b) const; + bool operator!=(const TYuvCscStandardEXT s) const; + bool operator!=(const TConstantUnion &constant) const; + bool operator>(const TConstantUnion &constant) const; + bool operator<(const TConstantUnion &constant) const; + static TConstantUnion add(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + static TConstantUnion sub(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + static TConstantUnion mul(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + TConstantUnion operator%(const TConstantUnion &constant) const; + static TConstantUnion rshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + static TConstantUnion lshift(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + const TSourceLoc &line); + TConstantUnion operator&(const TConstantUnion &constant) const; + TConstantUnion operator|(const TConstantUnion &constant) const; + TConstantUnion operator^(const TConstantUnion &constant) const; + TConstantUnion operator&&(const TConstantUnion &constant) const; + TConstantUnion operator||(const TConstantUnion &constant) const; + + TBasicType getType() const { return type; } + + private: + union + { + int iConst; // used for ivec, scalar ints + unsigned int uConst; // used for uvec, scalar uints + bool bConst; // used for bvec, scalar bools + float fConst; // used for vec, mat, scalar floats + TYuvCscStandardEXT yuvCscStandardEXTConst; + }; + + TBasicType type; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Declarator.cpp b/gfx/angle/checkout/src/compiler/translator/Declarator.cpp new file mode 100644 index 0000000000..7a17a82b6a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Declarator.cpp @@ -0,0 +1,33 @@ +// +// Copyright (c) 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. +// +// Declarator.cpp: +// Declarator type for parsing structure field declarators. + +#include "compiler/translator/Declarator.h" + +namespace sh +{ + +TDeclarator::TDeclarator(const ImmutableString &name, const TSourceLoc &line) + : mName(name), mArraySizes(nullptr), mLine(line) +{ + ASSERT(mName != ""); +} + +TDeclarator::TDeclarator(const ImmutableString &name, + const TVector<unsigned int> *arraySizes, + const TSourceLoc &line) + : mName(name), mArraySizes(arraySizes), mLine(line) +{ + ASSERT(mArraySizes); +} + +bool TDeclarator::isArray() const +{ + return mArraySizes != nullptr && mArraySizes->size() > 0; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/Declarator.h b/gfx/angle/checkout/src/compiler/translator/Declarator.h new file mode 100644 index 0000000000..5b5d26b53a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Declarator.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 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. +// +// Declarator.h: +// Declarator type for parsing structure field declarators. + +#ifndef COMPILER_TRANSLATOR_DECLARATOR_H_ +#define COMPILER_TRANSLATOR_DECLARATOR_H_ + +#include "compiler/translator/Common.h" +#include "compiler/translator/ImmutableString.h" + +namespace sh +{ + +// Declarator like "a[2][4]". Only used for parsing structure field declarators. +class TDeclarator : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TDeclarator(const ImmutableString &name, const TSourceLoc &line); + + TDeclarator(const ImmutableString &name, + const TVector<unsigned int> *arraySizes, + const TSourceLoc &line); + + const ImmutableString &name() const { return mName; } + + bool isArray() const; + const TVector<unsigned int> *arraySizes() const { return mArraySizes; } + + const TSourceLoc &line() const { return mLine; } + + private: + const ImmutableString mName; + + // Outermost array size is stored at the end of the vector. + const TVector<unsigned int> *const mArraySizes; + + const TSourceLoc mLine; +}; + +using TDeclaratorList = TVector<TDeclarator *>; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_DECLARATOR_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Diagnostics.cpp b/gfx/angle/checkout/src/compiler/translator/Diagnostics.cpp new file mode 100644 index 0000000000..5ec4867cbb --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Diagnostics.cpp @@ -0,0 +1,106 @@ +// +// Copyright (c) 2012-2013 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/Diagnostics.h" + +#include "common/debug.h" +#include "compiler/preprocessor/SourceLocation.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/InfoSink.h" + +namespace sh +{ + +TDiagnostics::TDiagnostics(TInfoSinkBase &infoSink) + : mInfoSink(infoSink), mNumErrors(0), mNumWarnings(0) +{} + +TDiagnostics::~TDiagnostics() {} + +void TDiagnostics::writeInfo(Severity severity, + const angle::pp::SourceLocation &loc, + const char *reason, + const char *token) +{ + switch (severity) + { + case SH_ERROR: + ++mNumErrors; + break; + case SH_WARNING: + ++mNumWarnings; + break; + default: + UNREACHABLE(); + break; + } + + /* VC++ format: file(linenum) : error #: 'token' : extrainfo */ + mInfoSink.prefix(severity); + mInfoSink.location(loc.file, loc.line); + mInfoSink << "'" << token << "' : " << reason << "\n"; +} + +void TDiagnostics::globalError(const char *message) +{ + ++mNumErrors; + mInfoSink.prefix(SH_ERROR); + mInfoSink << message << "\n"; +} + +void TDiagnostics::error(const angle::pp::SourceLocation &loc, + const char *reason, + const char *token) +{ + writeInfo(SH_ERROR, loc, reason, token); +} + +void TDiagnostics::warning(const angle::pp::SourceLocation &loc, + const char *reason, + const char *token) +{ + writeInfo(SH_WARNING, loc, reason, token); +} + +void TDiagnostics::error(const TSourceLoc &loc, const char *reason, const char *token) +{ + angle::pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + error(srcLoc, reason, token); +} + +void TDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char *token) +{ + angle::pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + warning(srcLoc, reason, token); +} + +void TDiagnostics::print(ID id, const angle::pp::SourceLocation &loc, const std::string &text) +{ + writeInfo(isError(id) ? SH_ERROR : SH_WARNING, loc, message(id), text.c_str()); +} + +void TDiagnostics::resetErrorCount() +{ + mNumErrors = 0; + mNumWarnings = 0; +} + +PerformanceDiagnostics::PerformanceDiagnostics(TDiagnostics *diagnostics) + : mDiagnostics(diagnostics) +{ + ASSERT(diagnostics); +} + +void PerformanceDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char *token) +{ + mDiagnostics->warning(loc, reason, token); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/Diagnostics.h b/gfx/angle/checkout/src/compiler/translator/Diagnostics.h new file mode 100644 index 0000000000..121b6f3c2a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Diagnostics.h @@ -0,0 +1,67 @@ +// +// Copyright (c) 2012-2013 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_DIAGNOSTICS_H_ +#define COMPILER_TRANSLATOR_DIAGNOSTICS_H_ + +#include "common/angleutils.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/translator/Severity.h" + +namespace sh +{ + +class TInfoSinkBase; +struct TSourceLoc; + +class TDiagnostics : public angle::pp::Diagnostics, angle::NonCopyable +{ + public: + TDiagnostics(TInfoSinkBase &infoSink); + ~TDiagnostics() override; + + int numErrors() const { return mNumErrors; } + int numWarnings() const { return mNumWarnings; } + + void error(const angle::pp::SourceLocation &loc, const char *reason, const char *token); + void warning(const angle::pp::SourceLocation &loc, const char *reason, const char *token); + + void error(const TSourceLoc &loc, const char *reason, const char *token); + void warning(const TSourceLoc &loc, const char *reason, const char *token); + + void globalError(const char *message); + + void resetErrorCount(); + + protected: + void writeInfo(Severity severity, + const angle::pp::SourceLocation &loc, + const char *reason, + const char *token); + + void print(ID id, const angle::pp::SourceLocation &loc, const std::string &text) override; + + private: + TInfoSinkBase &mInfoSink; + int mNumErrors; + int mNumWarnings; +}; + +// Diagnostics wrapper to use when the code is only allowed to generate warnings. +class PerformanceDiagnostics : public angle::NonCopyable +{ + public: + PerformanceDiagnostics(TDiagnostics *diagnostics); + + void warning(const TSourceLoc &loc, const char *reason, const char *token); + + private: + TDiagnostics *mDiagnostics; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_DIAGNOSTICS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp new file mode 100644 index 0000000000..8e4dae42d2 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp @@ -0,0 +1,204 @@ +// +// Copyright (c) 2012-2013 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/DirectiveHandler.h" + +#include <sstream> + +#include "angle_gl.h" +#include "common/debug.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/Diagnostics.h" + +namespace sh +{ + +static TBehavior getBehavior(const std::string &str) +{ + const char kRequire[] = "require"; + const char kEnable[] = "enable"; + const char kDisable[] = "disable"; + const char kWarn[] = "warn"; + + if (str == kRequire) + return EBhRequire; + else if (str == kEnable) + return EBhEnable; + else if (str == kDisable) + return EBhDisable; + else if (str == kWarn) + return EBhWarn; + return EBhUndefined; +} + +TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior, + TDiagnostics &diagnostics, + int &shaderVersion, + sh::GLenum shaderType, + bool debugShaderPrecisionSupported) + : mExtensionBehavior(extBehavior), + mDiagnostics(diagnostics), + mShaderVersion(shaderVersion), + mShaderType(shaderType), + mDebugShaderPrecisionSupported(debugShaderPrecisionSupported) +{} + +TDirectiveHandler::~TDirectiveHandler() {} + +void TDirectiveHandler::handleError(const angle::pp::SourceLocation &loc, const std::string &msg) +{ + mDiagnostics.error(loc, msg.c_str(), ""); +} + +void TDirectiveHandler::handlePragma(const angle::pp::SourceLocation &loc, + const std::string &name, + const std::string &value, + bool stdgl) +{ + if (stdgl) + { + const char kInvariant[] = "invariant"; + const char kAll[] = "all"; + + if (name == kInvariant && value == kAll) + { + if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER) + { + // ESSL 3.00.4 section 4.6.1 + mDiagnostics.error( + loc, "#pragma STDGL invariant(all) can not be used in fragment shader", + name.c_str()); + } + mPragma.stdgl.invariantAll = true; + } + // The STDGL pragma is used to reserve pragmas for use by future + // revisions of GLSL. Do not generate an error on unexpected + // name and value. + return; + } + else + { + const char kOptimize[] = "optimize"; + const char kDebug[] = "debug"; + const char kDebugShaderPrecision[] = "webgl_debug_shader_precision"; + const char kOn[] = "on"; + const char kOff[] = "off"; + + bool invalidValue = false; + if (name == kOptimize) + { + if (value == kOn) + mPragma.optimize = true; + else if (value == kOff) + mPragma.optimize = false; + else + invalidValue = true; + } + else if (name == kDebug) + { + if (value == kOn) + mPragma.debug = true; + else if (value == kOff) + mPragma.debug = false; + else + invalidValue = true; + } + else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported) + { + if (value == kOn) + mPragma.debugShaderPrecision = true; + else if (value == kOff) + mPragma.debugShaderPrecision = false; + else + invalidValue = true; + } + else + { + mDiagnostics.report(angle::pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); + return; + } + + if (invalidValue) + { + mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str()); + } + } +} + +void TDirectiveHandler::handleExtension(const angle::pp::SourceLocation &loc, + const std::string &name, + const std::string &behavior) +{ + const char kExtAll[] = "all"; + + TBehavior behaviorVal = getBehavior(behavior); + if (behaviorVal == EBhUndefined) + { + mDiagnostics.error(loc, "behavior invalid", name.c_str()); + return; + } + + if (name == kExtAll) + { + if (behaviorVal == EBhRequire) + { + mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str()); + } + else if (behaviorVal == EBhEnable) + { + mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str()); + } + else + { + for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin(); + iter != mExtensionBehavior.end(); ++iter) + iter->second = behaviorVal; + } + return; + } + + TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str())); + if (iter != mExtensionBehavior.end()) + { + iter->second = behaviorVal; + return; + } + + switch (behaviorVal) + { + case EBhRequire: + mDiagnostics.error(loc, "extension is not supported", name.c_str()); + break; + case EBhEnable: + case EBhWarn: + case EBhDisable: + mDiagnostics.warning(loc, "extension is not supported", name.c_str()); + break; + default: + UNREACHABLE(); + break; + } +} + +void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc, + int version, + ShShaderSpec spec) +{ + if (((version == 100 || version == 300 || version == 310) && !IsDesktopGLSpec(spec)) || + (version == 330 && IsDesktopGLSpec(spec))) + { + mShaderVersion = version; + } + else + { + std::stringstream stream = sh::InitializeStream<std::stringstream>(); + stream << version; + std::string str = stream.str(); + mDiagnostics.error(loc, "client/version number not supported", str.c_str()); + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.h b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.h new file mode 100644 index 0000000000..2d3b0ce044 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2012 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_DIRECTIVEHANDLER_H_ +#define COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ + +#include "GLSLANG/ShaderLang.h" +#include "common/angleutils.h" +#include "compiler/preprocessor/DirectiveHandlerBase.h" +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/Pragma.h" + +namespace sh +{ +class TDiagnostics; + +class TDirectiveHandler : public angle::pp::DirectiveHandler, angle::NonCopyable +{ + public: + TDirectiveHandler(TExtensionBehavior &extBehavior, + TDiagnostics &diagnostics, + int &shaderVersion, + sh::GLenum shaderType, + bool debugShaderPrecisionSupported); + ~TDirectiveHandler() override; + + const TPragma &pragma() const { return mPragma; } + const TExtensionBehavior &extensionBehavior() const { return mExtensionBehavior; } + + void handleError(const angle::pp::SourceLocation &loc, const std::string &msg) override; + + void handlePragma(const angle::pp::SourceLocation &loc, + const std::string &name, + const std::string &value, + bool stdgl) override; + + void handleExtension(const angle::pp::SourceLocation &loc, + const std::string &name, + const std::string &behavior) override; + + void handleVersion(const angle::pp::SourceLocation &loc, + int version, + ShShaderSpec spec) override; + + private: + TPragma mPragma; + TExtensionBehavior &mExtensionBehavior; + TDiagnostics &mDiagnostics; + int &mShaderVersion; + sh::GLenum mShaderType; + bool mDebugShaderPrecisionSupported; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.cpp b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.cpp new file mode 100644 index 0000000000..5a5c92b8bd --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.cpp @@ -0,0 +1,101 @@ +// +// Copyright (c) 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. +// +// ExtensionBehavior.cpp: Extension name enumeration and data structures for storing extension +// behavior. + +#include "compiler/translator/ExtensionBehavior.h" + +#include "common/debug.h" + +#include <string.h> + +#define LIST_EXTENSIONS(OP) \ + OP(ARB_texture_rectangle) \ + OP(ANGLE_texture_multisample) \ + OP(ARM_shader_framebuffer_fetch) \ + OP(EXT_blend_func_extended) \ + OP(EXT_draw_buffers) \ + OP(EXT_frag_depth) \ + OP(EXT_geometry_shader) \ + OP(EXT_shader_framebuffer_fetch) \ + OP(EXT_shader_texture_lod) \ + OP(EXT_YUV_target) \ + OP(NV_EGL_stream_consumer_external) \ + OP(NV_shader_framebuffer_fetch) \ + OP(OES_EGL_image_external) \ + OP(OES_EGL_image_external_essl3) \ + OP(OES_standard_derivatives) \ + OP(OES_texture_storage_multisample_2d_array) \ + OP(OES_texture_3D) \ + OP(OVR_multiview) \ + OP(OVR_multiview2) \ + OP(ANGLE_multi_draw) \ + OP(ANGLE_base_vertex_base_instance) + +namespace sh +{ + +#define RETURN_EXTENSION_NAME_CASE(ext) \ + case TExtension::ext: \ + return "GL_" #ext; + +const char *GetExtensionNameString(TExtension extension) +{ + switch (extension) + { + LIST_EXTENSIONS(RETURN_EXTENSION_NAME_CASE) + default: + UNREACHABLE(); + return ""; + } +} + +#define RETURN_EXTENSION_IF_NAME_MATCHES(ext) \ + if (strcmp(extWithoutGLPrefix, #ext) == 0) \ + { \ + return TExtension::ext; \ + } + +TExtension GetExtensionByName(const char *extension) +{ + // If first characters of the extension don't equal "GL_", early out. + if (strncmp(extension, "GL_", 3) != 0) + { + return TExtension::UNDEFINED; + } + const char *extWithoutGLPrefix = extension + 3; + + LIST_EXTENSIONS(RETURN_EXTENSION_IF_NAME_MATCHES) + + return TExtension::UNDEFINED; +} + +const char *GetBehaviorString(TBehavior b) +{ + switch (b) + { + case EBhRequire: + return "require"; + case EBhEnable: + return "enable"; + case EBhWarn: + return "warn"; + case EBhDisable: + return "disable"; + default: + return nullptr; + } +} + +bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, TExtension extension) +{ + ASSERT(extension != TExtension::UNDEFINED); + auto iter = extBehavior.find(extension); + return iter != extBehavior.end() && + (iter->second == EBhEnable || iter->second == EBhRequire || iter->second == EBhWarn); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.h b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.h new file mode 100644 index 0000000000..2d27ab9922 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ExtensionBehavior.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2002-2010 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. +// +// ExtensionBehavior.h: Extension name enumeration and data structures for storing extension +// behavior. + +#ifndef COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ +#define COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ + +#include <map> + +namespace sh +{ + +enum class TExtension +{ + UNDEFINED, // Special value used to indicate no extension. + + ARB_texture_rectangle, + ANGLE_texture_multisample, + ARM_shader_framebuffer_fetch, + EXT_blend_func_extended, + EXT_draw_buffers, + EXT_frag_depth, + EXT_geometry_shader, + EXT_shader_framebuffer_fetch, + EXT_shader_texture_lod, + EXT_YUV_target, + NV_EGL_stream_consumer_external, + NV_shader_framebuffer_fetch, + OES_EGL_image_external, + OES_EGL_image_external_essl3, + OES_standard_derivatives, + OES_texture_storage_multisample_2d_array, + OES_texture_3D, + OVR_multiview, + OVR_multiview2, + ANGLE_multi_draw, + ANGLE_base_vertex_base_instance +}; + +enum TBehavior +{ + EBhRequire, + EBhEnable, + EBhWarn, + EBhDisable, + EBhUndefined +}; + +const char *GetExtensionNameString(TExtension extension); +TExtension GetExtensionByName(const char *extension); + +const char *GetBehaviorString(TBehavior b); + +// Mapping between extension id and behavior. +typedef std::map<TExtension, TBehavior> TExtensionBehavior; + +bool IsExtensionEnabled(const TExtensionBehavior &extBehavior, TExtension extension); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.cpp new file mode 100644 index 0000000000..8a7aca95f2 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.cpp @@ -0,0 +1,104 @@ +// +// Copyright (c) 2015 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. +// +// ExtensionGLSL.cpp: Implements the TExtensionGLSL class that tracks GLSL extension requirements +// of shaders. + +#include "compiler/translator/ExtensionGLSL.h" + +#include "compiler/translator/VersionGLSL.h" + +namespace sh +{ + +TExtensionGLSL::TExtensionGLSL(ShShaderOutput output) + : TIntermTraverser(true, false, false), mTargetVersion(ShaderOutputTypeToGLSLVersion(output)) +{} + +const std::set<std::string> &TExtensionGLSL::getEnabledExtensions() const +{ + return mEnabledExtensions; +} + +const std::set<std::string> &TExtensionGLSL::getRequiredExtensions() const +{ + return mRequiredExtensions; +} + +bool TExtensionGLSL::visitUnary(Visit, TIntermUnary *node) +{ + checkOperator(node); + + return true; +} + +bool TExtensionGLSL::visitAggregate(Visit, TIntermAggregate *node) +{ + checkOperator(node); + + return true; +} + +void TExtensionGLSL::checkOperator(TIntermOperator *node) +{ + if (mTargetVersion < GLSL_VERSION_130) + { + return; + } + + switch (node->getOp()) + { + case EOpAbs: + break; + + case EOpSign: + break; + + case EOpMix: + break; + + case EOpFloatBitsToInt: + case EOpFloatBitsToUint: + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + if (mTargetVersion < GLSL_VERSION_330) + { + // Bit conversion functions cannot be emulated. + mRequiredExtensions.insert("GL_ARB_shader_bit_encoding"); + } + break; + + case EOpPackSnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackSnorm2x16: + case EOpUnpackHalf2x16: + if (mTargetVersion < GLSL_VERSION_420) + { + mEnabledExtensions.insert("GL_ARB_shading_language_packing"); + + if (mTargetVersion < GLSL_VERSION_330) + { + // floatBitsToUint and uintBitsToFloat are needed to emulate + // packHalf2x16 and unpackHalf2x16 respectively and cannot be + // emulated themselves. + mRequiredExtensions.insert("GL_ARB_shader_bit_encoding"); + } + } + break; + + case EOpPackUnorm2x16: + case EOpUnpackUnorm2x16: + if (mTargetVersion < GLSL_VERSION_410) + { + mEnabledExtensions.insert("GL_ARB_shading_language_packing"); + } + break; + + default: + break; + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h new file mode 100644 index 0000000000..9d752c4eaf --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2015 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. +// +// ExtensionGLSL.h: Defines the TExtensionGLSL class that tracks GLSL extension requirements of +// shaders. + +#ifndef COMPILER_TRANSLATOR_EXTENSIONGLSL_H_ +#define COMPILER_TRANSLATOR_EXTENSIONGLSL_H_ + +#include <set> +#include <string> + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +// Traverses the intermediate tree to determine which GLSL extensions are required +// to support the shader. +class TExtensionGLSL : public TIntermTraverser +{ + public: + TExtensionGLSL(ShShaderOutput output); + + const std::set<std::string> &getEnabledExtensions() const; + const std::set<std::string> &getRequiredExtensions() const; + + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + private: + void checkOperator(TIntermOperator *node); + + int mTargetVersion; + + std::set<std::string> mEnabledExtensions; + std::set<std::string> mRequiredExtensions; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_EXTENSIONGLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp new file mode 100644 index 0000000000..368854f068 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp @@ -0,0 +1,76 @@ +// +// Copyright (c) 2013 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. +// +// FlagStd140Structs.cpp: Find structs in std140 blocks, where the padding added in the translator +// conflicts with the "natural" unpadded type. + +#include "compiler/translator/FlagStd140Structs.h" + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class FlagStd140StructsTraverser : public TIntermTraverser +{ + public: + FlagStd140StructsTraverser() : TIntermTraverser(true, false, false) {} + + const std::vector<MappedStruct> getMappedStructs() const { return mMappedStructs; } + + protected: + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + + private: + void mapBlockStructMembers(TIntermSymbol *blockDeclarator, const TInterfaceBlock *block); + + std::vector<MappedStruct> mMappedStructs; +}; + +void FlagStd140StructsTraverser::mapBlockStructMembers(TIntermSymbol *blockDeclarator, + const TInterfaceBlock *block) +{ + for (auto *field : block->fields()) + { + if (field->type()->getBasicType() == EbtStruct) + { + MappedStruct mappedStruct; + mappedStruct.blockDeclarator = blockDeclarator; + mappedStruct.field = field; + mMappedStructs.push_back(mappedStruct); + } + } +} + +bool FlagStd140StructsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + TIntermTyped *declarator = node->getSequence()->back()->getAsTyped(); + if (declarator->getBasicType() == EbtInterfaceBlock) + { + const TInterfaceBlock *block = declarator->getType().getInterfaceBlock(); + if (block->blockStorage() == EbsStd140) + { + mapBlockStructMembers(declarator->getAsSymbolNode(), block); + } + } + return false; +} + +} // anonymous namespace + +std::vector<MappedStruct> FlagStd140Structs(TIntermNode *node) +{ + FlagStd140StructsTraverser flaggingTraversal; + + node->traverse(&flaggingTraversal); + + return flaggingTraversal.getMappedStructs(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.h b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.h new file mode 100644 index 0000000000..ce035d9185 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.h @@ -0,0 +1,30 @@ +// +// Copyright (c) 2013 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. +// +// FlagStd140Structs.h: Find structs in std140 blocks, where the padding added in the translator +// conflicts with the "natural" unpadded type. + +#ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ +#define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ + +#include <vector> + +namespace sh +{ + +class TField; +class TIntermNode; +class TIntermSymbol; + +struct MappedStruct +{ + TIntermSymbol *blockDeclarator; + TField *field; +}; + +std::vector<MappedStruct> FlagStd140Structs(TIntermNode *node); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/FunctionLookup.cpp b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.cpp new file mode 100644 index 0000000000..fd5091c5ed --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.cpp @@ -0,0 +1,179 @@ +// +// Copyright (c) 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. +// +// FunctionLookup.cpp: Used for storing function calls that have not yet been resolved during +// parsing. +// + +#include "compiler/translator/FunctionLookup.h" +#include "compiler/translator/ImmutableStringBuilder.h" + +namespace sh +{ + +namespace +{ + +const char kFunctionMangledNameSeparator = '('; + +constexpr const ImmutableString kEmptyName(""); + +// Helper function for GetMangledNames +// Gets all ordered combinations of elements in list[currentIndex, end] +std::vector<std::vector<int>> GetImplicitConversionCombinations(const std::vector<int> &list) +{ + std::vector<std::vector<int>> target; + target.push_back(std::vector<int>()); + + for (size_t currentIndex = 0; currentIndex < list.size(); currentIndex++) + { + size_t prevIterSize = target.size(); + for (size_t copyIndex = 0; copyIndex < prevIterSize; copyIndex++) + { + std::vector<int> combination = target[copyIndex]; + combination.push_back(list[currentIndex]); + target.push_back(combination); + } + } + + return target; +} + +} // anonymous namespace + +TFunctionLookup::TFunctionLookup(const ImmutableString &name, + const TType *constructorType, + const TSymbol *symbol) + : mName(name), mConstructorType(constructorType), mThisNode(nullptr), mSymbol(symbol) +{} + +// static +TFunctionLookup *TFunctionLookup::CreateConstructor(const TType *type) +{ + ASSERT(type != nullptr); + return new TFunctionLookup(kEmptyName, type, nullptr); +} + +// static +TFunctionLookup *TFunctionLookup::CreateFunctionCall(const ImmutableString &name, + const TSymbol *symbol) +{ + ASSERT(name != ""); + return new TFunctionLookup(name, nullptr, symbol); +} + +const ImmutableString &TFunctionLookup::name() const +{ + return mName; +} + +ImmutableString TFunctionLookup::getMangledName() const +{ + return GetMangledName(mName.data(), mArguments); +} + +ImmutableString TFunctionLookup::GetMangledName(const char *functionName, + const TIntermSequence &arguments) +{ + std::string newName(functionName); + newName += kFunctionMangledNameSeparator; + + for (TIntermNode *argument : arguments) + { + newName += argument->getAsTyped()->getType().getMangledName(); + } + return ImmutableString(newName); +} + +std::vector<ImmutableString> GetMangledNames(const char *functionName, + const TIntermSequence &arguments) +{ + std::vector<ImmutableString> target; + + std::vector<int> indexes; + for (int i = 0; i < static_cast<int>(arguments.size()); i++) + { + TIntermNode *argument = arguments[i]; + TBasicType argType = argument->getAsTyped()->getType().getBasicType(); + if (argType == EbtInt || argType == EbtUInt) + { + indexes.push_back(i); + } + } + + std::vector<std::vector<int>> combinations = GetImplicitConversionCombinations(indexes); + for (const std::vector<int> &combination : combinations) + { + // combination: ordered list of indexes for arguments that should be converted to float + std::string newName(functionName); + newName += kFunctionMangledNameSeparator; + // combination[currentIndex] represents index of next argument to be converted + int currentIndex = 0; + for (int i = 0; i < (int)arguments.size(); i++) + { + TIntermNode *argument = arguments[i]; + + if (currentIndex != static_cast<int>(combination.size()) && + combination[currentIndex] == i) + { + // Convert + TType type = argument->getAsTyped()->getType(); + type.setBasicType(EbtFloat); + newName += type.getMangledName(); + currentIndex++; + } + else + { + // Don't convert + newName += argument->getAsTyped()->getType().getMangledName(); + } + } + target.push_back(ImmutableString(newName)); + } + + return target; +} + +std::vector<ImmutableString> TFunctionLookup::getMangledNamesForImplicitConversions() const +{ + return GetMangledNames(mName.data(), mArguments); +} + +bool TFunctionLookup::isConstructor() const +{ + return mConstructorType != nullptr; +} + +const TType &TFunctionLookup::constructorType() const +{ + return *mConstructorType; +} + +void TFunctionLookup::setThisNode(TIntermTyped *thisNode) +{ + mThisNode = thisNode; +} + +TIntermTyped *TFunctionLookup::thisNode() const +{ + return mThisNode; +} + +void TFunctionLookup::addArgument(TIntermTyped *argument) +{ + mArguments.push_back(argument); +} + +TIntermSequence &TFunctionLookup::arguments() +{ + return mArguments; +} + +const TSymbol *TFunctionLookup::symbol() const +{ + return mSymbol; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/FunctionLookup.h b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.h new file mode 100644 index 0000000000..7b0b2dafa5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/FunctionLookup.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 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. +// +// FunctionLookup.h: Used for storing function calls that have not yet been resolved during parsing. +// + +#ifndef COMPILER_TRANSLATOR_FUNCTIONLOOKUP_H_ +#define COMPILER_TRANSLATOR_FUNCTIONLOOKUP_H_ + +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +// A function look-up. +class TFunctionLookup : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE + + static TFunctionLookup *CreateConstructor(const TType *type); + static TFunctionLookup *CreateFunctionCall(const ImmutableString &name, const TSymbol *symbol); + + const ImmutableString &name() const; + ImmutableString getMangledName() const; + static ImmutableString GetMangledName(const char *functionName, + const TIntermSequence &arguments); + std::vector<ImmutableString> getMangledNamesForImplicitConversions() const; + + bool isConstructor() const; + const TType &constructorType() const; + + void setThisNode(TIntermTyped *thisNode); + TIntermTyped *thisNode() const; + + void addArgument(TIntermTyped *argument); + TIntermSequence &arguments(); + + // Symbol looked up in the lexical phase using only the name of the function. + // This does not necessarily correspond to the correct overloaded function. + const TSymbol *symbol() const; + + private: + TFunctionLookup(const ImmutableString &name, + const TType *constructorType, + const TSymbol *symbol); + + const ImmutableString mName; + const TType *const mConstructorType; + TIntermTyped *mThisNode; + TIntermSequence mArguments; + const TSymbol *mSymbol; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_FUNCTIONLOOKUP_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/HashNames.cpp b/gfx/angle/checkout/src/compiler/translator/HashNames.cpp new file mode 100644 index 0000000000..6994c10afa --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/HashNames.cpp @@ -0,0 +1,94 @@ +// +// Copyright (c) 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. +// + +#include "compiler/translator/HashNames.h" + +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Symbol.h" + +namespace sh +{ + +namespace +{ +constexpr const ImmutableString kHashedNamePrefix("webgl_"); + +// Can't prefix with just _ because then we might introduce a double underscore, which is not safe +// in GLSL (ESSL 3.00.6 section 3.8: All identifiers containing a double underscore are reserved for +// use by the underlying implementation). u is short for user-defined. +constexpr const ImmutableString kUnhashedNamePrefix("_u"); + +ImmutableString HashName(const ImmutableString &name, ShHashFunction64 hashFunction) +{ + ASSERT(!name.empty()); + ASSERT(hashFunction); + khronos_uint64_t number = (*hashFunction)(name.data(), name.length()); + + // Build the hashed name in place. + static const unsigned int kHexStrMaxLength = sizeof(number) * 2; + static const size_t kHashedNameMaxLength = kHashedNamePrefix.length() + kHexStrMaxLength; + + ImmutableStringBuilder hashedName(kHashedNameMaxLength); + hashedName << kHashedNamePrefix; + + hashedName.appendHex(number); + + return hashedName; +} + +} // anonymous namespace + +ImmutableString HashName(const ImmutableString &name, + ShHashFunction64 hashFunction, + NameMap *nameMap) +{ + if (hashFunction == nullptr) + { + if (name.length() + kUnhashedNamePrefix.length() > kESSLMaxIdentifierLength) + { + // If the identifier length is already close to the limit, we can't prefix it. This is + // not a problem since there are no builtins or ANGLE's internal variables that would + // have as long names and could conflict. + return name; + } + ImmutableStringBuilder prefixedName(kUnhashedNamePrefix.length() + name.length()); + prefixedName << kUnhashedNamePrefix << name; + return prefixedName; + } + if (nameMap) + { + NameMap::const_iterator it = nameMap->find(name.data()); + if (it != nameMap->end()) + { + // TODO(oetuaho): Would be nice if we didn't need to allocate a string here. + return ImmutableString(it->second); + } + } + ImmutableString hashedName = HashName(name, hashFunction); + if (nameMap) + { + (*nameMap)[name.data()] = hashedName.data(); + } + return hashedName; +} + +ImmutableString HashName(const TSymbol *symbol, ShHashFunction64 hashFunction, NameMap *nameMap) +{ + if (symbol->symbolType() == SymbolType::Empty) + { + return kEmptyImmutableString; + } + if (symbol->symbolType() == SymbolType::AngleInternal || + symbol->symbolType() == SymbolType::BuiltIn) + { + return symbol->name(); + } + return HashName(symbol->name(), hashFunction, nameMap); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/HashNames.h b/gfx/angle/checkout/src/compiler/translator/HashNames.h new file mode 100644 index 0000000000..132cb59337 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/HashNames.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2002-2012 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_HASHNAMES_H_ +#define COMPILER_TRANSLATOR_HASHNAMES_H_ + +#include <map> + +#include "GLSLANG/ShaderLang.h" +#include "compiler/translator/Common.h" + +namespace sh +{ + +typedef std::map<TPersistString, TPersistString> NameMap; + +class ImmutableString; +class TSymbol; + +ImmutableString HashName(const ImmutableString &name, + ShHashFunction64 hashFunction, + NameMap *nameMap); + +// Hash user-defined name for GLSL output, with special handling for internal names. +// The nameMap parameter is optional and is used to cache hashed names if set. +ImmutableString HashName(const TSymbol *symbol, ShHashFunction64 hashFunction, NameMap *nameMap); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_HASHNAMES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.cpp new file mode 100644 index 0000000000..d60cce09e5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.cpp @@ -0,0 +1,371 @@ +// +// Copyright (c) 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. +// +// ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output. +// + +#include "compiler/translator/ImageFunctionHLSL.h" +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/UtilsHLSL.h" + +namespace sh +{ + +// static +ImmutableString ImageFunctionHLSL::GetImageReference( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction) +{ + static const ImmutableString kImageIndexStr("[index]"); + if (imageFunction.readonly) + { + static const ImmutableString kReadonlyImagesStr("readonlyImages"); + ImmutableString suffix( + TextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat)); + out << " const uint index = imageIndex - readonlyImageIndexOffset" << suffix.data() + << ";\n"; + ImmutableStringBuilder imageRefBuilder(kReadonlyImagesStr.length() + suffix.length() + + kImageIndexStr.length()); + imageRefBuilder << kReadonlyImagesStr << suffix << kImageIndexStr; + return imageRefBuilder; + } + else + { + static const ImmutableString kImagesStr("images"); + ImmutableString suffix( + RWTextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat)); + out << " const uint index = imageIndex - imageIndexOffset" << suffix.data() << ";\n"; + ImmutableStringBuilder imageRefBuilder(kImagesStr.length() + suffix.length() + + kImageIndexStr.length()); + imageRefBuilder << kImagesStr << suffix << kImageIndexStr; + return imageRefBuilder; + } +} + +void ImageFunctionHLSL::OutputImageFunctionArgumentList( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction) +{ + out << "uint imageIndex"; + + if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::LOAD || + imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE) + { + switch (imageFunction.image) + { + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + out << ", int2 p"; + break; + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + out << ", int3 p"; + break; + default: + UNREACHABLE(); + } + + if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE) + { + switch (imageFunction.image) + { + case EbtImage2D: + case EbtImage3D: + case EbtImageCube: + case EbtImage2DArray: + out << ", float4 data"; + break; + case EbtIImage2D: + case EbtIImage3D: + case EbtIImageCube: + case EbtIImage2DArray: + out << ", int4 data"; + break; + case EbtUImage2D: + case EbtUImage3D: + case EbtUImageCube: + case EbtUImage2DArray: + out << ", uint4 data"; + break; + default: + UNREACHABLE(); + } + } + } +} + +// static +void ImageFunctionHLSL::OutputImageSizeFunctionBody( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const ImmutableString &imageReference) +{ + if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || + IsImageCube(imageFunction.image)) + { + // "depth" stores either the number of layers in an array texture or 3D depth + out << " uint width; uint height; uint depth;\n" + << " " << imageReference << ".GetDimensions(width, height, depth);\n"; + } + else if (IsImage2D(imageFunction.image)) + { + out << " uint width; uint height;\n" + << " " << imageReference << ".GetDimensions(width, height);\n"; + } + else + UNREACHABLE(); + + if (strcmp(imageFunction.getReturnType(), "int3") == 0) + { + out << " return int3(width, height, depth);\n"; + } + else + { + out << " return int2(width, height);\n"; + } +} + +// static +void ImageFunctionHLSL::OutputImageLoadFunctionBody( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const ImmutableString &imageReference) +{ + if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || + IsImageCube(imageFunction.image)) + { + out << " return " << imageReference << "[uint3(p.x, p.y, p.z)];\n"; + } + else if (IsImage2D(imageFunction.image)) + { + out << " return " << imageReference << "[uint2(p.x, p.y)];\n"; + } + else + UNREACHABLE(); +} + +// static +void ImageFunctionHLSL::OutputImageStoreFunctionBody( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const ImmutableString &imageReference) +{ + if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || + IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image)) + { + out << " " << imageReference << "[p] = data;\n"; + } + else + UNREACHABLE(); +} + +ImmutableString ImageFunctionHLSL::ImageFunction::name() const +{ + static const ImmutableString kGlImageName("gl_image"); + + ImmutableString suffix(nullptr); + if (readonly) + { + suffix = ImmutableString(TextureTypeSuffix(image, imageInternalFormat)); + } + else + { + suffix = ImmutableString(RWTextureTypeSuffix(image, imageInternalFormat)); + } + + ImmutableStringBuilder name(kGlImageName.length() + suffix.length() + 5u); + + name << kGlImageName << suffix; + + switch (method) + { + case Method::SIZE: + name << "Size"; + break; + case Method::LOAD: + name << "Load"; + break; + case Method::STORE: + name << "Store"; + break; + default: + UNREACHABLE(); + } + + return name; +} + +ImageFunctionHLSL::ImageFunction::DataType ImageFunctionHLSL::ImageFunction::getDataType( + TLayoutImageInternalFormat format) const +{ + switch (format) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return ImageFunction::DataType::FLOAT4; + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return ImageFunction::DataType::UINT4; + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return ImageFunction::DataType::INT4; + case EiifRGBA8: + return ImageFunction::DataType::UNORM_FLOAT4; + case EiifRGBA8_SNORM: + return ImageFunction::DataType::SNORM_FLOAT4; + default: + UNREACHABLE(); + } + + return ImageFunction::DataType::NONE; +} + +const char *ImageFunctionHLSL::ImageFunction::getReturnType() const +{ + if (method == ImageFunction::Method::SIZE) + { + switch (image) + { + case EbtImage2D: + case EbtIImage2D: + case EbtUImage2D: + case EbtImageCube: + case EbtIImageCube: + case EbtUImageCube: + return "int2"; + case EbtImage3D: + case EbtIImage3D: + case EbtUImage3D: + case EbtImage2DArray: + case EbtIImage2DArray: + case EbtUImage2DArray: + return "int3"; + default: + UNREACHABLE(); + } + } + else if (method == ImageFunction::Method::LOAD) + { + switch (image) + { + case EbtImage2D: + case EbtImage3D: + case EbtImageCube: + case EbtImage2DArray: + return "float4"; + case EbtIImage2D: + case EbtIImage3D: + case EbtIImageCube: + case EbtIImage2DArray: + return "int4"; + case EbtUImage2D: + case EbtUImage3D: + case EbtUImageCube: + case EbtUImage2DArray: + return "uint4"; + default: + UNREACHABLE(); + } + } + else if (method == ImageFunction::Method::STORE) + { + return "void"; + } + else + { + UNREACHABLE(); + } + return ""; +} + +bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const +{ + return std::tie(image, type, method, readonly) < + std::tie(rhs.image, rhs.type, rhs.method, rhs.readonly); +} + +ImmutableString ImageFunctionHLSL::useImageFunction(const ImmutableString &name, + const TBasicType &type, + TLayoutImageInternalFormat imageInternalFormat, + bool readonly) +{ + ASSERT(IsImage(type)); + ImageFunction imageFunction; + imageFunction.image = type; + imageFunction.imageInternalFormat = imageInternalFormat; + imageFunction.readonly = readonly; + imageFunction.type = imageFunction.getDataType(imageInternalFormat); + + if (name == "imageSize") + { + imageFunction.method = ImageFunction::Method::SIZE; + } + else if (name == "imageLoad") + { + imageFunction.method = ImageFunction::Method::LOAD; + } + else if (name == "imageStore") + { + imageFunction.method = ImageFunction::Method::STORE; + } + else + UNREACHABLE(); + + mUsesImage.insert(imageFunction); + return imageFunction.name(); +} + +void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out) +{ + for (const ImageFunction &imageFunction : mUsesImage) + { + // Skip to generate image2D functions here, dynamically generate these + // functions when linking, or after dispatch or draw. + if (IsImage2D(imageFunction.image)) + { + mUsedImage2DFunctionNames.insert(imageFunction.name().data()); + continue; + } + // Function header + out << imageFunction.getReturnType() << " " << imageFunction.name() << "("; + + OutputImageFunctionArgumentList(out, imageFunction); + + out << ")\n" + "{\n"; + + ImmutableString imageReference = GetImageReference(out, imageFunction); + if (imageFunction.method == ImageFunction::Method::SIZE) + { + OutputImageSizeFunctionBody(out, imageFunction, imageReference); + } + else if (imageFunction.method == ImageFunction::Method::LOAD) + { + OutputImageLoadFunctionBody(out, imageFunction, imageReference); + } + else + { + OutputImageStoreFunctionBody(out, imageFunction, imageReference); + } + + out << "}\n" + "\n"; + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.h new file mode 100644 index 0000000000..56c1dcc8e0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ImageFunctionHLSL.h @@ -0,0 +1,96 @@ +// +// Copyright (c) 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. +// +// ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output. +// + +#ifndef COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_ +#define COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_ + +#include <set> + +#include "GLSLANG/ShaderLang.h" +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/Types.h" + +namespace sh +{ + +class ImageFunctionHLSL final : angle::NonCopyable +{ + public: + // Returns the name of the image function implementation to caller. + // The name that's passed in is the name of the GLSL image function that it should implement. + ImmutableString useImageFunction(const ImmutableString &name, + const TBasicType &type, + TLayoutImageInternalFormat imageInternalFormat, + bool readonly); + + void imageFunctionHeader(TInfoSinkBase &out); + const std::set<std::string> &getUsedImage2DFunctionNames() const + { + return mUsedImage2DFunctionNames; + } + + private: + struct ImageFunction + { + // See ESSL 3.10.4 section 8.12 for reference about what the different methods below do. + enum class Method + { + SIZE, + LOAD, + STORE + }; + + enum class DataType + { + NONE, + FLOAT4, + UINT4, + INT4, + UNORM_FLOAT4, + SNORM_FLOAT4 + }; + + ImmutableString name() const; + + bool operator<(const ImageFunction &rhs) const; + + DataType getDataType(TLayoutImageInternalFormat format) const; + + const char *getReturnType() const; + + TBasicType image; + TLayoutImageInternalFormat imageInternalFormat; + bool readonly; + Method method; + DataType type; + }; + + static ImmutableString GetImageReference(TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction); + static void OutputImageFunctionArgumentList( + TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction); + static void OutputImageSizeFunctionBody(TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const ImmutableString &imageReference); + static void OutputImageLoadFunctionBody(TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const ImmutableString &imageReference); + static void OutputImageStoreFunctionBody(TInfoSinkBase &out, + const ImageFunctionHLSL::ImageFunction &imageFunction, + const ImmutableString &imageReference); + using ImageFunctionSet = std::set<ImageFunction>; + ImageFunctionSet mUsesImage; + std::set<std::string> mUsedImage2DFunctionNames; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_IMAGEFUNCTIONHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp b/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp new file mode 100644 index 0000000000..38f3fa052c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 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. +// +// ImmutableString.cpp: Wrapper for static or pool allocated char arrays, that are guaranteed to be +// valid and unchanged for the duration of the compilation. +// + +#include "compiler/translator/ImmutableString.h" + +std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str) +{ + return os.write(str.data(), str.length()); +} + +#if defined(_MSC_VER) +# pragma warning(disable : 4309) // truncation of constant value +#endif + +namespace sh +{ + +template <> +const size_t ImmutableString::FowlerNollVoHash<4>::kFnvPrime = 16777619u; + +template <> +const size_t ImmutableString::FowlerNollVoHash<4>::kFnvOffsetBasis = 0x811c9dc5u; + +template <> +const size_t ImmutableString::FowlerNollVoHash<8>::kFnvPrime = + static_cast<size_t>(1099511628211ull); + +template <> +const size_t ImmutableString::FowlerNollVoHash<8>::kFnvOffsetBasis = + static_cast<size_t>(0xcbf29ce484222325ull); + +uint32_t ImmutableString::mangledNameHash() const +{ + const char *dataPtr = data(); + uint32_t hash = static_cast<uint32_t>(FowlerNollVoHash<4>::kFnvOffsetBasis); + const uint32_t kMaxSixBitValue = (1u << 6) - 1u; + uint32_t parenLocation = kMaxSixBitValue; + uint32_t hasArrayOrBlockParamBit = 0u; + uint32_t index = 0; + while (dataPtr[index] != '\0') + { + hash = hash ^ dataPtr[index]; + hash = hash * static_cast<uint32_t>(FowlerNollVoHash<4>::kFnvPrime); + if (dataPtr[index] == '(') + { + // We should only reach here once, since this function should not be called with invalid + // mangled names. + ASSERT(parenLocation == kMaxSixBitValue); + parenLocation = index; + } + else if (dataPtr[index] == '{' || dataPtr[index] == '[') + { + hasArrayOrBlockParamBit = 1u; + } + ++index; + } + // Should not be called with strings longer than 63 characters. + ASSERT(index <= kMaxSixBitValue); + return ((hash >> 13) ^ (hash & 0x1fff)) | (index << 19) | (parenLocation << 25) | + (hasArrayOrBlockParamBit << 31); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableString.h b/gfx/angle/checkout/src/compiler/translator/ImmutableString.h new file mode 100644 index 0000000000..5f08ea06cc --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ImmutableString.h @@ -0,0 +1,144 @@ +// +// Copyright (c) 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. +// +// ImmutableString.h: Wrapper for static or pool allocated char arrays, that are guaranteed to be +// valid and unchanged for the duration of the compilation. +// + +#ifndef COMPILER_TRANSLATOR_IMMUTABLESTRING_H_ +#define COMPILER_TRANSLATOR_IMMUTABLESTRING_H_ + +#include <string> + +#include "common/string_utils.h" +#include "compiler/translator/Common.h" + +namespace sh +{ + +namespace +{ +constexpr size_t constStrlen(const char *str) +{ + if (str == nullptr) + { + return 0u; + } + size_t len = 0u; + while (*(str + len) != '\0') + { + ++len; + } + return len; +} +} // namespace + +class ImmutableString +{ + public: + // The data pointer passed in must be one of: + // 1. nullptr (only valid with length 0). + // 2. a null-terminated static char array like a string literal. + // 3. a null-terminated pool allocated char array. This can't be c_str() of a local TString, + // since when a TString goes out of scope it clears its first character. + explicit constexpr ImmutableString(const char *data) : mData(data), mLength(constStrlen(data)) + {} + + constexpr ImmutableString(const char *data, size_t length) : mData(data), mLength(length) {} + + ImmutableString(const std::string &str) + : mData(AllocatePoolCharArray(str.c_str(), str.size())), mLength(str.size()) + {} + + constexpr ImmutableString(const ImmutableString &) = default; + + ImmutableString &operator=(const ImmutableString &) = default; + + constexpr const char *data() const { return mData ? mData : ""; } + constexpr size_t length() const { return mLength; } + + char operator[](size_t index) const { return data()[index]; } + + constexpr bool empty() const { return mLength == 0; } + bool beginsWith(const char *prefix) const { return angle::BeginsWith(data(), prefix); } + constexpr bool beginsWith(const ImmutableString &prefix) const + { + return mLength >= prefix.length() && memcmp(data(), prefix.data(), prefix.length()) == 0; + } + bool contains(const char *substr) const { return strstr(data(), substr) != nullptr; } + + constexpr bool operator==(const ImmutableString &b) const + { + if (mLength != b.mLength) + { + return false; + } + return memcmp(data(), b.data(), mLength) == 0; + } + constexpr bool operator!=(const ImmutableString &b) const { return !(*this == b); } + constexpr bool operator==(const char *b) const + { + if (b == nullptr) + { + return empty(); + } + return strcmp(data(), b) == 0; + } + constexpr bool operator!=(const char *b) const { return !(*this == b); } + bool operator==(const std::string &b) const + { + return mLength == b.length() && memcmp(data(), b.c_str(), mLength) == 0; + } + bool operator!=(const std::string &b) const { return !(*this == b); } + + constexpr bool operator<(const ImmutableString &b) const + { + if (mLength < b.mLength) + { + return true; + } + if (mLength > b.mLength) + { + return false; + } + return (memcmp(data(), b.data(), mLength) < 0); + } + + template <size_t hashBytes> + struct FowlerNollVoHash + { + static const size_t kFnvOffsetBasis; + static const size_t kFnvPrime; + + constexpr size_t operator()(const ImmutableString &a) const + { + const char *data = a.data(); + size_t hash = kFnvOffsetBasis; + while ((*data) != '\0') + { + hash = hash ^ (*data); + hash = hash * kFnvPrime; + ++data; + } + return hash; + } + }; + + // This hash encodes the opening parentheses location (if any), name length and whether the name + // contains { or [ characters in addition to a 19-bit hash. This way the hash is more useful for + // lookups. The string passed in should be at most 63 characters. + uint32_t mangledNameHash() const; + + private: + const char *mData; + size_t mLength; +}; + +constexpr ImmutableString kEmptyImmutableString(""); +} // namespace sh + +std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str); + +#endif // COMPILER_TRANSLATOR_IMMUTABLESTRING_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.cpp b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.cpp new file mode 100644 index 0000000000..d7d0a0135d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 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. +// +// ImmutableStringBuilder.cpp: Stringstream-like utility for building pool allocated strings where +// the maximum length is known in advance. +// + +#include "compiler/translator/ImmutableStringBuilder.h" + +#include <stdio.h> + +namespace sh +{ + +ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const ImmutableString &str) +{ + ASSERT(mData != nullptr); + ASSERT(mPos + str.length() <= mMaxLength); + memcpy(mData + mPos, str.data(), str.length()); + mPos += str.length(); + return *this; +} + +ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const char *str) +{ + ASSERT(mData != nullptr); + size_t len = strlen(str); + ASSERT(mPos + len <= mMaxLength); + memcpy(mData + mPos, str, len); + mPos += len; + return *this; +} + +ImmutableStringBuilder &ImmutableStringBuilder::operator<<(const char &c) +{ + ASSERT(mData != nullptr); + ASSERT(mPos + 1 <= mMaxLength); + mData[mPos++] = c; + return *this; +} + +void ImmutableStringBuilder::appendDecimal(const uint32_t &u) +{ + int numChars = snprintf(mData + mPos, mMaxLength - mPos, "%d", u); + ASSERT(numChars >= 0); + ASSERT(mPos + numChars <= mMaxLength); + mPos += numChars; +} + +ImmutableStringBuilder::operator ImmutableString() +{ + mData[mPos] = '\0'; + ImmutableString str(static_cast<const char *>(mData), mPos); +#if defined(ANGLE_ENABLE_ASSERTS) + // Make sure that nothing is added to the string after it is finalized. + mData = nullptr; +#endif + return str; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h new file mode 100644 index 0000000000..e68459169f --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 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. +// +// ImmutableStringBuilder.h: Stringstream-like utility for building pool allocated strings where the +// maximum length is known in advance. +// + +#ifndef COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_ +#define COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_ + +#include "compiler/translator/ImmutableString.h" + +namespace sh +{ + +class ImmutableStringBuilder +{ + public: + ImmutableStringBuilder(size_t maxLength) + : mPos(0u), mMaxLength(maxLength), mData(AllocateEmptyPoolCharArray(maxLength)) + {} + + ImmutableStringBuilder &operator<<(const ImmutableString &str); + + ImmutableStringBuilder &operator<<(const char *str); + + ImmutableStringBuilder &operator<<(const char &c); + + // This invalidates the ImmutableStringBuilder, so it should only be called once. + operator ImmutableString(); + + void appendDecimal(const uint32_t &i); + + template <typename T> + void appendHex(T number) + { + ASSERT(mData != nullptr); + ASSERT(mPos + sizeof(T) * 2u <= mMaxLength); + int index = static_cast<int>(sizeof(T)) * 2 - 1; + // Loop through leading zeroes. + while (((number >> (index * 4)) & 0xfu) == 0 && index > 0) + { + --index; + } + // Write the rest of the hex digits. + while (index >= 0) + { + char digit = static_cast<char>((number >> (index * 4)) & 0xfu); + char digitChar = (digit < 10) ? (digit + '0') : (digit + ('a' - 10)); + mData[mPos++] = digitChar; + --index; + } + } + + template <typename T> + static constexpr size_t GetHexCharCount() + { + return sizeof(T) * 2; + } + + private: + inline static char *AllocateEmptyPoolCharArray(size_t strLength) + { + size_t requiredSize = strLength + 1u; + return static_cast<char *>(GetGlobalPoolAllocator()->allocate(requiredSize)); + } + + size_t mPos; + size_t mMaxLength; + char *mData; +}; + +// GLSL ES 3.00.6 section 3.9: the maximum length of an identifier is 1024 characters. +constexpr unsigned int kESSLMaxIdentifierLength = 1024u; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_IMMUTABLESTRINGBUILDER_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/InfoSink.cpp b/gfx/angle/checkout/src/compiler/translator/InfoSink.cpp new file mode 100644 index 0000000000..e8a8453081 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/InfoSink.cpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2002-2010 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/InfoSink.h" + +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/Types.h" + +namespace sh +{ + +void TInfoSinkBase::prefix(Severity severity) +{ + switch (severity) + { + case SH_WARNING: + sink.append("WARNING: "); + break; + case SH_ERROR: + sink.append("ERROR: "); + break; + default: + sink.append("UNKOWN ERROR: "); + break; + } +} + +TInfoSinkBase &TInfoSinkBase::operator<<(const ImmutableString &str) +{ + sink.append(str.data()); + return *this; +} + +TInfoSinkBase &TInfoSinkBase::operator<<(const TType &type) +{ + if (type.isInvariant()) + sink.append("invariant "); + if (type.getQualifier() != EvqTemporary && type.getQualifier() != EvqGlobal) + { + sink.append(type.getQualifierString()); + sink.append(" "); + } + if (type.getPrecision() != EbpUndefined) + { + sink.append(type.getPrecisionString()); + sink.append(" "); + } + if (type.isArray()) + { + for (auto arraySizeIter = type.getArraySizes()->rbegin(); + arraySizeIter != type.getArraySizes()->rend(); ++arraySizeIter) + { + *this << "array[" << (*arraySizeIter) << "] of "; + } + } + if (type.isMatrix()) + { + *this << type.getCols() << "X" << type.getRows() << " matrix of "; + } + else if (type.isVector()) + *this << type.getNominalSize() << "-component vector of "; + + sink.append(type.getBasicString()); + return *this; +} + +void TInfoSinkBase::location(int file, int line) +{ + TPersistStringStream stream = sh::InitializeStream<TPersistStringStream>(); + if (line) + stream << file << ":" << line; + else + stream << file << ":? "; + stream << ": "; + + sink.append(stream.str()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/InfoSink.h b/gfx/angle/checkout/src/compiler/translator/InfoSink.h new file mode 100644 index 0000000000..100d06ec6b --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/InfoSink.h @@ -0,0 +1,129 @@ +// +// Copyright (c) 2002-2010 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_INFOSINK_H_ +#define COMPILER_TRANSLATOR_INFOSINK_H_ + +#include <math.h> +#include <stdlib.h> +#include "compiler/translator/Common.h" +#include "compiler/translator/Severity.h" + +namespace sh +{ + +class ImmutableString; +class TType; + +// Returns the fractional part of the given floating-point number. +inline float fractionalPart(float f) +{ + float intPart = 0.0f; + return modff(f, &intPart); +} + +class ImmutableString; + +// +// Encapsulate info logs for all objects that have them. +// +// The methods are a general set of tools for getting a variety of +// messages and types inserted into the log. +// +class TInfoSinkBase +{ + public: + TInfoSinkBase() {} + + template <typename T> + TInfoSinkBase &operator<<(const T &t) + { + TPersistStringStream stream = sh::InitializeStream<TPersistStringStream>(); + stream << t; + sink.append(stream.str()); + return *this; + } + // Override << operator for specific types. It is faster to append strings + // and characters directly to the sink. + TInfoSinkBase &operator<<(char c) + { + sink.append(1, c); + return *this; + } + TInfoSinkBase &operator<<(const char *str) + { + sink.append(str); + return *this; + } + TInfoSinkBase &operator<<(const TPersistString &str) + { + sink.append(str); + return *this; + } + TInfoSinkBase &operator<<(const TString &str) + { + sink.append(str.c_str()); + return *this; + } + TInfoSinkBase &operator<<(const ImmutableString &str); + + TInfoSinkBase &operator<<(const TType &type); + + // Make sure floats are written with correct precision. + TInfoSinkBase &operator<<(float f) + { + // Make sure that at least one decimal point is written. If a number + // does not have a fractional part, the default precision format does + // not write the decimal portion which gets interpreted as integer by + // the compiler. + TPersistStringStream stream = sh::InitializeStream<TPersistStringStream>(); + if (fractionalPart(f) == 0.0f) + { + stream.precision(1); + stream << std::showpoint << std::fixed << f; + } + else + { + stream.unsetf(std::ios::fixed); + stream.unsetf(std::ios::scientific); + stream.precision(8); + stream << f; + } + sink.append(stream.str()); + return *this; + } + // Write boolean values as their names instead of integral value. + TInfoSinkBase &operator<<(bool b) + { + const char *str = b ? "true" : "false"; + sink.append(str); + return *this; + } + + void erase() { sink.clear(); } + int size() { return static_cast<int>(sink.size()); } + + const TPersistString &str() const { return sink; } + const char *c_str() const { return sink.c_str(); } + + void prefix(Severity severity); + void location(int file, int line); + + private: + TPersistString sink; +}; + +class TInfoSink +{ + public: + TInfoSinkBase info; + TInfoSinkBase debug; + TInfoSinkBase obj; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INFOSINK_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Initialize.cpp b/gfx/angle/checkout/src/compiler/translator/Initialize.cpp new file mode 100644 index 0000000000..eb3a7675a1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Initialize.cpp @@ -0,0 +1,117 @@ +// +// Copyright (c) 2002-2014 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/Initialize.h" + +namespace sh +{ + +void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavior &extBehavior) +{ + if (resources.OES_standard_derivatives) + { + extBehavior[TExtension::OES_standard_derivatives] = EBhUndefined; + } + if (resources.OES_EGL_image_external) + { + extBehavior[TExtension::OES_EGL_image_external] = EBhUndefined; + } + if (resources.OES_EGL_image_external_essl3) + { + extBehavior[TExtension::OES_EGL_image_external_essl3] = EBhUndefined; + } + if (resources.NV_EGL_stream_consumer_external) + { + extBehavior[TExtension::NV_EGL_stream_consumer_external] = EBhUndefined; + } + if (resources.ARB_texture_rectangle) + { + // Special: ARB_texture_rectangle extension does not follow the standard for #extension + // directives - it is enabled by default. An extension directive may still disable it. + extBehavior[TExtension::ARB_texture_rectangle] = EBhEnable; + } + if (resources.EXT_blend_func_extended) + { + extBehavior[TExtension::EXT_blend_func_extended] = EBhUndefined; + } + if (resources.EXT_draw_buffers) + { + extBehavior[TExtension::EXT_draw_buffers] = EBhUndefined; + } + if (resources.EXT_frag_depth) + { + extBehavior[TExtension::EXT_frag_depth] = EBhUndefined; + } + if (resources.EXT_shader_texture_lod) + { + extBehavior[TExtension::EXT_shader_texture_lod] = EBhUndefined; + } + if (resources.EXT_shader_framebuffer_fetch) + { + extBehavior[TExtension::EXT_shader_framebuffer_fetch] = EBhUndefined; + } + if (resources.NV_shader_framebuffer_fetch) + { + extBehavior[TExtension::NV_shader_framebuffer_fetch] = EBhUndefined; + } + if (resources.ARM_shader_framebuffer_fetch) + { + extBehavior[TExtension::ARM_shader_framebuffer_fetch] = EBhUndefined; + } + if (resources.OVR_multiview) + { + extBehavior[TExtension::OVR_multiview] = EBhUndefined; + } + if (resources.OVR_multiview2) + { + extBehavior[TExtension::OVR_multiview2] = EBhUndefined; + } + if (resources.EXT_YUV_target) + { + extBehavior[TExtension::EXT_YUV_target] = EBhUndefined; + } + if (resources.EXT_geometry_shader) + { + extBehavior[TExtension::EXT_geometry_shader] = EBhUndefined; + } + if (resources.OES_texture_storage_multisample_2d_array) + { + extBehavior[TExtension::OES_texture_storage_multisample_2d_array] = EBhUndefined; + } + if (resources.OES_texture_3D) + { + extBehavior[TExtension::OES_texture_3D] = EBhUndefined; + } + if (resources.ANGLE_texture_multisample) + { + extBehavior[TExtension::ANGLE_texture_multisample] = EBhUndefined; + } + if (resources.ANGLE_multi_draw) + { + extBehavior[TExtension::ANGLE_multi_draw] = EBhUndefined; + } + if (resources.ANGLE_base_vertex_base_instance) + { + extBehavior[TExtension::ANGLE_base_vertex_base_instance] = EBhUndefined; + } +} + +void ResetExtensionBehavior(TExtensionBehavior &extBehavior) +{ + for (auto &ext : extBehavior) + { + if (ext.first == TExtension::ARB_texture_rectangle) + { + ext.second = EBhEnable; + } + else + { + ext.second = EBhUndefined; + } + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/Initialize.h b/gfx/angle/checkout/src/compiler/translator/Initialize.h new file mode 100644 index 0000000000..290af56684 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Initialize.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2002-2013 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_INITIALIZE_H_ +#define COMPILER_TRANSLATOR_INITIALIZE_H_ + +#include "compiler/translator/Common.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +void InitExtensionBehavior(const ShBuiltInResources &resources, + TExtensionBehavior &extensionBehavior); + +// Resets the behavior of the extensions listed in |extensionBehavior| to the +// undefined state. These extensions will only be those initially supported in +// the ShBuiltInResources object for this compiler instance. All other +// extensions will remain unsupported. +void ResetExtensionBehavior(TExtensionBehavior &extensionBehavior); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INITIALIZE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/InitializeDll.cpp b/gfx/angle/checkout/src/compiler/translator/InitializeDll.cpp new file mode 100644 index 0000000000..0698364500 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/InitializeDll.cpp @@ -0,0 +1,33 @@ +// +// Copyright (c) 2002-2010 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/InitializeDll.h" +#include "compiler/translator/InitializeGlobals.h" + +#include "common/platform.h" + +#include <assert.h> + +namespace sh +{ + +bool InitProcess() +{ + if (!InitializePoolIndex()) + { + assert(0 && "InitProcess(): Failed to initalize global pool"); + return false; + } + + return true; +} + +void DetachProcess() +{ + FreePoolIndex(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/InitializeDll.h b/gfx/angle/checkout/src/compiler/translator/InitializeDll.h new file mode 100644 index 0000000000..87f7251470 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/InitializeDll.h @@ -0,0 +1,15 @@ +// +// Copyright (c) 2002-2010 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_INITIALIZEDLL_H_ +#define COMPILER_TRANSLATOR_INITIALIZEDLL_H_ + +namespace sh +{ +bool InitProcess(); +void DetachProcess(); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/InitializeGlobals.h b/gfx/angle/checkout/src/compiler/translator/InitializeGlobals.h new file mode 100644 index 0000000000..9a67ed0e04 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/InitializeGlobals.h @@ -0,0 +1,13 @@ +// +// Copyright (c) 2002-2010 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_INITIALIZEGLOBALS_H_ +#define COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ + +bool InitializePoolIndex(); +void FreePoolIndex(); + +#endif // COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp b/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp new file mode 100644 index 0000000000..42c1c994cf --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp @@ -0,0 +1,3787 @@ +// +// Copyright (c) 2002-2014 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. +// + +// +// Build the intermediate representation. +// + +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdlib.h> +#include <algorithm> +#include <vector> + +#include "common/mathutil.h" +#include "common/matrix_utils.h" +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +const float kPi = 3.14159265358979323846f; +const float kDegreesToRadiansMultiplier = kPi / 180.0f; +const float kRadiansToDegreesMultiplier = 180.0f / kPi; + +TPrecision GetHigherPrecision(TPrecision left, TPrecision right) +{ + return left > right ? left : right; +} + +TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size) +{ + TConstantUnion *constUnion = new TConstantUnion[size]; + for (unsigned int i = 0; i < size; ++i) + constUnion[i] = constant; + + return constUnion; +} + +void UndefinedConstantFoldingError(const TSourceLoc &loc, + TOperator op, + TBasicType basicType, + TDiagnostics *diagnostics, + TConstantUnion *result) +{ + diagnostics->warning(loc, "operation result is undefined for the values passed in", + GetOperatorString(op)); + + switch (basicType) + { + case EbtFloat: + result->setFConst(0.0f); + break; + case EbtInt: + result->setIConst(0); + break; + case EbtUInt: + result->setUConst(0u); + break; + case EbtBool: + result->setBConst(false); + break; + default: + break; + } +} + +float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize) +{ + float result = 0.0f; + for (size_t i = 0; i < paramArraySize; i++) + { + float f = paramArray[i].getFConst(); + result += f * f; + } + return sqrtf(result); +} + +float VectorDotProduct(const TConstantUnion *paramArray1, + const TConstantUnion *paramArray2, + size_t paramArraySize) +{ + float result = 0.0f; + for (size_t i = 0; i < paramArraySize; i++) + result += paramArray1[i].getFConst() * paramArray2[i].getFConst(); + return result; +} + +TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode) +{ + ASSERT(constArray != nullptr); + // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded + // without being qualified as constant. + TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType()); + folded->setLine(originalNode->getLine()); + return folded; +} + +angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, + const unsigned int rows, + const unsigned int cols) +{ + std::vector<float> elements; + for (size_t i = 0; i < rows * cols; i++) + elements.push_back(paramArray[i].getFConst()); + // Transpose is used since the Matrix constructor expects arguments in row-major order, + // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below + // so that the created matrix will have the expected dimensions after the transpose. + return angle::Matrix<float>(elements, cols, rows).transpose(); +} + +angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int size) +{ + std::vector<float> elements; + for (size_t i = 0; i < size * size; i++) + elements.push_back(paramArray[i].getFConst()); + // Transpose is used since the Matrix constructor expects arguments in row-major order, + // whereas the paramArray is in column-major order. + return angle::Matrix<float>(elements, size).transpose(); +} + +void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray) +{ + // Transpose is used since the input Matrix is in row-major order, + // whereas the actual result should be in column-major order. + angle::Matrix<float> result = m.transpose(); + std::vector<float> resultElements = result.elements(); + for (size_t i = 0; i < resultElements.size(); i++) + resultArray[i].setFConst(resultElements[i]); +} + +bool CanFoldAggregateBuiltInOp(TOperator op) +{ + switch (op) + { + case EOpAtan: + case EOpPow: + case EOpMod: + case EOpMin: + case EOpMax: + case EOpClamp: + case EOpMix: + case EOpStep: + case EOpSmoothstep: + case EOpLdexp: + case EOpMulMatrixComponentWise: + case EOpOuterProduct: + case EOpEqualComponentWise: + case EOpNotEqualComponentWise: + case EOpLessThanComponentWise: + case EOpLessThanEqualComponentWise: + case EOpGreaterThanComponentWise: + case EOpGreaterThanEqualComponentWise: + case EOpDistance: + case EOpDot: + case EOpCross: + case EOpFaceforward: + case EOpReflect: + case EOpRefract: + case EOpBitfieldExtract: + case EOpBitfieldInsert: + return true; + default: + return false; + } +} + +} // namespace + +//////////////////////////////////////////////////////////////// +// +// Member functions of the nodes used for building the tree. +// +//////////////////////////////////////////////////////////////// + +TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t) {} + +void TIntermExpression::setTypePreservePrecision(const TType &t) +{ + TPrecision precision = getPrecision(); + mType = t; + ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined); + mType.setPrecision(precision); +} + +#define REPLACE_IF_IS(node, type, original, replacement) \ + do \ + { \ + if (node == original) \ + { \ + node = static_cast<type *>(replacement); \ + return true; \ + } \ + } while (0) + +size_t TIntermSymbol::getChildCount() const +{ + return 0; +} + +TIntermNode *TIntermSymbol::getChildNode(size_t index) const +{ + UNREACHABLE(); + return nullptr; +} + +size_t TIntermConstantUnion::getChildCount() const +{ + return 0; +} + +TIntermNode *TIntermConstantUnion::getChildNode(size_t index) const +{ + UNREACHABLE(); + return nullptr; +} + +size_t TIntermLoop::getChildCount() const +{ + return (mInit ? 1 : 0) + (mCond ? 1 : 0) + (mExpr ? 1 : 0) + (mBody ? 1 : 0); +} + +TIntermNode *TIntermLoop::getChildNode(size_t index) const +{ + TIntermNode *children[4]; + unsigned int childIndex = 0; + if (mInit) + { + children[childIndex] = mInit; + ++childIndex; + } + if (mCond) + { + children[childIndex] = mCond; + ++childIndex; + } + if (mExpr) + { + children[childIndex] = mExpr; + ++childIndex; + } + if (mBody) + { + children[childIndex] = mBody; + ++childIndex; + } + ASSERT(index < childIndex); + return children[index]; +} + +bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + ASSERT(original != nullptr); // This risks replacing multiple children. + REPLACE_IF_IS(mInit, TIntermNode, original, replacement); + REPLACE_IF_IS(mCond, TIntermTyped, original, replacement); + REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement); + REPLACE_IF_IS(mBody, TIntermBlock, original, replacement); + return false; +} + +size_t TIntermBranch::getChildCount() const +{ + return (mExpression ? 1 : 0); +} + +TIntermNode *TIntermBranch::getChildNode(size_t index) const +{ + ASSERT(mExpression); + ASSERT(index == 0); + return mExpression; +} + +bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement); + return false; +} + +size_t TIntermSwizzle::getChildCount() const +{ + return 1; +} + +TIntermNode *TIntermSwizzle::getChildNode(size_t index) const +{ + ASSERT(mOperand); + ASSERT(index == 0); + return mOperand; +} + +bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType()); + REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); + return false; +} + +size_t TIntermBinary::getChildCount() const +{ + return 2; +} + +TIntermNode *TIntermBinary::getChildNode(size_t index) const +{ + ASSERT(index < 2); + if (index == 0) + { + return mLeft; + } + return mRight; +} + +bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement); + REPLACE_IF_IS(mRight, TIntermTyped, original, replacement); + return false; +} + +size_t TIntermUnary::getChildCount() const +{ + return 1; +} + +TIntermNode *TIntermUnary::getChildNode(size_t index) const +{ + ASSERT(mOperand); + ASSERT(index == 0); + return mOperand; +} + +bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType()); + REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); + return false; +} + +size_t TIntermInvariantDeclaration::getChildCount() const +{ + return 1; +} + +TIntermNode *TIntermInvariantDeclaration::getChildNode(size_t index) const +{ + ASSERT(mSymbol); + ASSERT(index == 0); + return mSymbol; +} + +bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement); + return false; +} + +size_t TIntermFunctionDefinition::getChildCount() const +{ + return 2; +} + +TIntermNode *TIntermFunctionDefinition::getChildNode(size_t index) const +{ + ASSERT(index < 2); + if (index == 0) + { + return mPrototype; + } + return mBody; +} + +bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement); + REPLACE_IF_IS(mBody, TIntermBlock, original, replacement); + return false; +} + +size_t TIntermAggregate::getChildCount() const +{ + return mArguments.size(); +} + +TIntermNode *TIntermAggregate::getChildNode(size_t index) const +{ + return mArguments[index]; +} + +bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + return replaceChildNodeInternal(original, replacement); +} + +size_t TIntermBlock::getChildCount() const +{ + return mStatements.size(); +} + +TIntermNode *TIntermBlock::getChildNode(size_t index) const +{ + return mStatements[index]; +} + +bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + return replaceChildNodeInternal(original, replacement); +} + +size_t TIntermFunctionPrototype::getChildCount() const +{ + return 0; +} + +TIntermNode *TIntermFunctionPrototype::getChildNode(size_t index) const +{ + UNREACHABLE(); + return nullptr; +} + +bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + return false; +} + +size_t TIntermDeclaration::getChildCount() const +{ + return mDeclarators.size(); +} + +TIntermNode *TIntermDeclaration::getChildNode(size_t index) const +{ + return mDeclarators[index]; +} + +bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + return replaceChildNodeInternal(original, replacement); +} + +bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement) +{ + for (size_t ii = 0; ii < getSequence()->size(); ++ii) + { + REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement); + } + return false; +} + +bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original, + const TIntermSequence &replacements) +{ + for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it) + { + if (*it == original) + { + it = getSequence()->erase(it); + getSequence()->insert(it, replacements.begin(), replacements.end()); + return true; + } + } + return false; +} + +bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position, + const TIntermSequence &insertions) +{ + if (position > getSequence()->size()) + { + return false; + } + auto it = getSequence()->begin() + position; + getSequence()->insert(it, insertions.begin(), insertions.end()); + return true; +} + +TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable) {} + +bool TIntermSymbol::hasConstantValue() const +{ + return variable().getConstPointer() != nullptr; +} + +const TConstantUnion *TIntermSymbol::getConstantValue() const +{ + return variable().getConstPointer(); +} + +const TSymbolUniqueId &TIntermSymbol::uniqueId() const +{ + return mVariable->uniqueId(); +} + +ImmutableString TIntermSymbol::getName() const +{ + return mVariable->name(); +} + +const TType &TIntermSymbol::getType() const +{ + return mVariable->getType(); +} + +TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func, + TIntermSequence *arguments) +{ + return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments); +} + +TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func, + TIntermSequence *arguments) +{ + return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments); +} + +TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func, + TIntermSequence *arguments) +{ + // op should be either EOpCallBuiltInFunction or a specific math op. + ASSERT(func.getBuiltInOp() != EOpNull); + return new TIntermAggregate(&func, func.getReturnType(), func.getBuiltInOp(), arguments); +} + +TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type, TIntermSequence *arguments) +{ + return new TIntermAggregate(nullptr, type, EOpConstruct, arguments); +} + +TIntermAggregate::TIntermAggregate(const TFunction *func, + const TType &type, + TOperator op, + TIntermSequence *arguments) + : TIntermOperator(op, type), + mUseEmulatedFunction(false), + mGotPrecisionFromChildren(false), + mFunction(func) +{ + if (arguments != nullptr) + { + mArguments.swap(*arguments); + } + ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty); + setPrecisionAndQualifier(); +} + +void TIntermAggregate::setPrecisionAndQualifier() +{ + mType.setQualifier(EvqTemporary); + if (mOp == EOpCallBuiltInFunction) + { + setBuiltInFunctionPrecision(); + } + else if (!isFunctionCall()) + { + if (isConstructor()) + { + // Structs should not be precision qualified, the individual members may be. + // Built-in types on the other hand should be precision qualified. + if (getBasicType() != EbtStruct) + { + setPrecisionFromChildren(); + } + } + else + { + setPrecisionForBuiltInOp(); + } + if (areChildrenConstQualified()) + { + mType.setQualifier(EvqConst); + } + } +} + +bool TIntermAggregate::areChildrenConstQualified() +{ + for (TIntermNode *&arg : mArguments) + { + TIntermTyped *typedArg = arg->getAsTyped(); + if (typedArg && typedArg->getQualifier() != EvqConst) + { + return false; + } + } + return true; +} + +void TIntermAggregate::setPrecisionFromChildren() +{ + mGotPrecisionFromChildren = true; + if (getBasicType() == EbtBool) + { + mType.setPrecision(EbpUndefined); + return; + } + + TPrecision precision = EbpUndefined; + TIntermSequence::iterator childIter = mArguments.begin(); + while (childIter != mArguments.end()) + { + TIntermTyped *typed = (*childIter)->getAsTyped(); + if (typed) + precision = GetHigherPrecision(typed->getPrecision(), precision); + ++childIter; + } + mType.setPrecision(precision); +} + +void TIntermAggregate::setPrecisionForBuiltInOp() +{ + ASSERT(!isConstructor()); + ASSERT(!isFunctionCall()); + if (!setPrecisionForSpecialBuiltInOp()) + { + setPrecisionFromChildren(); + } +} + +bool TIntermAggregate::setPrecisionForSpecialBuiltInOp() +{ + switch (mOp) + { + case EOpBitfieldExtract: + mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision()); + mGotPrecisionFromChildren = true; + return true; + case EOpBitfieldInsert: + mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(), + mArguments[1]->getAsTyped()->getPrecision())); + mGotPrecisionFromChildren = true; + return true; + case EOpUaddCarry: + case EOpUsubBorrow: + mType.setPrecision(EbpHigh); + return true; + default: + return false; + } +} + +void TIntermAggregate::setBuiltInFunctionPrecision() +{ + // All built-ins returning bool should be handled as ops, not functions. + ASSERT(getBasicType() != EbtBool); + ASSERT(mOp == EOpCallBuiltInFunction); + + TPrecision precision = EbpUndefined; + for (TIntermNode *arg : mArguments) + { + TIntermTyped *typed = arg->getAsTyped(); + // ESSL spec section 8: texture functions get their precision from the sampler. + if (typed && IsSampler(typed->getBasicType())) + { + precision = typed->getPrecision(); + break; + } + } + // ESSL 3.0 spec section 8: textureSize always gets highp precision. + // All other functions that take a sampler are assumed to be texture functions. + if (mFunction->name() == "textureSize") + mType.setPrecision(EbpHigh); + else + mType.setPrecision(precision); +} + +const char *TIntermAggregate::functionName() const +{ + ASSERT(!isConstructor()); + switch (mOp) + { + case EOpCallInternalRawFunction: + case EOpCallBuiltInFunction: + case EOpCallFunctionInAST: + return mFunction->name().data(); + default: + return GetOperatorString(mOp); + } +} + +bool TIntermAggregate::hasConstantValue() const +{ + if (!isConstructor()) + { + return false; + } + for (TIntermNode *constructorArg : mArguments) + { + if (!constructorArg->getAsTyped()->hasConstantValue()) + { + return false; + } + } + return true; +} + +const TConstantUnion *TIntermAggregate::getConstantValue() const +{ + if (!hasConstantValue()) + { + return nullptr; + } + ASSERT(isConstructor()); + ASSERT(mArguments.size() > 0u); + + TConstantUnion *constArray = nullptr; + if (isArray()) + { + size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize(); + constArray = new TConstantUnion[elementSize * getOutermostArraySize()]; + + size_t elementOffset = 0u; + for (TIntermNode *constructorArg : mArguments) + { + const TConstantUnion *elementConstArray = + constructorArg->getAsTyped()->getConstantValue(); + ASSERT(elementConstArray); + size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize; + memcpy(static_cast<void *>(&constArray[elementOffset]), + static_cast<const void *>(elementConstArray), elementSizeBytes); + elementOffset += elementSize; + } + return constArray; + } + + size_t resultSize = getType().getObjectSize(); + constArray = new TConstantUnion[resultSize]; + TBasicType basicType = getBasicType(); + + size_t resultIndex = 0u; + + if (mArguments.size() == 1u) + { + TIntermNode *argument = mArguments.front(); + TIntermTyped *argumentTyped = argument->getAsTyped(); + const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue(); + // Check the special case of constructing a matrix diagonal from a single scalar, + // or a vector from a single scalar. + if (argumentTyped->getType().getObjectSize() == 1u) + { + if (isMatrix()) + { + int resultCols = getType().getCols(); + int resultRows = getType().getRows(); + for (int col = 0; col < resultCols; ++col) + { + for (int row = 0; row < resultRows; ++row) + { + if (col == row) + { + constArray[resultIndex].cast(basicType, argumentConstantValue[0]); + } + else + { + constArray[resultIndex].setFConst(0.0f); + } + ++resultIndex; + } + } + } + else + { + while (resultIndex < resultSize) + { + constArray[resultIndex].cast(basicType, argumentConstantValue[0]); + ++resultIndex; + } + } + ASSERT(resultIndex == resultSize); + return constArray; + } + else if (isMatrix() && argumentTyped->isMatrix()) + { + // The special case of constructing a matrix from a matrix. + int argumentCols = argumentTyped->getType().getCols(); + int argumentRows = argumentTyped->getType().getRows(); + int resultCols = getType().getCols(); + int resultRows = getType().getRows(); + for (int col = 0; col < resultCols; ++col) + { + for (int row = 0; row < resultRows; ++row) + { + if (col < argumentCols && row < argumentRows) + { + constArray[resultIndex].cast( + basicType, argumentConstantValue[col * argumentRows + row]); + } + else if (col == row) + { + constArray[resultIndex].setFConst(1.0f); + } + else + { + constArray[resultIndex].setFConst(0.0f); + } + ++resultIndex; + } + } + ASSERT(resultIndex == resultSize); + return constArray; + } + } + + for (TIntermNode *argument : mArguments) + { + TIntermTyped *argumentTyped = argument->getAsTyped(); + size_t argumentSize = argumentTyped->getType().getObjectSize(); + const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue(); + for (size_t i = 0u; i < argumentSize; ++i) + { + if (resultIndex >= resultSize) + break; + constArray[resultIndex].cast(basicType, argumentConstantValue[i]); + ++resultIndex; + } + } + ASSERT(resultIndex == resultSize); + return constArray; +} + +bool TIntermAggregate::hasSideEffects() const +{ + if (getQualifier() == EvqConst) + { + return false; + } + bool calledFunctionHasNoSideEffects = + isFunctionCall() && mFunction != nullptr && mFunction->isKnownToNotHaveSideEffects(); + if (calledFunctionHasNoSideEffects || isConstructor()) + { + for (TIntermNode *arg : mArguments) + { + if (arg->getAsTyped()->hasSideEffects()) + { + return true; + } + } + return false; + } + // Conservatively assume most aggregate operators have side-effects + return true; +} + +void TIntermBlock::appendStatement(TIntermNode *statement) +{ + // Declaration nodes with no children can appear if it was an empty declaration or if all the + // declarators just added constants to the symbol table instead of generating code. We still + // need to add the declaration to the AST in that case because it might be relevant to the + // validity of switch/case. + if (statement != nullptr) + { + mStatements.push_back(statement); + } +} + +void TIntermBlock::insertStatement(size_t insertPosition, TIntermNode *statement) +{ + ASSERT(statement != nullptr); + mStatements.insert(mStatements.begin() + insertPosition, statement); +} + +void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator) +{ + ASSERT(declarator != nullptr); + ASSERT(declarator->getAsSymbolNode() != nullptr || + (declarator->getAsBinaryNode() != nullptr && + declarator->getAsBinaryNode()->getOp() == EOpInitialize)); + ASSERT(mDeclarators.empty() || + declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType())); + mDeclarators.push_back(declarator); +} + +size_t TIntermTernary::getChildCount() const +{ + return 3; +} + +TIntermNode *TIntermTernary::getChildNode(size_t index) const +{ + ASSERT(index < 3); + if (index == 0) + { + return mCondition; + } + if (index == 1) + { + return mTrueExpression; + } + return mFalseExpression; +} + +bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement); + REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement); + return false; +} + +size_t TIntermIfElse::getChildCount() const +{ + return 1 + (mTrueBlock ? 1 : 0) + (mFalseBlock ? 1 : 0); +} + +TIntermNode *TIntermIfElse::getChildNode(size_t index) const +{ + if (index == 0) + { + return mCondition; + } + if (mTrueBlock && index == 1) + { + return mTrueBlock; + } + return mFalseBlock; +} + +bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement); + REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement); + return false; +} + +size_t TIntermSwitch::getChildCount() const +{ + return 2; +} + +TIntermNode *TIntermSwitch::getChildNode(size_t index) const +{ + ASSERT(index < 2); + if (index == 0) + { + return mInit; + } + return mStatementList; +} + +bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mInit, TIntermTyped, original, replacement); + REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement); + ASSERT(mStatementList); + return false; +} + +size_t TIntermCase::getChildCount() const +{ + return (mCondition ? 1 : 0); +} + +TIntermNode *TIntermCase::getChildNode(size_t index) const +{ + ASSERT(index == 0); + ASSERT(mCondition); + return mCondition; +} + +bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + return false; +} + +TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode() +{ + // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that + // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy. + // We need to manually copy any fields of TIntermNode. + mLine = node.mLine; +} + +bool TIntermTyped::hasConstantValue() const +{ + return false; +} + +const TConstantUnion *TIntermTyped::getConstantValue() const +{ + return nullptr; +} + +TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) + : TIntermExpression(node) +{ + mUnionArrayPointer = node.mUnionArrayPointer; +} + +TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function) + : TIntermTyped(), mFunction(function) +{ + ASSERT(mFunction->symbolType() != SymbolType::Empty); +} + +const TType &TIntermFunctionPrototype::getType() const +{ + return mFunction->getReturnType(); +} + +TIntermAggregate::TIntermAggregate(const TIntermAggregate &node) + : TIntermOperator(node), + mUseEmulatedFunction(node.mUseEmulatedFunction), + mGotPrecisionFromChildren(node.mGotPrecisionFromChildren), + mFunction(node.mFunction) +{ + for (TIntermNode *arg : node.mArguments) + { + TIntermTyped *typedArg = arg->getAsTyped(); + ASSERT(typedArg != nullptr); + TIntermTyped *argCopy = typedArg->deepCopy(); + mArguments.push_back(argCopy); + } +} + +TIntermAggregate *TIntermAggregate::shallowCopy() const +{ + TIntermSequence *copySeq = new TIntermSequence(); + copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end()); + TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, copySeq); + copyNode->setLine(mLine); + return copyNode; +} + +TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node) +{ + TIntermTyped *operandCopy = node.mOperand->deepCopy(); + ASSERT(operandCopy != nullptr); + mOperand = operandCopy; + mSwizzleOffsets = node.mSwizzleOffsets; + mHasFoldedDuplicateOffsets = node.mHasFoldedDuplicateOffsets; +} + +TIntermBinary::TIntermBinary(const TIntermBinary &node) + : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp) +{ + TIntermTyped *leftCopy = node.mLeft->deepCopy(); + TIntermTyped *rightCopy = node.mRight->deepCopy(); + ASSERT(leftCopy != nullptr && rightCopy != nullptr); + mLeft = leftCopy; + mRight = rightCopy; +} + +TIntermUnary::TIntermUnary(const TIntermUnary &node) + : TIntermOperator(node), + mUseEmulatedFunction(node.mUseEmulatedFunction), + mFunction(node.mFunction) +{ + TIntermTyped *operandCopy = node.mOperand->deepCopy(); + ASSERT(operandCopy != nullptr); + mOperand = operandCopy; +} + +TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node) +{ + TIntermTyped *conditionCopy = node.mCondition->deepCopy(); + TIntermTyped *trueCopy = node.mTrueExpression->deepCopy(); + TIntermTyped *falseCopy = node.mFalseExpression->deepCopy(); + ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr); + mCondition = conditionCopy; + mTrueExpression = trueCopy; + mFalseExpression = falseCopy; +} + +bool TIntermOperator::isAssignment() const +{ + return IsAssignment(mOp); +} + +bool TIntermOperator::isMultiplication() const +{ + switch (mOp) + { + case EOpMul: + case EOpMatrixTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpVectorTimesMatrix: + case EOpVectorTimesScalar: + return true; + default: + return false; + } +} + +bool TIntermOperator::isConstructor() const +{ + return (mOp == EOpConstruct); +} + +bool TIntermOperator::isFunctionCall() const +{ + switch (mOp) + { + case EOpCallFunctionInAST: + case EOpCallBuiltInFunction: + case EOpCallInternalRawFunction: + return true; + default: + return false; + } +} + +TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right) +{ + if (left.isMatrix()) + { + if (right.isMatrix()) + { + return EOpMatrixTimesMatrix; + } + else + { + if (right.isVector()) + { + return EOpMatrixTimesVector; + } + else + { + return EOpMatrixTimesScalar; + } + } + } + else + { + if (right.isMatrix()) + { + if (left.isVector()) + { + return EOpVectorTimesMatrix; + } + else + { + return EOpMatrixTimesScalar; + } + } + else + { + // Neither operand is a matrix. + if (left.isVector() == right.isVector()) + { + // Leave as component product. + return EOpMul; + } + else + { + return EOpVectorTimesScalar; + } + } + } +} + +TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right) +{ + if (left.isMatrix()) + { + if (right.isMatrix()) + { + return EOpMatrixTimesMatrixAssign; + } + else + { + // right should be scalar, but this may not be validated yet. + return EOpMatrixTimesScalarAssign; + } + } + else + { + if (right.isMatrix()) + { + // Left should be a vector, but this may not be validated yet. + return EOpVectorTimesMatrixAssign; + } + else + { + // Neither operand is a matrix. + if (left.isVector() == right.isVector()) + { + // Leave as component product. + return EOpMulAssign; + } + else + { + // left should be vector and right should be scalar, but this may not be validated + // yet. + return EOpVectorTimesScalarAssign; + } + } + } +} + +// +// Make sure the type of a unary operator is appropriate for its +// combination of operation and operand type. +// +void TIntermUnary::promote() +{ + if (mOp == EOpArrayLength) + { + // Special case: the qualifier of .length() doesn't depend on the operand qualifier. + setType(TType(EbtInt, EbpUndefined, EvqConst)); + return; + } + + TQualifier resultQualifier = EvqTemporary; + if (mOperand->getQualifier() == EvqConst) + resultQualifier = EvqConst; + + unsigned char operandPrimarySize = + static_cast<unsigned char>(mOperand->getType().getNominalSize()); + switch (mOp) + { + case EOpFloatBitsToInt: + setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpFloatBitsToUint: + setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + setType(TType(EbtUInt, EbpHigh, resultQualifier)); + break; + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + setType(TType(EbtFloat, EbpHigh, resultQualifier, 2)); + break; + case EOpUnpackHalf2x16: + setType(TType(EbtFloat, EbpMedium, resultQualifier, 2)); + break; + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + setType(TType(EbtFloat, EbpMedium, resultQualifier, 4)); + break; + case EOpAny: + case EOpAll: + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; + case EOpLength: + case EOpDeterminant: + setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier)); + break; + case EOpTranspose: + setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier, + static_cast<unsigned char>(mOperand->getType().getRows()), + static_cast<unsigned char>(mOperand->getType().getCols()))); + break; + case EOpIsinf: + case EOpIsnan: + setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize)); + break; + case EOpBitfieldReverse: + setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpBitCount: + setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize)); + break; + case EOpFindLSB: + setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize)); + break; + case EOpFindMSB: + setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize)); + break; + default: + setType(mOperand->getType()); + mType.setQualifier(resultQualifier); + break; + } +} + +TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets) + : TIntermExpression(TType(EbtFloat, EbpUndefined)), + mOperand(operand), + mSwizzleOffsets(swizzleOffsets), + mHasFoldedDuplicateOffsets(false) +{ + ASSERT(mOperand); + ASSERT(mSwizzleOffsets.size() <= 4); + promote(); +} + +TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function) + : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false), mFunction(function) +{ + ASSERT(mOperand); + promote(); +} + +TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right) + : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false) +{ + ASSERT(mLeft); + ASSERT(mRight); + promote(); +} + +TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left, + TIntermTyped *right, + int shaderVersion) +{ + TIntermBinary *node = new TIntermBinary(EOpComma, left, right); + node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right)); + return node; +} + +TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, + const TSourceLoc &line) + : TIntermNode(), mSymbol(symbol) +{ + ASSERT(symbol); + setLine(line); +} + +TIntermTernary::TIntermTernary(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression) + : TIntermExpression(trueExpression->getType()), + mCondition(cond), + mTrueExpression(trueExpression), + mFalseExpression(falseExpression) +{ + ASSERT(mCondition); + ASSERT(mTrueExpression); + ASSERT(mFalseExpression); + getTypePointer()->setQualifier( + TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression)); +} + +TIntermLoop::TIntermLoop(TLoopType type, + TIntermNode *init, + TIntermTyped *cond, + TIntermTyped *expr, + TIntermBlock *body) + : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body) +{ + // Declaration nodes with no children can appear if all the declarators just added constants to + // the symbol table instead of generating code. They're no-ops so don't add them to the tree. + if (mInit && mInit->getAsDeclarationNode() && + mInit->getAsDeclarationNode()->getSequence()->empty()) + { + mInit = nullptr; + } +} + +TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB) + : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB) +{ + ASSERT(mCondition); + // Prune empty false blocks so that there won't be unnecessary operations done on it. + if (mFalseBlock && mFalseBlock->getSequence()->empty()) + { + mFalseBlock = nullptr; + } +} + +TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList) + : TIntermNode(), mInit(init), mStatementList(statementList) +{ + ASSERT(mInit); + ASSERT(mStatementList); +} + +void TIntermSwitch::setStatementList(TIntermBlock *statementList) +{ + ASSERT(statementList); + mStatementList = statementList; +} + +// static +TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression) +{ + if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst && + falseExpression->getQualifier() == EvqConst) + { + return EvqConst; + } + return EvqTemporary; +} + +TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */) +{ + if (mCondition->getAsConstantUnion()) + { + if (mCondition->getAsConstantUnion()->getBConst(0)) + { + return mTrueExpression; + } + else + { + return mFalseExpression; + } + } + return this; +} + +void TIntermSwizzle::promote() +{ + TQualifier resultQualifier = EvqTemporary; + if (mOperand->getQualifier() == EvqConst) + resultQualifier = EvqConst; + + auto numFields = mSwizzleOffsets.size(); + setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier, + static_cast<unsigned char>(numFields))); +} + +bool TIntermSwizzle::hasDuplicateOffsets() const +{ + if (mHasFoldedDuplicateOffsets) + { + return true; + } + int offsetCount[4] = {0u, 0u, 0u, 0u}; + for (const auto offset : mSwizzleOffsets) + { + offsetCount[offset]++; + if (offsetCount[offset] > 1) + { + return true; + } + } + return false; +} + +void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets) +{ + mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets; +} + +bool TIntermSwizzle::offsetsMatch(int offset) const +{ + return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset; +} + +void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const +{ + for (const int offset : mSwizzleOffsets) + { + switch (offset) + { + case 0: + *out << "x"; + break; + case 1: + *out << "y"; + break; + case 2: + *out << "z"; + break; + case 3: + *out << "w"; + break; + default: + UNREACHABLE(); + } + } +} + +TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion, + const TIntermTyped *left, + const TIntermTyped *right) +{ + // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression. + if (shaderVersion >= 300 || left->getQualifier() != EvqConst || + right->getQualifier() != EvqConst) + { + return EvqTemporary; + } + return EvqConst; +} + +// Establishes the type of the result of the binary operation. +void TIntermBinary::promote() +{ + ASSERT(!isMultiplication() || + mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType())); + + // Comma is handled as a special case. Note that the comma node qualifier depends on the shader + // version and so is not being set here. + if (mOp == EOpComma) + { + setType(mRight->getType()); + return; + } + + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + setType(mLeft->getType()); + + TQualifier resultQualifier = EvqConst; + // Binary operations results in temporary variables unless both + // operands are const. + if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) + { + resultQualifier = EvqTemporary; + getTypePointer()->setQualifier(EvqTemporary); + } + + // Handle indexing ops. + switch (mOp) + { + case EOpIndexDirect: + case EOpIndexIndirect: + if (mLeft->isArray()) + { + mType.toArrayElementType(); + } + else if (mLeft->isMatrix()) + { + setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier, + static_cast<unsigned char>(mLeft->getRows()))); + } + else if (mLeft->isVector()) + { + setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier)); + } + else + { + UNREACHABLE(); + } + return; + case EOpIndexDirectStruct: + { + const TFieldList &fields = mLeft->getType().getStruct()->fields(); + const int i = mRight->getAsConstantUnion()->getIConst(0); + setType(*fields[i]->type()); + getTypePointer()->setQualifier(resultQualifier); + return; + } + case EOpIndexDirectInterfaceBlock: + { + const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields(); + const int i = mRight->getAsConstantUnion()->getIConst(0); + setType(*fields[i]->type()); + getTypePointer()->setQualifier(resultQualifier); + return; + } + default: + break; + } + + ASSERT(mLeft->isArray() == mRight->isArray()); + + // The result gets promoted to the highest precision. + TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision()); + getTypePointer()->setPrecision(higherPrecision); + + const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize()); + + // + // All scalars or structs. Code after this test assumes this case is removed! + // + if (nominalSize == 1) + { + switch (mOp) + { + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; + + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalXor: + case EOpLogicalOr: + ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool); + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; + + default: + break; + } + return; + } + + // If we reach here, at least one of the operands is vector or matrix. + // The other operand could be a scalar, vector, or matrix. + TBasicType basicType = mLeft->getBasicType(); + + switch (mOp) + { + case EOpMul: + break; + case EOpMatrixTimesScalar: + if (mRight->isMatrix()) + { + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(mRight->getCols()), + static_cast<unsigned char>(mRight->getRows()))); + } + break; + case EOpMatrixTimesVector: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(mLeft->getRows()), 1)); + break; + case EOpMatrixTimesMatrix: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(mRight->getCols()), + static_cast<unsigned char>(mLeft->getRows()))); + break; + case EOpVectorTimesScalar: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(nominalSize), 1)); + break; + case EOpVectorTimesMatrix: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(mRight->getCols()), 1)); + break; + case EOpMulAssign: + case EOpVectorTimesScalarAssign: + case EOpVectorTimesMatrixAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType())); + break; + case EOpAssign: + case EOpInitialize: + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + { + const int secondarySize = + std::max(mLeft->getSecondarySize(), mRight->getSecondarySize()); + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(nominalSize), + static_cast<unsigned char>(secondarySize))); + ASSERT(!mLeft->isArray() && !mRight->isArray()); + break; + } + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; + + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectInterfaceBlock: + case EOpIndexDirectStruct: + // These ops should be already fully handled. + UNREACHABLE(); + break; + default: + UNREACHABLE(); + break; + } +} + +bool TIntermConstantUnion::hasConstantValue() const +{ + return true; +} + +const TConstantUnion *TIntermConstantUnion::getConstantValue() const +{ + return mUnionArrayPointer; +} + +const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type, + const TConstantUnion *constArray, + int index) +{ + if (type.isArray()) + { + ASSERT(index < static_cast<int>(type.getOutermostArraySize())); + TType arrayElementType(type); + arrayElementType.toArrayElementType(); + size_t arrayElementSize = arrayElementType.getObjectSize(); + return &constArray[arrayElementSize * index]; + } + else if (type.isMatrix()) + { + ASSERT(index < type.getCols()); + int size = type.getRows(); + return &constArray[size * index]; + } + else if (type.isVector()) + { + ASSERT(index < type.getNominalSize()); + return &constArray[index]; + } + else + { + UNREACHABLE(); + return nullptr; + } +} + +TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */) +{ + TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode(); + if (operandSwizzle) + { + // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack + // overflow in ParseContext::checkCanBeLValue(). + bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets(); + TVector<int> foldedOffsets; + for (int offset : mSwizzleOffsets) + { + // Offset should already be validated. + ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size()); + foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]); + } + operandSwizzle->mSwizzleOffsets = foldedOffsets; + operandSwizzle->setType(getType()); + operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets); + return operandSwizzle; + } + TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); + if (operandConstant == nullptr) + { + return this; + } + + TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()]; + for (size_t i = 0; i < mSwizzleOffsets.size(); ++i) + { + constArray[i] = *TIntermConstantUnion::FoldIndexing( + operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i)); + } + return CreateFoldedNode(constArray, this); +} + +TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics) +{ + const TConstantUnion *rightConstant = mRight->getConstantValue(); + switch (mOp) + { + case EOpComma: + { + if (mLeft->hasSideEffects()) + { + return this; + } + return mRight; + } + case EOpIndexDirect: + case EOpIndexDirectStruct: + { + if (rightConstant == nullptr) + { + return this; + } + size_t index = static_cast<size_t>(rightConstant->getIConst()); + TIntermAggregate *leftAggregate = mLeft->getAsAggregate(); + if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() && + !leftAggregate->hasSideEffects()) + { + ASSERT(index < leftAggregate->getSequence()->size()); + // This transformation can't add complexity as we're eliminating the constructor + // entirely. + return leftAggregate->getSequence()->at(index)->getAsTyped(); + } + + // If the indexed value is already a constant union, we can't increase duplication of + // data by folding the indexing. Also fold the node in case it's generally beneficial to + // replace this type of node with a constant union even if that would mean duplicating + // data. + if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion()) + { + const TConstantUnion *constantValue = getConstantValue(); + if (constantValue == nullptr) + { + return this; + } + return CreateFoldedNode(constantValue, this); + } + return this; + } + case EOpIndexIndirect: + case EOpIndexDirectInterfaceBlock: + case EOpInitialize: + // Can never be constant folded. + return this; + default: + { + if (rightConstant == nullptr) + { + return this; + } + const TConstantUnion *leftConstant = mLeft->getConstantValue(); + if (leftConstant == nullptr) + { + return this; + } + const TConstantUnion *constArray = + TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant, + mRight->getType(), diagnostics, mLeft->getLine()); + if (!constArray) + { + return this; + } + return CreateFoldedNode(constArray, this); + } + } +} + +bool TIntermBinary::hasConstantValue() const +{ + switch (mOp) + { + case EOpIndexDirect: + case EOpIndexDirectStruct: + { + if (mLeft->hasConstantValue() && mRight->hasConstantValue()) + { + return true; + } + break; + } + default: + break; + } + return false; +} + +const TConstantUnion *TIntermBinary::getConstantValue() const +{ + if (!hasConstantValue()) + { + return nullptr; + } + + const TConstantUnion *leftConstantValue = mLeft->getConstantValue(); + int index = mRight->getConstantValue()->getIConst(); + const TConstantUnion *constIndexingResult = nullptr; + if (mOp == EOpIndexDirect) + { + constIndexingResult = + TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index); + } + else + { + ASSERT(mOp == EOpIndexDirectStruct); + const TFieldList &fields = mLeft->getType().getStruct()->fields(); + + size_t previousFieldsSize = 0; + for (int i = 0; i < index; ++i) + { + previousFieldsSize += fields[i]->type()->getObjectSize(); + } + constIndexingResult = leftConstantValue + previousFieldsSize; + } + return constIndexingResult; +} + +const ImmutableString &TIntermBinary::getIndexStructFieldName() const +{ + ASSERT(mOp == EOpIndexDirectStruct); + + const TType &lhsType = mLeft->getType(); + const TStructure *structure = lhsType.getStruct(); + const int index = mRight->getAsConstantUnion()->getIConst(0); + + return structure->fields()[index]->name(); +} + +TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics) +{ + TConstantUnion *constArray = nullptr; + + if (mOp == EOpArrayLength) + { + // The size of runtime-sized arrays may only be determined at runtime. + if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray()) + { + return this; + } + constArray = new TConstantUnion[1]; + constArray->setIConst(mOperand->getOutermostArraySize()); + } + else + { + TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); + if (operandConstant == nullptr) + { + return this; + } + + switch (mOp) + { + case EOpAny: + case EOpAll: + case EOpLength: + case EOpTranspose: + case EOpDeterminant: + case EOpInverse: + case EOpPackSnorm2x16: + case EOpUnpackSnorm2x16: + case EOpPackUnorm2x16: + case EOpUnpackUnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackHalf2x16: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + constArray = operandConstant->foldUnaryNonComponentWise(mOp); + break; + default: + constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics); + break; + } + } + if (constArray == nullptr) + { + return this; + } + return CreateFoldedNode(constArray, this); +} + +TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics) +{ + // Make sure that all params are constant before actual constant folding. + for (auto *param : *getSequence()) + { + if (param->getAsConstantUnion() == nullptr) + { + return this; + } + } + const TConstantUnion *constArray = nullptr; + if (isConstructor()) + { + if (mType.canReplaceWithConstantUnion()) + { + constArray = getConstantValue(); + if (constArray && mType.getBasicType() == EbtUInt) + { + // Check if we converted a negative float to uint and issue a warning in that case. + size_t sizeRemaining = mType.getObjectSize(); + for (TIntermNode *arg : mArguments) + { + TIntermTyped *typedArg = arg->getAsTyped(); + if (typedArg->getBasicType() == EbtFloat) + { + const TConstantUnion *argValue = typedArg->getConstantValue(); + size_t castSize = + std::min(typedArg->getType().getObjectSize(), sizeRemaining); + for (size_t i = 0; i < castSize; ++i) + { + if (argValue[i].getFConst() < 0.0f) + { + // ESSL 3.00.6 section 5.4.1. + diagnostics->warning( + mLine, "casting a negative float to uint is undefined", + mType.getBuiltInTypeNameString()); + } + } + } + sizeRemaining -= typedArg->getType().getObjectSize(); + } + } + } + } + else if (CanFoldAggregateBuiltInOp(mOp)) + { + constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics); + } + if (constArray == nullptr) + { + return this; + } + return CreateFoldedNode(constArray, this); +} + +// +// The fold functions see if an operation on a constant can be done in place, +// without generating run-time code. +// +// Returns the constant value to keep using or nullptr. +// +const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op, + const TConstantUnion *leftArray, + const TType &leftType, + const TConstantUnion *rightArray, + const TType &rightType, + TDiagnostics *diagnostics, + const TSourceLoc &line) +{ + ASSERT(leftArray && rightArray); + + size_t objectSize = leftType.getObjectSize(); + + // for a case like float f = vec4(2, 3, 4, 5) + 1.2; + if (rightType.getObjectSize() == 1 && objectSize > 1) + { + rightArray = Vectorize(*rightArray, objectSize); + } + else if (rightType.getObjectSize() > 1 && objectSize == 1) + { + // for a case like float f = 1.2 + vec4(2, 3, 4, 5); + leftArray = Vectorize(*leftArray, rightType.getObjectSize()); + objectSize = rightType.getObjectSize(); + } + + TConstantUnion *resultArray = nullptr; + + switch (op) + { + case EOpAdd: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line); + break; + case EOpSub: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line); + break; + + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line); + break; + + case EOpMatrixTimesMatrix: + { + // TODO(jmadll): This code should check for overflows. + ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat); + + const int leftCols = leftType.getCols(); + const int leftRows = leftType.getRows(); + const int rightCols = rightType.getCols(); + const int rightRows = rightType.getRows(); + const int resultCols = rightCols; + const int resultRows = leftRows; + + resultArray = new TConstantUnion[resultCols * resultRows]; + for (int row = 0; row < resultRows; row++) + { + for (int column = 0; column < resultCols; column++) + { + resultArray[resultRows * column + row].setFConst(0.0f); + for (int i = 0; i < leftCols; i++) + { + resultArray[resultRows * column + row].setFConst( + resultArray[resultRows * column + row].getFConst() + + leftArray[i * leftRows + row].getFConst() * + rightArray[column * rightRows + i].getFConst()); + } + } + } + } + break; + + case EOpDiv: + case EOpIMod: + { + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + if (IsFloatDivision(leftType.getBasicType(), rightType.getBasicType())) + { + // Float division requested, possibly with implicit conversion + ASSERT(op == EOpDiv); + float dividend = leftArray[i].getFConst(); + float divisor = rightArray[i].getFConst(); + + if (divisor == 0.0f) + { + if (dividend == 0.0f) + { + diagnostics->warning(line, + "Zero divided by zero during constant " + "folding generated NaN", + "/"); + resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN()); + } + else + { + diagnostics->warning(line, "Divide by zero during constant folding", + "/"); + bool negativeResult = std::signbit(dividend) != std::signbit(divisor); + resultArray[i].setFConst(negativeResult + ? -std::numeric_limits<float>::infinity() + : std::numeric_limits<float>::infinity()); + } + } + else if (gl::isInf(dividend) && gl::isInf(divisor)) + { + diagnostics->warning(line, + "Infinity divided by infinity during constant " + "folding generated NaN", + "/"); + resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN()); + } + else + { + float result = dividend / divisor; + if (!gl::isInf(dividend) && gl::isInf(result)) + { + diagnostics->warning( + line, "Constant folded division overflowed to infinity", "/"); + } + resultArray[i].setFConst(result); + } + } + else + { + // Types are either both int or both uint + switch (leftType.getBasicType()) + { + case EbtInt: + { + if (rightArray[i] == 0) + { + diagnostics->warning( + line, "Divide by zero error during constant folding", "/"); + resultArray[i].setIConst(INT_MAX); + } + else + { + int lhs = leftArray[i].getIConst(); + int divisor = rightArray[i].getIConst(); + if (op == EOpDiv) + { + // Check for the special case where the minimum + // representable number is divided by -1. If left alone this + // leads to integer overflow in C++. ESSL 3.00.6 + // section 4.1.3 Integers: "However, for the case where the + // minimum representable value is divided by -1, it is + // allowed to return either the minimum representable value + // or the maximum representable value." + if (lhs == -0x7fffffff - 1 && divisor == -1) + { + resultArray[i].setIConst(0x7fffffff); + } + else + { + resultArray[i].setIConst(lhs / divisor); + } + } + else + { + ASSERT(op == EOpIMod); + if (lhs < 0 || divisor < 0) + { + // ESSL 3.00.6 section 5.9: Results of modulus are + // undefined when either one of the operands is + // negative. + diagnostics->warning(line, + "Negative modulus operator operand " + "encountered during constant folding. " + "Results are undefined.", + "%"); + resultArray[i].setIConst(0); + } + else + { + resultArray[i].setIConst(lhs % divisor); + } + } + } + break; + } + case EbtUInt: + { + if (rightArray[i] == 0) + { + diagnostics->warning( + line, "Divide by zero error during constant folding", "/"); + resultArray[i].setUConst(UINT_MAX); + } + else + { + if (op == EOpDiv) + { + resultArray[i].setUConst(leftArray[i].getUConst() / + rightArray[i].getUConst()); + } + else + { + ASSERT(op == EOpIMod); + resultArray[i].setUConst(leftArray[i].getUConst() % + rightArray[i].getUConst()); + } + } + break; + } + default: + UNREACHABLE(); + return nullptr; + } + } + } + } + break; + + case EOpMatrixTimesVector: + { + // TODO(jmadll): This code should check for overflows. + ASSERT(rightType.getBasicType() == EbtFloat); + + const int matrixCols = leftType.getCols(); + const int matrixRows = leftType.getRows(); + + resultArray = new TConstantUnion[matrixRows]; + + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + resultArray[matrixRow].setFConst(0.0f); + for (int col = 0; col < matrixCols; col++) + { + resultArray[matrixRow].setFConst( + resultArray[matrixRow].getFConst() + + leftArray[col * matrixRows + matrixRow].getFConst() * + rightArray[col].getFConst()); + } + } + } + break; + + case EOpVectorTimesMatrix: + { + // TODO(jmadll): This code should check for overflows. + ASSERT(leftType.getBasicType() == EbtFloat); + + const int matrixCols = rightType.getCols(); + const int matrixRows = rightType.getRows(); + + resultArray = new TConstantUnion[matrixCols]; + + for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++) + { + resultArray[matrixCol].setFConst(0.0f); + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + resultArray[matrixCol].setFConst( + resultArray[matrixCol].getFConst() + + leftArray[matrixRow].getFConst() * + rightArray[matrixCol * matrixRows + matrixRow].getFConst()); + } + } + } + break; + + case EOpLogicalAnd: + { + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + resultArray[i] = leftArray[i] && rightArray[i]; + } + } + break; + + case EOpLogicalOr: + { + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + resultArray[i] = leftArray[i] || rightArray[i]; + } + } + break; + + case EOpLogicalXor: + { + ASSERT(leftType.getBasicType() == EbtBool); + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + resultArray[i].setBConst(leftArray[i] != rightArray[i]); + } + } + break; + + case EOpBitwiseAnd: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = leftArray[i] & rightArray[i]; + break; + case EOpBitwiseXor: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = leftArray[i] ^ rightArray[i]; + break; + case EOpBitwiseOr: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = leftArray[i] | rightArray[i]; + break; + case EOpBitShiftLeft: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line); + break; + case EOpBitShiftRight: + resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + resultArray[i] = + TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line); + break; + + case EOpLessThan: + ASSERT(objectSize == 1); + resultArray = new TConstantUnion[1]; + resultArray->setBConst(*leftArray < *rightArray); + break; + + case EOpGreaterThan: + ASSERT(objectSize == 1); + resultArray = new TConstantUnion[1]; + resultArray->setBConst(*leftArray > *rightArray); + break; + + case EOpLessThanEqual: + ASSERT(objectSize == 1); + resultArray = new TConstantUnion[1]; + resultArray->setBConst(!(*leftArray > *rightArray)); + break; + + case EOpGreaterThanEqual: + ASSERT(objectSize == 1); + resultArray = new TConstantUnion[1]; + resultArray->setBConst(!(*leftArray < *rightArray)); + break; + + case EOpEqual: + case EOpNotEqual: + { + resultArray = new TConstantUnion[1]; + bool equal = true; + for (size_t i = 0; i < objectSize; i++) + { + if (leftArray[i] != rightArray[i]) + { + equal = false; + break; // break out of for loop + } + } + if (op == EOpEqual) + { + resultArray->setBConst(equal); + } + else + { + resultArray->setBConst(!equal); + } + } + break; + + default: + UNREACHABLE(); + return nullptr; + } + return resultArray; +} + +// The fold functions do operations on a constant at GLSL compile time, without generating run-time +// code. Returns the constant value to keep using. Nullptr should not be returned. +TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op) +{ + // Do operations where the return type may have a different number of components compared to the + // operand type. + + const TConstantUnion *operandArray = getConstantValue(); + ASSERT(operandArray); + + size_t objectSize = getType().getObjectSize(); + TConstantUnion *resultArray = nullptr; + switch (op) + { + case EOpAny: + ASSERT(getType().getBasicType() == EbtBool); + resultArray = new TConstantUnion(); + resultArray->setBConst(false); + for (size_t i = 0; i < objectSize; i++) + { + if (operandArray[i].getBConst()) + { + resultArray->setBConst(true); + break; + } + } + break; + + case EOpAll: + ASSERT(getType().getBasicType() == EbtBool); + resultArray = new TConstantUnion(); + resultArray->setBConst(true); + for (size_t i = 0; i < objectSize; i++) + { + if (!operandArray[i].getBConst()) + { + resultArray->setBConst(false); + break; + } + } + break; + + case EOpLength: + ASSERT(getType().getBasicType() == EbtFloat); + resultArray = new TConstantUnion(); + resultArray->setFConst(VectorLength(operandArray, objectSize)); + break; + + case EOpTranspose: + { + ASSERT(getType().getBasicType() == EbtFloat); + resultArray = new TConstantUnion[objectSize]; + angle::Matrix<float> result = + GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose(); + SetUnionArrayFromMatrix(result, resultArray); + break; + } + + case EOpDeterminant: + { + ASSERT(getType().getBasicType() == EbtFloat); + unsigned int size = getType().getNominalSize(); + ASSERT(size >= 2 && size <= 4); + resultArray = new TConstantUnion(); + resultArray->setFConst(GetMatrix(operandArray, size).determinant()); + break; + } + + case EOpInverse: + { + ASSERT(getType().getBasicType() == EbtFloat); + unsigned int size = getType().getNominalSize(); + ASSERT(size >= 2 && size <= 4); + resultArray = new TConstantUnion[objectSize]; + angle::Matrix<float> result = GetMatrix(operandArray, size).inverse(); + SetUnionArrayFromMatrix(result, resultArray); + break; + } + + case EOpPackSnorm2x16: + ASSERT(getType().getBasicType() == EbtFloat); + ASSERT(getType().getNominalSize() == 2); + resultArray = new TConstantUnion(); + resultArray->setUConst( + gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + break; + + case EOpUnpackSnorm2x16: + { + ASSERT(getType().getBasicType() == EbtUInt); + resultArray = new TConstantUnion[2]; + float f1, f2; + gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2); + resultArray[0].setFConst(f1); + resultArray[1].setFConst(f2); + break; + } + + case EOpPackUnorm2x16: + ASSERT(getType().getBasicType() == EbtFloat); + ASSERT(getType().getNominalSize() == 2); + resultArray = new TConstantUnion(); + resultArray->setUConst( + gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + break; + + case EOpUnpackUnorm2x16: + { + ASSERT(getType().getBasicType() == EbtUInt); + resultArray = new TConstantUnion[2]; + float f1, f2; + gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2); + resultArray[0].setFConst(f1); + resultArray[1].setFConst(f2); + break; + } + + case EOpPackHalf2x16: + ASSERT(getType().getBasicType() == EbtFloat); + ASSERT(getType().getNominalSize() == 2); + resultArray = new TConstantUnion(); + resultArray->setUConst( + gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + break; + + case EOpUnpackHalf2x16: + { + ASSERT(getType().getBasicType() == EbtUInt); + resultArray = new TConstantUnion[2]; + float f1, f2; + gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2); + resultArray[0].setFConst(f1); + resultArray[1].setFConst(f2); + break; + } + + case EOpPackUnorm4x8: + { + ASSERT(getType().getBasicType() == EbtFloat); + resultArray = new TConstantUnion(); + resultArray->setUConst( + gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(), + operandArray[2].getFConst(), operandArray[3].getFConst())); + break; + } + case EOpPackSnorm4x8: + { + ASSERT(getType().getBasicType() == EbtFloat); + resultArray = new TConstantUnion(); + resultArray->setUConst( + gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(), + operandArray[2].getFConst(), operandArray[3].getFConst())); + break; + } + case EOpUnpackUnorm4x8: + { + ASSERT(getType().getBasicType() == EbtUInt); + resultArray = new TConstantUnion[4]; + float f[4]; + gl::UnpackUnorm4x8(operandArray[0].getUConst(), f); + for (size_t i = 0; i < 4; ++i) + { + resultArray[i].setFConst(f[i]); + } + break; + } + case EOpUnpackSnorm4x8: + { + ASSERT(getType().getBasicType() == EbtUInt); + resultArray = new TConstantUnion[4]; + float f[4]; + gl::UnpackSnorm4x8(operandArray[0].getUConst(), f); + for (size_t i = 0; i < 4; ++i) + { + resultArray[i].setFConst(f[i]); + } + break; + } + + default: + UNREACHABLE(); + break; + } + + return resultArray; +} + +TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op, + TDiagnostics *diagnostics) +{ + // Do unary operations where each component of the result is computed based on the corresponding + // component of the operand. Also folds normalize, though the divisor in that case takes all + // components into account. + + const TConstantUnion *operandArray = getConstantValue(); + ASSERT(operandArray); + + size_t objectSize = getType().getObjectSize(); + + TConstantUnion *resultArray = new TConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + switch (op) + { + case EOpNegative: + switch (getType().getBasicType()) + { + case EbtFloat: + resultArray[i].setFConst(-operandArray[i].getFConst()); + break; + case EbtInt: + if (operandArray[i] == std::numeric_limits<int>::min()) + { + // The minimum representable integer doesn't have a positive + // counterpart, rather the negation overflows and in ESSL is supposed to + // wrap back to the minimum representable integer. Make sure that we + // don't actually let the negation overflow, which has undefined + // behavior in C++. + resultArray[i].setIConst(std::numeric_limits<int>::min()); + } + else + { + resultArray[i].setIConst(-operandArray[i].getIConst()); + } + break; + case EbtUInt: + if (operandArray[i] == 0x80000000u) + { + resultArray[i].setUConst(0x80000000u); + } + else + { + resultArray[i].setUConst(static_cast<unsigned int>( + -static_cast<int>(operandArray[i].getUConst()))); + } + break; + default: + UNREACHABLE(); + return nullptr; + } + break; + + case EOpPositive: + switch (getType().getBasicType()) + { + case EbtFloat: + resultArray[i].setFConst(operandArray[i].getFConst()); + break; + case EbtInt: + resultArray[i].setIConst(operandArray[i].getIConst()); + break; + case EbtUInt: + resultArray[i].setUConst(static_cast<unsigned int>( + static_cast<int>(operandArray[i].getUConst()))); + break; + default: + UNREACHABLE(); + return nullptr; + } + break; + + case EOpLogicalNot: + switch (getType().getBasicType()) + { + case EbtBool: + resultArray[i].setBConst(!operandArray[i].getBConst()); + break; + default: + UNREACHABLE(); + return nullptr; + } + break; + + case EOpBitwiseNot: + switch (getType().getBasicType()) + { + case EbtInt: + resultArray[i].setIConst(~operandArray[i].getIConst()); + break; + case EbtUInt: + resultArray[i].setUConst(~operandArray[i].getUConst()); + break; + default: + UNREACHABLE(); + return nullptr; + } + break; + + case EOpRadians: + ASSERT(getType().getBasicType() == EbtFloat); + resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst()); + break; + + case EOpDegrees: + ASSERT(getType().getBasicType() == EbtFloat); + resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst()); + break; + + case EOpSin: + foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]); + break; + + case EOpCos: + foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]); + break; + + case EOpTan: + foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]); + break; + + case EOpAsin: + // For asin(x), results are undefined if |x| > 1, we are choosing to set result to + // 0. + if (fabsf(operandArray[i].getFConst()) > 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]); + break; + + case EOpAcos: + // For acos(x), results are undefined if |x| > 1, we are choosing to set result to + // 0. + if (fabsf(operandArray[i].getFConst()) > 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]); + break; + + case EOpAtan: + foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]); + break; + + case EOpSinh: + foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]); + break; + + case EOpCosh: + foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]); + break; + + case EOpTanh: + foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]); + break; + + case EOpAsinh: + foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]); + break; + + case EOpAcosh: + // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0. + if (operandArray[i].getFConst() < 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]); + break; + + case EOpAtanh: + // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to + // 0. + if (fabsf(operandArray[i].getFConst()) >= 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]); + break; + + case EOpAbs: + switch (getType().getBasicType()) + { + case EbtFloat: + resultArray[i].setFConst(fabsf(operandArray[i].getFConst())); + break; + case EbtInt: + resultArray[i].setIConst(abs(operandArray[i].getIConst())); + break; + default: + UNREACHABLE(); + return nullptr; + } + break; + + case EOpSign: + switch (getType().getBasicType()) + { + case EbtFloat: + { + float fConst = operandArray[i].getFConst(); + float fResult = 0.0f; + if (fConst > 0.0f) + fResult = 1.0f; + else if (fConst < 0.0f) + fResult = -1.0f; + resultArray[i].setFConst(fResult); + break; + } + case EbtInt: + { + int iConst = operandArray[i].getIConst(); + int iResult = 0; + if (iConst > 0) + iResult = 1; + else if (iConst < 0) + iResult = -1; + resultArray[i].setIConst(iResult); + break; + } + default: + UNREACHABLE(); + return nullptr; + } + break; + + case EOpFloor: + foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]); + break; + + case EOpTrunc: + foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]); + break; + + case EOpRound: + foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]); + break; + + case EOpRoundEven: + { + ASSERT(getType().getBasicType() == EbtFloat); + float x = operandArray[i].getFConst(); + float result; + float fractPart = modff(x, &result); + if (fabsf(fractPart) == 0.5f) + result = 2.0f * roundf(x / 2.0f); + else + result = roundf(x); + resultArray[i].setFConst(result); + break; + } + + case EOpCeil: + foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]); + break; + + case EOpFract: + { + ASSERT(getType().getBasicType() == EbtFloat); + float x = operandArray[i].getFConst(); + resultArray[i].setFConst(x - floorf(x)); + break; + } + + case EOpIsnan: + ASSERT(getType().getBasicType() == EbtFloat); + resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst())); + break; + + case EOpIsinf: + ASSERT(getType().getBasicType() == EbtFloat); + resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst())); + break; + + case EOpFloatBitsToInt: + ASSERT(getType().getBasicType() == EbtFloat); + resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst())); + break; + + case EOpFloatBitsToUint: + ASSERT(getType().getBasicType() == EbtFloat); + resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst())); + break; + + case EOpIntBitsToFloat: + ASSERT(getType().getBasicType() == EbtInt); + resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst())); + break; + + case EOpUintBitsToFloat: + ASSERT(getType().getBasicType() == EbtUInt); + resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst())); + break; + + case EOpExp: + foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]); + break; + + case EOpLog: + // For log(x), results are undefined if x <= 0, we are choosing to set result to 0. + if (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]); + break; + + case EOpExp2: + foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]); + break; + + case EOpLog2: + // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0. + // And log2f is not available on some plarforms like old android, so just using + // log(x)/log(2) here. + if (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + { + foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]); + resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f)); + } + break; + + case EOpSqrt: + // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0. + if (operandArray[i].getFConst() < 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]); + break; + + case EOpInversesqrt: + // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(), + // so getting the square root first using builtin function sqrt() and then taking + // its inverse. + // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set + // result to 0. + if (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + { + foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]); + resultArray[i].setFConst(1.0f / resultArray[i].getFConst()); + } + break; + + case EOpLogicalNotComponentWise: + ASSERT(getType().getBasicType() == EbtBool); + resultArray[i].setBConst(!operandArray[i].getBConst()); + break; + + case EOpNormalize: + { + ASSERT(getType().getBasicType() == EbtFloat); + float x = operandArray[i].getFConst(); + float length = VectorLength(operandArray, objectSize); + if (length) + resultArray[i].setFConst(x / length); + else + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + break; + } + case EOpBitfieldReverse: + { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + value = static_cast<uint32_t>(operandArray[i].getIConst()); + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + uint32_t result = gl::BitfieldReverse(value); + if (getType().getBasicType() == EbtInt) + { + resultArray[i].setIConst(static_cast<int32_t>(result)); + } + else + { + resultArray[i].setUConst(result); + } + break; + } + case EOpBitCount: + { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + value = static_cast<uint32_t>(operandArray[i].getIConst()); + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + int result = gl::BitCount(value); + resultArray[i].setIConst(result); + break; + } + case EOpFindLSB: + { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + value = static_cast<uint32_t>(operandArray[i].getIConst()); + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + resultArray[i].setIConst(gl::FindLSB(value)); + break; + } + case EOpFindMSB: + { + uint32_t value; + if (getType().getBasicType() == EbtInt) + { + int intValue = operandArray[i].getIConst(); + value = static_cast<uint32_t>(intValue); + if (intValue < 0) + { + // Look for zero instead of one in value. This also handles the intValue == + // -1 special case, where the return value needs to be -1. + value = ~value; + } + } + else + { + ASSERT(getType().getBasicType() == EbtUInt); + value = operandArray[i].getUConst(); + } + resultArray[i].setIConst(gl::FindMSB(value)); + break; + } + case EOpDFdx: + case EOpDFdy: + case EOpFwidth: + ASSERT(getType().getBasicType() == EbtFloat); + // Derivatives of constant arguments should be 0. + resultArray[i].setFConst(0.0f); + break; + + default: + return nullptr; + } + } + + return resultArray; +} + +void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter, + FloatTypeUnaryFunc builtinFunc, + TConstantUnion *result) const +{ + ASSERT(builtinFunc); + + ASSERT(getType().getBasicType() == EbtFloat); + result->setFConst(builtinFunc(parameter.getFConst())); +} + +// static +TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, + TDiagnostics *diagnostics) +{ + TOperator op = aggregate->getOp(); + TIntermSequence *arguments = aggregate->getSequence(); + unsigned int argsCount = static_cast<unsigned int>(arguments->size()); + std::vector<const TConstantUnion *> unionArrays(argsCount); + std::vector<size_t> objectSizes(argsCount); + size_t maxObjectSize = 0; + TBasicType basicType = EbtVoid; + TSourceLoc loc; + for (unsigned int i = 0; i < argsCount; i++) + { + TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion(); + ASSERT(argConstant != nullptr); // Should be checked already. + + if (i == 0) + { + basicType = argConstant->getType().getBasicType(); + loc = argConstant->getLine(); + } + unionArrays[i] = argConstant->getConstantValue(); + objectSizes[i] = argConstant->getType().getObjectSize(); + if (objectSizes[i] > maxObjectSize) + maxObjectSize = objectSizes[i]; + } + + if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct) + { + for (unsigned int i = 0; i < argsCount; i++) + if (objectSizes[i] != maxObjectSize) + unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize); + } + + TConstantUnion *resultArray = nullptr; + + switch (op) + { + case EOpAtan: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + float y = unionArrays[0][i].getFConst(); + float x = unionArrays[1][i].getFConst(); + // Results are undefined if x and y are both 0. + if (x == 0.0f && y == 0.0f) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); + else + resultArray[i].setFConst(atan2f(y, x)); + } + break; + } + + case EOpPow: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + // Results are undefined if x < 0. + // Results are undefined if x = 0 and y <= 0. + if (x < 0.0f) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); + else if (x == 0.0f && y <= 0.0f) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); + else + resultArray[i].setFConst(powf(x, y)); + } + break; + } + + case EOpMod: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + resultArray[i].setFConst(x - y * floorf(x / y)); + } + break; + } + + case EOpMin: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setFConst( + std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); + break; + case EbtInt: + resultArray[i].setIConst( + std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst())); + break; + case EbtUInt: + resultArray[i].setUConst( + std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); + break; + default: + UNREACHABLE(); + break; + } + } + break; + } + + case EOpMax: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setFConst( + std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); + break; + case EbtInt: + resultArray[i].setIConst( + std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst())); + break; + case EbtUInt: + resultArray[i].setUConst( + std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); + break; + default: + UNREACHABLE(); + break; + } + } + break; + } + + case EOpStep: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + resultArray[i].setFConst( + unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f); + break; + } + + case EOpLessThanComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() < + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() < + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() < + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; + } + } + break; + } + + case EOpLessThanEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() <= + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() <= + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() <= + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; + } + } + break; + } + + case EOpGreaterThanComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() > + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() > + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() > + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; + } + } + break; + } + case EOpGreaterThanEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() >= + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() >= + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() >= + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; + } + } + } + break; + + case EOpEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() == + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() == + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() == + unionArrays[1][i].getUConst()); + break; + case EbtBool: + resultArray[i].setBConst(unionArrays[0][i].getBConst() == + unionArrays[1][i].getBConst()); + break; + default: + UNREACHABLE(); + break; + } + } + break; + } + + case EOpNotEqualComponentWise: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() != + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() != + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() != + unionArrays[1][i].getUConst()); + break; + case EbtBool: + resultArray[i].setBConst(unionArrays[0][i].getBConst() != + unionArrays[1][i].getBConst()); + break; + default: + UNREACHABLE(); + break; + } + } + break; + } + + case EOpDistance: + { + ASSERT(basicType == EbtFloat); + TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize]; + resultArray = new TConstantUnion(); + for (size_t i = 0; i < maxObjectSize; i++) + { + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + distanceArray[i].setFConst(x - y); + } + resultArray->setFConst(VectorLength(distanceArray, maxObjectSize)); + break; + } + + case EOpDot: + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion(); + resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize)); + break; + + case EOpCross: + { + ASSERT(basicType == EbtFloat && maxObjectSize == 3); + resultArray = new TConstantUnion[maxObjectSize]; + float x0 = unionArrays[0][0].getFConst(); + float x1 = unionArrays[0][1].getFConst(); + float x2 = unionArrays[0][2].getFConst(); + float y0 = unionArrays[1][0].getFConst(); + float y1 = unionArrays[1][1].getFConst(); + float y2 = unionArrays[1][2].getFConst(); + resultArray[0].setFConst(x1 * y2 - y1 * x2); + resultArray[1].setFConst(x2 * y0 - y2 * x0); + resultArray[2].setFConst(x0 * y1 - y0 * x1); + break; + } + + case EOpReflect: + { + ASSERT(basicType == EbtFloat); + // genType reflect (genType I, genType N) : + // For the incident vector I and surface orientation N, returns the reflection + // direction: + // I - 2 * dot(N, I) * N. + resultArray = new TConstantUnion[maxObjectSize]; + float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize); + for (size_t i = 0; i < maxObjectSize; i++) + { + float result = unionArrays[0][i].getFConst() - + 2.0f * dotProduct * unionArrays[1][i].getFConst(); + resultArray[i].setFConst(result); + } + break; + } + + case EOpMulMatrixComponentWise: + { + ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() && + (*arguments)[1]->getAsTyped()->isMatrix()); + // Perform component-wise matrix multiplication. + resultArray = new TConstantUnion[maxObjectSize]; + int rows = (*arguments)[0]->getAsTyped()->getRows(); + int cols = (*arguments)[0]->getAsTyped()->getCols(); + angle::Matrix<float> lhs = GetMatrix(unionArrays[0], rows, cols); + angle::Matrix<float> rhs = GetMatrix(unionArrays[1], rows, cols); + angle::Matrix<float> result = lhs.compMult(rhs); + SetUnionArrayFromMatrix(result, resultArray); + break; + } + + case EOpOuterProduct: + { + ASSERT(basicType == EbtFloat); + size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize(); + size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize(); + resultArray = new TConstantUnion[numRows * numCols]; + angle::Matrix<float> result = + GetMatrix(unionArrays[0], static_cast<int>(numRows), 1) + .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols))); + SetUnionArrayFromMatrix(result, resultArray); + break; + } + + case EOpClamp: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + switch (basicType) + { + case EbtFloat: + { + float x = unionArrays[0][i].getFConst(); + float min = unionArrays[1][i].getFConst(); + float max = unionArrays[2][i].getFConst(); + // Results are undefined if min > max. + if (min > max) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); + else + resultArray[i].setFConst(gl::clamp(x, min, max)); + break; + } + + case EbtInt: + { + int x = unionArrays[0][i].getIConst(); + int min = unionArrays[1][i].getIConst(); + int max = unionArrays[2][i].getIConst(); + // Results are undefined if min > max. + if (min > max) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); + else + resultArray[i].setIConst(gl::clamp(x, min, max)); + break; + } + case EbtUInt: + { + unsigned int x = unionArrays[0][i].getUConst(); + unsigned int min = unionArrays[1][i].getUConst(); + unsigned int max = unionArrays[2][i].getUConst(); + // Results are undefined if min > max. + if (min > max) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); + else + resultArray[i].setUConst(gl::clamp(x, min, max)); + break; + } + default: + UNREACHABLE(); + break; + } + } + break; + } + + case EOpMix: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType(); + if (type == EbtFloat) + { + // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a. + float a = unionArrays[2][i].getFConst(); + resultArray[i].setFConst(x * (1.0f - a) + y * a); + } + else // 3rd parameter is EbtBool + { + ASSERT(type == EbtBool); + // Selects which vector each returned component comes from. + // For a component of a that is false, the corresponding component of x is + // returned. + // For a component of a that is true, the corresponding component of y is + // returned. + bool a = unionArrays[2][i].getBConst(); + resultArray[i].setFConst(a ? y : x); + } + } + break; + } + + case EOpSmoothstep: + { + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + float edge0 = unionArrays[0][i].getFConst(); + float edge1 = unionArrays[1][i].getFConst(); + float x = unionArrays[2][i].getFConst(); + // Results are undefined if edge0 >= edge1. + if (edge0 >= edge1) + { + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); + } + else + { + // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth + // Hermite interpolation between 0 and 1 when edge0 < x < edge1. + float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + resultArray[i].setFConst(t * t * (3.0f - 2.0f * t)); + } + } + break; + } + + case EOpLdexp: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + { + float x = unionArrays[0][i].getFConst(); + int exp = unionArrays[1][i].getIConst(); + if (exp > 128) + { + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]); + } + else + { + resultArray[i].setFConst(gl::Ldexp(x, exp)); + } + } + break; + } + + case EOpFaceforward: + { + ASSERT(basicType == EbtFloat); + // genType faceforward(genType N, genType I, genType Nref) : + // If dot(Nref, I) < 0 return N, otherwise return -N. + resultArray = new TConstantUnion[maxObjectSize]; + float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize); + for (size_t i = 0; i < maxObjectSize; i++) + { + if (dotProduct < 0) + resultArray[i].setFConst(unionArrays[0][i].getFConst()); + else + resultArray[i].setFConst(-unionArrays[0][i].getFConst()); + } + break; + } + + case EOpRefract: + { + ASSERT(basicType == EbtFloat); + // genType refract(genType I, genType N, float eta) : + // For the incident vector I and surface normal N, and the ratio of indices of + // refraction eta, + // return the refraction vector. The result is computed by + // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I)) + // if (k < 0.0) + // return genType(0.0) + // else + // return eta * I - (eta * dot(N, I) + sqrt(k)) * N + resultArray = new TConstantUnion[maxObjectSize]; + float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize); + for (size_t i = 0; i < maxObjectSize; i++) + { + float eta = unionArrays[2][i].getFConst(); + float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct); + if (k < 0.0f) + resultArray[i].setFConst(0.0f); + else + resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() - + (eta * dotProduct + sqrtf(k)) * + unionArrays[1][i].getFConst()); + } + break; + } + case EOpBitfieldExtract: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; ++i) + { + int offset = unionArrays[1][0].getIConst(); + int bits = unionArrays[2][0].getIConst(); + if (bits == 0) + { + if (aggregate->getBasicType() == EbtInt) + { + resultArray[i].setIConst(0); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + resultArray[i].setUConst(0); + } + } + else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32) + { + UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics, + &resultArray[i]); + } + else + { + // bits can be 32 here, so we need to avoid bit shift overflow. + uint32_t maskMsb = 1u << (bits - 1); + uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset; + if (aggregate->getBasicType() == EbtInt) + { + uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst()); + uint32_t resultUnsigned = (value & mask) >> offset; + if ((resultUnsigned & maskMsb) != 0) + { + // The most significant bits (from bits+1 to the most significant bit) + // should be set to 1. + uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits; + resultUnsigned |= higherBitsMask; + } + resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned)); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + uint32_t value = unionArrays[0][i].getUConst(); + resultArray[i].setUConst((value & mask) >> offset); + } + } + } + break; + } + case EOpBitfieldInsert: + { + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; ++i) + { + int offset = unionArrays[2][0].getIConst(); + int bits = unionArrays[3][0].getIConst(); + if (bits == 0) + { + if (aggregate->getBasicType() == EbtInt) + { + int32_t base = unionArrays[0][i].getIConst(); + resultArray[i].setIConst(base); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + uint32_t base = unionArrays[0][i].getUConst(); + resultArray[i].setUConst(base); + } + } + else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32) + { + UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics, + &resultArray[i]); + } + else + { + // bits can be 32 here, so we need to avoid bit shift overflow. + uint32_t maskMsb = 1u << (bits - 1); + uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset; + uint32_t baseMask = ~insertMask; + if (aggregate->getBasicType() == EbtInt) + { + uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst()); + uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst()); + uint32_t resultUnsigned = + (base & baseMask) | ((insert << offset) & insertMask); + resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned)); + } + else + { + ASSERT(aggregate->getBasicType() == EbtUInt); + uint32_t base = unionArrays[0][i].getUConst(); + uint32_t insert = unionArrays[1][i].getUConst(); + resultArray[i].setUConst((base & baseMask) | + ((insert << offset) & insertMask)); + } + } + } + break; + } + + default: + UNREACHABLE(); + return nullptr; + } + return resultArray; +} + +bool TIntermConstantUnion::IsFloatDivision(TBasicType t1, TBasicType t2) +{ + ImplicitTypeConversion conversion = GetConversion(t1, t2); + ASSERT(conversion != ImplicitTypeConversion::Invalid); + if (conversion == ImplicitTypeConversion::Same) + { + if (t1 == EbtFloat) + return true; + return false; + } + ASSERT(t1 == EbtFloat || t2 == EbtFloat); + return true; +} + +// TIntermPreprocessorDirective implementation. +TIntermPreprocessorDirective::TIntermPreprocessorDirective(PreprocessorDirective directive, + ImmutableString command) + : mDirective(directive), mCommand(std::move(command)) +{} + +TIntermPreprocessorDirective::~TIntermPreprocessorDirective() = default; + +size_t TIntermPreprocessorDirective::getChildCount() const +{ + return 0; +} + +TIntermNode *TIntermPreprocessorDirective::getChildNode(size_t index) const +{ + UNREACHABLE(); + return nullptr; +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/IntermNode.h b/gfx/angle/checkout/src/compiler/translator/IntermNode.h new file mode 100644 index 0000000000..5667378b14 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/IntermNode.h @@ -0,0 +1,936 @@ +// +// Copyright (c) 2002-2014 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. +// + +// +// Definition of the in-memory high-level intermediate representation +// of shaders. This is a tree that parser creates. +// +// Nodes in the tree are defined as a hierarchy of classes derived from +// TIntermNode. Each is a node in a tree. There is no preset branching factor; +// each node can have it's own type of list of children. +// + +#ifndef COMPILER_TRANSLATOR_INTERMNODE_H_ +#define COMPILER_TRANSLATOR_INTERMNODE_H_ + +#include "GLSLANG/ShaderLang.h" + +#include <algorithm> +#include <queue> + +#include "common/angleutils.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/ConstantUnion.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/Operator.h" +#include "compiler/translator/SymbolUniqueId.h" +#include "compiler/translator/Types.h" +#include "compiler/translator/tree_util/Visit.h" + +namespace sh +{ + +class TDiagnostics; + +class TIntermTraverser; +class TIntermAggregate; +class TIntermBlock; +class TIntermInvariantDeclaration; +class TIntermDeclaration; +class TIntermFunctionPrototype; +class TIntermFunctionDefinition; +class TIntermSwizzle; +class TIntermBinary; +class TIntermUnary; +class TIntermConstantUnion; +class TIntermTernary; +class TIntermIfElse; +class TIntermSwitch; +class TIntermCase; +class TIntermTyped; +class TIntermSymbol; +class TIntermLoop; +class TInfoSink; +class TInfoSinkBase; +class TIntermBranch; +class TIntermPreprocessorDirective; + +class TSymbolTable; +class TFunction; +class TVariable; + +// +// Base class for the tree nodes +// +class TIntermNode : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TIntermNode() + { + // TODO: Move this to TSourceLoc constructor + // after getting rid of TPublicType. + mLine.first_file = mLine.last_file = 0; + mLine.first_line = mLine.last_line = 0; + } + virtual ~TIntermNode() {} + + const TSourceLoc &getLine() const { return mLine; } + void setLine(const TSourceLoc &l) { mLine = l; } + + virtual void traverse(TIntermTraverser *it); + virtual bool visit(Visit visit, TIntermTraverser *it) = 0; + + virtual TIntermTyped *getAsTyped() { return nullptr; } + virtual TIntermConstantUnion *getAsConstantUnion() { return nullptr; } + virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; } + virtual TIntermAggregate *getAsAggregate() { return nullptr; } + virtual TIntermBlock *getAsBlock() { return nullptr; } + virtual TIntermFunctionPrototype *getAsFunctionPrototypeNode() { return nullptr; } + virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() { return nullptr; } + virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; } + virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; } + virtual TIntermBinary *getAsBinaryNode() { return nullptr; } + virtual TIntermUnary *getAsUnaryNode() { return nullptr; } + virtual TIntermTernary *getAsTernaryNode() { return nullptr; } + virtual TIntermIfElse *getAsIfElseNode() { return nullptr; } + virtual TIntermSwitch *getAsSwitchNode() { return nullptr; } + virtual TIntermCase *getAsCaseNode() { return nullptr; } + virtual TIntermSymbol *getAsSymbolNode() { return nullptr; } + virtual TIntermLoop *getAsLoopNode() { return nullptr; } + virtual TIntermBranch *getAsBranchNode() { return nullptr; } + virtual TIntermPreprocessorDirective *getAsPreprocessorDirective() { return nullptr; } + + virtual size_t getChildCount() const = 0; + virtual TIntermNode *getChildNode(size_t index) const = 0; + // Replace a child node. Return true if |original| is a child + // node and it is replaced; otherwise, return false. + virtual bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) = 0; + + protected: + TSourceLoc mLine; +}; + +// +// This is just to help yacc. +// +struct TIntermNodePair +{ + TIntermNode *node1; + TIntermNode *node2; +}; + +// +// Intermediate class for nodes that have a type. +// +class TIntermTyped : public TIntermNode +{ + public: + TIntermTyped() {} + + virtual TIntermTyped *deepCopy() const = 0; + + TIntermTyped *getAsTyped() override { return this; } + + virtual TIntermTyped *fold(TDiagnostics *diagnostics) { return this; } + + // getConstantValue() returns the constant value that this node represents, if any. It + // should only be used after nodes have been replaced with their folded versions returned + // from fold(). hasConstantValue() returns true if getConstantValue() will return a value. + virtual bool hasConstantValue() const; + virtual const TConstantUnion *getConstantValue() const; + + // True if executing the expression represented by this node affects state, like values of + // variables. False if the executing the expression only computes its return value without + // affecting state. May return true conservatively. + virtual bool hasSideEffects() const = 0; + + virtual const TType &getType() const = 0; + + TBasicType getBasicType() const { return getType().getBasicType(); } + TQualifier getQualifier() const { return getType().getQualifier(); } + TPrecision getPrecision() const { return getType().getPrecision(); } + TMemoryQualifier getMemoryQualifier() const { return getType().getMemoryQualifier(); } + int getCols() const { return getType().getCols(); } + int getRows() const { return getType().getRows(); } + int getNominalSize() const { return getType().getNominalSize(); } + int getSecondarySize() const { return getType().getSecondarySize(); } + + bool isInterfaceBlock() const { return getType().isInterfaceBlock(); } + bool isMatrix() const { return getType().isMatrix(); } + bool isArray() const { return getType().isArray(); } + bool isVector() const { return getType().isVector(); } + bool isScalar() const { return getType().isScalar(); } + bool isScalarInt() const { return getType().isScalarInt(); } + const char *getBasicString() const { return getType().getBasicString(); } + + unsigned int getOutermostArraySize() const { return getType().getOutermostArraySize(); } + + protected: + TIntermTyped(const TIntermTyped &node); +}; + +// +// Handle for, do-while, and while loops. +// +enum TLoopType +{ + ELoopFor, + ELoopWhile, + ELoopDoWhile +}; + +class TIntermLoop : public TIntermNode +{ + public: + TIntermLoop(TLoopType type, + TIntermNode *init, + TIntermTyped *cond, + TIntermTyped *expr, + TIntermBlock *body); + + TIntermLoop *getAsLoopNode() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + TLoopType getType() const { return mType; } + TIntermNode *getInit() { return mInit; } + TIntermTyped *getCondition() { return mCond; } + TIntermTyped *getExpression() { return mExpr; } + TIntermBlock *getBody() { return mBody; } + + void setInit(TIntermNode *init) { mInit = init; } + void setCondition(TIntermTyped *condition) { mCond = condition; } + void setExpression(TIntermTyped *expression) { mExpr = expression; } + void setBody(TIntermBlock *body) { mBody = body; } + + protected: + TLoopType mType; + TIntermNode *mInit; // for-loop initialization + TIntermTyped *mCond; // loop exit condition + TIntermTyped *mExpr; // for-loop expression + TIntermBlock *mBody; // loop body +}; + +// +// Handle break, continue, return, and kill. +// +class TIntermBranch : public TIntermNode +{ + public: + TIntermBranch(TOperator op, TIntermTyped *e) : mFlowOp(op), mExpression(e) {} + + TIntermBranch *getAsBranchNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + TOperator getFlowOp() { return mFlowOp; } + TIntermTyped *getExpression() { return mExpression; } + + protected: + TOperator mFlowOp; + TIntermTyped *mExpression; // zero except for "return exp;" statements +}; + +// Nodes that correspond to variable symbols in the source code. These may be regular variables or +// interface block instances. In declarations that only declare a struct type but no variables, a +// TIntermSymbol node with an empty variable is used to store the type. +class TIntermSymbol : public TIntermTyped +{ + public: + TIntermSymbol(const TVariable *variable); + + TIntermTyped *deepCopy() const override { return new TIntermSymbol(*this); } + + bool hasConstantValue() const override; + const TConstantUnion *getConstantValue() const override; + + bool hasSideEffects() const override { return false; } + + const TType &getType() const override; + + const TSymbolUniqueId &uniqueId() const; + ImmutableString getName() const; + const TVariable &variable() const { return *mVariable; } + + TIntermSymbol *getAsSymbolNode() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } + + private: + TIntermSymbol(const TIntermSymbol &) = default; // Note: not deleted, just private! + + const TVariable *const mVariable; // Guaranteed to be non-null +}; + +// A typed expression that is not just representing a symbol table symbol. +class TIntermExpression : public TIntermTyped +{ + public: + TIntermExpression(const TType &t); + + const TType &getType() const override { return mType; } + + protected: + TType *getTypePointer() { return &mType; } + void setType(const TType &t) { mType = t; } + void setTypePreservePrecision(const TType &t); + + TIntermExpression(const TIntermExpression &node) = default; + + TType mType; +}; + +// Constant folded node. +// Note that nodes may be constant folded and not be constant expressions with the EvqConst +// qualifier. This happens for example when the following expression is processed: +// "true ? 1.0 : non_constant" +// Other nodes than TIntermConstantUnion may also be constant expressions. +// +class TIntermConstantUnion : public TIntermExpression +{ + public: + TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type) + : TIntermExpression(type), mUnionArrayPointer(unionPointer) + { + ASSERT(unionPointer); + } + + TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); } + + bool hasConstantValue() const override; + const TConstantUnion *getConstantValue() const override; + + bool hasSideEffects() const override { return false; } + + int getIConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0; + } + unsigned int getUConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0; + } + float getFConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f; + } + bool getBConst(size_t index) const + { + return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false; + } + + TIntermConstantUnion *getAsConstantUnion() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } + + TConstantUnion *foldUnaryNonComponentWise(TOperator op); + TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics); + + static const TConstantUnion *FoldBinary(TOperator op, + const TConstantUnion *leftArray, + const TType &leftType, + const TConstantUnion *rightArray, + const TType &rightType, + TDiagnostics *diagnostics, + const TSourceLoc &line); + + static const TConstantUnion *FoldIndexing(const TType &type, + const TConstantUnion *constArray, + int index); + static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, + TDiagnostics *diagnostics); + static bool IsFloatDivision(TBasicType t1, TBasicType t2); + + protected: + // Same data may be shared between multiple constant unions, so it can't be modified. + const TConstantUnion *mUnionArrayPointer; + + private: + typedef float (*FloatTypeUnaryFunc)(float); + void foldFloatTypeUnary(const TConstantUnion ¶meter, + FloatTypeUnaryFunc builtinFunc, + TConstantUnion *result) const; + + TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private! +}; + +// +// Intermediate class for node types that hold operators. +// +class TIntermOperator : public TIntermExpression +{ + public: + TOperator getOp() const { return mOp; } + + bool isAssignment() const; + bool isMultiplication() const; + bool isConstructor() const; + + // Returns true for calls mapped to EOpCall*, false for built-ins that have their own specific + // ops. + bool isFunctionCall() const; + + bool hasSideEffects() const override { return isAssignment(); } + + protected: + TIntermOperator(TOperator op) : TIntermExpression(TType(EbtFloat, EbpUndefined)), mOp(op) {} + TIntermOperator(TOperator op, const TType &type) : TIntermExpression(type), mOp(op) {} + + TIntermOperator(const TIntermOperator &) = default; + + const TOperator mOp; +}; + +// Node for vector swizzles. +class TIntermSwizzle : public TIntermExpression +{ + public: + // This constructor determines the type of the node based on the operand. + TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets); + + TIntermTyped *deepCopy() const override { return new TIntermSwizzle(*this); } + + TIntermSwizzle *getAsSwizzleNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + bool hasSideEffects() const override { return mOperand->hasSideEffects(); } + + TIntermTyped *getOperand() { return mOperand; } + void writeOffsetsAsXYZW(TInfoSinkBase *out) const; + + const TVector<int> &getSwizzleOffsets() { return mSwizzleOffsets; } + + bool hasDuplicateOffsets() const; + void setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets); + bool offsetsMatch(int offset) const; + + TIntermTyped *fold(TDiagnostics *diagnostics) override; + + protected: + TIntermTyped *mOperand; + TVector<int> mSwizzleOffsets; + bool mHasFoldedDuplicateOffsets; + + private: + void promote(); + + TIntermSwizzle(const TIntermSwizzle &node); // Note: not deleted, just private! +}; + +// +// Nodes for all the basic binary math operators. +// +class TIntermBinary : public TIntermOperator +{ + public: + // This constructor determines the type of the binary node based on the operands and op. + TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right); + // Comma qualifier depends on the shader version, so use this to create comma nodes: + static TIntermBinary *CreateComma(TIntermTyped *left, TIntermTyped *right, int shaderVersion); + + TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); } + + bool hasConstantValue() const override; + const TConstantUnion *getConstantValue() const override; + + static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right); + static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right); + + TIntermBinary *getAsBinaryNode() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + bool hasSideEffects() const override + { + return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects(); + } + + TIntermTyped *getLeft() const { return mLeft; } + TIntermTyped *getRight() const { return mRight; } + TIntermTyped *fold(TDiagnostics *diagnostics) override; + + void setAddIndexClamp() { mAddIndexClamp = true; } + bool getAddIndexClamp() const { return mAddIndexClamp; } + + // This method is only valid for EOpIndexDirectStruct. It returns the name of the field. + const ImmutableString &getIndexStructFieldName() const; + + protected: + TIntermTyped *mLeft; + TIntermTyped *mRight; + + // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. + bool mAddIndexClamp; + + private: + void promote(); + + static TQualifier GetCommaQualifier(int shaderVersion, + const TIntermTyped *left, + const TIntermTyped *right); + + TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private! +}; + +// +// Nodes for unary math operators. +// +class TIntermUnary : public TIntermOperator +{ + public: + TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function); + + TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); } + + TIntermUnary *getAsUnaryNode() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); } + + TIntermTyped *getOperand() { return mOperand; } + TIntermTyped *fold(TDiagnostics *diagnostics) override; + + const TFunction *getFunction() const { return mFunction; } + + void setUseEmulatedFunction() { mUseEmulatedFunction = true; } + bool getUseEmulatedFunction() { return mUseEmulatedFunction; } + + protected: + TIntermTyped *mOperand; + + // If set to true, replace the built-in function call with an emulated one + // to work around driver bugs. + bool mUseEmulatedFunction; + + const TFunction *const mFunction; + + private: + void promote(); + + TIntermUnary(const TIntermUnary &node); // note: not deleted, just private! +}; + +typedef TVector<TIntermNode *> TIntermSequence; +typedef TVector<int> TQualifierList; + +// Interface for node classes that have an arbitrarily sized set of children. +class TIntermAggregateBase +{ + public: + virtual ~TIntermAggregateBase() {} + + virtual TIntermSequence *getSequence() = 0; + virtual const TIntermSequence *getSequence() const = 0; + + bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements); + bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions); + + protected: + TIntermAggregateBase() {} + + bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement); +}; + +// +// Nodes that operate on an arbitrary sized set of children. +// +class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase +{ + public: + static TIntermAggregate *CreateFunctionCall(const TFunction &func, TIntermSequence *arguments); + + static TIntermAggregate *CreateRawFunctionCall(const TFunction &func, + TIntermSequence *arguments); + + // This covers all built-in function calls - whether they are associated with an op or not. + static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func, + TIntermSequence *arguments); + static TIntermAggregate *CreateConstructor(const TType &type, TIntermSequence *arguments); + ~TIntermAggregate() {} + + // Note: only supported for nodes that can be a part of an expression. + TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); } + + TIntermAggregate *shallowCopy() const; + + bool hasConstantValue() const override; + const TConstantUnion *getConstantValue() const override; + + TIntermAggregate *getAsAggregate() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + bool hasSideEffects() const override; + + TIntermTyped *fold(TDiagnostics *diagnostics) override; + + TIntermSequence *getSequence() override { return &mArguments; } + const TIntermSequence *getSequence() const override { return &mArguments; } + + void setUseEmulatedFunction() { mUseEmulatedFunction = true; } + bool getUseEmulatedFunction() { return mUseEmulatedFunction; } + + // Returns true if changing parameter precision may affect the return value. + bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; } + + const TFunction *getFunction() const { return mFunction; } + + // Get the function name to display to the user in an error message. + const char *functionName() const; + + protected: + TIntermSequence mArguments; + + // If set to true, replace the built-in function call with an emulated one + // to work around driver bugs. Only for calls mapped to ops other than EOpCall*. + bool mUseEmulatedFunction; + + bool mGotPrecisionFromChildren; + + const TFunction *const mFunction; + + private: + TIntermAggregate(const TFunction *func, + const TType &type, + TOperator op, + TIntermSequence *arguments); + + TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private! + + void setPrecisionAndQualifier(); + + bool areChildrenConstQualified(); + + void setPrecisionFromChildren(); + + void setPrecisionForBuiltInOp(); + + // Returns true if precision was set according to special rules for this built-in. + bool setPrecisionForSpecialBuiltInOp(); + + // Used for built-in functions under EOpCallBuiltInFunction. The function name in the symbol + // info needs to be set before calling this. + void setBuiltInFunctionPrecision(); +}; + +// A list of statements. Either the root node which contains declarations and function definitions, +// or a block that can be marked with curly braces {}. +class TIntermBlock : public TIntermNode, public TIntermAggregateBase +{ + public: + TIntermBlock() : TIntermNode() {} + ~TIntermBlock() {} + + TIntermBlock *getAsBlock() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + // Only intended for initially building the block. + void appendStatement(TIntermNode *statement); + void insertStatement(size_t insertPosition, TIntermNode *statement); + + TIntermSequence *getSequence() override { return &mStatements; } + const TIntermSequence *getSequence() const override { return &mStatements; } + + protected: + TIntermSequence mStatements; +}; + +// Function prototype. May be in the AST either as a function prototype declaration or as a part of +// a function definition. The type of the node is the function return type. +class TIntermFunctionPrototype : public TIntermTyped +{ + public: + TIntermFunctionPrototype(const TFunction *function); + ~TIntermFunctionPrototype() {} + + TIntermFunctionPrototype *getAsFunctionPrototypeNode() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + const TType &getType() const override; + + TIntermTyped *deepCopy() const override + { + UNREACHABLE(); + return nullptr; + } + bool hasSideEffects() const override + { + UNREACHABLE(); + return true; + } + + const TFunction *getFunction() const { return mFunction; } + + protected: + const TFunction *const mFunction; +}; + +// Node for function definitions. The prototype child node stores the function header including +// parameters, and the body child node stores the function body. +class TIntermFunctionDefinition : public TIntermNode +{ + public: + TIntermFunctionDefinition(TIntermFunctionPrototype *prototype, TIntermBlock *body) + : TIntermNode(), mPrototype(prototype), mBody(body) + { + ASSERT(prototype != nullptr); + ASSERT(body != nullptr); + } + + TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; } + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + TIntermFunctionPrototype *getFunctionPrototype() const { return mPrototype; } + TIntermBlock *getBody() const { return mBody; } + + const TFunction *getFunction() const { return mPrototype->getFunction(); } + + private: + TIntermFunctionPrototype *mPrototype; + TIntermBlock *mBody; +}; + +// Struct, interface block or variable declaration. Can contain multiple variable declarators. +class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase +{ + public: + TIntermDeclaration() : TIntermNode() {} + ~TIntermDeclaration() {} + + TIntermDeclaration *getAsDeclarationNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + // Only intended for initially building the declaration. + // The declarator node should be either TIntermSymbol or TIntermBinary with op set to + // EOpInitialize. + void appendDeclarator(TIntermTyped *declarator); + + TIntermSequence *getSequence() override { return &mDeclarators; } + const TIntermSequence *getSequence() const override { return &mDeclarators; } + + protected: + TIntermSequence mDeclarators; +}; + +// Specialized declarations for attributing invariance. +class TIntermInvariantDeclaration : public TIntermNode +{ + public: + TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line); + + virtual TIntermInvariantDeclaration *getAsInvariantDeclarationNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + TIntermSymbol *getSymbol() { return mSymbol; } + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + private: + TIntermSymbol *mSymbol; +}; + +// For ternary operators like a ? b : c. +class TIntermTernary : public TIntermExpression +{ + public: + TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression); + + TIntermTernary *getAsTernaryNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + TIntermTyped *getCondition() const { return mCondition; } + TIntermTyped *getTrueExpression() const { return mTrueExpression; } + TIntermTyped *getFalseExpression() const { return mFalseExpression; } + + TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); } + + bool hasSideEffects() const override + { + return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() || + mFalseExpression->hasSideEffects(); + } + + TIntermTyped *fold(TDiagnostics *diagnostics) override; + + private: + TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private! + + static TQualifier DetermineQualifier(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression); + + TIntermTyped *mCondition; + TIntermTyped *mTrueExpression; + TIntermTyped *mFalseExpression; +}; + +class TIntermIfElse : public TIntermNode +{ + public: + TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB); + + TIntermIfElse *getAsIfElseNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + TIntermTyped *getCondition() const { return mCondition; } + TIntermBlock *getTrueBlock() const { return mTrueBlock; } + TIntermBlock *getFalseBlock() const { return mFalseBlock; } + + protected: + TIntermTyped *mCondition; + TIntermBlock *mTrueBlock; + TIntermBlock *mFalseBlock; +}; + +// +// Switch statement. +// +class TIntermSwitch : public TIntermNode +{ + public: + TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList); + + TIntermSwitch *getAsSwitchNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + TIntermTyped *getInit() { return mInit; } + TIntermBlock *getStatementList() { return mStatementList; } + + // Must be called with a non-null statementList. + void setStatementList(TIntermBlock *statementList); + + protected: + TIntermTyped *mInit; + TIntermBlock *mStatementList; +}; + +// +// Case label. +// +class TIntermCase : public TIntermNode +{ + public: + TIntermCase(TIntermTyped *condition) : TIntermNode(), mCondition(condition) {} + + TIntermCase *getAsCaseNode() override { return this; } + bool visit(Visit visit, TIntermTraverser *it) final; + + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; + + bool hasCondition() const { return mCondition != nullptr; } + TIntermTyped *getCondition() const { return mCondition; } + + protected: + TIntermTyped *mCondition; +}; + +// +// Preprocessor Directive. +// #ifdef, #define, #if, #endif, etc. +// + +enum class PreprocessorDirective +{ + Define, + Ifdef, + If, + Endif, +}; + +class TIntermPreprocessorDirective : public TIntermNode +{ + public: + // This could also take an ImmutbleString as an argument. + TIntermPreprocessorDirective(PreprocessorDirective directive, ImmutableString command); + ~TIntermPreprocessorDirective() final; + + void traverse(TIntermTraverser *it) final; + bool visit(Visit visit, TIntermTraverser *it) final; + bool replaceChildNode(TIntermNode *, TIntermNode *) final { return false; } + + TIntermPreprocessorDirective *getAsPreprocessorDirective() final { return this; } + size_t getChildCount() const final; + TIntermNode *getChildNode(size_t index) const final; + + PreprocessorDirective getDirective() const { return mDirective; } + const ImmutableString &getCommand() const { return mCommand; } + + private: + PreprocessorDirective mDirective; + ImmutableString mCommand; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INTERMNODE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.cpp b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.cpp new file mode 100644 index 0000000000..73cb9d1833 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 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. +// + +#include "compiler/translator/IsASTDepthBelowLimit.h" + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// Traverse the tree and compute max depth. Takes a maximum depth limit to prevent stack overflow. +class MaxDepthTraverser : public TIntermTraverser +{ + public: + MaxDepthTraverser(int depthLimit) : TIntermTraverser(true, false, false, nullptr) + { + setMaxAllowedDepth(depthLimit); + } +}; + +} // anonymous namespace + +bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth) +{ + MaxDepthTraverser traverser(maxDepth + 1); + root->traverse(&traverser); + + return traverser.getMaxDepth() <= maxDepth; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.h b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.h new file mode 100644 index 0000000000..ef2f02c974 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/IsASTDepthBelowLimit.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 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. +// +// IsASTDepthBelowLimit: Check whether AST depth is below a specific limit. + +#ifndef COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_ +#define COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_ + +namespace sh +{ + +class TIntermNode; + +bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Operator.cpp b/gfx/angle/checkout/src/compiler/translator/Operator.cpp new file mode 100644 index 0000000000..ce6bf3d868 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Operator.cpp @@ -0,0 +1,420 @@ +// +// Copyright (c) 2002-2015 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/Operator.h" + +const char *GetOperatorString(TOperator op) +{ + switch (op) + { + // Note: EOpNull and EOpCall* can't be handled here. + + case EOpNegative: + return "-"; + case EOpPositive: + return "+"; + case EOpLogicalNot: + return "!"; + case EOpBitwiseNot: + return "~"; + + case EOpPostIncrement: + return "++"; + case EOpPostDecrement: + return "--"; + case EOpPreIncrement: + return "++"; + case EOpPreDecrement: + return "--"; + + case EOpArrayLength: + return ".length()"; + + case EOpAdd: + return "+"; + case EOpSub: + return "-"; + case EOpMul: + return "*"; + case EOpDiv: + return "/"; + case EOpIMod: + return "%"; + + case EOpEqual: + return "=="; + case EOpNotEqual: + return "!="; + case EOpLessThan: + return "<"; + case EOpGreaterThan: + return ">"; + case EOpLessThanEqual: + return "<="; + case EOpGreaterThanEqual: + return ">="; + + case EOpEqualComponentWise: + return "equal"; + case EOpNotEqualComponentWise: + return "notEqual"; + case EOpLessThanComponentWise: + return "lessThan"; + case EOpGreaterThanComponentWise: + return "greaterThan"; + case EOpLessThanEqualComponentWise: + return "lessThanEqual"; + case EOpGreaterThanEqualComponentWise: + return "greaterThanEqual"; + + case EOpComma: + return ","; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + return "*"; + + case EOpLogicalOr: + return "||"; + case EOpLogicalXor: + return "^^"; + case EOpLogicalAnd: + return "&&"; + + case EOpBitShiftLeft: + return "<<"; + case EOpBitShiftRight: + return ">>"; + + case EOpBitwiseAnd: + return "&"; + case EOpBitwiseXor: + return "^"; + case EOpBitwiseOr: + return "|"; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: + return "[]"; + + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + return "."; + + case EOpRadians: + return "radians"; + case EOpDegrees: + return "degrees"; + case EOpSin: + return "sin"; + case EOpCos: + return "cos"; + case EOpTan: + return "tan"; + case EOpAsin: + return "asin"; + case EOpAcos: + return "acos"; + case EOpAtan: + return "atan"; + + case EOpSinh: + return "sinh"; + case EOpCosh: + return "cosh"; + case EOpTanh: + return "tanh"; + case EOpAsinh: + return "asinh"; + case EOpAcosh: + return "acosh"; + case EOpAtanh: + return "atanh"; + + case EOpPow: + return "pow"; + case EOpExp: + return "exp"; + case EOpLog: + return "log"; + case EOpExp2: + return "exp2"; + case EOpLog2: + return "log2"; + case EOpSqrt: + return "sqrt"; + case EOpInversesqrt: + return "inversesqrt"; + + case EOpAbs: + return "abs"; + case EOpSign: + return "sign"; + case EOpFloor: + return "floor"; + case EOpTrunc: + return "trunc"; + case EOpRound: + return "round"; + case EOpRoundEven: + return "roundEven"; + case EOpCeil: + return "ceil"; + case EOpFract: + return "fract"; + case EOpMod: + return "mod"; + case EOpModf: + return "modf"; + case EOpMin: + return "min"; + case EOpMax: + return "max"; + case EOpClamp: + return "clamp"; + case EOpMix: + return "mix"; + case EOpStep: + return "step"; + case EOpSmoothstep: + return "smoothstep"; + case EOpIsnan: + return "isnan"; + case EOpIsinf: + return "isinf"; + + case EOpFloatBitsToInt: + return "floatBitsToInt"; + case EOpFloatBitsToUint: + return "floatBitsToUint"; + case EOpIntBitsToFloat: + return "intBitsToFloat"; + case EOpUintBitsToFloat: + return "uintBitsToFloat"; + + case EOpFrexp: + return "frexp"; + case EOpLdexp: + return "ldexp"; + + case EOpPackSnorm2x16: + return "packSnorm2x16"; + case EOpPackUnorm2x16: + return "packUnorm2x16"; + case EOpPackHalf2x16: + return "packHalf2x16"; + case EOpUnpackSnorm2x16: + return "unpackSnorm2x16"; + case EOpUnpackUnorm2x16: + return "unpackUnorm2x16"; + case EOpUnpackHalf2x16: + return "unpackHalf2x16"; + + case EOpPackUnorm4x8: + return "packUnorm4x8"; + case EOpPackSnorm4x8: + return "packSnorm4x8"; + case EOpUnpackUnorm4x8: + return "unpackUnorm4x8"; + case EOpUnpackSnorm4x8: + return "unpackSnorm4x8"; + + case EOpLength: + return "length"; + case EOpDistance: + return "distance"; + case EOpDot: + return "dot"; + case EOpCross: + return "cross"; + case EOpNormalize: + return "normalize"; + case EOpFaceforward: + return "faceforward"; + case EOpReflect: + return "reflect"; + case EOpRefract: + return "refract"; + + case EOpDFdx: + return "dFdx"; + case EOpDFdy: + return "dFdy"; + case EOpFwidth: + return "fwidth"; + + case EOpMulMatrixComponentWise: + return "matrixCompMult"; + case EOpOuterProduct: + return "outerProduct"; + case EOpTranspose: + return "transpose"; + case EOpDeterminant: + return "determinant"; + case EOpInverse: + return "inverse"; + + case EOpAny: + return "any"; + case EOpAll: + return "all"; + case EOpLogicalNotComponentWise: + return "not"; + + case EOpBitfieldExtract: + return "bitfieldExtract"; + case EOpBitfieldInsert: + return "bitfieldInsert"; + case EOpBitfieldReverse: + return "bitfieldReverse"; + case EOpBitCount: + return "bitCount"; + case EOpFindLSB: + return "findLSB"; + case EOpFindMSB: + return "findMSB"; + case EOpUaddCarry: + return "uaddCarry"; + case EOpUsubBorrow: + return "usubBorrow"; + case EOpUmulExtended: + return "umulExtended"; + case EOpImulExtended: + return "imulExtended"; + + case EOpKill: + return "kill"; + case EOpReturn: + return "return"; + case EOpBreak: + return "break"; + case EOpContinue: + return "continue"; + + case EOpAssign: + return "="; + case EOpInitialize: + return "="; + case EOpAddAssign: + return "+="; + case EOpSubAssign: + return "-="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + return "*="; + + case EOpDivAssign: + return "/="; + case EOpIModAssign: + return "%="; + case EOpBitShiftLeftAssign: + return "<<="; + case EOpBitShiftRightAssign: + return ">>="; + case EOpBitwiseAndAssign: + return "&="; + case EOpBitwiseXorAssign: + return "^="; + case EOpBitwiseOrAssign: + return "|="; + case EOpBarrier: + return "barrier"; + case EOpMemoryBarrier: + return "memoryBarrier"; + case EOpMemoryBarrierAtomicCounter: + return "memoryBarrierAtomicCounter"; + case EOpMemoryBarrierBuffer: + return "memoryBarrierBuffer"; + case EOpMemoryBarrierImage: + return "memoryBarrierImage"; + case EOpMemoryBarrierShared: + return "memoryBarrierShared"; + case EOpGroupMemoryBarrier: + return "groupMemoryBarrier"; + + case EOpAtomicAdd: + return "atomicAdd"; + case EOpAtomicMin: + return "atomicMin"; + case EOpAtomicMax: + return "atomicMax"; + case EOpAtomicAnd: + return "atomicAnd"; + case EOpAtomicOr: + return "atomicOr"; + case EOpAtomicXor: + return "atomicXor"; + case EOpAtomicExchange: + return "atomicExchange"; + case EOpAtomicCompSwap: + return "atomicCompSwap"; + + case EOpEmitVertex: + return "EmitVertex"; + case EOpEndPrimitive: + return "EndPrimitive"; + default: + break; + } + return ""; +} + +bool IsAssignment(TOperator op) +{ + switch (op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + return true; + default: + return false; + } +} + +bool IsAtomicFunction(TOperator op) +{ + switch (op) + { + case EOpAtomicAdd: + case EOpAtomicMin: + case EOpAtomicMax: + case EOpAtomicAnd: + case EOpAtomicOr: + case EOpAtomicXor: + case EOpAtomicExchange: + case EOpAtomicCompSwap: + return true; + default: + return false; + } +}
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/Operator.h b/gfx/angle/checkout/src/compiler/translator/Operator.h new file mode 100644 index 0000000000..e1540faa44 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Operator.h @@ -0,0 +1,268 @@ +// +// Copyright (c) 2002-2015 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_OPERATOR_H_ +#define COMPILER_TRANSLATOR_OPERATOR_H_ + +// +// Operators used by the high-level (parse tree) representation. +// +enum TOperator +{ + EOpNull, // if in a node, should only mean a node is still being built + + // Call a function defined in the AST. This might be a user-defined function or a function + // inserted by an AST transformation. + EOpCallFunctionInAST, + + // Call an internal helper function with a raw implementation - the implementation can't be + // subject to AST transformations. Raw functions have a few constraints to keep them compatible + // with AST traversers: + // * They should not return arrays. + // * They should not have out parameters. + EOpCallInternalRawFunction, + + // Call a built-in function like a texture or image function. + EOpCallBuiltInFunction, + + // + // Unary operators + // + + EOpNegative, + EOpPositive, + EOpLogicalNot, + EOpBitwiseNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + EOpArrayLength, + + // + // binary operations (ones with special GLSL syntax are used in TIntermBinary nodes, others in + // TIntermAggregate nodes) + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpIMod, + + EOpEqual, + EOpNotEqual, + EOpLessThan, + EOpGreaterThan, + EOpLessThanEqual, + EOpGreaterThanEqual, + + EOpEqualComponentWise, + EOpNotEqualComponentWise, + EOpLessThanComponentWise, + EOpLessThanEqualComponentWise, + EOpGreaterThanComponentWise, + EOpGreaterThanEqualComponentWise, + + EOpComma, + + EOpVectorTimesScalar, + EOpVectorTimesMatrix, + EOpMatrixTimesVector, + EOpMatrixTimesScalar, + EOpMatrixTimesMatrix, + + EOpLogicalOr, + EOpLogicalXor, + EOpLogicalAnd, + + EOpBitShiftLeft, + EOpBitShiftRight, + + EOpBitwiseAnd, + EOpBitwiseXor, + EOpBitwiseOr, + + EOpIndexDirect, + EOpIndexIndirect, + EOpIndexDirectStruct, + EOpIndexDirectInterfaceBlock, + + // + // Built-in functions mapped to operators (either unary or with multiple parameters) + // + + EOpRadians, + EOpDegrees, + EOpSin, + EOpCos, + EOpTan, + EOpAsin, + EOpAcos, + EOpAtan, + + EOpSinh, + EOpCosh, + EOpTanh, + EOpAsinh, + EOpAcosh, + EOpAtanh, + + EOpPow, + EOpExp, + EOpLog, + EOpExp2, + EOpLog2, + EOpSqrt, + EOpInversesqrt, + + EOpAbs, + EOpSign, + EOpFloor, + EOpTrunc, + EOpRound, + EOpRoundEven, + EOpCeil, + EOpFract, + EOpMod, + EOpModf, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothstep, + EOpIsnan, + EOpIsinf, + + EOpFloatBitsToInt, + EOpFloatBitsToUint, + EOpIntBitsToFloat, + EOpUintBitsToFloat, + + EOpFrexp, + EOpLdexp, + + EOpPackSnorm2x16, + EOpPackUnorm2x16, + EOpPackHalf2x16, + EOpUnpackSnorm2x16, + EOpUnpackUnorm2x16, + EOpUnpackHalf2x16, + + EOpPackUnorm4x8, + EOpPackSnorm4x8, + EOpUnpackUnorm4x8, + EOpUnpackSnorm4x8, + + EOpLength, + EOpDistance, + EOpDot, + EOpCross, + EOpNormalize, + EOpFaceforward, + EOpReflect, + EOpRefract, + + EOpDFdx, // Fragment only, OES_standard_derivatives extension + EOpDFdy, // Fragment only, OES_standard_derivatives extension + EOpFwidth, // Fragment only, OES_standard_derivatives extension + + EOpMulMatrixComponentWise, + EOpOuterProduct, + EOpTranspose, + EOpDeterminant, + EOpInverse, + + EOpAny, + EOpAll, + EOpLogicalNotComponentWise, + + EOpBitfieldExtract, + EOpBitfieldInsert, + EOpBitfieldReverse, + EOpBitCount, + EOpFindLSB, + EOpFindMSB, + EOpUaddCarry, + EOpUsubBorrow, + EOpUmulExtended, + EOpImulExtended, + + // + // Branch + // + + EOpKill, // Fragment only + EOpReturn, + EOpBreak, + EOpContinue, + + // + // Constructor + // + + EOpConstruct, + + // + // moves + // + + EOpAssign, + EOpInitialize, + EOpAddAssign, + EOpSubAssign, + + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + + EOpDivAssign, + EOpIModAssign, + EOpBitShiftLeftAssign, + EOpBitShiftRightAssign, + EOpBitwiseAndAssign, + EOpBitwiseXorAssign, + EOpBitwiseOrAssign, + + // barriers + EOpBarrier, + EOpMemoryBarrier, + EOpMemoryBarrierAtomicCounter, + EOpMemoryBarrierBuffer, + EOpMemoryBarrierImage, + EOpMemoryBarrierShared, + EOpGroupMemoryBarrier, + + // Atomic functions + EOpAtomicAdd, + EOpAtomicMin, + EOpAtomicMax, + EOpAtomicAnd, + EOpAtomicOr, + EOpAtomicXor, + EOpAtomicExchange, + EOpAtomicCompSwap, + + // Geometry only + EOpEmitVertex, + EOpEndPrimitive +}; + +// Returns the string corresponding to the operator in GLSL +const char *GetOperatorString(TOperator op); + +// Say whether or not a binary or unary operation changes the value of a variable. +bool IsAssignment(TOperator op); + +// Say whether or not an operator represents an atomic function. +bool IsAtomicFunction(TOperator op); + +#endif // COMPILER_TRANSLATOR_OPERATOR_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/OutputESSL.cpp b/gfx/angle/checkout/src/compiler/translator/OutputESSL.cpp new file mode 100644 index 0000000000..8d57eeae84 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputESSL.cpp @@ -0,0 +1,46 @@ +// +// Copyright (c) 2002-2013 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/OutputESSL.h" + +namespace sh +{ + +TOutputESSL::TOutputESSL(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + bool forceHighp, + ShCompileOptions compileOptions) + : TOutputGLSLBase(objSink, + clampingStrategy, + hashFunction, + nameMap, + symbolTable, + shaderType, + shaderVersion, + SH_ESSL_OUTPUT, + compileOptions), + mForceHighp(forceHighp) +{} + +bool TOutputESSL::writeVariablePrecision(TPrecision precision) +{ + if (precision == EbpUndefined) + return false; + + TInfoSinkBase &out = objSink(); + if (mForceHighp) + out << getPrecisionString(EbpHigh); + else + out << getPrecisionString(precision); + return true; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/OutputESSL.h b/gfx/angle/checkout/src/compiler/translator/OutputESSL.h new file mode 100644 index 0000000000..e0c7bf2ae6 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputESSL.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-2013 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_OUTPUTESSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTESSL_H_ + +#include "compiler/translator/OutputGLSLBase.h" + +namespace sh +{ + +class TOutputESSL : public TOutputGLSLBase +{ + public: + TOutputESSL(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + bool forceHighp, + ShCompileOptions compileOptions); + + protected: + bool writeVariablePrecision(TPrecision precision) override; + + private: + bool mForceHighp; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.cpp new file mode 100644 index 0000000000..ced5020ba3 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.cpp @@ -0,0 +1,118 @@ +// +// Copyright (c) 2002-2013 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/OutputGLSL.h" + +#include "compiler/translator/Compiler.h" + +namespace sh +{ + +TOutputGLSL::TOutputGLSL(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput output, + ShCompileOptions compileOptions) + : TOutputGLSLBase(objSink, + clampingStrategy, + hashFunction, + nameMap, + symbolTable, + shaderType, + shaderVersion, + output, + compileOptions) +{} + +bool TOutputGLSL::writeVariablePrecision(TPrecision) +{ + return false; +} + +void TOutputGLSL::visitSymbol(TIntermSymbol *node) +{ + TInfoSinkBase &out = objSink(); + + // All the special cases are built-ins, so if it's not a built-in we can return early. + if (node->variable().symbolType() != SymbolType::BuiltIn) + { + TOutputGLSLBase::visitSymbol(node); + return; + } + + // Some built-ins get a special translation. + const ImmutableString &name = node->getName(); + if (name == "gl_FragDepthEXT") + { + out << "gl_FragDepth"; + } + else if (name == "gl_FragColor" && sh::IsGLSL130OrNewer(getShaderOutput())) + { + out << "webgl_FragColor"; + } + else if (name == "gl_FragData" && sh::IsGLSL130OrNewer(getShaderOutput())) + { + out << "webgl_FragData"; + } + else if (name == "gl_SecondaryFragColorEXT") + { + out << "angle_SecondaryFragColor"; + } + else if (name == "gl_SecondaryFragDataEXT") + { + out << "angle_SecondaryFragData"; + } + else + { + TOutputGLSLBase::visitSymbol(node); + } +} + +ImmutableString TOutputGLSL::translateTextureFunction(const ImmutableString &name) +{ + static const char *simpleRename[] = {"texture2DLodEXT", + "texture2DLod", + "texture2DProjLodEXT", + "texture2DProjLod", + "textureCubeLodEXT", + "textureCubeLod", + "texture2DGradEXT", + "texture2DGradARB", + "texture2DProjGradEXT", + "texture2DProjGradARB", + "textureCubeGradEXT", + "textureCubeGradARB", + nullptr, + nullptr}; + static const char *legacyToCoreRename[] = { + "texture2D", "texture", "texture2DProj", "textureProj", "texture2DLod", "textureLod", + "texture2DProjLod", "textureProjLod", "texture2DRect", "texture", "texture2DRectProj", + "textureProj", "textureCube", "texture", "textureCubeLod", "textureLod", + // Extensions + "texture2DLodEXT", "textureLod", "texture2DProjLodEXT", "textureProjLod", + "textureCubeLodEXT", "textureLod", "texture2DGradEXT", "textureGrad", + "texture2DProjGradEXT", "textureProjGrad", "textureCubeGradEXT", "textureGrad", "texture3D", + "texture", "texture3DProj", "textureProj", "texture3DLod", "textureLod", "texture3DProjLod", + "textureProjLod", nullptr, nullptr}; + const char **mapping = + (sh::IsGLSL130OrNewer(getShaderOutput())) ? legacyToCoreRename : simpleRename; + + for (int i = 0; mapping[i] != nullptr; i += 2) + { + if (name == mapping[i]) + { + return ImmutableString(mapping[i + 1]); + } + } + + return name; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSL.h b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.h new file mode 100644 index 0000000000..b676a79932 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSL.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2002-2013 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_OUTPUTGLSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTGLSL_H_ + +#include "compiler/translator/OutputGLSLBase.h" + +namespace sh +{ + +class TOutputGLSL : public TOutputGLSLBase +{ + public: + TOutputGLSL(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput output, + ShCompileOptions compileOptions); + + protected: + bool writeVariablePrecision(TPrecision) override; + void visitSymbol(TIntermSymbol *node) override; + ImmutableString translateTextureFunction(const ImmutableString &name) override; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_OUTPUTGLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp new file mode 100644 index 0000000000..eb830612ff --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp @@ -0,0 +1,1433 @@ +// +// Copyright (c) 2002-2014 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/OutputGLSLBase.h" + +#include "angle_gl.h" +#include "common/debug.h" +#include "common/mathutil.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/util.h" + +#include <cfloat> + +namespace sh +{ + +namespace +{ + +bool isSingleStatement(TIntermNode *node) +{ + if (node->getAsFunctionDefinition()) + { + return false; + } + else if (node->getAsBlock()) + { + return false; + } + else if (node->getAsIfElseNode()) + { + return false; + } + else if (node->getAsLoopNode()) + { + return false; + } + else if (node->getAsSwitchNode()) + { + return false; + } + else if (node->getAsCaseNode()) + { + return false; + } + else if (node->getAsPreprocessorDirective()) + { + return false; + } + return true; +} + +class CommaSeparatedListItemPrefixGenerator +{ + public: + CommaSeparatedListItemPrefixGenerator() : mFirst(true) {} + + private: + bool mFirst; + + template <typename Stream> + friend Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen); +}; + +template <typename Stream> +Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen) +{ + if (gen.mFirst) + { + gen.mFirst = false; + } + else + { + out << ", "; + } + return out; +} + +} // namespace + +TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput output, + ShCompileOptions compileOptions) + : TIntermTraverser(true, true, true, symbolTable), + mObjSink(objSink), + mDeclaringVariable(false), + mClampingStrategy(clampingStrategy), + mHashFunction(hashFunction), + mNameMap(nameMap), + mShaderType(shaderType), + mShaderVersion(shaderVersion), + mOutput(output), + mCompileOptions(compileOptions) +{} + +void TOutputGLSLBase::writeInvariantQualifier(const TType &type) +{ + if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions)) + { + TInfoSinkBase &out = objSink(); + out << "invariant "; + } +} + +void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f) +{ + if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300) + { + out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)"; + } + else + { + out << std::min(FLT_MAX, std::max(-FLT_MAX, f)); + } +} + +void TOutputGLSLBase::writeTriplet(Visit visit, + const char *preStr, + const char *inStr, + const char *postStr) +{ + TInfoSinkBase &out = objSink(); + if (visit == PreVisit && preStr) + out << preStr; + else if (visit == InVisit && inStr) + out << inStr; + else if (visit == PostVisit && postStr) + out << postStr; +} + +void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit, + TOperator op, + bool useEmulatedFunction) +{ + TInfoSinkBase &out = objSink(); + if (visit == PreVisit) + { + const char *opStr(GetOperatorString(op)); + if (useEmulatedFunction) + { + BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr); + } + else + { + out << opStr; + } + out << "("; + } + else + { + writeTriplet(visit, nullptr, ", ", ")"); + } +} + +// Outputs what goes inside layout(), except for location and binding qualifiers, as they are +// handled differently between GL GLSL and Vulkan GLSL. +std::string TOutputGLSLBase::getCommonLayoutQualifiers(TIntermTyped *variable) +{ + std::ostringstream out; + CommaSeparatedListItemPrefixGenerator listItemPrefix; + + const TType &type = variable->getType(); + const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); + + if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn || + IsVarying(type.getQualifier())) + { + if (type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0) + { + out << listItemPrefix << "index = " << layoutQualifier.index; + } + } + + if (type.getQualifier() == EvqFragmentOut) + { + if (layoutQualifier.yuv == true) + { + out << listItemPrefix << "yuv"; + } + } + + if (IsImage(type.getBasicType())) + { + if (layoutQualifier.imageInternalFormat != EiifUnspecified) + { + ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform); + out << listItemPrefix + << getImageInternalFormatString(layoutQualifier.imageInternalFormat); + } + } + + if (IsAtomicCounter(type.getBasicType())) + { + out << listItemPrefix << "offset = " << layoutQualifier.offset; + } + + return out.str(); +} + +// Outputs what comes after in/out/uniform/buffer storage qualifier. +std::string TOutputGLSLBase::getMemoryQualifiers(const TType &type) +{ + std::ostringstream out; + + const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier(); + if (memoryQualifier.readonly) + { + ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier())); + out << "readonly "; + } + + if (memoryQualifier.writeonly) + { + ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier())); + out << "writeonly "; + } + + if (memoryQualifier.coherent) + { + ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier())); + out << "coherent "; + } + + if (memoryQualifier.restrictQualifier) + { + ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier())); + out << "restrict "; + } + + if (memoryQualifier.volatileQualifier) + { + ASSERT(IsImage(type.getBasicType()) || IsStorageBuffer(type.getQualifier())); + out << "volatile "; + } + + return out.str(); +} + +void TOutputGLSLBase::writeLayoutQualifier(TIntermTyped *variable) +{ + const TType &type = variable->getType(); + + if (!NeedsToWriteLayoutQualifier(type)) + { + return; + } + + if (type.getBasicType() == EbtInterfaceBlock) + { + const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); + declareInterfaceBlockLayout(interfaceBlock); + return; + } + + TInfoSinkBase &out = objSink(); + const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); + out << "layout("; + + CommaSeparatedListItemPrefixGenerator listItemPrefix; + + if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn || + IsVarying(type.getQualifier())) + { + if (layoutQualifier.location >= 0) + { + out << listItemPrefix << "location = " << layoutQualifier.location; + } + } + + if (IsOpaqueType(type.getBasicType())) + { + if (layoutQualifier.binding >= 0) + { + out << listItemPrefix << "binding = " << layoutQualifier.binding; + } + } + + std::string otherQualifiers = getCommonLayoutQualifiers(variable); + if (!otherQualifiers.empty()) + { + out << listItemPrefix << otherQualifiers; + } + + out << ") "; +} + +void TOutputGLSLBase::writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol) +{ + const char *result = mapQualifierToString(qualifier); + if (result && result[0] != '\0') + { + objSink() << result << " "; + } + + objSink() << getMemoryQualifiers(type); +} + +const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier) +{ + if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 && + (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0) + { + switch (qualifier) + { + // The return string is consistent with sh::getQualifierString() from + // BaseTypes.h minus the "centroid" keyword. + case EvqCentroid: + return ""; + case EvqCentroidIn: + return "smooth in"; + case EvqCentroidOut: + return "smooth out"; + default: + break; + } + } + if (sh::IsGLSL130OrNewer(mOutput)) + { + switch (qualifier) + { + case EvqAttribute: + return "in"; + case EvqVaryingIn: + return "in"; + case EvqVaryingOut: + return "out"; + default: + break; + } + } + return sh::getQualifierString(qualifier); +} + +void TOutputGLSLBase::writeVariableType(const TType &type, const TSymbol *symbol) +{ + TQualifier qualifier = type.getQualifier(); + TInfoSinkBase &out = objSink(); + if (type.isInvariant()) + { + writeInvariantQualifier(type); + } + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + { + writeQualifier(qualifier, type, symbol); + } + + // Declare the struct if we have not done so already. + if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) + { + const TStructure *structure = type.getStruct(); + + declareStruct(structure); + } + else if (type.getBasicType() == EbtInterfaceBlock) + { + const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); + declareInterfaceBlock(interfaceBlock); + } + else + { + if (writeVariablePrecision(type.getPrecision())) + out << " "; + out << getTypeName(type); + } +} + +void TOutputGLSLBase::writeFunctionParameters(const TFunction *func) +{ + TInfoSinkBase &out = objSink(); + size_t paramCount = func->getParamCount(); + for (size_t i = 0; i < paramCount; ++i) + { + const TVariable *param = func->getParam(i); + const TType &type = param->getType(); + writeVariableType(type, param); + + if (param->symbolType() != SymbolType::Empty) + out << " " << hashName(param); + if (type.isArray()) + out << ArrayString(type); + + // Put a comma if this is not the last argument. + if (i != paramCount - 1) + out << ", "; + } +} + +const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type, + const TConstantUnion *pConstUnion) +{ + TInfoSinkBase &out = objSink(); + + if (type.getBasicType() == EbtStruct) + { + const TStructure *structure = type.getStruct(); + out << hashName(structure) << "("; + + const TFieldList &fields = structure->fields(); + for (size_t i = 0; i < fields.size(); ++i) + { + const TType *fieldType = fields[i]->type(); + ASSERT(fieldType != nullptr); + pConstUnion = writeConstantUnion(*fieldType, pConstUnion); + if (i != fields.size() - 1) + out << ", "; + } + out << ")"; + } + else + { + size_t size = type.getObjectSize(); + bool writeType = size > 1; + if (writeType) + out << getTypeName(type) << "("; + for (size_t i = 0; i < size; ++i, ++pConstUnion) + { + switch (pConstUnion->getType()) + { + case EbtFloat: + writeFloat(out, pConstUnion->getFConst()); + break; + case EbtInt: + out << pConstUnion->getIConst(); + break; + case EbtUInt: + out << pConstUnion->getUConst() << "u"; + break; + case EbtBool: + out << pConstUnion->getBConst(); + break; + case EbtYuvCscStandardEXT: + out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst()); + break; + default: + UNREACHABLE(); + } + if (i != size - 1) + out << ", "; + } + if (writeType) + out << ")"; + } + return pConstUnion; +} + +void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type) +{ + TInfoSinkBase &out = objSink(); + if (visit == PreVisit) + { + if (type.isArray()) + { + out << getTypeName(type); + out << ArrayString(type); + out << "("; + } + else + { + out << getTypeName(type) << "("; + } + } + else + { + writeTriplet(visit, nullptr, ", ", ")"); + } +} + +void TOutputGLSLBase::visitSymbol(TIntermSymbol *node) +{ + TInfoSinkBase &out = objSink(); + out << hashName(&node->variable()); + + if (mDeclaringVariable && node->getType().isArray()) + out << ArrayString(node->getType()); +} + +void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node) +{ + writeConstantUnion(node->getType(), node->getConstantValue()); +} + +bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + TInfoSinkBase &out = objSink(); + if (visit == PostVisit) + { + out << "."; + node->writeOffsetsAsXYZW(&out); + } + return true; +} + +bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) +{ + bool visitChildren = true; + TInfoSinkBase &out = objSink(); + switch (node->getOp()) + { + case EOpComma: + writeTriplet(visit, "(", ", ", ")"); + break; + case EOpInitialize: + if (visit == InVisit) + { + out << " = "; + // RHS of initialize is not being declared. + mDeclaringVariable = false; + } + break; + case EOpAssign: + writeTriplet(visit, "(", " = ", ")"); + break; + case EOpAddAssign: + writeTriplet(visit, "(", " += ", ")"); + break; + case EOpSubAssign: + writeTriplet(visit, "(", " -= ", ")"); + break; + case EOpDivAssign: + writeTriplet(visit, "(", " /= ", ")"); + break; + case EOpIModAssign: + writeTriplet(visit, "(", " %= ", ")"); + break; + // Notice the fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + writeTriplet(visit, "(", " *= ", ")"); + break; + case EOpBitShiftLeftAssign: + writeTriplet(visit, "(", " <<= ", ")"); + break; + case EOpBitShiftRightAssign: + writeTriplet(visit, "(", " >>= ", ")"); + break; + case EOpBitwiseAndAssign: + writeTriplet(visit, "(", " &= ", ")"); + break; + case EOpBitwiseXorAssign: + writeTriplet(visit, "(", " ^= ", ")"); + break; + case EOpBitwiseOrAssign: + writeTriplet(visit, "(", " |= ", ")"); + break; + + case EOpIndexDirect: + writeTriplet(visit, nullptr, "[", "]"); + break; + case EOpIndexIndirect: + if (node->getAddIndexClamp()) + { + if (visit == InVisit) + { + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "[int(clamp(float("; + else + out << "[webgl_int_clamp("; + } + else if (visit == PostVisit) + { + TIntermTyped *left = node->getLeft(); + TType leftType = left->getType(); + + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "), 0.0, float("; + else + out << ", 0, "; + + if (leftType.isUnsizedArray()) + { + // For runtime-sized arrays in ESSL 3.10 we need to call the length method + // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note + // that a runtime-sized array expression is guaranteed not to have side + // effects, so it's fine to add the expression to the output twice. + ASSERT(mShaderVersion >= 310); + ASSERT(!left->hasSideEffects()); + left->traverse(this); + out << ".length() - 1"; + } + else + { + int maxSize; + if (leftType.isArray()) + { + maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1; + } + else + { + maxSize = leftType.getNominalSize() - 1; + } + out << maxSize; + } + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << ")))]"; + else + out << ")]"; + } + } + else + { + writeTriplet(visit, nullptr, "[", "]"); + } + break; + case EOpIndexDirectStruct: + if (visit == InVisit) + { + // Here we are writing out "foo.bar", where "foo" is struct + // and "bar" is field. In AST, it is represented as a binary + // node, where left child represents "foo" and right child "bar". + // The node itself represents ".". The struct field "bar" is + // actually stored as an index into TStructure::fields. + out << "."; + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + + out << hashFieldName(field); + visitChildren = false; + } + break; + case EOpIndexDirectInterfaceBlock: + if (visit == InVisit) + { + out << "."; + const TInterfaceBlock *interfaceBlock = + node->getLeft()->getType().getInterfaceBlock(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = interfaceBlock->fields()[index->getIConst(0)]; + out << hashFieldName(field); + visitChildren = false; + } + break; + + case EOpAdd: + writeTriplet(visit, "(", " + ", ")"); + break; + case EOpSub: + writeTriplet(visit, "(", " - ", ")"); + break; + case EOpMul: + writeTriplet(visit, "(", " * ", ")"); + break; + case EOpDiv: + writeTriplet(visit, "(", " / ", ")"); + break; + case EOpIMod: + writeTriplet(visit, "(", " % ", ")"); + break; + case EOpBitShiftLeft: + writeTriplet(visit, "(", " << ", ")"); + break; + case EOpBitShiftRight: + writeTriplet(visit, "(", " >> ", ")"); + break; + case EOpBitwiseAnd: + writeTriplet(visit, "(", " & ", ")"); + break; + case EOpBitwiseXor: + writeTriplet(visit, "(", " ^ ", ")"); + break; + case EOpBitwiseOr: + writeTriplet(visit, "(", " | ", ")"); + break; + + case EOpEqual: + writeTriplet(visit, "(", " == ", ")"); + break; + case EOpNotEqual: + writeTriplet(visit, "(", " != ", ")"); + break; + case EOpLessThan: + writeTriplet(visit, "(", " < ", ")"); + break; + case EOpGreaterThan: + writeTriplet(visit, "(", " > ", ")"); + break; + case EOpLessThanEqual: + writeTriplet(visit, "(", " <= ", ")"); + break; + case EOpGreaterThanEqual: + writeTriplet(visit, "(", " >= ", ")"); + break; + + // Notice the fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + writeTriplet(visit, "(", " * ", ")"); + break; + + case EOpLogicalOr: + writeTriplet(visit, "(", " || ", ")"); + break; + case EOpLogicalXor: + writeTriplet(visit, "(", " ^^ ", ")"); + break; + case EOpLogicalAnd: + writeTriplet(visit, "(", " && ", ")"); + break; + default: + UNREACHABLE(); + } + + return visitChildren; +} + +bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) +{ + const char *preString = ""; + const char *postString = ")"; + + switch (node->getOp()) + { + case EOpNegative: + preString = "(-"; + break; + case EOpPositive: + preString = "(+"; + break; + case EOpLogicalNot: + preString = "(!"; + break; + case EOpBitwiseNot: + preString = "(~"; + break; + + case EOpPostIncrement: + preString = "("; + postString = "++)"; + break; + case EOpPostDecrement: + preString = "("; + postString = "--)"; + break; + case EOpPreIncrement: + preString = "(++"; + break; + case EOpPreDecrement: + preString = "(--"; + break; + case EOpArrayLength: + preString = "(("; + postString = ").length())"; + break; + + case EOpRadians: + case EOpDegrees: + case EOpSin: + case EOpCos: + case EOpTan: + case EOpAsin: + case EOpAcos: + case EOpAtan: + case EOpSinh: + case EOpCosh: + case EOpTanh: + case EOpAsinh: + case EOpAcosh: + case EOpAtanh: + case EOpExp: + case EOpLog: + case EOpExp2: + case EOpLog2: + case EOpSqrt: + case EOpInversesqrt: + case EOpAbs: + case EOpSign: + case EOpFloor: + case EOpTrunc: + case EOpRound: + case EOpRoundEven: + case EOpCeil: + case EOpFract: + case EOpIsnan: + case EOpIsinf: + case EOpFloatBitsToInt: + case EOpFloatBitsToUint: + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + case EOpUnpackHalf2x16: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + case EOpLength: + case EOpNormalize: + case EOpDFdx: + case EOpDFdy: + case EOpFwidth: + case EOpTranspose: + case EOpDeterminant: + case EOpInverse: + case EOpAny: + case EOpAll: + case EOpLogicalNotComponentWise: + case EOpBitfieldReverse: + case EOpBitCount: + case EOpFindLSB: + case EOpFindMSB: + writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction()); + return true; + default: + UNREACHABLE(); + } + + writeTriplet(visit, preString, nullptr, postString); + + return true; +} + +bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node) +{ + TInfoSinkBase &out = objSink(); + // Notice two brackets at the beginning and end. The outer ones + // encapsulate the whole ternary expression. This preserves the + // order of precedence when ternary expressions are used in a + // compound expression, i.e., c = 2 * (a < b ? 1 : 2). + out << "(("; + node->getCondition()->traverse(this); + out << ") ? ("; + node->getTrueExpression()->traverse(this); + out << ") : ("; + node->getFalseExpression()->traverse(this); + out << "))"; + return false; +} + +bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node) +{ + TInfoSinkBase &out = objSink(); + + out << "if ("; + node->getCondition()->traverse(this); + out << ")\n"; + + visitCodeBlock(node->getTrueBlock()); + + if (node->getFalseBlock()) + { + out << "else\n"; + visitCodeBlock(node->getFalseBlock()); + } + return false; +} + +bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node) +{ + ASSERT(node->getStatementList()); + writeTriplet(visit, "switch (", ") ", nullptr); + // The curly braces get written when visiting the statementList aggregate + return true; +} + +bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node) +{ + if (node->hasCondition()) + { + writeTriplet(visit, "case (", nullptr, "):\n"); + return true; + } + else + { + TInfoSinkBase &out = objSink(); + out << "default:\n"; + return false; + } +} + +bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node) +{ + TInfoSinkBase &out = objSink(); + // Scope the blocks except when at the global scope. + if (getCurrentTraversalDepth() > 0) + { + out << "{\n"; + } + + for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); + iter != node->getSequence()->end(); ++iter) + { + TIntermNode *curNode = *iter; + ASSERT(curNode != nullptr); + curNode->traverse(this); + + if (isSingleStatement(curNode)) + out << ";\n"; + } + + // Scope the blocks except when at the global scope. + if (getCurrentTraversalDepth() > 0) + { + out << "}\n"; + } + return false; +} + +bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + TIntermFunctionPrototype *prototype = node->getFunctionPrototype(); + prototype->traverse(this); + visitCodeBlock(node->getBody()); + + // Fully processed; no need to visit children. + return false; +} + +bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + TInfoSinkBase &out = objSink(); + ASSERT(visit == PreVisit); + const TIntermSymbol *symbol = node->getSymbol(); + out << "invariant " << hashName(&symbol->variable()); + return false; +} + +void TOutputGLSLBase::visitFunctionPrototype(TIntermFunctionPrototype *node) +{ + TInfoSinkBase &out = objSink(); + + const TType &type = node->getType(); + writeVariableType(type, node->getFunction()); + if (type.isArray()) + out << ArrayString(type); + + out << " " << hashFunctionNameIfNeeded(node->getFunction()); + + out << "("; + writeFunctionParameters(node->getFunction()); + out << ")"; +} + +bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) +{ + bool visitChildren = true; + TInfoSinkBase &out = objSink(); + switch (node->getOp()) + { + case EOpCallFunctionInAST: + case EOpCallInternalRawFunction: + case EOpCallBuiltInFunction: + // Function call. + if (visit == PreVisit) + { + if (node->getOp() == EOpCallBuiltInFunction) + { + out << translateTextureFunction(node->getFunction()->name()); + } + else + { + out << hashFunctionNameIfNeeded(node->getFunction()); + } + out << "("; + } + else if (visit == InVisit) + out << ", "; + else + out << ")"; + break; + case EOpConstruct: + writeConstructorTriplet(visit, node->getType()); + break; + + case EOpEqualComponentWise: + case EOpNotEqualComponentWise: + case EOpLessThanComponentWise: + case EOpGreaterThanComponentWise: + case EOpLessThanEqualComponentWise: + case EOpGreaterThanEqualComponentWise: + case EOpMod: + case EOpModf: + case EOpPow: + case EOpAtan: + case EOpMin: + case EOpMax: + case EOpClamp: + case EOpMix: + case EOpStep: + case EOpSmoothstep: + case EOpFrexp: + case EOpLdexp: + case EOpDistance: + case EOpDot: + case EOpCross: + case EOpFaceforward: + case EOpReflect: + case EOpRefract: + case EOpMulMatrixComponentWise: + case EOpOuterProduct: + case EOpBitfieldExtract: + case EOpBitfieldInsert: + case EOpUaddCarry: + case EOpUsubBorrow: + case EOpUmulExtended: + case EOpImulExtended: + case EOpBarrier: + case EOpMemoryBarrier: + case EOpMemoryBarrierAtomicCounter: + case EOpMemoryBarrierBuffer: + case EOpMemoryBarrierImage: + case EOpMemoryBarrierShared: + case EOpGroupMemoryBarrier: + case EOpAtomicAdd: + case EOpAtomicMin: + case EOpAtomicMax: + case EOpAtomicAnd: + case EOpAtomicOr: + case EOpAtomicXor: + case EOpAtomicExchange: + case EOpAtomicCompSwap: + case EOpEmitVertex: + case EOpEndPrimitive: + writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction()); + break; + default: + UNREACHABLE(); + } + return visitChildren; +} + +bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + TInfoSinkBase &out = objSink(); + + // Variable declaration. + if (visit == PreVisit) + { + const TIntermSequence &sequence = *(node->getSequence()); + TIntermTyped *variable = sequence.front()->getAsTyped(); + writeLayoutQualifier(variable); + TIntermSymbol *symbolNode = variable->getAsSymbolNode(); + writeVariableType(variable->getType(), symbolNode ? &symbolNode->variable() : nullptr); + if (variable->getAsSymbolNode() == nullptr || + variable->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty) + { + out << " "; + } + mDeclaringVariable = true; + } + else if (visit == InVisit) + { + UNREACHABLE(); + } + else + { + mDeclaringVariable = false; + } + return true; +} + +bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node) +{ + TInfoSinkBase &out = objSink(); + + TLoopType loopType = node->getType(); + + if (loopType == ELoopFor) // for loop + { + out << "for ("; + if (node->getInit()) + node->getInit()->traverse(this); + out << "; "; + + if (node->getCondition()) + node->getCondition()->traverse(this); + out << "; "; + + if (node->getExpression()) + node->getExpression()->traverse(this); + out << ")\n"; + + visitCodeBlock(node->getBody()); + } + else if (loopType == ELoopWhile) // while loop + { + out << "while ("; + ASSERT(node->getCondition() != nullptr); + node->getCondition()->traverse(this); + out << ")\n"; + + visitCodeBlock(node->getBody()); + } + else // do-while loop + { + ASSERT(loopType == ELoopDoWhile); + out << "do\n"; + + visitCodeBlock(node->getBody()); + + out << "while ("; + ASSERT(node->getCondition() != nullptr); + node->getCondition()->traverse(this); + out << ");\n"; + } + + // No need to visit children. They have been already processed in + // this function. + return false; +} + +bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node) +{ + switch (node->getFlowOp()) + { + case EOpKill: + writeTriplet(visit, "discard", nullptr, nullptr); + break; + case EOpBreak: + writeTriplet(visit, "break", nullptr, nullptr); + break; + case EOpContinue: + writeTriplet(visit, "continue", nullptr, nullptr); + break; + case EOpReturn: + writeTriplet(visit, "return ", nullptr, nullptr); + break; + default: + UNREACHABLE(); + } + + return true; +} + +void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node) +{ + TInfoSinkBase &out = objSink(); + if (node != nullptr) + { + node->traverse(this); + // Single statements not part of a sequence need to be terminated + // with semi-colon. + if (isSingleStatement(node)) + out << ";\n"; + } + else + { + out << "{\n}\n"; // Empty code block. + } +} + +void TOutputGLSLBase::visitPreprocessorDirective(TIntermPreprocessorDirective *node) +{ + TInfoSinkBase &out = objSink(); + + out << "\n"; + + switch (node->getDirective()) + { + case PreprocessorDirective::Define: + out << "#define"; + break; + case PreprocessorDirective::Endif: + out << "#endif"; + break; + case PreprocessorDirective::If: + out << "#if"; + break; + case PreprocessorDirective::Ifdef: + out << "#ifdef"; + break; + + default: + UNREACHABLE(); + break; + } + + if (!node->getCommand().empty()) + { + out << " " << node->getCommand(); + } + + out << "\n"; +} + +ImmutableString TOutputGLSLBase::getTypeName(const TType &type) +{ + return GetTypeName(type, mHashFunction, &mNameMap); +} + +ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol) +{ + return HashName(symbol, mHashFunction, &mNameMap); +} + +ImmutableString TOutputGLSLBase::hashFieldName(const TField *field) +{ + ASSERT(field->symbolType() != SymbolType::Empty); + if (field->symbolType() == SymbolType::UserDefined) + { + return HashName(field->name(), mHashFunction, &mNameMap); + } + + return field->name(); +} + +ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func) +{ + if (func->isMain()) + { + return func->name(); + } + else + { + return hashName(func); + } +} + +bool TOutputGLSLBase::structDeclared(const TStructure *structure) const +{ + ASSERT(structure); + if (structure->symbolType() == SymbolType::Empty) + { + return false; + } + + return (mDeclaredStructs.count(structure->uniqueId().get()) > 0); +} + +void TOutputGLSLBase::declareStruct(const TStructure *structure) +{ + TInfoSinkBase &out = objSink(); + + out << "struct "; + + if (structure->symbolType() != SymbolType::Empty) + { + out << hashName(structure) << " "; + } + out << "{\n"; + const TFieldList &fields = structure->fields(); + for (size_t i = 0; i < fields.size(); ++i) + { + const TField *field = fields[i]; + if (writeVariablePrecision(field->type()->getPrecision())) + out << " "; + out << getTypeName(*field->type()) << " " << hashFieldName(field); + if (field->type()->isArray()) + out << ArrayString(*field->type()); + out << ";\n"; + } + out << "}"; + + if (structure->symbolType() != SymbolType::Empty) + { + mDeclaredStructs.insert(structure->uniqueId().get()); + } +} + +void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock) +{ + TInfoSinkBase &out = objSink(); + + out << "layout("; + + switch (interfaceBlock->blockStorage()) + { + case EbsUnspecified: + case EbsShared: + // Default block storage is shared. + out << "shared"; + break; + + case EbsPacked: + out << "packed"; + break; + + case EbsStd140: + out << "std140"; + break; + + case EbsStd430: + out << "std430"; + break; + + default: + UNREACHABLE(); + break; + } + + if (interfaceBlock->blockBinding() >= 0) + { + out << ", "; + out << "binding = " << interfaceBlock->blockBinding(); + } + + out << ") "; +} + +void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock) +{ + TInfoSinkBase &out = objSink(); + + out << hashName(interfaceBlock) << "{\n"; + const TFieldList &fields = interfaceBlock->fields(); + for (const TField *field : fields) + { + if (field->type()->isMatrix() || field->type()->isStructureContainingMatrices()) + { + out << "layout("; + switch (field->type()->getLayoutQualifier().matrixPacking) + { + case EmpUnspecified: + case EmpColumnMajor: + // Default matrix packing is column major. + out << "column_major"; + break; + + case EmpRowMajor: + out << "row_major"; + break; + + default: + UNREACHABLE(); + break; + } + out << ") "; + } + + if (writeVariablePrecision(field->type()->getPrecision())) + out << " "; + out << getTypeName(*field->type()) << " " << hashFieldName(field); + if (field->type()->isArray()) + out << ArrayString(*field->type()); + out << ";\n"; + } + out << "}"; +} + +void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, + sh::TLayoutPrimitiveType inputPrimitive, + int invocations, + sh::TLayoutPrimitiveType outputPrimitive, + int maxVertices) +{ + // Omit 'invocations = 1' + if (inputPrimitive != EptUndefined || invocations > 1) + { + out << "layout ("; + + if (inputPrimitive != EptUndefined) + { + out << getGeometryShaderPrimitiveTypeString(inputPrimitive); + } + + if (invocations > 1) + { + if (inputPrimitive != EptUndefined) + { + out << ", "; + } + out << "invocations = " << invocations; + } + out << ") in;\n"; + } + + if (outputPrimitive != EptUndefined || maxVertices != -1) + { + out << "layout ("; + + if (outputPrimitive != EptUndefined) + { + out << getGeometryShaderPrimitiveTypeString(outputPrimitive); + } + + if (maxVertices != -1) + { + if (outputPrimitive != EptUndefined) + { + out << ", "; + } + out << "max_vertices = " << maxVertices; + } + out << ") out;\n"; + } +} + +// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever +// variables with specified layout qualifiers are copied. Additional checks are needed against the +// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted. +// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove +// NeedsToWriteLayoutQualifier. +bool NeedsToWriteLayoutQualifier(const TType &type) +{ + if (type.getBasicType() == EbtInterfaceBlock) + { + return true; + } + + const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); + + if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn || + IsVarying(type.getQualifier())) && + layoutQualifier.location >= 0) + { + return true; + } + + if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true) + { + return true; + } + + if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1) + { + return true; + } + + if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified) + { + return true; + } + return false; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.h b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.h new file mode 100644 index 0000000000..d6f9416f33 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.h @@ -0,0 +1,125 @@ +// +// Copyright (c) 2002-2013 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_OUTPUTGLSLBASE_H_ +#define COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ + +#include <set> + +#include "compiler/translator/HashNames.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +class TOutputGLSLBase : public TIntermTraverser +{ + public: + TOutputGLSLBase(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable *symbolTable, + sh::GLenum shaderType, + int shaderVersion, + ShShaderOutput output, + ShCompileOptions compileOptions); + + ShShaderOutput getShaderOutput() const { return mOutput; } + + // Return the original name if hash function pointer is NULL; + // otherwise return the hashed name. Has special handling for internal names and built-ins, + // which are not hashed. + ImmutableString hashName(const TSymbol *symbol); + + protected: + TInfoSinkBase &objSink() { return mObjSink; } + void writeFloat(TInfoSinkBase &out, float f); + void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr); + std::string getCommonLayoutQualifiers(TIntermTyped *variable); + std::string getMemoryQualifiers(const TType &type); + virtual void writeLayoutQualifier(TIntermTyped *variable); + void writeInvariantQualifier(const TType &type); + virtual void writeVariableType(const TType &type, const TSymbol *symbol); + virtual bool writeVariablePrecision(TPrecision precision) = 0; + void writeFunctionParameters(const TFunction *func); + const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion); + void writeConstructorTriplet(Visit visit, const TType &type); + ImmutableString getTypeName(const TType &type); + + void visitSymbol(TIntermSymbol *node) override; + void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; + bool visitSwitch(Visit visit, TIntermSwitch *node) override; + bool visitCase(Visit visit, TIntermCase *node) override; + void visitFunctionPrototype(TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitLoop(Visit visit, TIntermLoop *node) override; + bool visitBranch(Visit visit, TIntermBranch *node) override; + void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override; + + void visitCodeBlock(TIntermBlock *node); + + ImmutableString hashFieldName(const TField *field); + // Same as hashName(), but without hashing "main". + ImmutableString hashFunctionNameIfNeeded(const TFunction *func); + // Used to translate function names for differences between ESSL and GLSL + virtual ImmutableString translateTextureFunction(const ImmutableString &name) { return name; } + + void declareStruct(const TStructure *structure); + virtual void writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol); + bool structDeclared(const TStructure *structure) const; + + private: + void declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock); + void declareInterfaceBlock(const TInterfaceBlock *interfaceBlock); + + void writeBuiltInFunctionTriplet(Visit visit, TOperator op, bool useEmulatedFunction); + + const char *mapQualifierToString(TQualifier qualifier); + + TInfoSinkBase &mObjSink; + bool mDeclaringVariable; + + // This set contains all the ids of the structs from every scope. + std::set<int> mDeclaredStructs; + + ShArrayIndexClampingStrategy mClampingStrategy; + + // name hashing. + ShHashFunction64 mHashFunction; + + NameMap &mNameMap; + + sh::GLenum mShaderType; + + const int mShaderVersion; + + ShShaderOutput mOutput; + + ShCompileOptions mCompileOptions; +}; + +void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, + sh::TLayoutPrimitiveType inputPrimitive, + int invocations, + sh::TLayoutPrimitiveType outputPrimitive, + int maxVertices); + +bool NeedsToWriteLayoutQualifier(const TType &type); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/OutputHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.cpp new file mode 100644 index 0000000000..3ff3ffdd2a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.cpp @@ -0,0 +1,3568 @@ +// +// Copyright (c) 2002-2014 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/OutputHLSL.h" + +#include <stdio.h> +#include <algorithm> +#include <cfloat> + +#include "common/angleutils.h" +#include "common/debug.h" +#include "common/utilities.h" +#include "compiler/translator/AtomicCounterFunctionHLSL.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" +#include "compiler/translator/ImageFunctionHLSL.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/ResourcesHLSL.h" +#include "compiler/translator/StructureHLSL.h" +#include "compiler/translator/TextureFunctionHLSL.h" +#include "compiler/translator/TranslatorHLSL.h" +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/blocklayout.h" +#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h" +#include "compiler/translator/tree_util/FindSymbolNode.h" +#include "compiler/translator/tree_util/NodeSearch.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +constexpr const char kImage2DFunctionString[] = "// @@ IMAGE2D DECLARATION FUNCTION STRING @@"; + +TString ArrayHelperFunctionName(const char *prefix, const TType &type) +{ + TStringStream fnName = sh::InitializeStream<TStringStream>(); + fnName << prefix << "_"; + if (type.isArray()) + { + for (unsigned int arraySize : *type.getArraySizes()) + { + fnName << arraySize << "_"; + } + } + fnName << TypeString(type); + return fnName.str(); +} + +bool IsDeclarationWrittenOut(TIntermDeclaration *node) +{ + TIntermSequence *sequence = node->getSequence(); + TIntermTyped *variable = (*sequence)[0]->getAsTyped(); + ASSERT(sequence->size() == 1); + ASSERT(variable); + return (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal || + variable->getQualifier() == EvqConst || variable->getQualifier() == EvqShared); +} + +bool IsInStd140UniformBlock(TIntermTyped *node) +{ + TIntermBinary *binaryNode = node->getAsBinaryNode(); + + if (binaryNode) + { + return IsInStd140UniformBlock(binaryNode->getLeft()); + } + + const TType &type = node->getType(); + + if (type.getQualifier() == EvqUniform) + { + // determine if we are in the standard layout + const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); + if (interfaceBlock) + { + return (interfaceBlock->blockStorage() == EbsStd140); + } + } + + return false; +} + +const char *GetHLSLAtomicFunctionStringAndLeftParenthesis(TOperator op) +{ + switch (op) + { + case EOpAtomicAdd: + return "InterlockedAdd("; + case EOpAtomicMin: + return "InterlockedMin("; + case EOpAtomicMax: + return "InterlockedMax("; + case EOpAtomicAnd: + return "InterlockedAnd("; + case EOpAtomicOr: + return "InterlockedOr("; + case EOpAtomicXor: + return "InterlockedXor("; + case EOpAtomicExchange: + return "InterlockedExchange("; + case EOpAtomicCompSwap: + return "InterlockedCompareExchange("; + default: + UNREACHABLE(); + return ""; + } +} + +bool IsAtomicFunctionForSharedVariableDirectAssign(const TIntermBinary &node) +{ + TIntermAggregate *aggregateNode = node.getRight()->getAsAggregate(); + if (aggregateNode == nullptr) + { + return false; + } + + if (node.getOp() == EOpAssign && IsAtomicFunction(aggregateNode->getOp())) + { + return !IsInShaderStorageBlock((*aggregateNode->getSequence())[0]->getAsTyped()); + } + + return false; +} + +const char *kZeros = "_ANGLE_ZEROS_"; +constexpr int kZeroCount = 256; +std::string DefineZeroArray() +{ + std::stringstream ss = sh::InitializeStream<std::stringstream>(); + // For 'static', if the declaration does not include an initializer, the value is set to zero. + // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax + ss << "static uint " << kZeros << "[" << kZeroCount << "];\n"; + return ss.str(); +} + +std::string GetZeroInitializer(size_t size) +{ + std::stringstream ss = sh::InitializeStream<std::stringstream>(); + size_t quotient = size / kZeroCount; + size_t reminder = size % kZeroCount; + + for (size_t i = 0; i < quotient; ++i) + { + if (i != 0) + { + ss << ", "; + } + ss << kZeros; + } + + for (size_t i = 0; i < reminder; ++i) + { + if (quotient != 0 || i != 0) + { + ss << ", "; + } + ss << "0"; + } + + return ss.str(); +} + +} // anonymous namespace + +TReferencedBlock::TReferencedBlock(const TInterfaceBlock *aBlock, + const TVariable *aInstanceVariable) + : block(aBlock), instanceVariable(aInstanceVariable) +{} + +bool OutputHLSL::needStructMapping(TIntermTyped *node) +{ + ASSERT(node->getBasicType() == EbtStruct); + for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n) + { + TIntermNode *ancestor = getAncestorNode(n); + const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode(); + if (ancestorBinary) + { + switch (ancestorBinary->getOp()) + { + case EOpIndexDirectStruct: + { + const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = + ancestorBinary->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + if (field->type()->getStruct() == nullptr) + { + return false; + } + break; + } + case EOpIndexDirect: + case EOpIndexIndirect: + break; + default: + return true; + } + } + else + { + const TIntermAggregate *ancestorAggregate = ancestor->getAsAggregate(); + if (ancestorAggregate) + { + return true; + } + return false; + } + } + return true; +} + +void OutputHLSL::writeFloat(TInfoSinkBase &out, float f) +{ + // This is known not to work for NaN on all drivers but make the best effort to output NaNs + // regardless. + if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300 && + mOutputType == SH_HLSL_4_1_OUTPUT) + { + out << "asfloat(" << gl::bitCast<uint32_t>(f) << "u)"; + } + else + { + out << std::min(FLT_MAX, std::max(-FLT_MAX, f)); + } +} + +void OutputHLSL::writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion) +{ + ASSERT(constUnion != nullptr); + switch (constUnion->getType()) + { + case EbtFloat: + writeFloat(out, constUnion->getFConst()); + break; + case EbtInt: + out << constUnion->getIConst(); + break; + case EbtUInt: + out << constUnion->getUConst(); + break; + case EbtBool: + out << constUnion->getBConst(); + break; + default: + UNREACHABLE(); + } +} + +const TConstantUnion *OutputHLSL::writeConstantUnionArray(TInfoSinkBase &out, + const TConstantUnion *const constUnion, + const size_t size) +{ + const TConstantUnion *constUnionIterated = constUnion; + for (size_t i = 0; i < size; i++, constUnionIterated++) + { + writeSingleConstant(out, constUnionIterated); + + if (i != size - 1) + { + out << ", "; + } + } + return constUnionIterated; +} + +OutputHLSL::OutputHLSL(sh::GLenum shaderType, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, + ShShaderOutput outputType, + int numRenderTargets, + int maxDualSourceDrawBuffers, + const std::vector<Uniform> &uniforms, + ShCompileOptions compileOptions, + sh::WorkGroupSize workGroupSize, + TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics, + const std::vector<InterfaceBlock> &shaderStorageBlocks) + : TIntermTraverser(true, true, true, symbolTable), + mShaderType(shaderType), + mShaderVersion(shaderVersion), + mExtensionBehavior(extensionBehavior), + mSourcePath(sourcePath), + mOutputType(outputType), + mCompileOptions(compileOptions), + mInsideFunction(false), + mInsideMain(false), + mNumRenderTargets(numRenderTargets), + mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers), + mCurrentFunctionMetadata(nullptr), + mWorkGroupSize(workGroupSize), + mPerfDiagnostics(perfDiagnostics), + mNeedStructMapping(false) +{ + mUsesFragColor = false; + mUsesFragData = false; + mUsesDepthRange = false; + mUsesFragCoord = false; + mUsesPointCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesInstanceID = false; + mHasMultiviewExtensionEnabled = + IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview) || + IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2); + mUsesViewID = false; + mUsesVertexID = false; + mUsesFragDepth = false; + mUsesNumWorkGroups = false; + mUsesWorkGroupID = false; + mUsesLocalInvocationID = false; + mUsesGlobalInvocationID = false; + mUsesLocalInvocationIndex = false; + mUsesXor = false; + mUsesDiscardRewriting = false; + mUsesNestedBreak = false; + mRequiresIEEEStrictCompiling = false; + mUseZeroArray = false; + mUsesSecondaryColor = false; + + mUniqueIndex = 0; + + mOutputLod0Function = false; + mInsideDiscontinuousLoop = false; + mNestedLoopDepth = 0; + + mExcessiveLoopIndex = nullptr; + + mStructureHLSL = new StructureHLSL; + mTextureFunctionHLSL = new TextureFunctionHLSL; + mImageFunctionHLSL = new ImageFunctionHLSL; + mAtomicCounterFunctionHLSL = + new AtomicCounterFunctionHLSL((compileOptions & SH_FORCE_ATOMIC_VALUE_RESOLUTION) != 0); + + unsigned int firstUniformRegister = + ((compileOptions & SH_SKIP_D3D_CONSTANT_REGISTER_ZERO) != 0) ? 1u : 0u; + mResourcesHLSL = new ResourcesHLSL(mStructureHLSL, outputType, uniforms, firstUniformRegister); + + if (mOutputType == SH_HLSL_3_0_OUTPUT) + { + // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront. + // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and + // dx_ViewAdjust. + // In both cases total 3 uniform registers need to be reserved. + mResourcesHLSL->reserveUniformRegisters(3); + } + + // Reserve registers for the default uniform block and driver constants + mResourcesHLSL->reserveUniformBlockRegisters(2); + + mSSBOOutputHLSL = + new ShaderStorageBlockOutputHLSL(this, symbolTable, mResourcesHLSL, shaderStorageBlocks); +} + +OutputHLSL::~OutputHLSL() +{ + SafeDelete(mSSBOOutputHLSL); + SafeDelete(mStructureHLSL); + SafeDelete(mResourcesHLSL); + SafeDelete(mTextureFunctionHLSL); + SafeDelete(mImageFunctionHLSL); + SafeDelete(mAtomicCounterFunctionHLSL); + for (auto &eqFunction : mStructEqualityFunctions) + { + SafeDelete(eqFunction); + } + for (auto &eqFunction : mArrayEqualityFunctions) + { + SafeDelete(eqFunction); + } +} + +void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink) +{ + BuiltInFunctionEmulator builtInFunctionEmulator; + InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator); + if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0) + { + InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator, + mShaderVersion); + } + + builtInFunctionEmulator.markBuiltInFunctionsForEmulation(treeRoot); + + // Now that we are done changing the AST, do the analyses need for HLSL generation + CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr); + ASSERT(success == CallDAG::INITDAG_SUCCESS); + mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag); + + const std::vector<MappedStruct> std140Structs = FlagStd140Structs(treeRoot); + // TODO(oetuaho): The std140Structs could be filtered based on which ones actually get used in + // the shader code. When we add shader storage blocks we might also consider an alternative + // solution, since the struct mapping won't work very well for shader storage blocks. + + // Output the body and footer first to determine what has to go in the header + mInfoSinkStack.push(&mBody); + treeRoot->traverse(this); + mInfoSinkStack.pop(); + + mInfoSinkStack.push(&mFooter); + mInfoSinkStack.pop(); + + mInfoSinkStack.push(&mHeader); + header(mHeader, std140Structs, &builtInFunctionEmulator); + mInfoSinkStack.pop(); + + objSink << mHeader.c_str(); + objSink << mBody.c_str(); + objSink << mFooter.c_str(); + + builtInFunctionEmulator.cleanup(); +} + +const std::map<std::string, unsigned int> &OutputHLSL::getShaderStorageBlockRegisterMap() const +{ + return mResourcesHLSL->getShaderStorageBlockRegisterMap(); +} + +const std::map<std::string, unsigned int> &OutputHLSL::getUniformBlockRegisterMap() const +{ + return mResourcesHLSL->getUniformBlockRegisterMap(); +} + +const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() const +{ + return mResourcesHLSL->getUniformRegisterMap(); +} + +unsigned int OutputHLSL::getReadonlyImage2DRegisterIndex() const +{ + return mResourcesHLSL->getReadonlyImage2DRegisterIndex(); +} + +unsigned int OutputHLSL::getImage2DRegisterIndex() const +{ + return mResourcesHLSL->getImage2DRegisterIndex(); +} + +const std::set<std::string> &OutputHLSL::getUsedImage2DFunctionNames() const +{ + return mImageFunctionHLSL->getUsedImage2DFunctionNames(); +} + +TString OutputHLSL::structInitializerString(int indent, + const TType &type, + const TString &name) const +{ + TString init; + + TString indentString; + for (int spaces = 0; spaces < indent; spaces++) + { + indentString += " "; + } + + if (type.isArray()) + { + init += indentString + "{\n"; + for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex) + { + TStringStream indexedString = sh::InitializeStream<TStringStream>(); + indexedString << name << "[" << arrayIndex << "]"; + TType elementType = type; + elementType.toArrayElementType(); + init += structInitializerString(indent + 1, elementType, indexedString.str()); + if (arrayIndex < type.getOutermostArraySize() - 1) + { + init += ","; + } + init += "\n"; + } + init += indentString + "}"; + } + else if (type.getBasicType() == EbtStruct) + { + init += indentString + "{\n"; + const TStructure &structure = *type.getStruct(); + const TFieldList &fields = structure.fields(); + for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const TField &field = *fields[fieldIndex]; + const TString &fieldName = name + "." + Decorate(field.name()); + const TType &fieldType = *field.type(); + + init += structInitializerString(indent + 1, fieldType, fieldName); + if (fieldIndex < fields.size() - 1) + { + init += ","; + } + init += "\n"; + } + init += indentString + "}"; + } + else + { + init += indentString + name; + } + + return init; +} + +TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std140Structs) const +{ + TString mappedStructs; + + for (auto &mappedStruct : std140Structs) + { + const TInterfaceBlock *interfaceBlock = + mappedStruct.blockDeclarator->getType().getInterfaceBlock(); + TQualifier qualifier = mappedStruct.blockDeclarator->getType().getQualifier(); + switch (qualifier) + { + case EvqUniform: + if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0) + { + continue; + } + break; + case EvqBuffer: + continue; + default: + UNREACHABLE(); + return mappedStructs; + } + + unsigned int instanceCount = 1u; + bool isInstanceArray = mappedStruct.blockDeclarator->isArray(); + if (isInstanceArray) + { + instanceCount = mappedStruct.blockDeclarator->getOutermostArraySize(); + } + + for (unsigned int instanceArrayIndex = 0; instanceArrayIndex < instanceCount; + ++instanceArrayIndex) + { + TString originalName; + TString mappedName("map"); + + if (mappedStruct.blockDeclarator->variable().symbolType() != SymbolType::Empty) + { + const ImmutableString &instanceName = + mappedStruct.blockDeclarator->variable().name(); + unsigned int instanceStringArrayIndex = GL_INVALID_INDEX; + if (isInstanceArray) + instanceStringArrayIndex = instanceArrayIndex; + TString instanceString = mResourcesHLSL->InterfaceBlockInstanceString( + instanceName, instanceStringArrayIndex); + originalName += instanceString; + mappedName += instanceString; + originalName += "."; + mappedName += "_"; + } + + TString fieldName = Decorate(mappedStruct.field->name()); + originalName += fieldName; + mappedName += fieldName; + + TType *structType = mappedStruct.field->type(); + mappedStructs += + "static " + Decorate(structType->getStruct()->name()) + " " + mappedName; + + if (structType->isArray()) + { + mappedStructs += ArrayString(*mappedStruct.field->type()).data(); + } + + mappedStructs += " =\n"; + mappedStructs += structInitializerString(0, *structType, originalName); + mappedStructs += ";\n"; + } + } + return mappedStructs; +} + +void OutputHLSL::writeReferencedAttributes(TInfoSinkBase &out) const +{ + for (const auto &attribute : mReferencedAttributes) + { + const TType &type = attribute.second->getType(); + const ImmutableString &name = attribute.second->name(); + + out << "static " << TypeString(type) << " " << Decorate(name) << ArrayString(type) << " = " + << zeroInitializer(type) << ";\n"; + } +} + +void OutputHLSL::writeReferencedVaryings(TInfoSinkBase &out) const +{ + for (const auto &varying : mReferencedVaryings) + { + const TType &type = varying.second->getType(); + + // Program linking depends on this exact format + out << "static " << InterpolationString(type.getQualifier()) << " " << TypeString(type) + << " " << DecorateVariableIfNeeded(*varying.second) << ArrayString(type) << " = " + << zeroInitializer(type) << ";\n"; + } +} + +void OutputHLSL::header(TInfoSinkBase &out, + const std::vector<MappedStruct> &std140Structs, + const BuiltInFunctionEmulator *builtInFunctionEmulator) const +{ + TString mappedStructs; + if (mNeedStructMapping) + { + mappedStructs = generateStructMapping(std140Structs); + } + + out << mStructureHLSL->structsHeader(); + + mResourcesHLSL->uniformsHeader(out, mOutputType, mReferencedUniforms, mSymbolTable); + out << mResourcesHLSL->uniformBlocksHeader(mReferencedUniformBlocks); + mSSBOOutputHLSL->writeShaderStorageBlocksHeader(out); + + if (!mEqualityFunctions.empty()) + { + out << "\n// Equality functions\n\n"; + for (const auto &eqFunction : mEqualityFunctions) + { + out << eqFunction->functionDefinition << "\n"; + } + } + if (!mArrayAssignmentFunctions.empty()) + { + out << "\n// Assignment functions\n\n"; + for (const auto &assignmentFunction : mArrayAssignmentFunctions) + { + out << assignmentFunction.functionDefinition << "\n"; + } + } + if (!mArrayConstructIntoFunctions.empty()) + { + out << "\n// Array constructor functions\n\n"; + for (const auto &constructIntoFunction : mArrayConstructIntoFunctions) + { + out << constructIntoFunction.functionDefinition << "\n"; + } + } + + if (mUsesDiscardRewriting) + { + out << "#define ANGLE_USES_DISCARD_REWRITING\n"; + } + + if (mUsesNestedBreak) + { + out << "#define ANGLE_USES_NESTED_BREAK\n"; + } + + if (mRequiresIEEEStrictCompiling) + { + out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n"; + } + + out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n" + "#define LOOP [loop]\n" + "#define FLATTEN [flatten]\n" + "#else\n" + "#define LOOP\n" + "#define FLATTEN\n" + "#endif\n"; + + // array stride for atomic counter buffers is always 4 per original extension + // ARB_shader_atomic_counters and discussion on + // https://github.com/KhronosGroup/OpenGL-API/issues/5 + out << "\n#define ATOMIC_COUNTER_ARRAY_STRIDE 4\n\n"; + + if (mUseZeroArray) + { + out << DefineZeroArray() << "\n"; + } + + if (mShaderType == GL_FRAGMENT_SHADER) + { + const bool usingMRTExtension = + IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers); + const bool usingBFEExtension = + IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_blend_func_extended); + + out << "// Varyings\n"; + writeReferencedVaryings(out); + out << "\n"; + + if (mShaderVersion >= 300) + { + for (const auto &outputVariable : mReferencedOutputVariables) + { + const ImmutableString &variableName = outputVariable.second->name(); + const TType &variableType = outputVariable.second->getType(); + + out << "static " << TypeString(variableType) << " out_" << variableName + << ArrayString(variableType) << " = " << zeroInitializer(variableType) << ";\n"; + } + } + else + { + const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1; + + out << "static float4 gl_Color[" << numColorValues + << "] =\n" + "{\n"; + for (unsigned int i = 0; i < numColorValues; i++) + { + out << " float4(0, 0, 0, 0)"; + if (i + 1 != numColorValues) + { + out << ","; + } + out << "\n"; + } + + out << "};\n"; + + if (usingBFEExtension && mUsesSecondaryColor) + { + out << "static float4 gl_SecondaryColor[" << mMaxDualSourceDrawBuffers + << "] = \n" + "{\n"; + for (int i = 0; i < mMaxDualSourceDrawBuffers; i++) + { + out << " float4(0, 0, 0, 0)"; + if (i + 1 != mMaxDualSourceDrawBuffers) + { + out << ","; + } + out << "\n"; + } + out << "};\n"; + } + } + + if (mUsesFragDepth) + { + out << "static float gl_Depth = 0.0;\n"; + } + + if (mUsesFragCoord) + { + out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"; + } + + if (mUsesPointCoord) + { + out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n"; + } + + if (mUsesFrontFacing) + { + out << "static bool gl_FrontFacing = false;\n"; + } + + out << "\n"; + + if (mUsesDepthRange) + { + out << "struct gl_DepthRangeParameters\n" + "{\n" + " float near;\n" + " float far;\n" + " float diff;\n" + "};\n" + "\n"; + } + + if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + out << "cbuffer DriverConstants : register(b1)\n" + "{\n"; + + if (mUsesDepthRange) + { + out << " float3 dx_DepthRange : packoffset(c0);\n"; + } + + if (mUsesFragCoord) + { + out << " float4 dx_ViewCoords : packoffset(c1);\n"; + } + + if (mUsesFragCoord || mUsesFrontFacing) + { + out << " float3 dx_DepthFront : packoffset(c2);\n"; + } + + if (mUsesFragCoord) + { + // dx_ViewScale is only used in the fragment shader to correct + // the value for glFragCoord if necessary + out << " float2 dx_ViewScale : packoffset(c3);\n"; + } + + if (mHasMultiviewExtensionEnabled) + { + // We have to add a value which we can use to keep track of which multi-view code + // path is to be selected in the GS. + out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n"; + } + + if (mOutputType == SH_HLSL_4_1_OUTPUT) + { + mResourcesHLSL->samplerMetadataUniforms(out, 4); + } + + out << "};\n"; + } + else + { + if (mUsesDepthRange) + { + out << "uniform float3 dx_DepthRange : register(c0);"; + } + + if (mUsesFragCoord) + { + out << "uniform float4 dx_ViewCoords : register(c1);\n"; + } + + if (mUsesFragCoord || mUsesFrontFacing) + { + out << "uniform float3 dx_DepthFront : register(c2);\n"; + } + } + + out << "\n"; + + if (mUsesDepthRange) + { + out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, " + "dx_DepthRange.y, dx_DepthRange.z};\n" + "\n"; + } + + if (usingMRTExtension && mNumRenderTargets > 1) + { + out << "#define GL_USES_MRT\n"; + } + + if (mUsesFragColor) + { + out << "#define GL_USES_FRAG_COLOR\n"; + } + + if (mUsesFragData) + { + out << "#define GL_USES_FRAG_DATA\n"; + } + + if (mShaderVersion < 300 && usingBFEExtension && mUsesSecondaryColor) + { + out << "#define GL_USES_SECONDARY_COLOR\n"; + } + } + else if (mShaderType == GL_VERTEX_SHADER) + { + out << "// Attributes\n"; + writeReferencedAttributes(out); + out << "\n" + "static float4 gl_Position = float4(0, 0, 0, 0);\n"; + + if (mUsesPointSize) + { + out << "static float gl_PointSize = float(1);\n"; + } + + if (mUsesInstanceID) + { + out << "static int gl_InstanceID;"; + } + + if (mUsesVertexID) + { + out << "static int gl_VertexID;"; + } + + out << "\n" + "// Varyings\n"; + writeReferencedVaryings(out); + out << "\n"; + + if (mUsesDepthRange) + { + out << "struct gl_DepthRangeParameters\n" + "{\n" + " float near;\n" + " float far;\n" + " float diff;\n" + "};\n" + "\n"; + } + + if (mOutputType == SH_HLSL_4_1_OUTPUT || mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + out << "cbuffer DriverConstants : register(b1)\n" + "{\n"; + + if (mUsesDepthRange) + { + out << " float3 dx_DepthRange : packoffset(c0);\n"; + } + + // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9 + // shaders. However, we declare it for all shaders (including Feature Level 10+). + // The bytecode is the same whether we declare it or not, since D3DCompiler removes it + // if it's unused. + out << " float4 dx_ViewAdjust : packoffset(c1);\n"; + out << " float2 dx_ViewCoords : packoffset(c2);\n"; + out << " float2 dx_ViewScale : packoffset(c3);\n"; + + if (mHasMultiviewExtensionEnabled) + { + // We have to add a value which we can use to keep track of which multi-view code + // path is to be selected in the GS. + out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n"; + } + + if (mOutputType == SH_HLSL_4_1_OUTPUT) + { + mResourcesHLSL->samplerMetadataUniforms(out, 4); + } + + if (mUsesVertexID) + { + out << " uint dx_VertexID : packoffset(c3.w);\n"; + } + + out << "};\n" + "\n"; + } + else + { + if (mUsesDepthRange) + { + out << "uniform float3 dx_DepthRange : register(c0);\n"; + } + + out << "uniform float4 dx_ViewAdjust : register(c1);\n"; + out << "uniform float2 dx_ViewCoords : register(c2);\n" + "\n"; + } + + if (mUsesDepthRange) + { + out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, " + "dx_DepthRange.y, dx_DepthRange.z};\n" + "\n"; + } + } + else // Compute shader + { + ASSERT(mShaderType == GL_COMPUTE_SHADER); + + out << "cbuffer DriverConstants : register(b1)\n" + "{\n"; + if (mUsesNumWorkGroups) + { + out << " uint3 gl_NumWorkGroups : packoffset(c0);\n"; + } + ASSERT(mOutputType == SH_HLSL_4_1_OUTPUT); + unsigned int registerIndex = 1; + mResourcesHLSL->samplerMetadataUniforms(out, registerIndex); + // Sampler metadata struct must be two 4-vec, 32 bytes. + registerIndex += mResourcesHLSL->getSamplerCount() * 2; + mResourcesHLSL->imageMetadataUniforms(out, registerIndex); + out << "};\n"; + + out << kImage2DFunctionString << "\n"; + + std::ostringstream systemValueDeclaration = sh::InitializeStream<std::ostringstream>(); + std::ostringstream glBuiltinInitialization = sh::InitializeStream<std::ostringstream>(); + + systemValueDeclaration << "\nstruct CS_INPUT\n{\n"; + glBuiltinInitialization << "\nvoid initGLBuiltins(CS_INPUT input)\n" + << "{\n"; + + if (mUsesWorkGroupID) + { + out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n"; + systemValueDeclaration << " uint3 dx_WorkGroupID : " + << "SV_GroupID;\n"; + glBuiltinInitialization << " gl_WorkGroupID = input.dx_WorkGroupID;\n"; + } + + if (mUsesLocalInvocationID) + { + out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n"; + systemValueDeclaration << " uint3 dx_LocalInvocationID : " + << "SV_GroupThreadID;\n"; + glBuiltinInitialization << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n"; + } + + if (mUsesGlobalInvocationID) + { + out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n"; + systemValueDeclaration << " uint3 dx_GlobalInvocationID : " + << "SV_DispatchThreadID;\n"; + glBuiltinInitialization << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n"; + } + + if (mUsesLocalInvocationIndex) + { + out << "static uint gl_LocalInvocationIndex = uint(0);\n"; + systemValueDeclaration << " uint dx_LocalInvocationIndex : " + << "SV_GroupIndex;\n"; + glBuiltinInitialization + << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n"; + } + + systemValueDeclaration << "};\n\n"; + glBuiltinInitialization << "};\n\n"; + + out << systemValueDeclaration.str(); + out << glBuiltinInitialization.str(); + } + + if (!mappedStructs.empty()) + { + out << "// Structures from std140 blocks with padding removed\n"; + out << "\n"; + out << mappedStructs; + out << "\n"; + } + + bool getDimensionsIgnoresBaseLevel = + (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0; + mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel); + mImageFunctionHLSL->imageFunctionHeader(out); + mAtomicCounterFunctionHLSL->atomicCounterFunctionHeader(out); + + if (mUsesFragCoord) + { + out << "#define GL_USES_FRAG_COORD\n"; + } + + if (mUsesPointCoord) + { + out << "#define GL_USES_POINT_COORD\n"; + } + + if (mUsesFrontFacing) + { + out << "#define GL_USES_FRONT_FACING\n"; + } + + if (mUsesPointSize) + { + out << "#define GL_USES_POINT_SIZE\n"; + } + + if (mHasMultiviewExtensionEnabled) + { + out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n"; + } + + if (mUsesVertexID) + { + out << "#define GL_USES_VERTEX_ID\n"; + } + + if (mUsesViewID) + { + out << "#define GL_USES_VIEW_ID\n"; + } + + if (mUsesFragDepth) + { + out << "#define GL_USES_FRAG_DEPTH\n"; + } + + if (mUsesDepthRange) + { + out << "#define GL_USES_DEPTH_RANGE\n"; + } + + if (mUsesXor) + { + out << "bool xor(bool p, bool q)\n" + "{\n" + " return (p || q) && !(p && q);\n" + "}\n" + "\n"; + } + + builtInFunctionEmulator->outputEmulatedFunctions(out); +} + +void OutputHLSL::visitSymbol(TIntermSymbol *node) +{ + const TVariable &variable = node->variable(); + + // Empty symbols can only appear in declarations and function arguments, and in either of those + // cases the symbol nodes are not visited. + ASSERT(variable.symbolType() != SymbolType::Empty); + + TInfoSinkBase &out = getInfoSink(); + + // Handle accessing std140 structs by value + if (IsInStd140UniformBlock(node) && node->getBasicType() == EbtStruct && + needStructMapping(node)) + { + mNeedStructMapping = true; + out << "map"; + } + + const ImmutableString &name = variable.name(); + const TSymbolUniqueId &uniqueId = variable.uniqueId(); + + if (name == "gl_DepthRange") + { + mUsesDepthRange = true; + out << name; + } + else if (IsAtomicCounter(variable.getType().getBasicType())) + { + const TType &variableType = variable.getType(); + if (variableType.getQualifier() == EvqUniform) + { + TLayoutQualifier layout = variableType.getLayoutQualifier(); + mReferencedUniforms[uniqueId.get()] = &variable; + out << getAtomicCounterNameForBinding(layout.binding) << ", " << layout.offset; + } + else + { + TString varName = DecorateVariableIfNeeded(variable); + out << varName << ", " << varName << "_offset"; + } + } + else + { + const TType &variableType = variable.getType(); + TQualifier qualifier = variable.getType().getQualifier(); + + ensureStructDefined(variableType); + + if (qualifier == EvqUniform) + { + const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock(); + + if (interfaceBlock) + { + if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0) + { + const TVariable *instanceVariable = nullptr; + if (variableType.isInterfaceBlock()) + { + instanceVariable = &variable; + } + mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] = + new TReferencedBlock(interfaceBlock, instanceVariable); + } + } + else + { + mReferencedUniforms[uniqueId.get()] = &variable; + } + + out << DecorateVariableIfNeeded(variable); + } + else if (qualifier == EvqBuffer) + { + UNREACHABLE(); + } + else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) + { + mReferencedAttributes[uniqueId.get()] = &variable; + out << Decorate(name); + } + else if (IsVarying(qualifier)) + { + mReferencedVaryings[uniqueId.get()] = &variable; + out << DecorateVariableIfNeeded(variable); + if (variable.symbolType() == SymbolType::AngleInternal && name == "ViewID_OVR") + { + mUsesViewID = true; + } + } + else if (qualifier == EvqFragmentOut) + { + mReferencedOutputVariables[uniqueId.get()] = &variable; + out << "out_" << name; + } + else if (qualifier == EvqFragColor) + { + out << "gl_Color[0]"; + mUsesFragColor = true; + } + else if (qualifier == EvqFragData) + { + out << "gl_Color"; + mUsesFragData = true; + } + else if (qualifier == EvqSecondaryFragColorEXT) + { + out << "gl_SecondaryColor[0]"; + mUsesSecondaryColor = true; + } + else if (qualifier == EvqSecondaryFragDataEXT) + { + out << "gl_SecondaryColor"; + mUsesSecondaryColor = true; + } + else if (qualifier == EvqFragCoord) + { + mUsesFragCoord = true; + out << name; + } + else if (qualifier == EvqPointCoord) + { + mUsesPointCoord = true; + out << name; + } + else if (qualifier == EvqFrontFacing) + { + mUsesFrontFacing = true; + out << name; + } + else if (qualifier == EvqPointSize) + { + mUsesPointSize = true; + out << name; + } + else if (qualifier == EvqInstanceID) + { + mUsesInstanceID = true; + out << name; + } + else if (qualifier == EvqVertexID) + { + mUsesVertexID = true; + out << name; + } + else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth") + { + mUsesFragDepth = true; + out << "gl_Depth"; + } + else if (qualifier == EvqNumWorkGroups) + { + mUsesNumWorkGroups = true; + out << name; + } + else if (qualifier == EvqWorkGroupID) + { + mUsesWorkGroupID = true; + out << name; + } + else if (qualifier == EvqLocalInvocationID) + { + mUsesLocalInvocationID = true; + out << name; + } + else if (qualifier == EvqGlobalInvocationID) + { + mUsesGlobalInvocationID = true; + out << name; + } + else if (qualifier == EvqLocalInvocationIndex) + { + mUsesLocalInvocationIndex = true; + out << name; + } + else + { + out << DecorateVariableIfNeeded(variable); + } + } +} + +void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out) +{ + if (type.isScalar() && !type.isArray()) + { + if (op == EOpEqual) + { + outputTriplet(out, visit, "(", " == ", ")"); + } + else + { + outputTriplet(out, visit, "(", " != ", ")"); + } + } + else + { + if (visit == PreVisit && op == EOpNotEqual) + { + out << "!"; + } + + if (type.isArray()) + { + const TString &functionName = addArrayEqualityFunction(type); + outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")"); + } + else if (type.getBasicType() == EbtStruct) + { + const TStructure &structure = *type.getStruct(); + const TString &functionName = addStructEqualityFunction(structure); + outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")"); + } + else + { + ASSERT(type.isMatrix() || type.isVector()); + outputTriplet(out, visit, "all(", " == ", ")"); + } + } +} + +void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out) +{ + if (type.isArray()) + { + const TString &functionName = addArrayAssignmentFunction(type); + outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")"); + } + else + { + outputTriplet(out, visit, "(", " = ", ")"); + } +} + +bool OutputHLSL::ancestorEvaluatesToSamplerInStruct() +{ + for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n) + { + TIntermNode *ancestor = getAncestorNode(n); + const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode(); + if (ancestorBinary == nullptr) + { + return false; + } + switch (ancestorBinary->getOp()) + { + case EOpIndexDirectStruct: + { + const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = + ancestorBinary->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + if (IsSampler(field->type()->getBasicType())) + { + return true; + } + break; + } + case EOpIndexDirect: + break; + default: + // Returning a sampler from indirect indexing is not supported. + return false; + } + } + return false; +} + +bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + TInfoSinkBase &out = getInfoSink(); + if (visit == PostVisit) + { + out << "."; + node->writeOffsetsAsXYZW(&out); + } + return true; +} + +bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = getInfoSink(); + + switch (node->getOp()) + { + case EOpComma: + outputTriplet(out, visit, "(", ", ", ")"); + break; + case EOpAssign: + if (node->isArray()) + { + TIntermAggregate *rightAgg = node->getRight()->getAsAggregate(); + if (rightAgg != nullptr && rightAgg->isConstructor()) + { + const TString &functionName = addArrayConstructIntoFunction(node->getType()); + out << functionName << "("; + node->getLeft()->traverse(this); + TIntermSequence *seq = rightAgg->getSequence(); + for (auto &arrayElement : *seq) + { + out << ", "; + arrayElement->traverse(this); + } + out << ")"; + return false; + } + // ArrayReturnValueToOutParameter should have eliminated expressions where a + // function call is assigned. + ASSERT(rightAgg == nullptr); + } + // Assignment expressions with atomic functions should be transformed into atomic + // function calls in HLSL. + // e.g. original_value = atomicAdd(dest, value) should be translated into + // InterlockedAdd(dest, value, original_value); + else if (IsAtomicFunctionForSharedVariableDirectAssign(*node)) + { + TIntermAggregate *atomicFunctionNode = node->getRight()->getAsAggregate(); + TOperator atomicFunctionOp = atomicFunctionNode->getOp(); + out << GetHLSLAtomicFunctionStringAndLeftParenthesis(atomicFunctionOp); + TIntermSequence *argumentSeq = atomicFunctionNode->getSequence(); + ASSERT(argumentSeq->size() >= 2u); + for (auto &argument : *argumentSeq) + { + argument->traverse(this); + out << ", "; + } + node->getLeft()->traverse(this); + out << ")"; + return false; + } + else if (IsInShaderStorageBlock(node->getLeft())) + { + mSSBOOutputHLSL->outputStoreFunctionCallPrefix(node->getLeft()); + out << ", "; + if (IsInShaderStorageBlock(node->getRight())) + { + mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight()); + } + else + { + node->getRight()->traverse(this); + } + + out << ")"; + return false; + } + else if (IsInShaderStorageBlock(node->getRight())) + { + node->getLeft()->traverse(this); + out << " = "; + mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight()); + return false; + } + + outputAssign(visit, node->getType(), out); + break; + case EOpInitialize: + if (visit == PreVisit) + { + TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); + ASSERT(symbolNode); + TIntermTyped *initializer = node->getRight(); + + // Global initializers must be constant at this point. + ASSERT(symbolNode->getQualifier() != EvqGlobal || initializer->hasConstantValue()); + + // GLSL allows to write things like "float x = x;" where a new variable x is defined + // and the value of an existing variable x is assigned. HLSL uses C semantics (the + // new variable is created before the assignment is evaluated), so we need to + // convert + // this to "float t = x, x = t;". + if (writeSameSymbolInitializer(out, symbolNode, initializer)) + { + // Skip initializing the rest of the expression + return false; + } + else if (writeConstantInitialization(out, symbolNode, initializer)) + { + return false; + } + } + else if (visit == InVisit) + { + out << " = "; + if (IsInShaderStorageBlock(node->getRight())) + { + mSSBOOutputHLSL->outputLoadFunctionCall(node->getRight()); + return false; + } + } + break; + case EOpAddAssign: + outputTriplet(out, visit, "(", " += ", ")"); + break; + case EOpSubAssign: + outputTriplet(out, visit, "(", " -= ", ")"); + break; + case EOpMulAssign: + outputTriplet(out, visit, "(", " *= ", ")"); + break; + case EOpVectorTimesScalarAssign: + outputTriplet(out, visit, "(", " *= ", ")"); + break; + case EOpMatrixTimesScalarAssign: + outputTriplet(out, visit, "(", " *= ", ")"); + break; + case EOpVectorTimesMatrixAssign: + if (visit == PreVisit) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = mul("; + node->getLeft()->traverse(this); + out << ", transpose("; + } + else + { + out << ")))"; + } + break; + case EOpMatrixTimesMatrixAssign: + if (visit == PreVisit) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = transpose(mul(transpose("; + node->getLeft()->traverse(this); + out << "), transpose("; + } + else + { + out << "))))"; + } + break; + case EOpDivAssign: + outputTriplet(out, visit, "(", " /= ", ")"); + break; + case EOpIModAssign: + outputTriplet(out, visit, "(", " %= ", ")"); + break; + case EOpBitShiftLeftAssign: + outputTriplet(out, visit, "(", " <<= ", ")"); + break; + case EOpBitShiftRightAssign: + outputTriplet(out, visit, "(", " >>= ", ")"); + break; + case EOpBitwiseAndAssign: + outputTriplet(out, visit, "(", " &= ", ")"); + break; + case EOpBitwiseXorAssign: + outputTriplet(out, visit, "(", " ^= ", ")"); + break; + case EOpBitwiseOrAssign: + outputTriplet(out, visit, "(", " |= ", ")"); + break; + case EOpIndexDirect: + { + const TType &leftType = node->getLeft()->getType(); + if (leftType.isInterfaceBlock()) + { + if (visit == PreVisit) + { + TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode(); + const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock(); + + ASSERT(leftType.getQualifier() == EvqUniform); + if (mReferencedUniformBlocks.count(interfaceBlock->uniqueId().get()) == 0) + { + mReferencedUniformBlocks[interfaceBlock->uniqueId().get()] = + new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable()); + } + const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0); + out << mResourcesHLSL->InterfaceBlockInstanceString( + instanceArraySymbol->getName(), arrayIndex); + return false; + } + } + else if (ancestorEvaluatesToSamplerInStruct()) + { + // All parts of an expression that access a sampler in a struct need to use _ as + // separator to access the sampler variable that has been moved out of the struct. + outputTriplet(out, visit, "", "_", ""); + } + else if (IsAtomicCounter(leftType.getBasicType())) + { + outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE"); + } + else + { + outputTriplet(out, visit, "", "[", "]"); + } + } + break; + case EOpIndexIndirect: + { + // We do not currently support indirect references to interface blocks + ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock); + + const TType &leftType = node->getLeft()->getType(); + if (IsAtomicCounter(leftType.getBasicType())) + { + outputTriplet(out, visit, "", " + (", ") * ATOMIC_COUNTER_ARRAY_STRIDE"); + } + else + { + outputTriplet(out, visit, "", "[", "]"); + } + break; + } + case EOpIndexDirectStruct: + { + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + + // In cases where indexing returns a sampler, we need to access the sampler variable + // that has been moved out of the struct. + bool indexingReturnsSampler = IsSampler(field->type()->getBasicType()); + if (visit == PreVisit && indexingReturnsSampler) + { + // Samplers extracted from structs have "angle" prefix to avoid name conflicts. + // This prefix is only output at the beginning of the indexing expression, which + // may have multiple parts. + out << "angle"; + } + if (!indexingReturnsSampler) + { + // All parts of an expression that access a sampler in a struct need to use _ as + // separator to access the sampler variable that has been moved out of the struct. + indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct(); + } + if (visit == InVisit) + { + if (indexingReturnsSampler) + { + out << "_" << field->name(); + } + else + { + out << "." << DecorateField(field->name(), *structure); + } + + return false; + } + } + break; + case EOpIndexDirectInterfaceBlock: + { + ASSERT(!IsInShaderStorageBlock(node->getLeft())); + bool structInStd140UniformBlock = node->getBasicType() == EbtStruct && + IsInStd140UniformBlock(node->getLeft()) && + needStructMapping(node); + if (visit == PreVisit && structInStd140UniformBlock) + { + mNeedStructMapping = true; + out << "map"; + } + if (visit == InVisit) + { + const TInterfaceBlock *interfaceBlock = + node->getLeft()->getType().getInterfaceBlock(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = interfaceBlock->fields()[index->getIConst(0)]; + if (structInStd140UniformBlock) + { + out << "_"; + } + else + { + out << "."; + } + out << Decorate(field->name()); + + return false; + } + break; + } + case EOpAdd: + outputTriplet(out, visit, "(", " + ", ")"); + break; + case EOpSub: + outputTriplet(out, visit, "(", " - ", ")"); + break; + case EOpMul: + outputTriplet(out, visit, "(", " * ", ")"); + break; + case EOpDiv: + outputTriplet(out, visit, "(", " / ", ")"); + break; + case EOpIMod: + outputTriplet(out, visit, "(", " % ", ")"); + break; + case EOpBitShiftLeft: + outputTriplet(out, visit, "(", " << ", ")"); + break; + case EOpBitShiftRight: + outputTriplet(out, visit, "(", " >> ", ")"); + break; + case EOpBitwiseAnd: + outputTriplet(out, visit, "(", " & ", ")"); + break; + case EOpBitwiseXor: + outputTriplet(out, visit, "(", " ^ ", ")"); + break; + case EOpBitwiseOr: + outputTriplet(out, visit, "(", " | ", ")"); + break; + case EOpEqual: + case EOpNotEqual: + outputEqual(visit, node->getLeft()->getType(), node->getOp(), out); + break; + case EOpLessThan: + outputTriplet(out, visit, "(", " < ", ")"); + break; + case EOpGreaterThan: + outputTriplet(out, visit, "(", " > ", ")"); + break; + case EOpLessThanEqual: + outputTriplet(out, visit, "(", " <= ", ")"); + break; + case EOpGreaterThanEqual: + outputTriplet(out, visit, "(", " >= ", ")"); + break; + case EOpVectorTimesScalar: + outputTriplet(out, visit, "(", " * ", ")"); + break; + case EOpMatrixTimesScalar: + outputTriplet(out, visit, "(", " * ", ")"); + break; + case EOpVectorTimesMatrix: + outputTriplet(out, visit, "mul(", ", transpose(", "))"); + break; + case EOpMatrixTimesVector: + outputTriplet(out, visit, "mul(transpose(", "), ", ")"); + break; + case EOpMatrixTimesMatrix: + outputTriplet(out, visit, "transpose(mul(transpose(", "), transpose(", ")))"); + break; + case EOpLogicalOr: + // HLSL doesn't short-circuit ||, so we assume that || affected by short-circuiting have + // been unfolded. + ASSERT(!node->getRight()->hasSideEffects()); + outputTriplet(out, visit, "(", " || ", ")"); + return true; + case EOpLogicalXor: + mUsesXor = true; + outputTriplet(out, visit, "xor(", ", ", ")"); + break; + case EOpLogicalAnd: + // HLSL doesn't short-circuit &&, so we assume that && affected by short-circuiting have + // been unfolded. + ASSERT(!node->getRight()->hasSideEffects()); + outputTriplet(out, visit, "(", " && ", ")"); + return true; + default: + UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) +{ + TInfoSinkBase &out = getInfoSink(); + + switch (node->getOp()) + { + case EOpNegative: + outputTriplet(out, visit, "(-", "", ")"); + break; + case EOpPositive: + outputTriplet(out, visit, "(+", "", ")"); + break; + case EOpLogicalNot: + outputTriplet(out, visit, "(!", "", ")"); + break; + case EOpBitwiseNot: + outputTriplet(out, visit, "(~", "", ")"); + break; + case EOpPostIncrement: + outputTriplet(out, visit, "(", "", "++)"); + break; + case EOpPostDecrement: + outputTriplet(out, visit, "(", "", "--)"); + break; + case EOpPreIncrement: + outputTriplet(out, visit, "(++", "", ")"); + break; + case EOpPreDecrement: + outputTriplet(out, visit, "(--", "", ")"); + break; + case EOpRadians: + outputTriplet(out, visit, "radians(", "", ")"); + break; + case EOpDegrees: + outputTriplet(out, visit, "degrees(", "", ")"); + break; + case EOpSin: + outputTriplet(out, visit, "sin(", "", ")"); + break; + case EOpCos: + outputTriplet(out, visit, "cos(", "", ")"); + break; + case EOpTan: + outputTriplet(out, visit, "tan(", "", ")"); + break; + case EOpAsin: + outputTriplet(out, visit, "asin(", "", ")"); + break; + case EOpAcos: + outputTriplet(out, visit, "acos(", "", ")"); + break; + case EOpAtan: + outputTriplet(out, visit, "atan(", "", ")"); + break; + case EOpSinh: + outputTriplet(out, visit, "sinh(", "", ")"); + break; + case EOpCosh: + outputTriplet(out, visit, "cosh(", "", ")"); + break; + case EOpTanh: + case EOpAsinh: + case EOpAcosh: + case EOpAtanh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpExp: + outputTriplet(out, visit, "exp(", "", ")"); + break; + case EOpLog: + outputTriplet(out, visit, "log(", "", ")"); + break; + case EOpExp2: + outputTriplet(out, visit, "exp2(", "", ")"); + break; + case EOpLog2: + outputTriplet(out, visit, "log2(", "", ")"); + break; + case EOpSqrt: + outputTriplet(out, visit, "sqrt(", "", ")"); + break; + case EOpInversesqrt: + outputTriplet(out, visit, "rsqrt(", "", ")"); + break; + case EOpAbs: + outputTriplet(out, visit, "abs(", "", ")"); + break; + case EOpSign: + outputTriplet(out, visit, "sign(", "", ")"); + break; + case EOpFloor: + outputTriplet(out, visit, "floor(", "", ")"); + break; + case EOpTrunc: + outputTriplet(out, visit, "trunc(", "", ")"); + break; + case EOpRound: + outputTriplet(out, visit, "round(", "", ")"); + break; + case EOpRoundEven: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpCeil: + outputTriplet(out, visit, "ceil(", "", ")"); + break; + case EOpFract: + outputTriplet(out, visit, "frac(", "", ")"); + break; + case EOpIsnan: + if (node->getUseEmulatedFunction()) + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + else + outputTriplet(out, visit, "isnan(", "", ")"); + mRequiresIEEEStrictCompiling = true; + break; + case EOpIsinf: + outputTriplet(out, visit, "isinf(", "", ")"); + break; + case EOpFloatBitsToInt: + outputTriplet(out, visit, "asint(", "", ")"); + break; + case EOpFloatBitsToUint: + outputTriplet(out, visit, "asuint(", "", ")"); + break; + case EOpIntBitsToFloat: + outputTriplet(out, visit, "asfloat(", "", ")"); + break; + case EOpUintBitsToFloat: + outputTriplet(out, visit, "asfloat(", "", ")"); + break; + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + case EOpUnpackHalf2x16: + case EOpPackUnorm4x8: + case EOpPackSnorm4x8: + case EOpUnpackUnorm4x8: + case EOpUnpackSnorm4x8: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpLength: + outputTriplet(out, visit, "length(", "", ")"); + break; + case EOpNormalize: + outputTriplet(out, visit, "normalize(", "", ")"); + break; + case EOpDFdx: + if (mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(out, visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(out, visit, "ddx(", "", ")"); + } + break; + case EOpDFdy: + if (mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(out, visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(out, visit, "ddy(", "", ")"); + } + break; + case EOpFwidth: + if (mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(out, visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(out, visit, "fwidth(", "", ")"); + } + break; + case EOpTranspose: + outputTriplet(out, visit, "transpose(", "", ")"); + break; + case EOpDeterminant: + outputTriplet(out, visit, "determinant(transpose(", "", "))"); + break; + case EOpInverse: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + + case EOpAny: + outputTriplet(out, visit, "any(", "", ")"); + break; + case EOpAll: + outputTriplet(out, visit, "all(", "", ")"); + break; + case EOpLogicalNotComponentWise: + outputTriplet(out, visit, "(!", "", ")"); + break; + case EOpBitfieldReverse: + outputTriplet(out, visit, "reversebits(", "", ")"); + break; + case EOpBitCount: + outputTriplet(out, visit, "countbits(", "", ")"); + break; + case EOpFindLSB: + // Note that it's unclear from the HLSL docs what this returns for 0, but this is tested + // in GLSLTest and results are consistent with GL. + outputTriplet(out, visit, "firstbitlow(", "", ")"); + break; + case EOpFindMSB: + // Note that it's unclear from the HLSL docs what this returns for 0 or -1, but this is + // tested in GLSLTest and results are consistent with GL. + outputTriplet(out, visit, "firstbithigh(", "", ")"); + break; + case EOpArrayLength: + { + TIntermTyped *operand = node->getOperand(); + ASSERT(IsInShaderStorageBlock(operand)); + mSSBOOutputHLSL->outputLengthFunctionCall(operand); + return false; + } + default: + UNREACHABLE(); + } + + return true; +} + +ImmutableString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node) +{ + if (node->getAsSymbolNode()) + { + ASSERT(node->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty); + return node->getAsSymbolNode()->getName(); + } + TIntermBinary *nodeBinary = node->getAsBinaryNode(); + switch (nodeBinary->getOp()) + { + case EOpIndexDirect: + { + int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0); + + std::stringstream prefixSink = sh::InitializeStream<std::stringstream>(); + prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index; + return ImmutableString(prefixSink.str()); + } + case EOpIndexDirectStruct: + { + const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct(); + int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0); + const TField *field = s->fields()[index]; + + std::stringstream prefixSink = sh::InitializeStream<std::stringstream>(); + prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" + << field->name(); + return ImmutableString(prefixSink.str()); + } + default: + UNREACHABLE(); + return kEmptyImmutableString; + } +} + +bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node) +{ + TInfoSinkBase &out = getInfoSink(); + + bool isMainBlock = mInsideMain && getParentNode()->getAsFunctionDefinition(); + + if (mInsideFunction) + { + outputLineDirective(out, node->getLine().first_line); + out << "{\n"; + if (isMainBlock) + { + if (mShaderType == GL_COMPUTE_SHADER) + { + out << "initGLBuiltins(input);\n"; + } + else + { + out << "@@ MAIN PROLOGUE @@\n"; + } + } + } + + for (TIntermNode *statement : *node->getSequence()) + { + outputLineDirective(out, statement->getLine().first_line); + + statement->traverse(this); + + // Don't output ; after case labels, they're terminated by : + // This is needed especially since outputting a ; after a case statement would turn empty + // case statements into non-empty case statements, disallowing fall-through from them. + // Also the output code is clearer if we don't output ; after statements where it is not + // needed: + // * if statements + // * switch statements + // * blocks + // * function definitions + // * loops (do-while loops output the semicolon in VisitLoop) + // * declarations that don't generate output. + if (statement->getAsCaseNode() == nullptr && statement->getAsIfElseNode() == nullptr && + statement->getAsBlock() == nullptr && statement->getAsLoopNode() == nullptr && + statement->getAsSwitchNode() == nullptr && + statement->getAsFunctionDefinition() == nullptr && + (statement->getAsDeclarationNode() == nullptr || + IsDeclarationWrittenOut(statement->getAsDeclarationNode())) && + statement->getAsInvariantDeclarationNode() == nullptr) + { + out << ";\n"; + } + } + + if (mInsideFunction) + { + outputLineDirective(out, node->getLine().last_line); + if (isMainBlock && shaderNeedsGenerateOutput()) + { + // We could have an empty main, a main function without a branch at the end, or a main + // function with a discard statement at the end. In these cases we need to add a return + // statement. + bool needReturnStatement = + node->getSequence()->empty() || !node->getSequence()->back()->getAsBranchNode() || + node->getSequence()->back()->getAsBranchNode()->getFlowOp() != EOpReturn; + if (needReturnStatement) + { + out << "return " << generateOutputCall() << ";\n"; + } + } + out << "}\n"; + } + + return false; +} + +bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + TInfoSinkBase &out = getInfoSink(); + + ASSERT(mCurrentFunctionMetadata == nullptr); + + size_t index = mCallDag.findIndex(node->getFunction()->uniqueId()); + ASSERT(index != CallDAG::InvalidIndex); + mCurrentFunctionMetadata = &mASTMetadataList[index]; + + const TFunction *func = node->getFunction(); + + if (func->isMain()) + { + // The stub strings below are replaced when shader is dynamically defined by its layout: + switch (mShaderType) + { + case GL_VERTEX_SHADER: + out << "@@ VERTEX ATTRIBUTES @@\n\n" + << "@@ VERTEX OUTPUT @@\n\n" + << "VS_OUTPUT main(VS_INPUT input)"; + break; + case GL_FRAGMENT_SHADER: + out << "@@ PIXEL OUTPUT @@\n\n" + << "PS_OUTPUT main(@@ PIXEL MAIN PARAMETERS @@)"; + break; + case GL_COMPUTE_SHADER: + out << "[numthreads(" << mWorkGroupSize[0] << ", " << mWorkGroupSize[1] << ", " + << mWorkGroupSize[2] << ")]\n"; + out << "void main(CS_INPUT input)"; + break; + default: + UNREACHABLE(); + break; + } + } + else + { + out << TypeString(node->getFunctionPrototype()->getType()) << " "; + out << DecorateFunctionIfNeeded(func) << DisambiguateFunctionName(func) + << (mOutputLod0Function ? "Lod0(" : "("); + + size_t paramCount = func->getParamCount(); + for (unsigned int i = 0; i < paramCount; i++) + { + const TVariable *param = func->getParam(i); + ensureStructDefined(param->getType()); + + writeParameter(param, out); + + if (i < paramCount - 1) + { + out << ", "; + } + } + + out << ")\n"; + } + + mInsideFunction = true; + if (func->isMain()) + { + mInsideMain = true; + } + // The function body node will output braces. + node->getBody()->traverse(this); + mInsideFunction = false; + mInsideMain = false; + + mCurrentFunctionMetadata = nullptr; + + bool needsLod0 = mASTMetadataList[index].mNeedsLod0; + if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER) + { + ASSERT(!node->getFunction()->isMain()); + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } + + return false; +} + +bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + if (visit == PreVisit) + { + TIntermSequence *sequence = node->getSequence(); + TIntermTyped *declarator = (*sequence)[0]->getAsTyped(); + ASSERT(sequence->size() == 1); + ASSERT(declarator); + + if (IsDeclarationWrittenOut(node)) + { + TInfoSinkBase &out = getInfoSink(); + ensureStructDefined(declarator->getType()); + + if (!declarator->getAsSymbolNode() || + declarator->getAsSymbolNode()->variable().symbolType() != + SymbolType::Empty) // Variable declaration + { + if (declarator->getQualifier() == EvqShared) + { + out << "groupshared "; + } + else if (!mInsideFunction) + { + out << "static "; + } + + out << TypeString(declarator->getType()) + " "; + + TIntermSymbol *symbol = declarator->getAsSymbolNode(); + + if (symbol) + { + symbol->traverse(this); + out << ArrayString(symbol->getType()); + // Temporarily disable shadred memory initialization. It is very slow for D3D11 + // drivers to compile a compute shader if we add code to initialize a + // groupshared array variable with a large array size. And maybe produce + // incorrect result. See http://anglebug.com/3226. + if (declarator->getQualifier() != EvqShared) + { + out << " = " + zeroInitializer(symbol->getType()); + } + } + else + { + declarator->traverse(this); + } + } + } + else if (IsVaryingOut(declarator->getQualifier())) + { + TIntermSymbol *symbol = declarator->getAsSymbolNode(); + ASSERT(symbol); // Varying declarations can't have initializers. + + const TVariable &variable = symbol->variable(); + + if (variable.symbolType() != SymbolType::Empty) + { + // Vertex outputs which are declared but not written to should still be declared to + // allow successful linking. + mReferencedVaryings[symbol->uniqueId().get()] = &variable; + } + } + } + return false; +} + +bool OutputHLSL::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + // Do not do any translation + return false; +} + +void OutputHLSL::visitFunctionPrototype(TIntermFunctionPrototype *node) +{ + TInfoSinkBase &out = getInfoSink(); + + size_t index = mCallDag.findIndex(node->getFunction()->uniqueId()); + // Skip the prototype if it is not implemented (and thus not used) + if (index == CallDAG::InvalidIndex) + { + return; + } + + const TFunction *func = node->getFunction(); + + TString name = DecorateFunctionIfNeeded(func); + out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(func) + << (mOutputLod0Function ? "Lod0(" : "("); + + size_t paramCount = func->getParamCount(); + for (unsigned int i = 0; i < paramCount; i++) + { + writeParameter(func->getParam(i), out); + + if (i < paramCount - 1) + { + out << ", "; + } + } + + out << ");\n"; + + // Also prototype the Lod0 variant if needed + bool needsLod0 = mASTMetadataList[index].mNeedsLod0; + if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER) + { + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } +} + +bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) +{ + TInfoSinkBase &out = getInfoSink(); + + switch (node->getOp()) + { + case EOpCallBuiltInFunction: + case EOpCallFunctionInAST: + case EOpCallInternalRawFunction: + { + TIntermSequence *arguments = node->getSequence(); + + bool lod0 = (mInsideDiscontinuousLoop || mOutputLod0Function) && + mShaderType == GL_FRAGMENT_SHADER; + if (node->getOp() == EOpCallFunctionInAST) + { + if (node->isArray()) + { + UNIMPLEMENTED(); + } + size_t index = mCallDag.findIndex(node->getFunction()->uniqueId()); + ASSERT(index != CallDAG::InvalidIndex); + lod0 &= mASTMetadataList[index].mNeedsLod0; + + out << DecorateFunctionIfNeeded(node->getFunction()); + out << DisambiguateFunctionName(node->getSequence()); + out << (lod0 ? "Lod0(" : "("); + } + else if (node->getOp() == EOpCallInternalRawFunction) + { + // This path is used for internal functions that don't have their definitions in the + // AST, such as precision emulation functions. + out << DecorateFunctionIfNeeded(node->getFunction()) << "("; + } + else if (node->getFunction()->isImageFunction()) + { + const ImmutableString &name = node->getFunction()->name(); + TType type = (*arguments)[0]->getAsTyped()->getType(); + const ImmutableString &imageFunctionName = mImageFunctionHLSL->useImageFunction( + name, type.getBasicType(), type.getLayoutQualifier().imageInternalFormat, + type.getMemoryQualifier().readonly); + out << imageFunctionName << "("; + } + else if (node->getFunction()->isAtomicCounterFunction()) + { + const ImmutableString &name = node->getFunction()->name(); + ImmutableString atomicFunctionName = + mAtomicCounterFunctionHLSL->useAtomicCounterFunction(name); + out << atomicFunctionName << "("; + } + else + { + const ImmutableString &name = node->getFunction()->name(); + TBasicType samplerType = (*arguments)[0]->getAsTyped()->getType().getBasicType(); + int coords = 0; // textureSize(gsampler2DMS) doesn't have a second argument. + if (arguments->size() > 1) + { + coords = (*arguments)[1]->getAsTyped()->getNominalSize(); + } + const ImmutableString &textureFunctionName = + mTextureFunctionHLSL->useTextureFunction(name, samplerType, coords, + arguments->size(), lod0, mShaderType); + out << textureFunctionName << "("; + } + + for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++) + { + TIntermTyped *typedArg = (*arg)->getAsTyped(); + if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType())) + { + out << "texture_"; + (*arg)->traverse(this); + out << ", sampler_"; + } + + (*arg)->traverse(this); + + if (typedArg->getType().isStructureContainingSamplers()) + { + const TType &argType = typedArg->getType(); + TVector<const TVariable *> samplerSymbols; + ImmutableString structName = samplerNamePrefixFromStruct(typedArg); + std::string namePrefix = "angle_"; + namePrefix += structName.data(); + argType.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, + nullptr, mSymbolTable); + for (const TVariable *sampler : samplerSymbols) + { + if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + out << ", texture_" << sampler->name(); + out << ", sampler_" << sampler->name(); + } + else + { + // In case of HLSL 4.1+, this symbol is the sampler index, and in case + // of D3D9, it's the sampler variable. + out << ", " << sampler->name(); + } + } + } + + if (arg < arguments->end() - 1) + { + out << ", "; + } + } + + out << ")"; + + return false; + } + case EOpConstruct: + outputConstructor(out, visit, node); + break; + case EOpEqualComponentWise: + outputTriplet(out, visit, "(", " == ", ")"); + break; + case EOpNotEqualComponentWise: + outputTriplet(out, visit, "(", " != ", ")"); + break; + case EOpLessThanComponentWise: + outputTriplet(out, visit, "(", " < ", ")"); + break; + case EOpGreaterThanComponentWise: + outputTriplet(out, visit, "(", " > ", ")"); + break; + case EOpLessThanEqualComponentWise: + outputTriplet(out, visit, "(", " <= ", ")"); + break; + case EOpGreaterThanEqualComponentWise: + outputTriplet(out, visit, "(", " >= ", ")"); + break; + case EOpMod: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpModf: + outputTriplet(out, visit, "modf(", ", ", ")"); + break; + case EOpPow: + outputTriplet(out, visit, "pow(", ", ", ")"); + break; + case EOpAtan: + ASSERT(node->getSequence()->size() == 2); // atan(x) is a unary operator + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpMin: + outputTriplet(out, visit, "min(", ", ", ")"); + break; + case EOpMax: + outputTriplet(out, visit, "max(", ", ", ")"); + break; + case EOpClamp: + outputTriplet(out, visit, "clamp(", ", ", ")"); + break; + case EOpMix: + { + TIntermTyped *lastParamNode = (*(node->getSequence()))[2]->getAsTyped(); + if (lastParamNode->getType().getBasicType() == EbtBool) + { + // There is no HLSL equivalent for ESSL3 built-in "genType mix (genType x, genType + // y, genBType a)", + // so use emulated version. + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + } + else + { + outputTriplet(out, visit, "lerp(", ", ", ")"); + } + break; + } + case EOpStep: + outputTriplet(out, visit, "step(", ", ", ")"); + break; + case EOpSmoothstep: + outputTriplet(out, visit, "smoothstep(", ", ", ")"); + break; + case EOpFrexp: + case EOpLdexp: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpDistance: + outputTriplet(out, visit, "distance(", ", ", ")"); + break; + case EOpDot: + outputTriplet(out, visit, "dot(", ", ", ")"); + break; + case EOpCross: + outputTriplet(out, visit, "cross(", ", ", ")"); + break; + case EOpFaceforward: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpReflect: + outputTriplet(out, visit, "reflect(", ", ", ")"); + break; + case EOpRefract: + outputTriplet(out, visit, "refract(", ", ", ")"); + break; + case EOpOuterProduct: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpMulMatrixComponentWise: + outputTriplet(out, visit, "(", " * ", ")"); + break; + case EOpBitfieldExtract: + case EOpBitfieldInsert: + case EOpUaddCarry: + case EOpUsubBorrow: + case EOpUmulExtended: + case EOpImulExtended: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(out, visit, node->getOp()); + break; + case EOpBarrier: + // barrier() is translated to GroupMemoryBarrierWithGroupSync(), which is the + // cheapest *WithGroupSync() function, without any functionality loss, but + // with the potential for severe performance loss. + outputTriplet(out, visit, "GroupMemoryBarrierWithGroupSync(", "", ")"); + break; + case EOpMemoryBarrierShared: + outputTriplet(out, visit, "GroupMemoryBarrier(", "", ")"); + break; + case EOpMemoryBarrierAtomicCounter: + case EOpMemoryBarrierBuffer: + case EOpMemoryBarrierImage: + outputTriplet(out, visit, "DeviceMemoryBarrier(", "", ")"); + break; + case EOpGroupMemoryBarrier: + case EOpMemoryBarrier: + outputTriplet(out, visit, "AllMemoryBarrier(", "", ")"); + break; + + // Single atomic function calls without return value. + // e.g. atomicAdd(dest, value) should be translated into InterlockedAdd(dest, value). + case EOpAtomicAdd: + case EOpAtomicMin: + case EOpAtomicMax: + case EOpAtomicAnd: + case EOpAtomicOr: + case EOpAtomicXor: + // The parameter 'original_value' of InterlockedExchange(dest, value, original_value) + // and InterlockedCompareExchange(dest, compare_value, value, original_value) is not + // optional. + // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedexchange + // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/interlockedcompareexchange + // So all the call of atomicExchange(dest, value) and atomicCompSwap(dest, + // compare_value, value) should all be modified into the form of "int temp; temp = + // atomicExchange(dest, value);" and "int temp; temp = atomicCompSwap(dest, + // compare_value, value);" in the intermediate tree before traversing outputHLSL. + case EOpAtomicExchange: + case EOpAtomicCompSwap: + { + ASSERT(node->getChildCount() > 1); + TIntermTyped *memNode = (*node->getSequence())[0]->getAsTyped(); + if (IsInShaderStorageBlock(memNode)) + { + // Atomic memory functions for SSBO. + // "_ssbo_atomicXXX_TYPE(RWByteAddressBuffer buffer, uint loc" is written to |out|. + mSSBOOutputHLSL->outputAtomicMemoryFunctionCallPrefix(memNode, node->getOp()); + // Write the rest argument list to |out|. + for (size_t i = 1; i < node->getChildCount(); i++) + { + out << ", "; + TIntermTyped *argument = (*node->getSequence())[i]->getAsTyped(); + if (IsInShaderStorageBlock(argument)) + { + mSSBOOutputHLSL->outputLoadFunctionCall(argument); + } + else + { + argument->traverse(this); + } + } + + out << ")"; + return false; + } + else + { + // Atomic memory functions for shared variable. + if (node->getOp() != EOpAtomicExchange && node->getOp() != EOpAtomicCompSwap) + { + outputTriplet(out, visit, + GetHLSLAtomicFunctionStringAndLeftParenthesis(node->getOp()), ",", + ")"); + } + else + { + UNREACHABLE(); + } + } + + break; + } + default: + UNREACHABLE(); + } + + return true; +} + +void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node) +{ + out << "if ("; + + node->getCondition()->traverse(this); + + out << ")\n"; + + outputLineDirective(out, node->getLine().first_line); + + bool discard = false; + + if (node->getTrueBlock()) + { + // The trueBlock child node will output braces. + node->getTrueBlock()->traverse(this); + + // Detect true discard + discard = (discard || FindDiscard::search(node->getTrueBlock())); + } + else + { + // TODO(oetuaho): Check if the semicolon inside is necessary. + // It's there as a result of conservative refactoring of the output. + out << "{;}\n"; + } + + outputLineDirective(out, node->getLine().first_line); + + if (node->getFalseBlock()) + { + out << "else\n"; + + outputLineDirective(out, node->getFalseBlock()->getLine().first_line); + + // The falseBlock child node will output braces. + node->getFalseBlock()->traverse(this); + + outputLineDirective(out, node->getFalseBlock()->getLine().first_line); + + // Detect false discard + discard = (discard || FindDiscard::search(node->getFalseBlock())); + } + + // ANGLE issue 486: Detect problematic conditional discard + if (discard) + { + mUsesDiscardRewriting = true; + } +} + +bool OutputHLSL::visitTernary(Visit, TIntermTernary *) +{ + // Ternary ops should have been already converted to something else in the AST. HLSL ternary + // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator. + UNREACHABLE(); + return false; +} + +bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node) +{ + TInfoSinkBase &out = getInfoSink(); + + ASSERT(mInsideFunction); + + // D3D errors when there is a gradient operation in a loop in an unflattened if. + if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node)) + { + out << "FLATTEN "; + } + + writeIfElse(out, node); + + return false; +} + +bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node) +{ + TInfoSinkBase &out = getInfoSink(); + + ASSERT(node->getStatementList()); + if (visit == PreVisit) + { + node->setStatementList(RemoveSwitchFallThrough(node->getStatementList(), mPerfDiagnostics)); + } + outputTriplet(out, visit, "switch (", ") ", ""); + // The curly braces get written when visiting the statementList block. + return true; +} + +bool OutputHLSL::visitCase(Visit visit, TIntermCase *node) +{ + TInfoSinkBase &out = getInfoSink(); + + if (node->hasCondition()) + { + outputTriplet(out, visit, "case (", "", "):\n"); + return true; + } + else + { + out << "default:\n"; + return false; + } +} + +void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) +{ + TInfoSinkBase &out = getInfoSink(); + writeConstantUnion(out, node->getType(), node->getConstantValue()); +} + +bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) +{ + mNestedLoopDepth++; + + bool wasDiscontinuous = mInsideDiscontinuousLoop; + mInsideDiscontinuousLoop = + mInsideDiscontinuousLoop || mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) > 0; + + TInfoSinkBase &out = getInfoSink(); + + if (mOutputType == SH_HLSL_3_0_OUTPUT) + { + if (handleExcessiveLoop(out, node)) + { + mInsideDiscontinuousLoop = wasDiscontinuous; + mNestedLoopDepth--; + + return false; + } + } + + const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : ""; + if (node->getType() == ELoopDoWhile) + { + out << "{" << unroll << " do\n"; + + outputLineDirective(out, node->getLine().first_line); + } + else + { + out << "{" << unroll << " for("; + + if (node->getInit()) + { + node->getInit()->traverse(this); + } + + out << "; "; + + if (node->getCondition()) + { + node->getCondition()->traverse(this); + } + + out << "; "; + + if (node->getExpression()) + { + node->getExpression()->traverse(this); + } + + out << ")\n"; + + outputLineDirective(out, node->getLine().first_line); + } + + if (node->getBody()) + { + // The loop body node will output braces. + node->getBody()->traverse(this); + } + else + { + // TODO(oetuaho): Check if the semicolon inside is necessary. + // It's there as a result of conservative refactoring of the output. + out << "{;}\n"; + } + + outputLineDirective(out, node->getLine().first_line); + + if (node->getType() == ELoopDoWhile) + { + outputLineDirective(out, node->getCondition()->getLine().first_line); + out << "while ("; + + node->getCondition()->traverse(this); + + out << ");\n"; + } + + out << "}\n"; + + mInsideDiscontinuousLoop = wasDiscontinuous; + mNestedLoopDepth--; + + return false; +} + +bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) +{ + if (visit == PreVisit) + { + TInfoSinkBase &out = getInfoSink(); + + switch (node->getFlowOp()) + { + case EOpKill: + out << "discard"; + break; + case EOpBreak: + if (mNestedLoopDepth > 1) + { + mUsesNestedBreak = true; + } + + if (mExcessiveLoopIndex) + { + out << "{Break"; + mExcessiveLoopIndex->traverse(this); + out << " = true; break;}\n"; + } + else + { + out << "break"; + } + break; + case EOpContinue: + out << "continue"; + break; + case EOpReturn: + if (node->getExpression()) + { + ASSERT(!mInsideMain); + out << "return "; + } + else + { + if (mInsideMain && shaderNeedsGenerateOutput()) + { + out << "return " << generateOutputCall(); + } + else + { + out << "return"; + } + } + break; + default: + UNREACHABLE(); + } + } + + return true; +} + +// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them +// (The D3D documentation says 255 iterations, but the compiler complains at anything more than +// 254). +bool OutputHLSL::handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node) +{ + const int MAX_LOOP_ITERATIONS = 254; + + // Parse loops of the form: + // for(int index = initial; index [comparator] limit; index += increment) + TIntermSymbol *index = nullptr; + TOperator comparator = EOpNull; + int initial = 0; + int limit = 0; + int increment = 0; + + // Parse index name and intial value + if (node->getInit()) + { + TIntermDeclaration *init = node->getInit()->getAsDeclarationNode(); + + if (init) + { + TIntermSequence *sequence = init->getSequence(); + TIntermTyped *variable = (*sequence)[0]->getAsTyped(); + + if (variable && variable->getQualifier() == EvqTemporary) + { + TIntermBinary *assign = variable->getAsBinaryNode(); + + if (assign->getOp() == EOpInitialize) + { + TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode(); + TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion(); + + if (symbol && constant) + { + if (constant->getBasicType() == EbtInt && constant->isScalar()) + { + index = symbol; + initial = constant->getIConst(0); + } + } + } + } + } + } + + // Parse comparator and limit value + if (index != nullptr && node->getCondition()) + { + TIntermBinary *test = node->getCondition()->getAsBinaryNode(); + + if (test && test->getLeft()->getAsSymbolNode()->uniqueId() == index->uniqueId()) + { + TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion(); + + if (constant) + { + if (constant->getBasicType() == EbtInt && constant->isScalar()) + { + comparator = test->getOp(); + limit = constant->getIConst(0); + } + } + } + } + + // Parse increment + if (index != nullptr && comparator != EOpNull && node->getExpression()) + { + TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode(); + TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode(); + + if (binaryTerminal) + { + TOperator op = binaryTerminal->getOp(); + TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion(); + + if (constant) + { + if (constant->getBasicType() == EbtInt && constant->isScalar()) + { + int value = constant->getIConst(0); + + switch (op) + { + case EOpAddAssign: + increment = value; + break; + case EOpSubAssign: + increment = -value; + break; + default: + UNIMPLEMENTED(); + } + } + } + } + else if (unaryTerminal) + { + TOperator op = unaryTerminal->getOp(); + + switch (op) + { + case EOpPostIncrement: + increment = 1; + break; + case EOpPostDecrement: + increment = -1; + break; + case EOpPreIncrement: + increment = 1; + break; + case EOpPreDecrement: + increment = -1; + break; + default: + UNIMPLEMENTED(); + } + } + } + + if (index != nullptr && comparator != EOpNull && increment != 0) + { + if (comparator == EOpLessThanEqual) + { + comparator = EOpLessThan; + limit += 1; + } + + if (comparator == EOpLessThan) + { + int iterations = (limit - initial) / increment; + + if (iterations <= MAX_LOOP_ITERATIONS) + { + return false; // Not an excessive loop + } + + TIntermSymbol *restoreIndex = mExcessiveLoopIndex; + mExcessiveLoopIndex = index; + + out << "{int "; + index->traverse(this); + out << ";\n" + "bool Break"; + index->traverse(this); + out << " = false;\n"; + + bool firstLoopFragment = true; + + while (iterations > 0) + { + int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations); + + if (!firstLoopFragment) + { + out << "if (!Break"; + index->traverse(this); + out << ") {\n"; + } + + if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment + { + mExcessiveLoopIndex = nullptr; // Stops setting the Break flag + } + + // for(int index = initial; index < clampedLimit; index += increment) + const char *unroll = + mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : ""; + + out << unroll << " for("; + index->traverse(this); + out << " = "; + out << initial; + + out << "; "; + index->traverse(this); + out << " < "; + out << clampedLimit; + + out << "; "; + index->traverse(this); + out << " += "; + out << increment; + out << ")\n"; + + outputLineDirective(out, node->getLine().first_line); + out << "{\n"; + + if (node->getBody()) + { + node->getBody()->traverse(this); + } + + outputLineDirective(out, node->getLine().first_line); + out << ";}\n"; + + if (!firstLoopFragment) + { + out << "}\n"; + } + + firstLoopFragment = false; + + initial += MAX_LOOP_ITERATIONS * increment; + iterations -= MAX_LOOP_ITERATIONS; + } + + out << "}"; + + mExcessiveLoopIndex = restoreIndex; + + return true; + } + else + UNIMPLEMENTED(); + } + + return false; // Not handled as an excessive loop +} + +void OutputHLSL::outputTriplet(TInfoSinkBase &out, + Visit visit, + const char *preString, + const char *inString, + const char *postString) +{ + if (visit == PreVisit) + { + out << preString; + } + else if (visit == InVisit) + { + out << inString; + } + else if (visit == PostVisit) + { + out << postString; + } +} + +void OutputHLSL::outputLineDirective(TInfoSinkBase &out, int line) +{ + if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0)) + { + out << "\n"; + out << "#line " << line; + + if (mSourcePath) + { + out << " \"" << mSourcePath << "\""; + } + + out << "\n"; + } +} + +void OutputHLSL::writeParameter(const TVariable *param, TInfoSinkBase &out) +{ + const TType &type = param->getType(); + TQualifier qualifier = type.getQualifier(); + + TString nameStr = DecorateVariableIfNeeded(*param); + ASSERT(nameStr != ""); // HLSL demands named arguments, also for prototypes + + if (IsSampler(type.getBasicType())) + { + if (mOutputType == SH_HLSL_4_1_OUTPUT) + { + // Samplers are passed as indices to the sampler array. + ASSERT(qualifier != EvqOut && qualifier != EvqInOut); + out << "const uint " << nameStr << ArrayString(type); + return; + } + if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + out << QualifierString(qualifier) << " " << TextureString(type.getBasicType()) + << " texture_" << nameStr << ArrayString(type) << ", " << QualifierString(qualifier) + << " " << SamplerString(type.getBasicType()) << " sampler_" << nameStr + << ArrayString(type); + return; + } + } + + // If the parameter is an atomic counter, we need to add an extra parameter to keep track of the + // buffer offset. + if (IsAtomicCounter(type.getBasicType())) + { + out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr << ", int " + << nameStr << "_offset"; + } + else + { + out << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr + << ArrayString(type); + } + + // If the structure parameter contains samplers, they need to be passed into the function as + // separate parameters. HLSL doesn't natively support samplers in structs. + if (type.isStructureContainingSamplers()) + { + ASSERT(qualifier != EvqOut && qualifier != EvqInOut); + TVector<const TVariable *> samplerSymbols; + std::string namePrefix = "angle"; + namePrefix += nameStr.c_str(); + type.createSamplerSymbols(ImmutableString(namePrefix), "", &samplerSymbols, nullptr, + mSymbolTable); + for (const TVariable *sampler : samplerSymbols) + { + const TType &samplerType = sampler->getType(); + if (mOutputType == SH_HLSL_4_1_OUTPUT) + { + out << ", const uint " << sampler->name() << ArrayString(samplerType); + } + else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + ASSERT(IsSampler(samplerType.getBasicType())); + out << ", " << QualifierString(qualifier) << " " + << TextureString(samplerType.getBasicType()) << " texture_" << sampler->name() + << ArrayString(samplerType) << ", " << QualifierString(qualifier) << " " + << SamplerString(samplerType.getBasicType()) << " sampler_" << sampler->name() + << ArrayString(samplerType); + } + else + { + ASSERT(IsSampler(samplerType.getBasicType())); + out << ", " << QualifierString(qualifier) << " " << TypeString(samplerType) << " " + << sampler->name() << ArrayString(samplerType); + } + } + } +} + +TString OutputHLSL::zeroInitializer(const TType &type) const +{ + TString string; + + size_t size = type.getObjectSize(); + if (size >= kZeroCount) + { + mUseZeroArray = true; + } + string = GetZeroInitializer(size).c_str(); + + return "{" + string + "}"; +} + +void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node) +{ + // Array constructors should have been already pruned from the code. + ASSERT(!node->getType().isArray()); + + if (visit == PreVisit) + { + TString constructorName; + if (node->getBasicType() == EbtStruct) + { + constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct()); + } + else + { + constructorName = + mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence()); + } + out << constructorName << "("; + } + else if (visit == InVisit) + { + out << ", "; + } + else if (visit == PostVisit) + { + out << ")"; + } +} + +const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out, + const TType &type, + const TConstantUnion *const constUnion) +{ + ASSERT(!type.isArray()); + + const TConstantUnion *constUnionIterated = constUnion; + + const TStructure *structure = type.getStruct(); + if (structure) + { + out << mStructureHLSL->addStructConstructor(*structure) << "("; + + const TFieldList &fields = structure->fields(); + + for (size_t i = 0; i < fields.size(); i++) + { + const TType *fieldType = fields[i]->type(); + constUnionIterated = writeConstantUnion(out, *fieldType, constUnionIterated); + + if (i != fields.size() - 1) + { + out << ", "; + } + } + + out << ")"; + } + else + { + size_t size = type.getObjectSize(); + bool writeType = size > 1; + + if (writeType) + { + out << TypeString(type) << "("; + } + constUnionIterated = writeConstantUnionArray(out, constUnionIterated, size); + if (writeType) + { + out << ")"; + } + } + + return constUnionIterated; +} + +void OutputHLSL::writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op) +{ + if (visit == PreVisit) + { + const char *opStr = GetOperatorString(op); + BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr); + out << "("; + } + else + { + outputTriplet(out, visit, nullptr, ", ", ")"); + } +} + +bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, + TIntermSymbol *symbolNode, + TIntermTyped *expression) +{ + ASSERT(symbolNode->variable().symbolType() != SymbolType::Empty); + const TIntermSymbol *symbolInInitializer = FindSymbolNode(expression, symbolNode->getName()); + + if (symbolInInitializer) + { + // Type already printed + out << "t" + str(mUniqueIndex) + " = "; + expression->traverse(this); + out << ", "; + symbolNode->traverse(this); + out << " = t" + str(mUniqueIndex); + + mUniqueIndex++; + return true; + } + + return false; +} + +bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out, + TIntermSymbol *symbolNode, + TIntermTyped *initializer) +{ + if (initializer->hasConstantValue()) + { + symbolNode->traverse(this); + out << ArrayString(symbolNode->getType()); + out << " = {"; + writeConstantUnionArray(out, initializer->getConstantValue(), + initializer->getType().getObjectSize()); + out << "}"; + return true; + } + return false; +} + +TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) +{ + const TFieldList &fields = structure.fields(); + + for (const auto &eqFunction : mStructEqualityFunctions) + { + if (eqFunction->structure == &structure) + { + return eqFunction->functionName; + } + } + + const TString &structNameString = StructNameString(structure); + + StructEqualityFunction *function = new StructEqualityFunction(); + function->structure = &structure; + function->functionName = "angle_eq_" + structNameString; + + TInfoSinkBase fnOut; + + fnOut << "bool " << function->functionName << "(" << structNameString << " a, " + << structNameString + " b)\n" + << "{\n" + " return "; + + for (size_t i = 0; i < fields.size(); i++) + { + const TField *field = fields[i]; + const TType *fieldType = field->type(); + + const TString &fieldNameA = "a." + Decorate(field->name()); + const TString &fieldNameB = "b." + Decorate(field->name()); + + if (i > 0) + { + fnOut << " && "; + } + + fnOut << "("; + outputEqual(PreVisit, *fieldType, EOpEqual, fnOut); + fnOut << fieldNameA; + outputEqual(InVisit, *fieldType, EOpEqual, fnOut); + fnOut << fieldNameB; + outputEqual(PostVisit, *fieldType, EOpEqual, fnOut); + fnOut << ")"; + } + + fnOut << ";\n" + << "}\n"; + + function->functionDefinition = fnOut.c_str(); + + mStructEqualityFunctions.push_back(function); + mEqualityFunctions.push_back(function); + + return function->functionName; +} + +TString OutputHLSL::addArrayEqualityFunction(const TType &type) +{ + for (const auto &eqFunction : mArrayEqualityFunctions) + { + if (eqFunction->type == type) + { + return eqFunction->functionName; + } + } + + TType elementType(type); + elementType.toArrayElementType(); + + ArrayHelperFunction *function = new ArrayHelperFunction(); + function->type = type; + + function->functionName = ArrayHelperFunctionName("angle_eq", type); + + TInfoSinkBase fnOut; + + const TString &typeName = TypeString(type); + fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type) + << ", " << typeName << " b" << ArrayString(type) << ")\n" + << "{\n" + " for (int i = 0; i < " + << type.getOutermostArraySize() + << "; ++i)\n" + " {\n" + " if ("; + + outputEqual(PreVisit, elementType, EOpNotEqual, fnOut); + fnOut << "a[i]"; + outputEqual(InVisit, elementType, EOpNotEqual, fnOut); + fnOut << "b[i]"; + outputEqual(PostVisit, elementType, EOpNotEqual, fnOut); + + fnOut << ") { return false; }\n" + " }\n" + " return true;\n" + "}\n"; + + function->functionDefinition = fnOut.c_str(); + + mArrayEqualityFunctions.push_back(function); + mEqualityFunctions.push_back(function); + + return function->functionName; +} + +TString OutputHLSL::addArrayAssignmentFunction(const TType &type) +{ + for (const auto &assignFunction : mArrayAssignmentFunctions) + { + if (assignFunction.type == type) + { + return assignFunction.functionName; + } + } + + TType elementType(type); + elementType.toArrayElementType(); + + ArrayHelperFunction function; + function.type = type; + + function.functionName = ArrayHelperFunctionName("angle_assign", type); + + TInfoSinkBase fnOut; + + const TString &typeName = TypeString(type); + fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type) + << ", " << typeName << " b" << ArrayString(type) << ")\n" + << "{\n" + " for (int i = 0; i < " + << type.getOutermostArraySize() + << "; ++i)\n" + " {\n" + " "; + + outputAssign(PreVisit, elementType, fnOut); + fnOut << "a[i]"; + outputAssign(InVisit, elementType, fnOut); + fnOut << "b[i]"; + outputAssign(PostVisit, elementType, fnOut); + + fnOut << ";\n" + " }\n" + "}\n"; + + function.functionDefinition = fnOut.c_str(); + + mArrayAssignmentFunctions.push_back(function); + + return function.functionName; +} + +TString OutputHLSL::addArrayConstructIntoFunction(const TType &type) +{ + for (const auto &constructIntoFunction : mArrayConstructIntoFunctions) + { + if (constructIntoFunction.type == type) + { + return constructIntoFunction.functionName; + } + } + + TType elementType(type); + elementType.toArrayElementType(); + + ArrayHelperFunction function; + function.type = type; + + function.functionName = ArrayHelperFunctionName("angle_construct_into", type); + + TInfoSinkBase fnOut; + + const TString &typeName = TypeString(type); + fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type); + for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i) + { + fnOut << ", " << typeName << " b" << i << ArrayString(elementType); + } + fnOut << ")\n" + "{\n"; + + for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i) + { + fnOut << " "; + outputAssign(PreVisit, elementType, fnOut); + fnOut << "a[" << i << "]"; + outputAssign(InVisit, elementType, fnOut); + fnOut << "b" << i; + outputAssign(PostVisit, elementType, fnOut); + fnOut << ";\n"; + } + fnOut << "}\n"; + + function.functionDefinition = fnOut.c_str(); + + mArrayConstructIntoFunctions.push_back(function); + + return function.functionName; +} + +void OutputHLSL::ensureStructDefined(const TType &type) +{ + const TStructure *structure = type.getStruct(); + if (structure) + { + ASSERT(type.getBasicType() == EbtStruct); + mStructureHLSL->ensureStructDefined(*structure); + } +} + +bool OutputHLSL::shaderNeedsGenerateOutput() const +{ + return mShaderType == GL_VERTEX_SHADER || mShaderType == GL_FRAGMENT_SHADER; +} + +const char *OutputHLSL::generateOutputCall() const +{ + if (mShaderType == GL_VERTEX_SHADER) + { + return "generateOutput(input)"; + } + else + { + return "generateOutput()"; + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/OutputHLSL.h b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.h new file mode 100644 index 0000000000..7aaa303e5d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputHLSL.h @@ -0,0 +1,279 @@ +// +// Copyright (c) 2002-2014 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_OUTPUTHLSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTHLSL_H_ + +#include <list> +#include <map> +#include <stack> + +#include "angle_gl.h" +#include "compiler/translator/ASTMetadataHLSL.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/FlagStd140Structs.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/ShaderStorageBlockOutputHLSL.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +class BuiltInFunctionEmulator; + +namespace sh +{ +class AtomicCounterFunctionHLSL; +class ImageFunctionHLSL; +class ResourcesHLSL; +class StructureHLSL; +class TextureFunctionHLSL; +class TSymbolTable; +class TVariable; +class UnfoldShortCircuit; + +using ReferencedVariables = std::map<int, const TVariable *>; + +class OutputHLSL : public TIntermTraverser +{ + public: + OutputHLSL(sh::GLenum shaderType, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, + ShShaderOutput outputType, + int numRenderTargets, + int maxDualSourceDrawBuffers, + const std::vector<Uniform> &uniforms, + ShCompileOptions compileOptions, + sh::WorkGroupSize workGroupSize, + TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics, + const std::vector<InterfaceBlock> &shaderStorageBlocks); + + ~OutputHLSL(); + + void output(TIntermNode *treeRoot, TInfoSinkBase &objSink); + + const std::map<std::string, unsigned int> &getShaderStorageBlockRegisterMap() const; + const std::map<std::string, unsigned int> &getUniformBlockRegisterMap() const; + const std::map<std::string, unsigned int> &getUniformRegisterMap() const; + unsigned int getReadonlyImage2DRegisterIndex() const; + unsigned int getImage2DRegisterIndex() const; + const std::set<std::string> &getUsedImage2DFunctionNames() const; + + TInfoSinkBase &getInfoSink() + { + ASSERT(!mInfoSinkStack.empty()); + return *mInfoSinkStack.top(); + } + + protected: + friend class ShaderStorageBlockOutputHLSL; + + TString zeroInitializer(const TType &type) const; + + void writeReferencedAttributes(TInfoSinkBase &out) const; + void writeReferencedVaryings(TInfoSinkBase &out) const; + void header(TInfoSinkBase &out, + const std::vector<MappedStruct> &std140Structs, + const BuiltInFunctionEmulator *builtInFunctionEmulator) const; + + void writeFloat(TInfoSinkBase &out, float f); + void writeSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion); + const TConstantUnion *writeConstantUnionArray(TInfoSinkBase &out, + const TConstantUnion *const constUnion, + const size_t size); + + // Visit AST nodes and output their code to the body stream + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; + bool visitBinary(Visit visit, TIntermBinary *) override; + bool visitUnary(Visit visit, TIntermUnary *) override; + bool visitTernary(Visit visit, TIntermTernary *) override; + bool visitIfElse(Visit visit, TIntermIfElse *) override; + bool visitSwitch(Visit visit, TIntermSwitch *) override; + bool visitCase(Visit visit, TIntermCase *) override; + void visitFunctionPrototype(TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit visit, TIntermBranch *) override; + + bool handleExcessiveLoop(TInfoSinkBase &out, TIntermLoop *node); + + // Emit one of three strings depending on traverse phase. Called with literal strings so using + // const char* instead of TString. + void outputTriplet(TInfoSinkBase &out, + Visit visit, + const char *preString, + const char *inString, + const char *postString); + void outputLineDirective(TInfoSinkBase &out, int line); + void writeParameter(const TVariable *param, TInfoSinkBase &out); + + void outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node); + const TConstantUnion *writeConstantUnion(TInfoSinkBase &out, + const TType &type, + const TConstantUnion *constUnion); + + void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out); + void outputAssign(Visit visit, const TType &type, TInfoSinkBase &out); + + void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op); + + // Returns true if it found a 'same symbol' initializer (initializer that references the + // variable it's initting) + bool writeSameSymbolInitializer(TInfoSinkBase &out, + TIntermSymbol *symbolNode, + TIntermTyped *expression); + // Returns true if variable initializer could be written using literal {} notation. + bool writeConstantInitialization(TInfoSinkBase &out, + TIntermSymbol *symbolNode, + TIntermTyped *expression); + + void writeIfElse(TInfoSinkBase &out, TIntermIfElse *node); + + // Returns the function name + TString addStructEqualityFunction(const TStructure &structure); + TString addArrayEqualityFunction(const TType &type); + TString addArrayAssignmentFunction(const TType &type); + TString addArrayConstructIntoFunction(const TType &type); + + // Ensures if the type is a struct, the struct is defined + void ensureStructDefined(const TType &type); + + bool shaderNeedsGenerateOutput() const; + const char *generateOutputCall() const; + + sh::GLenum mShaderType; + int mShaderVersion; + const TExtensionBehavior &mExtensionBehavior; + const char *mSourcePath; + const ShShaderOutput mOutputType; + ShCompileOptions mCompileOptions; + + bool mInsideFunction; + bool mInsideMain; + + // Output streams + TInfoSinkBase mHeader; + TInfoSinkBase mBody; + TInfoSinkBase mFooter; + + // A stack is useful when we want to traverse in the header, or in helper functions, but not + // always write to the body. Instead use an InfoSink stack to keep our current state intact. + // TODO (jmadill): Just passing an InfoSink in function parameters would be simpler. + std::stack<TInfoSinkBase *> mInfoSinkStack; + + ReferencedVariables mReferencedUniforms; + + // Indexed by block id, not instance id. + ReferencedInterfaceBlocks mReferencedUniformBlocks; + + ReferencedVariables mReferencedAttributes; + ReferencedVariables mReferencedVaryings; + ReferencedVariables mReferencedOutputVariables; + + StructureHLSL *mStructureHLSL; + ResourcesHLSL *mResourcesHLSL; + TextureFunctionHLSL *mTextureFunctionHLSL; + ImageFunctionHLSL *mImageFunctionHLSL; + AtomicCounterFunctionHLSL *mAtomicCounterFunctionHLSL; + + // Parameters determining what goes in the header output + bool mUsesFragColor; + bool mUsesFragData; + bool mUsesDepthRange; + bool mUsesFragCoord; + bool mUsesPointCoord; + bool mUsesFrontFacing; + bool mUsesPointSize; + bool mUsesInstanceID; + bool mHasMultiviewExtensionEnabled; + bool mUsesViewID; + bool mUsesVertexID; + bool mUsesFragDepth; + bool mUsesNumWorkGroups; + bool mUsesWorkGroupID; + bool mUsesLocalInvocationID; + bool mUsesGlobalInvocationID; + bool mUsesLocalInvocationIndex; + bool mUsesXor; + bool mUsesDiscardRewriting; + bool mUsesNestedBreak; + bool mRequiresIEEEStrictCompiling; + mutable bool mUseZeroArray; + bool mUsesSecondaryColor; + + int mNumRenderTargets; + int mMaxDualSourceDrawBuffers; + + int mUniqueIndex; // For creating unique names + + CallDAG mCallDag; + MetadataList mASTMetadataList; + ASTMetadataHLSL *mCurrentFunctionMetadata; + bool mOutputLod0Function; + bool mInsideDiscontinuousLoop; + int mNestedLoopDepth; + + TIntermSymbol *mExcessiveLoopIndex; + + TString structInitializerString(int indent, const TType &type, const TString &name) const; + + struct HelperFunction + { + TString functionName; + TString functionDefinition; + + virtual ~HelperFunction() {} + }; + + // A list of all equality comparison functions. It's important to preserve the order at + // which we add the functions, since nested structures call each other recursively, and + // structure equality functions may need to call array equality functions and vice versa. + // The ownership of the pointers is maintained by the type-specific arrays. + std::vector<HelperFunction *> mEqualityFunctions; + + struct StructEqualityFunction : public HelperFunction + { + const TStructure *structure; + }; + std::vector<StructEqualityFunction *> mStructEqualityFunctions; + + struct ArrayHelperFunction : public HelperFunction + { + TType type; + }; + std::vector<ArrayHelperFunction *> mArrayEqualityFunctions; + + std::vector<ArrayHelperFunction> mArrayAssignmentFunctions; + + // The construct-into functions are functions that fill an N-element array passed as an out + // parameter with the other N parameters of the function. This is used to work around that + // arrays can't be return values in HLSL. + std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions; + + sh::WorkGroupSize mWorkGroupSize; + + PerformanceDiagnostics *mPerfDiagnostics; + + private: + TString generateStructMapping(const std::vector<MappedStruct> &std140Structs) const; + ImmutableString samplerNamePrefixFromStruct(TIntermTyped *node); + bool ancestorEvaluatesToSamplerInStruct(); + // We need to do struct mapping when pass the struct to a function or copy the struct via + // assignment. + bool needStructMapping(TIntermTyped *node); + + ShaderStorageBlockOutputHLSL *mSSBOOutputHLSL; + bool mNeedStructMapping; +}; +} // namespace sh + +#endif // COMPILER_TRANSLATOR_OUTPUTHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/OutputTree.cpp b/gfx/angle/checkout/src/compiler/translator/OutputTree.cpp new file mode 100644 index 0000000000..6de64a660a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputTree.cpp @@ -0,0 +1,699 @@ +// +// Copyright (c) 2002-2014 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/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +void OutputFunction(TInfoSinkBase &out, const char *str, const TFunction *func) +{ + const char *internal = + (func->symbolType() == SymbolType::AngleInternal) ? " (internal function)" : ""; + out << str << internal << ": " << func->name() << " (symbol id " << func->uniqueId().get() + << ")"; +} + +// Two purposes: +// 1. Show an example of how to iterate tree. Functions can also directly call traverse() on +// children themselves to have finer grained control over the process than shown here, though +// that's not recommended if it can be avoided. +// 2. Print out a text based description of the tree. + +// The traverser subclass is used to carry along data from node to node in the traversal. +class TOutputTraverser : public TIntermTraverser +{ + public: + TOutputTraverser(TInfoSinkBase &out) + : TIntermTraverser(true, false, false), mOut(out), mIndentDepth(0) + {} + + protected: + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; + bool visitBinary(Visit visit, TIntermBinary *) override; + bool visitUnary(Visit visit, TIntermUnary *) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; + bool visitSwitch(Visit visit, TIntermSwitch *node) override; + bool visitCase(Visit visit, TIntermCase *node) override; + void visitFunctionPrototype(TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *) override; + bool visitBlock(Visit visit, TIntermBlock *) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit visit, TIntermBranch *) override; + + int getCurrentIndentDepth() const { return mIndentDepth + getCurrentTraversalDepth(); } + + TInfoSinkBase &mOut; + int mIndentDepth; +}; + +// +// Helper functions for printing, not part of traversing. +// +void OutputTreeText(TInfoSinkBase &out, TIntermNode *node, const int depth) +{ + int i; + + out.location(node->getLine().first_file, node->getLine().first_line); + + for (i = 0; i < depth; ++i) + out << " "; +} + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TOutputTraverser::visitSymbol(TIntermSymbol *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + if (node->variable().symbolType() == SymbolType::Empty) + { + mOut << "''"; + } + else + { + mOut << "'" << node->getName() << "' "; + } + mOut << "(symbol id " << node->uniqueId().get() << ") "; + mOut << "(" << node->getType() << ")"; + mOut << "\n"; +} + +bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "vector swizzle ("; + node->writeOffsetsAsXYZW(&mOut); + mOut << ")"; + + mOut << " (" << node->getType() << ")"; + mOut << "\n"; + return true; +} + +bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + switch (node->getOp()) + { + case EOpComma: + mOut << "comma"; + break; + case EOpAssign: + mOut << "move second child to first child"; + break; + case EOpInitialize: + mOut << "initialize first child with second child"; + break; + case EOpAddAssign: + mOut << "add second child into first child"; + break; + case EOpSubAssign: + mOut << "subtract second child into first child"; + break; + case EOpMulAssign: + mOut << "multiply second child into first child"; + break; + case EOpVectorTimesMatrixAssign: + mOut << "matrix mult second child into first child"; + break; + case EOpVectorTimesScalarAssign: + mOut << "vector scale second child into first child"; + break; + case EOpMatrixTimesScalarAssign: + mOut << "matrix scale second child into first child"; + break; + case EOpMatrixTimesMatrixAssign: + mOut << "matrix mult second child into first child"; + break; + case EOpDivAssign: + mOut << "divide second child into first child"; + break; + case EOpIModAssign: + mOut << "modulo second child into first child"; + break; + case EOpBitShiftLeftAssign: + mOut << "bit-wise shift first child left by second child"; + break; + case EOpBitShiftRightAssign: + mOut << "bit-wise shift first child right by second child"; + break; + case EOpBitwiseAndAssign: + mOut << "bit-wise and second child into first child"; + break; + case EOpBitwiseXorAssign: + mOut << "bit-wise xor second child into first child"; + break; + case EOpBitwiseOrAssign: + mOut << "bit-wise or second child into first child"; + break; + + case EOpIndexDirect: + mOut << "direct index"; + break; + case EOpIndexIndirect: + mOut << "indirect index"; + break; + case EOpIndexDirectStruct: + mOut << "direct index for structure"; + break; + case EOpIndexDirectInterfaceBlock: + mOut << "direct index for interface block"; + break; + + case EOpAdd: + mOut << "add"; + break; + case EOpSub: + mOut << "subtract"; + break; + case EOpMul: + mOut << "component-wise multiply"; + break; + case EOpDiv: + mOut << "divide"; + break; + case EOpIMod: + mOut << "modulo"; + break; + case EOpBitShiftLeft: + mOut << "bit-wise shift left"; + break; + case EOpBitShiftRight: + mOut << "bit-wise shift right"; + break; + case EOpBitwiseAnd: + mOut << "bit-wise and"; + break; + case EOpBitwiseXor: + mOut << "bit-wise xor"; + break; + case EOpBitwiseOr: + mOut << "bit-wise or"; + break; + + case EOpEqual: + mOut << "Compare Equal"; + break; + case EOpNotEqual: + mOut << "Compare Not Equal"; + break; + case EOpLessThan: + mOut << "Compare Less Than"; + break; + case EOpGreaterThan: + mOut << "Compare Greater Than"; + break; + case EOpLessThanEqual: + mOut << "Compare Less Than or Equal"; + break; + case EOpGreaterThanEqual: + mOut << "Compare Greater Than or Equal"; + break; + + case EOpVectorTimesScalar: + mOut << "vector-scale"; + break; + case EOpVectorTimesMatrix: + mOut << "vector-times-matrix"; + break; + case EOpMatrixTimesVector: + mOut << "matrix-times-vector"; + break; + case EOpMatrixTimesScalar: + mOut << "matrix-scale"; + break; + case EOpMatrixTimesMatrix: + mOut << "matrix-multiply"; + break; + + case EOpLogicalOr: + mOut << "logical-or"; + break; + case EOpLogicalXor: + mOut << "logical-xor"; + break; + case EOpLogicalAnd: + mOut << "logical-and"; + break; + default: + mOut << "<unknown op>"; + } + + mOut << " (" << node->getType() << ")"; + + mOut << "\n"; + + // Special handling for direct indexes. Because constant + // unions are not aware they are struct indexes, treat them + // here where we have that contextual knowledge. + if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock) + { + node->getLeft()->traverse(this); + + TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion(); + ASSERT(intermConstantUnion); + + OutputTreeText(mOut, intermConstantUnion, getCurrentIndentDepth() + 1); + + // The following code finds the field name from the constant union + const TConstantUnion *constantUnion = intermConstantUnion->getConstantValue(); + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); + ASSERT(structure || interfaceBlock); + + const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields(); + + const TField *field = fields[constantUnion->getIConst()]; + + mOut << constantUnion->getIConst() << " (field '" << field->name() << "')"; + + mOut << "\n"; + + return false; + } + + return true; +} + +bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + switch (node->getOp()) + { + // Give verbose names for ops that have special syntax and some built-in functions that are + // easy to confuse with others, but mostly use GLSL names for functions. + case EOpNegative: + mOut << "Negate value"; + break; + case EOpPositive: + mOut << "Positive sign"; + break; + case EOpLogicalNot: + mOut << "negation"; + break; + case EOpBitwiseNot: + mOut << "bit-wise not"; + break; + + case EOpPostIncrement: + mOut << "Post-Increment"; + break; + case EOpPostDecrement: + mOut << "Post-Decrement"; + break; + case EOpPreIncrement: + mOut << "Pre-Increment"; + break; + case EOpPreDecrement: + mOut << "Pre-Decrement"; + break; + + case EOpArrayLength: + mOut << "Array length"; + break; + + case EOpLogicalNotComponentWise: + mOut << "component-wise not"; + break; + + default: + mOut << GetOperatorString(node->getOp()); + break; + } + + mOut << " (" << node->getType() << ")"; + + mOut << "\n"; + + return true; +} + +bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "Function Definition:\n"; + return true; +} + +bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "Invariant Declaration:\n"; + return true; +} + +void TOutputTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + OutputFunction(mOut, "Function Prototype", node->getFunction()); + mOut << " (" << node->getType() << ")"; + mOut << "\n"; + size_t paramCount = node->getFunction()->getParamCount(); + for (size_t i = 0; i < paramCount; ++i) + { + const TVariable *param = node->getFunction()->getParam(i); + OutputTreeText(mOut, node, getCurrentIndentDepth() + 1); + mOut << "parameter: " << param->name() << " (" << param->getType() << ")"; + } +} + +bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + if (node->getOp() == EOpNull) + { + mOut.prefix(SH_ERROR); + mOut << "node is still EOpNull!\n"; + return true; + } + + // Give verbose names for some built-in functions that are easy to confuse with others, but + // mostly use GLSL names for functions. + switch (node->getOp()) + { + case EOpCallFunctionInAST: + OutputFunction(mOut, "Call an user-defined function", node->getFunction()); + break; + case EOpCallInternalRawFunction: + OutputFunction(mOut, "Call an internal function with raw implementation", + node->getFunction()); + break; + case EOpCallBuiltInFunction: + OutputFunction(mOut, "Call a built-in function", node->getFunction()); + break; + + case EOpConstruct: + // The type of the constructor will be printed below. + mOut << "Construct"; + break; + + case EOpEqualComponentWise: + mOut << "component-wise equal"; + break; + case EOpNotEqualComponentWise: + mOut << "component-wise not equal"; + break; + case EOpLessThanComponentWise: + mOut << "component-wise less than"; + break; + case EOpGreaterThanComponentWise: + mOut << "component-wise greater than"; + break; + case EOpLessThanEqualComponentWise: + mOut << "component-wise less than or equal"; + break; + case EOpGreaterThanEqualComponentWise: + mOut << "component-wise greater than or equal"; + break; + + case EOpDot: + mOut << "dot product"; + break; + case EOpCross: + mOut << "cross product"; + break; + case EOpMulMatrixComponentWise: + mOut << "component-wise multiply"; + break; + + default: + mOut << GetOperatorString(node->getOp()); + break; + } + + mOut << " (" << node->getType() << ")"; + + mOut << "\n"; + + return true; +} + +bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "Code block\n"; + + return true; +} + +bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "Declaration\n"; + + return true; +} + +bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + mOut << "Ternary selection"; + mOut << " (" << node->getType() << ")\n"; + + ++mIndentDepth; + + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(mOut, node, getCurrentIndentDepth()); + if (node->getTrueExpression()) + { + mOut << "true case\n"; + node->getTrueExpression()->traverse(this); + } + if (node->getFalseExpression()) + { + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "false case\n"; + node->getFalseExpression()->traverse(this); + } + + --mIndentDepth; + + return false; +} + +bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + mOut << "If test\n"; + + ++mIndentDepth; + + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(mOut, node, getCurrentIndentDepth()); + if (node->getTrueBlock()) + { + mOut << "true case\n"; + node->getTrueBlock()->traverse(this); + } + else + { + mOut << "true case is null\n"; + } + + if (node->getFalseBlock()) + { + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "false case\n"; + node->getFalseBlock()->traverse(this); + } + + --mIndentDepth; + + return false; +} + +bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + mOut << "Switch\n"; + + return true; +} + +bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + if (node->getCondition() == nullptr) + { + mOut << "Default\n"; + } + else + { + mOut << "Case\n"; + } + + return true; +} + +void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node) +{ + size_t size = node->getType().getObjectSize(); + + for (size_t i = 0; i < size; i++) + { + OutputTreeText(mOut, node, getCurrentIndentDepth()); + switch (node->getConstantValue()[i].getType()) + { + case EbtBool: + if (node->getConstantValue()[i].getBConst()) + mOut << "true"; + else + mOut << "false"; + + mOut << " (" + << "const bool" + << ")"; + mOut << "\n"; + break; + case EbtFloat: + mOut << node->getConstantValue()[i].getFConst(); + mOut << " (const float)\n"; + break; + case EbtInt: + mOut << node->getConstantValue()[i].getIConst(); + mOut << " (const int)\n"; + break; + case EbtUInt: + mOut << node->getConstantValue()[i].getUConst(); + mOut << " (const uint)\n"; + break; + case EbtYuvCscStandardEXT: + mOut << getYuvCscStandardEXTString( + node->getConstantValue()[i].getYuvCscStandardEXTConst()); + mOut << " (const yuvCscStandardEXT)\n"; + break; + default: + mOut.prefix(SH_ERROR); + mOut << "Unknown constant\n"; + break; + } + } +} + +bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + mOut << "Loop with condition "; + if (node->getType() == ELoopDoWhile) + mOut << "not "; + mOut << "tested first\n"; + + ++mIndentDepth; + + OutputTreeText(mOut, node, getCurrentIndentDepth()); + if (node->getCondition()) + { + mOut << "Loop Condition\n"; + node->getCondition()->traverse(this); + } + else + { + mOut << "No loop condition\n"; + } + + OutputTreeText(mOut, node, getCurrentIndentDepth()); + if (node->getBody()) + { + mOut << "Loop Body\n"; + node->getBody()->traverse(this); + } + else + { + mOut << "No loop body\n"; + } + + if (node->getExpression()) + { + OutputTreeText(mOut, node, getCurrentIndentDepth()); + mOut << "Loop Terminal Expression\n"; + node->getExpression()->traverse(this); + } + + --mIndentDepth; + + return false; +} + +bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node) +{ + OutputTreeText(mOut, node, getCurrentIndentDepth()); + + switch (node->getFlowOp()) + { + case EOpKill: + mOut << "Branch: Kill"; + break; + case EOpBreak: + mOut << "Branch: Break"; + break; + case EOpContinue: + mOut << "Branch: Continue"; + break; + case EOpReturn: + mOut << "Branch: Return"; + break; + default: + mOut << "Branch: Unknown Branch"; + break; + } + + if (node->getExpression()) + { + mOut << " with expression\n"; + ++mIndentDepth; + node->getExpression()->traverse(this); + --mIndentDepth; + } + else + { + mOut << "\n"; + } + + return false; +} + +} // anonymous namespace + +void OutputTree(TIntermNode *root, TInfoSinkBase &out) +{ + TOutputTraverser it(out); + ASSERT(root); + root->traverse(&it); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/OutputTree.h b/gfx/angle/checkout/src/compiler/translator/OutputTree.h new file mode 100644 index 0000000000..9f11989cb1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/OutputTree.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 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. +// +// Output the AST intermediate representation of the GLSL code. + +#ifndef COMPILER_TRANSLATOR_OUTPUTTREE_H_ +#define COMPILER_TRANSLATOR_OUTPUTTREE_H_ + +namespace sh +{ + +class TIntermNode; +class TInfoSinkBase; + +// Output the AST along with metadata. +void OutputTree(TIntermNode *root, TInfoSinkBase &out); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_OUTPUTTREE_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp b/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp new file mode 100644 index 0000000000..5808c880d1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp @@ -0,0 +1,6100 @@ +// +// Copyright (c) 2002-2014 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/ParseContext.h" + +#include <stdarg.h> +#include <stdio.h> + +#include "common/mathutil.h" +#include "compiler/preprocessor/SourceLocation.h" +#include "compiler/translator/Declarator.h" +#include "compiler/translator/ParseContext_autogen.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/ValidateGlobalInitializer.h" +#include "compiler/translator/ValidateSwitch.h" +#include "compiler/translator/glslang.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +/////////////////////////////////////////////////////////////////////// +// +// Sub- vector and matrix fields +// +//////////////////////////////////////////////////////////////////////// + +namespace +{ + +const int kWebGLMaxStructNesting = 4; + +bool ContainsSampler(const TStructure *structType); + +bool ContainsSampler(const TType &type) +{ + if (IsSampler(type.getBasicType())) + { + return true; + } + if (type.getBasicType() == EbtStruct) + { + return ContainsSampler(type.getStruct()); + } + + return false; +} + +bool ContainsSampler(const TStructure *structType) +{ + for (const auto &field : structType->fields()) + { + if (ContainsSampler(*field->type())) + return true; + } + return false; +} + +// Get a token from an image argument to use as an error message token. +const char *GetImageArgumentToken(TIntermTyped *imageNode) +{ + ASSERT(IsImage(imageNode->getBasicType())); + while (imageNode->getAsBinaryNode() && + (imageNode->getAsBinaryNode()->getOp() == EOpIndexIndirect || + imageNode->getAsBinaryNode()->getOp() == EOpIndexDirect)) + { + imageNode = imageNode->getAsBinaryNode()->getLeft(); + } + TIntermSymbol *imageSymbol = imageNode->getAsSymbolNode(); + if (imageSymbol) + { + return imageSymbol->getName().data(); + } + return "image"; +} + +bool CanSetDefaultPrecisionOnType(const TPublicType &type) +{ + if (!SupportsPrecision(type.getBasicType())) + { + return false; + } + if (type.getBasicType() == EbtUInt) + { + // ESSL 3.00.4 section 4.5.4 + return false; + } + if (type.isAggregate()) + { + // Not allowed to set for aggregate types + return false; + } + return true; +} + +// Map input primitive types to input array sizes in a geometry shader. +GLuint GetGeometryShaderInputArraySize(TLayoutPrimitiveType primitiveType) +{ + switch (primitiveType) + { + case EptPoints: + return 1u; + case EptLines: + return 2u; + case EptTriangles: + return 3u; + case EptLinesAdjacency: + return 4u; + case EptTrianglesAdjacency: + return 6u; + default: + UNREACHABLE(); + return 0u; + } +} + +bool IsBufferOrSharedVariable(TIntermTyped *var) +{ + if (var->isInterfaceBlock() || var->getQualifier() == EvqBuffer || + var->getQualifier() == EvqShared) + { + return true; + } + return false; +} + +} // namespace + +// This tracks each binding point's current default offset for inheritance of subsequent +// variables using the same binding, and keeps offsets unique and non overlapping. +// See GLSL ES 3.1, section 4.4.6. +class TParseContext::AtomicCounterBindingState +{ + public: + AtomicCounterBindingState() : mDefaultOffset(0) {} + // Inserts a new span and returns -1 if overlapping, else returns the starting offset of + // newly inserted span. + int insertSpan(int start, size_t length) + { + gl::RangeI newSpan(start, start + static_cast<int>(length)); + for (const auto &span : mSpans) + { + if (newSpan.intersects(span)) + { + return -1; + } + } + mSpans.push_back(newSpan); + mDefaultOffset = newSpan.high(); + return start; + } + // Inserts a new span starting from the default offset. + int appendSpan(size_t length) { return insertSpan(mDefaultOffset, length); } + void setDefaultOffset(int offset) { mDefaultOffset = offset; } + + private: + int mDefaultOffset; + std::vector<gl::RangeI> mSpans; +}; + +TParseContext::TParseContext(TSymbolTable &symt, + TExtensionBehavior &ext, + sh::GLenum type, + ShShaderSpec spec, + ShCompileOptions options, + bool checksPrecErrors, + TDiagnostics *diagnostics, + const ShBuiltInResources &resources) + : symbolTable(symt), + mDeferredNonEmptyDeclarationErrorCheck(false), + mShaderType(type), + mShaderSpec(spec), + mCompileOptions(options), + mShaderVersion(100), + mTreeRoot(nullptr), + mLoopNestingLevel(0), + mStructNestingLevel(0), + mSwitchNestingLevel(0), + mCurrentFunctionType(nullptr), + mFunctionReturnsValue(false), + mChecksPrecisionErrors(checksPrecErrors), + mFragmentPrecisionHighOnESSL1(false), + mDefaultUniformMatrixPacking(EmpColumnMajor), + mDefaultUniformBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), + mDefaultBufferMatrixPacking(EmpColumnMajor), + mDefaultBufferBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), + mDiagnostics(diagnostics), + mDirectiveHandler(ext, + *mDiagnostics, + mShaderVersion, + mShaderType, + resources.WEBGL_debug_shader_precision == 1), + mPreprocessor(mDiagnostics, &mDirectiveHandler, angle::pp::PreprocessorSettings(spec)), + mScanner(nullptr), + mMinProgramTexelOffset(resources.MinProgramTexelOffset), + mMaxProgramTexelOffset(resources.MaxProgramTexelOffset), + mMinProgramTextureGatherOffset(resources.MinProgramTextureGatherOffset), + mMaxProgramTextureGatherOffset(resources.MaxProgramTextureGatherOffset), + mComputeShaderLocalSizeDeclared(false), + mComputeShaderLocalSize(-1), + mNumViews(-1), + mMaxNumViews(resources.MaxViewsOVR), + mMaxImageUnits(resources.MaxImageUnits), + mMaxCombinedTextureImageUnits(resources.MaxCombinedTextureImageUnits), + mMaxUniformLocations(resources.MaxUniformLocations), + mMaxUniformBufferBindings(resources.MaxUniformBufferBindings), + mMaxAtomicCounterBindings(resources.MaxAtomicCounterBindings), + mMaxShaderStorageBufferBindings(resources.MaxShaderStorageBufferBindings), + mDeclaringFunction(false), + mGeometryShaderInputPrimitiveType(EptUndefined), + mGeometryShaderOutputPrimitiveType(EptUndefined), + mGeometryShaderInvocations(0), + mGeometryShaderMaxVertices(-1), + mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations), + mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices), + mFunctionBodyNewScope(false) +{} + +TParseContext::~TParseContext() {} + +bool TParseContext::anyMultiviewExtensionAvailable() +{ + return isExtensionEnabled(TExtension::OVR_multiview) || + isExtensionEnabled(TExtension::OVR_multiview2); +} + +bool TParseContext::parseVectorFields(const TSourceLoc &line, + const ImmutableString &compString, + int vecSize, + TVector<int> *fieldOffsets) +{ + ASSERT(fieldOffsets); + size_t fieldCount = compString.length(); + if (fieldCount > 4u) + { + error(line, "illegal vector field selection", compString); + return false; + } + fieldOffsets->resize(fieldCount); + + enum + { + exyzw, + ergba, + estpq + } fieldSet[4]; + + for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) + { + switch (compString[i]) + { + case 'x': + (*fieldOffsets)[i] = 0; + fieldSet[i] = exyzw; + break; + case 'r': + (*fieldOffsets)[i] = 0; + fieldSet[i] = ergba; + break; + case 's': + (*fieldOffsets)[i] = 0; + fieldSet[i] = estpq; + break; + case 'y': + (*fieldOffsets)[i] = 1; + fieldSet[i] = exyzw; + break; + case 'g': + (*fieldOffsets)[i] = 1; + fieldSet[i] = ergba; + break; + case 't': + (*fieldOffsets)[i] = 1; + fieldSet[i] = estpq; + break; + case 'z': + (*fieldOffsets)[i] = 2; + fieldSet[i] = exyzw; + break; + case 'b': + (*fieldOffsets)[i] = 2; + fieldSet[i] = ergba; + break; + case 'p': + (*fieldOffsets)[i] = 2; + fieldSet[i] = estpq; + break; + + case 'w': + (*fieldOffsets)[i] = 3; + fieldSet[i] = exyzw; + break; + case 'a': + (*fieldOffsets)[i] = 3; + fieldSet[i] = ergba; + break; + case 'q': + (*fieldOffsets)[i] = 3; + fieldSet[i] = estpq; + break; + default: + error(line, "illegal vector field selection", compString); + return false; + } + } + + for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) + { + if ((*fieldOffsets)[i] >= vecSize) + { + error(line, "vector field selection out of range", compString); + return false; + } + + if (i > 0) + { + if (fieldSet[i] != fieldSet[i - 1]) + { + error(line, "illegal - vector component fields not from the same set", compString); + return false; + } + } + } + + return true; +} + +/////////////////////////////////////////////////////////////////////// +// +// Errors +// +//////////////////////////////////////////////////////////////////////// + +// +// Used by flex/bison to output all syntax and parsing errors. +// +void TParseContext::error(const TSourceLoc &loc, const char *reason, const char *token) +{ + mDiagnostics->error(loc, reason, token); +} + +void TParseContext::error(const TSourceLoc &loc, const char *reason, const ImmutableString &token) +{ + mDiagnostics->error(loc, reason, token.data()); +} + +void TParseContext::warning(const TSourceLoc &loc, const char *reason, const char *token) +{ + mDiagnostics->warning(loc, reason, token); +} + +void TParseContext::outOfRangeError(bool isError, + const TSourceLoc &loc, + const char *reason, + const char *token) +{ + if (isError) + { + error(loc, reason, token); + } + else + { + warning(loc, reason, token); + } +} + +// +// Same error message for all places assignments don't work. +// +void TParseContext::assignError(const TSourceLoc &line, + const char *op, + const TType &left, + const TType &right) +{ + TInfoSinkBase reasonStream; + reasonStream << "cannot convert from '" << right << "' to '" << left << "'"; + error(line, reasonStream.c_str(), op); +} + +// +// Same error message for all places unary operations don't work. +// +void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, const TType &operand) +{ + TInfoSinkBase reasonStream; + reasonStream << "wrong operand type - no operation '" << op + << "' exists that takes an operand of type " << operand + << " (or there is no acceptable conversion)"; + error(line, reasonStream.c_str(), op); +} + +// +// Same error message for all binary operations don't work. +// +void TParseContext::binaryOpError(const TSourceLoc &line, + const char *op, + const TType &left, + const TType &right) +{ + TInfoSinkBase reasonStream; + reasonStream << "wrong operand types - no operation '" << op + << "' exists that takes a left-hand operand of type '" << left + << "' and a right operand of type '" << right + << "' (or there is no acceptable conversion)"; + error(line, reasonStream.c_str(), op); +} + +void TParseContext::checkPrecisionSpecified(const TSourceLoc &line, + TPrecision precision, + TBasicType type) +{ + if (!mChecksPrecisionErrors) + return; + + if (precision != EbpUndefined && !SupportsPrecision(type)) + { + error(line, "illegal type for precision qualifier", getBasicString(type)); + } + + if (precision == EbpUndefined) + { + switch (type) + { + case EbtFloat: + error(line, "No precision specified for (float)", ""); + return; + case EbtInt: + case EbtUInt: + UNREACHABLE(); // there's always a predeclared qualifier + error(line, "No precision specified (int)", ""); + return; + default: + if (IsOpaqueType(type)) + { + error(line, "No precision specified", getBasicString(type)); + return; + } + } + } +} + +void TParseContext::markStaticReadIfSymbol(TIntermNode *node) +{ + TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); + if (swizzleNode) + { + markStaticReadIfSymbol(swizzleNode->getOperand()); + return; + } + TIntermBinary *binaryNode = node->getAsBinaryNode(); + if (binaryNode) + { + switch (binaryNode->getOp()) + { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + markStaticReadIfSymbol(binaryNode->getLeft()); + return; + default: + return; + } + } + TIntermSymbol *symbolNode = node->getAsSymbolNode(); + if (symbolNode) + { + symbolTable.markStaticRead(symbolNode->variable()); + } +} + +// Both test and if necessary, spit out an error, to see if the node is really +// an l-value that can be operated on this way. +bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node) +{ + TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); + if (swizzleNode) + { + bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand()); + if (ok && swizzleNode->hasDuplicateOffsets()) + { + error(line, " l-value of swizzle cannot have duplicate components", op); + return false; + } + return ok; + } + + TIntermBinary *binaryNode = node->getAsBinaryNode(); + if (binaryNode) + { + switch (binaryNode->getOp()) + { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + if (node->getMemoryQualifier().readonly) + { + error(line, "can't modify a readonly variable", op); + return false; + } + return checkCanBeLValue(line, op, binaryNode->getLeft()); + default: + break; + } + error(line, " l-value required", op); + return false; + } + + std::string message; + switch (node->getQualifier()) + { + case EvqConst: + message = "can't modify a const"; + break; + case EvqConstReadOnly: + message = "can't modify a const"; + break; + case EvqAttribute: + message = "can't modify an attribute"; + break; + case EvqFragmentIn: + case EvqVertexIn: + case EvqGeometryIn: + case EvqFlatIn: + case EvqSmoothIn: + case EvqCentroidIn: + message = "can't modify an input"; + break; + case EvqUniform: + message = "can't modify a uniform"; + break; + case EvqVaryingIn: + message = "can't modify a varying"; + break; + case EvqFragCoord: + message = "can't modify gl_FragCoord"; + break; + case EvqFrontFacing: + message = "can't modify gl_FrontFacing"; + break; + case EvqPointCoord: + message = "can't modify gl_PointCoord"; + break; + case EvqNumWorkGroups: + message = "can't modify gl_NumWorkGroups"; + break; + case EvqWorkGroupSize: + message = "can't modify gl_WorkGroupSize"; + break; + case EvqWorkGroupID: + message = "can't modify gl_WorkGroupID"; + break; + case EvqLocalInvocationID: + message = "can't modify gl_LocalInvocationID"; + break; + case EvqGlobalInvocationID: + message = "can't modify gl_GlobalInvocationID"; + break; + case EvqLocalInvocationIndex: + message = "can't modify gl_LocalInvocationIndex"; + break; + case EvqViewIDOVR: + message = "can't modify gl_ViewID_OVR"; + break; + case EvqComputeIn: + message = "can't modify work group size variable"; + break; + case EvqPerVertexIn: + message = "can't modify any member in gl_in"; + break; + case EvqPrimitiveIDIn: + message = "can't modify gl_PrimitiveIDIn"; + break; + case EvqInvocationID: + message = "can't modify gl_InvocationID"; + break; + case EvqPrimitiveID: + if (mShaderType == GL_FRAGMENT_SHADER) + { + message = "can't modify gl_PrimitiveID in a fragment shader"; + } + break; + case EvqLayer: + if (mShaderType == GL_FRAGMENT_SHADER) + { + message = "can't modify gl_Layer in a fragment shader"; + } + break; + default: + // + // Type that can't be written to? + // + if (node->getBasicType() == EbtVoid) + { + message = "can't modify void"; + } + if (IsOpaqueType(node->getBasicType())) + { + message = "can't modify a variable with type "; + message += getBasicString(node->getBasicType()); + } + else if (node->getMemoryQualifier().readonly) + { + message = "can't modify a readonly variable"; + } + } + + ASSERT(binaryNode == nullptr && swizzleNode == nullptr); + TIntermSymbol *symNode = node->getAsSymbolNode(); + if (message.empty() && symNode != nullptr) + { + symbolTable.markStaticWrite(symNode->variable()); + return true; + } + + std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); + reasonStream << "l-value required"; + if (!message.empty()) + { + if (symNode) + { + // Symbol inside an expression can't be nameless. + ASSERT(symNode->variable().symbolType() != SymbolType::Empty); + const ImmutableString &symbol = symNode->getName(); + reasonStream << " (" << message << " \"" << symbol << "\")"; + } + else + { + reasonStream << " (" << message << ")"; + } + } + std::string reason = reasonStream.str(); + error(line, reason.c_str(), op); + + return false; +} + +// Both test, and if necessary spit out an error, to see if the node is really +// a constant. +void TParseContext::checkIsConst(TIntermTyped *node) +{ + if (node->getQualifier() != EvqConst) + { + error(node->getLine(), "constant expression required", ""); + } +} + +// Both test, and if necessary spit out an error, to see if the node is really +// an integer. +void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token) +{ + if (!node->isScalarInt()) + { + error(node->getLine(), "integer expression required", token); + } +} + +// Both test, and if necessary spit out an error, to see if we are currently +// globally scoped. +bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token) +{ + if (!symbolTable.atGlobalLevel()) + { + error(line, "only allowed at global scope", token); + return false; + } + return true; +} + +// ESSL 3.00.5 sections 3.8 and 3.9. +// If it starts "gl_" or contains two consecutive underscores, it's reserved. +// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a webgl shader. +bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier) +{ + static const char *reservedErrMsg = "reserved built-in name"; + if (identifier.beginsWith("gl_")) + { + error(line, reservedErrMsg, "gl_"); + return false; + } + if (sh::IsWebGLBasedSpec(mShaderSpec)) + { + if (identifier.beginsWith("webgl_")) + { + error(line, reservedErrMsg, "webgl_"); + return false; + } + if (identifier.beginsWith("_webgl_")) + { + error(line, reservedErrMsg, "_webgl_"); + return false; + } + } + if (identifier.contains("__")) + { + error(line, + "identifiers containing two consecutive underscores (__) are reserved as " + "possible future keywords", + identifier); + return false; + } + return true; +} + +// Make sure the argument types are correct for constructing a specific type. +bool TParseContext::checkConstructorArguments(const TSourceLoc &line, + const TIntermSequence &arguments, + const TType &type) +{ + if (arguments.empty()) + { + error(line, "constructor does not have any arguments", "constructor"); + return false; + } + + for (TIntermNode *arg : arguments) + { + markStaticReadIfSymbol(arg); + const TIntermTyped *argTyped = arg->getAsTyped(); + ASSERT(argTyped != nullptr); + if (type.getBasicType() != EbtStruct && IsOpaqueType(argTyped->getBasicType())) + { + std::string reason("cannot convert a variable with type "); + reason += getBasicString(argTyped->getBasicType()); + error(line, reason.c_str(), "constructor"); + return false; + } + else if (argTyped->getMemoryQualifier().writeonly) + { + error(line, "cannot convert a variable with writeonly", "constructor"); + return false; + } + if (argTyped->getBasicType() == EbtVoid) + { + error(line, "cannot convert a void", "constructor"); + return false; + } + } + + if (type.isArray()) + { + // The size of an unsized constructor should already have been determined. + ASSERT(!type.isUnsizedArray()); + if (static_cast<size_t>(type.getOutermostArraySize()) != arguments.size()) + { + error(line, "array constructor needs one argument per array element", "constructor"); + return false; + } + // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of + // the array. + for (TIntermNode *const &argNode : arguments) + { + const TType &argType = argNode->getAsTyped()->getType(); + if (mShaderVersion < 310 && argType.isArray()) + { + error(line, "constructing from a non-dereferenced array", "constructor"); + return false; + } + if (!argType.isElementTypeOf(type)) + { + error(line, "Array constructor argument has an incorrect type", "constructor"); + return false; + } + } + } + else if (type.getBasicType() == EbtStruct) + { + const TFieldList &fields = type.getStruct()->fields(); + if (fields.size() != arguments.size()) + { + error(line, + "Number of constructor parameters does not match the number of structure fields", + "constructor"); + return false; + } + + for (size_t i = 0; i < fields.size(); i++) + { + if (i >= arguments.size() || + arguments[i]->getAsTyped()->getType() != *fields[i]->type()) + { + error(line, "Structure constructor arguments do not match structure fields", + "constructor"); + return false; + } + } + } + else + { + // We're constructing a scalar, vector, or matrix. + + // Note: It's okay to have too many components available, but not okay to have unused + // arguments. 'full' will go to true when enough args have been seen. If we loop again, + // there is an extra argument, so 'overFull' will become true. + + size_t size = 0; + bool full = false; + bool overFull = false; + bool matrixArg = false; + for (TIntermNode *arg : arguments) + { + const TIntermTyped *argTyped = arg->getAsTyped(); + ASSERT(argTyped != nullptr); + + if (argTyped->getBasicType() == EbtStruct) + { + error(line, "a struct cannot be used as a constructor argument for this type", + "constructor"); + return false; + } + if (argTyped->getType().isArray()) + { + error(line, "constructing from a non-dereferenced array", "constructor"); + return false; + } + if (argTyped->getType().isMatrix()) + { + matrixArg = true; + } + + size += argTyped->getType().getObjectSize(); + if (full) + { + overFull = true; + } + if (size >= type.getObjectSize()) + { + full = true; + } + } + + if (type.isMatrix() && matrixArg) + { + if (arguments.size() != 1) + { + error(line, "constructing matrix from matrix can only take one argument", + "constructor"); + return false; + } + } + else + { + if (size != 1 && size < type.getObjectSize()) + { + error(line, "not enough data provided for construction", "constructor"); + return false; + } + if (overFull) + { + error(line, "too many arguments", "constructor"); + return false; + } + } + } + + return true; +} + +// This function checks to see if a void variable has been declared and raise an error message for +// such a case +// +// returns true in case of an error +// +bool TParseContext::checkIsNonVoid(const TSourceLoc &line, + const ImmutableString &identifier, + const TBasicType &type) +{ + if (type == EbtVoid) + { + error(line, "illegal use of type 'void'", identifier); + return false; + } + + return true; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression +// or not. +bool TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type) +{ + if (type->getBasicType() != EbtBool || !type->isScalar()) + { + error(line, "boolean expression expected", ""); + return false; + } + return true; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression +// or not. +void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType) +{ + if (pType.getBasicType() != EbtBool || pType.isAggregate()) + { + error(line, "boolean expression expected", ""); + } +} + +bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line, + const TTypeSpecifierNonArray &pType, + const char *reason) +{ + if (pType.type == EbtStruct) + { + if (ContainsSampler(pType.userDef)) + { + std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); + reasonStream << reason << " (structure contains a sampler)"; + std::string reasonStr = reasonStream.str(); + error(line, reasonStr.c_str(), getBasicString(pType.type)); + return false; + } + // only samplers need to be checked from structs, since other opaque types can't be struct + // members. + return true; + } + else if (IsOpaqueType(pType.type)) + { + error(line, reason, getBasicString(pType.type)); + return false; + } + + return true; +} + +void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, + const TPublicType &pType) +{ + if (pType.layoutQualifier.location != -1) + { + error(line, "location must only be specified for a single input or output variable", + "location"); + } +} + +void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier) +{ + if (layoutQualifier.location != -1) + { + const char *errorMsg = "invalid layout qualifier: only valid on program inputs and outputs"; + if (mShaderVersion >= 310) + { + errorMsg = + "invalid layout qualifier: only valid on shader inputs, outputs, and uniforms"; + } + error(location, errorMsg, "location"); + } +} + +void TParseContext::checkStd430IsForShaderStorageBlock(const TSourceLoc &location, + const TLayoutBlockStorage &blockStorage, + const TQualifier &qualifier) +{ + if (blockStorage == EbsStd430 && qualifier != EvqBuffer) + { + error(location, "The std430 layout is supported only for shader storage blocks.", "std430"); + } +} + +void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line, + TQualifier qualifier, + const TType &type) +{ + ASSERT(qualifier == EvqOut || qualifier == EvqInOut); + if (IsOpaqueType(type.getBasicType())) + { + error(line, "opaque types cannot be output parameters", type.getBasicString()); + } +} + +// Do size checking for an array type's size. +unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr) +{ + TIntermConstantUnion *constant = expr->getAsConstantUnion(); + + // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be + // safe against corner cases we still check for constant folding. Some interpretations of the + // spec have allowed constant expressions with side effects - like array length() method on a + // non-constant array. + if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt()) + { + error(line, "array size must be a constant integer expression", ""); + return 1u; + } + + unsigned int size = 0u; + + if (constant->getBasicType() == EbtUInt) + { + size = constant->getUConst(0); + } + else + { + int signedSize = constant->getIConst(0); + + if (signedSize < 0) + { + error(line, "array size must be non-negative", ""); + return 1u; + } + + size = static_cast<unsigned int>(signedSize); + } + + if (size == 0u) + { + error(line, "array size must be greater than zero", ""); + return 1u; + } + + // The size of arrays is restricted here to prevent issues further down the + // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to + // 4096 registers so this should be reasonable even for aggressively optimizable code. + const unsigned int sizeLimit = 65536; + + if (size > sizeLimit) + { + error(line, "array size too large", ""); + return 1u; + } + + return size; +} + +// See if this qualifier can be an array. +bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line, + const TPublicType &elementQualifier) +{ + if ((elementQualifier.qualifier == EvqAttribute) || + (elementQualifier.qualifier == EvqVertexIn) || + (elementQualifier.qualifier == EvqConst && mShaderVersion < 300)) + { + error(line, "cannot declare arrays of this qualifier", + TType(elementQualifier).getQualifierString()); + return false; + } + + return true; +} + +// See if this element type can be formed into an array. +bool TParseContext::checkArrayElementIsNotArray(const TSourceLoc &line, + const TPublicType &elementType) +{ + if (mShaderVersion < 310 && elementType.isArray()) + { + TInfoSinkBase typeString; + typeString << TType(elementType); + error(line, "cannot declare arrays of arrays", typeString.c_str()); + return false; + } + return true; +} + +// Check if this qualified element type can be formed into an array. This is only called when array +// brackets are associated with an identifier in a declaration, like this: +// float a[2]; +// Similar checks are done in addFullySpecifiedType for array declarations where the array brackets +// are associated with the type, like this: +// float[2] a; +bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, + const TPublicType &elementType) +{ + if (!checkArrayElementIsNotArray(indexLocation, elementType)) + { + return false; + } + // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere. + // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section + // 4.3.4). + // Geometry shader requires each user-defined input be declared as arrays or inside input + // blocks declared as arrays (GL_EXT_geometry_shader section 11.1gs.4.3). For the purposes of + // interface matching, such variables and blocks are treated as though they were not declared + // as arrays (GL_EXT_geometry_shader section 7.4.1). + if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct && + sh::IsVarying(elementType.qualifier) && + !IsGeometryShaderInput(mShaderType, elementType.qualifier)) + { + TInfoSinkBase typeString; + typeString << TType(elementType); + error(indexLocation, "cannot declare arrays of structs of this qualifier", + typeString.c_str()); + return false; + } + return checkIsValidQualifierForArray(indexLocation, elementType); +} + +// Enforce non-initializer type/qualifier rules. +void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, + const ImmutableString &identifier, + TType *type) +{ + ASSERT(type != nullptr); + if (type->getQualifier() == EvqConst) + { + // Make the qualifier make sense. + type->setQualifier(EvqTemporary); + + // Generate informative error messages for ESSL1. + // In ESSL3 arrays and structures containing arrays can be constant. + if (mShaderVersion < 300 && type->isStructureContainingArrays()) + { + error(line, + "structures containing arrays may not be declared constant since they cannot be " + "initialized", + identifier); + } + else + { + error(line, "variables with qualifier 'const' must be initialized", identifier); + } + } + // This will make the type sized if it isn't sized yet. + checkIsNotUnsizedArray(line, "implicitly sized arrays need to be initialized", identifier, + type); +} + +// Do some simple checks that are shared between all variable declarations, +// and update the symbol table. +// +// Returns true if declaring the variable succeeded. +// +bool TParseContext::declareVariable(const TSourceLoc &line, + const ImmutableString &identifier, + const TType *type, + TVariable **variable) +{ + ASSERT((*variable) == nullptr); + + (*variable) = new TVariable(&symbolTable, identifier, type, SymbolType::UserDefined); + + ASSERT(type->getLayoutQualifier().index == -1 || + (isExtensionEnabled(TExtension::EXT_blend_func_extended) && + mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300)); + if (type->getQualifier() == EvqFragmentOut) + { + if (type->getLayoutQualifier().index != -1 && type->getLayoutQualifier().location == -1) + { + error(line, + "If index layout qualifier is specified for a fragment output, location must " + "also be specified.", + "index"); + return false; + } + } + else + { + checkIndexIsNotSpecified(line, type->getLayoutQualifier().index); + } + + checkBindingIsValid(line, *type); + + bool needsReservedCheck = true; + + // gl_LastFragData may be redeclared with a new precision qualifier + if (type->isArray() && identifier.beginsWith("gl_LastFragData")) + { + const TVariable *maxDrawBuffers = static_cast<const TVariable *>( + symbolTable.findBuiltIn(ImmutableString("gl_MaxDrawBuffers"), mShaderVersion)); + if (type->isArrayOfArrays()) + { + error(line, "redeclaration of gl_LastFragData as an array of arrays", identifier); + return false; + } + else if (static_cast<int>(type->getOutermostArraySize()) == + maxDrawBuffers->getConstPointer()->getIConst()) + { + if (const TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion)) + { + needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->extension()); + } + } + else + { + error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers", + identifier); + return false; + } + } + + if (needsReservedCheck && !checkIsNotReserved(line, identifier)) + return false; + + if (!symbolTable.declare(*variable)) + { + error(line, "redefinition", identifier); + return false; + } + + if (!checkIsNonVoid(line, identifier, type->getBasicType())) + return false; + + return true; +} + +void TParseContext::checkIsParameterQualifierValid( + const TSourceLoc &line, + const TTypeQualifierBuilder &typeQualifierBuilder, + TType *type) +{ + // The only parameter qualifiers a parameter can have are in, out, inout or const. + TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics); + + if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut) + { + checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type); + } + + if (!IsImage(type->getBasicType())) + { + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, line); + } + else + { + type->setMemoryQualifier(typeQualifier.memoryQualifier); + } + + type->setQualifier(typeQualifier.qualifier); + + if (typeQualifier.precision != EbpUndefined) + { + type->setPrecision(typeQualifier.precision); + } +} + +template <size_t size> +bool TParseContext::checkCanUseOneOfExtensions(const TSourceLoc &line, + const std::array<TExtension, size> &extensions) +{ + ASSERT(!extensions.empty()); + const TExtensionBehavior &extBehavior = extensionBehavior(); + + bool canUseWithWarning = false; + bool canUseWithoutWarning = false; + + const char *errorMsgString = ""; + TExtension errorMsgExtension = TExtension::UNDEFINED; + + for (TExtension extension : extensions) + { + auto extIter = extBehavior.find(extension); + if (canUseWithWarning) + { + // We already have an extension that we can use, but with a warning. + // See if we can use the alternative extension without a warning. + if (extIter == extBehavior.end()) + { + continue; + } + if (extIter->second == EBhEnable || extIter->second == EBhRequire) + { + canUseWithoutWarning = true; + break; + } + continue; + } + if (extIter == extBehavior.end()) + { + errorMsgString = "extension is not supported"; + errorMsgExtension = extension; + } + else if (extIter->second == EBhUndefined || extIter->second == EBhDisable) + { + errorMsgString = "extension is disabled"; + errorMsgExtension = extension; + } + else if (extIter->second == EBhWarn) + { + errorMsgExtension = extension; + canUseWithWarning = true; + } + else + { + ASSERT(extIter->second == EBhEnable || extIter->second == EBhRequire); + canUseWithoutWarning = true; + break; + } + } + + if (canUseWithoutWarning) + { + return true; + } + if (canUseWithWarning) + { + warning(line, "extension is being used", GetExtensionNameString(errorMsgExtension)); + return true; + } + error(line, errorMsgString, GetExtensionNameString(errorMsgExtension)); + return false; +} + +template bool TParseContext::checkCanUseOneOfExtensions( + const TSourceLoc &line, + const std::array<TExtension, 1> &extensions); +template bool TParseContext::checkCanUseOneOfExtensions( + const TSourceLoc &line, + const std::array<TExtension, 2> &extensions); +template bool TParseContext::checkCanUseOneOfExtensions( + const TSourceLoc &line, + const std::array<TExtension, 3> &extensions); + +bool TParseContext::checkCanUseExtension(const TSourceLoc &line, TExtension extension) +{ + ASSERT(extension != TExtension::UNDEFINED); + return checkCanUseOneOfExtensions(line, std::array<TExtension, 1u>{{extension}}); +} + +// ESSL 3.00.6 section 4.8 Empty Declarations: "The combinations of qualifiers that cause +// compile-time or link-time errors are the same whether or not the declaration is empty". +// This function implements all the checks that are done on qualifiers regardless of if the +// declaration is empty. +void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifier, + const sh::TLayoutQualifier &layoutQualifier, + const TSourceLoc &location) +{ + if (qualifier == EvqShared && !layoutQualifier.isEmpty()) + { + error(location, "Shared memory declarations cannot have layout specified", "layout"); + } + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + error(location, "layout qualifier only valid for interface blocks", + getMatrixPackingString(layoutQualifier.matrixPacking)); + return; + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + error(location, "layout qualifier only valid for interface blocks", + getBlockStorageString(layoutQualifier.blockStorage)); + return; + } + + if (qualifier == EvqFragmentOut) + { + if (layoutQualifier.location != -1 && layoutQualifier.yuv == true) + { + error(location, "invalid layout qualifier combination", "yuv"); + return; + } + } + else + { + checkYuvIsNotSpecified(location, layoutQualifier.yuv); + } + + // If multiview extension is enabled, "in" qualifier is allowed in the vertex shader in previous + // parsing steps. So it needs to be checked here. + if (anyMultiviewExtensionAvailable() && mShaderVersion < 300 && qualifier == EvqVertexIn) + { + error(location, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); + } + + bool canHaveLocation = qualifier == EvqVertexIn || qualifier == EvqFragmentOut; + if (mShaderVersion >= 310) + { + canHaveLocation = canHaveLocation || qualifier == EvqUniform || IsVarying(qualifier); + // We're not checking whether the uniform location is in range here since that depends on + // the type of the variable. + // The type can only be fully determined for non-empty declarations. + } + if (!canHaveLocation) + { + checkLocationIsNotSpecified(location, layoutQualifier); + } +} + +void TParseContext::atomicCounterQualifierErrorCheck(const TPublicType &publicType, + const TSourceLoc &location) +{ + if (publicType.precision != EbpHigh) + { + error(location, "Can only be highp", "atomic counter"); + } + // dEQP enforces compile error if location is specified. See uniform_location.test. + if (publicType.layoutQualifier.location != -1) + { + error(location, "location must not be set for atomic_uint", "layout"); + } + if (publicType.layoutQualifier.binding == -1) + { + error(location, "no binding specified", "atomic counter"); + } +} + +void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location) +{ + if (type.isUnsizedArray()) + { + // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an + // error. It is assumed that this applies to empty declarations as well. + error(location, "empty array declaration needs to specify a size", ""); + } + + if (type.getQualifier() != EvqFragmentOut) + { + checkIndexIsNotSpecified(location, type.getLayoutQualifier().index); + } +} + +// These checks are done for all declarations that are non-empty. They're done for non-empty +// declarations starting a declarator list, and declarators that follow an empty declaration. +void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType, + const TSourceLoc &identifierLocation) +{ + switch (publicType.qualifier) + { + case EvqVaryingIn: + case EvqVaryingOut: + case EvqAttribute: + case EvqVertexIn: + case EvqFragmentOut: + case EvqComputeIn: + if (publicType.getBasicType() == EbtStruct) + { + error(identifierLocation, "cannot be used with a structure", + getQualifierString(publicType.qualifier)); + return; + } + break; + case EvqBuffer: + if (publicType.getBasicType() != EbtInterfaceBlock) + { + error(identifierLocation, + "cannot declare buffer variables at global scope(outside a block)", + getQualifierString(publicType.qualifier)); + return; + } + break; + default: + break; + } + std::string reason(getBasicString(publicType.getBasicType())); + reason += "s must be uniform"; + if (publicType.qualifier != EvqUniform && + !checkIsNotOpaqueType(identifierLocation, publicType.typeSpecifierNonArray, reason.c_str())) + { + return; + } + + if ((publicType.qualifier != EvqTemporary && publicType.qualifier != EvqGlobal && + publicType.qualifier != EvqConst) && + publicType.getBasicType() == EbtYuvCscStandardEXT) + { + error(identifierLocation, "cannot be used with a yuvCscStandardEXT", + getQualifierString(publicType.qualifier)); + return; + } + + if (mShaderVersion >= 310 && publicType.qualifier == EvqUniform) + { + // Valid uniform declarations can't be unsized arrays since uniforms can't be initialized. + // But invalid shaders may still reach here with an unsized array declaration. + TType type(publicType); + if (!type.isUnsizedArray()) + { + checkUniformLocationInRange(identifierLocation, type.getLocationCount(), + publicType.layoutQualifier); + } + } + + // check for layout qualifier issues + const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; + + if (IsImage(publicType.getBasicType())) + { + + switch (layoutQualifier.imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + case EiifRGBA8: + case EiifRGBA8_SNORM: + if (!IsFloatImage(publicType.getBasicType())) + { + error(identifierLocation, + "internal image format requires a floating image type", + getBasicString(publicType.getBasicType())); + return; + } + break; + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + if (!IsIntegerImage(publicType.getBasicType())) + { + error(identifierLocation, + "internal image format requires an integer image type", + getBasicString(publicType.getBasicType())); + return; + } + break; + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + if (!IsUnsignedImage(publicType.getBasicType())) + { + error(identifierLocation, + "internal image format requires an unsigned image type", + getBasicString(publicType.getBasicType())); + return; + } + break; + case EiifUnspecified: + error(identifierLocation, "layout qualifier", "No image internal format specified"); + return; + default: + error(identifierLocation, "layout qualifier", "unrecognized token"); + return; + } + + // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers + switch (layoutQualifier.imageInternalFormat) + { + case EiifR32F: + case EiifR32I: + case EiifR32UI: + break; + default: + if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly) + { + error(identifierLocation, "layout qualifier", + "Except for images with the r32f, r32i and r32ui format qualifiers, " + "image variables must be qualified readonly and/or writeonly"); + return; + } + break; + } + } + else + { + checkInternalFormatIsNotSpecified(identifierLocation, layoutQualifier.imageInternalFormat); + checkMemoryQualifierIsNotSpecified(publicType.memoryQualifier, identifierLocation); + } + + if (IsAtomicCounter(publicType.getBasicType())) + { + atomicCounterQualifierErrorCheck(publicType, identifierLocation); + } + else + { + checkOffsetIsNotSpecified(identifierLocation, layoutQualifier.offset); + } +} + +void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type) +{ + TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); + // Note that the ESSL 3.10 section 4.4.5 is not particularly clear on how the binding qualifier + // on arrays of arrays should be handled. We interpret the spec so that the binding value is + // incremented for each element of the innermost nested arrays. This is in line with how arrays + // of arrays of blocks are specified to behave in GLSL 4.50 and a conservative interpretation + // when it comes to which shaders are accepted by the compiler. + int arrayTotalElementCount = type.getArraySizeProduct(); + if (IsImage(type.getBasicType())) + { + checkImageBindingIsValid(identifierLocation, layoutQualifier.binding, + arrayTotalElementCount); + } + else if (IsSampler(type.getBasicType())) + { + checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding, + arrayTotalElementCount); + } + else if (IsAtomicCounter(type.getBasicType())) + { + checkAtomicCounterBindingIsValid(identifierLocation, layoutQualifier.binding); + } + else + { + ASSERT(!IsOpaqueType(type.getBasicType())); + checkBindingIsNotSpecified(identifierLocation, layoutQualifier.binding); + } +} + +void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location, + const ImmutableString &layoutQualifierName, + int versionRequired) +{ + + if (mShaderVersion < versionRequired) + { + error(location, "invalid layout qualifier: not supported", layoutQualifierName); + } +} + +bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier) +{ + const sh::WorkGroupSize &localSize = layoutQualifier.localSize; + for (size_t i = 0u; i < localSize.size(); ++i) + { + if (localSize[i] != -1) + { + error(location, + "invalid layout qualifier: only valid when used with 'in' in a compute shader " + "global layout declaration", + getWorkGroupSizeString(i)); + return false; + } + } + + return true; +} + +void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location, + TLayoutImageInternalFormat internalFormat) +{ + if (internalFormat != EiifUnspecified) + { + error(location, "invalid layout qualifier: only valid when used with images", + getImageInternalFormatString(internalFormat)); + } +} + +void TParseContext::checkIndexIsNotSpecified(const TSourceLoc &location, int index) +{ + if (index != -1) + { + error(location, + "invalid layout qualifier: only valid when used with a fragment shader output in " + "ESSL version >= 3.00 and EXT_blend_func_extended is enabled", + "index"); + } +} + +void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding) +{ + if (binding != -1) + { + error(location, + "invalid layout qualifier: only valid when used with opaque types or blocks", + "binding"); + } +} + +void TParseContext::checkOffsetIsNotSpecified(const TSourceLoc &location, int offset) +{ + if (offset != -1) + { + error(location, "invalid layout qualifier: only valid when used with atomic counters", + "offset"); + } +} + +void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount) +{ + // Expects arraySize to be 1 when setting binding for only a single variable. + if (binding >= 0 && binding + arrayTotalElementCount > mMaxImageUnits) + { + error(location, "image binding greater than gl_MaxImageUnits", "binding"); + } +} + +void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount) +{ + // Expects arraySize to be 1 when setting binding for only a single variable. + if (binding >= 0 && binding + arrayTotalElementCount > mMaxCombinedTextureImageUnits) + { + error(location, "sampler binding greater than maximum texture units", "binding"); + } +} + +void TParseContext::checkBlockBindingIsValid(const TSourceLoc &location, + const TQualifier &qualifier, + int binding, + int arraySize) +{ + int size = (arraySize == 0 ? 1 : arraySize); + if (qualifier == EvqUniform) + { + if (binding + size > mMaxUniformBufferBindings) + { + error(location, "uniform block binding greater than MAX_UNIFORM_BUFFER_BINDINGS", + "binding"); + } + } + else if (qualifier == EvqBuffer) + { + if (binding + size > mMaxShaderStorageBufferBindings) + { + error(location, + "shader storage block binding greater than MAX_SHADER_STORAGE_BUFFER_BINDINGS", + "binding"); + } + } +} +void TParseContext::checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding) +{ + if (binding >= mMaxAtomicCounterBindings) + { + error(location, "atomic counter binding greater than gl_MaxAtomicCounterBindings", + "binding"); + } +} + +void TParseContext::checkUniformLocationInRange(const TSourceLoc &location, + int objectLocationCount, + const TLayoutQualifier &layoutQualifier) +{ + int loc = layoutQualifier.location; + if (loc >= 0 && loc + objectLocationCount > mMaxUniformLocations) + { + error(location, "Uniform location out of range", "location"); + } +} + +void TParseContext::checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv) +{ + if (yuv != false) + { + error(location, "invalid layout qualifier: only valid on program outputs", "yuv"); + } +} + +void TParseContext::functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, + TIntermAggregate *fnCall) +{ + for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) + { + TQualifier qual = fnCandidate->getParam(i)->getType().getQualifier(); + TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped(); + bool argumentIsRead = (IsQualifierUnspecified(qual) || qual == EvqIn || qual == EvqInOut || + qual == EvqConstReadOnly); + if (argumentIsRead) + { + markStaticReadIfSymbol(argument); + if (!IsImage(argument->getBasicType())) + { + if (argument->getMemoryQualifier().writeonly) + { + error(argument->getLine(), + "Writeonly value cannot be passed for 'in' or 'inout' parameters.", + fnCall->functionName()); + return; + } + } + } + if (qual == EvqOut || qual == EvqInOut) + { + if (!checkCanBeLValue(argument->getLine(), "assign", argument)) + { + error(argument->getLine(), + "Constant value cannot be passed for 'out' or 'inout' parameters.", + fnCall->functionName()); + return; + } + } + } +} + +void TParseContext::checkInvariantVariableQualifier(bool invariant, + const TQualifier qualifier, + const TSourceLoc &invariantLocation) +{ + if (!invariant) + return; + + if (mShaderVersion < 300) + { + // input variables in the fragment shader can be also qualified as invariant + if (!sh::CanBeInvariantESSL1(qualifier)) + { + error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); + } + } + else + { + if (!sh::CanBeInvariantESSL3OrGreater(qualifier)) + { + error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); + } + } +} + +bool TParseContext::isExtensionEnabled(TExtension extension) const +{ + return IsExtensionEnabled(extensionBehavior(), extension); +} + +void TParseContext::handleExtensionDirective(const TSourceLoc &loc, + const char *extName, + const char *behavior) +{ + angle::pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + mDirectiveHandler.handleExtension(srcLoc, extName, behavior); +} + +void TParseContext::handlePragmaDirective(const TSourceLoc &loc, + const char *name, + const char *value, + bool stdgl) +{ + angle::pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl); +} + +sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const +{ + sh::WorkGroupSize result(-1); + for (size_t i = 0u; i < result.size(); ++i) + { + if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1) + { + result[i] = 1; + } + else + { + result[i] = mComputeShaderLocalSize[i]; + } + } + return result; +} + +TIntermConstantUnion *TParseContext::addScalarLiteral(const TConstantUnion *constantUnion, + const TSourceLoc &line) +{ + TIntermConstantUnion *node = new TIntermConstantUnion( + constantUnion, TType(constantUnion->getType(), EbpUndefined, EvqConst)); + node->setLine(line); + return node; +} + +///////////////////////////////////////////////////////////////////////////////// +// +// Non-Errors. +// +///////////////////////////////////////////////////////////////////////////////// + +const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, + const ImmutableString &name, + const TSymbol *symbol) +{ + if (!symbol) + { + error(location, "undeclared identifier", name); + return nullptr; + } + + if (!symbol->isVariable()) + { + error(location, "variable expected", name); + return nullptr; + } + + const TVariable *variable = static_cast<const TVariable *>(symbol); + + if (variable->extension() != TExtension::UNDEFINED) + { + checkCanUseExtension(location, variable->extension()); + } + + // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables + if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared && + variable->getType().getQualifier() == EvqWorkGroupSize) + { + error(location, + "It is an error to use gl_WorkGroupSize before declaring the local group size", + "gl_WorkGroupSize"); + } + return variable; +} + +TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location, + const ImmutableString &name, + const TSymbol *symbol) +{ + const TVariable *variable = getNamedVariable(location, name, symbol); + + if (!variable) + { + TIntermTyped *node = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); + node->setLine(location); + return node; + } + + const TType &variableType = variable->getType(); + TIntermTyped *node = nullptr; + + if (variable->getConstPointer() && variableType.canReplaceWithConstantUnion()) + { + const TConstantUnion *constArray = variable->getConstPointer(); + node = new TIntermConstantUnion(constArray, variableType); + } + else if (variableType.getQualifier() == EvqWorkGroupSize && mComputeShaderLocalSizeDeclared) + { + // gl_WorkGroupSize can be used to size arrays according to the ESSL 3.10.4 spec, so it + // needs to be added to the AST as a constant and not as a symbol. + sh::WorkGroupSize workGroupSize = getComputeShaderLocalSize(); + TConstantUnion *constArray = new TConstantUnion[3]; + for (size_t i = 0; i < 3; ++i) + { + constArray[i].setUConst(static_cast<unsigned int>(workGroupSize[i])); + } + + ASSERT(variableType.getBasicType() == EbtUInt); + ASSERT(variableType.getObjectSize() == 3); + + TType type(variableType); + type.setQualifier(EvqConst); + node = new TIntermConstantUnion(constArray, type); + } + else if ((mGeometryShaderInputPrimitiveType != EptUndefined) && + (variableType.getQualifier() == EvqPerVertexIn)) + { + ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr); + node = new TIntermSymbol(symbolTable.getGlInVariableWithArraySize()); + } + else + { + node = new TIntermSymbol(variable); + } + ASSERT(node != nullptr); + node->setLine(location); + return node; +} + +// Initializers show up in several places in the grammar. Have one set of +// code to handle them here. +// +// Returns true on success. +bool TParseContext::executeInitializer(const TSourceLoc &line, + const ImmutableString &identifier, + TType *type, + TIntermTyped *initializer, + TIntermBinary **initNode) +{ + ASSERT(initNode != nullptr); + ASSERT(*initNode == nullptr); + + if (type->isUnsizedArray()) + { + // In case initializer is not an array or type has more dimensions than initializer, this + // will default to setting array sizes to 1. We have not checked yet whether the initializer + // actually is an array or not. Having a non-array initializer for an unsized array will + // result in an error later, so we don't generate an error message here. + auto *arraySizes = initializer->getType().getArraySizes(); + type->sizeUnsizedArrays(arraySizes); + } + + const TQualifier qualifier = type->getQualifier(); + + bool constError = false; + if (qualifier == EvqConst) + { + if (EvqConst != initializer->getType().getQualifier()) + { + TInfoSinkBase reasonStream; + reasonStream << "assigning non-constant to '" << *type << "'"; + error(line, reasonStream.c_str(), "="); + + // We're still going to declare the variable to avoid extra error messages. + type->setQualifier(EvqTemporary); + constError = true; + } + } + + TVariable *variable = nullptr; + if (!declareVariable(line, identifier, type, &variable)) + { + return false; + } + + if (constError) + { + return false; + } + + bool globalInitWarning = false; + if (symbolTable.atGlobalLevel() && + !ValidateGlobalInitializer(initializer, mShaderVersion, &globalInitWarning)) + { + // Error message does not completely match behavior with ESSL 1.00, but + // we want to steer developers towards only using constant expressions. + error(line, "global variable initializers must be constant expressions", "="); + return false; + } + if (globalInitWarning) + { + warning( + line, + "global variable initializers should be constant expressions " + "(uniforms and globals are allowed in global initializers for legacy compatibility)", + "="); + } + + // identifier must be of type constant, a global, or a temporary + if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) + { + error(line, " cannot initialize this type of qualifier ", + variable->getType().getQualifierString()); + return false; + } + + TIntermSymbol *intermSymbol = new TIntermSymbol(variable); + intermSymbol->setLine(line); + + if (!binaryOpCommonCheck(EOpInitialize, intermSymbol, initializer, line)) + { + assignError(line, "=", variable->getType(), initializer->getType()); + return false; + } + + if (qualifier == EvqConst) + { + // Save the constant folded value to the variable if possible. + const TConstantUnion *constArray = initializer->getConstantValue(); + if (constArray) + { + variable->shareConstPointer(constArray); + if (initializer->getType().canReplaceWithConstantUnion()) + { + ASSERT(*initNode == nullptr); + return true; + } + } + } + + *initNode = new TIntermBinary(EOpInitialize, intermSymbol, initializer); + markStaticReadIfSymbol(initializer); + (*initNode)->setLine(line); + return true; +} + +TIntermNode *TParseContext::addConditionInitializer(const TPublicType &pType, + const ImmutableString &identifier, + TIntermTyped *initializer, + const TSourceLoc &loc) +{ + checkIsScalarBool(loc, pType); + TIntermBinary *initNode = nullptr; + TType *type = new TType(pType); + if (executeInitializer(loc, identifier, type, initializer, &initNode)) + { + // The initializer is valid. The init condition needs to have a node - either the + // initializer node, or a constant node in case the initialized variable is const and won't + // be recorded in the AST. + if (initNode == nullptr) + { + return initializer; + } + else + { + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->appendDeclarator(initNode); + return declaration; + } + } + return nullptr; +} + +TIntermNode *TParseContext::addLoop(TLoopType type, + TIntermNode *init, + TIntermNode *cond, + TIntermTyped *expr, + TIntermNode *body, + const TSourceLoc &line) +{ + TIntermNode *node = nullptr; + TIntermTyped *typedCond = nullptr; + if (cond) + { + markStaticReadIfSymbol(cond); + typedCond = cond->getAsTyped(); + } + if (expr) + { + markStaticReadIfSymbol(expr); + } + // In case the loop body was not parsed as a block and contains a statement that simply refers + // to a variable, we need to mark it as statically used. + if (body) + { + markStaticReadIfSymbol(body); + } + if (cond == nullptr || typedCond) + { + if (type == ELoopDoWhile) + { + checkIsScalarBool(line, typedCond); + } + // In the case of other loops, it was checked before that the condition is a scalar boolean. + ASSERT(mDiagnostics->numErrors() > 0 || typedCond == nullptr || + (typedCond->getBasicType() == EbtBool && !typedCond->isArray() && + !typedCond->isVector())); + + node = new TIntermLoop(type, init, typedCond, expr, EnsureBlock(body)); + node->setLine(line); + return node; + } + + ASSERT(type != ELoopDoWhile); + + TIntermDeclaration *declaration = cond->getAsDeclarationNode(); + ASSERT(declaration); + TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode(); + ASSERT(declarator->getLeft()->getAsSymbolNode()); + + // The condition is a declaration. In the AST representation we don't support declarations as + // loop conditions. Wrap the loop to a block that declares the condition variable and contains + // the loop. + TIntermBlock *block = new TIntermBlock(); + + TIntermDeclaration *declareCondition = new TIntermDeclaration(); + declareCondition->appendDeclarator(declarator->getLeft()->deepCopy()); + block->appendStatement(declareCondition); + + TIntermBinary *conditionInit = new TIntermBinary(EOpAssign, declarator->getLeft()->deepCopy(), + declarator->getRight()->deepCopy()); + TIntermLoop *loop = new TIntermLoop(type, init, conditionInit, expr, EnsureBlock(body)); + block->appendStatement(loop); + loop->setLine(line); + block->setLine(line); + return block; +} + +TIntermNode *TParseContext::addIfElse(TIntermTyped *cond, + TIntermNodePair code, + const TSourceLoc &loc) +{ + bool isScalarBool = checkIsScalarBool(loc, cond); + // In case the conditional statements were not parsed as blocks and contain a statement that + // simply refers to a variable, we need to mark them as statically used. + if (code.node1) + { + markStaticReadIfSymbol(code.node1); + } + if (code.node2) + { + markStaticReadIfSymbol(code.node2); + } + + // For compile time constant conditions, prune the code now. + if (isScalarBool && cond->getAsConstantUnion()) + { + if (cond->getAsConstantUnion()->getBConst(0) == true) + { + return EnsureBlock(code.node1); + } + else + { + return EnsureBlock(code.node2); + } + } + + TIntermIfElse *node = new TIntermIfElse(cond, EnsureBlock(code.node1), EnsureBlock(code.node2)); + markStaticReadIfSymbol(cond); + node->setLine(loc); + + return node; +} + +void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier) +{ + checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision, + typeSpecifier->getBasicType()); + + if (mShaderVersion < 300 && typeSpecifier->isArray()) + { + error(typeSpecifier->getLine(), "not supported", "first-class array"); + typeSpecifier->clearArrayness(); + } +} + +TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, + const TPublicType &typeSpecifier) +{ + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + + TPublicType returnType = typeSpecifier; + returnType.qualifier = typeQualifier.qualifier; + returnType.invariant = typeQualifier.invariant; + returnType.layoutQualifier = typeQualifier.layoutQualifier; + returnType.memoryQualifier = typeQualifier.memoryQualifier; + returnType.precision = typeSpecifier.precision; + + if (typeQualifier.precision != EbpUndefined) + { + returnType.precision = typeQualifier.precision; + } + + checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision, + typeSpecifier.getBasicType()); + + checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier, + typeSpecifier.getLine()); + + checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier); + + if (mShaderVersion < 300) + { + if (typeSpecifier.isArray()) + { + error(typeSpecifier.getLine(), "not supported", "first-class array"); + returnType.clearArrayness(); + } + + if (returnType.qualifier == EvqAttribute && + (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) + { + error(typeSpecifier.getLine(), "cannot be bool or int", + getQualifierString(returnType.qualifier)); + } + + if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) && + (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) + { + error(typeSpecifier.getLine(), "cannot be bool or int", + getQualifierString(returnType.qualifier)); + } + } + else + { + if (!returnType.layoutQualifier.isEmpty()) + { + checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout"); + } + if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || + returnType.qualifier == EvqFragmentOut) + { + checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, + typeSpecifier.getLine()); + } + if (returnType.qualifier == EvqComputeIn) + { + error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size", + "in"); + } + } + + return returnType; +} + +void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier, + const TPublicType &type, + const TSourceLoc &qualifierLocation) +{ + // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere. + if (type.getBasicType() == EbtBool) + { + error(qualifierLocation, "cannot be bool", getQualifierString(qualifier)); + } + + // Specific restrictions apply for vertex shader inputs and fragment shader outputs. + switch (qualifier) + { + case EvqVertexIn: + // ESSL 3.00 section 4.3.4 + if (type.isArray()) + { + error(qualifierLocation, "cannot be array", getQualifierString(qualifier)); + } + // Vertex inputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck + return; + case EvqFragmentOut: + // ESSL 3.00 section 4.3.6 + if (type.typeSpecifierNonArray.isMatrix()) + { + error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier)); + } + // Fragment outputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck + return; + default: + break; + } + + // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of + // restrictions. + bool typeContainsIntegers = + (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt || + type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt)); + if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut) + { + error(qualifierLocation, "must use 'flat' interpolation here", + getQualifierString(qualifier)); + } + + if (type.getBasicType() == EbtStruct) + { + // ESSL 3.00 sections 4.3.4 and 4.3.6. + // These restrictions are only implied by the ESSL 3.00 spec, but + // the ESSL 3.10 spec lists these restrictions explicitly. + if (type.isArray()) + { + error(qualifierLocation, "cannot be an array of structures", + getQualifierString(qualifier)); + } + if (type.isStructureContainingArrays()) + { + error(qualifierLocation, "cannot be a structure containing an array", + getQualifierString(qualifier)); + } + if (type.isStructureContainingType(EbtStruct)) + { + error(qualifierLocation, "cannot be a structure containing a structure", + getQualifierString(qualifier)); + } + if (type.isStructureContainingType(EbtBool)) + { + error(qualifierLocation, "cannot be a structure containing a bool", + getQualifierString(qualifier)); + } + } +} + +void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier) +{ + if (qualifier.getType() == QtStorage) + { + const TStorageQualifierWrapper &storageQualifier = + static_cast<const TStorageQualifierWrapper &>(qualifier); + if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst && + !symbolTable.atGlobalLevel()) + { + error(storageQualifier.getLine(), + "Local variables can only use the const storage qualifier.", + storageQualifier.getQualifierString()); + } + } +} + +void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier, + const TSourceLoc &location) +{ + const std::string reason( + "Only allowed with shader storage blocks, variables declared within shader storage blocks " + "and variables declared as image types."); + if (memoryQualifier.readonly) + { + error(location, reason.c_str(), "readonly"); + } + if (memoryQualifier.writeonly) + { + error(location, reason.c_str(), "writeonly"); + } + if (memoryQualifier.coherent) + { + error(location, reason.c_str(), "coherent"); + } + if (memoryQualifier.restrictQualifier) + { + error(location, reason.c_str(), "restrict"); + } + if (memoryQualifier.volatileQualifier) + { + error(location, reason.c_str(), "volatile"); + } +} + +// Make sure there is no offset overlapping, and store the newly assigned offset to "type" in +// intermediate tree. +void TParseContext::checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend, + const TSourceLoc &loc, + TType *type) +{ + const size_t size = type->isArray() ? kAtomicCounterArrayStride * type->getArraySizeProduct() + : kAtomicCounterSize; + TLayoutQualifier layoutQualifier = type->getLayoutQualifier(); + auto &bindingState = mAtomicCounterBindingStates[layoutQualifier.binding]; + int offset; + if (layoutQualifier.offset == -1 || forceAppend) + { + offset = bindingState.appendSpan(size); + } + else + { + offset = bindingState.insertSpan(layoutQualifier.offset, size); + } + if (offset == -1) + { + error(loc, "Offset overlapping", "atomic counter"); + return; + } + layoutQualifier.offset = offset; + type->setLayoutQualifier(layoutQualifier); +} + +void TParseContext::checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type) +{ + TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); + + // OpenGL ES 3.1 Table 6.5, Atomic counter offset must be a multiple of 4 + if (layoutQualifier.offset % 4 != 0) + { + error(location, "Offset must be multiple of 4", "atomic counter"); + } +} + +void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location, + const ImmutableString &token, + TType *type) +{ + if (IsGeometryShaderInput(mShaderType, type->getQualifier())) + { + if (type->isArray() && type->getOutermostArraySize() == 0u) + { + // Set size for the unsized geometry shader inputs if they are declared after a valid + // input primitive declaration. + if (mGeometryShaderInputPrimitiveType != EptUndefined) + { + ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr); + type->sizeOutermostUnsizedArray( + symbolTable.getGlInVariableWithArraySize()->getType().getOutermostArraySize()); + } + else + { + // [GLSL ES 3.2 SPEC Chapter 4.4.1.2] + // An input can be declared without an array size if there is a previous layout + // which specifies the size. + error(location, + "Missing a valid input primitive declaration before declaring an unsized " + "array input", + token); + } + } + else if (type->isArray()) + { + setGeometryShaderInputArraySize(type->getOutermostArraySize(), location); + } + else + { + error(location, "Geometry shader input variable must be declared as an array", token); + } + } +} + +TIntermDeclaration *TParseContext::parseSingleDeclaration( + TPublicType &publicType, + const TSourceLoc &identifierOrTypeLocation, + const ImmutableString &identifier) +{ + TType *type = new TType(publicType); + if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) && + mDirectiveHandler.pragma().stdgl.invariantAll) + { + TQualifier qualifier = type->getQualifier(); + + // The directive handler has already taken care of rejecting invalid uses of this pragma + // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all + // affected variable declarations: + // + // 1. Built-in special variables which are inputs to the fragment shader. (These are handled + // elsewhere, in TranslatorGLSL.) + // + // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It + // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but + // the way this is currently implemented we have to enable this compiler option before + // parsing the shader and determining the shading language version it uses. If this were + // implemented as a post-pass, the workaround could be more targeted. + if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut) + { + type->setInvariant(true); + } + } + + checkGeometryShaderInputAndSetArraySize(identifierOrTypeLocation, identifier, type); + + declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, + identifierOrTypeLocation); + + bool emptyDeclaration = (identifier == ""); + mDeferredNonEmptyDeclarationErrorCheck = emptyDeclaration; + + TIntermSymbol *symbol = nullptr; + if (emptyDeclaration) + { + emptyDeclarationErrorCheck(*type, identifierOrTypeLocation); + // In most cases we don't need to create a symbol node for an empty declaration. + // But if the empty declaration is declaring a struct type, the symbol node will store that. + if (type->getBasicType() == EbtStruct) + { + TVariable *emptyVariable = + new TVariable(&symbolTable, kEmptyImmutableString, type, SymbolType::Empty); + symbol = new TIntermSymbol(emptyVariable); + } + else if (IsAtomicCounter(publicType.getBasicType())) + { + setAtomicCounterBindingDefaultOffset(publicType, identifierOrTypeLocation); + } + } + else + { + nonEmptyDeclarationErrorCheck(publicType, identifierOrTypeLocation); + + checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, type); + + if (IsAtomicCounter(type->getBasicType())) + { + checkAtomicCounterOffsetDoesNotOverlap(false, identifierOrTypeLocation, type); + + checkAtomicCounterOffsetAlignment(identifierOrTypeLocation, *type); + } + + TVariable *variable = nullptr; + if (declareVariable(identifierOrTypeLocation, identifier, type, &variable)) + { + symbol = new TIntermSymbol(variable); + } + } + + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierOrTypeLocation); + if (symbol) + { + symbol->setLine(identifierOrTypeLocation); + declaration->appendDeclarator(symbol); + } + return declaration; +} + +TIntermDeclaration *TParseContext::parseSingleArrayDeclaration( + TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &indexLocation, + const TVector<unsigned int> &arraySizes) +{ + mDeferredNonEmptyDeclarationErrorCheck = false; + + declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, + identifierLocation); + + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); + + checkIsValidTypeAndQualifierForArray(indexLocation, elementType); + + TType *arrayType = new TType(elementType); + arrayType->makeArrays(arraySizes); + + checkGeometryShaderInputAndSetArraySize(indexLocation, identifier, arrayType); + + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); + + if (IsAtomicCounter(arrayType->getBasicType())) + { + checkAtomicCounterOffsetDoesNotOverlap(false, identifierLocation, arrayType); + + checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType); + } + + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierLocation); + + TVariable *variable = nullptr; + if (declareVariable(identifierLocation, identifier, arrayType, &variable)) + { + TIntermSymbol *symbol = new TIntermSymbol(variable); + symbol->setLine(identifierLocation); + declaration->appendDeclarator(symbol); + } + + return declaration; +} + +TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &initLocation, + TIntermTyped *initializer) +{ + mDeferredNonEmptyDeclarationErrorCheck = false; + + declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, + identifierLocation); + + nonEmptyDeclarationErrorCheck(publicType, identifierLocation); + + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierLocation); + + TIntermBinary *initNode = nullptr; + TType *type = new TType(publicType); + if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) + { + if (initNode) + { + declaration->appendDeclarator(initNode); + } + } + return declaration; +} + +TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration( + TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &indexLocation, + const TVector<unsigned int> &arraySizes, + const TSourceLoc &initLocation, + TIntermTyped *initializer) +{ + mDeferredNonEmptyDeclarationErrorCheck = false; + + declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, + identifierLocation); + + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); + + checkIsValidTypeAndQualifierForArray(indexLocation, elementType); + + TType *arrayType = new TType(elementType); + arrayType->makeArrays(arraySizes); + + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->setLine(identifierLocation); + + // initNode will correspond to the whole of "type b[n] = initializer". + TIntermBinary *initNode = nullptr; + if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) + { + if (initNode) + { + declaration->appendDeclarator(initNode); + } + } + + return declaration; +} + +TIntermInvariantDeclaration *TParseContext::parseInvariantDeclaration( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &identifierLoc, + const ImmutableString &identifier, + const TSymbol *symbol) +{ + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + + if (!typeQualifier.invariant) + { + error(identifierLoc, "Expected invariant", identifier); + return nullptr; + } + if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying")) + { + return nullptr; + } + if (!symbol) + { + error(identifierLoc, "undeclared identifier declared as invariant", identifier); + return nullptr; + } + if (!IsQualifierUnspecified(typeQualifier.qualifier)) + { + error(identifierLoc, "invariant declaration specifies qualifier", + getQualifierString(typeQualifier.qualifier)); + } + if (typeQualifier.precision != EbpUndefined) + { + error(identifierLoc, "invariant declaration specifies precision", + getPrecisionString(typeQualifier.precision)); + } + if (!typeQualifier.layoutQualifier.isEmpty()) + { + error(identifierLoc, "invariant declaration specifies layout", "'layout'"); + } + + const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); + if (!variable) + { + return nullptr; + } + const TType &type = variable->getType(); + + checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(), + typeQualifier.line); + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); + + symbolTable.addInvariantVarying(*variable); + + TIntermSymbol *intermSymbol = new TIntermSymbol(variable); + intermSymbol->setLine(identifierLoc); + + return new TIntermInvariantDeclaration(intermSymbol, identifierLoc); +} + +void TParseContext::parseDeclarator(TPublicType &publicType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + TIntermDeclaration *declarationOut) +{ + // If the declaration starting this declarator list was empty (example: int,), some checks were + // not performed. + if (mDeferredNonEmptyDeclarationErrorCheck) + { + nonEmptyDeclarationErrorCheck(publicType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; + } + + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); + + TType *type = new TType(publicType); + + checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, type); + + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, type); + + if (IsAtomicCounter(type->getBasicType())) + { + checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, type); + + checkAtomicCounterOffsetAlignment(identifierLocation, *type); + } + + TVariable *variable = nullptr; + if (declareVariable(identifierLocation, identifier, type, &variable)) + { + TIntermSymbol *symbol = new TIntermSymbol(variable); + symbol->setLine(identifierLocation); + declarationOut->appendDeclarator(symbol); + } +} + +void TParseContext::parseArrayDeclarator(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &arrayLocation, + const TVector<unsigned int> &arraySizes, + TIntermDeclaration *declarationOut) +{ + // If the declaration starting this declarator list was empty (example: int,), some checks were + // not performed. + if (mDeferredNonEmptyDeclarationErrorCheck) + { + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; + } + + checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); + + if (checkIsValidTypeAndQualifierForArray(arrayLocation, elementType)) + { + TType *arrayType = new TType(elementType); + arrayType->makeArrays(arraySizes); + + checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, arrayType); + + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); + + if (IsAtomicCounter(arrayType->getBasicType())) + { + checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, arrayType); + + checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType); + } + + TVariable *variable = nullptr; + if (declareVariable(identifierLocation, identifier, arrayType, &variable)) + { + TIntermSymbol *symbol = new TIntermSymbol(variable); + symbol->setLine(identifierLocation); + declarationOut->appendDeclarator(symbol); + } + } +} + +void TParseContext::parseInitDeclarator(const TPublicType &publicType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut) +{ + // If the declaration starting this declarator list was empty (example: int,), some checks were + // not performed. + if (mDeferredNonEmptyDeclarationErrorCheck) + { + nonEmptyDeclarationErrorCheck(publicType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; + } + + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); + + TIntermBinary *initNode = nullptr; + TType *type = new TType(publicType); + if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) + { + // + // build the intermediate representation + // + if (initNode) + { + declarationOut->appendDeclarator(initNode); + } + } +} + +void TParseContext::parseArrayInitDeclarator(const TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &indexLocation, + const TVector<unsigned int> &arraySizes, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut) +{ + // If the declaration starting this declarator list was empty (example: int,), some checks were + // not performed. + if (mDeferredNonEmptyDeclarationErrorCheck) + { + nonEmptyDeclarationErrorCheck(elementType, identifierLocation); + mDeferredNonEmptyDeclarationErrorCheck = false; + } + + checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); + + checkIsValidTypeAndQualifierForArray(indexLocation, elementType); + + TType *arrayType = new TType(elementType); + arrayType->makeArrays(arraySizes); + + // initNode will correspond to the whole of "b[n] = initializer". + TIntermBinary *initNode = nullptr; + if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) + { + if (initNode) + { + declarationOut->appendDeclarator(initNode); + } + } +} + +TIntermNode *TParseContext::addEmptyStatement(const TSourceLoc &location) +{ + // It's simpler to parse an empty statement as a constant expression rather than having a + // different type of node just for empty statements, that will be pruned from the AST anyway. + TIntermNode *node = CreateZeroNode(TType(EbtInt, EbpMedium)); + node->setLine(location); + return node; +} + +void TParseContext::setAtomicCounterBindingDefaultOffset(const TPublicType &publicType, + const TSourceLoc &location) +{ + const TLayoutQualifier &layoutQualifier = publicType.layoutQualifier; + checkAtomicCounterBindingIsValid(location, layoutQualifier.binding); + if (layoutQualifier.binding == -1 || layoutQualifier.offset == -1) + { + error(location, "Requires both binding and offset", "layout"); + return; + } + mAtomicCounterBindingStates[layoutQualifier.binding].setDefaultOffset(layoutQualifier.offset); +} + +void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision, + const TPublicType &type, + const TSourceLoc &loc) +{ + if ((precision == EbpHigh) && (getShaderType() == GL_FRAGMENT_SHADER) && + !getFragmentPrecisionHigh()) + { + error(loc, "precision is not supported in fragment shader", "highp"); + } + + if (!CanSetDefaultPrecisionOnType(type)) + { + error(loc, "illegal type argument for default precision qualifier", + getBasicString(type.getBasicType())); + return; + } + symbolTable.setDefaultPrecision(type.getBasicType(), precision); +} + +bool TParseContext::checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier) +{ + switch (typeQualifier.layoutQualifier.primitiveType) + { + case EptLines: + case EptLinesAdjacency: + case EptTriangles: + case EptTrianglesAdjacency: + return typeQualifier.qualifier == EvqGeometryIn; + + case EptLineStrip: + case EptTriangleStrip: + return typeQualifier.qualifier == EvqGeometryOut; + + case EptPoints: + return true; + + default: + UNREACHABLE(); + return false; + } +} + +void TParseContext::setGeometryShaderInputArraySize(unsigned int inputArraySize, + const TSourceLoc &line) +{ + if (!symbolTable.setGlInArraySize(inputArraySize)) + { + error(line, + "Array size or input primitive declaration doesn't match the size of earlier sized " + "array inputs.", + "layout"); + } +} + +bool TParseContext::parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier) +{ + ASSERT(typeQualifier.qualifier == EvqGeometryIn); + + const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; + + if (layoutQualifier.maxVertices != -1) + { + error(typeQualifier.line, + "max_vertices can only be declared in 'out' layout in a geometry shader", "layout"); + return false; + } + + // Set mGeometryInputPrimitiveType if exists + if (layoutQualifier.primitiveType != EptUndefined) + { + if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) + { + error(typeQualifier.line, "invalid primitive type for 'in' layout", "layout"); + return false; + } + + if (mGeometryShaderInputPrimitiveType == EptUndefined) + { + mGeometryShaderInputPrimitiveType = layoutQualifier.primitiveType; + setGeometryShaderInputArraySize( + GetGeometryShaderInputArraySize(mGeometryShaderInputPrimitiveType), + typeQualifier.line); + } + else if (mGeometryShaderInputPrimitiveType != layoutQualifier.primitiveType) + { + error(typeQualifier.line, "primitive doesn't match earlier input primitive declaration", + "layout"); + return false; + } + } + + // Set mGeometryInvocations if exists + if (layoutQualifier.invocations > 0) + { + if (mGeometryShaderInvocations == 0) + { + mGeometryShaderInvocations = layoutQualifier.invocations; + } + else if (mGeometryShaderInvocations != layoutQualifier.invocations) + { + error(typeQualifier.line, "invocations contradicts to the earlier declaration", + "layout"); + return false; + } + } + + return true; +} + +bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier) +{ + ASSERT(typeQualifier.qualifier == EvqGeometryOut); + + const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; + + if (layoutQualifier.invocations > 0) + { + error(typeQualifier.line, + "invocations can only be declared in 'in' layout in a geometry shader", "layout"); + return false; + } + + // Set mGeometryOutputPrimitiveType if exists + if (layoutQualifier.primitiveType != EptUndefined) + { + if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) + { + error(typeQualifier.line, "invalid primitive type for 'out' layout", "layout"); + return false; + } + + if (mGeometryShaderOutputPrimitiveType == EptUndefined) + { + mGeometryShaderOutputPrimitiveType = layoutQualifier.primitiveType; + } + else if (mGeometryShaderOutputPrimitiveType != layoutQualifier.primitiveType) + { + error(typeQualifier.line, + "primitive doesn't match earlier output primitive declaration", "layout"); + return false; + } + } + + // Set mGeometryMaxVertices if exists + if (layoutQualifier.maxVertices > -1) + { + if (mGeometryShaderMaxVertices == -1) + { + mGeometryShaderMaxVertices = layoutQualifier.maxVertices; + } + else if (mGeometryShaderMaxVertices != layoutQualifier.maxVertices) + { + error(typeQualifier.line, "max_vertices contradicts to the earlier declaration", + "layout"); + return false; + } + } + + return true; +} + +void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder) +{ + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; + + checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier, + typeQualifier.line); + + // It should never be the case, but some strange parser errors can send us here. + if (layoutQualifier.isEmpty()) + { + error(typeQualifier.line, "Error during layout qualifier parsing.", "?"); + return; + } + + if (!layoutQualifier.isCombinationValid()) + { + error(typeQualifier.line, "invalid layout qualifier combination", "layout"); + return; + } + + checkIndexIsNotSpecified(typeQualifier.line, layoutQualifier.index); + + checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding); + + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); + + checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat); + + checkYuvIsNotSpecified(typeQualifier.line, layoutQualifier.yuv); + + checkOffsetIsNotSpecified(typeQualifier.line, layoutQualifier.offset); + + checkStd430IsForShaderStorageBlock(typeQualifier.line, layoutQualifier.blockStorage, + typeQualifier.qualifier); + + if (typeQualifier.qualifier == EvqComputeIn) + { + if (mComputeShaderLocalSizeDeclared && + !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize)) + { + error(typeQualifier.line, "Work group size does not match the previous declaration", + "layout"); + return; + } + + if (mShaderVersion < 310) + { + error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout"); + return; + } + + if (!layoutQualifier.localSize.isAnyValueSet()) + { + error(typeQualifier.line, "No local work group size specified", "layout"); + return; + } + + const TVariable *maxComputeWorkGroupSize = static_cast<const TVariable *>( + symbolTable.findBuiltIn(ImmutableString("gl_MaxComputeWorkGroupSize"), mShaderVersion)); + + const TConstantUnion *maxComputeWorkGroupSizeData = + maxComputeWorkGroupSize->getConstPointer(); + + for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i) + { + if (layoutQualifier.localSize[i] != -1) + { + mComputeShaderLocalSize[i] = layoutQualifier.localSize[i]; + const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst(); + if (mComputeShaderLocalSize[i] < 1 || + mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue) + { + std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); + reasonStream << "invalid value: Value must be at least 1 and no greater than " + << maxComputeWorkGroupSizeValue; + const std::string &reason = reasonStream.str(); + + error(typeQualifier.line, reason.c_str(), getWorkGroupSizeString(i)); + return; + } + } + } + + mComputeShaderLocalSizeDeclared = true; + } + else if (typeQualifier.qualifier == EvqGeometryIn) + { + if (mShaderVersion < 310) + { + error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout"); + return; + } + + if (!parseGeometryShaderInputLayoutQualifier(typeQualifier)) + { + return; + } + } + else if (typeQualifier.qualifier == EvqGeometryOut) + { + if (mShaderVersion < 310) + { + error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 only", + "layout"); + return; + } + + if (!parseGeometryShaderOutputLayoutQualifier(typeQualifier)) + { + return; + } + } + else if (anyMultiviewExtensionAvailable() && typeQualifier.qualifier == EvqVertexIn) + { + // This error is only specified in WebGL, but tightens unspecified behavior in the native + // specification. + if (mNumViews != -1 && layoutQualifier.numViews != mNumViews) + { + error(typeQualifier.line, "Number of views does not match the previous declaration", + "layout"); + return; + } + + if (layoutQualifier.numViews == -1) + { + error(typeQualifier.line, "No num_views specified", "layout"); + return; + } + + if (layoutQualifier.numViews > mMaxNumViews) + { + error(typeQualifier.line, "num_views greater than the value of GL_MAX_VIEWS_OVR", + "layout"); + return; + } + + mNumViews = layoutQualifier.numViews; + } + else + { + if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier)) + { + return; + } + + if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) + { + error(typeQualifier.line, "invalid qualifier: global layout can only be set for blocks", + getQualifierString(typeQualifier.qualifier)); + return; + } + + if (mShaderVersion < 300) + { + error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above", + "layout"); + return; + } + + checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier); + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + if (typeQualifier.qualifier == EvqUniform) + { + mDefaultUniformMatrixPacking = layoutQualifier.matrixPacking; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + mDefaultBufferMatrixPacking = layoutQualifier.matrixPacking; + } + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + if (typeQualifier.qualifier == EvqUniform) + { + mDefaultUniformBlockStorage = layoutQualifier.blockStorage; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + mDefaultBufferBlockStorage = layoutQualifier.blockStorage; + } + } + } +} + +TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction( + const TFunction &function, + const TSourceLoc &location, + bool insertParametersToSymbolTable) +{ + checkIsNotReserved(location, function.name()); + + TIntermFunctionPrototype *prototype = new TIntermFunctionPrototype(&function); + prototype->setLine(location); + + for (size_t i = 0; i < function.getParamCount(); i++) + { + const TVariable *param = function.getParam(i); + + // If the parameter has no name, it's not an error, just don't add it to symbol table (could + // be used for unused args). + if (param->symbolType() != SymbolType::Empty) + { + if (insertParametersToSymbolTable) + { + if (!symbolTable.declare(const_cast<TVariable *>(param))) + { + error(location, "redefinition", param->name()); + } + } + // Unsized type of a named parameter should have already been checked and sanitized. + ASSERT(!param->getType().isUnsizedArray()); + } + else + { + if (param->getType().isUnsizedArray()) + { + error(location, "function parameter array must be sized at compile time", "[]"); + // We don't need to size the arrays since the parameter is unnamed and hence + // inaccessible. + } + } + } + return prototype; +} + +TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration( + const TFunction &parsedFunction, + const TSourceLoc &location) +{ + // Note: function found from the symbol table could be the same as parsedFunction if this is the + // first declaration. Either way the instance in the symbol table is used to track whether the + // function is declared multiple times. + bool hadPrototypeDeclaration = false; + const TFunction *function = symbolTable.markFunctionHasPrototypeDeclaration( + parsedFunction.getMangledName(), &hadPrototypeDeclaration); + + if (hadPrototypeDeclaration && mShaderVersion == 100) + { + // ESSL 1.00.17 section 4.2.7. + // Doesn't apply to ESSL 3.00.4: see section 4.2.3. + error(location, "duplicate function prototype declarations are not allowed", "function"); + } + + TIntermFunctionPrototype *prototype = + createPrototypeNodeFromFunction(*function, location, false); + + symbolTable.pop(); + + if (!symbolTable.atGlobalLevel()) + { + // ESSL 3.00.4 section 4.2.4. + error(location, "local function prototype declarations are not allowed", "function"); + } + + return prototype; +} + +TIntermFunctionDefinition *TParseContext::addFunctionDefinition( + TIntermFunctionPrototype *functionPrototype, + TIntermBlock *functionBody, + const TSourceLoc &location) +{ + // Undo push at end of parseFunctionDefinitionHeader() below for ESSL1.00 case + if (mFunctionBodyNewScope) + { + mFunctionBodyNewScope = false; + symbolTable.pop(); + } + + // Check that non-void functions have at least one return statement. + if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue) + { + error(location, + "function does not return a value:", functionPrototype->getFunction()->name()); + } + + if (functionBody == nullptr) + { + functionBody = new TIntermBlock(); + functionBody->setLine(location); + } + TIntermFunctionDefinition *functionNode = + new TIntermFunctionDefinition(functionPrototype, functionBody); + functionNode->setLine(location); + + symbolTable.pop(); + return functionNode; +} + +void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location, + const TFunction *function, + TIntermFunctionPrototype **prototypeOut) +{ + ASSERT(function); + + bool wasDefined = false; + function = symbolTable.setFunctionParameterNamesFromDefinition(function, &wasDefined); + if (wasDefined) + { + error(location, "function already has a body", function->name()); + } + + // Remember the return type for later checking for return statements. + mCurrentFunctionType = &(function->getReturnType()); + mFunctionReturnsValue = false; + + *prototypeOut = createPrototypeNodeFromFunction(*function, location, true); + setLoopNestingLevel(0); + + // ESSL 1.00 spec allows for variable in function body to redefine parameter + if (IsSpecWithFunctionBodyNewScope(mShaderSpec, mShaderVersion)) + { + mFunctionBodyNewScope = true; + symbolTable.push(); + } +} + +TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function) +{ + // + // We don't know at this point whether this is a function definition or a prototype. + // The definition production code will check for redefinitions. + // In the case of ESSL 1.00 the prototype production code will also check for redeclarations. + // + + for (size_t i = 0u; i < function->getParamCount(); ++i) + { + const TVariable *param = function->getParam(i); + if (param->getType().isStructSpecifier()) + { + // ESSL 3.00.6 section 12.10. + error(location, "Function parameter type cannot be a structure definition", + function->name()); + } + } + + if (getShaderVersion() >= 300) + { + const UnmangledBuiltIn *builtIn = + symbolTable.getUnmangledBuiltInForShaderVersion(function->name(), getShaderVersion()); + if (builtIn && + (builtIn->extension == TExtension::UNDEFINED || isExtensionEnabled(builtIn->extension))) + { + // With ESSL 3.00 and above, names of built-in functions cannot be redeclared as + // functions. Therefore overloading or redefining builtin functions is an error. + error(location, "Name of a built-in function cannot be redeclared as function", + function->name()); + } + } + else + { + // ESSL 1.00.17 section 4.2.6: built-ins can be overloaded but not redefined. We assume that + // this applies to redeclarations as well. + const TSymbol *builtIn = + symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion()); + if (builtIn) + { + error(location, "built-in functions cannot be redefined", function->name()); + } + } + + // Return types and parameter qualifiers must match in all redeclarations, so those are checked + // here. + const TFunction *prevDec = + static_cast<const TFunction *>(symbolTable.findGlobal(function->getMangledName())); + if (prevDec) + { + if (prevDec->getReturnType() != function->getReturnType()) + { + error(location, "function must have the same return type in all of its declarations", + function->getReturnType().getBasicString()); + } + for (size_t i = 0; i < prevDec->getParamCount(); ++i) + { + if (prevDec->getParam(i)->getType().getQualifier() != + function->getParam(i)->getType().getQualifier()) + { + error(location, + "function must have the same parameter qualifiers in all of its declarations", + function->getParam(i)->getType().getQualifierString()); + } + } + } + + // Check for previously declared variables using the same name. + const TSymbol *prevSym = symbolTable.find(function->name(), getShaderVersion()); + bool insertUnmangledName = true; + if (prevSym) + { + if (!prevSym->isFunction()) + { + error(location, "redefinition of a function", function->name()); + } + insertUnmangledName = false; + } + // Parsing is at the inner scope level of the function's arguments and body statement at this + // point, but declareUserDefinedFunction takes care of declaring the function at the global + // scope. + symbolTable.declareUserDefinedFunction(function, insertUnmangledName); + + // Raise error message if main function takes any parameters or return anything other than void + if (function->isMain()) + { + if (function->getParamCount() > 0) + { + error(location, "function cannot take any parameter(s)", "main"); + } + if (function->getReturnType().getBasicType() != EbtVoid) + { + error(location, "main function cannot return a value", + function->getReturnType().getBasicString()); + } + } + + // + // If this is a redeclaration, it could also be a definition, in which case, we want to use the + // variable names from this one, and not the one that's + // being redeclared. So, pass back up this declaration, not the one in the symbol table. + // + return function; +} + +TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, + const ImmutableString &name, + const TSourceLoc &location) +{ + if (type.qualifier != EvqGlobal && type.qualifier != EvqTemporary) + { + error(location, "no qualifiers allowed for function return", + getQualifierString(type.qualifier)); + } + if (!type.layoutQualifier.isEmpty()) + { + error(location, "no qualifiers allowed for function return", "layout"); + } + // make sure an opaque type is not involved as well... + std::string reason(getBasicString(type.getBasicType())); + reason += "s can't be function return values"; + checkIsNotOpaqueType(location, type.typeSpecifierNonArray, reason.c_str()); + if (mShaderVersion < 300) + { + // Array return values are forbidden, but there's also no valid syntax for declaring array + // return values in ESSL 1.00. + ASSERT(!type.isArray() || mDiagnostics->numErrors() > 0); + + if (type.isStructureContainingArrays()) + { + // ESSL 1.00.17 section 6.1 Function Definitions + TInfoSinkBase typeString; + typeString << TType(type); + error(location, "structures containing arrays can't be function return values", + typeString.c_str()); + } + } + + // Add the function as a prototype after parsing it (we do not support recursion) + return new TFunction(&symbolTable, name, SymbolType::UserDefined, new TType(type), false); +} + +TFunctionLookup *TParseContext::addNonConstructorFunc(const ImmutableString &name, + const TSymbol *symbol) +{ + return TFunctionLookup::CreateFunctionCall(name, symbol); +} + +TFunctionLookup *TParseContext::addConstructorFunc(const TPublicType &publicType) +{ + if (mShaderVersion < 300 && publicType.isArray()) + { + error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only", + "[]"); + } + if (publicType.isStructSpecifier()) + { + error(publicType.getLine(), "constructor can't be a structure definition", + getBasicString(publicType.getBasicType())); + } + + TType *type = new TType(publicType); + if (!type->canBeConstructed()) + { + error(publicType.getLine(), "cannot construct this type", + getBasicString(publicType.getBasicType())); + type->setBasicType(EbtFloat); + } + return TFunctionLookup::CreateConstructor(type); +} + +void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line, + const char *errorMessage, + const ImmutableString &token, + TType *arrayType) +{ + if (arrayType->isUnsizedArray()) + { + error(line, errorMessage, token); + arrayType->sizeUnsizedArrays(nullptr); + } +} + +TParameter TParseContext::parseParameterDeclarator(TType *type, + const ImmutableString &name, + const TSourceLoc &nameLoc) +{ + ASSERT(type); + checkIsNotUnsizedArray(nameLoc, "function parameter array must specify a size", name, type); + if (type->getBasicType() == EbtVoid) + { + error(nameLoc, "illegal use of type 'void'", name); + } + checkIsNotReserved(nameLoc, name); + TParameter param = {name.data(), type}; + return param; +} + +TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType, + const ImmutableString &name, + const TSourceLoc &nameLoc) +{ + TType *type = new TType(publicType); + return parseParameterDeclarator(type, name, nameLoc); +} + +TParameter TParseContext::parseParameterArrayDeclarator(const ImmutableString &name, + const TSourceLoc &nameLoc, + const TVector<unsigned int> &arraySizes, + const TSourceLoc &arrayLoc, + TPublicType *elementType) +{ + checkArrayElementIsNotArray(arrayLoc, *elementType); + TType *arrayType = new TType(*elementType); + arrayType->makeArrays(arraySizes); + return parseParameterDeclarator(arrayType, name, nameLoc); +} + +bool TParseContext::checkUnsizedArrayConstructorArgumentDimensionality( + const TIntermSequence &arguments, + TType type, + const TSourceLoc &line) +{ + if (arguments.empty()) + { + error(line, "implicitly sized array constructor must have at least one argument", "[]"); + return false; + } + for (TIntermNode *arg : arguments) + { + const TIntermTyped *element = arg->getAsTyped(); + ASSERT(element); + size_t dimensionalityFromElement = element->getType().getNumArraySizes() + 1u; + if (dimensionalityFromElement > type.getNumArraySizes()) + { + error(line, "constructing from a non-dereferenced array", "constructor"); + return false; + } + else if (dimensionalityFromElement < type.getNumArraySizes()) + { + if (dimensionalityFromElement == 1u) + { + error(line, "implicitly sized array of arrays constructor argument is not an array", + "constructor"); + } + else + { + error(line, + "implicitly sized array of arrays constructor argument dimensionality is too " + "low", + "constructor"); + } + return false; + } + } + return true; +} + +// This function is used to test for the correctness of the parameters passed to various constructor +// functions and also convert them to the right datatype if it is allowed and required. +// +// Returns a node to add to the tree regardless of if an error was generated or not. +// +TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line) +{ + TType type = fnCall->constructorType(); + TIntermSequence &arguments = fnCall->arguments(); + if (type.isUnsizedArray()) + { + if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line)) + { + type.sizeUnsizedArrays(nullptr); + return CreateZeroNode(type); + } + TIntermTyped *firstElement = arguments.at(0)->getAsTyped(); + ASSERT(firstElement); + if (type.getOutermostArraySize() == 0u) + { + type.sizeOutermostUnsizedArray(static_cast<unsigned int>(arguments.size())); + } + for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i) + { + if ((*type.getArraySizes())[i] == 0u) + { + type.setArraySize(i, (*firstElement->getType().getArraySizes())[i]); + } + } + ASSERT(!type.isUnsizedArray()); + } + + if (!checkConstructorArguments(line, arguments, type)) + { + return CreateZeroNode(type); + } + + TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, &arguments); + constructorNode->setLine(line); + + return constructorNode->fold(mDiagnostics); +} + +// +// Interface/uniform blocks +// TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks. +// +TIntermDeclaration *TParseContext::addInterfaceBlock( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &nameLine, + const ImmutableString &blockName, + TFieldList *fieldList, + const ImmutableString &instanceName, + const TSourceLoc &instanceLine, + TIntermTyped *arrayIndex, + const TSourceLoc &arrayIndexLine) +{ + checkIsNotReserved(nameLine, blockName); + + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + + if (mShaderVersion < 310 && typeQualifier.qualifier != EvqUniform) + { + error(typeQualifier.line, + "invalid qualifier: interface blocks must be uniform in version lower than GLSL ES " + "3.10", + getQualifierString(typeQualifier.qualifier)); + } + else if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) + { + error(typeQualifier.line, "invalid qualifier: interface blocks must be uniform or buffer", + getQualifierString(typeQualifier.qualifier)); + } + + if (typeQualifier.invariant) + { + error(typeQualifier.line, "invalid qualifier on interface block member", "invariant"); + } + + if (typeQualifier.qualifier != EvqBuffer) + { + checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); + } + + // add array index + unsigned int arraySize = 0; + if (arrayIndex != nullptr) + { + arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex); + } + + checkIndexIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.index); + + if (mShaderVersion < 310) + { + checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding); + } + else + { + checkBlockBindingIsValid(typeQualifier.line, typeQualifier.qualifier, + typeQualifier.layoutQualifier.binding, arraySize); + } + + checkYuvIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.yuv); + + TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; + checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier); + checkStd430IsForShaderStorageBlock(typeQualifier.line, blockLayoutQualifier.blockStorage, + typeQualifier.qualifier); + + if (blockLayoutQualifier.matrixPacking == EmpUnspecified) + { + if (typeQualifier.qualifier == EvqUniform) + { + blockLayoutQualifier.matrixPacking = mDefaultUniformMatrixPacking; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + blockLayoutQualifier.matrixPacking = mDefaultBufferMatrixPacking; + } + } + + if (blockLayoutQualifier.blockStorage == EbsUnspecified) + { + if (typeQualifier.qualifier == EvqUniform) + { + blockLayoutQualifier.blockStorage = mDefaultUniformBlockStorage; + } + else if (typeQualifier.qualifier == EvqBuffer) + { + blockLayoutQualifier.blockStorage = mDefaultBufferBlockStorage; + } + } + + checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier); + + checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat); + + // check for sampler types and apply layout qualifiers + for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) + { + TField *field = (*fieldList)[memberIndex]; + TType *fieldType = field->type(); + if (IsOpaqueType(fieldType->getBasicType())) + { + std::string reason("unsupported type - "); + reason += fieldType->getBasicString(); + reason += " types are not allowed in interface blocks"; + error(field->line(), reason.c_str(), fieldType->getBasicString()); + } + + const TQualifier qualifier = fieldType->getQualifier(); + switch (qualifier) + { + case EvqGlobal: + break; + case EvqUniform: + if (typeQualifier.qualifier == EvqBuffer) + { + error(field->line(), "invalid qualifier on shader storage block member", + getQualifierString(qualifier)); + } + break; + case EvqBuffer: + if (typeQualifier.qualifier == EvqUniform) + { + error(field->line(), "invalid qualifier on uniform block member", + getQualifierString(qualifier)); + } + break; + default: + error(field->line(), "invalid qualifier on interface block member", + getQualifierString(qualifier)); + break; + } + + if (fieldType->isInvariant()) + { + error(field->line(), "invalid qualifier on interface block member", "invariant"); + } + + // check layout qualifiers + TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); + checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier); + checkIndexIsNotSpecified(field->line(), fieldLayoutQualifier.index); + checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding); + + if (fieldLayoutQualifier.blockStorage != EbsUnspecified) + { + error(field->line(), "invalid layout qualifier: cannot be used here", + getBlockStorageString(fieldLayoutQualifier.blockStorage)); + } + + if (fieldLayoutQualifier.matrixPacking == EmpUnspecified) + { + fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking; + } + else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct) + { + warning(field->line(), + "extraneous layout qualifier: only has an effect on matrix types", + getMatrixPackingString(fieldLayoutQualifier.matrixPacking)); + } + + fieldType->setLayoutQualifier(fieldLayoutQualifier); + + if (mShaderVersion < 310 || memberIndex != fieldList->size() - 1u || + typeQualifier.qualifier != EvqBuffer) + { + // ESSL 3.10 spec section 4.1.9 allows for runtime-sized arrays. + checkIsNotUnsizedArray(field->line(), + "array members of interface blocks must specify a size", + field->name(), field->type()); + } + + if (typeQualifier.qualifier == EvqBuffer) + { + // set memory qualifiers + // GLSL ES 3.10 session 4.9 [Memory Access Qualifiers]. When a block declaration is + // qualified with a memory qualifier, it is as if all of its members were declared with + // the same memory qualifier. + const TMemoryQualifier &blockMemoryQualifier = typeQualifier.memoryQualifier; + TMemoryQualifier fieldMemoryQualifier = fieldType->getMemoryQualifier(); + fieldMemoryQualifier.readonly |= blockMemoryQualifier.readonly; + fieldMemoryQualifier.writeonly |= blockMemoryQualifier.writeonly; + fieldMemoryQualifier.coherent |= blockMemoryQualifier.coherent; + fieldMemoryQualifier.restrictQualifier |= blockMemoryQualifier.restrictQualifier; + fieldMemoryQualifier.volatileQualifier |= blockMemoryQualifier.volatileQualifier; + // TODO(jiajia.qin@intel.com): Decide whether if readonly and writeonly buffer variable + // is legal. See bug https://github.com/KhronosGroup/OpenGL-API/issues/7 + fieldType->setMemoryQualifier(fieldMemoryQualifier); + } + } + + TInterfaceBlock *interfaceBlock = new TInterfaceBlock( + &symbolTable, blockName, fieldList, blockLayoutQualifier, SymbolType::UserDefined); + if (!symbolTable.declare(interfaceBlock)) + { + error(nameLine, "redefinition of an interface block name", blockName); + } + + TType *interfaceBlockType = + new TType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier); + if (arrayIndex != nullptr) + { + interfaceBlockType->makeArray(arraySize); + } + + // The instance variable gets created to refer to the interface block type from the AST + // regardless of if there's an instance name. It's created as an empty symbol if there is no + // instance name. + TVariable *instanceVariable = + new TVariable(&symbolTable, instanceName, interfaceBlockType, + instanceName.empty() ? SymbolType::Empty : SymbolType::UserDefined); + + if (instanceVariable->symbolType() == SymbolType::Empty) + { + // define symbols for the members of the interface block + for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) + { + TField *field = (*fieldList)[memberIndex]; + TType *fieldType = new TType(*field->type()); + + // set parent pointer of the field variable + fieldType->setInterfaceBlock(interfaceBlock); + + fieldType->setQualifier(typeQualifier.qualifier); + + TVariable *fieldVariable = + new TVariable(&symbolTable, field->name(), fieldType, SymbolType::UserDefined); + if (!symbolTable.declare(fieldVariable)) + { + error(field->line(), "redefinition of an interface block member name", + field->name()); + } + } + } + else + { + checkIsNotReserved(instanceLine, instanceName); + + // add a symbol for this interface block + if (!symbolTable.declare(instanceVariable)) + { + error(instanceLine, "redefinition of an interface block instance name", instanceName); + } + } + + TIntermSymbol *blockSymbol = new TIntermSymbol(instanceVariable); + blockSymbol->setLine(typeQualifier.line); + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->appendDeclarator(blockSymbol); + declaration->setLine(nameLine); + + exitStructDeclaration(); + return declaration; +} + +void TParseContext::enterStructDeclaration(const TSourceLoc &line, + const ImmutableString &identifier) +{ + ++mStructNestingLevel; + + // Embedded structure definitions are not supported per GLSL ES spec. + // ESSL 1.00.17 section 10.9. ESSL 3.00.6 section 12.11. + if (mStructNestingLevel > 1) + { + error(line, "Embedded struct definitions are not allowed", "struct"); + } +} + +void TParseContext::exitStructDeclaration() +{ + --mStructNestingLevel; +} + +void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field) +{ + if (!sh::IsWebGLBasedSpec(mShaderSpec)) + { + return; + } + + if (field.type()->getBasicType() != EbtStruct) + { + return; + } + + // We're already inside a structure definition at this point, so add + // one to the field's struct nesting. + if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) + { + std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); + if (field.type()->getStruct()->symbolType() == SymbolType::Empty) + { + // This may happen in case there are nested struct definitions. While they are also + // invalid GLSL, they don't cause a syntax error. + reasonStream << "Struct nesting"; + } + else + { + reasonStream << "Reference of struct type " << field.type()->getStruct()->name(); + } + reasonStream << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting; + std::string reason = reasonStream.str(); + error(line, reason.c_str(), field.name()); + return; + } +} + +// +// Parse an array index expression +// +TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, + const TSourceLoc &location, + TIntermTyped *indexExpression) +{ + if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) + { + if (baseExpression->getAsSymbolNode()) + { + error(location, " left of '[' is not of type array, matrix, or vector ", + baseExpression->getAsSymbolNode()->getName()); + } + else + { + error(location, " left of '[' is not of type array, matrix, or vector ", "expression"); + } + + return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); + } + + if (baseExpression->getQualifier() == EvqPerVertexIn) + { + ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT); + if (mGeometryShaderInputPrimitiveType == EptUndefined) + { + error(location, "missing input primitive declaration before indexing gl_in.", "["); + return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); + } + } + + TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); + + // ANGLE should be able to fold any constant expressions resulting in an integer - but to be + // safe we don't treat "EvqConst" that's evaluated according to the spec as being sufficient + // for constness. Some interpretations of the spec have allowed constant expressions with side + // effects - like array length() method on a non-constant array. + if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr) + { + if (baseExpression->isInterfaceBlock()) + { + // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks. + switch (baseExpression->getQualifier()) + { + case EvqPerVertexIn: + break; + case EvqUniform: + case EvqBuffer: + error(location, + "array indexes for uniform block arrays and shader storage block arrays " + "must be constant integral expressions", + "["); + break; + default: + // We can reach here only in error cases. + ASSERT(mDiagnostics->numErrors() > 0); + break; + } + } + else if (baseExpression->getQualifier() == EvqFragmentOut) + { + error(location, + "array indexes for fragment outputs must be constant integral expressions", "["); + } + else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData) + { + error(location, "array index for gl_FragData must be constant zero", "["); + } + } + + if (indexConstantUnion) + { + // If an out-of-range index is not qualified as constant, the behavior in the spec is + // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may + // constant fold expressions that are not constant expressions). The most compatible way to + // handle this case is to report a warning instead of an error and force the index to be in + // the correct range. + bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst; + int index = 0; + if (indexConstantUnion->getBasicType() == EbtInt) + { + index = indexConstantUnion->getIConst(0); + } + else if (indexConstantUnion->getBasicType() == EbtUInt) + { + index = static_cast<int>(indexConstantUnion->getUConst(0)); + } + + int safeIndex = -1; + + if (index < 0) + { + outOfRangeError(outOfRangeIndexIsError, location, "index expression is negative", "[]"); + safeIndex = 0; + } + + if (!baseExpression->getType().isUnsizedArray()) + { + if (baseExpression->isArray()) + { + if (baseExpression->getQualifier() == EvqFragData && index > 0) + { + if (!isExtensionEnabled(TExtension::EXT_draw_buffers)) + { + outOfRangeError(outOfRangeIndexIsError, location, + "array index for gl_FragData must be zero when " + "GL_EXT_draw_buffers is disabled", + "[]"); + safeIndex = 0; + } + } + } + // Only do generic out-of-range check if similar error hasn't already been reported. + if (safeIndex < 0) + { + if (baseExpression->isArray()) + { + safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, + baseExpression->getOutermostArraySize(), + "array index out of range"); + } + else if (baseExpression->isMatrix()) + { + safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, + baseExpression->getType().getCols(), + "matrix field selection out of range"); + } + else + { + ASSERT(baseExpression->isVector()); + safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, + baseExpression->getType().getNominalSize(), + "vector field selection out of range"); + } + } + + ASSERT(safeIndex >= 0); + // Data of constant unions can't be changed, because it may be shared with other + // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new + // sanitized object. + if (safeIndex != index || indexConstantUnion->getBasicType() != EbtInt) + { + TConstantUnion *safeConstantUnion = new TConstantUnion(); + safeConstantUnion->setIConst(safeIndex); + indexExpression = new TIntermConstantUnion( + safeConstantUnion, TType(EbtInt, indexExpression->getPrecision(), + indexExpression->getQualifier())); + } + + TIntermBinary *node = + new TIntermBinary(EOpIndexDirect, baseExpression, indexExpression); + node->setLine(location); + return expressionOrFoldedResult(node); + } + } + + markStaticReadIfSymbol(indexExpression); + TIntermBinary *node = new TIntermBinary(EOpIndexIndirect, baseExpression, indexExpression); + node->setLine(location); + // Indirect indexing can never be constant folded. + return node; +} + +int TParseContext::checkIndexLessThan(bool outOfRangeIndexIsError, + const TSourceLoc &location, + int index, + int arraySize, + const char *reason) +{ + // Should not reach here with an unsized / runtime-sized array. + ASSERT(arraySize > 0); + // A negative index should already have been checked. + ASSERT(index >= 0); + if (index >= arraySize) + { + std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); + reasonStream << reason << " '" << index << "'"; + std::string token = reasonStream.str(); + outOfRangeError(outOfRangeIndexIsError, location, reason, "[]"); + return arraySize - 1; + } + return index; +} + +TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, + const TSourceLoc &dotLocation, + const ImmutableString &fieldString, + const TSourceLoc &fieldLocation) +{ + if (baseExpression->isArray()) + { + error(fieldLocation, "cannot apply dot operator to an array", "."); + return baseExpression; + } + + if (baseExpression->isVector()) + { + TVector<int> fieldOffsets; + if (!parseVectorFields(fieldLocation, fieldString, baseExpression->getNominalSize(), + &fieldOffsets)) + { + fieldOffsets.resize(1); + fieldOffsets[0] = 0; + } + TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldOffsets); + node->setLine(dotLocation); + + return node->fold(mDiagnostics); + } + else if (baseExpression->getBasicType() == EbtStruct) + { + const TFieldList &fields = baseExpression->getType().getStruct()->fields(); + if (fields.empty()) + { + error(dotLocation, "structure has no fields", "Internal Error"); + return baseExpression; + } + else + { + bool fieldFound = false; + unsigned int i; + for (i = 0; i < fields.size(); ++i) + { + if (fields[i]->name() == fieldString) + { + fieldFound = true; + break; + } + } + if (fieldFound) + { + TIntermTyped *index = CreateIndexNode(i); + index->setLine(fieldLocation); + TIntermBinary *node = + new TIntermBinary(EOpIndexDirectStruct, baseExpression, index); + node->setLine(dotLocation); + return expressionOrFoldedResult(node); + } + else + { + error(dotLocation, " no such field in structure", fieldString); + return baseExpression; + } + } + } + else if (baseExpression->isInterfaceBlock()) + { + const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields(); + if (fields.empty()) + { + error(dotLocation, "interface block has no fields", "Internal Error"); + return baseExpression; + } + else + { + bool fieldFound = false; + unsigned int i; + for (i = 0; i < fields.size(); ++i) + { + if (fields[i]->name() == fieldString) + { + fieldFound = true; + break; + } + } + if (fieldFound) + { + TIntermTyped *index = CreateIndexNode(i); + index->setLine(fieldLocation); + TIntermBinary *node = + new TIntermBinary(EOpIndexDirectInterfaceBlock, baseExpression, index); + node->setLine(dotLocation); + // Indexing interface blocks can never be constant folded. + return node; + } + else + { + error(dotLocation, " no such field in interface block", fieldString); + return baseExpression; + } + } + } + else + { + if (mShaderVersion < 300) + { + error(dotLocation, " field selection requires structure or vector on left hand side", + fieldString); + } + else + { + error(dotLocation, + " field selection requires structure, vector, or interface block on left hand " + "side", + fieldString); + } + return baseExpression; + } +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType, + const TSourceLoc &qualifierTypeLine) +{ + TLayoutQualifier qualifier = TLayoutQualifier::Create(); + + if (qualifierType == "shared") + { + if (sh::IsWebGLBasedSpec(mShaderSpec)) + { + error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared"); + } + qualifier.blockStorage = EbsShared; + } + else if (qualifierType == "packed") + { + if (sh::IsWebGLBasedSpec(mShaderSpec)) + { + error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed"); + } + qualifier.blockStorage = EbsPacked; + } + else if (qualifierType == "std430") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.blockStorage = EbsStd430; + } + else if (qualifierType == "std140") + { + qualifier.blockStorage = EbsStd140; + } + else if (qualifierType == "row_major") + { + qualifier.matrixPacking = EmpRowMajor; + } + else if (qualifierType == "column_major") + { + qualifier.matrixPacking = EmpColumnMajor; + } + else if (qualifierType == "location") + { + error(qualifierTypeLine, "invalid layout qualifier: location requires an argument", + qualifierType); + } + else if (qualifierType == "yuv" && mShaderType == GL_FRAGMENT_SHADER) + { + if (checkCanUseExtension(qualifierTypeLine, TExtension::EXT_YUV_target)) + { + qualifier.yuv = true; + } + } + else if (qualifierType == "rgba32f") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA32F; + } + else if (qualifierType == "rgba16f") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA16F; + } + else if (qualifierType == "r32f") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifR32F; + } + else if (qualifierType == "rgba8") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8; + } + else if (qualifierType == "rgba8_snorm") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8_SNORM; + } + else if (qualifierType == "rgba32i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA32I; + } + else if (qualifierType == "rgba16i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA16I; + } + else if (qualifierType == "rgba8i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8I; + } + else if (qualifierType == "r32i") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifR32I; + } + else if (qualifierType == "rgba32ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA32UI; + } + else if (qualifierType == "rgba16ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA16UI; + } + else if (qualifierType == "rgba8ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifRGBA8UI; + } + else if (qualifierType == "r32ui") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.imageInternalFormat = EiifR32UI; + } + else if (qualifierType == "points" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptPoints; + } + else if (qualifierType == "lines" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptLines; + } + else if (qualifierType == "lines_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptLinesAdjacency; + } + else if (qualifierType == "triangles" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptTriangles; + } + else if (qualifierType == "triangles_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptTrianglesAdjacency; + } + else if (qualifierType == "line_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptLineStrip; + } + else if (qualifierType == "triangle_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + qualifier.primitiveType = EptTriangleStrip; + } + + else + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType); + } + + return qualifier; +} + +void TParseContext::parseLocalSize(const ImmutableString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + size_t index, + sh::WorkGroupSize *localSize) +{ + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + if (intValue < 1) + { + std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); + reasonStream << "out of range: " << getWorkGroupSizeString(index) << " must be positive"; + std::string reason = reasonStream.str(); + error(intValueLine, reason.c_str(), intValueString.c_str()); + } + (*localSize)[index] = intValue; +} + +void TParseContext::parseNumViews(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numViews) +{ + // This error is only specified in WebGL, but tightens unspecified behavior in the native + // specification. + if (intValue < 1) + { + error(intValueLine, "out of range: num_views must be positive", intValueString.c_str()); + } + *numViews = intValue; +} + +void TParseContext::parseInvocations(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numInvocations) +{ + // Although SPEC isn't clear whether invocations can be less than 1, we add this limit because + // it doesn't make sense to accept invocations <= 0. + if (intValue < 1 || intValue > mMaxGeometryShaderInvocations) + { + error(intValueLine, + "out of range: invocations must be in the range of [1, " + "MAX_GEOMETRY_SHADER_INVOCATIONS_OES]", + intValueString.c_str()); + } + else + { + *numInvocations = intValue; + } +} + +void TParseContext::parseMaxVertices(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *maxVertices) +{ + // Although SPEC isn't clear whether max_vertices can be less than 0, we add this limit because + // it doesn't make sense to accept max_vertices < 0. + if (intValue < 0 || intValue > mMaxGeometryShaderMaxVertices) + { + error( + intValueLine, + "out of range: max_vertices must be in the range of [0, gl_MaxGeometryOutputVertices]", + intValueString.c_str()); + } + else + { + *maxVertices = intValue; + } +} + +void TParseContext::parseIndexLayoutQualifier(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *index) +{ + // EXT_blend_func_extended specifies that most validation should happen at link time, but since + // we're validating output variable locations at compile time, it makes sense to validate that + // index is 0 or 1 also at compile time. Also since we use "-1" as a placeholder for unspecified + // index, we can't accept it here. + if (intValue < 0 || intValue > 1) + { + error(intValueLine, "out of range: index layout qualifier can only be 0 or 1", + intValueString.c_str()); + } + else + { + *index = intValue; + } +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine) +{ + TLayoutQualifier qualifier = TLayoutQualifier::Create(); + + std::string intValueString = Str(intValue); + + if (qualifierType == "location") + { + // must check that location is non-negative + if (intValue < 0) + { + error(intValueLine, "out of range: location must be non-negative", + intValueString.c_str()); + } + else + { + qualifier.location = intValue; + qualifier.locationsSpecified = 1; + } + } + else if (qualifierType == "binding") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + if (intValue < 0) + { + error(intValueLine, "out of range: binding must be non-negative", + intValueString.c_str()); + } + else + { + qualifier.binding = intValue; + } + } + else if (qualifierType == "offset") + { + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + if (intValue < 0) + { + error(intValueLine, "out of range: offset must be non-negative", + intValueString.c_str()); + } + else + { + qualifier.offset = intValue; + } + } + else if (qualifierType == "local_size_x") + { + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u, + &qualifier.localSize); + } + else if (qualifierType == "local_size_y") + { + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u, + &qualifier.localSize); + } + else if (qualifierType == "local_size_z") + { + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u, + &qualifier.localSize); + } + else if (qualifierType == "num_views" && mShaderType == GL_VERTEX_SHADER) + { + if (checkCanUseOneOfExtensions( + qualifierTypeLine, std::array<TExtension, 2u>{ + {TExtension::OVR_multiview, TExtension::OVR_multiview2}})) + { + parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews); + } + } + else if (qualifierType == "invocations" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + parseInvocations(intValue, intValueLine, intValueString, &qualifier.invocations); + } + else if (qualifierType == "max_vertices" && mShaderType == GL_GEOMETRY_SHADER_EXT && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) + { + parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices); + } + else if (qualifierType == "index" && mShaderType == GL_FRAGMENT_SHADER && + checkCanUseExtension(qualifierTypeLine, TExtension::EXT_blend_func_extended)) + { + parseIndexLayoutQualifier(intValue, intValueLine, intValueString, &qualifier.index); + } + else + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType); + } + + return qualifier; +} + +TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc) +{ + return new TTypeQualifierBuilder( + new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc), + mShaderVersion); +} + +TStorageQualifierWrapper *TParseContext::parseGlobalStorageQualifier(TQualifier qualifier, + const TSourceLoc &loc) +{ + checkIsAtGlobalLevel(loc, getQualifierString(qualifier)); + return new TStorageQualifierWrapper(qualifier, loc); +} + +TStorageQualifierWrapper *TParseContext::parseVaryingQualifier(const TSourceLoc &loc) +{ + if (getShaderType() == GL_VERTEX_SHADER) + { + return parseGlobalStorageQualifier(EvqVaryingOut, loc); + } + return parseGlobalStorageQualifier(EvqVaryingIn, loc); +} + +TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc) +{ + if (declaringFunction()) + { + return new TStorageQualifierWrapper(EvqIn, loc); + } + + switch (getShaderType()) + { + case GL_VERTEX_SHADER: + { + if (mShaderVersion < 300 && !anyMultiviewExtensionAvailable()) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); + } + return new TStorageQualifierWrapper(EvqVertexIn, loc); + } + case GL_FRAGMENT_SHADER: + { + if (mShaderVersion < 300) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); + } + return new TStorageQualifierWrapper(EvqFragmentIn, loc); + } + case GL_COMPUTE_SHADER: + { + return new TStorageQualifierWrapper(EvqComputeIn, loc); + } + case GL_GEOMETRY_SHADER_EXT: + { + return new TStorageQualifierWrapper(EvqGeometryIn, loc); + } + default: + { + UNREACHABLE(); + return new TStorageQualifierWrapper(EvqLast, loc); + } + } +} + +TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc) +{ + if (declaringFunction()) + { + return new TStorageQualifierWrapper(EvqOut, loc); + } + switch (getShaderType()) + { + case GL_VERTEX_SHADER: + { + if (mShaderVersion < 300) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out"); + } + return new TStorageQualifierWrapper(EvqVertexOut, loc); + } + case GL_FRAGMENT_SHADER: + { + if (mShaderVersion < 300) + { + error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out"); + } + return new TStorageQualifierWrapper(EvqFragmentOut, loc); + } + case GL_COMPUTE_SHADER: + { + error(loc, "storage qualifier isn't supported in compute shaders", "out"); + return new TStorageQualifierWrapper(EvqLast, loc); + } + case GL_GEOMETRY_SHADER_EXT: + { + return new TStorageQualifierWrapper(EvqGeometryOut, loc); + } + default: + { + UNREACHABLE(); + return new TStorageQualifierWrapper(EvqLast, loc); + } + } +} + +TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc) +{ + if (!declaringFunction()) + { + error(loc, "invalid qualifier: can be only used with function parameters", "inout"); + } + return new TStorageQualifierWrapper(EvqInOut, loc); +} + +TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation) +{ + return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation, + mDiagnostics); +} + +TDeclarator *TParseContext::parseStructDeclarator(const ImmutableString &identifier, + const TSourceLoc &loc) +{ + checkIsNotReserved(loc, identifier); + return new TDeclarator(identifier, loc); +} + +TDeclarator *TParseContext::parseStructArrayDeclarator(const ImmutableString &identifier, + const TSourceLoc &loc, + const TVector<unsigned int> *arraySizes) +{ + checkIsNotReserved(loc, identifier); + return new TDeclarator(identifier, arraySizes, loc); +} + +void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin, + const TFieldList::const_iterator end, + const ImmutableString &name, + const TSourceLoc &location) +{ + for (auto fieldIter = begin; fieldIter != end; ++fieldIter) + { + if ((*fieldIter)->name() == name) + { + error(location, "duplicate field name in structure", name); + } + } +} + +TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location) +{ + for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end(); + ++fieldIter) + { + checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(), + location); + } + return fields; +} + +TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields, + const TFieldList *newlyAddedFields, + const TSourceLoc &location) +{ + for (TField *field : *newlyAddedFields) + { + checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(), + field->name(), location); + processedFields->push_back(field); + } + return processedFields; +} + +TFieldList *TParseContext::addStructDeclaratorListWithQualifiers( + const TTypeQualifierBuilder &typeQualifierBuilder, + TPublicType *typeSpecifier, + const TDeclaratorList *declaratorList) +{ + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); + + typeSpecifier->qualifier = typeQualifier.qualifier; + typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier; + typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier; + typeSpecifier->invariant = typeQualifier.invariant; + if (typeQualifier.precision != EbpUndefined) + { + typeSpecifier->precision = typeQualifier.precision; + } + return addStructDeclaratorList(*typeSpecifier, declaratorList); +} + +TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, + const TDeclaratorList *declaratorList) +{ + checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision, + typeSpecifier.getBasicType()); + + checkIsNonVoid(typeSpecifier.getLine(), (*declaratorList)[0]->name(), + typeSpecifier.getBasicType()); + + checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier); + + TFieldList *fieldList = new TFieldList(); + + for (const TDeclarator *declarator : *declaratorList) + { + TType *type = new TType(typeSpecifier); + if (declarator->isArray()) + { + // Don't allow arrays of arrays in ESSL < 3.10. + checkArrayElementIsNotArray(typeSpecifier.getLine(), typeSpecifier); + type->makeArrays(*declarator->arraySizes()); + } + + TField *field = + new TField(type, declarator->name(), declarator->line(), SymbolType::UserDefined); + checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *field); + fieldList->push_back(field); + } + + return fieldList; +} + +TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine, + const TSourceLoc &nameLine, + const ImmutableString &structName, + TFieldList *fieldList) +{ + SymbolType structSymbolType = SymbolType::UserDefined; + if (structName.empty()) + { + structSymbolType = SymbolType::Empty; + } + TStructure *structure = new TStructure(&symbolTable, structName, fieldList, structSymbolType); + + // Store a bool in the struct if we're at global scope, to allow us to + // skip the local struct scoping workaround in HLSL. + structure->setAtGlobalScope(symbolTable.atGlobalLevel()); + + if (structSymbolType != SymbolType::Empty) + { + checkIsNotReserved(nameLine, structName); + if (!symbolTable.declare(structure)) + { + error(nameLine, "redefinition of a struct", structName); + } + } + + // ensure we do not specify any storage qualifiers on the struct members + for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++) + { + TField &field = *(*fieldList)[typeListIndex]; + const TQualifier qualifier = field.type()->getQualifier(); + switch (qualifier) + { + case EvqGlobal: + case EvqTemporary: + break; + default: + error(field.line(), "invalid qualifier on struct member", + getQualifierString(qualifier)); + break; + } + if (field.type()->isInvariant()) + { + error(field.line(), "invalid qualifier on struct member", "invariant"); + } + // ESSL 3.10 section 4.1.8 -- atomic_uint or images are not allowed as structure member. + if (IsImage(field.type()->getBasicType()) || IsAtomicCounter(field.type()->getBasicType())) + { + error(field.line(), "disallowed type in struct", field.type()->getBasicString()); + } + + checkIsNotUnsizedArray(field.line(), "array members of structs must specify a size", + field.name(), field.type()); + + checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line()); + + checkIndexIsNotSpecified(field.line(), field.type()->getLayoutQualifier().index); + + checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding); + + checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier()); + } + + TTypeSpecifierNonArray typeSpecifierNonArray; + typeSpecifierNonArray.initializeStruct(structure, true, structLine); + exitStructDeclaration(); + + return typeSpecifierNonArray; +} + +TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, + TIntermBlock *statementList, + const TSourceLoc &loc) +{ + TBasicType switchType = init->getBasicType(); + if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() || + init->isVector()) + { + error(init->getLine(), "init-expression in a switch statement must be a scalar integer", + "switch"); + return nullptr; + } + + ASSERT(statementList); + if (!ValidateSwitchStatementList(switchType, mDiagnostics, statementList, loc)) + { + ASSERT(mDiagnostics->numErrors() > 0); + return nullptr; + } + + markStaticReadIfSymbol(init); + TIntermSwitch *node = new TIntermSwitch(init, statementList); + node->setLine(loc); + return node; +} + +TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc) +{ + if (mSwitchNestingLevel == 0) + { + error(loc, "case labels need to be inside switch statements", "case"); + return nullptr; + } + if (condition == nullptr) + { + error(loc, "case label must have a condition", "case"); + return nullptr; + } + if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || + condition->isMatrix() || condition->isArray() || condition->isVector()) + { + error(condition->getLine(), "case label must be a scalar integer", "case"); + } + TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); + // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be + // safe against corner cases we still check for conditionConst. Some interpretations of the + // spec have allowed constant expressions with side effects - like array length() method on a + // non-constant array. + if (condition->getQualifier() != EvqConst || conditionConst == nullptr) + { + error(condition->getLine(), "case label must be constant", "case"); + } + TIntermCase *node = new TIntermCase(condition); + node->setLine(loc); + return node; +} + +TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) +{ + if (mSwitchNestingLevel == 0) + { + error(loc, "default labels need to be inside switch statements", "default"); + return nullptr; + } + TIntermCase *node = new TIntermCase(nullptr); + node->setLine(loc); + return node; +} + +TIntermTyped *TParseContext::createUnaryMath(TOperator op, + TIntermTyped *child, + const TSourceLoc &loc, + const TFunction *func) +{ + ASSERT(child != nullptr); + + switch (op) + { + case EOpLogicalNot: + if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() || + child->isVector()) + { + unaryOpError(loc, GetOperatorString(op), child->getType()); + return nullptr; + } + break; + case EOpBitwiseNot: + if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) || + child->isMatrix() || child->isArray()) + { + unaryOpError(loc, GetOperatorString(op), child->getType()); + return nullptr; + } + break; + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + case EOpPositive: + if (child->getBasicType() == EbtStruct || child->isInterfaceBlock() || + child->getBasicType() == EbtBool || child->isArray() || + child->getBasicType() == EbtVoid || IsOpaqueType(child->getBasicType())) + { + unaryOpError(loc, GetOperatorString(op), child->getType()); + return nullptr; + } + break; + // Operators for built-ins are already type checked against their prototype. + default: + break; + } + + if (child->getMemoryQualifier().writeonly) + { + unaryOpError(loc, GetOperatorString(op), child->getType()); + return nullptr; + } + + markStaticReadIfSymbol(child); + TIntermUnary *node = new TIntermUnary(op, child, func); + node->setLine(loc); + + return node->fold(mDiagnostics); +} + +TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) +{ + ASSERT(op != EOpNull); + TIntermTyped *node = createUnaryMath(op, child, loc, nullptr); + if (node == nullptr) + { + return child; + } + return node; +} + +TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, + TIntermTyped *child, + const TSourceLoc &loc) +{ + checkCanBeLValue(loc, GetOperatorString(op), child); + return addUnaryMath(op, child, loc); +} + +TIntermTyped *TParseContext::expressionOrFoldedResult(TIntermTyped *expression) +{ + // If we can, we should return the folded version of the expression for subsequent parsing. This + // enables folding the containing expression during parsing as well, instead of the separate + // FoldExpressions() step where folding nested expressions requires multiple full AST + // traversals. + + // Even if folding fails the fold() functions return some node representing the expression, + // typically the original node. So "folded" can be assumed to be non-null. + TIntermTyped *folded = expression->fold(mDiagnostics); + ASSERT(folded != nullptr); + if (folded->getQualifier() == expression->getQualifier()) + { + // We need this expression to have the correct qualifier when validating the consuming + // expression. So we can only return the folded node from here in case it has the same + // qualifier as the original expression. In this kind of a cases the qualifier of the folded + // node is EvqConst, whereas the qualifier of the expression is EvqTemporary: + // 1. (true ? 1.0 : non_constant) + // 2. (non_constant, 1.0) + return folded; + } + return expression; +} + +bool TParseContext::binaryOpCommonCheck(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) +{ + // Check opaque types are not allowed to be operands in expressions other than array indexing + // and structure member selection. + if (IsOpaqueType(left->getBasicType()) || IsOpaqueType(right->getBasicType())) + { + switch (op) + { + case EOpIndexDirect: + case EOpIndexIndirect: + break; + + default: + ASSERT(op != EOpIndexDirectStruct); + error(loc, "Invalid operation for variables with an opaque type", + GetOperatorString(op)); + return false; + } + } + + if (right->getMemoryQualifier().writeonly) + { + error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op)); + return false; + } + + if (left->getMemoryQualifier().writeonly) + { + switch (op) + { + case EOpAssign: + case EOpInitialize: + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + break; + default: + error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op)); + return false; + } + } + + if (left->getType().getStruct() || right->getType().getStruct()) + { + switch (op) + { + case EOpIndexDirectStruct: + ASSERT(left->getType().getStruct()); + break; + case EOpEqual: + case EOpNotEqual: + case EOpAssign: + case EOpInitialize: + if (left->getType() != right->getType()) + { + return false; + } + break; + default: + error(loc, "Invalid operation for structs", GetOperatorString(op)); + return false; + } + } + + if (left->isInterfaceBlock() || right->isInterfaceBlock()) + { + switch (op) + { + case EOpIndexDirectInterfaceBlock: + ASSERT(left->getType().getInterfaceBlock()); + break; + default: + error(loc, "Invalid operation for interface blocks", GetOperatorString(op)); + return false; + } + } + + if (left->isArray() != right->isArray()) + { + error(loc, "array / non-array mismatch", GetOperatorString(op)); + return false; + } + + if (left->isArray()) + { + ASSERT(right->isArray()); + if (mShaderVersion < 300) + { + error(loc, "Invalid operation for arrays", GetOperatorString(op)); + return false; + } + + switch (op) + { + case EOpEqual: + case EOpNotEqual: + case EOpAssign: + case EOpInitialize: + break; + default: + error(loc, "Invalid operation for arrays", GetOperatorString(op)); + return false; + } + // At this point, size of implicitly sized arrays should be resolved. + if (*left->getType().getArraySizes() != *right->getType().getArraySizes()) + { + error(loc, "array size mismatch", GetOperatorString(op)); + return false; + } + } + + // Check ops which require integer / ivec parameters + bool isBitShift = false; + switch (op) + { + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + // Unsigned can be bit-shifted by signed and vice versa, but we need to + // check that the basic type is an integer type. + isBitShift = true; + if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType())) + { + return false; + } + break; + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + // It is enough to check the type of only one operand, since later it + // is checked that the operand types match. + if (!IsInteger(left->getBasicType())) + { + return false; + } + break; + default: + break; + } + + ImplicitTypeConversion conversion = GetConversion(left->getBasicType(), right->getBasicType()); + + // Implicit type casting only supported for GL shaders + if (!isBitShift && conversion != ImplicitTypeConversion::Same && + (!IsDesktopGLSpec(mShaderSpec) || !IsValidImplicitConversion(conversion, op))) + { + return false; + } + + // Check that: + // 1. Type sizes match exactly on ops that require that. + // 2. Restrictions for structs that contain arrays or samplers are respected. + // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected. + switch (op) + { + case EOpAssign: + case EOpInitialize: + case EOpEqual: + case EOpNotEqual: + // ESSL 1.00 sections 5.7, 5.8, 5.9 + if (mShaderVersion < 300 && left->getType().isStructureContainingArrays()) + { + error(loc, "undefined operation for structs containing arrays", + GetOperatorString(op)); + return false; + } + // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7, + // we interpret the spec so that this extends to structs containing samplers, + // similarly to ESSL 1.00 spec. + if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) && + left->getType().isStructureContainingSamplers()) + { + error(loc, "undefined operation for structs containing samplers", + GetOperatorString(op)); + return false; + } + + if ((left->getNominalSize() != right->getNominalSize()) || + (left->getSecondarySize() != right->getSecondarySize())) + { + error(loc, "dimension mismatch", GetOperatorString(op)); + return false; + } + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (!left->isScalar() || !right->isScalar()) + { + error(loc, "comparison operator only defined for scalars", GetOperatorString(op)); + return false; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) + { + return false; + } + + // Are the sizes compatible? + if (left->getNominalSize() != right->getNominalSize() || + left->getSecondarySize() != right->getSecondarySize()) + { + // If the nominal sizes of operands do not match: + // One of them must be a scalar. + if (!left->isScalar() && !right->isScalar()) + return false; + + // In the case of compound assignment other than multiply-assign, + // the right side needs to be a scalar. Otherwise a vector/matrix + // would be assigned to a scalar. A scalar can't be shifted by a + // vector either. + if (!right->isScalar() && + (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight)) + return false; + } + break; + default: + break; + } + + return true; +} + +bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op, + const TType &left, + const TType &right) +{ + switch (op) + { + case EOpMul: + case EOpMulAssign: + return left.getNominalSize() == right.getNominalSize() && + left.getSecondarySize() == right.getSecondarySize(); + case EOpVectorTimesScalar: + return true; + case EOpVectorTimesScalarAssign: + ASSERT(!left.isMatrix() && !right.isMatrix()); + return left.isVector() && !right.isVector(); + case EOpVectorTimesMatrix: + return left.getNominalSize() == right.getRows(); + case EOpVectorTimesMatrixAssign: + ASSERT(!left.isMatrix() && right.isMatrix()); + return left.isVector() && left.getNominalSize() == right.getRows() && + left.getNominalSize() == right.getCols(); + case EOpMatrixTimesVector: + return left.getCols() == right.getNominalSize(); + case EOpMatrixTimesScalar: + return true; + case EOpMatrixTimesScalarAssign: + ASSERT(left.isMatrix() && !right.isMatrix()); + return !right.isVector(); + case EOpMatrixTimesMatrix: + return left.getCols() == right.getRows(); + case EOpMatrixTimesMatrixAssign: + ASSERT(left.isMatrix() && right.isMatrix()); + // We need to check two things: + // 1. The matrix multiplication step is valid. + // 2. The result will have the same number of columns as the lvalue. + return left.getCols() == right.getRows() && left.getCols() == right.getCols(); + + default: + UNREACHABLE(); + return false; + } +} + +TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) +{ + if (!binaryOpCommonCheck(op, left, right, loc)) + return nullptr; + + switch (op) + { + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); + if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar()) + { + return nullptr; + } + // Basic types matching should have been already checked. + ASSERT(right->getBasicType() == EbtBool); + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); + if (left->getBasicType() == EbtBool) + { + return nullptr; + } + break; + case EOpIMod: + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); + // Note that this is only for the % operator, not for mod() + if (left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) + { + return nullptr; + } + break; + default: + break; + } + + if (op == EOpMul) + { + op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType()); + if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) + { + return nullptr; + } + } + + TIntermBinary *node = new TIntermBinary(op, left, right); + ASSERT(op != EOpAssign); + markStaticReadIfSymbol(left); + markStaticReadIfSymbol(right); + node->setLine(loc); + return expressionOrFoldedResult(node); +} + +TIntermTyped *TParseContext::addBinaryMath(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); + if (node == 0) + { + binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType()); + return left; + } + return node; +} + +TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); + if (node == nullptr) + { + binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType()); + node = CreateBoolNode(false); + node->setLine(loc); + } + return node; +} + +TIntermTyped *TParseContext::addAssign(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) +{ + checkCanBeLValue(loc, "assign", left); + TIntermBinary *node = nullptr; + if (binaryOpCommonCheck(op, left, right, loc)) + { + if (op == EOpMulAssign) + { + op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType()); + if (isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) + { + node = new TIntermBinary(op, left, right); + } + } + else + { + node = new TIntermBinary(op, left, right); + } + } + if (node == nullptr) + { + assignError(loc, "assign", left->getType(), right->getType()); + return left; + } + if (op != EOpAssign) + { + markStaticReadIfSymbol(left); + } + markStaticReadIfSymbol(right); + node->setLine(loc); + return node; +} + +TIntermTyped *TParseContext::addComma(TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc) +{ + // WebGL2 section 5.26, the following results in an error: + // "Sequence operator applied to void, arrays, or structs containing arrays" + if (mShaderSpec == SH_WEBGL2_SPEC && + (left->isArray() || left->getBasicType() == EbtVoid || + left->getType().isStructureContainingArrays() || right->isArray() || + right->getBasicType() == EbtVoid || right->getType().isStructureContainingArrays())) + { + error(loc, + "sequence operator is not allowed for void, arrays, or structs containing arrays", + ","); + } + + TIntermBinary *commaNode = TIntermBinary::CreateComma(left, right, mShaderVersion); + markStaticReadIfSymbol(left); + markStaticReadIfSymbol(right); + commaNode->setLine(loc); + + return expressionOrFoldedResult(commaNode); +} + +TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) +{ + switch (op) + { + case EOpContinue: + if (mLoopNestingLevel <= 0) + { + error(loc, "continue statement only allowed in loops", ""); + } + break; + case EOpBreak: + if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0) + { + error(loc, "break statement only allowed in loops and switch statements", ""); + } + break; + case EOpReturn: + if (mCurrentFunctionType->getBasicType() != EbtVoid) + { + error(loc, "non-void function must return a value", "return"); + } + break; + case EOpKill: + if (mShaderType != GL_FRAGMENT_SHADER) + { + error(loc, "discard supported in fragment shaders only", "discard"); + } + break; + default: + UNREACHABLE(); + break; + } + return addBranch(op, nullptr, loc); +} + +TIntermBranch *TParseContext::addBranch(TOperator op, + TIntermTyped *expression, + const TSourceLoc &loc) +{ + if (expression != nullptr) + { + markStaticReadIfSymbol(expression); + ASSERT(op == EOpReturn); + mFunctionReturnsValue = true; + if (mCurrentFunctionType->getBasicType() == EbtVoid) + { + error(loc, "void function cannot return a value", "return"); + } + else if (*mCurrentFunctionType != expression->getType()) + { + error(loc, "function return is not matching type:", "return"); + } + } + TIntermBranch *node = new TIntermBranch(op, expression); + node->setLine(loc); + return node; +} + +void TParseContext::appendStatement(TIntermBlock *block, TIntermNode *statement) +{ + if (statement != nullptr) + { + markStaticReadIfSymbol(statement); + block->appendStatement(statement); + } +} + +void TParseContext::checkTextureGather(TIntermAggregate *functionCall) +{ + ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); + const TFunction *func = functionCall->getFunction(); + if (BuiltInGroup::isTextureGather(func)) + { + bool isTextureGatherOffset = BuiltInGroup::isTextureGatherOffset(func); + TIntermNode *componentNode = nullptr; + TIntermSequence *arguments = functionCall->getSequence(); + ASSERT(arguments->size() >= 2u && arguments->size() <= 4u); + const TIntermTyped *sampler = arguments->front()->getAsTyped(); + ASSERT(sampler != nullptr); + switch (sampler->getBasicType()) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + if ((!isTextureGatherOffset && arguments->size() == 3u) || + (isTextureGatherOffset && arguments->size() == 4u)) + { + componentNode = arguments->back(); + } + break; + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + ASSERT(!isTextureGatherOffset); + if (arguments->size() == 3u) + { + componentNode = arguments->back(); + } + break; + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + case EbtSamplerCubeShadow: + break; + default: + UNREACHABLE(); + break; + } + if (componentNode) + { + const TIntermConstantUnion *componentConstantUnion = + componentNode->getAsConstantUnion(); + if (componentNode->getAsTyped()->getQualifier() != EvqConst || !componentConstantUnion) + { + error(functionCall->getLine(), "Texture component must be a constant expression", + func->name()); + } + else + { + int component = componentConstantUnion->getIConst(0); + if (component < 0 || component > 3) + { + error(functionCall->getLine(), "Component must be in the range [0;3]", + func->name()); + } + } + } + } +} + +void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) +{ + ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); + const TFunction *func = functionCall->getFunction(); + TIntermNode *offset = nullptr; + TIntermSequence *arguments = functionCall->getSequence(); + bool useTextureGatherOffsetConstraints = false; + if (BuiltInGroup::isTextureOffsetNoBias(func)) + { + offset = arguments->back(); + } + else if (BuiltInGroup::isTextureOffsetBias(func)) + { + // A bias parameter follows the offset parameter. + ASSERT(arguments->size() >= 3); + offset = (*arguments)[2]; + } + else if (BuiltInGroup::isTextureGatherOffset(func)) + { + ASSERT(arguments->size() >= 3u); + const TIntermTyped *sampler = arguments->front()->getAsTyped(); + ASSERT(sampler != nullptr); + switch (sampler->getBasicType()) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + offset = (*arguments)[2]; + break; + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + offset = (*arguments)[3]; + break; + default: + UNREACHABLE(); + break; + } + useTextureGatherOffsetConstraints = true; + } + if (offset != nullptr) + { + TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion(); + if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion) + { + error(functionCall->getLine(), "Texture offset must be a constant expression", + func->name()); + } + else + { + ASSERT(offsetConstantUnion->getBasicType() == EbtInt); + size_t size = offsetConstantUnion->getType().getObjectSize(); + const TConstantUnion *values = offsetConstantUnion->getConstantValue(); + int minOffsetValue = useTextureGatherOffsetConstraints ? mMinProgramTextureGatherOffset + : mMinProgramTexelOffset; + int maxOffsetValue = useTextureGatherOffsetConstraints ? mMaxProgramTextureGatherOffset + : mMaxProgramTexelOffset; + for (size_t i = 0u; i < size; ++i) + { + int offsetValue = values[i].getIConst(); + if (offsetValue > maxOffsetValue || offsetValue < minOffsetValue) + { + std::stringstream tokenStream = sh::InitializeStream<std::stringstream>(); + tokenStream << offsetValue; + std::string token = tokenStream.str(); + error(offset->getLine(), "Texture offset value out of valid range", + token.c_str()); + } + } + } + } +} + +void TParseContext::checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall) +{ + const TFunction *func = functionCall->getFunction(); + if (BuiltInGroup::isAtomicMemory(func)) + { + ASSERT(IsAtomicFunction(functionCall->getOp())); + TIntermSequence *arguments = functionCall->getSequence(); + TIntermTyped *memNode = (*arguments)[0]->getAsTyped(); + + if (IsBufferOrSharedVariable(memNode)) + { + return; + } + + while (memNode->getAsBinaryNode()) + { + memNode = memNode->getAsBinaryNode()->getLeft(); + if (IsBufferOrSharedVariable(memNode)) + { + return; + } + } + + error(memNode->getLine(), + "The value passed to the mem argument of an atomic memory function does not " + "correspond to a buffer or shared variable.", + func->name()); + } +} + +// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers +void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall) +{ + ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); + + const TFunction *func = functionCall->getFunction(); + + if (BuiltInGroup::isImage(func)) + { + TIntermSequence *arguments = functionCall->getSequence(); + TIntermTyped *imageNode = (*arguments)[0]->getAsTyped(); + + const TMemoryQualifier &memoryQualifier = imageNode->getMemoryQualifier(); + + if (BuiltInGroup::isImageStore(func)) + { + if (memoryQualifier.readonly) + { + error(imageNode->getLine(), + "'imageStore' cannot be used with images qualified as 'readonly'", + GetImageArgumentToken(imageNode)); + } + } + else if (BuiltInGroup::isImageLoad(func)) + { + if (memoryQualifier.writeonly) + { + error(imageNode->getLine(), + "'imageLoad' cannot be used with images qualified as 'writeonly'", + GetImageArgumentToken(imageNode)); + } + } + } +} + +// GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters +void TParseContext::checkImageMemoryAccessForUserDefinedFunctions( + const TFunction *functionDefinition, + const TIntermAggregate *functionCall) +{ + ASSERT(functionCall->getOp() == EOpCallFunctionInAST); + + const TIntermSequence &arguments = *functionCall->getSequence(); + + ASSERT(functionDefinition->getParamCount() == arguments.size()); + + for (size_t i = 0; i < arguments.size(); ++i) + { + TIntermTyped *typedArgument = arguments[i]->getAsTyped(); + const TType &functionArgumentType = typedArgument->getType(); + const TType &functionParameterType = functionDefinition->getParam(i)->getType(); + ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType()); + + if (IsImage(functionArgumentType.getBasicType())) + { + const TMemoryQualifier &functionArgumentMemoryQualifier = + functionArgumentType.getMemoryQualifier(); + const TMemoryQualifier &functionParameterMemoryQualifier = + functionParameterType.getMemoryQualifier(); + if (functionArgumentMemoryQualifier.readonly && + !functionParameterMemoryQualifier.readonly) + { + error(functionCall->getLine(), + "Function call discards the 'readonly' qualifier from image", + GetImageArgumentToken(typedArgument)); + } + + if (functionArgumentMemoryQualifier.writeonly && + !functionParameterMemoryQualifier.writeonly) + { + error(functionCall->getLine(), + "Function call discards the 'writeonly' qualifier from image", + GetImageArgumentToken(typedArgument)); + } + + if (functionArgumentMemoryQualifier.coherent && + !functionParameterMemoryQualifier.coherent) + { + error(functionCall->getLine(), + "Function call discards the 'coherent' qualifier from image", + GetImageArgumentToken(typedArgument)); + } + + if (functionArgumentMemoryQualifier.volatileQualifier && + !functionParameterMemoryQualifier.volatileQualifier) + { + error(functionCall->getLine(), + "Function call discards the 'volatile' qualifier from image", + GetImageArgumentToken(typedArgument)); + } + } + } +} + +TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc) +{ + if (fnCall->thisNode() != nullptr) + { + return addMethod(fnCall, loc); + } + if (fnCall->isConstructor()) + { + return addConstructor(fnCall, loc); + } + return addNonConstructorFunctionCall(fnCall, loc); +} + +TIntermTyped *TParseContext::addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc) +{ + TIntermTyped *thisNode = fnCall->thisNode(); + // It's possible for the name pointer in the TFunction to be null in case it gets parsed as + // a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS + // mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead. + // So accessing fnCall->name() below is safe. + if (fnCall->name() != "length") + { + error(loc, "invalid method", fnCall->name()); + } + else if (!fnCall->arguments().empty()) + { + error(loc, "method takes no parameters", "length"); + } + else if (!thisNode->isArray()) + { + error(loc, "length can only be called on arrays", "length"); + } + else if (thisNode->getQualifier() == EvqPerVertexIn && + mGeometryShaderInputPrimitiveType == EptUndefined) + { + ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT); + error(loc, "missing input primitive declaration before calling length on gl_in", "length"); + } + else + { + TIntermUnary *node = new TIntermUnary(EOpArrayLength, thisNode, nullptr); + markStaticReadIfSymbol(thisNode); + node->setLine(loc); + return node->fold(mDiagnostics); + } + return CreateZeroNode(TType(EbtInt, EbpUndefined, EvqConst)); +} + +TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunctionLookup *fnCall, + const TSourceLoc &loc) +{ + // First check whether the function has been hidden by a variable name or struct typename by + // using the symbol looked up in the lexical phase. If the function is not hidden, look for one + // with a matching argument list. + if (fnCall->symbol() != nullptr && !fnCall->symbol()->isFunction()) + { + error(loc, "function name expected", fnCall->name()); + } + else + { + // There are no inner functions, so it's enough to look for user-defined functions in the + // global scope. + const TSymbol *symbol = symbolTable.findGlobal(fnCall->getMangledName()); + + if (symbol == nullptr && IsDesktopGLSpec(mShaderSpec)) + { + // If using Desktop GL spec, need to check for implicit conversion + symbol = symbolTable.findGlobalWithConversion( + fnCall->getMangledNamesForImplicitConversions()); + } + + if (symbol != nullptr) + { + // A user-defined function - could be an overloaded built-in as well. + ASSERT(symbol->symbolType() == SymbolType::UserDefined); + const TFunction *fnCandidate = static_cast<const TFunction *>(symbol); + TIntermAggregate *callNode = + TIntermAggregate::CreateFunctionCall(*fnCandidate, &fnCall->arguments()); + callNode->setLine(loc); + checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode); + functionCallRValueLValueErrorCheck(fnCandidate, callNode); + return callNode; + } + + symbol = symbolTable.findBuiltIn(fnCall->getMangledName(), mShaderVersion); + + if (symbol == nullptr && IsDesktopGLSpec(mShaderSpec)) + { + // If using Desktop GL spec, need to check for implicit conversion + symbol = symbolTable.findBuiltInWithConversion( + fnCall->getMangledNamesForImplicitConversions(), mShaderVersion); + } + + if (symbol != nullptr) + { + // A built-in function. + ASSERT(symbol->symbolType() == SymbolType::BuiltIn); + const TFunction *fnCandidate = static_cast<const TFunction *>(symbol); + + if (fnCandidate->extension() != TExtension::UNDEFINED) + { + checkCanUseExtension(loc, fnCandidate->extension()); + } + TOperator op = fnCandidate->getBuiltInOp(); + if (op != EOpCallBuiltInFunction) + { + // A function call mapped to a built-in operation. + if (fnCandidate->getParamCount() == 1) + { + // Treat it like a built-in unary operator. + TIntermNode *unaryParamNode = fnCall->arguments().front(); + TIntermTyped *callNode = + createUnaryMath(op, unaryParamNode->getAsTyped(), loc, fnCandidate); + ASSERT(callNode != nullptr); + return callNode; + } + + TIntermAggregate *callNode = + TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments()); + callNode->setLine(loc); + + checkAtomicMemoryBuiltinFunctions(callNode); + + // Some built-in functions have out parameters too. + functionCallRValueLValueErrorCheck(fnCandidate, callNode); + + // See if we can constant fold a built-in. Note that this may be possible + // even if it is not const-qualified. + return callNode->fold(mDiagnostics); + } + + // This is a built-in function with no op associated with it. + TIntermAggregate *callNode = + TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments()); + callNode->setLine(loc); + checkTextureOffsetConst(callNode); + checkTextureGather(callNode); + checkImageMemoryAccessForBuiltinFunctions(callNode); + functionCallRValueLValueErrorCheck(fnCandidate, callNode); + return callNode; + } + else + { + error(loc, "no matching overloaded function found", fnCall->name()); + } + } + + // Error message was already written. Put on a dummy node for error recovery. + return CreateZeroNode(TType(EbtFloat, EbpMedium, EvqConst)); +} + +TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, + const TSourceLoc &loc) +{ + if (!checkIsScalarBool(loc, cond)) + { + return falseExpression; + } + + if (trueExpression->getType() != falseExpression->getType()) + { + TInfoSinkBase reasonStream; + reasonStream << "mismatching ternary operator operand types '" << trueExpression->getType() + << " and '" << falseExpression->getType() << "'"; + error(loc, reasonStream.c_str(), "?:"); + return falseExpression; + } + if (IsOpaqueType(trueExpression->getBasicType())) + { + // ESSL 1.00 section 4.1.7 + // ESSL 3.00.6 section 4.1.7 + // Opaque/sampler types are not allowed in most types of expressions, including ternary. + // Note that structs containing opaque types don't need to be checked as structs are + // forbidden below. + error(loc, "ternary operator is not allowed for opaque types", "?:"); + return falseExpression; + } + + if (cond->getMemoryQualifier().writeonly || trueExpression->getMemoryQualifier().writeonly || + falseExpression->getMemoryQualifier().writeonly) + { + error(loc, "ternary operator is not allowed for variables with writeonly", "?:"); + return falseExpression; + } + + // ESSL 1.00.17 sections 5.2 and 5.7: + // Ternary operator is not among the operators allowed for structures/arrays. + // ESSL 3.00.6 section 5.7: + // Ternary operator support is optional for arrays. No certainty that it works across all + // devices with struct either, so we err on the side of caution here. TODO (oetuaho@nvidia.com): + // Would be nice to make the spec and implementation agree completely here. + if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct) + { + error(loc, "ternary operator is not allowed for structures or arrays", "?:"); + return falseExpression; + } + if (trueExpression->getBasicType() == EbtInterfaceBlock) + { + error(loc, "ternary operator is not allowed for interface blocks", "?:"); + return falseExpression; + } + + // WebGL2 section 5.26, the following results in an error: + // "Ternary operator applied to void, arrays, or structs containing arrays" + if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid) + { + error(loc, "ternary operator is not allowed for void", "?:"); + return falseExpression; + } + + TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression); + markStaticReadIfSymbol(cond); + markStaticReadIfSymbol(trueExpression); + markStaticReadIfSymbol(falseExpression); + node->setLine(loc); + return expressionOrFoldedResult(node); +} + +// +// Parse an array of strings using yyparse. +// +// Returns 0 for success. +// +int PaParseStrings(size_t count, + const char *const string[], + const int length[], + TParseContext *context) +{ + if ((count == 0) || (string == nullptr)) + return 1; + + if (glslang_initialize(context)) + return 1; + + int error = glslang_scan(count, string, length, context); + if (!error) + error = glslang_parse(context); + + glslang_finalize(context); + + return (error == 0) && (context->numErrors() == 0) ? 0 : 1; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ParseContext.h b/gfx/angle/checkout/src/compiler/translator/ParseContext.h new file mode 100644 index 0000000000..22707d57aa --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ParseContext.h @@ -0,0 +1,667 @@ +// +// Copyright (c) 2002-2014 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_PARSECONTEXT_H_ +#define COMPILER_TRANSLATOR_PARSECONTEXT_H_ + +#include "compiler/preprocessor/Preprocessor.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/Declarator.h" +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/DirectiveHandler.h" +#include "compiler/translator/FunctionLookup.h" +#include "compiler/translator/QualifierTypes.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +struct TMatrixFields +{ + bool wholeRow; + bool wholeCol; + int row; + int col; +}; + +// +// The following are extra variables needed during parsing, grouped together so +// they can be passed to the parser without needing a global. +// +class TParseContext : angle::NonCopyable +{ + public: + TParseContext(TSymbolTable &symt, + TExtensionBehavior &ext, + sh::GLenum type, + ShShaderSpec spec, + ShCompileOptions options, + bool checksPrecErrors, + TDiagnostics *diagnostics, + const ShBuiltInResources &resources); + ~TParseContext(); + + bool anyMultiviewExtensionAvailable(); + const angle::pp::Preprocessor &getPreprocessor() const { return mPreprocessor; } + angle::pp::Preprocessor &getPreprocessor() { return mPreprocessor; } + void *getScanner() const { return mScanner; } + void setScanner(void *scanner) { mScanner = scanner; } + int getShaderVersion() const { return mShaderVersion; } + sh::GLenum getShaderType() const { return mShaderType; } + ShShaderSpec getShaderSpec() const { return mShaderSpec; } + int numErrors() const { return mDiagnostics->numErrors(); } + void error(const TSourceLoc &loc, const char *reason, const char *token); + void error(const TSourceLoc &loc, const char *reason, const ImmutableString &token); + void warning(const TSourceLoc &loc, const char *reason, const char *token); + + // If isError is false, a warning will be reported instead. + void outOfRangeError(bool isError, + const TSourceLoc &loc, + const char *reason, + const char *token); + + TIntermBlock *getTreeRoot() const { return mTreeRoot; } + void setTreeRoot(TIntermBlock *treeRoot) { mTreeRoot = treeRoot; } + + bool getFragmentPrecisionHigh() const + { + return mFragmentPrecisionHighOnESSL1 || mShaderVersion >= 300; + } + void setFragmentPrecisionHighOnESSL1(bool fragmentPrecisionHigh) + { + mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh; + } + + void setLoopNestingLevel(int loopNestintLevel) { mLoopNestingLevel = loopNestintLevel; } + + void incrLoopNestingLevel() { ++mLoopNestingLevel; } + void decrLoopNestingLevel() { --mLoopNestingLevel; } + + void incrSwitchNestingLevel() { ++mSwitchNestingLevel; } + void decrSwitchNestingLevel() { --mSwitchNestingLevel; } + + bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } + sh::WorkGroupSize getComputeShaderLocalSize() const; + + int getNumViews() const { return mNumViews; } + + void enterFunctionDeclaration() { mDeclaringFunction = true; } + + void exitFunctionDeclaration() { mDeclaringFunction = false; } + + bool declaringFunction() const { return mDeclaringFunction; } + + TIntermConstantUnion *addScalarLiteral(const TConstantUnion *constantUnion, + const TSourceLoc &line); + + // This method is guaranteed to succeed, even if no variable with 'name' exists. + const TVariable *getNamedVariable(const TSourceLoc &location, + const ImmutableString &name, + const TSymbol *symbol); + TIntermTyped *parseVariableIdentifier(const TSourceLoc &location, + const ImmutableString &name, + const TSymbol *symbol); + + // Look at a '.' field selector string and change it into offsets for a vector. + bool parseVectorFields(const TSourceLoc &line, + const ImmutableString &compString, + int vecSize, + TVector<int> *fieldOffsets); + + void assignError(const TSourceLoc &line, const char *op, const TType &left, const TType &right); + void unaryOpError(const TSourceLoc &line, const char *op, const TType &operand); + void binaryOpError(const TSourceLoc &line, + const char *op, + const TType &left, + const TType &right); + + // Check functions - the ones that return bool return false if an error was generated. + + bool checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier); + void checkPrecisionSpecified(const TSourceLoc &line, TPrecision precision, TBasicType type); + bool checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node); + void checkIsConst(TIntermTyped *node); + void checkIsScalarInteger(TIntermTyped *node, const char *token); + bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token); + bool checkConstructorArguments(const TSourceLoc &line, + const TIntermSequence &arguments, + const TType &type); + + // Returns a sanitized array size to use (the size is at least 1). + unsigned int checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr); + bool checkIsValidQualifierForArray(const TSourceLoc &line, const TPublicType &elementQualifier); + bool checkArrayElementIsNotArray(const TSourceLoc &line, const TPublicType &elementType); + bool checkIsNonVoid(const TSourceLoc &line, + const ImmutableString &identifier, + const TBasicType &type); + bool checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type); + void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType); + bool checkIsNotOpaqueType(const TSourceLoc &line, + const TTypeSpecifierNonArray &pType, + const char *reason); + void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType); + void checkLocationIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier); + void checkStd430IsForShaderStorageBlock(const TSourceLoc &location, + const TLayoutBlockStorage &blockStorage, + const TQualifier &qualifier); + void checkIsParameterQualifierValid(const TSourceLoc &line, + const TTypeQualifierBuilder &typeQualifierBuilder, + TType *type); + + // Check if at least one of the specified extensions can be used, and generate error/warning as + // appropriate according to the spec. + // This function is only needed for a few different small constant sizes of extension array, and + // we want to avoid unnecessary dynamic allocations. That's why checkCanUseOneOfExtensions is a + // template function rather than one taking a vector. + template <size_t size> + bool checkCanUseOneOfExtensions(const TSourceLoc &line, + const std::array<TExtension, size> &extensions); + bool checkCanUseExtension(const TSourceLoc &line, TExtension extension); + + // Done for all declarations, whether empty or not. + void declarationQualifierErrorCheck(const sh::TQualifier qualifier, + const sh::TLayoutQualifier &layoutQualifier, + const TSourceLoc &location); + // Done for the first non-empty declarator in a declaration. + void nonEmptyDeclarationErrorCheck(const TPublicType &publicType, + const TSourceLoc &identifierLocation); + // Done only for empty declarations. + void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location); + + void checkLayoutQualifierSupported(const TSourceLoc &location, + const ImmutableString &layoutQualifierName, + int versionRequired); + bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier); + void functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall); + void checkInvariantVariableQualifier(bool invariant, + const TQualifier qualifier, + const TSourceLoc &invariantLocation); + void checkInputOutputTypeIsValidES3(const TQualifier qualifier, + const TPublicType &type, + const TSourceLoc &qualifierLocation); + void checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier); + const TPragma &pragma() const { return mDirectiveHandler.pragma(); } + const TExtensionBehavior &extensionBehavior() const + { + return mDirectiveHandler.extensionBehavior(); + } + + bool isExtensionEnabled(TExtension extension) const; + void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior); + void handlePragmaDirective(const TSourceLoc &loc, + const char *name, + const char *value, + bool stdgl); + + // Returns true on success. *initNode may still be nullptr on success in case the initialization + // is not needed in the AST. + bool executeInitializer(const TSourceLoc &line, + const ImmutableString &identifier, + TType *type, + TIntermTyped *initializer, + TIntermBinary **initNode); + TIntermNode *addConditionInitializer(const TPublicType &pType, + const ImmutableString &identifier, + TIntermTyped *initializer, + const TSourceLoc &loc); + TIntermNode *addLoop(TLoopType type, + TIntermNode *init, + TIntermNode *cond, + TIntermTyped *expr, + TIntermNode *body, + const TSourceLoc &loc); + + // For "if" test nodes. There are three children: a condition, a true path, and a false path. + // The two paths are in TIntermNodePair code. + TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &loc); + + void addFullySpecifiedType(TPublicType *typeSpecifier); + TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, + const TPublicType &typeSpecifier); + + TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType, + const TSourceLoc &identifierOrTypeLocation, + const ImmutableString &identifier); + TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &indexLocation, + const TVector<unsigned int> &arraySizes); + TIntermDeclaration *parseSingleInitDeclaration(const TPublicType &publicType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &initLocation, + TIntermTyped *initializer); + + // Parse a declaration like "type a[n] = initializer" + // Note that this does not apply to declarations like "type[n] a = initializer" + TIntermDeclaration *parseSingleArrayInitDeclaration(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &indexLocation, + const TVector<unsigned int> &arraySizes, + const TSourceLoc &initLocation, + TIntermTyped *initializer); + + TIntermInvariantDeclaration *parseInvariantDeclaration( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &identifierLoc, + const ImmutableString &identifier, + const TSymbol *symbol); + + void parseDeclarator(TPublicType &publicType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + TIntermDeclaration *declarationOut); + void parseArrayDeclarator(TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &arrayLocation, + const TVector<unsigned int> &arraySizes, + TIntermDeclaration *declarationOut); + void parseInitDeclarator(const TPublicType &publicType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut); + + // Parse a declarator like "a[n] = initializer" + void parseArrayInitDeclarator(const TPublicType &elementType, + const TSourceLoc &identifierLocation, + const ImmutableString &identifier, + const TSourceLoc &indexLocation, + const TVector<unsigned int> &arraySizes, + const TSourceLoc &initLocation, + TIntermTyped *initializer, + TIntermDeclaration *declarationOut); + + TIntermNode *addEmptyStatement(const TSourceLoc &location); + + void parseDefaultPrecisionQualifier(const TPrecision precision, + const TPublicType &type, + const TSourceLoc &loc); + void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder); + + TIntermFunctionPrototype *addFunctionPrototypeDeclaration(const TFunction &parsedFunction, + const TSourceLoc &location); + TIntermFunctionDefinition *addFunctionDefinition(TIntermFunctionPrototype *functionPrototype, + TIntermBlock *functionBody, + const TSourceLoc &location); + void parseFunctionDefinitionHeader(const TSourceLoc &location, + const TFunction *function, + TIntermFunctionPrototype **prototypeOut); + TFunction *parseFunctionDeclarator(const TSourceLoc &location, TFunction *function); + TFunction *parseFunctionHeader(const TPublicType &type, + const ImmutableString &name, + const TSourceLoc &location); + + TFunctionLookup *addNonConstructorFunc(const ImmutableString &name, const TSymbol *symbol); + TFunctionLookup *addConstructorFunc(const TPublicType &publicType); + + TParameter parseParameterDeclarator(const TPublicType &publicType, + const ImmutableString &name, + const TSourceLoc &nameLoc); + + TParameter parseParameterArrayDeclarator(const ImmutableString &name, + const TSourceLoc &nameLoc, + const TVector<unsigned int> &arraySizes, + const TSourceLoc &arrayLoc, + TPublicType *elementType); + + TIntermTyped *addIndexExpression(TIntermTyped *baseExpression, + const TSourceLoc &location, + TIntermTyped *indexExpression); + TIntermTyped *addFieldSelectionExpression(TIntermTyped *baseExpression, + const TSourceLoc &dotLocation, + const ImmutableString &fieldString, + const TSourceLoc &fieldLocation); + + // Parse declarator for a single field + TDeclarator *parseStructDeclarator(const ImmutableString &identifier, const TSourceLoc &loc); + TDeclarator *parseStructArrayDeclarator(const ImmutableString &identifier, + const TSourceLoc &loc, + const TVector<unsigned int> *arraySizes); + + void checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin, + const TFieldList::const_iterator end, + const ImmutableString &name, + const TSourceLoc &location); + TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location); + TFieldList *combineStructFieldLists(TFieldList *processedFields, + const TFieldList *newlyAddedFields, + const TSourceLoc &location); + TFieldList *addStructDeclaratorListWithQualifiers( + const TTypeQualifierBuilder &typeQualifierBuilder, + TPublicType *typeSpecifier, + const TDeclaratorList *declaratorList); + TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, + const TDeclaratorList *declaratorList); + TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine, + const TSourceLoc &nameLine, + const ImmutableString &structName, + TFieldList *fieldList); + + TIntermDeclaration *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &nameLine, + const ImmutableString &blockName, + TFieldList *fieldList, + const ImmutableString &instanceName, + const TSourceLoc &instanceLine, + TIntermTyped *arrayIndex, + const TSourceLoc &arrayIndexLine); + + void parseLocalSize(const ImmutableString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + size_t index, + sh::WorkGroupSize *localSize); + void parseNumViews(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numViews); + void parseInvocations(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numInvocations); + void parseMaxVertices(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *numMaxVertices); + void parseIndexLayoutQualifier(int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + int *index); + TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType, + const TSourceLoc &qualifierTypeLine); + TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine); + TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc); + TStorageQualifierWrapper *parseGlobalStorageQualifier(TQualifier qualifier, + const TSourceLoc &loc); + TStorageQualifierWrapper *parseVaryingQualifier(const TSourceLoc &loc); + TStorageQualifierWrapper *parseInQualifier(const TSourceLoc &loc); + TStorageQualifierWrapper *parseOutQualifier(const TSourceLoc &loc); + TStorageQualifierWrapper *parseInOutQualifier(const TSourceLoc &loc); + TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation); + + // Performs an error check for embedded struct declarations. + void enterStructDeclaration(const TSourceLoc &line, const ImmutableString &identifier); + void exitStructDeclaration(); + + void checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field); + + TIntermSwitch *addSwitch(TIntermTyped *init, + TIntermBlock *statementList, + const TSourceLoc &loc); + TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc); + TIntermCase *addDefault(const TSourceLoc &loc); + + TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc); + TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc); + TIntermTyped *addBinaryMath(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + TIntermTyped *addBinaryMathBooleanResult(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + TIntermTyped *addAssign(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + + TIntermTyped *addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc); + + TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc); + TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc); + + void appendStatement(TIntermBlock *block, TIntermNode *statement); + + void checkTextureGather(TIntermAggregate *functionCall); + void checkTextureOffsetConst(TIntermAggregate *functionCall); + void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall); + void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition, + const TIntermAggregate *functionCall); + void checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall); + + // fnCall is only storing the built-in op, and function name or constructor type. arguments + // has the arguments. + TIntermTyped *addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc); + + TIntermTyped *addTernarySelection(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, + const TSourceLoc &line); + + int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; } + int getGeometryShaderInvocations() const + { + return (mGeometryShaderInvocations > 0) ? mGeometryShaderInvocations : 1; + } + TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const + { + return mGeometryShaderInputPrimitiveType; + } + TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const + { + return mGeometryShaderOutputPrimitiveType; + } + + // TODO(jmadill): make this private + TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed + + private: + class AtomicCounterBindingState; + constexpr static size_t kAtomicCounterSize = 4; + // UNIFORM_ARRAY_STRIDE for atomic counter arrays is an implementation-dependent value which + // can be queried after a program is linked according to ES 3.10 section 7.7.1. This is + // controversial with the offset inheritance as described in ESSL 3.10 section 4.4.6. Currently + // we treat it as always 4 in favour of the original interpretation in + // "ARB_shader_atomic_counters". + // TODO(jie.a.chen@intel.com): Double check this once the spec vagueness is resolved. + // Note that there may be tests in AtomicCounter_test that will need to be updated as well. + constexpr static size_t kAtomicCounterArrayStride = 4; + + void markStaticReadIfSymbol(TIntermNode *node); + + // Returns a clamped index. If it prints out an error message, the token is "[]". + int checkIndexLessThan(bool outOfRangeIndexIsError, + const TSourceLoc &location, + int index, + int arraySize, + const char *reason); + + bool declareVariable(const TSourceLoc &line, + const ImmutableString &identifier, + const TType *type, + TVariable **variable); + + void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, + const ImmutableString &identifier, + TType *type); + + TParameter parseParameterDeclarator(TType *type, + const ImmutableString &name, + const TSourceLoc &nameLoc); + + bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, + const TPublicType &elementType); + // Done for all atomic counter declarations, whether empty or not. + void atomicCounterQualifierErrorCheck(const TPublicType &publicType, + const TSourceLoc &location); + + // Assumes that multiplication op has already been set based on the types. + bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right); + + void checkOutParameterIsNotOpaqueType(const TSourceLoc &line, + TQualifier qualifier, + const TType &type); + + void checkInternalFormatIsNotSpecified(const TSourceLoc &location, + TLayoutImageInternalFormat internalFormat); + void checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier, + const TSourceLoc &location); + void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend, + const TSourceLoc &loc, + TType *type); + void checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type); + + void checkIndexIsNotSpecified(const TSourceLoc &location, int index); + void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type); + void checkBindingIsNotSpecified(const TSourceLoc &location, int binding); + void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset); + void checkImageBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount); + void checkSamplerBindingIsValid(const TSourceLoc &location, + int binding, + int arrayTotalElementCount); + void checkBlockBindingIsValid(const TSourceLoc &location, + const TQualifier &qualifier, + int binding, + int arraySize); + void checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding); + + void checkUniformLocationInRange(const TSourceLoc &location, + int objectLocationCount, + const TLayoutQualifier &layoutQualifier); + + void checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv); + + bool checkUnsizedArrayConstructorArgumentDimensionality(const TIntermSequence &arguments, + TType type, + const TSourceLoc &line); + + // Will set the size of the outermost array according to geometry shader input layout. + void checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location, + const ImmutableString &token, + TType *type); + + // Will size any unsized array type so unsized arrays won't need to be taken into account + // further along the line in parsing. + void checkIsNotUnsizedArray(const TSourceLoc &line, + const char *errorMessage, + const ImmutableString &token, + TType *arrayType); + + TIntermTyped *addBinaryMathInternal(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + TIntermTyped *createUnaryMath(TOperator op, + TIntermTyped *child, + const TSourceLoc &loc, + const TFunction *func); + + TIntermTyped *addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc); + TIntermTyped *addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line); + TIntermTyped *addNonConstructorFunctionCall(TFunctionLookup *fnCall, const TSourceLoc &loc); + + // Return either the original expression or the folded version of the expression in case the + // folded node will validate the same way during subsequent parsing. + TIntermTyped *expressionOrFoldedResult(TIntermTyped *expression); + + // Return true if the checks pass + bool binaryOpCommonCheck(TOperator op, + TIntermTyped *left, + TIntermTyped *right, + const TSourceLoc &loc); + + TIntermFunctionPrototype *createPrototypeNodeFromFunction(const TFunction &function, + const TSourceLoc &location, + bool insertParametersToSymbolTable); + + void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration, + const TSourceLoc &location); + + bool checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier); + bool parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier); + bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier); + void setGeometryShaderInputArraySize(unsigned int inputArraySize, const TSourceLoc &line); + + // Set to true when the last/current declarator list was started with an empty declaration. The + // non-empty declaration error check will need to be performed if the empty declaration is + // followed by a declarator. + bool mDeferredNonEmptyDeclarationErrorCheck; + + sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack) + ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + ShCompileOptions mCompileOptions; // Options passed to TCompiler + int mShaderVersion; + TIntermBlock *mTreeRoot; // root of parse tree being created + int mLoopNestingLevel; // 0 if outside all loops + int mStructNestingLevel; // incremented while parsing a struct declaration + int mSwitchNestingLevel; // 0 if outside all switch statements + const TType + *mCurrentFunctionType; // the return type of the function that's currently being parsed + bool mFunctionReturnsValue; // true if a non-void function has a return + bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared + // without precision, explicit or implicit. + bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling + // ESSL1. + TLayoutMatrixPacking mDefaultUniformMatrixPacking; + TLayoutBlockStorage mDefaultUniformBlockStorage; + TLayoutMatrixPacking mDefaultBufferMatrixPacking; + TLayoutBlockStorage mDefaultBufferBlockStorage; + TString mHashErrMsg; + TDiagnostics *mDiagnostics; + TDirectiveHandler mDirectiveHandler; + angle::pp::Preprocessor mPreprocessor; + void *mScanner; + int mMinProgramTexelOffset; + int mMaxProgramTexelOffset; + + int mMinProgramTextureGatherOffset; + int mMaxProgramTextureGatherOffset; + + // keep track of local group size declared in layout. It should be declared only once. + bool mComputeShaderLocalSizeDeclared; + sh::WorkGroupSize mComputeShaderLocalSize; + // keep track of number of views declared in layout. + int mNumViews; + int mMaxNumViews; + int mMaxImageUnits; + int mMaxCombinedTextureImageUnits; + int mMaxUniformLocations; + int mMaxUniformBufferBindings; + int mMaxAtomicCounterBindings; + int mMaxShaderStorageBufferBindings; + + // keeps track whether we are declaring / defining a function + bool mDeclaringFunction; + + // Track the state of each atomic counter binding. + std::map<int, AtomicCounterBindingState> mAtomicCounterBindingStates; + + // Track the geometry shader global parameters declared in layout. + TLayoutPrimitiveType mGeometryShaderInputPrimitiveType; + TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType; + int mGeometryShaderInvocations; + int mGeometryShaderMaxVertices; + int mMaxGeometryShaderInvocations; + int mMaxGeometryShaderMaxVertices; + + // Track when we add new scope for func body in ESSL 1.00 spec + bool mFunctionBodyNewScope; +}; + +int PaParseStrings(size_t count, + const char *const string[], + const int length[], + TParseContext *context); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h b/gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h new file mode 100644 index 0000000000..8310be80b5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h @@ -0,0 +1,66 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_builtin_symbols.py using data from builtin_variables.json and +// builtin_function_declarations.txt. +// +// 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. +// +// ParseContext_autogen.h: +// Helpers for built-in related checks. + +#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_ +#define COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_ + +namespace sh +{ + +namespace BuiltInGroup +{ + +bool isTextureOffsetNoBias(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 677 && id <= 746; +} +bool isTextureOffsetBias(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 747 && id <= 766; +} +bool isTextureGatherOffset(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 844 && id <= 857; +} +bool isTextureGather(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 820 && id <= 857; +} +bool isAtomicMemory(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 874 && id <= 891; +} +bool isImageLoad(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 916 && id <= 927; +} +bool isImageStore(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 928 && id <= 939; +} +bool isImage(const TFunction *func) +{ + int id = func->uniqueId().get(); + return id >= 892 && id <= 939; +} + +} // namespace BuiltInGroup + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/PoolAlloc.cpp b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.cpp new file mode 100644 index 0000000000..7a95658e7b --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2002-2010 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/PoolAlloc.h" + +#include <assert.h> +#include "common/tls.h" + +TLSIndex PoolIndex = TLS_INVALID_INDEX; + +bool InitializePoolIndex() +{ + assert(PoolIndex == TLS_INVALID_INDEX); + + PoolIndex = CreateTLSIndex(); + return PoolIndex != TLS_INVALID_INDEX; +} + +void FreePoolIndex() +{ + assert(PoolIndex != TLS_INVALID_INDEX); + + DestroyTLSIndex(PoolIndex); + PoolIndex = TLS_INVALID_INDEX; +} + +angle::PoolAllocator *GetGlobalPoolAllocator() +{ + assert(PoolIndex != TLS_INVALID_INDEX); + return static_cast<angle::PoolAllocator *>(GetTLSValue(PoolIndex)); +} + +void SetGlobalPoolAllocator(angle::PoolAllocator *poolAllocator) +{ + assert(PoolIndex != TLS_INVALID_INDEX); + SetTLSValue(PoolIndex, poolAllocator); +} diff --git a/gfx/angle/checkout/src/compiler/translator/PoolAlloc.h b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.h new file mode 100644 index 0000000000..86980b43a1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/PoolAlloc.h @@ -0,0 +1,102 @@ +// +// Copyright (c) 2002-2010 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_POOLALLOC_H_ +#define COMPILER_TRANSLATOR_POOLALLOC_H_ + +// +// This header defines the pool_allocator class that allows STL containers +// to use the angle::PoolAllocator class by using the pool_allocator +// class as the allocator (second) template argument. +// +// It also defines functions for managing the GlobalPoolAllocator used by the compiler. +// + +#include <stddef.h> +#include <string.h> +#include <vector> + +#include "common/PoolAlloc.h" + +// +// There could potentially be many pools with pops happening at +// different times. But a simple use is to have a global pop +// with everyone using the same global allocator. +// +extern angle::PoolAllocator *GetGlobalPoolAllocator(); +extern void SetGlobalPoolAllocator(angle::PoolAllocator *poolAllocator); + +// +// This STL compatible allocator is intended to be used as the allocator +// parameter to templatized STL containers, like vector and map. +// +// It will use the pools for allocation, and not +// do any deallocation, but will still do destruction. +// +template <class T> +class pool_allocator +{ + public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + typedef T value_type; + + template <class Other> + struct rebind + { + typedef pool_allocator<Other> other; + }; + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pool_allocator() {} + + template <class Other> + pool_allocator(const pool_allocator<Other> &p) + {} + + template <class Other> + pool_allocator<T> &operator=(const pool_allocator<Other> &p) + { + return *this; + } + +#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR) + // libCStd on some platforms have a different allocate/deallocate interface. + // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be + // allocated, not the number of elements. + void *allocate(size_type n) { return getAllocator().allocate(n); } + void *allocate(size_type n, const void *) { return getAllocator().allocate(n); } + void deallocate(void *, size_type) {} +#else + pointer allocate(size_type n) + { + return static_cast<pointer>(getAllocator().allocate(n * sizeof(T))); + } + pointer allocate(size_type n, const void *) + { + return static_cast<pointer>(getAllocator().allocate(n * sizeof(T))); + } + void deallocate(pointer, size_type) {} +#endif // _RWSTD_ALLOCATOR + + void construct(pointer p, const T &val) { new ((void *)p) T(val); } + void destroy(pointer p) { p->T::~T(); } + + bool operator==(const pool_allocator &rhs) const { return true; } + bool operator!=(const pool_allocator &rhs) const { return false; } + + size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); } + size_type max_size(int size) const { return static_cast<size_type>(-1) / size; } + + angle::PoolAllocator &getAllocator() const { return *GetGlobalPoolAllocator(); } +}; + +#endif // COMPILER_TRANSLATOR_POOLALLOC_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Pragma.h b/gfx/angle/checkout/src/compiler/translator/Pragma.h new file mode 100644 index 0000000000..8c419fc17e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Pragma.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2012 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_PRAGMA_H_ +#define COMPILER_TRANSLATOR_PRAGMA_H_ + +struct TPragma +{ + struct STDGL + { + STDGL() : invariantAll(false) {} + + bool invariantAll; + }; + + // By default optimization is turned on and debug is turned off. + // Precision emulation is turned on by default, but has no effect unless + // the extension is enabled. + TPragma() : optimize(true), debug(false), debugShaderPrecision(true) {} + TPragma(bool o, bool d) : optimize(o), debug(d), debugShaderPrecision(true) {} + + bool optimize; + bool debug; + bool debugShaderPrecision; + STDGL stdgl; +}; + +#endif // COMPILER_TRANSLATOR_PRAGMA_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/QualifierTypes.cpp b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.cpp new file mode 100644 index 0000000000..f9b4474b50 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.cpp @@ -0,0 +1,829 @@ +// +// Copyright (c) 2002-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. +// + +#include "compiler/translator/QualifierTypes.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/ImmutableStringBuilder.h" + +#include <algorithm> + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kSpecifiedMultipleTimes(" specified multiple times"); +constexpr const ImmutableString kInvariantMultipleTimes( + "The invariant qualifier specified multiple times."); +constexpr const ImmutableString kPrecisionMultipleTimes( + "The precision qualifier specified multiple times."); +constexpr const ImmutableString kLayoutMultipleTimes( + "The layout qualifier specified multiple times."); +constexpr const ImmutableString kLayoutAndInvariantDisallowed( + "The layout qualifier and invariant qualifier cannot coexist in the same " + "declaration according to the grammar."); +constexpr const ImmutableString kInterpolationMultipleTimes( + "The interpolation qualifier specified multiple times."); +constexpr const ImmutableString kOutputLayoutMultipleTimes( + "Output layout location specified multiple times."); +constexpr const ImmutableString kInvariantQualifierFirst( + "The invariant qualifier has to be first in the expression."); +constexpr const ImmutableString kStorageAfterInterpolation( + "Storage qualifiers have to be after interpolation qualifiers."); +constexpr const ImmutableString kPrecisionAfterInterpolation( + "Precision qualifiers have to be after interpolation qualifiers."); +constexpr const ImmutableString kStorageAfterLayout( + "Storage qualifiers have to be after layout qualifiers."); +constexpr const ImmutableString kPrecisionAfterLayout( + "Precision qualifiers have to be after layout qualifiers."); +constexpr const ImmutableString kPrecisionAfterStorage( + "Precision qualifiers have to be after storage qualifiers."); +constexpr const ImmutableString kPrecisionAfterMemory( + "Precision qualifiers have to be after memory qualifiers."); + +// GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout +// declarations. +// GLSL ES 3.10 Revision 4, 4.10 Order of Qualification +bool AreTypeQualifierChecksRelaxed(int shaderVersion) +{ + return shaderVersion >= 310; +} + +bool IsScopeQualifier(TQualifier qualifier) +{ + return qualifier == EvqGlobal || qualifier == EvqTemporary; +} + +bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier) +{ + if (qualifier->getType() != QtStorage) + return false; + const TStorageQualifierWrapper *storageQualifier = + static_cast<const TStorageQualifierWrapper *>(qualifier); + TQualifier q = storageQualifier->getQualifier(); + return IsScopeQualifier(q); +} + +// Returns true if the invariant for the qualifier sequence holds +bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers) +{ + // We should have at least one qualifier. + // The first qualifier always tells the scope. + return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]); +} + +ImmutableString QualifierSpecifiedMultipleTimesErrorMessage(const ImmutableString &qualifierString) +{ + ImmutableStringBuilder errorMsg(qualifierString.length() + kSpecifiedMultipleTimes.length()); + errorMsg << qualifierString << kSpecifiedMultipleTimes; + return errorMsg; +} + +// Returns true if there are qualifiers which have been specified multiple times +// If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed. +bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers, + bool areQualifierChecksRelaxed, + ImmutableString *errorMessage) +{ + bool invariantFound = false; + bool precisionFound = false; + bool layoutFound = false; + bool interpolationFound = false; + + unsigned int locationsSpecified = 0; + bool isOut = false; + + // The iteration starts from one since the first qualifier only reveals the scope of the + // expression. It is inserted first whenever the sequence gets created. + for (size_t i = 1; i < qualifiers.size(); ++i) + { + switch (qualifiers[i]->getType()) + { + case QtInvariant: + { + if (invariantFound) + { + *errorMessage = kInvariantMultipleTimes; + return true; + } + invariantFound = true; + break; + } + case QtPrecision: + { + if (precisionFound) + { + *errorMessage = kPrecisionMultipleTimes; + return true; + } + precisionFound = true; + break; + } + case QtLayout: + { + if (layoutFound && !areQualifierChecksRelaxed) + { + *errorMessage = kLayoutMultipleTimes; + return true; + } + if (invariantFound && !areQualifierChecksRelaxed) + { + // This combination is not correct according to the syntax specified in the + // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have + // a similar restriction. + *errorMessage = kLayoutAndInvariantDisallowed; + return true; + } + layoutFound = true; + const TLayoutQualifier ¤tQualifier = + static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier(); + locationsSpecified += currentQualifier.locationsSpecified; + break; + } + case QtInterpolation: + { + // 'centroid' is treated as a storage qualifier + // 'flat centroid' will be squashed to 'flat' + // 'smooth centroid' will be squashed to 'centroid' + if (interpolationFound) + { + *errorMessage = kInterpolationMultipleTimes; + return true; + } + interpolationFound = true; + break; + } + case QtStorage: + { + // Go over all of the storage qualifiers up until the current one and check for + // repetitions. + TQualifier currentQualifier = + static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier(); + if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut) + { + isOut = true; + } + for (size_t j = 1; j < i; ++j) + { + if (qualifiers[j]->getType() == QtStorage) + { + const TStorageQualifierWrapper *previousQualifierWrapper = + static_cast<const TStorageQualifierWrapper *>(qualifiers[j]); + TQualifier previousQualifier = previousQualifierWrapper->getQualifier(); + if (currentQualifier == previousQualifier) + { + *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage( + previousQualifierWrapper->getQualifierString()); + return true; + } + } + } + break; + } + case QtMemory: + { + // Go over all of the memory qualifiers up until the current one and check for + // repetitions. + // Having both readonly and writeonly in a sequence is valid. + // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers + TQualifier currentQualifier = + static_cast<const TMemoryQualifierWrapper *>(qualifiers[i])->getQualifier(); + for (size_t j = 1; j < i; ++j) + { + if (qualifiers[j]->getType() == QtMemory) + { + const TMemoryQualifierWrapper *previousQualifierWrapper = + static_cast<const TMemoryQualifierWrapper *>(qualifiers[j]); + TQualifier previousQualifier = previousQualifierWrapper->getQualifier(); + if (currentQualifier == previousQualifier) + { + *errorMessage = QualifierSpecifiedMultipleTimesErrorMessage( + previousQualifierWrapper->getQualifierString()); + return true; + } + } + } + break; + } + default: + UNREACHABLE(); + } + } + + if (locationsSpecified > 1 && isOut) + { + // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers + // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers + // "The qualifier may appear at most once within a declaration." + *errorMessage = kOutputLayoutMultipleTimes; + return true; + } + + return false; +} + +// GLSL ES 3.00_6, 4.7 Order of Qualification +// The correct order of qualifiers is: +// invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier +// layout-qualifier has to be before storage-qualifier. +bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers, + ImmutableString *errorMessage) +{ + bool foundInterpolation = false; + bool foundStorage = false; + bool foundPrecision = false; + for (size_t i = 1; i < qualifiers.size(); ++i) + { + switch (qualifiers[i]->getType()) + { + case QtInvariant: + if (foundInterpolation || foundStorage || foundPrecision) + { + *errorMessage = kInvariantQualifierFirst; + return false; + } + break; + case QtInterpolation: + if (foundStorage) + { + *errorMessage = kStorageAfterInterpolation; + return false; + } + else if (foundPrecision) + { + *errorMessage = kPrecisionAfterInterpolation; + return false; + } + foundInterpolation = true; + break; + case QtLayout: + if (foundStorage) + { + *errorMessage = kStorageAfterLayout; + return false; + } + else if (foundPrecision) + { + *errorMessage = kPrecisionAfterLayout; + return false; + } + break; + case QtStorage: + if (foundPrecision) + { + *errorMessage = kPrecisionAfterStorage; + return false; + } + foundStorage = true; + break; + case QtMemory: + if (foundPrecision) + { + *errorMessage = kPrecisionAfterMemory; + return false; + } + break; + case QtPrecision: + foundPrecision = true; + break; + default: + UNREACHABLE(); + } + } + return true; +} + +struct QualifierComparator +{ + bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2) + { + return q1->getRank() < q2->getRank(); + } +}; + +void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers) +{ + // We need a stable sorting algorithm since the order of layout-qualifier declarations matter. + // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope + // and we always want it to be first. + std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator()); +} + +// Handles the joining of storage qualifiers for variables. +bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier) +{ + switch (*joinedQualifier) + { + case EvqGlobal: + *joinedQualifier = storageQualifier; + break; + case EvqTemporary: + { + switch (storageQualifier) + { + case EvqConst: + *joinedQualifier = storageQualifier; + break; + default: + return false; + } + break; + } + case EvqSmooth: + { + switch (storageQualifier) + { + case EvqCentroid: + *joinedQualifier = EvqCentroid; + break; + case EvqVertexOut: + case EvqGeometryOut: + *joinedQualifier = EvqSmoothOut; + break; + case EvqFragmentIn: + case EvqGeometryIn: + *joinedQualifier = EvqSmoothIn; + break; + default: + return false; + } + break; + } + case EvqFlat: + { + switch (storageQualifier) + { + case EvqCentroid: + *joinedQualifier = EvqFlat; + break; + case EvqVertexOut: + case EvqGeometryOut: + *joinedQualifier = EvqFlatOut; + break; + case EvqFragmentIn: + case EvqGeometryIn: + *joinedQualifier = EvqFlatIn; + break; + default: + return false; + } + break; + } + case EvqCentroid: + { + switch (storageQualifier) + { + case EvqVertexOut: + case EvqGeometryOut: + *joinedQualifier = EvqCentroidOut; + break; + case EvqFragmentIn: + case EvqGeometryIn: + *joinedQualifier = EvqCentroidIn; + break; + default: + return false; + } + break; + } + default: + return false; + } + return true; +} + +// Handles the joining of storage qualifiers for a parameter in a function. +bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier) +{ + switch (*joinedQualifier) + { + case EvqTemporary: + *joinedQualifier = storageQualifier; + break; + case EvqConst: + { + switch (storageQualifier) + { + case EvqIn: + *joinedQualifier = EvqConstReadOnly; + break; + default: + return false; + } + break; + } + default: + return false; + } + return true; +} + +bool JoinMemoryQualifier(TMemoryQualifier *joinedMemoryQualifier, TQualifier memoryQualifier) +{ + switch (memoryQualifier) + { + case EvqReadOnly: + joinedMemoryQualifier->readonly = true; + break; + case EvqWriteOnly: + joinedMemoryQualifier->writeonly = true; + break; + case EvqCoherent: + joinedMemoryQualifier->coherent = true; + break; + case EvqRestrict: + joinedMemoryQualifier->restrictQualifier = true; + break; + case EvqVolatile: + // Variables having the volatile qualifier are automatcally treated as coherent as well. + // GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers + joinedMemoryQualifier->volatileQualifier = true; + joinedMemoryQualifier->coherent = true; + break; + default: + UNREACHABLE(); + } + return true; +} + +TTypeQualifier GetVariableTypeQualifierFromSortedSequence( + const TTypeQualifierBuilder::QualifierSequence &sortedSequence, + TDiagnostics *diagnostics) +{ + TTypeQualifier typeQualifier( + static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(), + sortedSequence[0]->getLine()); + for (size_t i = 1; i < sortedSequence.size(); ++i) + { + const TQualifierWrapperBase *qualifier = sortedSequence[i]; + bool isQualifierValid = false; + switch (qualifier->getType()) + { + case QtInvariant: + isQualifierValid = true; + typeQualifier.invariant = true; + break; + case QtInterpolation: + { + switch (typeQualifier.qualifier) + { + case EvqGlobal: + isQualifierValid = true; + typeQualifier.qualifier = + static_cast<const TInterpolationQualifierWrapper *>(qualifier) + ->getQualifier(); + break; + default: + isQualifierValid = false; + } + break; + } + case QtLayout: + { + const TLayoutQualifierWrapper *layoutQualifierWrapper = + static_cast<const TLayoutQualifierWrapper *>(qualifier); + isQualifierValid = true; + typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers( + typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(), + layoutQualifierWrapper->getLine(), diagnostics); + break; + } + case QtStorage: + isQualifierValid = JoinVariableStorageQualifier( + &typeQualifier.qualifier, + static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier()); + break; + case QtPrecision: + isQualifierValid = true; + typeQualifier.precision = + static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier(); + ASSERT(typeQualifier.precision != EbpUndefined); + break; + case QtMemory: + isQualifierValid = JoinMemoryQualifier( + &typeQualifier.memoryQualifier, + static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier()); + break; + default: + UNREACHABLE(); + } + if (!isQualifierValid) + { + const ImmutableString &qualifierString = qualifier->getQualifierString(); + diagnostics->error(qualifier->getLine(), "invalid qualifier combination", + qualifierString.data()); + break; + } + } + return typeQualifier; +} + +TTypeQualifier GetParameterTypeQualifierFromSortedSequence( + const TTypeQualifierBuilder::QualifierSequence &sortedSequence, + TDiagnostics *diagnostics) +{ + TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine()); + for (size_t i = 1; i < sortedSequence.size(); ++i) + { + const TQualifierWrapperBase *qualifier = sortedSequence[i]; + bool isQualifierValid = false; + switch (qualifier->getType()) + { + case QtInvariant: + case QtInterpolation: + case QtLayout: + break; + case QtMemory: + isQualifierValid = JoinMemoryQualifier( + &typeQualifier.memoryQualifier, + static_cast<const TMemoryQualifierWrapper *>(qualifier)->getQualifier()); + break; + case QtStorage: + isQualifierValid = JoinParameterStorageQualifier( + &typeQualifier.qualifier, + static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier()); + break; + case QtPrecision: + isQualifierValid = true; + typeQualifier.precision = + static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier(); + ASSERT(typeQualifier.precision != EbpUndefined); + break; + default: + UNREACHABLE(); + } + if (!isQualifierValid) + { + const ImmutableString &qualifierString = qualifier->getQualifierString(); + diagnostics->error(qualifier->getLine(), "invalid parameter qualifier", + qualifierString.data()); + break; + } + } + + switch (typeQualifier.qualifier) + { + case EvqIn: + case EvqConstReadOnly: // const in + case EvqOut: + case EvqInOut: + break; + case EvqConst: + typeQualifier.qualifier = EvqConstReadOnly; + break; + case EvqTemporary: + // no qualifier has been specified, set it to EvqIn which is the default + typeQualifier.qualifier = EvqIn; + break; + default: + diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ", + getQualifierString(typeQualifier.qualifier)); + } + return typeQualifier; +} +} // namespace + +TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation, + TDiagnostics *diagnostics) +{ + TLayoutQualifier joinedQualifier = leftQualifier; + + if (rightQualifier.location != -1) + { + joinedQualifier.location = rightQualifier.location; + ++joinedQualifier.locationsSpecified; + } + if (rightQualifier.yuv != false) + { + joinedQualifier.yuv = rightQualifier.yuv; + } + if (rightQualifier.binding != -1) + { + joinedQualifier.binding = rightQualifier.binding; + } + if (rightQualifier.offset != -1) + { + joinedQualifier.offset = rightQualifier.offset; + } + if (rightQualifier.matrixPacking != EmpUnspecified) + { + joinedQualifier.matrixPacking = rightQualifier.matrixPacking; + } + if (rightQualifier.blockStorage != EbsUnspecified) + { + joinedQualifier.blockStorage = rightQualifier.blockStorage; + } + + for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i) + { + if (rightQualifier.localSize[i] != -1) + { + if (joinedQualifier.localSize[i] != -1 && + joinedQualifier.localSize[i] != rightQualifier.localSize[i]) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different work group size specifiers", + getWorkGroupSizeString(i)); + } + joinedQualifier.localSize[i] = rightQualifier.localSize[i]; + } + } + + if (rightQualifier.numViews != -1) + { + joinedQualifier.numViews = rightQualifier.numViews; + } + + if (rightQualifier.imageInternalFormat != EiifUnspecified) + { + joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat; + } + + if (rightQualifier.primitiveType != EptUndefined) + { + if (joinedQualifier.primitiveType != EptUndefined && + joinedQualifier.primitiveType != rightQualifier.primitiveType) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different primitive specifiers", + getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType)); + } + joinedQualifier.primitiveType = rightQualifier.primitiveType; + } + + if (rightQualifier.invocations != 0) + { + if (joinedQualifier.invocations != 0 && + joinedQualifier.invocations != rightQualifier.invocations) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different invocations specifiers", + "invocations"); + } + joinedQualifier.invocations = rightQualifier.invocations; + } + + if (rightQualifier.maxVertices != -1) + { + if (joinedQualifier.maxVertices != -1 && + joinedQualifier.maxVertices != rightQualifier.maxVertices) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different max_vertices specifiers", + "max_vertices"); + } + joinedQualifier.maxVertices = rightQualifier.maxVertices; + } + + if (rightQualifier.index != -1) + { + if (joinedQualifier.index != -1) + { + // EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once" + diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers", + "index"); + } + joinedQualifier.index = rightQualifier.index; + } + + return joinedQualifier; +} + +unsigned int TInvariantQualifierWrapper::getRank() const +{ + return 0u; +} + +unsigned int TInterpolationQualifierWrapper::getRank() const +{ + return 1u; +} + +unsigned int TLayoutQualifierWrapper::getRank() const +{ + return 2u; +} + +unsigned int TStorageQualifierWrapper::getRank() const +{ + // Force the 'centroid' auxilary storage qualifier to be always first among all storage + // qualifiers. + if (mStorageQualifier == EvqCentroid) + { + return 3u; + } + else + { + return 4u; + } +} + +unsigned int TMemoryQualifierWrapper::getRank() const +{ + return 4u; +} + +unsigned int TPrecisionQualifierWrapper::getRank() const +{ + return 5u; +} + +TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc) + : layoutQualifier(TLayoutQualifier::Create()), + memoryQualifier(TMemoryQualifier::Create()), + precision(EbpUndefined), + qualifier(scope), + invariant(false), + line(loc) +{ + ASSERT(IsScopeQualifier(qualifier)); +} + +TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, + int shaderVersion) + : mShaderVersion(shaderVersion) +{ + ASSERT(IsScopeQualifier(scope->getQualifier())); + mQualifiers.push_back(scope); +} + +void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier) +{ + mQualifiers.push_back(qualifier); +} + +bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const +{ + bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion); + ImmutableString errorMessage(""); + if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage)) + { + diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence"); + return false; + } + + if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage)) + { + diagnostics->error(mQualifiers[0]->getLine(), errorMessage.data(), "qualifier sequence"); + return false; + } + + return true; +} + +TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const +{ + ASSERT(IsInvariantCorrect(mQualifiers)); + ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() == + EvqTemporary); + + if (!checkSequenceIsValid(diagnostics)) + { + return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine()); + } + + // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so + // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to + // combine the qualifiers. + if (AreTypeQualifierChecksRelaxed(mShaderVersion)) + { + // Copy the qualifier sequence so that we can sort them. + QualifierSequence sortedQualifierSequence = mQualifiers; + SortSequence(sortedQualifierSequence); + return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics); + } + return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics); +} + +TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const +{ + ASSERT(IsInvariantCorrect(mQualifiers)); + + if (!checkSequenceIsValid(diagnostics)) + { + return TTypeQualifier( + static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(), + mQualifiers[0]->getLine()); + } + + // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so + // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to + // combine the qualifiers. + if (AreTypeQualifierChecksRelaxed(mShaderVersion)) + { + // Copy the qualifier sequence so that we can sort them. + QualifierSequence sortedQualifierSequence = mQualifiers; + SortSequence(sortedQualifierSequence); + return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics); + } + return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/QualifierTypes.h b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.h new file mode 100644 index 0000000000..950ba5f93e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/QualifierTypes.h @@ -0,0 +1,200 @@ +// +// Copyright (c) 2002-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. +// + +#ifndef COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ +#define COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ + +#include "common/angleutils.h" +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/Types.h" + +namespace sh +{ +class TDiagnostics; + +TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation, + TDiagnostics *diagnostics); + +enum TQualifierType +{ + QtInvariant, + QtInterpolation, + QtLayout, + QtStorage, + QtPrecision, + QtMemory +}; + +class TQualifierWrapperBase : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TQualifierWrapperBase(const TSourceLoc &line) : mLine(line) {} + virtual ~TQualifierWrapperBase() {} + virtual TQualifierType getType() const = 0; + virtual ImmutableString getQualifierString() const = 0; + virtual unsigned int getRank() const = 0; + const TSourceLoc &getLine() const { return mLine; } + + private: + TSourceLoc mLine; +}; + +class TInvariantQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TInvariantQualifierWrapper(const TSourceLoc &line) : TQualifierWrapperBase(line) {} + ~TInvariantQualifierWrapper() {} + + TQualifierType getType() const override { return QtInvariant; } + ImmutableString getQualifierString() const override { return ImmutableString("invariant"); } + unsigned int getRank() const override; +}; + +class TInterpolationQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TInterpolationQualifierWrapper(TQualifier interpolationQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mInterpolationQualifier(interpolationQualifier) + {} + ~TInterpolationQualifierWrapper() {} + + TQualifierType getType() const override { return QtInterpolation; } + ImmutableString getQualifierString() const override + { + return ImmutableString(sh::getQualifierString(mInterpolationQualifier)); + } + TQualifier getQualifier() const { return mInterpolationQualifier; } + unsigned int getRank() const override; + + private: + TQualifier mInterpolationQualifier; +}; + +class TLayoutQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TLayoutQualifierWrapper(TLayoutQualifier layoutQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mLayoutQualifier(layoutQualifier) + {} + ~TLayoutQualifierWrapper() {} + + TQualifierType getType() const override { return QtLayout; } + ImmutableString getQualifierString() const override { return ImmutableString("layout"); } + const TLayoutQualifier &getQualifier() const { return mLayoutQualifier; } + unsigned int getRank() const override; + + private: + TLayoutQualifier mLayoutQualifier; +}; + +class TStorageQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TStorageQualifierWrapper(TQualifier storageQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mStorageQualifier(storageQualifier) + {} + ~TStorageQualifierWrapper() {} + + TQualifierType getType() const override { return QtStorage; } + ImmutableString getQualifierString() const override + { + return ImmutableString(sh::getQualifierString(mStorageQualifier)); + } + TQualifier getQualifier() const { return mStorageQualifier; } + unsigned int getRank() const override; + + private: + TQualifier mStorageQualifier; +}; + +class TPrecisionQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TPrecisionQualifierWrapper(TPrecision precisionQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mPrecisionQualifier(precisionQualifier) + {} + ~TPrecisionQualifierWrapper() {} + + TQualifierType getType() const override { return QtPrecision; } + ImmutableString getQualifierString() const override + { + return ImmutableString(sh::getPrecisionString(mPrecisionQualifier)); + } + TPrecision getQualifier() const { return mPrecisionQualifier; } + unsigned int getRank() const override; + + private: + TPrecision mPrecisionQualifier; +}; + +class TMemoryQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TMemoryQualifierWrapper(TQualifier memoryQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mMemoryQualifier(memoryQualifier) + {} + ~TMemoryQualifierWrapper() {} + + TQualifierType getType() const override { return QtMemory; } + ImmutableString getQualifierString() const override + { + return ImmutableString(sh::getQualifierString(mMemoryQualifier)); + } + TQualifier getQualifier() const { return mMemoryQualifier; } + unsigned int getRank() const override; + + private: + TQualifier mMemoryQualifier; +}; + +// TTypeQualifier tightly covers type_qualifier from the grammar +struct TTypeQualifier +{ + // initializes all of the qualifiers and sets the scope + TTypeQualifier(TQualifier scope, const TSourceLoc &loc); + + TLayoutQualifier layoutQualifier; + TMemoryQualifier memoryQualifier; + TPrecision precision; + TQualifier qualifier; + bool invariant; + TSourceLoc line; +}; + +// TTypeQualifierBuilder contains all of the qualifiers when type_qualifier gets parsed. +// It is to be used to validate the qualifier sequence and build a TTypeQualifier from it. +class TTypeQualifierBuilder : angle::NonCopyable +{ + public: + using QualifierSequence = TVector<const TQualifierWrapperBase *>; + + public: + POOL_ALLOCATOR_NEW_DELETE + TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, int shaderVersion); + // Adds the passed qualifier to the end of the sequence. + void appendQualifier(const TQualifierWrapperBase *qualifier); + // Checks for the order of qualification and repeating qualifiers. + bool checkSequenceIsValid(TDiagnostics *diagnostics) const; + // Goes over the qualifier sequence and parses it to form a type qualifier for a function + // parameter. + // The returned object is initialized even if the parsing fails. + TTypeQualifier getParameterTypeQualifier(TDiagnostics *diagnostics) const; + // Goes over the qualifier sequence and parses it to form a type qualifier for a variable. + // The returned object is initialized even if the parsing fails. + TTypeQualifier getVariableTypeQualifier(TDiagnostics *diagnostics) const; + + private: + QualifierSequence mQualifiers; + int mShaderVersion; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp new file mode 100644 index 0000000000..4b600a9ae2 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.cpp @@ -0,0 +1,790 @@ +// +// Copyright (c) 2014 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. +// +// ResourcesHLSL.cpp: +// Methods for GLSL to HLSL translation for uniforms and interface blocks. +// + +#include "compiler/translator/ResourcesHLSL.h" + +#include "common/utilities.h" +#include "compiler/translator/AtomicCounterFunctionHLSL.h" +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/StructureHLSL.h" +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kAngleDecorString("angle_"); + +static const char *UniformRegisterPrefix(const TType &type) +{ + if (IsSampler(type.getBasicType())) + { + return "s"; + } + else + { + return "c"; + } +} + +static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage) +{ + const TType &fieldType = *field.type(); + const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; + ASSERT(matrixPacking != EmpUnspecified); + const TStructure *structure = fieldType.getStruct(); + + if (fieldType.isMatrix()) + { + // Use HLSL row-major packing for GLSL column-major matrices + const TString &matrixPackString = + (matrixPacking == EmpRowMajor ? "column_major" : "row_major"); + return matrixPackString + " " + TypeString(fieldType); + } + else if (structure) + { + // Use HLSL row-major packing for GLSL column-major matrices + return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor, + blockStorage == EbsStd140); + } + else + { + return TypeString(fieldType); + } +} + +static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) +{ + return DecoratePrivate(interfaceBlock.name()) + "_type"; +} + +void OutputUniformIndexArrayInitializer(TInfoSinkBase &out, + const TType &type, + unsigned int startIndex) +{ + out << "{"; + TType elementType(type); + elementType.toArrayElementType(); + for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i) + { + if (i > 0u) + { + out << ", "; + } + if (elementType.isArray()) + { + OutputUniformIndexArrayInitializer(out, elementType, + startIndex + i * elementType.getArraySizeProduct()); + } + else + { + out << (startIndex + i); + } + } + out << "}"; +} + +} // anonymous namespace + +ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL, + ShShaderOutput outputType, + const std::vector<Uniform> &uniforms, + unsigned int firstUniformRegister) + : mUniformRegister(firstUniformRegister), + mUniformBlockRegister(0), + mTextureRegister(0), + mUAVRegister(0), + mSamplerCount(0), + mStructureHLSL(structureHLSL), + mOutputType(outputType), + mUniforms(uniforms) +{} + +void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount) +{ + mUniformRegister = registerCount; +} + +void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount) +{ + mUniformBlockRegister = registerCount; +} + +const Uniform *ResourcesHLSL::findUniformByName(const ImmutableString &name) const +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) + { + if (name == mUniforms[uniformIndex].name) + { + return &mUniforms[uniformIndex]; + } + } + + return nullptr; +} + +unsigned int ResourcesHLSL::assignUniformRegister(const TType &type, + const ImmutableString &name, + unsigned int *outRegisterCount) +{ + unsigned int registerIndex; + const Uniform *uniform = findUniformByName(name); + ASSERT(uniform); + + if (IsSampler(type.getBasicType()) || + (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly)) + { + registerIndex = mTextureRegister; + } + else if (IsImage(type.getBasicType())) + { + registerIndex = mUAVRegister; + } + else + { + registerIndex = mUniformRegister; + } + + if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID") + { + mUniformRegisterMap["gl_DrawID"] = registerIndex; + } + else + { + mUniformRegisterMap[uniform->name] = registerIndex; + } + + unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); + + if (IsSampler(type.getBasicType()) || + (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly)) + { + mTextureRegister += registerCount; + } + else if (IsImage(type.getBasicType())) + { + mUAVRegister += registerCount; + } + else + { + mUniformRegister += registerCount; + } + if (outRegisterCount) + { + *outRegisterCount = registerCount; + } + return registerIndex; +} + +unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type, + const TString &name, + unsigned int *outRegisterCount) +{ + // Sampler that is a field of a uniform structure. + ASSERT(IsSampler(type.getBasicType())); + unsigned int registerIndex = mTextureRegister; + mUniformRegisterMap[std::string(name.c_str())] = registerIndex; + unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u; + mTextureRegister += registerCount; + if (outRegisterCount) + { + *outRegisterCount = registerCount; + } + return registerIndex; +} + +void ResourcesHLSL::outputHLSLSamplerUniformGroup( + TInfoSinkBase &out, + const HLSLTextureGroup textureGroup, + const TVector<const TVariable *> &group, + const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames, + unsigned int *groupTextureRegisterIndex) +{ + if (group.empty()) + { + return; + } + unsigned int groupRegisterCount = 0; + for (const TVariable *uniform : group) + { + const TType &type = uniform->getType(); + const ImmutableString &name = uniform->name(); + unsigned int registerCount; + + // The uniform might be just a regular sampler or one extracted from a struct. + unsigned int samplerArrayIndex = 0u; + const Uniform *uniformByName = findUniformByName(name); + if (uniformByName) + { + samplerArrayIndex = assignUniformRegister(type, name, ®isterCount); + } + else + { + ASSERT(samplerInStructSymbolsToAPINames.find(uniform) != + samplerInStructSymbolsToAPINames.end()); + samplerArrayIndex = assignSamplerInStructUniformRegister( + type, samplerInStructSymbolsToAPINames.at(uniform), ®isterCount); + } + groupRegisterCount += registerCount; + + if (type.isArray()) + { + out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type) + << " = "; + OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex); + out << ";\n"; + } + else + { + out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = " + << samplerArrayIndex << ";\n"; + } + } + TString suffix = TextureGroupSuffix(textureGroup); + // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero. + if (textureGroup != HLSL_TEXTURE_2D) + { + out << "static const uint textureIndexOffset" << suffix << " = " + << (*groupTextureRegisterIndex) << ";\n"; + out << "static const uint samplerIndexOffset" << suffix << " = " + << (*groupTextureRegisterIndex) << ";\n"; + } + out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "[" + << groupRegisterCount << "]" + << " : register(t" << (*groupTextureRegisterIndex) << ");\n"; + out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "[" + << groupRegisterCount << "]" + << " : register(s" << (*groupTextureRegisterIndex) << ");\n"; + *groupTextureRegisterIndex += groupRegisterCount; +} + +void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out, + const TVector<const TVariable *> &group, + unsigned int imageArrayIndex, + unsigned int *groupRegisterCount) +{ + for (const TVariable *uniform : group) + { + const TType &type = uniform->getType(); + const ImmutableString &name = uniform->name(); + unsigned int registerCount = 0; + + assignUniformRegister(type, name, ®isterCount); + *groupRegisterCount += registerCount; + + if (type.isArray()) + { + out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type) + << " = "; + OutputUniformIndexArrayInitializer(out, type, imageArrayIndex); + out << ";\n"; + } + else + { + out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = " + << imageArrayIndex << ";\n"; + } + + imageArrayIndex += registerCount; + } +} + +void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out, + const HLSLTextureGroup textureGroup, + const TVector<const TVariable *> &group, + unsigned int *groupTextureRegisterIndex) +{ + if (group.empty()) + { + return; + } + + unsigned int groupRegisterCount = 0; + outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount); + + TString suffix = TextureGroupSuffix(textureGroup); + out << "static const uint readonlyImageIndexOffset" << suffix << " = " + << (*groupTextureRegisterIndex) << ";\n"; + out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "[" + << groupRegisterCount << "]" + << " : register(t" << (*groupTextureRegisterIndex) << ");\n"; + *groupTextureRegisterIndex += groupRegisterCount; +} + +void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out, + const HLSLRWTextureGroup textureGroup, + const TVector<const TVariable *> &group, + unsigned int *groupTextureRegisterIndex) +{ + if (group.empty()) + { + return; + } + + unsigned int groupRegisterCount = 0; + outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount); + + TString suffix = RWTextureGroupSuffix(textureGroup); + out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex) + << ";\n"; + out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "[" + << groupRegisterCount << "]" + << " : register(u" << (*groupTextureRegisterIndex) << ");\n"; + *groupTextureRegisterIndex += groupRegisterCount; +} + +void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out, + const TType &type, + const TVariable &variable, + const unsigned int registerIndex) +{ + out << "uniform " << SamplerString(type.getBasicType()) << " sampler_" + << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s" + << str(registerIndex) << ");\n"; + out << "uniform " << TextureString(type.getBasicType()) << " texture_" + << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t" + << str(registerIndex) << ");\n"; +} + +void ResourcesHLSL::outputUniform(TInfoSinkBase &out, + const TType &type, + const TVariable &variable, + const unsigned int registerIndex) +{ + const TStructure *structure = type.getStruct(); + // If this is a nameless struct, we need to use its full definition, rather than its (empty) + // name. + // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for + // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers + // are permitted. + const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty) + ? QualifiedStructNameString(*structure, false, false) + : TypeString(type)); + + const TString ®isterString = + TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; + + out << "uniform " << typeName << " "; + + out << DecorateVariableIfNeeded(variable); + + out << ArrayString(type) << " : " << registerString << ";\n"; +} + +void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out, + const int binding, + const unsigned int registerIndex) +{ + // Atomic counter memory access is not incoherent + out << "uniform globallycoherent RWByteAddressBuffer " + << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n"; +} + +void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out, + ShShaderOutput outputType, + const ReferencedVariables &referencedUniforms, + TSymbolTable *symbolTable) +{ + if (!referencedUniforms.empty()) + { + out << "// Uniforms\n\n"; + } + // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is + // written. They are grouped based on the combination of the HLSL texture type and + // HLSL sampler type, enumerated in HLSLTextureSamplerGroup. + TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1); + TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames; + TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1); + TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1); + + TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings; + unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0; + for (auto &uniformIt : referencedUniforms) + { + // Output regular uniforms. Group sampler uniforms by type. + const TVariable &variable = *uniformIt.second; + const TType &type = variable.getType(); + + if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType())) + { + HLSLTextureGroup group = TextureGroup(type.getBasicType()); + groupedSamplerUniforms[group].push_back(&variable); + } + else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType())) + { + unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr); + outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex); + } + else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType())) + { + if (IsImage2D(type.getBasicType())) + { + const Uniform *uniform = findUniformByName(variable.name()); + if (type.getMemoryQualifier().readonly) + { + reservedReadonlyImageRegisterCount += + HLSLVariableRegisterCount(*uniform, mOutputType); + } + else + { + reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType); + } + continue; + } + if (type.getMemoryQualifier().readonly) + { + HLSLTextureGroup group = TextureGroup( + type.getBasicType(), type.getLayoutQualifier().imageInternalFormat); + groupedReadonlyImageUniforms[group].push_back(&variable); + } + else + { + HLSLRWTextureGroup group = RWTextureGroup( + type.getBasicType(), type.getLayoutQualifier().imageInternalFormat); + groupedImageUniforms[group].push_back(&variable); + } + } + else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType())) + { + TLayoutQualifier layout = type.getLayoutQualifier(); + int binding = layout.binding; + unsigned int registerIndex; + if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end()) + { + registerIndex = mUAVRegister++; + assignedAtomicCounterBindings[binding] = registerIndex; + outputAtomicCounterBuffer(out, binding, registerIndex); + } + else + { + registerIndex = assignedAtomicCounterBindings[binding]; + } + const Uniform *uniform = findUniformByName(variable.name()); + mUniformRegisterMap[uniform->name] = registerIndex; + } + else + { + if (type.isStructureContainingSamplers()) + { + TVector<const TVariable *> samplerSymbols; + TMap<const TVariable *, TString> symbolsToAPINames; + ImmutableStringBuilder namePrefix(kAngleDecorString.length() + + variable.name().length()); + namePrefix << kAngleDecorString; + namePrefix << variable.name(); + type.createSamplerSymbols(namePrefix, TString(variable.name().data()), + &samplerSymbols, &symbolsToAPINames, symbolTable); + for (const TVariable *sampler : samplerSymbols) + { + const TType &samplerType = sampler->getType(); + + if (outputType == SH_HLSL_4_1_OUTPUT) + { + HLSLTextureGroup group = TextureGroup(samplerType.getBasicType()); + groupedSamplerUniforms[group].push_back(sampler); + samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler]; + } + else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + unsigned int registerIndex = assignSamplerInStructUniformRegister( + samplerType, symbolsToAPINames[sampler], nullptr); + outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex); + } + else + { + ASSERT(outputType == SH_HLSL_3_0_OUTPUT); + unsigned int registerIndex = assignSamplerInStructUniformRegister( + samplerType, symbolsToAPINames[sampler], nullptr); + outputUniform(out, samplerType, *sampler, registerIndex); + } + } + } + unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr); + outputUniform(out, type, variable, registerIndex); + } + } + + if (outputType == SH_HLSL_4_1_OUTPUT) + { + unsigned int groupTextureRegisterIndex = 0; + // Atomic counters and RW texture share the same resources. Therefore, RW texture need to + // start counting after the last atomic counter. + unsigned int groupRWTextureRegisterIndex = mUAVRegister; + // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case. + ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D); + for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId) + { + outputHLSLSamplerUniformGroup( + out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId], + samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex); + } + mSamplerCount = groupTextureRegisterIndex; + + // Reserve t type register for readonly image2D variables. + mReadonlyImage2DRegisterIndex = mTextureRegister; + groupTextureRegisterIndex += reservedReadonlyImageRegisterCount; + mTextureRegister += reservedReadonlyImageRegisterCount; + + for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId) + { + outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId), + groupedReadonlyImageUniforms[groupId], + &groupTextureRegisterIndex); + } + mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex; + if (mReadonlyImageCount) + { + out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex + << ";\n"; + } + + // Reserve u type register for writable image2D variables. + mImage2DRegisterIndex = mUAVRegister; + groupRWTextureRegisterIndex += reservedImageRegisterCount; + mUAVRegister += reservedImageRegisterCount; + + for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId) + { + outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId), + groupedImageUniforms[groupId], + &groupRWTextureRegisterIndex); + } + mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex; + if (mImageCount) + { + out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n"; + } + } +} + +void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex) +{ + // If mSamplerCount is 0 the shader doesn't use any textures for samplers. + if (mSamplerCount > 0) + { + out << " struct SamplerMetadata\n" + " {\n" + " int baseLevel;\n" + " int internalFormatBits;\n" + " int wrapModes;\n" + " int padding;\n" + " int4 intBorderColor;\n" + " };\n" + " SamplerMetadata samplerMetadata[" + << mSamplerCount << "] : packoffset(c" << regIndex << ");\n"; + } +} + +void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex) +{ + if (mReadonlyImageCount > 0 || mImageCount > 0) + { + out << " struct ImageMetadata\n" + " {\n" + " int layer;\n" + " uint level;\n" + " int2 padding;\n" + " };\n"; + + if (mReadonlyImageCount > 0) + { + out << " ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount + << "] : packoffset(c" << regIndex << ");\n"; + } + + if (mImageCount > 0) + { + out << " ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c" + << regIndex + mReadonlyImageCount << ");\n"; + } + } +} + +TString ResourcesHLSL::uniformBlocksHeader( + const ReferencedInterfaceBlocks &referencedInterfaceBlocks) +{ + TString interfaceBlocks; + + for (const auto &blockReference : referencedInterfaceBlocks) + { + const TInterfaceBlock &interfaceBlock = *blockReference.second->block; + const TVariable *instanceVariable = blockReference.second->instanceVariable; + if (instanceVariable != nullptr) + { + interfaceBlocks += uniformBlockStructString(interfaceBlock); + } + + unsigned int activeRegister = mUniformBlockRegister; + mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister; + + if (instanceVariable != nullptr && instanceVariable->getType().isArray()) + { + unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize(); + for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++) + { + interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, + activeRegister + arrayIndex, arrayIndex); + } + mUniformBlockRegister += instanceArraySize; + } + else + { + interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister, + GL_INVALID_INDEX); + mUniformBlockRegister += 1u; + } + } + + return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks)); +} + +TString ResourcesHLSL::shaderStorageBlocksHeader( + const ReferencedInterfaceBlocks &referencedInterfaceBlocks) +{ + TString interfaceBlocks; + + for (const auto &interfaceBlockReference : referencedInterfaceBlocks) + { + const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block; + const TVariable *instanceVariable = interfaceBlockReference.second->instanceVariable; + + unsigned int activeRegister = mUAVRegister; + mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = activeRegister; + + if (instanceVariable != nullptr && instanceVariable->getType().isArray()) + { + unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize(); + for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++) + { + interfaceBlocks += shaderStorageBlockString( + interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex); + } + mUAVRegister += instanceArraySize; + } + else + { + interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable, + activeRegister, GL_INVALID_INDEX); + mUAVRegister += 1u; + } + } + + return (interfaceBlocks.empty() ? "" : ("// Shader Storage Blocks\n\n" + interfaceBlocks)); +} + +TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock, + const TVariable *instanceVariable, + unsigned int registerIndex, + unsigned int arrayIndex) +{ + const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : ""); + const TString &blockName = TString(interfaceBlock.name().data()) + arrayIndexString; + TString hlsl; + + hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + + ")\n" + "{\n"; + + if (instanceVariable != nullptr) + { + hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " + + InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n"; + } + else + { + const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); + hlsl += uniformBlockMembersString(interfaceBlock, blockStorage); + } + + hlsl += "};\n\n"; + + return hlsl; +} + +TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock, + const TVariable *instanceVariable, + unsigned int registerIndex, + unsigned int arrayIndex) +{ + TString hlsl; + if (instanceVariable != nullptr) + { + hlsl += "RWByteAddressBuffer " + + InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + + ": register(u" + str(registerIndex) + ");\n"; + } + else + { + hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" + + str(registerIndex) + ");\n"; + } + return hlsl; +} + +TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName, + unsigned int arrayIndex) +{ + if (arrayIndex != GL_INVALID_INDEX) + { + return DecoratePrivate(instanceName) + "_" + str(arrayIndex); + } + else + { + return Decorate(instanceName); + } +} + +TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock, + TLayoutBlockStorage blockStorage) +{ + TString hlsl; + + Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper(); + + for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++) + { + const TField &field = *interfaceBlock.fields()[typeIndex]; + const TType &fieldType = *field.type(); + + if (blockStorage == EbsStd140) + { + // 2 and 3 component vector types in some cases need pre-padding + hlsl += padHelper.prePaddingString(fieldType); + } + + hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) + " " + + Decorate(field.name()) + ArrayString(fieldType).data() + ";\n"; + + // must pad out after matrices and arrays, where HLSL usually allows itself room to pack + // stuff + if (blockStorage == EbsStd140) + { + const bool useHLSLRowMajorPacking = + (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor); + hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking); + } + } + + return hlsl; +} + +TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock) +{ + const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); + + return "struct " + InterfaceBlockStructName(interfaceBlock) + + "\n" + "{\n" + + uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n"; +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.h b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.h new file mode 100644 index 0000000000..0c028224b0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ResourcesHLSL.h @@ -0,0 +1,139 @@ +// +// Copyright (c) 2014 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. +// +// ResourcesHLSL.h: +// Methods for GLSL to HLSL translation for uniforms and interface blocks. +// + +#ifndef COMPILER_TRANSLATOR_RESOURCESHLSL_H_ +#define COMPILER_TRANSLATOR_RESOURCESHLSL_H_ + +#include "compiler/translator/OutputHLSL.h" +#include "compiler/translator/UtilsHLSL.h" + +namespace sh +{ +class ImmutableString; +class StructureHLSL; +class TSymbolTable; + +class ResourcesHLSL : angle::NonCopyable +{ + public: + ResourcesHLSL(StructureHLSL *structureHLSL, + ShShaderOutput outputType, + const std::vector<Uniform> &uniforms, + unsigned int firstUniformRegister); + + void reserveUniformRegisters(unsigned int registerCount); + void reserveUniformBlockRegisters(unsigned int registerCount); + void uniformsHeader(TInfoSinkBase &out, + ShShaderOutput outputType, + const ReferencedVariables &referencedUniforms, + TSymbolTable *symbolTable); + + // Must be called after uniformsHeader + void samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex); + unsigned int getSamplerCount() const { return mSamplerCount; } + void imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex); + TString uniformBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks); + TString shaderStorageBlocksHeader(const ReferencedInterfaceBlocks &referencedInterfaceBlocks); + + // Used for direct index references + static TString InterfaceBlockInstanceString(const ImmutableString &instanceName, + unsigned int arrayIndex); + + const std::map<std::string, unsigned int> &getShaderStorageBlockRegisterMap() const + { + return mShaderStorageBlockRegisterMap; + } + + const std::map<std::string, unsigned int> &getUniformBlockRegisterMap() const + { + return mUniformBlockRegisterMap; + } + const std::map<std::string, unsigned int> &getUniformRegisterMap() const + { + return mUniformRegisterMap; + } + + unsigned int getReadonlyImage2DRegisterIndex() const { return mReadonlyImage2DRegisterIndex; } + unsigned int getImage2DRegisterIndex() const { return mImage2DRegisterIndex; } + + private: + TString uniformBlockString(const TInterfaceBlock &interfaceBlock, + const TVariable *instanceVariable, + unsigned int registerIndex, + unsigned int arrayIndex); + + TString shaderStorageBlockString(const TInterfaceBlock &interfaceBlock, + const TVariable *instanceVariable, + unsigned int registerIndex, + unsigned int arrayIndex); + TString uniformBlockMembersString(const TInterfaceBlock &interfaceBlock, + TLayoutBlockStorage blockStorage); + TString uniformBlockStructString(const TInterfaceBlock &interfaceBlock); + const Uniform *findUniformByName(const ImmutableString &name) const; + + void outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out, + const TType &type, + const TVariable &variable, + const unsigned int registerIndex); + void outputUniform(TInfoSinkBase &out, + const TType &type, + const TVariable &variable, + const unsigned int registerIndex); + void outputAtomicCounterBuffer(TInfoSinkBase &out, + const int binding, + const unsigned int registerIndex); + + // Returns the uniform's register index + unsigned int assignUniformRegister(const TType &type, + const ImmutableString &name, + unsigned int *outRegisterCount); + unsigned int assignSamplerInStructUniformRegister(const TType &type, + const TString &name, + unsigned int *outRegisterCount); + + void outputHLSLSamplerUniformGroup( + TInfoSinkBase &out, + const HLSLTextureGroup textureGroup, + const TVector<const TVariable *> &group, + const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames, + unsigned int *groupTextureRegisterIndex); + + void outputHLSLImageUniformIndices(TInfoSinkBase &out, + const TVector<const TVariable *> &group, + unsigned int imageArrayIndex, + unsigned int *groupRegisterCount); + void outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out, + const HLSLTextureGroup textureGroup, + const TVector<const TVariable *> &group, + unsigned int *groupTextureRegisterIndex); + void outputHLSLImageUniformGroup(TInfoSinkBase &out, + const HLSLRWTextureGroup textureGroup, + const TVector<const TVariable *> &group, + unsigned int *groupTextureRegisterIndex); + + unsigned int mUniformRegister; + unsigned int mUniformBlockRegister; + unsigned int mTextureRegister; + unsigned int mUAVRegister; + unsigned int mSamplerCount; + unsigned int mReadonlyImageCount; + unsigned int mImageCount; + StructureHLSL *mStructureHLSL; + ShShaderOutput mOutputType; + + const std::vector<Uniform> &mUniforms; + std::map<std::string, unsigned int> mUniformBlockRegisterMap; + std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap; + std::map<std::string, unsigned int> mUniformRegisterMap; + unsigned int mReadonlyImage2DRegisterIndex; + unsigned int mImage2DRegisterIndex; +}; +} // namespace sh + +#endif // COMPILER_TRANSLATOR_RESOURCESHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Severity.h b/gfx/angle/checkout/src/compiler/translator/Severity.h new file mode 100644 index 0000000000..47808a16a7 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Severity.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 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. +// + +#ifndef COMPILER_TRANSLATOR_SEVERITY_H_ +#define COMPILER_TRANSLATOR_SEVERITY_H_ + +namespace sh +{ + +// Severity is used to classify info log messages. +enum Severity +{ + SH_WARNING, + SH_ERROR +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SEVERITY_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp new file mode 100644 index 0000000000..3a947d3c09 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ShaderLang.cpp @@ -0,0 +1,675 @@ +// +// Copyright (c) 2002-2013 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. +// + +// +// Implement the top-level of interface to the compiler, +// as defined in ShaderLang.h +// + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/translator/Compiler.h" +#include "compiler/translator/InitializeDll.h" +#include "compiler/translator/length_limits.h" +#ifdef ANGLE_ENABLE_HLSL +# include "compiler/translator/TranslatorHLSL.h" +#endif // ANGLE_ENABLE_HLSL +#include "angle_gl.h" +#include "compiler/translator/VariablePacker.h" + +namespace sh +{ + +namespace +{ + +bool isInitialized = false; + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler. +// + +template <typename VarT> +const std::vector<VarT> *GetVariableList(const TCompiler *compiler); + +template <> +const std::vector<Uniform> *GetVariableList(const TCompiler *compiler) +{ + return &compiler->getUniforms(); +} + +template <> +const std::vector<Varying> *GetVariableList(const TCompiler *compiler) +{ + switch (compiler->getShaderType()) + { + case GL_VERTEX_SHADER: + return &compiler->getOutputVaryings(); + case GL_FRAGMENT_SHADER: + return &compiler->getInputVaryings(); + case GL_COMPUTE_SHADER: + ASSERT(compiler->getOutputVaryings().empty() && compiler->getInputVaryings().empty()); + return &compiler->getOutputVaryings(); + // Since geometry shaders have both input and output varyings, we shouldn't call GetVaryings + // on a geometry shader. + default: + return nullptr; + } +} + +template <> +const std::vector<Attribute> *GetVariableList(const TCompiler *compiler) +{ + return &compiler->getAttributes(); +} + +template <> +const std::vector<OutputVariable> *GetVariableList(const TCompiler *compiler) +{ + return &compiler->getOutputVariables(); +} + +template <> +const std::vector<InterfaceBlock> *GetVariableList(const TCompiler *compiler) +{ + return &compiler->getInterfaceBlocks(); +} + +TCompiler *GetCompilerFromHandle(ShHandle handle) +{ + if (!handle) + { + return nullptr; + } + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + return base->getAsCompiler(); +} + +template <typename VarT> +const std::vector<VarT> *GetShaderVariables(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + if (!compiler) + { + return nullptr; + } + + return GetVariableList<VarT>(compiler); +} + +#ifdef ANGLE_ENABLE_HLSL +TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) +{ + if (!handle) + return nullptr; + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + return base->getAsTranslatorHLSL(); +} +#endif // ANGLE_ENABLE_HLSL + +GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType) +{ + switch (primitiveType) + { + case EptPoints: + return GL_POINTS; + case EptLines: + return GL_LINES; + case EptLinesAdjacency: + return GL_LINES_ADJACENCY_EXT; + case EptTriangles: + return GL_TRIANGLES; + case EptTrianglesAdjacency: + return GL_TRIANGLES_ADJACENCY_EXT; + + case EptLineStrip: + return GL_LINE_STRIP; + case EptTriangleStrip: + return GL_TRIANGLE_STRIP; + + case EptUndefined: + default: + UNREACHABLE(); + return GL_INVALID_VALUE; + } +} + +} // anonymous namespace + +// +// Driver must call this first, once, before doing any other compiler operations. +// Subsequent calls to this function are no-op. +// +bool Initialize() +{ + if (!isInitialized) + { + isInitialized = InitProcess(); + } + return isInitialized; +} + +// +// Cleanup symbol tables +// +bool Finalize() +{ + if (isInitialized) + { + DetachProcess(); + isInitialized = false; + } + return true; +} + +// +// Initialize built-in resources with minimum expected values. +// +void InitBuiltInResources(ShBuiltInResources *resources) +{ + // Make comparable. + memset(resources, 0, sizeof(*resources)); + + // Constants. + resources->MaxVertexAttribs = 8; + resources->MaxVertexUniformVectors = 128; + resources->MaxVaryingVectors = 8; + resources->MaxVertexTextureImageUnits = 0; + resources->MaxCombinedTextureImageUnits = 8; + resources->MaxTextureImageUnits = 8; + resources->MaxFragmentUniformVectors = 16; + resources->MaxDrawBuffers = 1; + + // Extensions. + resources->OES_standard_derivatives = 0; + resources->OES_EGL_image_external = 0; + resources->OES_EGL_image_external_essl3 = 0; + resources->NV_EGL_stream_consumer_external = 0; + resources->ARB_texture_rectangle = 0; + resources->EXT_blend_func_extended = 0; + resources->EXT_draw_buffers = 0; + resources->EXT_frag_depth = 0; + resources->EXT_shader_texture_lod = 0; + resources->WEBGL_debug_shader_precision = 0; + resources->EXT_shader_framebuffer_fetch = 0; + resources->NV_shader_framebuffer_fetch = 0; + resources->ARM_shader_framebuffer_fetch = 0; + resources->OVR_multiview = 0; + resources->OVR_multiview2 = 0; + resources->EXT_YUV_target = 0; + resources->EXT_geometry_shader = 0; + resources->OES_texture_storage_multisample_2d_array = 0; + resources->OES_texture_3D = 0; + resources->ANGLE_texture_multisample = 0; + resources->ANGLE_multi_draw = 0; + resources->ANGLE_base_vertex_base_instance = 0; + + resources->NV_draw_buffers = 0; + + // Disable highp precision in fragment shader by default. + resources->FragmentPrecisionHigh = 0; + + // GLSL ES 3.0 constants. + resources->MaxVertexOutputVectors = 16; + resources->MaxFragmentInputVectors = 15; + resources->MinProgramTexelOffset = -8; + resources->MaxProgramTexelOffset = 7; + + // Extensions constants. + resources->MaxDualSourceDrawBuffers = 0; + + resources->MaxViewsOVR = 4; + + // Disable name hashing by default. + resources->HashFunction = nullptr; + + resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC; + + resources->MaxExpressionComplexity = 256; + resources->MaxCallStackDepth = 256; + resources->MaxFunctionParameters = 1024; + + // ES 3.1 Revision 4, 7.2 Built-in Constants + + // ES 3.1, Revision 4, 8.13 Texture minification + // "The value of MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be less than or equal to the value of + // MIN_PROGRAM_TEXEL_OFFSET. The value of MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be greater than + // or equal to the value of MAX_PROGRAM_TEXEL_OFFSET" + resources->MinProgramTextureGatherOffset = -8; + resources->MaxProgramTextureGatherOffset = 7; + + resources->MaxImageUnits = 4; + resources->MaxVertexImageUniforms = 0; + resources->MaxFragmentImageUniforms = 0; + resources->MaxComputeImageUniforms = 4; + resources->MaxCombinedImageUniforms = 4; + + resources->MaxUniformLocations = 1024; + + resources->MaxCombinedShaderOutputResources = 4; + + resources->MaxComputeWorkGroupCount[0] = 65535; + resources->MaxComputeWorkGroupCount[1] = 65535; + resources->MaxComputeWorkGroupCount[2] = 65535; + resources->MaxComputeWorkGroupSize[0] = 128; + resources->MaxComputeWorkGroupSize[1] = 128; + resources->MaxComputeWorkGroupSize[2] = 64; + resources->MaxComputeUniformComponents = 512; + resources->MaxComputeTextureImageUnits = 16; + + resources->MaxComputeAtomicCounters = 8; + resources->MaxComputeAtomicCounterBuffers = 1; + + resources->MaxVertexAtomicCounters = 0; + resources->MaxFragmentAtomicCounters = 0; + resources->MaxCombinedAtomicCounters = 8; + resources->MaxAtomicCounterBindings = 1; + + resources->MaxVertexAtomicCounterBuffers = 0; + resources->MaxFragmentAtomicCounterBuffers = 0; + resources->MaxCombinedAtomicCounterBuffers = 1; + resources->MaxAtomicCounterBufferSize = 32; + + resources->MaxUniformBufferBindings = 32; + resources->MaxShaderStorageBufferBindings = 4; + + resources->MaxGeometryUniformComponents = 1024; + resources->MaxGeometryUniformBlocks = 12; + resources->MaxGeometryInputComponents = 64; + resources->MaxGeometryOutputComponents = 64; + resources->MaxGeometryOutputVertices = 256; + resources->MaxGeometryTotalOutputComponents = 1024; + resources->MaxGeometryTextureImageUnits = 16; + resources->MaxGeometryAtomicCounterBuffers = 0; + resources->MaxGeometryAtomicCounters = 0; + resources->MaxGeometryShaderStorageBlocks = 0; + resources->MaxGeometryShaderInvocations = 32; + resources->MaxGeometryImageUniforms = 0; +} + +// +// Driver calls these to create and destroy compiler objects. +// +ShHandle ConstructCompiler(sh::GLenum type, + ShShaderSpec spec, + ShShaderOutput output, + const ShBuiltInResources *resources) +{ + TShHandleBase *base = static_cast<TShHandleBase *>(ConstructCompiler(type, spec, output)); + if (base == nullptr) + { + return 0; + } + + TCompiler *compiler = base->getAsCompiler(); + if (compiler == nullptr) + { + return 0; + } + + // Generate built-in symbol table. + if (!compiler->Init(*resources)) + { + Destruct(base); + return 0; + } + + return base; +} + +void Destruct(ShHandle handle) +{ + if (handle == 0) + return; + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + + if (base->getAsCompiler()) + DeleteCompiler(base->getAsCompiler()); +} + +const std::string &GetBuiltInResourcesString(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return compiler->getBuiltInResourcesString(); +} + +// +// Do an actual compile on the given strings. The result is left +// in the given compile object. +// +// Return: The return value of ShCompile is really boolean, indicating +// success or failure. +// +bool Compile(const ShHandle handle, + const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + + return compiler->compile(shaderStrings, numStrings, compileOptions); +} + +void ClearResults(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + compiler->clearResults(); +} + +int GetShaderVersion(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return compiler->getShaderVersion(); +} + +ShShaderOutput GetShaderOutputType(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return compiler->getOutputType(); +} + +// +// Return any compiler log of messages for the application. +// +const std::string &GetInfoLog(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + + TInfoSink &infoSink = compiler->getInfoSink(); + return infoSink.info.str(); +} + +// +// Return any object code. +// +const std::string &GetObjectCode(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + + TInfoSink &infoSink = compiler->getInfoSink(); + return infoSink.obj.str(); +} + +const std::map<std::string, std::string> *GetNameHashingMap(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return &(compiler->getNameMap()); +} + +const std::vector<Uniform> *GetUniforms(const ShHandle handle) +{ + return GetShaderVariables<Uniform>(handle); +} + +const std::vector<Varying> *GetInputVaryings(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + if (compiler == nullptr) + { + return nullptr; + } + return &compiler->getInputVaryings(); +} + +const std::vector<Varying> *GetOutputVaryings(const ShHandle handle) +{ + TCompiler *compiler = GetCompilerFromHandle(handle); + if (compiler == nullptr) + { + return nullptr; + } + return &compiler->getOutputVaryings(); +} + +const std::vector<Varying> *GetVaryings(const ShHandle handle) +{ + return GetShaderVariables<Varying>(handle); +} + +const std::vector<Attribute> *GetAttributes(const ShHandle handle) +{ + return GetShaderVariables<Attribute>(handle); +} + +const std::vector<OutputVariable> *GetOutputVariables(const ShHandle handle) +{ + return GetShaderVariables<OutputVariable>(handle); +} + +const std::vector<InterfaceBlock> *GetInterfaceBlocks(const ShHandle handle) +{ + return GetShaderVariables<InterfaceBlock>(handle); +} + +const std::vector<InterfaceBlock> *GetUniformBlocks(const ShHandle handle) +{ + ASSERT(handle); + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return &compiler->getUniformBlocks(); +} + +const std::vector<InterfaceBlock> *GetShaderStorageBlocks(const ShHandle handle) +{ + ASSERT(handle); + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return &compiler->getShaderStorageBlocks(); +} + +WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getComputeShaderLocalSize(); +} + +int GetVertexShaderNumViews(const ShHandle handle) +{ + ASSERT(handle); + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getNumViews(); +} + +bool CheckVariablesWithinPackingLimits(int maxVectors, const std::vector<ShaderVariable> &variables) +{ + return CheckVariablesInPackingLimits(maxVectors, variables); +} + +bool GetShaderStorageBlockRegister(const ShHandle handle, + const std::string &shaderStorageBlockName, + unsigned int *indexOut) +{ +#ifdef ANGLE_ENABLE_HLSL + ASSERT(indexOut); + + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); + + if (!translator->hasShaderStorageBlock(shaderStorageBlockName)) + { + return false; + } + + *indexOut = translator->getShaderStorageBlockRegister(shaderStorageBlockName); + return true; +#else + return false; +#endif // ANGLE_ENABLE_HLSL +} + +bool GetUniformBlockRegister(const ShHandle handle, + const std::string &uniformBlockName, + unsigned int *indexOut) +{ +#ifdef ANGLE_ENABLE_HLSL + ASSERT(indexOut); + + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); + + if (!translator->hasUniformBlock(uniformBlockName)) + { + return false; + } + + *indexOut = translator->getUniformBlockRegister(uniformBlockName); + return true; +#else + return false; +#endif // ANGLE_ENABLE_HLSL +} + +const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle handle) +{ +#ifdef ANGLE_ENABLE_HLSL + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); + + return translator->getUniformRegisterMap(); +#else + return nullptr; +#endif // ANGLE_ENABLE_HLSL +} + +unsigned int GetReadonlyImage2DRegisterIndex(const ShHandle handle) +{ +#ifdef ANGLE_ENABLE_HLSL + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); + + return translator->getReadonlyImage2DRegisterIndex(); +#else + return 0; +#endif // ANGLE_ENABLE_HLSL +} + +unsigned int GetImage2DRegisterIndex(const ShHandle handle) +{ +#ifdef ANGLE_ENABLE_HLSL + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); + + return translator->getImage2DRegisterIndex(); +#else + return 0; +#endif // ANGLE_ENABLE_HLSL +} + +const std::set<std::string> *GetUsedImage2DFunctionNames(const ShHandle handle) +{ +#ifdef ANGLE_ENABLE_HLSL + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); + + return translator->getUsedImage2DFunctionNames(); +#else + return nullptr; +#endif // ANGLE_ENABLE_HLSL +} + +bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getGeometryShaderInputPrimitiveType() != EptUndefined; +} + +bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getGeometryShaderOutputPrimitiveType() != EptUndefined; +} + +bool HasValidGeometryShaderMaxVertices(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getGeometryShaderMaxVertices() >= 0; +} + +GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return GetGeometryShaderPrimitiveTypeEnum(compiler->getGeometryShaderInputPrimitiveType()); +} + +GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return GetGeometryShaderPrimitiveTypeEnum(compiler->getGeometryShaderOutputPrimitiveType()); +} + +int GetGeometryShaderInvocations(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getGeometryShaderInvocations(); +} + +int GetGeometryShaderMaxVertices(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + int maxVertices = compiler->getGeometryShaderMaxVertices(); + ASSERT(maxVertices >= 0); + return maxVertices; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp new file mode 100644 index 0000000000..01b246d1d7 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.cpp @@ -0,0 +1,435 @@ +// +// 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. +// +// ShaderStorageBlockFunctionHLSL: Wrapper functions for RWByteAddressBuffer Load/Store functions. +// + +#include "compiler/translator/ShaderStorageBlockFunctionHLSL.h" + +#include "common/utilities.h" +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/blocklayout.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +// static +void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody( + TInfoSinkBase &out, + const ShaderStorageBlockFunction &ssboFunction) +{ + const char *convertString; + switch (ssboFunction.type.getBasicType()) + { + case EbtFloat: + convertString = "asfloat("; + break; + case EbtInt: + convertString = "asint("; + break; + case EbtUInt: + convertString = "asuint("; + break; + case EbtBool: + convertString = "asint("; + break; + default: + UNREACHABLE(); + return; + } + + size_t bytesPerComponent = + gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type))); + out << " " << ssboFunction.typeString << " result"; + if (ssboFunction.type.isScalar()) + { + size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent; + out << " = " << convertString << "buffer.Load(loc + " << offset << "));\n "; + } + else if (ssboFunction.type.isVector()) + { + if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle) + { + size_t componentStride = bytesPerComponent; + if (ssboFunction.rowMajor) + { + componentStride = ssboFunction.matrixStride; + } + + out << " = {"; + for (const int offset : ssboFunction.swizzleOffsets) + { + size_t offsetInBytes = offset * componentStride; + out << convertString << "buffer.Load(loc + " << offsetInBytes << ")),"; + } + out << "};\n"; + } + else + { + out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize() + << "(loc));\n"; + } + } + else if (ssboFunction.type.isMatrix()) + { + if (ssboFunction.rowMajor) + { + out << ";"; + out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols() + << " tmp_ = {"; + for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++) + { + out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc + " + << rowIndex * ssboFunction.matrixStride << ")), "; + } + out << "};\n"; + out << " result = transpose(tmp_);\n"; + } + else + { + out << " = {"; + for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++) + { + out << "asfloat(buffer.Load" << ssboFunction.type.getRows() << "(loc + " + << columnIndex * ssboFunction.matrixStride << ")), "; + } + out << "};\n"; + } + } + else + { + // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951 + out << ";\n"; + } + + out << " return result;\n"; + return; +} + +// static +void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody( + TInfoSinkBase &out, + const ShaderStorageBlockFunction &ssboFunction) +{ + size_t bytesPerComponent = + gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type))); + if (ssboFunction.type.isScalar()) + { + size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent; + if (ssboFunction.type.getBasicType() == EbtBool) + { + out << " buffer.Store(loc + " << offset << ", uint(value));\n"; + } + else + { + out << " buffer.Store(loc + " << offset << ", asuint(value));\n"; + } + } + else if (ssboFunction.type.isVector()) + { + out << " uint" << ssboFunction.type.getNominalSize() << " _value;\n"; + if (ssboFunction.type.getBasicType() == EbtBool) + { + out << " _value = uint" << ssboFunction.type.getNominalSize() << "(value);\n"; + } + else + { + out << " _value = asuint(value);\n"; + } + + if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle) + { + size_t componentStride = bytesPerComponent; + if (ssboFunction.rowMajor) + { + componentStride = ssboFunction.matrixStride; + } + const TVector<int> &swizzleOffsets = ssboFunction.swizzleOffsets; + for (int index = 0; index < static_cast<int>(swizzleOffsets.size()); index++) + { + size_t offsetInBytes = swizzleOffsets[index] * componentStride; + out << "buffer.Store(loc + " << offsetInBytes << ", _value[" << index << "]);\n"; + } + } + else + { + out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _value);\n"; + } + } + else if (ssboFunction.type.isMatrix()) + { + if (ssboFunction.rowMajor) + { + out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols() + << " tmp_ = transpose(value);\n"; + for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++) + { + out << " buffer.Store" << ssboFunction.type.getCols() << "(loc + " + << rowIndex * ssboFunction.matrixStride << ", asuint(tmp_[" << rowIndex + << "]));\n"; + } + } + else + { + for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++) + { + out << " buffer.Store" << ssboFunction.type.getRows() << "(loc + " + << columnIndex * ssboFunction.matrixStride << ", asuint(value[" << columnIndex + << "]));\n"; + } + } + } + else + { + // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951 + } +} + +// static +void ShaderStorageBlockFunctionHLSL::OutputSSBOLengthFunctionBody(TInfoSinkBase &out, + int unsizedArrayStride) +{ + out << " uint dim = 0;\n"; + out << " buffer.GetDimensions(dim);\n"; + out << " return int((dim - loc)/uint(" << unsizedArrayStride << "));\n"; +} + +// static +void ShaderStorageBlockFunctionHLSL::OutputSSBOAtomicMemoryFunctionBody( + TInfoSinkBase &out, + const ShaderStorageBlockFunction &ssboFunction) +{ + out << " " << ssboFunction.typeString << " original_value;\n"; + switch (ssboFunction.method) + { + case SSBOMethod::ATOMIC_ADD: + out << " buffer.InterlockedAdd(loc, value, original_value);\n"; + break; + case SSBOMethod::ATOMIC_MIN: + out << " buffer.InterlockedMin(loc, value, original_value);\n"; + break; + case SSBOMethod::ATOMIC_MAX: + out << " buffer.InterlockedMax(loc, value, original_value);\n"; + break; + case SSBOMethod::ATOMIC_AND: + out << " buffer.InterlockedAnd(loc, value, original_value);\n"; + break; + case SSBOMethod::ATOMIC_OR: + out << " buffer.InterlockedOr(loc, value, original_value);\n"; + break; + case SSBOMethod::ATOMIC_XOR: + out << " buffer.InterlockedXor(loc, value, original_value);\n"; + break; + case SSBOMethod::ATOMIC_EXCHANGE: + out << " buffer.InterlockedExchange(loc, value, original_value);\n"; + break; + case SSBOMethod::ATOMIC_COMPSWAP: + out << " buffer.InterlockedCompareExchange(loc, compare_value, value, " + "original_value);\n"; + break; + default: + UNREACHABLE(); + } + out << " return original_value;\n"; +} + +bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<( + const ShaderStorageBlockFunction &rhs) const +{ + return functionName < rhs.functionName; +} + +TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction( + const TType &type, + SSBOMethod method, + TLayoutBlockStorage storage, + bool rowMajor, + int matrixStride, + int unsizedArrayStride, + TIntermSwizzle *swizzleNode) +{ + ShaderStorageBlockFunction ssboFunction; + ssboFunction.typeString = TypeString(type); + ssboFunction.method = method; + switch (method) + { + case SSBOMethod::LOAD: + ssboFunction.functionName = "_Load_"; + break; + case SSBOMethod::STORE: + ssboFunction.functionName = "_Store_"; + break; + case SSBOMethod::LENGTH: + ssboFunction.unsizedArrayStride = unsizedArrayStride; + ssboFunction.functionName = "_Length_" + str(unsizedArrayStride); + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_ADD: + ssboFunction.functionName = "_ssbo_atomicAdd_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_MIN: + ssboFunction.functionName = "_ssbo_atomicMin_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_MAX: + ssboFunction.functionName = "_ssbo_atomicMax_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_AND: + ssboFunction.functionName = "_ssbo_atomicAnd_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_OR: + ssboFunction.functionName = "_ssbo_atomicOr_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_XOR: + ssboFunction.functionName = "_ssbo_atomicXor_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_EXCHANGE: + ssboFunction.functionName = "_ssbo_atomicExchange_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + case SSBOMethod::ATOMIC_COMPSWAP: + ssboFunction.functionName = "_ssbo_atomicCompSwap_" + ssboFunction.typeString; + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; + default: + UNREACHABLE(); + } + + ssboFunction.functionName += ssboFunction.typeString; + ssboFunction.type = type; + if (swizzleNode != nullptr) + { + ssboFunction.swizzleOffsets = swizzleNode->getSwizzleOffsets(); + ssboFunction.isDefaultSwizzle = false; + } + else + { + if (ssboFunction.type.getNominalSize() > 1) + { + for (int index = 0; index < ssboFunction.type.getNominalSize(); index++) + { + ssboFunction.swizzleOffsets.push_back(index); + } + } + else + { + ssboFunction.swizzleOffsets.push_back(0); + } + + ssboFunction.isDefaultSwizzle = true; + } + ssboFunction.rowMajor = rowMajor; + ssboFunction.matrixStride = matrixStride; + ssboFunction.functionName += "_" + TString(getBlockStorageString(storage)); + + if (rowMajor) + { + ssboFunction.functionName += "_rm_"; + } + else + { + ssboFunction.functionName += "_cm_"; + } + + for (const int offset : ssboFunction.swizzleOffsets) + { + switch (offset) + { + case 0: + ssboFunction.functionName += "x"; + break; + case 1: + ssboFunction.functionName += "y"; + break; + case 2: + ssboFunction.functionName += "z"; + break; + case 3: + ssboFunction.functionName += "w"; + break; + default: + UNREACHABLE(); + } + } + + mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); + return ssboFunction.functionName; +} + +void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkBase &out) +{ + for (const ShaderStorageBlockFunction &ssboFunction : mRegisteredShaderStorageBlockFunctions) + { + switch (ssboFunction.method) + { + case SSBOMethod::LOAD: + { + // Function header + out << ssboFunction.typeString << " " << ssboFunction.functionName + << "(RWByteAddressBuffer buffer, uint loc)\n"; + out << "{\n"; + OutputSSBOLoadFunctionBody(out, ssboFunction); + break; + } + case SSBOMethod::STORE: + { + // Function header + out << "void " << ssboFunction.functionName + << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString + << " value)\n"; + out << "{\n"; + OutputSSBOStoreFunctionBody(out, ssboFunction); + break; + } + case SSBOMethod::LENGTH: + { + out << "int " << ssboFunction.functionName + << "(RWByteAddressBuffer buffer, uint loc)\n"; + out << "{\n"; + OutputSSBOLengthFunctionBody(out, ssboFunction.unsizedArrayStride); + break; + } + case SSBOMethod::ATOMIC_ADD: + case SSBOMethod::ATOMIC_MIN: + case SSBOMethod::ATOMIC_MAX: + case SSBOMethod::ATOMIC_AND: + case SSBOMethod::ATOMIC_OR: + case SSBOMethod::ATOMIC_XOR: + case SSBOMethod::ATOMIC_EXCHANGE: + { + out << ssboFunction.typeString << " " << ssboFunction.functionName + << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString + << " value)\n"; + out << "{\n"; + + OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction); + break; + } + case SSBOMethod::ATOMIC_COMPSWAP: + { + out << ssboFunction.typeString << " " << ssboFunction.functionName + << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString + << " compare_value, " << ssboFunction.typeString << " value)\n"; + out << "{\n"; + OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction); + break; + } + default: + UNREACHABLE(); + } + + out << "}\n" + "\n"; + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.h new file mode 100644 index 0000000000..0d3cd0291b --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockFunctionHLSL.h @@ -0,0 +1,94 @@ +// +// 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. +// +// ShaderStorageBlockOutputHLSL: A traverser to translate a ssbo_access_chain to an offset of +// RWByteAddressBuffer. +// //EOpIndexDirectInterfaceBlock +// ssbo_variable := +// | the name of the SSBO +// | the name of a variable in an SSBO backed interface block + +// // EOpIndexInDirect +// // EOpIndexDirect +// ssbo_array_indexing := ssbo_access_chain[expr_no_ssbo] + +// // EOpIndexDirectStruct +// ssbo_structure_access := ssbo_access_chain.identifier + +// ssbo_access_chain := +// | ssbo_variable +// | ssbo_array_indexing +// | ssbo_structure_access +// + +#ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_ +#define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_ + +#include <set> + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/Types.h" + +namespace sh +{ + +class TIntermSwizzle; +enum class SSBOMethod +{ + LOAD, + STORE, + LENGTH, + ATOMIC_ADD, + ATOMIC_MIN, + ATOMIC_MAX, + ATOMIC_AND, + ATOMIC_OR, + ATOMIC_XOR, + ATOMIC_EXCHANGE, + ATOMIC_COMPSWAP +}; + +class ShaderStorageBlockFunctionHLSL final : angle::NonCopyable +{ + public: + TString registerShaderStorageBlockFunction(const TType &type, + SSBOMethod method, + TLayoutBlockStorage storage, + bool rowMajor, + int matrixStride, + int unsizedArrayStride, + TIntermSwizzle *node); + + void shaderStorageBlockFunctionHeader(TInfoSinkBase &out); + + private: + struct ShaderStorageBlockFunction + { + bool operator<(const ShaderStorageBlockFunction &rhs) const; + TString functionName; + TString typeString; + SSBOMethod method; + TType type; + bool rowMajor; + int matrixStride; + int unsizedArrayStride; + TVector<int> swizzleOffsets; + bool isDefaultSwizzle; + }; + + static void OutputSSBOLoadFunctionBody(TInfoSinkBase &out, + const ShaderStorageBlockFunction &ssboFunction); + static void OutputSSBOStoreFunctionBody(TInfoSinkBase &out, + const ShaderStorageBlockFunction &ssboFunction); + static void OutputSSBOLengthFunctionBody(TInfoSinkBase &out, int unsizedArrayStride); + static void OutputSSBOAtomicMemoryFunctionBody(TInfoSinkBase &out, + const ShaderStorageBlockFunction &ssboFunction); + using ShaderStorageBlockFunctionSet = std::set<ShaderStorageBlockFunction>; + ShaderStorageBlockFunctionSet mRegisteredShaderStorageBlockFunctions; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKFUNCTIONHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp new file mode 100644 index 0000000000..bef88db386 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.cpp @@ -0,0 +1,762 @@ +// +// 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. +// +// ShaderStorageBlockOutputHLSL: A traverser to translate a ssbo_access_chain to an offset of +// RWByteAddressBuffer. +// //EOpIndexDirectInterfaceBlock +// ssbo_variable := +// | the name of the SSBO +// | the name of a variable in an SSBO backed interface block + +// // EOpIndexInDirect +// // EOpIndexDirect +// ssbo_array_indexing := ssbo_access_chain[expr_no_ssbo] + +// // EOpIndexDirectStruct +// ssbo_structure_access := ssbo_access_chain.identifier + +// ssbo_access_chain := +// | ssbo_variable +// | ssbo_array_indexing +// | ssbo_structure_access +// + +#include "compiler/translator/ShaderStorageBlockOutputHLSL.h" + +#include "compiler/translator/ResourcesHLSL.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +void GetBlockLayoutInfo(TIntermTyped *node, + bool rowMajorAlreadyAssigned, + TLayoutBlockStorage *storage, + bool *rowMajor) +{ + TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); + if (swizzleNode) + { + return GetBlockLayoutInfo(swizzleNode->getOperand(), rowMajorAlreadyAssigned, storage, + rowMajor); + } + + TIntermBinary *binaryNode = node->getAsBinaryNode(); + if (binaryNode) + { + switch (binaryNode->getOp()) + { + case EOpIndexDirectInterfaceBlock: + { + // The column_major/row_major qualifier of a field member overrides the interface + // block's row_major/column_major. So we can assign rowMajor here and don't need to + // assign it again. But we still need to call recursively to get the storage's + // value. + const TType &type = node->getType(); + *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor; + return GetBlockLayoutInfo(binaryNode->getLeft(), true, storage, rowMajor); + } + case EOpIndexIndirect: + case EOpIndexDirect: + case EOpIndexDirectStruct: + return GetBlockLayoutInfo(binaryNode->getLeft(), rowMajorAlreadyAssigned, storage, + rowMajor); + default: + UNREACHABLE(); + return; + } + } + + const TType &type = node->getType(); + ASSERT(type.getQualifier() == EvqBuffer); + const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); + ASSERT(interfaceBlock); + *storage = interfaceBlock->blockStorage(); + // If the block doesn't have an instance name, rowMajorAlreadyAssigned will be false. In + // this situation, we still need to set rowMajor's value. + if (!rowMajorAlreadyAssigned) + { + *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor; + } +} + +// It's possible that the current type has lost the original layout information. So we should pass +// the right layout information to GetBlockMemberInfoByType. +const BlockMemberInfo GetBlockMemberInfoByType(const TType &type, + TLayoutBlockStorage storage, + bool rowMajor) +{ + sh::Std140BlockEncoder std140Encoder; + sh::Std430BlockEncoder std430Encoder; + sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false); + sh::BlockLayoutEncoder *encoder = nullptr; + + if (storage == EbsStd140) + { + encoder = &std140Encoder; + } + else if (storage == EbsStd430) + { + encoder = &std430Encoder; + } + else + { + encoder = &hlslEncoder; + } + + std::vector<unsigned int> arraySizes; + auto *typeArraySizes = type.getArraySizes(); + if (typeArraySizes != nullptr) + { + arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end()); + } + return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor); +} + +const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock, + const ImmutableString &variableName) +{ + for (const TField *field : interfaceBlock->fields()) + { + if (field->name() == variableName) + { + return field; + } + } + return nullptr; +} + +const InterfaceBlock *FindInterfaceBlock(const TInterfaceBlock *needle, + const std::vector<InterfaceBlock> &haystack) +{ + for (const InterfaceBlock &block : haystack) + { + if (strcmp(block.name.c_str(), needle->name().data()) == 0) + { + ASSERT(block.fields.size() == needle->fields().size()); + return █ + } + } + + UNREACHABLE(); + return nullptr; +} + +std::string StripArrayIndices(const std::string &nameIn) +{ + std::string name = nameIn; + size_t pos = name.find('['); + while (pos != std::string::npos) + { + size_t closePos = name.find(']', pos); + ASSERT(closePos != std::string::npos); + name.erase(pos, closePos - pos + 1); + pos = name.find('[', pos); + } + ASSERT(name.find(']') == std::string::npos); + return name; +} + +// Does not include any array indices. +void MapVariableToField(const ShaderVariable &variable, + const TField *field, + std::string currentName, + ShaderVarToFieldMap *shaderVarToFieldMap) +{ + ASSERT((field->type()->getStruct() == nullptr) == variable.fields.empty()); + (*shaderVarToFieldMap)[currentName] = field; + + if (!variable.fields.empty()) + { + const TStructure *subStruct = field->type()->getStruct(); + ASSERT(variable.fields.size() == subStruct->fields().size()); + + for (size_t index = 0; index < variable.fields.size(); ++index) + { + const TField *subField = subStruct->fields()[index]; + const ShaderVariable &subVariable = variable.fields[index]; + std::string subName = currentName + "." + subVariable.name; + MapVariableToField(subVariable, subField, subName, shaderVarToFieldMap); + } + } +} + +class BlockInfoVisitor final : public BlockEncoderVisitor +{ + public: + BlockInfoVisitor(const std::string &prefix, + TLayoutBlockStorage storage, + const ShaderVarToFieldMap &shaderVarToFieldMap, + BlockMemberInfoMap *blockInfoOut) + : BlockEncoderVisitor(prefix, "", getEncoder(storage)), + mShaderVarToFieldMap(shaderVarToFieldMap), + mBlockInfoOut(blockInfoOut), + mHLSLEncoder(HLSLBlockEncoder::ENCODE_PACKED, false), + mStorage(storage) + {} + + BlockLayoutEncoder *getEncoder(TLayoutBlockStorage storage) + { + switch (storage) + { + case EbsStd140: + return &mStd140Encoder; + case EbsStd430: + return &mStd430Encoder; + default: + return &mHLSLEncoder; + } + } + + void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override + { + BlockEncoderVisitor::enterStructAccess(structVar, isRowMajor); + + std::string variableName = StripArrayIndices(collapseNameStack()); + + // Remove the trailing "." + variableName.pop_back(); + + BlockInfoVisitor childVisitor(variableName, mStorage, mShaderVarToFieldMap, mBlockInfoOut); + childVisitor.getEncoder(mStorage)->enterAggregateType(structVar); + TraverseShaderVariables(structVar.fields, isRowMajor, &childVisitor); + childVisitor.getEncoder(mStorage)->exitAggregateType(structVar); + + int offset = getEncoder(mStorage)->getCurrentOffset(); + int arrayStride = childVisitor.getEncoder(mStorage)->getCurrentOffset(); + + auto iter = mShaderVarToFieldMap.find(variableName); + if (iter == mShaderVarToFieldMap.end()) + return; + + const TField *structField = iter->second; + if (mBlockInfoOut->count(structField) == 0) + { + mBlockInfoOut->emplace(structField, BlockMemberInfo(offset, arrayStride, -1, false)); + } + } + + void encodeVariable(const ShaderVariable &variable, + const BlockMemberInfo &variableInfo, + const std::string &name, + const std::string &mappedName) override + { + auto iter = mShaderVarToFieldMap.find(StripArrayIndices(name)); + if (iter == mShaderVarToFieldMap.end()) + return; + + const TField *field = iter->second; + if (mBlockInfoOut->count(field) == 0) + { + mBlockInfoOut->emplace(field, variableInfo); + } + } + + private: + const ShaderVarToFieldMap &mShaderVarToFieldMap; + BlockMemberInfoMap *mBlockInfoOut; + Std140BlockEncoder mStd140Encoder; + Std430BlockEncoder mStd430Encoder; + HLSLBlockEncoder mHLSLEncoder; + TLayoutBlockStorage mStorage; +}; + +void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock, + const std::vector<InterfaceBlock> &shaderStorageBlocks, + BlockMemberInfoMap *blockInfoOut) +{ + // Find the sh::InterfaceBlock. + const InterfaceBlock *block = FindInterfaceBlock(interfaceBlock, shaderStorageBlocks); + ASSERT(block); + + // Map ShaderVariable to TField. + ShaderVarToFieldMap shaderVarToFieldMap; + for (size_t index = 0; index < block->fields.size(); ++index) + { + const TField *field = interfaceBlock->fields()[index]; + const ShaderVariable &variable = block->fields[index]; + MapVariableToField(variable, field, variable.name, &shaderVarToFieldMap); + } + + BlockInfoVisitor visitor("", interfaceBlock->blockStorage(), shaderVarToFieldMap, blockInfoOut); + TraverseShaderVariables(block->fields, false, &visitor); +} + +bool IsInArrayOfArraysChain(TIntermTyped *node) +{ + if (node->getType().isArrayOfArrays()) + return true; + TIntermBinary *binaryNode = node->getAsBinaryNode(); + if (binaryNode) + { + if (binaryNode->getLeft()->getType().isArrayOfArrays()) + return true; + } + + return false; +} +} // anonymous namespace + +ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL( + OutputHLSL *outputHLSL, + TSymbolTable *symbolTable, + ResourcesHLSL *resourcesHLSL, + const std::vector<InterfaceBlock> &shaderStorageBlocks) + : TIntermTraverser(true, true, true, symbolTable), + mMatrixStride(0), + mRowMajor(false), + mLocationAsTheLastArgument(false), + mOutputHLSL(outputHLSL), + mResourcesHLSL(resourcesHLSL), + mShaderStorageBlocks(shaderStorageBlocks) +{ + mSSBOFunctionHLSL = new ShaderStorageBlockFunctionHLSL; +} + +ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL() +{ + SafeDelete(mSSBOFunctionHLSL); +} + +void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node) +{ + mLocationAsTheLastArgument = false; + traverseSSBOAccess(node, SSBOMethod::STORE); +} + +void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node) +{ + mLocationAsTheLastArgument = true; + traverseSSBOAccess(node, SSBOMethod::LOAD); +} + +void ShaderStorageBlockOutputHLSL::outputLengthFunctionCall(TIntermTyped *node) +{ + mLocationAsTheLastArgument = true; + traverseSSBOAccess(node, SSBOMethod::LENGTH); +} + +void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node, + TOperator op) +{ + mLocationAsTheLastArgument = false; + + switch (op) + { + case EOpAtomicAdd: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_ADD); + break; + case EOpAtomicMin: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_MIN); + break; + case EOpAtomicMax: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_MAX); + break; + case EOpAtomicAnd: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_AND); + break; + case EOpAtomicOr: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_OR); + break; + case EOpAtomicXor: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_XOR); + break; + case EOpAtomicExchange: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_EXCHANGE); + break; + case EOpAtomicCompSwap: + traverseSSBOAccess(node, SSBOMethod::ATOMIC_COMPSWAP); + break; + default: + UNREACHABLE(); + break; + } +} + +// Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL. +// It's because that if the current node's type is a vector which comes from a matrix, we will +// lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL. +void ShaderStorageBlockOutputHLSL::setMatrixStride(TIntermTyped *node, + TLayoutBlockStorage storage, + bool rowMajor) +{ + if (node->getType().isMatrix()) + { + mMatrixStride = GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride; + mRowMajor = rowMajor; + return; + } + + if (node->getType().isVector()) + { + TIntermBinary *binaryNode = node->getAsBinaryNode(); + if (binaryNode) + { + return setMatrixStride(binaryNode->getLeft(), storage, rowMajor); + } + else + { + TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); + if (swizzleNode) + { + return setMatrixStride(swizzleNode->getOperand(), storage, rowMajor); + } + } + } +} + +void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method) +{ + mMatrixStride = 0; + mRowMajor = false; + + // Note that we don't have correct BlockMemberInfo from mBlockMemberInfoMap at the current + // point. But we must use those information to generate the right function name. So here we have + // to calculate them again. + TLayoutBlockStorage storage; + bool rowMajor; + GetBlockLayoutInfo(node, false, &storage, &rowMajor); + int unsizedArrayStride = 0; + if (node->getType().isUnsizedArray()) + { + unsizedArrayStride = + GetBlockMemberInfoByType(node->getType(), storage, rowMajor).arrayStride; + } + setMatrixStride(node, storage, rowMajor); + + const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction( + node->getType(), method, storage, mRowMajor, mMatrixStride, unsizedArrayStride, + node->getAsSwizzleNode()); + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); + out << functionName; + out << "("; + node->traverse(this); +} + +void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(TInfoSinkBase &out) const +{ + out << mResourcesHLSL->shaderStorageBlocksHeader(mReferencedShaderStorageBlocks); + mSSBOFunctionHLSL->shaderStorageBlockFunctionHeader(out); +} + +// Check if the current node is the end of the SSBO access chain. If true, we should output ')' for +// Load method. +bool ShaderStorageBlockOutputHLSL::isEndOfSSBOAccessChain() +{ + TIntermNode *parent = getParentNode(); + if (parent) + { + TIntermBinary *parentBinary = parent->getAsBinaryNode(); + if (parentBinary != nullptr) + { + switch (parentBinary->getOp()) + { + case EOpIndexDirectStruct: + case EOpIndexDirect: + case EOpIndexIndirect: + { + return false; + } + default: + return true; + } + } + + const TIntermSwizzle *parentSwizzle = parent->getAsSwizzleNode(); + if (parentSwizzle) + { + return false; + } + } + return true; +} + +void ShaderStorageBlockOutputHLSL::visitSymbol(TIntermSymbol *node) +{ + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); + const TVariable &variable = node->variable(); + TQualifier qualifier = variable.getType().getQualifier(); + + if (qualifier == EvqBuffer) + { + const TType &variableType = variable.getType(); + const TInterfaceBlock *interfaceBlock = variableType.getInterfaceBlock(); + ASSERT(interfaceBlock); + if (mReferencedShaderStorageBlocks.count(interfaceBlock->uniqueId().get()) == 0) + { + const TVariable *instanceVariable = nullptr; + if (variableType.isInterfaceBlock()) + { + instanceVariable = &variable; + } + mReferencedShaderStorageBlocks[interfaceBlock->uniqueId().get()] = + new TReferencedBlock(interfaceBlock, instanceVariable); + GetShaderStorageBlockMembersInfo(interfaceBlock, mShaderStorageBlocks, + &mBlockMemberInfoMap); + } + if (variableType.isInterfaceBlock()) + { + out << DecorateVariableIfNeeded(variable); + } + else + { + out << Decorate(interfaceBlock->name()); + out << ", "; + + const TField *field = + GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name()); + writeDotOperatorOutput(out, field); + } + } + else + { + return mOutputHLSL->visitSymbol(node); + } +} + +void ShaderStorageBlockOutputHLSL::visitConstantUnion(TIntermConstantUnion *node) +{ + mOutputHLSL->visitConstantUnion(node); +} + +bool ShaderStorageBlockOutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) +{ + return mOutputHLSL->visitAggregate(visit, node); +} + +bool ShaderStorageBlockOutputHLSL::visitTernary(Visit visit, TIntermTernary *node) +{ + return mOutputHLSL->visitTernary(visit, node); +} + +bool ShaderStorageBlockOutputHLSL::visitUnary(Visit visit, TIntermUnary *node) +{ + return mOutputHLSL->visitUnary(visit, node); +} + +bool ShaderStorageBlockOutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + if (visit == PostVisit) + { + if (!IsInShaderStorageBlock(node)) + { + return mOutputHLSL->visitSwizzle(visit, node); + } + + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); + // TODO(jiajia.qin@intel.com): add swizzle process if the swizzle node is not the last node + // of ssbo access chain. Such as, data.xy[0] + if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain()) + { + out << ")"; + } + } + return true; +} + +bool ShaderStorageBlockOutputHLSL::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); + + switch (node->getOp()) + { + case EOpIndexDirect: + { + if (!IsInShaderStorageBlock(node->getLeft())) + { + return mOutputHLSL->visitBinary(visit, node); + } + + const TType &leftType = node->getLeft()->getType(); + if (leftType.isInterfaceBlock()) + { + if (visit == PreVisit) + { + ASSERT(leftType.getQualifier() == EvqBuffer); + TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode(); + const TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock(); + + if (mReferencedShaderStorageBlocks.count(interfaceBlock->uniqueId().get()) == 0) + { + mReferencedShaderStorageBlocks[interfaceBlock->uniqueId().get()] = + new TReferencedBlock(interfaceBlock, &instanceArraySymbol->variable()); + GetShaderStorageBlockMembersInfo(interfaceBlock, mShaderStorageBlocks, + &mBlockMemberInfoMap); + } + + const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0); + out << mResourcesHLSL->InterfaceBlockInstanceString( + instanceArraySymbol->getName(), arrayIndex); + return false; + } + } + else + { + writeEOpIndexDirectOrIndirectOutput(out, visit, node); + } + break; + } + case EOpIndexIndirect: + { + if (!IsInShaderStorageBlock(node->getLeft())) + { + return mOutputHLSL->visitBinary(visit, node); + } + + // We do not currently support indirect references to interface blocks + ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock); + writeEOpIndexDirectOrIndirectOutput(out, visit, node); + break; + } + case EOpIndexDirectStruct: + { + if (!IsInShaderStorageBlock(node->getLeft())) + { + return mOutputHLSL->visitBinary(visit, node); + } + + if (visit == InVisit) + { + ASSERT(IsInShaderStorageBlock(node->getLeft())); + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + out << " + "; + writeDotOperatorOutput(out, field); + return false; + } + break; + } + case EOpIndexDirectInterfaceBlock: + if (!IsInShaderStorageBlock(node->getLeft())) + { + return mOutputHLSL->visitBinary(visit, node); + } + + if (visit == InVisit) + { + ASSERT(IsInShaderStorageBlock(node->getLeft())); + out << ", "; + const TInterfaceBlock *interfaceBlock = + node->getLeft()->getType().getInterfaceBlock(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = interfaceBlock->fields()[index->getIConst(0)]; + writeDotOperatorOutput(out, field); + return false; + } + break; + default: + // It may have other operators in EOpIndexIndirect. Such as buffer.attribs[(y * gridSize + // + x) * 6u + 0u] + return mOutputHLSL->visitBinary(visit, node); + } + + return true; +} + +void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out, + Visit visit, + TIntermBinary *node) +{ + ASSERT(IsInShaderStorageBlock(node->getLeft())); + if (visit == InVisit) + { + const TType &type = node->getLeft()->getType(); + // For array of arrays, we calculate the offset using the formula below: + // elementStride * (a3 * a2 * a1 * i0 + a3 * a2 * i1 + a3 * i2 + i3) + // Note: assume that there are 4 dimensions. + // a0, a1, a2, a3 is the size of the array in each dimension. (S s[a0][a1][a2][a3]) + // i0, i1, i2, i3 is the index of the array in each dimension. (s[i0][i1][i2][i3]) + if (IsInArrayOfArraysChain(node->getLeft())) + { + if (type.isArrayOfArrays()) + { + const TVector<unsigned int> &arraySizes = *type.getArraySizes(); + // Don't need to concern the tail comma which will be used to multiply the index. + for (unsigned int i = 0; i < (arraySizes.size() - 1); i++) + { + out << arraySizes[i]; + out << " * "; + } + } + } + else + { + if (node->getType().isVector() && type.isMatrix()) + { + if (mRowMajor) + { + out << " + " << str(BlockLayoutEncoder::kBytesPerComponent); + } + else + { + out << " + " << str(mMatrixStride); + } + } + else if (node->getType().isScalar() && !type.isArray()) + { + if (mRowMajor) + { + out << " + " << str(mMatrixStride); + } + else + { + out << " + " << str(BlockLayoutEncoder::kBytesPerComponent); + } + } + + out << " * "; + } + } + else if (visit == PostVisit) + { + // This is used to output the '+' in the array of arrays formula in above. + if (node->getType().isArray() && !isEndOfSSBOAccessChain()) + { + out << " + "; + } + // This corresponds to '(' in writeDotOperatorOutput when fieldType.isArrayOfArrays() is + // true. + if (IsInArrayOfArraysChain(node->getLeft()) && !node->getType().isArray()) + { + out << ")"; + } + if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain()) + { + out << ")"; + } + } +} + +void ShaderStorageBlockOutputHLSL::writeDotOperatorOutput(TInfoSinkBase &out, const TField *field) +{ + auto fieldInfoIter = mBlockMemberInfoMap.find(field); + ASSERT(fieldInfoIter != mBlockMemberInfoMap.end()); + const BlockMemberInfo &memberInfo = fieldInfoIter->second; + mMatrixStride = memberInfo.matrixStride; + mRowMajor = memberInfo.isRowMajorMatrix; + out << memberInfo.offset; + + const TType &fieldType = *field->type(); + if (fieldType.isArray() && !isEndOfSSBOAccessChain()) + { + out << " + "; + out << memberInfo.arrayStride; + if (fieldType.isArrayOfArrays()) + { + out << " * ("; + } + } + if (mLocationAsTheLastArgument && isEndOfSSBOAccessChain()) + { + out << ")"; + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.h b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.h new file mode 100644 index 0000000000..2ef2364129 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ShaderStorageBlockOutputHLSL.h @@ -0,0 +1,92 @@ +// +// 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. +// +// ShaderStorageBlockOutputHLSL: A traverser to translate a buffer variable of shader storage block +// to an offset of RWByteAddressBuffer. +// + +#ifndef COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_ +#define COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_ + +#include "compiler/translator/ShaderStorageBlockFunctionHLSL.h" +#include "compiler/translator/blocklayout.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ +class ResourcesHLSL; +class OutputHLSL; +class TSymbolTable; + +struct TReferencedBlock : angle::NonCopyable +{ + POOL_ALLOCATOR_NEW_DELETE + TReferencedBlock(const TInterfaceBlock *block, const TVariable *instanceVariable); + const TInterfaceBlock *block; + const TVariable *instanceVariable; // May be nullptr if the block is not instanced. +}; + +// Maps from uniqueId to a variable. +using ReferencedInterfaceBlocks = std::map<int, const TReferencedBlock *>; + +// Used to save shader storage block field member information. +using BlockMemberInfoMap = std::map<const TField *, BlockMemberInfo>; + +using ShaderVarToFieldMap = std::map<std::string, const TField *>; + +class ShaderStorageBlockOutputHLSL : public TIntermTraverser +{ + public: + ShaderStorageBlockOutputHLSL(OutputHLSL *outputHLSL, + TSymbolTable *symbolTable, + ResourcesHLSL *resourcesHLSL, + const std::vector<InterfaceBlock> &shaderStorageBlocks); + + ~ShaderStorageBlockOutputHLSL(); + + // This writes part of the function call to store a value to a SSBO to the output stream. After + // calling this, ", <stored value>)" should be written to the output stream to complete the + // function call. + void outputStoreFunctionCallPrefix(TIntermTyped *node); + // This writes the function call to load a SSBO value to the output stream. + void outputLoadFunctionCall(TIntermTyped *node); + // This writes the function call to get the lengh of unsized array member of SSBO. + void outputLengthFunctionCall(TIntermTyped *node); + // Writes the atomic memory function calls for SSBO. + void outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node, TOperator op); + + void writeShaderStorageBlocksHeader(TInfoSinkBase &out) const; + + protected: + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; + bool visitBinary(Visit visit, TIntermBinary *) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitTernary(Visit visit, TIntermTernary *) override; + bool visitUnary(Visit visit, TIntermUnary *) override; + + private: + void traverseSSBOAccess(TIntermTyped *node, SSBOMethod method); + void setMatrixStride(TIntermTyped *node, TLayoutBlockStorage storage, bool rowMajor); + bool isEndOfSSBOAccessChain(); + void writeEOpIndexDirectOrIndirectOutput(TInfoSinkBase &out, Visit visit, TIntermBinary *node); + // Common part in dot operations. + void writeDotOperatorOutput(TInfoSinkBase &out, const TField *field); + + int mMatrixStride; + bool mRowMajor; + bool mLocationAsTheLastArgument; + OutputHLSL *mOutputHLSL; + ShaderStorageBlockFunctionHLSL *mSSBOFunctionHLSL; + ResourcesHLSL *mResourcesHLSL; + ReferencedInterfaceBlocks mReferencedShaderStorageBlocks; + + BlockMemberInfoMap mBlockMemberInfoMap; + const std::vector<InterfaceBlock> &mShaderStorageBlocks; +}; +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SHADERSTORAGEBLOCKOUTPUTHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp new file mode 100644 index 0000000000..202ed21119 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp @@ -0,0 +1,582 @@ +// +// Copyright (c) 2014 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. +// +// ShaderVars.cpp: +// Methods for GL variable types (varyings, uniforms, etc) +// + +#include <GLSLANG/ShaderLang.h> + +#include "common/debug.h" +#include "common/utilities.h" + +namespace sh +{ + +namespace +{ + +InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation) +{ + return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation); +} +} // namespace +// The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion +// on Khronos.org, clarifies that a smooth/flat mismatch produces a link error, +// but auxiliary qualifier mismatch (centroid) does not. +bool InterpolationTypesMatch(InterpolationType a, InterpolationType b) +{ + return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b)); +} + +ShaderVariable::ShaderVariable() : ShaderVariable(GL_NONE) {} + +ShaderVariable::ShaderVariable(GLenum typeIn) + : type(typeIn), + precision(0), + staticUse(false), + active(false), + isRowMajorLayout(false), + flattenedOffsetInParentArrays(-1) +{} + +ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn) +{ + ASSERT(arraySizeIn != 0); + arraySizes.push_back(arraySizeIn); +} + +ShaderVariable::~ShaderVariable() {} + +ShaderVariable::ShaderVariable(const ShaderVariable &other) + : type(other.type), + precision(other.precision), + name(other.name), + mappedName(other.mappedName), + arraySizes(other.arraySizes), + staticUse(other.staticUse), + active(other.active), + fields(other.fields), + structName(other.structName), + isRowMajorLayout(other.isRowMajorLayout), + flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays) +{} + +ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other) +{ + type = other.type; + precision = other.precision; + name = other.name; + mappedName = other.mappedName; + arraySizes = other.arraySizes; + staticUse = other.staticUse; + active = other.active; + fields = other.fields; + structName = other.structName; + isRowMajorLayout = other.isRowMajorLayout; + flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays; + return *this; +} + +bool ShaderVariable::operator==(const ShaderVariable &other) const +{ + if (type != other.type || precision != other.precision || name != other.name || + mappedName != other.mappedName || arraySizes != other.arraySizes || + staticUse != other.staticUse || active != other.active || + fields.size() != other.fields.size() || structName != other.structName || + isRowMajorLayout != other.isRowMajorLayout) + { + return false; + } + for (size_t ii = 0; ii < fields.size(); ++ii) + { + if (fields[ii] != other.fields[ii]) + return false; + } + return true; +} + +void ShaderVariable::setArraySize(unsigned int size) +{ + arraySizes.clear(); + if (size != 0) + { + arraySizes.push_back(size); + } +} + +unsigned int ShaderVariable::getInnerArraySizeProduct() const +{ + unsigned int arraySizeProduct = 1u; + for (size_t index = 1; index < arraySizes.size(); ++index) + { + arraySizeProduct *= getNestedArraySize(index); + } + return arraySizeProduct; +} + +unsigned int ShaderVariable::getArraySizeProduct() const +{ + return gl::ArraySizeProduct(arraySizes); +} + +void ShaderVariable::indexIntoArray(unsigned int arrayIndex) +{ + ASSERT(isArray()); + flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex(); + arraySizes.pop_back(); +} + +unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const +{ + ASSERT(arraySizes.size() > arrayNestingIndex); + return arraySizes[arraySizes.size() - 1u - arrayNestingIndex]; +} + +unsigned int ShaderVariable::getBasicTypeElementCount() const +{ + // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated + // for each array element when dealing with an array of arrays or an array of structs. + ASSERT(!isArrayOfArrays()); + ASSERT(!isStruct() || !isArray()); + + // GLES 3.1 Nov 2016 page 82. + if (isArray()) + { + return getOutermostArraySize(); + } + return 1u; +} + +bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName, + const ShaderVariable **leafVar, + std::string *originalFullName) const +{ + ASSERT(leafVar && originalFullName); + // There are three cases: + // 1) the top variable is of struct type; + // 2) the top variable is an array; + // 3) otherwise. + size_t pos = mappedFullName.find_first_of(".["); + + if (pos == std::string::npos) + { + // Case 3. + if (mappedFullName != this->mappedName) + return false; + *originalFullName = this->name; + *leafVar = this; + return true; + } + else + { + std::string topName = mappedFullName.substr(0, pos); + if (topName != this->mappedName) + return false; + std::string originalName = this->name; + std::string remaining; + if (mappedFullName[pos] == '[') + { + // Case 2. + size_t closePos = mappedFullName.find_first_of(']'); + if (closePos < pos || closePos == std::string::npos) + return false; + // Append '[index]'. + originalName += mappedFullName.substr(pos, closePos - pos + 1); + if (closePos + 1 == mappedFullName.size()) + { + *originalFullName = originalName; + *leafVar = this; + return true; + } + else + { + // In the form of 'a[0].b', so after ']', '.' is expected. + if (mappedFullName[closePos + 1] != '.') + return false; + remaining = mappedFullName.substr(closePos + 2); // Skip "]." + } + } + else + { + // Case 1. + remaining = mappedFullName.substr(pos + 1); // Skip "." + } + for (size_t ii = 0; ii < this->fields.size(); ++ii) + { + const ShaderVariable *fieldVar = nullptr; + std::string originalFieldName; + bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName); + if (found) + { + *originalFullName = originalName + "." + originalFieldName; + *leafVar = fieldVar; + return true; + } + } + return false; + } +} + +bool ShaderVariable::isBuiltIn() const +{ + return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_'); +} + +bool ShaderVariable::isEmulatedBuiltIn() const +{ + return isBuiltIn() && name != mappedName; +} + +bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other, + bool matchPrecision, + bool matchName) const +{ + if (type != other.type) + return false; + if (matchPrecision && precision != other.precision) + return false; + if (matchName && name != other.name) + return false; + ASSERT(!matchName || mappedName == other.mappedName); + if (arraySizes != other.arraySizes) + return false; + if (isRowMajorLayout != other.isRowMajorLayout) + return false; + if (fields.size() != other.fields.size()) + return false; + + // [OpenGL ES 3.1 SPEC Chapter 7.4.1] + // Variables declared as structures are considered to match in type if and only if structure + // members match in name, type, qualification, and declaration order. + for (size_t ii = 0; ii < fields.size(); ++ii) + { + if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true)) + { + return false; + } + } + if (structName != other.structName) + return false; + return true; +} + +Uniform::Uniform() + : binding(-1), imageUnitFormat(GL_NONE), offset(-1), readonly(false), writeonly(false) +{} + +Uniform::~Uniform() {} + +Uniform::Uniform(const Uniform &other) + : VariableWithLocation(other), + binding(other.binding), + imageUnitFormat(other.imageUnitFormat), + offset(other.offset), + readonly(other.readonly), + writeonly(other.writeonly) +{} + +Uniform &Uniform::operator=(const Uniform &other) +{ + VariableWithLocation::operator=(other); + binding = other.binding; + imageUnitFormat = other.imageUnitFormat; + offset = other.offset; + readonly = other.readonly; + writeonly = other.writeonly; + return *this; +} + +bool Uniform::operator==(const Uniform &other) const +{ + return VariableWithLocation::operator==(other) && binding == other.binding && + imageUnitFormat == other.imageUnitFormat && offset == other.offset && + readonly == other.readonly && writeonly == other.writeonly; +} + +bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const +{ + // Enforce a consistent match. + // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261 + if (binding != -1 && other.binding != -1 && binding != other.binding) + { + return false; + } + if (imageUnitFormat != other.imageUnitFormat) + { + return false; + } + if (location != -1 && other.location != -1 && location != other.location) + { + return false; + } + if (offset != other.offset) + { + return false; + } + if (readonly != other.readonly || writeonly != other.writeonly) + { + return false; + } + return VariableWithLocation::isSameVariableAtLinkTime(other, true, true); +} + +VariableWithLocation::VariableWithLocation() : location(-1) {} + +VariableWithLocation::~VariableWithLocation() {} + +VariableWithLocation::VariableWithLocation(const VariableWithLocation &other) + : ShaderVariable(other), location(other.location) +{} + +VariableWithLocation &VariableWithLocation::operator=(const VariableWithLocation &other) +{ + ShaderVariable::operator=(other); + location = other.location; + return *this; +} + +bool VariableWithLocation::operator==(const VariableWithLocation &other) const +{ + return (ShaderVariable::operator==(other) && location == other.location); +} + +Attribute::Attribute() {} + +Attribute::~Attribute() {} + +Attribute::Attribute(const Attribute &other) : VariableWithLocation(other) {} + +Attribute &Attribute::operator=(const Attribute &other) +{ + VariableWithLocation::operator=(other); + return *this; +} + +bool Attribute::operator==(const Attribute &other) const +{ + return VariableWithLocation::operator==(other); +} + +OutputVariable::OutputVariable() : index(-1) {} + +OutputVariable::~OutputVariable() {} + +OutputVariable::OutputVariable(const OutputVariable &other) = default; +OutputVariable &OutputVariable::operator=(const OutputVariable &other) = default; + +bool OutputVariable::operator==(const OutputVariable &other) const +{ + return VariableWithLocation::operator==(other) && index == other.index; +} + +InterfaceBlockField::InterfaceBlockField() {} + +InterfaceBlockField::~InterfaceBlockField() {} + +InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) : ShaderVariable(other) +{} + +InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other) +{ + ShaderVariable::operator=(other); + return *this; +} + +bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const +{ + return ShaderVariable::operator==(other); +} + +bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime( + const InterfaceBlockField &other) const +{ + return (ShaderVariable::isSameVariableAtLinkTime(other, true, true)); +} + +Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) {} + +Varying::~Varying() {} + +Varying::Varying(const Varying &other) + : VariableWithLocation(other), + interpolation(other.interpolation), + isInvariant(other.isInvariant) +{} + +Varying &Varying::operator=(const Varying &other) +{ + VariableWithLocation::operator=(other); + interpolation = other.interpolation; + isInvariant = other.isInvariant; + return *this; +} + +bool Varying::operator==(const Varying &other) const +{ + return (VariableWithLocation::operator==(other) && interpolation == other.interpolation && + isInvariant == other.isInvariant); +} + +bool Varying::isSameVaryingAtLinkTime(const Varying &other) const +{ + return isSameVaryingAtLinkTime(other, 100); +} + +bool Varying::isSameVaryingAtLinkTime(const Varying &other, int shaderVersion) const +{ + return (ShaderVariable::isSameVariableAtLinkTime(other, false, false) && + InterpolationTypesMatch(interpolation, other.interpolation) && + (shaderVersion >= 300 || isInvariant == other.isInvariant) && + (location == other.location) && + (name == other.name || (shaderVersion >= 310 && location >= 0))); +} + +InterfaceBlock::InterfaceBlock() + : arraySize(0), + layout(BLOCKLAYOUT_PACKED), + isRowMajorLayout(false), + binding(-1), + staticUse(false), + active(false), + blockType(BlockType::BLOCK_UNIFORM) +{} + +InterfaceBlock::~InterfaceBlock() {} + +InterfaceBlock::InterfaceBlock(const InterfaceBlock &other) + : name(other.name), + mappedName(other.mappedName), + instanceName(other.instanceName), + arraySize(other.arraySize), + layout(other.layout), + isRowMajorLayout(other.isRowMajorLayout), + binding(other.binding), + staticUse(other.staticUse), + active(other.active), + blockType(other.blockType), + fields(other.fields) +{} + +InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other) +{ + name = other.name; + mappedName = other.mappedName; + instanceName = other.instanceName; + arraySize = other.arraySize; + layout = other.layout; + isRowMajorLayout = other.isRowMajorLayout; + binding = other.binding; + staticUse = other.staticUse; + active = other.active; + blockType = other.blockType; + fields = other.fields; + return *this; +} + +std::string InterfaceBlock::fieldPrefix() const +{ + return instanceName.empty() ? "" : name; +} + +std::string InterfaceBlock::fieldMappedPrefix() const +{ + return instanceName.empty() ? "" : mappedName; +} + +bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const +{ + if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize || + layout != other.layout || isRowMajorLayout != other.isRowMajorLayout || + binding != other.binding || blockType != other.blockType || + fields.size() != other.fields.size()) + { + return false; + } + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex) + { + if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex])) + { + return false; + } + } + + return true; +} + +bool InterfaceBlock::isBuiltIn() const +{ + return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_'); +} + +void WorkGroupSize::fill(int fillValue) +{ + localSizeQualifiers[0] = fillValue; + localSizeQualifiers[1] = fillValue; + localSizeQualifiers[2] = fillValue; +} + +void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ) +{ + localSizeQualifiers[0] = localSizeX; + localSizeQualifiers[1] = localSizeY; + localSizeQualifiers[2] = localSizeZ; +} + +// check that if one of them is less than 1, then all of them are. +// Or if one is positive, then all of them are positive. +bool WorkGroupSize::isLocalSizeValid() const +{ + return ( + (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) || + (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0)); +} + +bool WorkGroupSize::isAnyValueSet() const +{ + return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0; +} + +bool WorkGroupSize::isDeclared() const +{ + bool localSizeDeclared = localSizeQualifiers[0] > 0; + ASSERT(isLocalSizeValid()); + return localSizeDeclared; +} + +bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const +{ + for (size_t i = 0u; i < size(); ++i) + { + bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] || + (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) || + (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1)); + if (!result) + { + return false; + } + } + return true; +} + +int &WorkGroupSize::operator[](size_t index) +{ + ASSERT(index < size()); + return localSizeQualifiers[index]; +} + +int WorkGroupSize::operator[](size_t index) const +{ + ASSERT(index < size()); + return localSizeQualifiers[index]; +} + +size_t WorkGroupSize::size() const +{ + return 3u; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/StaticType.h b/gfx/angle/checkout/src/compiler/translator/StaticType.h new file mode 100644 index 0000000000..6ecb24fbc9 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/StaticType.h @@ -0,0 +1,202 @@ +// +// Copyright (c) 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. +// +// Compile-time instances of many common TType values. These are looked up +// (statically or dynamically) through the methods defined in the namespace. +// + +#ifndef COMPILER_TRANSLATOR_STATIC_TYPE_H_ +#define COMPILER_TRANSLATOR_STATIC_TYPE_H_ + +#include "compiler/translator/Types.h" + +namespace sh +{ + +namespace StaticType +{ + +namespace Helpers +{ + +// +// Generation and static allocation of type mangled name values. +// + +// Size of the constexpr-generated mangled name. +// If this value is too small, the compiler will produce errors. +static constexpr size_t kStaticMangledNameLength = 2; + +// Type which holds the mangled names for constexpr-generated TTypes. +// This simple struct is needed so that a char array can be returned by value. +struct StaticMangledName +{ + // If this array is too small, the compiler will produce errors. + char name[kStaticMangledNameLength + 1] = {}; +}; + +// Generates a mangled name for a TType given its parameters. +constexpr StaticMangledName BuildStaticMangledName(TBasicType basicType, + TPrecision precision, + TQualifier qualifier, + unsigned char primarySize, + unsigned char secondarySize) +{ + StaticMangledName name = {}; + name.name[0] = TType::GetSizeMangledName(primarySize, secondarySize); + name.name[1] = GetBasicMangledName(basicType); + name.name[2] = '\0'; + return name; +} + +// This "variable" contains the mangled names for every constexpr-generated TType. +// If kMangledNameInstance<B, P, Q, PS, SS> is used anywhere (specifally +// in instance, below), this is where the appropriate type will be stored. +template <TBasicType basicType, + TPrecision precision, + TQualifier qualifier, + unsigned char primarySize, + unsigned char secondarySize> +static constexpr StaticMangledName kMangledNameInstance = + BuildStaticMangledName(basicType, precision, qualifier, primarySize, secondarySize); + +// +// Generation and static allocation of TType values. +// + +// This "variable" contains every constexpr-generated TType. +// If instance<B, P, Q, PS, SS> is used anywhere (specifally +// in Get, below), this is where the appropriate type will be stored. +// +// TODO(crbug.com/981610): This is constexpr but doesn't follow the kConstant naming convention +// because TType has a mutable member that prevents it from being in .data.rel.ro and makes the +// Android Binary Size builder complain when ANGLE is rolled in Chromium. +template <TBasicType basicType, + TPrecision precision, + TQualifier qualifier, + unsigned char primarySize, + unsigned char secondarySize> +static constexpr TType instance = + TType(basicType, + precision, + qualifier, + primarySize, + secondarySize, + kMangledNameInstance<basicType, precision, qualifier, primarySize, secondarySize>.name); + +} // namespace Helpers + +// +// Fully-qualified type lookup. +// + +template <TBasicType basicType, + TPrecision precision, + TQualifier qualifier, + unsigned char primarySize, + unsigned char secondarySize> +constexpr const TType *Get() +{ + static_assert(1 <= primarySize && primarySize <= 4, "primarySize out of bounds"); + static_assert(1 <= secondarySize && secondarySize <= 4, "secondarySize out of bounds"); + return &Helpers::instance<basicType, precision, qualifier, primarySize, secondarySize>; +} + +// +// Overloads +// + +template <TBasicType basicType, unsigned char primarySize = 1, unsigned char secondarySize = 1> +constexpr const TType *GetBasic() +{ + return Get<basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize>(); +} + +template <TBasicType basicType, + TQualifier qualifier, + unsigned char primarySize = 1, + unsigned char secondarySize = 1> +const TType *GetQualified() +{ + return Get<basicType, EbpUndefined, qualifier, primarySize, secondarySize>(); +} + +// Dynamic lookup methods (convert runtime values to template args) + +namespace Helpers +{ + +// Helper which takes secondarySize statically but primarySize dynamically. +template <TBasicType basicType, + TPrecision precision, + TQualifier qualifier, + unsigned char secondarySize> +constexpr const TType *GetForVecMatHelper(unsigned char primarySize) +{ + static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt || + basicType == EbtBool, + "unsupported basicType"); + switch (primarySize) + { + case 1: + return Get<basicType, precision, qualifier, 1, secondarySize>(); + case 2: + return Get<basicType, precision, qualifier, 2, secondarySize>(); + case 3: + return Get<basicType, precision, qualifier, 3, secondarySize>(); + case 4: + return Get<basicType, precision, qualifier, 4, secondarySize>(); + default: + UNREACHABLE(); + return GetBasic<EbtVoid>(); + } +} + +} // namespace Helpers + +template <TBasicType basicType, + TPrecision precision = EbpUndefined, + TQualifier qualifier = EvqGlobal> +constexpr const TType *GetForVecMat(unsigned char primarySize, unsigned char secondarySize = 1) +{ + static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt || + basicType == EbtBool, + "unsupported basicType"); + switch (secondarySize) + { + case 1: + return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 1>(primarySize); + case 2: + return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 2>(primarySize); + case 3: + return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 3>(primarySize); + case 4: + return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 4>(primarySize); + default: + UNREACHABLE(); + return GetBasic<EbtVoid>(); + } +} + +template <TBasicType basicType, TPrecision precision = EbpUndefined> +constexpr const TType *GetForVec(TQualifier qualifier, unsigned char size) +{ + switch (qualifier) + { + case EvqGlobal: + return Helpers::GetForVecMatHelper<basicType, precision, EvqGlobal, 1>(size); + case EvqOut: + return Helpers::GetForVecMatHelper<basicType, precision, EvqOut, 1>(size); + default: + UNREACHABLE(); + return GetBasic<EbtVoid>(); + } +} + +} // namespace StaticType + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_STATIC_TYPE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/StructureHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.cpp new file mode 100644 index 0000000000..172ca07fc0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.cpp @@ -0,0 +1,591 @@ +// +// Copyright (c) 2014 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. +// +// StructureHLSL.cpp: +// HLSL translation of GLSL constructors and structures. +// + +#include "compiler/translator/StructureHLSL.h" +#include "common/utilities.h" +#include "compiler/translator/OutputHLSL.h" +#include "compiler/translator/Types.h" +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +TString Define(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing, + Std140PaddingHelper *padHelper) +{ + const TFieldList &fields = structure.fields(); + const bool isNameless = (structure.symbolType() == SymbolType::Empty); + const TString &structName = + QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing); + const TString declareString = (isNameless ? "struct" : "struct " + structName); + + TString string; + string += declareString + + "\n" + "{\n"; + + for (const TField *field : fields) + { + const TType &fieldType = *field->type(); + if (!IsSampler(fieldType.getBasicType())) + { + const TStructure *fieldStruct = fieldType.getStruct(); + const TString &fieldTypeString = + fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking, + useStd140Packing) + : TypeString(fieldType); + + if (padHelper) + { + string += padHelper->prePaddingString(fieldType); + } + + string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) + + ArrayString(fieldType).data() + ";\n"; + + if (padHelper) + { + string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking); + } + } + } + + // Nameless structs do not finish with a semicolon and newline, to leave room for an instance + // variable + string += (isNameless ? "} " : "};\n"); + + return string; +} + +TString WriteParameterList(const std::vector<TType> ¶meters) +{ + TString parameterList; + for (size_t parameter = 0u; parameter < parameters.size(); parameter++) + { + const TType ¶mType = parameters[parameter]; + + parameterList += + TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType).data(); + + if (parameter < parameters.size() - 1u) + { + parameterList += ", "; + } + } + return parameterList; +} + +} // anonymous namespace + +Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes, + unsigned *uniqueCounter) + : mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes) +{} + +Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other) + : mPaddingCounter(other.mPaddingCounter), + mElementIndex(other.mElementIndex), + mStructElementIndexes(other.mStructElementIndexes) +{} + +Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other) +{ + mPaddingCounter = other.mPaddingCounter; + mElementIndex = other.mElementIndex; + mStructElementIndexes = other.mStructElementIndexes; + return *this; +} + +TString Std140PaddingHelper::next() +{ + unsigned value = (*mPaddingCounter)++; + return str(value); +} + +int Std140PaddingHelper::prePadding(const TType &type) +{ + if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray()) + { + // no padding needed, HLSL will align the field to a new register + mElementIndex = 0; + return 0; + } + + const GLenum glType = GLVariableType(type); + const int numComponents = gl::VariableComponentCount(glType); + + if (numComponents >= 4) + { + // no padding needed, HLSL will align the field to a new register + mElementIndex = 0; + return 0; + } + + if (mElementIndex + numComponents > 4) + { + // 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 paddingOffset = (mElementIndex % alignment); + const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0); + + mElementIndex += paddingCount; + mElementIndex += numComponents; + mElementIndex %= 4; + + return paddingCount; +} + +TString Std140PaddingHelper::prePaddingString(const TType &type) +{ + int paddingCount = prePadding(type); + + TString padding; + + for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++) + { + padding += " float pad_" + next() + ";\n"; + } + + return padding; +} + +TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking) +{ + if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct) + { + return ""; + } + + int numComponents = 0; + const TStructure *structure = type.getStruct(); + + if (type.isMatrix()) + { + // This method can also be called from structureString, which does not use layout + // qualifiers. + // Thus, use the method parameter for determining the matrix packing. + // + // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we + // wish to always transpose GL matrices to play well with HLSL's matrix array indexing. + // + const bool isRowMajorMatrix = !useHLSLRowMajorPacking; + const GLenum glType = GLVariableType(type); + numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix); + } + else if (structure) + { + const TString &structName = + QualifiedStructNameString(*structure, useHLSLRowMajorPacking, true); + numComponents = mStructElementIndexes->find(structName)->second; + + if (numComponents == 0) + { + return ""; + } + } + else + { + const GLenum glType = GLVariableType(type); + numComponents = gl::VariableComponentCount(glType); + } + + TString padding; + for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++) + { + padding += " float pad_" + next() + ";\n"; + } + return padding; +} + +StructureHLSL::StructureHLSL() : mUniquePaddingCounter(0) {} + +Std140PaddingHelper StructureHLSL::getPaddingHelper() +{ + return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter); +} + +TString StructureHLSL::defineQualified(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing) +{ + if (useStd140Packing) + { + Std140PaddingHelper padHelper = getPaddingHelper(); + return Define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper); + } + else + { + return Define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr); + } +} + +TString StructureHLSL::defineNameless(const TStructure &structure) +{ + return Define(structure, false, false, nullptr); +} + +StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStructure &structure, + const TString &name) +{ + ASSERT(mDefinedStructs.find(name) == mDefinedStructs.end()); + + for (const TField *field : structure.fields()) + { + const TType *fieldType = field->type(); + if (fieldType->getBasicType() == EbtStruct) + { + ensureStructDefined(*fieldType->getStruct()); + } + } + + DefinedStructs::iterator addedStruct = + mDefinedStructs.insert(std::make_pair(name, new TStructProperties())).first; + // Add element index + storeStd140ElementIndex(structure, false); + storeStd140ElementIndex(structure, true); + + const TString &structString = defineQualified(structure, false, false); + + ASSERT(std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == + mStructDeclarations.end()); + // Add row-major packed struct for interface blocks + TString rowMajorString = "#pragma pack_matrix(row_major)\n" + + defineQualified(structure, true, false) + + "#pragma pack_matrix(column_major)\n"; + + TString std140String = defineQualified(structure, false, true); + TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" + + defineQualified(structure, true, true) + + "#pragma pack_matrix(column_major)\n"; + + mStructDeclarations.push_back(structString); + mStructDeclarations.push_back(rowMajorString); + mStructDeclarations.push_back(std140String); + mStructDeclarations.push_back(std140RowMajorString); + return addedStruct; +} + +void StructureHLSL::ensureStructDefined(const TStructure &structure) +{ + const TString name = StructNameString(structure); + if (name == "") + { + return; // Nameless structures are not defined + } + if (mDefinedStructs.find(name) == mDefinedStructs.end()) + { + defineVariants(structure, name); + } +} + +TString StructureHLSL::addStructConstructor(const TStructure &structure) +{ + const TString name = StructNameString(structure); + + if (name == "") + { + return TString(); // Nameless structures don't have constructors + } + + auto definedStruct = mDefinedStructs.find(name); + if (definedStruct == mDefinedStructs.end()) + { + definedStruct = defineVariants(structure, name); + } + const TString constructorFunctionName = TString(name) + "_ctor"; + TString *constructor = &definedStruct->second->constructor; + if (!constructor->empty()) + { + return constructorFunctionName; // Already added + } + *constructor += name + " " + constructorFunctionName + "("; + + std::vector<TType> ctorParameters; + const TFieldList &fields = structure.fields(); + for (const TField *field : fields) + { + const TType *fieldType = field->type(); + if (!IsSampler(fieldType->getBasicType())) + { + ctorParameters.push_back(*fieldType); + } + } + // Structs that have sampler members should not have constructor calls, and otherwise structs + // are guaranteed to be non-empty by the grammar. Structs can't contain empty declarations + // either. + ASSERT(!ctorParameters.empty()); + + *constructor += WriteParameterList(ctorParameters); + + *constructor += + ")\n" + "{\n" + " " + + name + " structure = { "; + + for (size_t parameterIndex = 0u; parameterIndex < ctorParameters.size(); ++parameterIndex) + { + *constructor += "x" + str(parameterIndex); + if (parameterIndex < ctorParameters.size() - 1u) + { + *constructor += ", "; + } + } + *constructor += + "};\n" + " return structure;\n" + "}\n"; + + return constructorFunctionName; +} + +TString StructureHLSL::addBuiltInConstructor(const TType &type, const TIntermSequence *parameters) +{ + ASSERT(!type.isArray()); + ASSERT(type.getStruct() == nullptr); + ASSERT(parameters); + + TType ctorType = type; + ctorType.setPrecision(EbpHigh); + ctorType.setQualifier(EvqTemporary); + + const TString constructorFunctionName = + TString(type.getBuiltInTypeNameString()) + "_ctor" + DisambiguateFunctionName(parameters); + TString constructor = TypeString(ctorType) + " " + constructorFunctionName + "("; + + std::vector<TType> ctorParameters; + for (auto parameter : *parameters) + { + const TType ¶mType = parameter->getAsTyped()->getType(); + ASSERT(!paramType.isArray()); + ctorParameters.push_back(paramType); + } + constructor += WriteParameterList(ctorParameters); + + constructor += + ")\n" + "{\n" + " return " + + TypeString(ctorType) + "("; + + if (ctorType.isMatrix() && ctorParameters.size() == 1) + { + int rows = ctorType.getRows(); + int cols = ctorType.getCols(); + const TType ¶meter = ctorParameters[0]; + + if (parameter.isScalar()) + { + for (int col = 0; col < cols; col++) + { + for (int row = 0; row < rows; row++) + { + constructor += TString((row == col) ? "x0" : "0.0"); + + if (row < rows - 1 || col < cols - 1) + { + constructor += ", "; + } + } + } + } + else if (parameter.isMatrix()) + { + for (int col = 0; col < cols; col++) + { + for (int row = 0; row < rows; row++) + { + if (row < parameter.getRows() && col < parameter.getCols()) + { + constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]"; + } + else + { + constructor += TString((row == col) ? "1.0" : "0.0"); + } + + if (row < rows - 1 || col < cols - 1) + { + constructor += ", "; + } + } + } + } + else + { + ASSERT(rows == 2 && cols == 2 && parameter.isVector() && + parameter.getNominalSize() == 4); + + constructor += "x0"; + } + } + else + { + size_t remainingComponents = ctorType.getObjectSize(); + size_t parameterIndex = 0; + + while (remainingComponents > 0) + { + const TType ¶meter = ctorParameters[parameterIndex]; + const size_t parameterSize = parameter.getObjectSize(); + bool moreParameters = parameterIndex + 1 < ctorParameters.size(); + + constructor += "x" + str(parameterIndex); + + if (parameter.isScalar()) + { + remainingComponents -= parameter.getObjectSize(); + } + else if (parameter.isVector()) + { + if (remainingComponents == parameterSize || moreParameters) + { + ASSERT(parameterSize <= remainingComponents); + remainingComponents -= parameterSize; + } + else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize())) + { + switch (remainingComponents) + { + case 1: + constructor += ".x"; + break; + case 2: + constructor += ".xy"; + break; + case 3: + constructor += ".xyz"; + break; + case 4: + constructor += ".xyzw"; + break; + default: + UNREACHABLE(); + } + + remainingComponents = 0; + } + else + UNREACHABLE(); + } + else if (parameter.isMatrix()) + { + int column = 0; + while (remainingComponents > 0 && column < parameter.getCols()) + { + constructor += "[" + str(column) + "]"; + + if (remainingComponents < static_cast<size_t>(parameter.getRows())) + { + switch (remainingComponents) + { + case 1: + constructor += ".x"; + break; + case 2: + constructor += ".xy"; + break; + case 3: + constructor += ".xyz"; + break; + default: + UNREACHABLE(); + } + + remainingComponents = 0; + } + else + { + remainingComponents -= parameter.getRows(); + + if (remainingComponents > 0) + { + constructor += ", x" + str(parameterIndex); + } + } + + column++; + } + } + else + { + UNREACHABLE(); + } + + if (moreParameters) + { + parameterIndex++; + } + + if (remainingComponents) + { + constructor += ", "; + } + } + } + + constructor += + ");\n" + "}\n"; + + mBuiltInConstructors.insert(constructor); + + return constructorFunctionName; +} + +std::string StructureHLSL::structsHeader() const +{ + TInfoSinkBase out; + + for (auto &declaration : mStructDeclarations) + { + out << declaration; + } + + for (auto &structure : mDefinedStructs) + { + out << structure.second->constructor; + } + + for (auto &constructor : mBuiltInConstructors) + { + out << constructor; + } + + return out.str(); +} + +void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, + bool useHLSLRowMajorPacking) +{ + Std140PaddingHelper padHelper = getPaddingHelper(); + const TFieldList &fields = structure.fields(); + + for (const TField *field : fields) + { + padHelper.prePadding(*field->type()); + } + + // Add remaining element index to the global map, for use with nested structs in standard + // layouts + const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true); + mStd140StructElementIndexes[structName] = padHelper.elementIndex(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/StructureHLSL.h b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.h new file mode 100644 index 0000000000..ba4a8d11bc --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/StructureHLSL.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2014 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. +// +// StructureHLSL.h: +// HLSL translation of GLSL constructors and structures. +// + +#ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ +#define COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ + +#include "compiler/translator/Common.h" +#include "compiler/translator/IntermNode.h" + +#include <set> + +class TInfoSinkBase; +class TScopeBracket; + +namespace sh +{ + +// This helper class assists structure and interface block definitions in determining +// how to pack std140 structs within HLSL's packing rules. +class Std140PaddingHelper +{ + public: + explicit Std140PaddingHelper(const std::map<TString, int> &structElementIndexes, + unsigned int *uniqueCounter); + Std140PaddingHelper(const Std140PaddingHelper &other); + Std140PaddingHelper &operator=(const Std140PaddingHelper &other); + + int elementIndex() const { return mElementIndex; } + int prePadding(const TType &type); + TString prePaddingString(const TType &type); + TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking); + + private: + TString next(); + + unsigned *mPaddingCounter; + int mElementIndex; + const std::map<TString, int> *mStructElementIndexes; +}; + +class StructureHLSL : angle::NonCopyable +{ + public: + StructureHLSL(); + + // Returns the name of the constructor function. + TString addStructConstructor(const TStructure &structure); + TString addBuiltInConstructor(const TType &type, const TIntermSequence *parameters); + + static TString defineNameless(const TStructure &structure); + void ensureStructDefined(const TStructure &structure); + + std::string structsHeader() const; + + Std140PaddingHelper getPaddingHelper(); + + private: + unsigned mUniquePaddingCounter; + + std::map<TString, int> mStd140StructElementIndexes; + + struct TStructProperties : public angle::NonCopyable + { + POOL_ALLOCATOR_NEW_DELETE + + TStructProperties() {} + + // Constructor is an empty string in case the struct doesn't have a constructor yet. + TString constructor; + }; + + // Map from struct name to struct properties. + typedef std::map<TString, TStructProperties *> DefinedStructs; + DefinedStructs mDefinedStructs; + + // Struct declarations need to be kept in a vector instead of having them inside mDefinedStructs + // since maintaining the original order is necessary for nested structs. + typedef std::vector<TString> StructDeclarations; + StructDeclarations mStructDeclarations; + + typedef std::set<TString> BuiltInConstructors; + BuiltInConstructors mBuiltInConstructors; + + void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking); + TString defineQualified(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing); + DefinedStructs::iterator defineVariants(const TStructure &structure, const TString &name); +}; +} // namespace sh + +#endif // COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Symbol.cpp b/gfx/angle/checkout/src/compiler/translator/Symbol.cpp new file mode 100644 index 0000000000..52ad4f319d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Symbol.cpp @@ -0,0 +1,238 @@ +// +// Copyright (c) 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. +// +// Symbol.cpp: Symbols representing variables, functions, structures and interface blocks. +// + +#if defined(_MSC_VER) +# pragma warning(disable : 4718) +#endif + +#include "compiler/translator/Symbol.h" + +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kMainName("main"); +constexpr const ImmutableString kImageLoadName("imageLoad"); +constexpr const ImmutableString kImageStoreName("imageStore"); +constexpr const ImmutableString kImageSizeName("imageSize"); +constexpr const ImmutableString kAtomicCounterName("atomicCounter"); + +static const char kFunctionMangledNameSeparator = '('; + +} // anonymous namespace + +TSymbol::TSymbol(TSymbolTable *symbolTable, + const ImmutableString &name, + SymbolType symbolType, + SymbolClass symbolClass, + TExtension extension) + : mName(name), + mUniqueId(symbolTable->nextUniqueId()), + mSymbolType(symbolType), + mExtension(extension), + mSymbolClass(symbolClass) +{ + ASSERT(mSymbolType == SymbolType::BuiltIn || mExtension == TExtension::UNDEFINED); + ASSERT(mName != "" || mSymbolType == SymbolType::AngleInternal || + mSymbolType == SymbolType::Empty); +} + +ImmutableString TSymbol::name() const +{ + if (!mName.empty()) + { + return mName; + } + // This can be called for nameless function parameters in HLSL. + ASSERT(mSymbolType == SymbolType::AngleInternal || + (mSymbolType == SymbolType::Empty && isVariable())); + int uniqueId = mUniqueId.get(); + ImmutableStringBuilder symbolNameOut(sizeof(uniqueId) * 2u + 1u); + symbolNameOut << 's'; + symbolNameOut.appendHex(mUniqueId.get()); + return symbolNameOut; +} + +ImmutableString TSymbol::getMangledName() const +{ + if (mSymbolClass == SymbolClass::Function) + { + // We do this instead of using proper virtual functions so that we can better support + // constexpr symbols. + return static_cast<const TFunction *>(this)->getFunctionMangledName(); + } + ASSERT(mSymbolType != SymbolType::Empty); + return name(); +} + +TVariable::TVariable(TSymbolTable *symbolTable, + const ImmutableString &name, + const TType *type, + SymbolType symbolType, + TExtension extension) + : TSymbol(symbolTable, name, symbolType, SymbolClass::Variable, extension), + mType(type), + unionArray(nullptr) +{ + ASSERT(mType); + ASSERT(name.empty() || symbolType != SymbolType::Empty); +} + +TStructure::TStructure(TSymbolTable *symbolTable, + const ImmutableString &name, + const TFieldList *fields, + SymbolType symbolType) + : TSymbol(symbolTable, name, symbolType, SymbolClass::Struct), TFieldListCollection(fields) +{} + +TStructure::TStructure(const TSymbolUniqueId &id, + const ImmutableString &name, + TExtension extension, + const TFieldList *fields) + : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::Struct), + TFieldListCollection(fields) +{} + +void TStructure::createSamplerSymbols(const char *namePrefix, + const TString &apiNamePrefix, + TVector<const TVariable *> *outputSymbols, + TMap<const TVariable *, TString> *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const +{ + ASSERT(containsSamplers()); + for (const auto *field : *mFields) + { + const TType *fieldType = field->type(); + if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers()) + { + std::stringstream fieldName = sh::InitializeStream<std::stringstream>(); + fieldName << namePrefix << "_" << field->name(); + TString fieldApiName = apiNamePrefix + "."; + fieldApiName += field->name().data(); + fieldType->createSamplerSymbols(ImmutableString(fieldName.str()), fieldApiName, + outputSymbols, outputSymbolsToAPINames, symbolTable); + } + } +} + +void TStructure::setName(const ImmutableString &name) +{ + ImmutableString *mutableName = const_cast<ImmutableString *>(&mName); + *mutableName = name; +} + +TInterfaceBlock::TInterfaceBlock(TSymbolTable *symbolTable, + const ImmutableString &name, + const TFieldList *fields, + const TLayoutQualifier &layoutQualifier, + SymbolType symbolType, + TExtension extension) + : TSymbol(symbolTable, name, symbolType, SymbolClass::InterfaceBlock, extension), + TFieldListCollection(fields), + mBlockStorage(layoutQualifier.blockStorage), + mBinding(layoutQualifier.binding) +{ + ASSERT(name != nullptr); +} + +TInterfaceBlock::TInterfaceBlock(const TSymbolUniqueId &id, + const ImmutableString &name, + TExtension extension, + const TFieldList *fields) + : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::InterfaceBlock), + TFieldListCollection(fields), + mBlockStorage(EbsUnspecified), + mBinding(0) +{} + +TFunction::TFunction(TSymbolTable *symbolTable, + const ImmutableString &name, + SymbolType symbolType, + const TType *retType, + bool knownToNotHaveSideEffects) + : TSymbol(symbolTable, name, symbolType, SymbolClass::Function, TExtension::UNDEFINED), + mParametersVector(new TParamVector()), + mParameters(nullptr), + mParamCount(0u), + returnType(retType), + mMangledName(""), + mOp(EOpNull), + defined(false), + mHasPrototypeDeclaration(false), + mKnownToNotHaveSideEffects(knownToNotHaveSideEffects) +{ + // Functions with an empty name are not allowed. + ASSERT(symbolType != SymbolType::Empty); + ASSERT(name != nullptr || symbolType == SymbolType::AngleInternal); +} + +void TFunction::addParameter(const TVariable *p) +{ + ASSERT(mParametersVector); + mParametersVector->push_back(p); + mParameters = mParametersVector->data(); + mParamCount = mParametersVector->size(); + mMangledName = kEmptyImmutableString; +} + +void TFunction::shareParameters(const TFunction ¶metersSource) +{ + mParametersVector = nullptr; + mParameters = parametersSource.mParameters; + mParamCount = parametersSource.mParamCount; + ASSERT(parametersSource.name() == name()); + mMangledName = parametersSource.mMangledName; +} + +ImmutableString TFunction::buildMangledName() const +{ + std::string newName(name().data(), name().length()); + newName += kFunctionMangledNameSeparator; + + for (size_t i = 0u; i < mParamCount; ++i) + { + newName += mParameters[i]->getType().getMangledName(); + } + return ImmutableString(newName); +} + +bool TFunction::isMain() const +{ + return symbolType() == SymbolType::UserDefined && name() == kMainName; +} + +bool TFunction::isImageFunction() const +{ + return symbolType() == SymbolType::BuiltIn && + (name() == kImageSizeName || name() == kImageLoadName || name() == kImageStoreName); +} + +bool TFunction::isAtomicCounterFunction() const +{ + return SymbolType() == SymbolType::BuiltIn && name().beginsWith(kAtomicCounterName); +} + +bool TFunction::hasSamplerInStructParams() const +{ + for (size_t paramIndex = 0; paramIndex < mParamCount; ++paramIndex) + { + const TVariable *param = getParam(paramIndex); + if (param->getType().isStructureContainingSamplers()) + { + return true; + } + } + + return false; +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/Symbol.h b/gfx/angle/checkout/src/compiler/translator/Symbol.h new file mode 100644 index 0000000000..3b74a0baa4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Symbol.h @@ -0,0 +1,277 @@ +// +// Copyright (c) 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. +// +// Symbol.h: Symbols representing variables, functions, structures and interface blocks. +// + +#ifndef COMPILER_TRANSLATOR_SYMBOL_H_ +#define COMPILER_TRANSLATOR_SYMBOL_H_ + +#include "common/angleutils.h" +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolUniqueId.h" + +namespace sh +{ + +class TSymbolTable; + +// Symbol base class. (Can build functions or variables out of these...) +class TSymbol : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TSymbol(TSymbolTable *symbolTable, + const ImmutableString &name, + SymbolType symbolType, + SymbolClass symbolClass, + TExtension extension = TExtension::UNDEFINED); + + // Note that we can't have a virtual destructor in order to support constexpr symbols. Data is + // either statically allocated or pool allocated. + ~TSymbol() = default; + + // Calling name() for empty symbols (symbolType == SymbolType::Empty) generates a similar name + // as for internal variables. + ImmutableString name() const; + // Don't call getMangledName() for empty symbols (symbolType == SymbolType::Empty). + ImmutableString getMangledName() const; + + bool isFunction() const { return mSymbolClass == SymbolClass::Function; } + bool isVariable() const { return mSymbolClass == SymbolClass::Variable; } + bool isStruct() const { return mSymbolClass == SymbolClass::Struct; } + bool isInterfaceBlock() const { return mSymbolClass == SymbolClass::InterfaceBlock; } + + const TSymbolUniqueId &uniqueId() const { return mUniqueId; } + SymbolType symbolType() const { return mSymbolType; } + TExtension extension() const { return mExtension; } + + protected: + constexpr TSymbol(const TSymbolUniqueId &id, + const ImmutableString &name, + SymbolType symbolType, + TExtension extension, + SymbolClass symbolClass) + : mName(name), + mUniqueId(id), + mSymbolType(symbolType), + mExtension(extension), + mSymbolClass(symbolClass) + {} + + const ImmutableString mName; + + private: + const TSymbolUniqueId mUniqueId; + const SymbolType mSymbolType; + const TExtension mExtension; + + // We use this instead of having virtual functions for querying the class in order to support + // constexpr symbols. + const SymbolClass mSymbolClass; +}; + +// Variable. +// May store the value of a constant variable of any type (float, int, bool or struct). +class TVariable : public TSymbol +{ + public: + TVariable(TSymbolTable *symbolTable, + const ImmutableString &name, + const TType *type, + SymbolType symbolType, + TExtension ext = TExtension::UNDEFINED); + + const TType &getType() const { return *mType; } + + const TConstantUnion *getConstPointer() const { return unionArray; } + + void shareConstPointer(const TConstantUnion *constArray) { unionArray = constArray; } + + // Note: only to be used for built-in variables with autogenerated ids! + constexpr TVariable(const TSymbolUniqueId &id, + const ImmutableString &name, + SymbolType symbolType, + TExtension extension, + const TType *type) + : TSymbol(id, name, symbolType, extension, SymbolClass::Variable), + mType(type), + unionArray(nullptr) + {} + + private: + const TType *mType; + const TConstantUnion *unionArray; +}; + +// Struct type. +class TStructure : public TSymbol, public TFieldListCollection +{ + public: + TStructure(TSymbolTable *symbolTable, + const ImmutableString &name, + const TFieldList *fields, + SymbolType symbolType); + + // The char arrays passed in must be pool allocated or static. + void createSamplerSymbols(const char *namePrefix, + const TString &apiNamePrefix, + TVector<const TVariable *> *outputSymbols, + TMap<const TVariable *, TString> *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const; + + void setAtGlobalScope(bool atGlobalScope) { mAtGlobalScope = atGlobalScope; } + bool atGlobalScope() const { return mAtGlobalScope; } + + private: + friend class TSymbolTable; + // For creating built-in structs. + TStructure(const TSymbolUniqueId &id, + const ImmutableString &name, + TExtension extension, + const TFieldList *fields); + + // TODO(zmo): Find a way to get rid of the const_cast in function + // setName(). At the moment keep this function private so only + // friend class RegenerateStructNames may call it. + friend class RegenerateStructNames; + void setName(const ImmutableString &name); + + bool mAtGlobalScope; +}; + +// Interface block. Note that this contains the block name, not the instance name. Interface block +// instances are stored as TVariable. +class TInterfaceBlock : public TSymbol, public TFieldListCollection +{ + public: + TInterfaceBlock(TSymbolTable *symbolTable, + const ImmutableString &name, + const TFieldList *fields, + const TLayoutQualifier &layoutQualifier, + SymbolType symbolType, + TExtension extension = TExtension::UNDEFINED); + + TLayoutBlockStorage blockStorage() const { return mBlockStorage; } + int blockBinding() const { return mBinding; } + + private: + friend class TSymbolTable; + // For creating built-in interface blocks. + TInterfaceBlock(const TSymbolUniqueId &id, + const ImmutableString &name, + TExtension extension, + const TFieldList *fields); + + TLayoutBlockStorage mBlockStorage; + int mBinding; + + // Note that we only record matrix packing on a per-field granularity. +}; + +// Parameter class used for parsing user-defined function parameters. +struct TParameter +{ + // Destructively converts to TVariable. + // This method resets name and type to nullptrs to make sure + // their content cannot be modified after the call. + const TVariable *createVariable(TSymbolTable *symbolTable) + { + const ImmutableString constName(name); + const TType *constType = type; + name = nullptr; + type = nullptr; + return new TVariable(symbolTable, constName, constType, + constName.empty() ? SymbolType::Empty : SymbolType::UserDefined); + } + + const char *name; // either pool allocated or static. + TType *type; +}; + +// The function sub-class of a symbol. +class TFunction : public TSymbol +{ + public: + // User-defined function + TFunction(TSymbolTable *symbolTable, + const ImmutableString &name, + SymbolType symbolType, + const TType *retType, + bool knownToNotHaveSideEffects); + + void addParameter(const TVariable *p); + void shareParameters(const TFunction ¶metersSource); + + ImmutableString getFunctionMangledName() const + { + ASSERT(symbolType() != SymbolType::BuiltIn); + if (mMangledName.empty()) + { + mMangledName = buildMangledName(); + } + return mMangledName; + } + + const TType &getReturnType() const { return *returnType; } + + TOperator getBuiltInOp() const { return mOp; } + + void setDefined() { defined = true; } + bool isDefined() { return defined; } + void setHasPrototypeDeclaration() { mHasPrototypeDeclaration = true; } + bool hasPrototypeDeclaration() const { return mHasPrototypeDeclaration; } + + size_t getParamCount() const { return mParamCount; } + const TVariable *getParam(size_t i) const { return mParameters[i]; } + + bool isKnownToNotHaveSideEffects() const { return mKnownToNotHaveSideEffects; } + + bool isMain() const; + bool isImageFunction() const; + bool isAtomicCounterFunction() const; + bool hasSamplerInStructParams() const; + + // Note: Only to be used for static built-in functions! + constexpr TFunction(const TSymbolUniqueId &id, + const ImmutableString &name, + TExtension extension, + const TVariable *const *parameters, + size_t paramCount, + const TType *retType, + TOperator op, + bool knownToNotHaveSideEffects) + : TSymbol(id, name, SymbolType::BuiltIn, extension, SymbolClass::Function), + mParametersVector(nullptr), + mParameters(parameters), + mParamCount(paramCount), + returnType(retType), + mMangledName(nullptr), + mOp(op), + defined(false), + mHasPrototypeDeclaration(false), + mKnownToNotHaveSideEffects(knownToNotHaveSideEffects) + {} + + private: + ImmutableString buildMangledName() const; + + typedef TVector<const TVariable *> TParamVector; + TParamVector *mParametersVector; + const TVariable *const *mParameters; + size_t mParamCount; + const TType *const returnType; + mutable ImmutableString mMangledName; + const TOperator mOp; // Only set for built-ins + bool defined; + bool mHasPrototypeDeclaration; + bool mKnownToNotHaveSideEffects; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SYMBOL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp b/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp new file mode 100644 index 0000000000..cc9e72e880 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable.cpp @@ -0,0 +1,417 @@ +// +// Copyright (c) 2002-2013 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. +// +// Symbol table for parsing. The design principles and most of the functionality are documented in +// the header file. +// + +#if defined(_MSC_VER) +# pragma warning(disable : 4718) +#endif + +#include "compiler/translator/SymbolTable.h" + +#include "angle_gl.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +class TSymbolTable::TSymbolTableLevel +{ + public: + TSymbolTableLevel() = default; + + bool insert(TSymbol *symbol); + + // Insert a function using its unmangled name as the key. + void insertUnmangled(TFunction *function); + + TSymbol *find(const ImmutableString &name) const; + + private: + using tLevel = TUnorderedMap<ImmutableString, + TSymbol *, + ImmutableString::FowlerNollVoHash<sizeof(size_t)>>; + using tLevelPair = const tLevel::value_type; + using tInsertResult = std::pair<tLevel::iterator, bool>; + + tLevel level; +}; + +bool TSymbolTable::TSymbolTableLevel::insert(TSymbol *symbol) +{ + // returning true means symbol was added to the table + tInsertResult result = level.insert(tLevelPair(symbol->getMangledName(), symbol)); + return result.second; +} + +void TSymbolTable::TSymbolTableLevel::insertUnmangled(TFunction *function) +{ + level.insert(tLevelPair(function->name(), function)); +} + +TSymbol *TSymbolTable::TSymbolTableLevel::find(const ImmutableString &name) const +{ + tLevel::const_iterator it = level.find(name); + if (it == level.end()) + return nullptr; + else + return (*it).second; +} + +TSymbolTable::TSymbolTable() + : mGlobalInvariant(false), + mUniqueIdCounter(0), + mShaderType(GL_FRAGMENT_SHADER), + mGlInVariableWithArraySize(nullptr) +{} + +TSymbolTable::~TSymbolTable() = default; + +bool TSymbolTable::isEmpty() const +{ + return mTable.empty(); +} + +bool TSymbolTable::atGlobalLevel() const +{ + return mTable.size() == 1u; +} + +void TSymbolTable::push() +{ + mTable.emplace_back(new TSymbolTableLevel); + mPrecisionStack.emplace_back(new PrecisionStackLevel); +} + +void TSymbolTable::pop() +{ + mTable.pop_back(); + mPrecisionStack.pop_back(); +} + +const TFunction *TSymbolTable::markFunctionHasPrototypeDeclaration( + const ImmutableString &mangledName, + bool *hadPrototypeDeclarationOut) const +{ + TFunction *function = findUserDefinedFunction(mangledName); + *hadPrototypeDeclarationOut = function->hasPrototypeDeclaration(); + function->setHasPrototypeDeclaration(); + return function; +} + +const TFunction *TSymbolTable::setFunctionParameterNamesFromDefinition(const TFunction *function, + bool *wasDefinedOut) const +{ + TFunction *firstDeclaration = findUserDefinedFunction(function->getMangledName()); + ASSERT(firstDeclaration); + // Note: 'firstDeclaration' could be 'function' if this is the first time we've seen function as + // it would have just been put in the symbol table. Otherwise, we're looking up an earlier + // occurance. + if (function != firstDeclaration) + { + // The previous declaration should have the same parameters as the function definition + // (parameter names may differ). + firstDeclaration->shareParameters(*function); + } + + *wasDefinedOut = firstDeclaration->isDefined(); + firstDeclaration->setDefined(); + return firstDeclaration; +} + +bool TSymbolTable::setGlInArraySize(unsigned int inputArraySize) +{ + if (mGlInVariableWithArraySize) + { + return mGlInVariableWithArraySize->getType().getOutermostArraySize() == inputArraySize; + } + const TInterfaceBlock *glPerVertex = mVar_gl_PerVertex; + TType *glInType = new TType(glPerVertex, EvqPerVertexIn, TLayoutQualifier::Create()); + glInType->makeArray(inputArraySize); + mGlInVariableWithArraySize = + new TVariable(this, ImmutableString("gl_in"), glInType, SymbolType::BuiltIn, + TExtension::EXT_geometry_shader); + return true; +} + +TVariable *TSymbolTable::getGlInVariableWithArraySize() const +{ + return mGlInVariableWithArraySize; +} + +const TVariable *TSymbolTable::gl_FragData() const +{ + return mVar_gl_FragData; +} + +const TVariable *TSymbolTable::gl_SecondaryFragDataEXT() const +{ + return mVar_gl_SecondaryFragDataEXT; +} + +TSymbolTable::VariableMetadata *TSymbolTable::getOrCreateVariableMetadata(const TVariable &variable) +{ + int id = variable.uniqueId().get(); + auto iter = mVariableMetadata.find(id); + if (iter == mVariableMetadata.end()) + { + iter = mVariableMetadata.insert(std::make_pair(id, VariableMetadata())).first; + } + return &iter->second; +} + +void TSymbolTable::markStaticWrite(const TVariable &variable) +{ + auto metadata = getOrCreateVariableMetadata(variable); + metadata->staticWrite = true; +} + +void TSymbolTable::markStaticRead(const TVariable &variable) +{ + auto metadata = getOrCreateVariableMetadata(variable); + metadata->staticRead = true; +} + +bool TSymbolTable::isStaticallyUsed(const TVariable &variable) const +{ + ASSERT(!variable.getConstPointer()); + int id = variable.uniqueId().get(); + auto iter = mVariableMetadata.find(id); + return iter != mVariableMetadata.end() && (iter->second.staticRead || iter->second.staticWrite); +} + +void TSymbolTable::addInvariantVarying(const TVariable &variable) +{ + ASSERT(atGlobalLevel()); + auto metadata = getOrCreateVariableMetadata(variable); + metadata->invariant = true; +} + +bool TSymbolTable::isVaryingInvariant(const TVariable &variable) const +{ + ASSERT(atGlobalLevel()); + if (mGlobalInvariant && (IsShaderOutput(variable.getType().getQualifier()))) + { + return true; + } + int id = variable.uniqueId().get(); + auto iter = mVariableMetadata.find(id); + return iter != mVariableMetadata.end() && iter->second.invariant; +} + +void TSymbolTable::setGlobalInvariant(bool invariant) +{ + ASSERT(atGlobalLevel()); + mGlobalInvariant = invariant; +} + +const TSymbol *TSymbolTable::find(const ImmutableString &name, int shaderVersion) const +{ + const TSymbol *userSymbol = findUserDefined(name); + if (userSymbol) + { + return userSymbol; + } + + return findBuiltIn(name, shaderVersion); +} + +const TSymbol *TSymbolTable::findUserDefined(const ImmutableString &name) const +{ + int userDefinedLevel = static_cast<int>(mTable.size()) - 1; + while (userDefinedLevel >= 0) + { + const TSymbol *symbol = mTable[userDefinedLevel]->find(name); + if (symbol) + { + return symbol; + } + userDefinedLevel--; + } + + return nullptr; +} + +TFunction *TSymbolTable::findUserDefinedFunction(const ImmutableString &name) const +{ + // User-defined functions are always declared at the global level. + ASSERT(!mTable.empty()); + return static_cast<TFunction *>(mTable[0]->find(name)); +} + +const TSymbol *TSymbolTable::findGlobal(const ImmutableString &name) const +{ + ASSERT(!mTable.empty()); + return mTable[0]->find(name); +} + +const TSymbol *TSymbolTable::findGlobalWithConversion( + const std::vector<ImmutableString> &names) const +{ + const TSymbol *target; + for (ImmutableString name : names) + { + target = findGlobal(name); + if (target != nullptr) + break; + } + return target; +} + +const TSymbol *TSymbolTable::findBuiltInWithConversion(const std::vector<ImmutableString> &names, + int shaderVersion) const +{ + const TSymbol *target; + for (ImmutableString name : names) + { + target = findBuiltIn(name, shaderVersion); + if (target != nullptr) + break; + } + return target; +} + +bool TSymbolTable::declare(TSymbol *symbol) +{ + ASSERT(!mTable.empty()); + ASSERT(symbol->symbolType() == SymbolType::UserDefined); + ASSERT(!symbol->isFunction()); + return mTable.back()->insert(symbol); +} + +bool TSymbolTable::declareInternal(TSymbol *symbol) +{ + ASSERT(!mTable.empty()); + ASSERT(symbol->symbolType() == SymbolType::AngleInternal); + ASSERT(!symbol->isFunction()); + return mTable.back()->insert(symbol); +} + +void TSymbolTable::declareUserDefinedFunction(TFunction *function, bool insertUnmangledName) +{ + ASSERT(!mTable.empty()); + if (insertUnmangledName) + { + // Insert the unmangled name to detect potential future redefinition as a variable. + mTable[0]->insertUnmangled(function); + } + mTable[0]->insert(function); +} + +void TSymbolTable::setDefaultPrecision(TBasicType type, TPrecision prec) +{ + int indexOfLastElement = static_cast<int>(mPrecisionStack.size()) - 1; + // Uses map operator [], overwrites the current value + (*mPrecisionStack[indexOfLastElement])[type] = prec; +} + +TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const +{ + if (!SupportsPrecision(type)) + return EbpUndefined; + + // unsigned integers use the same precision as signed + TBasicType baseType = (type == EbtUInt) ? EbtInt : type; + + int level = static_cast<int>(mPrecisionStack.size()) - 1; + ASSERT(level >= 0); // Just to be safe. Should not happen. + // If we dont find anything we return this. Some types don't have predefined default precision. + TPrecision prec = EbpUndefined; + while (level >= 0) + { + PrecisionStackLevel::iterator it = mPrecisionStack[level]->find(baseType); + if (it != mPrecisionStack[level]->end()) + { + prec = (*it).second; + break; + } + level--; + } + return prec; +} + +void TSymbolTable::clearCompilationResults() +{ + mGlobalInvariant = false; + mUniqueIdCounter = kLastBuiltInId + 1; + mVariableMetadata.clear(); + mGlInVariableWithArraySize = nullptr; + + // User-defined scopes should have already been cleared when the compilation finished. + ASSERT(mTable.empty()); +} + +int TSymbolTable::nextUniqueIdValue() +{ + ASSERT(mUniqueIdCounter < std::numeric_limits<int>::max()); + return ++mUniqueIdCounter; +} + +void TSymbolTable::initializeBuiltIns(sh::GLenum type, + ShShaderSpec spec, + const ShBuiltInResources &resources) +{ + mShaderType = type; + mResources = resources; + + // We need just one precision stack level for predefined precisions. + mPrecisionStack.emplace_back(new PrecisionStackLevel); + + if (IsDesktopGLSpec(spec)) + { + setDefaultPrecision(EbtInt, EbpUndefined); + setDefaultPrecision(EbtFloat, EbpUndefined); + } + else + { + switch (type) + { + case GL_FRAGMENT_SHADER: + setDefaultPrecision(EbtInt, EbpMedium); + break; + case GL_VERTEX_SHADER: + case GL_COMPUTE_SHADER: + case GL_GEOMETRY_SHADER_EXT: + setDefaultPrecision(EbtInt, EbpHigh); + setDefaultPrecision(EbtFloat, EbpHigh); + break; + default: + UNREACHABLE(); + } + } + + // Set defaults for sampler types that have default precision, even those that are + // only available if an extension exists. + // New sampler types in ESSL3 don't have default precision. ESSL1 types do. + initSamplerDefaultPrecision(EbtSampler2D); + initSamplerDefaultPrecision(EbtSamplerCube); + // SamplerExternalOES is specified in the extension to have default precision. + initSamplerDefaultPrecision(EbtSamplerExternalOES); + // SamplerExternal2DY2YEXT is specified in the extension to have default precision. + initSamplerDefaultPrecision(EbtSamplerExternal2DY2YEXT); + // It isn't specified whether Sampler2DRect has default precision. + initSamplerDefaultPrecision(EbtSampler2DRect); + + setDefaultPrecision(EbtAtomicCounter, EbpHigh); + + initializeBuiltInVariables(type, spec, resources); + mUniqueIdCounter = kLastBuiltInId + 1; +} + +void TSymbolTable::initSamplerDefaultPrecision(TBasicType samplerType) +{ + ASSERT(samplerType >= EbtGuardSamplerBegin && samplerType <= EbtGuardSamplerEnd); + setDefaultPrecision(samplerType, EbpLow); +} + +TSymbolTable::VariableMetadata::VariableMetadata() + : staticRead(false), staticWrite(false), invariant(false) +{} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable.h b/gfx/angle/checkout/src/compiler/translator/SymbolTable.h new file mode 100644 index 0000000000..687ddccd6f --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable.h @@ -0,0 +1,201 @@ +// +// Copyright (c) 2002-2014 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_SYMBOLTABLE_H_ +#define COMPILER_TRANSLATOR_SYMBOLTABLE_H_ + +// +// Symbol table for parsing. Has these design characteristics: +// +// * Same symbol table can be used to compile many shaders, to preserve +// effort of creating and loading with the large numbers of built-in +// symbols. +// +// * Name mangling will be used to give each function a unique name +// so that symbol table lookups are never ambiguous. This allows +// a simpler symbol table structure. +// +// * Pushing and popping of scope, so symbol table will really be a stack +// of symbol tables. Searched from the top, with new inserts going into +// the top. +// +// * Constants: Compile time constant symbols will keep their values +// in the symbol table. The parser can substitute constants at parse +// time, including doing constant folding and constant propagation. +// +// * No temporaries: Temporaries made from operations (+, --, .xy, etc.) +// are tracked in the intermediate representation, not the symbol table. +// + +#include <memory> +#include <set> + +#include "common/angleutils.h" +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Symbol.h" +#include "compiler/translator/SymbolTable_autogen.h" + +namespace sh +{ + +// Define ESymbolLevel as int rather than an enum so that we can do arithmetic on it. +typedef int ESymbolLevel; +const int COMMON_BUILTINS = 0; +const int ESSL1_BUILTINS = 1; +const int ESSL3_BUILTINS = 2; +const int ESSL3_1_BUILTINS = 3; +// GLSL_BUILTINS are desktop GLSL builtins that don't exist in ESSL but are used to implement +// features in ANGLE's GLSL backend. They're not visible to the parser. +const int GLSL_BUILTINS = 4; +const int LAST_BUILTIN_LEVEL = GLSL_BUILTINS; + +struct UnmangledBuiltIn +{ + constexpr UnmangledBuiltIn(TExtension extension) : extension(extension) {} + + TExtension extension; +}; + +class TSymbolTable : angle::NonCopyable, TSymbolTableBase +{ + public: + TSymbolTable(); + // To start using the symbol table after construction: + // * initializeBuiltIns() needs to be called. + // * push() needs to be called to push the global level. + + ~TSymbolTable(); + + bool isEmpty() const; + bool atGlobalLevel() const; + + void push(); + void pop(); + + // Declare a non-function symbol at the current scope. Return true in case the declaration was + // successful, and false if the declaration failed due to redefinition. + bool declare(TSymbol *symbol); + + // Only used to declare internal variables. + bool declareInternal(TSymbol *symbol); + + // Functions are always declared at global scope. + void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName); + + // These return the TFunction pointer to keep using to refer to this function. + const TFunction *markFunctionHasPrototypeDeclaration(const ImmutableString &mangledName, + bool *hadPrototypeDeclarationOut) const; + const TFunction *setFunctionParameterNamesFromDefinition(const TFunction *function, + bool *wasDefinedOut) const; + + // Return false if the gl_in array size has already been initialized with a mismatching value. + bool setGlInArraySize(unsigned int inputArraySize); + TVariable *getGlInVariableWithArraySize() const; + + const TVariable *gl_FragData() const; + const TVariable *gl_SecondaryFragDataEXT() const; + + void markStaticRead(const TVariable &variable); + void markStaticWrite(const TVariable &variable); + + // Note: Should not call this for constant variables. + bool isStaticallyUsed(const TVariable &variable) const; + + // find() is guaranteed not to retain a reference to the ImmutableString, so an ImmutableString + // with a reference to a short-lived char * is fine to pass here. + const TSymbol *find(const ImmutableString &name, int shaderVersion) const; + + const TSymbol *findUserDefined(const ImmutableString &name) const; + + TFunction *findUserDefinedFunction(const ImmutableString &name) const; + + const TSymbol *findGlobal(const ImmutableString &name) const; + const TSymbol *findGlobalWithConversion(const std::vector<ImmutableString> &names) const; + + const TSymbol *findBuiltIn(const ImmutableString &name, int shaderVersion) const; + const TSymbol *findBuiltInWithConversion(const std::vector<ImmutableString> &names, + int shaderVersion) const; + + void setDefaultPrecision(TBasicType type, TPrecision prec); + + // Searches down the precisionStack for a precision qualifier + // for the specified TBasicType + TPrecision getDefaultPrecision(TBasicType type) const; + + // This records invariant varyings declared through "invariant varying_name;". + void addInvariantVarying(const TVariable &variable); + + // If this returns false, the varying could still be invariant if it is set as invariant during + // the varying variable declaration - this piece of information is stored in the variable's + // type, not here. + bool isVaryingInvariant(const TVariable &variable) const; + + void setGlobalInvariant(bool invariant); + + const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); } + + // Gets the built-in accessible by a shader with the specified version, if any. + const UnmangledBuiltIn *getUnmangledBuiltInForShaderVersion(const ImmutableString &name, + int shaderVersion); + + void initializeBuiltIns(sh::GLenum type, + ShShaderSpec spec, + const ShBuiltInResources &resources); + void clearCompilationResults(); + + private: + friend class TSymbolUniqueId; + + struct VariableMetadata + { + VariableMetadata(); + bool staticRead; + bool staticWrite; + bool invariant; + }; + + int nextUniqueIdValue(); + + class TSymbolTableLevel; + + void initSamplerDefaultPrecision(TBasicType samplerType); + + void initializeBuiltInVariables(sh::GLenum shaderType, + ShShaderSpec spec, + const ShBuiltInResources &resources); + + VariableMetadata *getOrCreateVariableMetadata(const TVariable &variable); + + std::vector<std::unique_ptr<TSymbolTableLevel>> mTable; + + // There's one precision stack level for predefined precisions and then one level for each scope + // in table. + typedef TMap<TBasicType, TPrecision> PrecisionStackLevel; + std::vector<std::unique_ptr<PrecisionStackLevel>> mPrecisionStack; + + bool mGlobalInvariant; + + int mUniqueIdCounter; + + static const int kLastBuiltInId; + + sh::GLenum mShaderType; + ShBuiltInResources mResources; + + // Indexed by unique id. Map instead of vector since the variables are fairly sparse. + std::map<int, VariableMetadata> mVariableMetadata; + + // Store gl_in variable with its array size once the array size can be determined. The array + // size can also be checked against latter input primitive type declaration. + TVariable *mGlInVariableWithArraySize; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp new file mode 100644 index 0000000000..d2307d5f53 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp @@ -0,0 +1,20959 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_builtin_symbols.py using data from builtin_variables.json and +// builtin_function_declarations.txt. +// +// 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. +// +// SymbolTable_autogen.cpp: +// Compile-time initialized built-ins. + +#include "compiler/translator/SymbolTable.h" + +#include "angle_gl.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/Symbol.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.h" + +namespace sh +{ + +// Since some of the BuiltInId declarations are used outside of constexpr expressions, we need to +// have these definitions without an initializer. C++17 should eventually remove the need for this. +constexpr const TSymbolUniqueId BuiltInId::radians_Float1; +constexpr const TSymbolUniqueId BuiltInId::radians_Float2; +constexpr const TSymbolUniqueId BuiltInId::radians_Float3; +constexpr const TSymbolUniqueId BuiltInId::radians_Float4; +constexpr const TSymbolUniqueId BuiltInId::degrees_Float1; +constexpr const TSymbolUniqueId BuiltInId::degrees_Float2; +constexpr const TSymbolUniqueId BuiltInId::degrees_Float3; +constexpr const TSymbolUniqueId BuiltInId::degrees_Float4; +constexpr const TSymbolUniqueId BuiltInId::sin_Float1; +constexpr const TSymbolUniqueId BuiltInId::sin_Float2; +constexpr const TSymbolUniqueId BuiltInId::sin_Float3; +constexpr const TSymbolUniqueId BuiltInId::sin_Float4; +constexpr const TSymbolUniqueId BuiltInId::cos_Float1; +constexpr const TSymbolUniqueId BuiltInId::cos_Float2; +constexpr const TSymbolUniqueId BuiltInId::cos_Float3; +constexpr const TSymbolUniqueId BuiltInId::cos_Float4; +constexpr const TSymbolUniqueId BuiltInId::tan_Float1; +constexpr const TSymbolUniqueId BuiltInId::tan_Float2; +constexpr const TSymbolUniqueId BuiltInId::tan_Float3; +constexpr const TSymbolUniqueId BuiltInId::tan_Float4; +constexpr const TSymbolUniqueId BuiltInId::asin_Float1; +constexpr const TSymbolUniqueId BuiltInId::asin_Float2; +constexpr const TSymbolUniqueId BuiltInId::asin_Float3; +constexpr const TSymbolUniqueId BuiltInId::asin_Float4; +constexpr const TSymbolUniqueId BuiltInId::acos_Float1; +constexpr const TSymbolUniqueId BuiltInId::acos_Float2; +constexpr const TSymbolUniqueId BuiltInId::acos_Float3; +constexpr const TSymbolUniqueId BuiltInId::acos_Float4; +constexpr const TSymbolUniqueId BuiltInId::atan_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::atan_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::atan_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::atan_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::atan_Float1; +constexpr const TSymbolUniqueId BuiltInId::atan_Float2; +constexpr const TSymbolUniqueId BuiltInId::atan_Float3; +constexpr const TSymbolUniqueId BuiltInId::atan_Float4; +constexpr const TSymbolUniqueId BuiltInId::sinh_Float1; +constexpr const TSymbolUniqueId BuiltInId::sinh_Float2; +constexpr const TSymbolUniqueId BuiltInId::sinh_Float3; +constexpr const TSymbolUniqueId BuiltInId::sinh_Float4; +constexpr const TSymbolUniqueId BuiltInId::cosh_Float1; +constexpr const TSymbolUniqueId BuiltInId::cosh_Float2; +constexpr const TSymbolUniqueId BuiltInId::cosh_Float3; +constexpr const TSymbolUniqueId BuiltInId::cosh_Float4; +constexpr const TSymbolUniqueId BuiltInId::tanh_Float1; +constexpr const TSymbolUniqueId BuiltInId::tanh_Float2; +constexpr const TSymbolUniqueId BuiltInId::tanh_Float3; +constexpr const TSymbolUniqueId BuiltInId::tanh_Float4; +constexpr const TSymbolUniqueId BuiltInId::asinh_Float1; +constexpr const TSymbolUniqueId BuiltInId::asinh_Float2; +constexpr const TSymbolUniqueId BuiltInId::asinh_Float3; +constexpr const TSymbolUniqueId BuiltInId::asinh_Float4; +constexpr const TSymbolUniqueId BuiltInId::acosh_Float1; +constexpr const TSymbolUniqueId BuiltInId::acosh_Float2; +constexpr const TSymbolUniqueId BuiltInId::acosh_Float3; +constexpr const TSymbolUniqueId BuiltInId::acosh_Float4; +constexpr const TSymbolUniqueId BuiltInId::atanh_Float1; +constexpr const TSymbolUniqueId BuiltInId::atanh_Float2; +constexpr const TSymbolUniqueId BuiltInId::atanh_Float3; +constexpr const TSymbolUniqueId BuiltInId::atanh_Float4; +constexpr const TSymbolUniqueId BuiltInId::pow_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::pow_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::pow_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::pow_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::exp_Float1; +constexpr const TSymbolUniqueId BuiltInId::exp_Float2; +constexpr const TSymbolUniqueId BuiltInId::exp_Float3; +constexpr const TSymbolUniqueId BuiltInId::exp_Float4; +constexpr const TSymbolUniqueId BuiltInId::log_Float1; +constexpr const TSymbolUniqueId BuiltInId::log_Float2; +constexpr const TSymbolUniqueId BuiltInId::log_Float3; +constexpr const TSymbolUniqueId BuiltInId::log_Float4; +constexpr const TSymbolUniqueId BuiltInId::exp2_Float1; +constexpr const TSymbolUniqueId BuiltInId::exp2_Float2; +constexpr const TSymbolUniqueId BuiltInId::exp2_Float3; +constexpr const TSymbolUniqueId BuiltInId::exp2_Float4; +constexpr const TSymbolUniqueId BuiltInId::log2_Float1; +constexpr const TSymbolUniqueId BuiltInId::log2_Float2; +constexpr const TSymbolUniqueId BuiltInId::log2_Float3; +constexpr const TSymbolUniqueId BuiltInId::log2_Float4; +constexpr const TSymbolUniqueId BuiltInId::sqrt_Float1; +constexpr const TSymbolUniqueId BuiltInId::sqrt_Float2; +constexpr const TSymbolUniqueId BuiltInId::sqrt_Float3; +constexpr const TSymbolUniqueId BuiltInId::sqrt_Float4; +constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float1; +constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float2; +constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float3; +constexpr const TSymbolUniqueId BuiltInId::inversesqrt_Float4; +constexpr const TSymbolUniqueId BuiltInId::abs_Float1; +constexpr const TSymbolUniqueId BuiltInId::abs_Float2; +constexpr const TSymbolUniqueId BuiltInId::abs_Float3; +constexpr const TSymbolUniqueId BuiltInId::abs_Float4; +constexpr const TSymbolUniqueId BuiltInId::abs_Int1; +constexpr const TSymbolUniqueId BuiltInId::abs_Int2; +constexpr const TSymbolUniqueId BuiltInId::abs_Int3; +constexpr const TSymbolUniqueId BuiltInId::abs_Int4; +constexpr const TSymbolUniqueId BuiltInId::sign_Float1; +constexpr const TSymbolUniqueId BuiltInId::sign_Float2; +constexpr const TSymbolUniqueId BuiltInId::sign_Float3; +constexpr const TSymbolUniqueId BuiltInId::sign_Float4; +constexpr const TSymbolUniqueId BuiltInId::sign_Int1; +constexpr const TSymbolUniqueId BuiltInId::sign_Int2; +constexpr const TSymbolUniqueId BuiltInId::sign_Int3; +constexpr const TSymbolUniqueId BuiltInId::sign_Int4; +constexpr const TSymbolUniqueId BuiltInId::floor_Float1; +constexpr const TSymbolUniqueId BuiltInId::floor_Float2; +constexpr const TSymbolUniqueId BuiltInId::floor_Float3; +constexpr const TSymbolUniqueId BuiltInId::floor_Float4; +constexpr const TSymbolUniqueId BuiltInId::trunc_Float1; +constexpr const TSymbolUniqueId BuiltInId::trunc_Float2; +constexpr const TSymbolUniqueId BuiltInId::trunc_Float3; +constexpr const TSymbolUniqueId BuiltInId::trunc_Float4; +constexpr const TSymbolUniqueId BuiltInId::round_Float1; +constexpr const TSymbolUniqueId BuiltInId::round_Float2; +constexpr const TSymbolUniqueId BuiltInId::round_Float3; +constexpr const TSymbolUniqueId BuiltInId::round_Float4; +constexpr const TSymbolUniqueId BuiltInId::roundEven_Float1; +constexpr const TSymbolUniqueId BuiltInId::roundEven_Float2; +constexpr const TSymbolUniqueId BuiltInId::roundEven_Float3; +constexpr const TSymbolUniqueId BuiltInId::roundEven_Float4; +constexpr const TSymbolUniqueId BuiltInId::ceil_Float1; +constexpr const TSymbolUniqueId BuiltInId::ceil_Float2; +constexpr const TSymbolUniqueId BuiltInId::ceil_Float3; +constexpr const TSymbolUniqueId BuiltInId::ceil_Float4; +constexpr const TSymbolUniqueId BuiltInId::fract_Float1; +constexpr const TSymbolUniqueId BuiltInId::fract_Float2; +constexpr const TSymbolUniqueId BuiltInId::fract_Float3; +constexpr const TSymbolUniqueId BuiltInId::fract_Float4; +constexpr const TSymbolUniqueId BuiltInId::mod_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::mod_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::mod_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::mod_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::mod_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::mod_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::mod_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::min_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::min_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::min_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::min_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::min_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::min_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::min_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::min_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::min_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::min_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::min_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::min_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::min_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::min_Int4_Int1; +constexpr const TSymbolUniqueId BuiltInId::min_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::min_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::min_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::min_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::min_UInt2_UInt1; +constexpr const TSymbolUniqueId BuiltInId::min_UInt3_UInt1; +constexpr const TSymbolUniqueId BuiltInId::min_UInt4_UInt1; +constexpr const TSymbolUniqueId BuiltInId::max_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::max_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::max_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::max_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::max_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::max_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::max_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::max_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::max_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::max_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::max_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::max_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::max_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::max_Int4_Int1; +constexpr const TSymbolUniqueId BuiltInId::max_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::max_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::max_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::max_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::max_UInt2_UInt1; +constexpr const TSymbolUniqueId BuiltInId::max_UInt3_UInt1; +constexpr const TSymbolUniqueId BuiltInId::max_UInt4_UInt1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Float1_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Float2_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Float3_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Float4_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::clamp_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::clamp_Float4_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::clamp_Int1_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Int2_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Int3_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Int4_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::clamp_Int2_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::clamp_Int3_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::clamp_Int4_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::clamp_UInt1_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::clamp_UInt2_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::clamp_UInt3_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::clamp_UInt4_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::clamp_UInt2_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::clamp_UInt3_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::clamp_UInt4_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::mix_Float1_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::mix_Float2_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::mix_Float3_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::mix_Float4_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::mix_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::mix_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::mix_Float4_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::mix_Float1_Float1_Bool1; +constexpr const TSymbolUniqueId BuiltInId::mix_Float2_Float2_Bool2; +constexpr const TSymbolUniqueId BuiltInId::mix_Float3_Float3_Bool3; +constexpr const TSymbolUniqueId BuiltInId::mix_Float4_Float4_Bool4; +constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::step_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::step_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::step_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float2; +constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float3; +constexpr const TSymbolUniqueId BuiltInId::step_Float1_Float4; +constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float4_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float2; +constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float3; +constexpr const TSymbolUniqueId BuiltInId::smoothstep_Float1_Float1_Float4; +constexpr const TSymbolUniqueId BuiltInId::modf_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::modf_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::modf_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::modf_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::isnan_Float1; +constexpr const TSymbolUniqueId BuiltInId::isnan_Float2; +constexpr const TSymbolUniqueId BuiltInId::isnan_Float3; +constexpr const TSymbolUniqueId BuiltInId::isnan_Float4; +constexpr const TSymbolUniqueId BuiltInId::isinf_Float1; +constexpr const TSymbolUniqueId BuiltInId::isinf_Float2; +constexpr const TSymbolUniqueId BuiltInId::isinf_Float3; +constexpr const TSymbolUniqueId BuiltInId::isinf_Float4; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float1; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float2; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float3; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToInt_Float4; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float1; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float2; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float3; +constexpr const TSymbolUniqueId BuiltInId::floatBitsToUint_Float4; +constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int1; +constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int2; +constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int3; +constexpr const TSymbolUniqueId BuiltInId::intBitsToFloat_Int4; +constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt1; +constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt2; +constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt3; +constexpr const TSymbolUniqueId BuiltInId::uintBitsToFloat_UInt4; +constexpr const TSymbolUniqueId BuiltInId::frexp_Float1_Int1; +constexpr const TSymbolUniqueId BuiltInId::frexp_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::frexp_Float3_Int3; +constexpr const TSymbolUniqueId BuiltInId::frexp_Float4_Int4; +constexpr const TSymbolUniqueId BuiltInId::ldexp_Float1_Int1; +constexpr const TSymbolUniqueId BuiltInId::ldexp_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::ldexp_Float3_Int3; +constexpr const TSymbolUniqueId BuiltInId::ldexp_Float4_Int4; +constexpr const TSymbolUniqueId BuiltInId::packSnorm2x16_Float2; +constexpr const TSymbolUniqueId BuiltInId::packUnorm2x16_Float2; +constexpr const TSymbolUniqueId BuiltInId::packHalf2x16_Float2; +constexpr const TSymbolUniqueId BuiltInId::unpackSnorm2x16_UInt1; +constexpr const TSymbolUniqueId BuiltInId::unpackUnorm2x16_UInt1; +constexpr const TSymbolUniqueId BuiltInId::unpackHalf2x16_UInt1; +constexpr const TSymbolUniqueId BuiltInId::packUnorm4x8_Float4; +constexpr const TSymbolUniqueId BuiltInId::packSnorm4x8_Float4; +constexpr const TSymbolUniqueId BuiltInId::unpackUnorm4x8_UInt1; +constexpr const TSymbolUniqueId BuiltInId::unpackSnorm4x8_UInt1; +constexpr const TSymbolUniqueId BuiltInId::length_Float1; +constexpr const TSymbolUniqueId BuiltInId::length_Float2; +constexpr const TSymbolUniqueId BuiltInId::length_Float3; +constexpr const TSymbolUniqueId BuiltInId::length_Float4; +constexpr const TSymbolUniqueId BuiltInId::distance_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::distance_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::distance_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::distance_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::dot_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::dot_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::dot_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::dot_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::cross_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::normalize_Float1; +constexpr const TSymbolUniqueId BuiltInId::normalize_Float2; +constexpr const TSymbolUniqueId BuiltInId::normalize_Float3; +constexpr const TSymbolUniqueId BuiltInId::normalize_Float4; +constexpr const TSymbolUniqueId BuiltInId::faceforward_Float1_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::faceforward_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::faceforward_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::faceforward_Float4_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::reflect_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::reflect_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::reflect_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::reflect_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::refract_Float1_Float1_Float1; +constexpr const TSymbolUniqueId BuiltInId::refract_Float2_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::refract_Float3_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::refract_Float4_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float2x2_Float2x2; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float3x3_Float3x3; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float4x4_Float4x4; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float2x3_Float2x3; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float3x2_Float3x2; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float2x4_Float2x4; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float4x2_Float4x2; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float3x4_Float3x4; +constexpr const TSymbolUniqueId BuiltInId::matrixCompMult_Float4x3_Float4x3; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float3_Float2; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float2_Float3; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float4_Float2; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float2_Float4; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float4_Float3; +constexpr const TSymbolUniqueId BuiltInId::outerProduct_Float3_Float4; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float2x2; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float3x3; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float4x4; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float3x2; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float2x3; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float4x2; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float2x4; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float4x3; +constexpr const TSymbolUniqueId BuiltInId::transpose_Float3x4; +constexpr const TSymbolUniqueId BuiltInId::determinant_Float2x2; +constexpr const TSymbolUniqueId BuiltInId::determinant_Float3x3; +constexpr const TSymbolUniqueId BuiltInId::determinant_Float4x4; +constexpr const TSymbolUniqueId BuiltInId::inverse_Float2x2; +constexpr const TSymbolUniqueId BuiltInId::inverse_Float3x3; +constexpr const TSymbolUniqueId BuiltInId::inverse_Float4x4; +constexpr const TSymbolUniqueId BuiltInId::lessThan_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::lessThan_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::lessThan_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::lessThan_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::lessThan_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::lessThan_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::lessThan_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::lessThan_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::lessThan_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::lessThanEqual_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::greaterThan_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::greaterThanEqual_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::equal_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::equal_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::equal_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::equal_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::equal_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::equal_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::equal_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::equal_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::equal_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::equal_Bool2_Bool2; +constexpr const TSymbolUniqueId BuiltInId::equal_Bool3_Bool3; +constexpr const TSymbolUniqueId BuiltInId::equal_Bool4_Bool4; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Float4_Float4; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::notEqual_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::notEqual_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::notEqual_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Bool2_Bool2; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Bool3_Bool3; +constexpr const TSymbolUniqueId BuiltInId::notEqual_Bool4_Bool4; +constexpr const TSymbolUniqueId BuiltInId::any_Bool2; +constexpr const TSymbolUniqueId BuiltInId::any_Bool3; +constexpr const TSymbolUniqueId BuiltInId::any_Bool4; +constexpr const TSymbolUniqueId BuiltInId::all_Bool2; +constexpr const TSymbolUniqueId BuiltInId::all_Bool3; +constexpr const TSymbolUniqueId BuiltInId::all_Bool4; +constexpr const TSymbolUniqueId BuiltInId::notFunc_Bool2; +constexpr const TSymbolUniqueId BuiltInId::notFunc_Bool3; +constexpr const TSymbolUniqueId BuiltInId::notFunc_Bool4; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int1_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int2_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int3_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_Int4_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt1_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt2_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt3_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldExtract_UInt4_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int1_Int1_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int2_Int2_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int3_Int3_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_Int4_Int4_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt1_UInt1_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt2_UInt2_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt3_UInt3_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldInsert_UInt4_UInt4_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int2; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int3; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_Int4; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt1; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt2; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt3; +constexpr const TSymbolUniqueId BuiltInId::bitfieldReverse_UInt4; +constexpr const TSymbolUniqueId BuiltInId::bitCount_Int1; +constexpr const TSymbolUniqueId BuiltInId::bitCount_Int2; +constexpr const TSymbolUniqueId BuiltInId::bitCount_Int3; +constexpr const TSymbolUniqueId BuiltInId::bitCount_Int4; +constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt1; +constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt2; +constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt3; +constexpr const TSymbolUniqueId BuiltInId::bitCount_UInt4; +constexpr const TSymbolUniqueId BuiltInId::findLSB_Int1; +constexpr const TSymbolUniqueId BuiltInId::findLSB_Int2; +constexpr const TSymbolUniqueId BuiltInId::findLSB_Int3; +constexpr const TSymbolUniqueId BuiltInId::findLSB_Int4; +constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt1; +constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt2; +constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt3; +constexpr const TSymbolUniqueId BuiltInId::findLSB_UInt4; +constexpr const TSymbolUniqueId BuiltInId::findMSB_Int1; +constexpr const TSymbolUniqueId BuiltInId::findMSB_Int2; +constexpr const TSymbolUniqueId BuiltInId::findMSB_Int3; +constexpr const TSymbolUniqueId BuiltInId::findMSB_Int4; +constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt1; +constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt2; +constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt3; +constexpr const TSymbolUniqueId BuiltInId::findMSB_UInt4; +constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt1_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt2_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt3_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::uaddCarry_UInt4_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt1_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt2_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt3_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::usubBorrow_UInt4_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt2_UInt2_UInt2_UInt2; +constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt3_UInt3_UInt3_UInt3; +constexpr const TSymbolUniqueId BuiltInId::umulExtended_UInt4_UInt4_UInt4_UInt4; +constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int1_Int1_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int2_Int2_Int2_Int2; +constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int3_Int3_Int3_Int3; +constexpr const TSymbolUniqueId BuiltInId::imulExtended_Int4_Int4_Int4_Int4; +constexpr const TSymbolUniqueId BuiltInId::texture2D_Sampler2D1_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureCube_SamplerCube1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture2D_SamplerExternalOES1_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture2DProj_SamplerExternalOES1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture2DProj_SamplerExternalOES1_Float4; +constexpr const TSymbolUniqueId BuiltInId::texture2DRect_Sampler2DRect1_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture2DRectProj_Sampler2DRect1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture2DRectProj_Sampler2DRect1_Float4; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DRect1_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DRect1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DRect1_Float4; +constexpr const TSymbolUniqueId BuiltInId::texture2DGradEXT_Sampler2D1_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture2DProjGradEXT_Sampler2D1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture2DProjGradEXT_Sampler2D1_Float4_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureCubeGradEXT_SamplerCube1_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture2D_Sampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture2DProj_Sampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureCube_SamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float1; +constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float2; +constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float3; +constexpr const TSymbolUniqueId BuiltInId::dFdxExt_Float4; +constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float1; +constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float2; +constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float3; +constexpr const TSymbolUniqueId BuiltInId::dFdyExt_Float4; +constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float1; +constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float2; +constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float3; +constexpr const TSymbolUniqueId BuiltInId::fwidthExt_Float4; +constexpr const TSymbolUniqueId BuiltInId::texture2DLodEXT_Sampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture2DProjLodEXT_Sampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture2DProjLodEXT_Sampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureCubeLodEXT_SamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture3D_Sampler3D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture3D_Sampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture3DProj_Sampler3D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::texture3DProj_Sampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture3DLod_Sampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture3DProjLod_Sampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture2DLod_Sampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture2DProjLod_Sampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture2DProjLod_Sampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureCubeLod_SamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2D1_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2D1_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture_USampler2D1_Float2; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler3D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_ISampler3D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_USampler3D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCube1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_ISamplerCube1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_USamplerCube1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DArray1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2DArray1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_USampler2DArray1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler3D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler3D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler3D1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_ISampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_USampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_ISampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_USampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_SamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_ISamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_USamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler2DArray1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_ISampler2DArray1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureLod_USampler2DArray1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DShadow1_Float3; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCubeShadow1_Float4; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DArrayShadow1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DShadow1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureLod_Sampler2DShadow1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2D1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2D1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2D1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler3D1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler3D1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler3D1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerCube1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_ISamplerCube1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_USamplerCube1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DArray1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2DArray1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2DArray1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DShadow1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerCubeShadow1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DArrayShadow1_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_ISampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_USampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_ISampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_USampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_ISampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_USampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjLod_Sampler2DShadow1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2D1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2D1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2D1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler3D1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler3D1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler3D1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2DArray1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2DArray1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2DArray1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2D1_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISampler2D1_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_USampler2D1_Float2_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler3D1_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISampler3D1_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_USampler3D1_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_SamplerCube1_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISamplerCube1_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_USamplerCube1_Float3_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2DShadow1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_SamplerCubeShadow1_Float4_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2DArray1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_ISampler2DArray1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_USampler2DArray1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGrad_Sampler2DArrayShadow1_Float4_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler2D1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_ISampler2D1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_USampler2D1_Float3_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler2D1_Float4_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_ISampler2D1_Float4_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_USampler2D1_Float4_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler3D1_Float4_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_ISampler3D1_Float4_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_USampler3D1_Float4_Float3_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProjGrad_Sampler2DShadow1_Float4_Float2_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DMS1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2DMS1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2DMS1; +constexpr const TSymbolUniqueId BuiltInId::textureSizeExt_Sampler2DMS1; +constexpr const TSymbolUniqueId BuiltInId::textureSizeExt_ISampler2DMS1; +constexpr const TSymbolUniqueId BuiltInId::textureSizeExt_USampler2DMS1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_Sampler2DMSArray1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_ISampler2DMSArray1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_USampler2DMSArray1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2D1_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2D1_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2D1_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler3D1_Float3_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler3D1_Float3_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler3D1_Float3_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2DArray1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float4_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler3D1_Float4_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler2D1_Float2_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_ISampler2D1_Float2_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_USampler2D1_Float2_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler3D1_Float3_Float1_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_ISampler3D1_Float3_Float1_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_USampler3D1_Float3_Float1_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler2DShadow1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_Sampler2DArray1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_ISampler2DArray1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureLodOffset_USampler2DArray1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler2D1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_ISampler2D1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_USampler2D1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler2D1_Float4_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_ISampler2D1_Float4_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_USampler2D1_Float4_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler3D1_Float4_Float1_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_ISampler3D1_Float4_Float1_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_USampler3D1_Float4_Float1_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureProjLodOffset_Sampler2DShadow1_Float4_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_Sampler2D1_Int2_Int1_Int2; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_ISampler2D1_Int2_Int1_Int2; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_USampler2D1_Int2_Int1_Int2; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_Sampler3D1_Int3_Int1_Int3; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_ISampler3D1_Int3_Int1_Int3; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_USampler3D1_Int3_Int1_Int3; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_Sampler2DArray1_Int3_Int1_Int2; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_ISampler2DArray1_Int3_Int1_Int2; +constexpr const TSymbolUniqueId BuiltInId::texelFetchOffset_USampler2DArray1_Int3_Int1_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_Sampler2D1_Float2_Float2_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_ISampler2D1_Float2_Float2_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_USampler2D1_Float2_Float2_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_Sampler3D1_Float3_Float3_Float3_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_ISampler3D1_Float3_Float3_Float3_Int3; +constexpr const TSymbolUniqueId BuiltInId::textureGradOffset_USampler3D1_Float3_Float3_Float3_Int3; +constexpr const TSymbolUniqueId + BuiltInId::textureGradOffset_Sampler2DShadow1_Float3_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureGradOffset_Sampler2DArray1_Float3_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureGradOffset_ISampler2DArray1_Float3_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureGradOffset_USampler2DArray1_Float3_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureGradOffset_Sampler2DArrayShadow1_Float4_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_Sampler2D1_Float3_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_ISampler2D1_Float3_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_USampler2D1_Float3_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_Sampler2D1_Float4_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_ISampler2D1_Float4_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_USampler2D1_Float4_Float2_Float2_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_Sampler3D1_Float4_Float3_Float3_Int3; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_ISampler3D1_Float4_Float3_Float3_Int3; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_USampler3D1_Float4_Float3_Float3_Int3; +constexpr const TSymbolUniqueId + BuiltInId::textureProjGradOffset_Sampler2DShadow1_Float4_Float2_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2D1_Float2_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2D1_Float2_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2D1_Float2_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler3D1_Float3_Int3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler3D1_Float3_Int3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler3D1_Float3_Int3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureOffset_USampler2DArray1_Float3_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float3_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler2D1_Float4_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_USampler3D1_Float4_Int3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternalOES1_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float4; +constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerExternalOES1_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_SamplerExternalOES1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4; +constexpr const TSymbolUniqueId BuiltInId::rgb_2_yuv_Float3_YuvCscStandardEXT1; +constexpr const TSymbolUniqueId BuiltInId::yuv_2_rgb_Float3_YuvCscStandardEXT1; +constexpr const TSymbolUniqueId BuiltInId::textureSize_SamplerExternal2DY2YEXT1_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_SamplerExternal2DY2YEXT1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_USampler2D1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_ISampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_USampler3D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_ISamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_USamplerCube1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DArray1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_ISampler2DArray1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_USampler2DArray1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler2D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_ISampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_USampler3D1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_Sampler2DShadow1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerCubeShadow1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_Sampler2DShadow1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternalOES1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternalOES1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4_Float1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2DMS1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2DMS1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2DMS1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetchExt_Sampler2DMS1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetchExt_ISampler2DMS1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetchExt_USampler2DMS1_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_Sampler2DMSArray1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_ISampler2DMSArray1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::texelFetch_USampler2DMSArray1_Int3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2D1_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2D1_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2D1_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2D1_Float2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2D1_Float2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2D1_Float2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArray1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2DArray1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2DArray1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArray1_Float3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_ISampler2DArray1_Float3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_USampler2DArray1_Float3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCube1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_ISamplerCube1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_USamplerCube1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCube1_Float3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_ISamplerCube1_Float3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_USamplerCube1_Float3_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DShadow1_Float2; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DShadow1_Float2_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArrayShadow1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_Sampler2DArrayShadow1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCubeShadow1_Float3; +constexpr const TSymbolUniqueId BuiltInId::textureGather_SamplerCubeShadow1_Float3_Float1; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2_Int1; +constexpr const TSymbolUniqueId BuiltInId::textureGatherOffset_Sampler2DShadow1_Float2_Float1_Int2; +constexpr const TSymbolUniqueId + BuiltInId::textureGatherOffset_Sampler2DArrayShadow1_Float3_Float1_Int2; +constexpr const TSymbolUniqueId BuiltInId::dFdx_Float1; +constexpr const TSymbolUniqueId BuiltInId::dFdx_Float2; +constexpr const TSymbolUniqueId BuiltInId::dFdx_Float3; +constexpr const TSymbolUniqueId BuiltInId::dFdx_Float4; +constexpr const TSymbolUniqueId BuiltInId::dFdy_Float1; +constexpr const TSymbolUniqueId BuiltInId::dFdy_Float2; +constexpr const TSymbolUniqueId BuiltInId::dFdy_Float3; +constexpr const TSymbolUniqueId BuiltInId::dFdy_Float4; +constexpr const TSymbolUniqueId BuiltInId::fwidth_Float1; +constexpr const TSymbolUniqueId BuiltInId::fwidth_Float2; +constexpr const TSymbolUniqueId BuiltInId::fwidth_Float3; +constexpr const TSymbolUniqueId BuiltInId::fwidth_Float4; +constexpr const TSymbolUniqueId BuiltInId::atomicCounter_AtomicCounter1; +constexpr const TSymbolUniqueId BuiltInId::atomicCounterIncrement_AtomicCounter1; +constexpr const TSymbolUniqueId BuiltInId::atomicCounterDecrement_AtomicCounter1; +constexpr const TSymbolUniqueId BuiltInId::atomicAdd_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicAdd_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::atomicMin_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicMin_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::atomicMax_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicMax_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::atomicAnd_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicAnd_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::atomicOr_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicOr_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::atomicXor_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicXor_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::atomicExchange_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicExchange_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::atomicCompSwap_UInt1_UInt1_UInt1; +constexpr const TSymbolUniqueId BuiltInId::atomicCompSwap_Int1_Int1_Int1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_Image2D1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_IImage2D1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_UImage2D1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_Image3D1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_IImage3D1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_UImage3D1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_Image2DArray1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_IImage2DArray1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_UImage2DArray1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_ImageCube1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_IImageCube1; +constexpr const TSymbolUniqueId BuiltInId::imageSize_UImageCube1; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_Image2D1_Int2; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImage2D1_Int2; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImage2D1_Int2; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_Image3D1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImage3D1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImage3D1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_Image2DArray1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImage2DArray1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImage2DArray1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_ImageCube1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_IImageCube1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageLoad_UImageCube1_Int3; +constexpr const TSymbolUniqueId BuiltInId::imageStore_Image2D1_Int2_Float4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_IImage2D1_Int2_Int4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_UImage2D1_Int2_UInt4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_Image3D1_Int3_Float4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_IImage3D1_Int3_Int4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_UImage3D1_Int3_UInt4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_Image2DArray1_Int3_Float4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_IImage2DArray1_Int3_Int4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_UImage2DArray1_Int3_UInt4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_ImageCube1_Int3_Float4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_IImageCube1_Int3_Int4; +constexpr const TSymbolUniqueId BuiltInId::imageStore_UImageCube1_Int3_UInt4; +constexpr const TSymbolUniqueId BuiltInId::memoryBarrier; +constexpr const TSymbolUniqueId BuiltInId::memoryBarrierAtomicCounter; +constexpr const TSymbolUniqueId BuiltInId::memoryBarrierBuffer; +constexpr const TSymbolUniqueId BuiltInId::memoryBarrierImage; +constexpr const TSymbolUniqueId BuiltInId::barrier; +constexpr const TSymbolUniqueId BuiltInId::memoryBarrierShared; +constexpr const TSymbolUniqueId BuiltInId::groupMemoryBarrier; +constexpr const TSymbolUniqueId BuiltInId::EmitVertex; +constexpr const TSymbolUniqueId BuiltInId::EndPrimitive; +constexpr const TSymbolUniqueId BuiltInId::gl_DepthRangeParameters; +constexpr const TSymbolUniqueId BuiltInId::gl_DepthRange; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexAttribs; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexUniformVectors; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexTextureImageUnits; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedTextureImageUnits; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxTextureImageUnits; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentUniformVectors; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVaryingVectors; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxDrawBuffers; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxDualSourceDrawBuffersEXT; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexOutputVectors; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentInputVectors; +constexpr const TSymbolUniqueId BuiltInId::gl_MinProgramTexelOffset; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxProgramTexelOffset; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxImageUnits; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexImageUniforms; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentImageUniforms; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeImageUniforms; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedImageUniforms; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedShaderOutputResources; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeWorkGroupCount; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeWorkGroupSize; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeUniformComponents; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeTextureImageUnits; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeAtomicCounters; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxComputeAtomicCounterBuffers; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexAtomicCounters; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentAtomicCounters; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedAtomicCounters; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxAtomicCounterBindings; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxVertexAtomicCounterBuffers; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxFragmentAtomicCounterBuffers; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxCombinedAtomicCounterBuffers; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxAtomicCounterBufferSize; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryInputComponents; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryOutputComponents; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryImageUniforms; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryTextureImageUnits; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryOutputVertices; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryTotalOutputComponents; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryUniformComponents; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryAtomicCounters; +constexpr const TSymbolUniqueId BuiltInId::gl_MaxGeometryAtomicCounterBuffers; +constexpr const TSymbolUniqueId BuiltInId::gl_FragCoord; +constexpr const TSymbolUniqueId BuiltInId::gl_FrontFacing; +constexpr const TSymbolUniqueId BuiltInId::gl_PointCoord; +constexpr const TSymbolUniqueId BuiltInId::gl_FragColor; +constexpr const TSymbolUniqueId BuiltInId::gl_FragData; +constexpr const TSymbolUniqueId BuiltInId::gl_FragDepth; +constexpr const TSymbolUniqueId BuiltInId::gl_SecondaryFragColorEXT; +constexpr const TSymbolUniqueId BuiltInId::gl_SecondaryFragDataEXT; +constexpr const TSymbolUniqueId BuiltInId::gl_FragDepthEXT; +constexpr const TSymbolUniqueId BuiltInId::gl_LastFragData; +constexpr const TSymbolUniqueId BuiltInId::gl_LastFragColor; +constexpr const TSymbolUniqueId BuiltInId::gl_LastFragDataNV; +constexpr const TSymbolUniqueId BuiltInId::gl_LastFragColorARM; +constexpr const TSymbolUniqueId BuiltInId::gl_PrimitiveID; +constexpr const TSymbolUniqueId BuiltInId::gl_Layer; +constexpr const TSymbolUniqueId BuiltInId::gl_Position; +constexpr const TSymbolUniqueId BuiltInId::gl_PointSize; +constexpr const TSymbolUniqueId BuiltInId::gl_InstanceID; +constexpr const TSymbolUniqueId BuiltInId::gl_VertexID; +constexpr const TSymbolUniqueId BuiltInId::gl_ViewportIndex; +constexpr const TSymbolUniqueId BuiltInId::gl_LayerVS; +constexpr const TSymbolUniqueId BuiltInId::gl_DrawID; +constexpr const TSymbolUniqueId BuiltInId::gl_DrawIDESSL1; +constexpr const TSymbolUniqueId BuiltInId::gl_BaseVertex; +constexpr const TSymbolUniqueId BuiltInId::gl_BaseInstance; +constexpr const TSymbolUniqueId BuiltInId::gl_NumWorkGroups; +constexpr const TSymbolUniqueId BuiltInId::gl_WorkGroupSize; +constexpr const TSymbolUniqueId BuiltInId::gl_WorkGroupID; +constexpr const TSymbolUniqueId BuiltInId::gl_LocalInvocationID; +constexpr const TSymbolUniqueId BuiltInId::gl_GlobalInvocationID; +constexpr const TSymbolUniqueId BuiltInId::gl_LocalInvocationIndex; +constexpr const TSymbolUniqueId BuiltInId::gl_PrimitiveIDIn; +constexpr const TSymbolUniqueId BuiltInId::gl_InvocationID; +constexpr const TSymbolUniqueId BuiltInId::gl_PrimitiveIDGS; +constexpr const TSymbolUniqueId BuiltInId::gl_LayerGS; +constexpr const TSymbolUniqueId BuiltInId::gl_PerVertex; +constexpr const TSymbolUniqueId BuiltInId::gl_in; +constexpr const TSymbolUniqueId BuiltInId::gl_PerVertexOutBlock; +constexpr const TSymbolUniqueId BuiltInId::gl_PositionGS; +constexpr const TSymbolUniqueId BuiltInId::gl_ViewID_OVR; +constexpr const TSymbolUniqueId BuiltInId::gl_ViewID_OVRESSL1; + +const int TSymbolTable::kLastBuiltInId = 1033; + +namespace BuiltInName +{ + +constexpr const ImmutableString _empty(""); +constexpr const ImmutableString EmitVertex("EmitVertex"); +constexpr const ImmutableString EndPrimitive("EndPrimitive"); +constexpr const ImmutableString abs("abs"); +constexpr const ImmutableString acos("acos"); +constexpr const ImmutableString acosh("acosh"); +constexpr const ImmutableString all("all"); +constexpr const ImmutableString any("any"); +constexpr const ImmutableString asin("asin"); +constexpr const ImmutableString asinh("asinh"); +constexpr const ImmutableString atan("atan"); +constexpr const ImmutableString atanh("atanh"); +constexpr const ImmutableString atomicAdd("atomicAdd"); +constexpr const ImmutableString atomicAnd("atomicAnd"); +constexpr const ImmutableString atomicCompSwap("atomicCompSwap"); +constexpr const ImmutableString atomicCompSwap_0D0D0D("atomicCompSwap(0D0D0D"); +constexpr const ImmutableString atomicCounter("atomicCounter"); +constexpr const ImmutableString atomicCounterDecrement("atomicCounterDecrement"); +constexpr const ImmutableString atomicCounterIncrement("atomicCounterIncrement"); +constexpr const ImmutableString atomicExchange("atomicExchange"); +constexpr const ImmutableString atomicMax("atomicMax"); +constexpr const ImmutableString atomicMin("atomicMin"); +constexpr const ImmutableString atomicOr("atomicOr"); +constexpr const ImmutableString atomicXor("atomicXor"); +constexpr const ImmutableString barrier("barrier"); +constexpr const ImmutableString bitCount("bitCount"); +constexpr const ImmutableString bitfieldExtract("bitfieldExtract"); +constexpr const ImmutableString bitfieldExtract_0D0C0C("bitfieldExtract(0D0C0C"); +constexpr const ImmutableString bitfieldExtract_1C0C0C("bitfieldExtract(1C0C0C"); +constexpr const ImmutableString bitfieldExtract_3C0C0C("bitfieldExtract(3C0C0C"); +constexpr const ImmutableString bitfieldInsert("bitfieldInsert"); +constexpr const ImmutableString bitfieldInsert_0C0C0C0C("bitfieldInsert(0C0C0C0C"); +constexpr const ImmutableString bitfieldInsert_0D0D0C0C("bitfieldInsert(0D0D0C0C"); +constexpr const ImmutableString bitfieldInsert_1C1C0C0C("bitfieldInsert(1C1C0C0C"); +constexpr const ImmutableString bitfieldInsert_1D1D0C0C("bitfieldInsert(1D1D0C0C"); +constexpr const ImmutableString bitfieldInsert_2C2C0C0C("bitfieldInsert(2C2C0C0C"); +constexpr const ImmutableString bitfieldInsert_2D2D0C0C("bitfieldInsert(2D2D0C0C"); +constexpr const ImmutableString bitfieldInsert_3C3C0C0C("bitfieldInsert(3C3C0C0C"); +constexpr const ImmutableString bitfieldInsert_3D3D0C0C("bitfieldInsert(3D3D0C0C"); +constexpr const ImmutableString bitfieldReverse("bitfieldReverse"); +constexpr const ImmutableString ceil("ceil"); +constexpr const ImmutableString clamp("clamp"); +constexpr const ImmutableString clamp_0D0D0D("clamp(0D0D0D"); +constexpr const ImmutableString clamp_1B0B0B("clamp(1B0B0B"); +constexpr const ImmutableString clamp_1B1B1B("clamp(1B1B1B"); +constexpr const ImmutableString clamp_1C0C0C("clamp(1C0C0C"); +constexpr const ImmutableString clamp_1C1C1C("clamp(1C1C1C"); +constexpr const ImmutableString clamp_1D1D1D("clamp(1D1D1D"); +constexpr const ImmutableString clamp_2C2C2C("clamp(2C2C2C"); +constexpr const ImmutableString clamp_3B0B0B("clamp(3B0B0B"); +constexpr const ImmutableString clamp_3C0C0C("clamp(3C0C0C"); +constexpr const ImmutableString clamp_3D0D0D("clamp(3D0D0D"); +constexpr const ImmutableString cos("cos"); +constexpr const ImmutableString cosh("cosh"); +constexpr const ImmutableString cross("cross"); +constexpr const ImmutableString dFdx("dFdx"); +constexpr const ImmutableString dFdxExt("dFdx"); +constexpr const ImmutableString dFdy("dFdy"); +constexpr const ImmutableString dFdyExt("dFdy"); +constexpr const ImmutableString degrees("degrees"); +constexpr const ImmutableString determinant("determinant"); +constexpr const ImmutableString diff("diff"); +constexpr const ImmutableString distance("distance"); +constexpr const ImmutableString dot("dot"); +constexpr const ImmutableString equal("equal"); +constexpr const ImmutableString exp("exp"); +constexpr const ImmutableString exp2("exp2"); +constexpr const ImmutableString faceforward("faceforward"); +constexpr const ImmutableString faceforward_1B1B1B("faceforward(1B1B1B"); +constexpr const ImmutableString faceforward_2B2B2B("faceforward(2B2B2B"); +constexpr const ImmutableString faceforward_3B3B3B("faceforward(3B3B3B"); +constexpr const ImmutableString far("far"); +constexpr const ImmutableString findLSB("findLSB"); +constexpr const ImmutableString findMSB("findMSB"); +constexpr const ImmutableString floatBitsToInt("floatBitsToInt"); +constexpr const ImmutableString floatBitsToUint("floatBitsToUint"); +constexpr const ImmutableString floor("floor"); +constexpr const ImmutableString fract("fract"); +constexpr const ImmutableString frexp("frexp"); +constexpr const ImmutableString frexp_3B3C("frexp(3B3C"); +constexpr const ImmutableString fwidth("fwidth"); +constexpr const ImmutableString fwidthExt("fwidth"); +constexpr const ImmutableString gl_BaseInstance("gl_BaseInstance"); +constexpr const ImmutableString gl_BaseVertex("gl_BaseVertex"); +constexpr const ImmutableString gl_DepthRange("gl_DepthRange"); +constexpr const ImmutableString gl_DepthRangeParameters("gl_DepthRangeParameters"); +constexpr const ImmutableString gl_DrawID("gl_DrawID"); +constexpr const ImmutableString gl_FragColor("gl_FragColor"); +constexpr const ImmutableString gl_FragCoord("gl_FragCoord"); +constexpr const ImmutableString gl_FragData("gl_FragData"); +constexpr const ImmutableString gl_FragDepth("gl_FragDepth"); +constexpr const ImmutableString gl_FragDepthEXT("gl_FragDepthEXT"); +constexpr const ImmutableString gl_FrontFacing("gl_FrontFacing"); +constexpr const ImmutableString gl_GlobalInvocationID("gl_GlobalInvocationID"); +constexpr const ImmutableString gl_InstanceID("gl_InstanceID"); +constexpr const ImmutableString gl_InvocationID("gl_InvocationID"); +constexpr const ImmutableString gl_LastFragColor("gl_LastFragColor"); +constexpr const ImmutableString gl_LastFragColorARM("gl_LastFragColorARM"); +constexpr const ImmutableString gl_LastFragData("gl_LastFragData"); +constexpr const ImmutableString gl_Layer("gl_Layer"); +constexpr const ImmutableString gl_LocalInvocationID("gl_LocalInvocationID"); +constexpr const ImmutableString gl_LocalInvocationIndex("gl_LocalInvocationIndex"); +constexpr const ImmutableString gl_MaxAtomicCounterBindings("gl_MaxAtomicCounterBindings"); +constexpr const ImmutableString gl_MaxAtomicCounterBufferSize("gl_MaxAtomicCounterBufferSize"); +constexpr const ImmutableString gl_MaxCombinedAtomicCounterBuffers( + "gl_MaxCombinedAtomicCounterBuffers"); +constexpr const ImmutableString gl_MaxCombinedAtomicCounters("gl_MaxCombinedAtomicCounters"); +constexpr const ImmutableString gl_MaxCombinedImageUniforms("gl_MaxCombinedImageUniforms"); +constexpr const ImmutableString gl_MaxCombinedShaderOutputResources( + "gl_MaxCombinedShaderOutputResources"); +constexpr const ImmutableString gl_MaxCombinedTextureImageUnits("gl_MaxCombinedTextureImageUnits"); +constexpr const ImmutableString gl_MaxComputeAtomicCounterBuffers( + "gl_MaxComputeAtomicCounterBuffers"); +constexpr const ImmutableString gl_MaxComputeAtomicCounters("gl_MaxComputeAtomicCounters"); +constexpr const ImmutableString gl_MaxComputeImageUniforms("gl_MaxComputeImageUniforms"); +constexpr const ImmutableString gl_MaxComputeTextureImageUnits("gl_MaxComputeTextureImageUnits"); +constexpr const ImmutableString gl_MaxComputeUniformComponents("gl_MaxComputeUniformComponents"); +constexpr const ImmutableString gl_MaxComputeWorkGroupCount("gl_MaxComputeWorkGroupCount"); +constexpr const ImmutableString gl_MaxComputeWorkGroupSize("gl_MaxComputeWorkGroupSize"); +constexpr const ImmutableString gl_MaxDrawBuffers("gl_MaxDrawBuffers"); +constexpr const ImmutableString gl_MaxDualSourceDrawBuffersEXT("gl_MaxDualSourceDrawBuffersEXT"); +constexpr const ImmutableString gl_MaxFragmentAtomicCounterBuffers( + "gl_MaxFragmentAtomicCounterBuffers"); +constexpr const ImmutableString gl_MaxFragmentAtomicCounters("gl_MaxFragmentAtomicCounters"); +constexpr const ImmutableString gl_MaxFragmentImageUniforms("gl_MaxFragmentImageUniforms"); +constexpr const ImmutableString gl_MaxFragmentInputVectors("gl_MaxFragmentInputVectors"); +constexpr const ImmutableString gl_MaxFragmentUniformVectors("gl_MaxFragmentUniformVectors"); +constexpr const ImmutableString gl_MaxGeometryAtomicCounterBuffers( + "gl_MaxGeometryAtomicCounterBuffers"); +constexpr const ImmutableString gl_MaxGeometryAtomicCounters("gl_MaxGeometryAtomicCounters"); +constexpr const ImmutableString gl_MaxGeometryImageUniforms("gl_MaxGeometryImageUniforms"); +constexpr const ImmutableString gl_MaxGeometryInputComponents("gl_MaxGeometryInputComponents"); +constexpr const ImmutableString gl_MaxGeometryOutputComponents("gl_MaxGeometryOutputComponents"); +constexpr const ImmutableString gl_MaxGeometryOutputVertices("gl_MaxGeometryOutputVertices"); +constexpr const ImmutableString gl_MaxGeometryTextureImageUnits("gl_MaxGeometryTextureImageUnits"); +constexpr const ImmutableString gl_MaxGeometryTotalOutputComponents( + "gl_MaxGeometryTotalOutputComponents"); +constexpr const ImmutableString gl_MaxGeometryUniformComponents("gl_MaxGeometryUniformComponents"); +constexpr const ImmutableString gl_MaxImageUnits("gl_MaxImageUnits"); +constexpr const ImmutableString gl_MaxProgramTexelOffset("gl_MaxProgramTexelOffset"); +constexpr const ImmutableString gl_MaxTextureImageUnits("gl_MaxTextureImageUnits"); +constexpr const ImmutableString gl_MaxVaryingVectors("gl_MaxVaryingVectors"); +constexpr const ImmutableString gl_MaxVertexAtomicCounterBuffers( + "gl_MaxVertexAtomicCounterBuffers"); +constexpr const ImmutableString gl_MaxVertexAtomicCounters("gl_MaxVertexAtomicCounters"); +constexpr const ImmutableString gl_MaxVertexAttribs("gl_MaxVertexAttribs"); +constexpr const ImmutableString gl_MaxVertexImageUniforms("gl_MaxVertexImageUniforms"); +constexpr const ImmutableString gl_MaxVertexOutputVectors("gl_MaxVertexOutputVectors"); +constexpr const ImmutableString gl_MaxVertexTextureImageUnits("gl_MaxVertexTextureImageUnits"); +constexpr const ImmutableString gl_MaxVertexUniformVectors("gl_MaxVertexUniformVectors"); +constexpr const ImmutableString gl_MinProgramTexelOffset("gl_MinProgramTexelOffset"); +constexpr const ImmutableString gl_NumWorkGroups("gl_NumWorkGroups"); +constexpr const ImmutableString gl_PerVertex("gl_PerVertex"); +constexpr const ImmutableString gl_PointCoord("gl_PointCoord"); +constexpr const ImmutableString gl_PointSize("gl_PointSize"); +constexpr const ImmutableString gl_Position("gl_Position"); +constexpr const ImmutableString gl_PrimitiveID("gl_PrimitiveID"); +constexpr const ImmutableString gl_PrimitiveIDIn("gl_PrimitiveIDIn"); +constexpr const ImmutableString gl_SecondaryFragColorEXT("gl_SecondaryFragColorEXT"); +constexpr const ImmutableString gl_SecondaryFragDataEXT("gl_SecondaryFragDataEXT"); +constexpr const ImmutableString gl_VertexID("gl_VertexID"); +constexpr const ImmutableString gl_ViewID_OVR("gl_ViewID_OVR"); +constexpr const ImmutableString gl_ViewportIndex("gl_ViewportIndex"); +constexpr const ImmutableString gl_WorkGroupID("gl_WorkGroupID"); +constexpr const ImmutableString gl_WorkGroupSize("gl_WorkGroupSize"); +constexpr const ImmutableString gl_in("gl_in"); +constexpr const ImmutableString greaterThan("greaterThan"); +constexpr const ImmutableString greaterThanEqual("greaterThanEqual"); +constexpr const ImmutableString groupMemoryBarrier("groupMemoryBarrier"); +constexpr const ImmutableString imageLoad("imageLoad"); +constexpr const ImmutableString imageSize("imageSize"); +constexpr const ImmutableString imageStore("imageStore"); +constexpr const ImmutableString imageStore_0h1C3D("imageStore(0h1C3D"); +constexpr const ImmutableString imageStore_0j2C3C("imageStore(0j2C3C"); +constexpr const ImmutableString imageStore_0l2C3B("imageStore(0l2C3B"); +constexpr const ImmutableString imageStore_0n2C3D("imageStore(0n2C3D"); +constexpr const ImmutableString imageStore_0p2C3C("imageStore(0p2C3C"); +constexpr const ImmutableString imulExtended("imulExtended"); +constexpr const ImmutableString imulExtended_0C0C0C0C("imulExtended(0C0C0C0C"); +constexpr const ImmutableString imulExtended_1C1C1C1C("imulExtended(1C1C1C1C"); +constexpr const ImmutableString imulExtended_2C2C2C2C("imulExtended(2C2C2C2C"); +constexpr const ImmutableString imulExtended_3C3C3C3C("imulExtended(3C3C3C3C"); +constexpr const ImmutableString intBitsToFloat("intBitsToFloat"); +constexpr const ImmutableString inverse("inverse"); +constexpr const ImmutableString inversesqrt("inversesqrt"); +constexpr const ImmutableString isinf("isinf"); +constexpr const ImmutableString isnan("isnan"); +constexpr const ImmutableString ldexp("ldexp"); +constexpr const ImmutableString length("length"); +constexpr const ImmutableString lessThan("lessThan"); +constexpr const ImmutableString lessThanEqual("lessThanEqual"); +constexpr const ImmutableString log("log"); +constexpr const ImmutableString log2("log2"); +constexpr const ImmutableString matrixCompMult("matrixCompMult"); +constexpr const ImmutableString max("max"); +constexpr const ImmutableString memoryBarrier("memoryBarrier"); +constexpr const ImmutableString memoryBarrierAtomicCounter("memoryBarrierAtomicCounter"); +constexpr const ImmutableString memoryBarrierBuffer("memoryBarrierBuffer"); +constexpr const ImmutableString memoryBarrierImage("memoryBarrierImage"); +constexpr const ImmutableString memoryBarrierShared("memoryBarrierShared"); +constexpr const ImmutableString min("min"); +constexpr const ImmutableString mix("mix"); +constexpr const ImmutableString mix_0B0B0E("mix(0B0B0E"); +constexpr const ImmutableString mix_1B1B1B("mix(1B1B1B"); +constexpr const ImmutableString mix_1B1B1E("mix(1B1B1E"); +constexpr const ImmutableString mix_3B3B0B("mix(3B3B0B"); +constexpr const ImmutableString mix_3B3B3B("mix(3B3B3B"); +constexpr const ImmutableString mod("mod"); +constexpr const ImmutableString modf("modf"); +constexpr const ImmutableString near("near"); +constexpr const ImmutableString normalize("normalize"); +constexpr const ImmutableString notEqual("notEqual"); +constexpr const ImmutableString notFunc("not"); +constexpr const ImmutableString outerProduct("outerProduct"); +constexpr const ImmutableString packHalf2x16("packHalf2x16"); +constexpr const ImmutableString packSnorm2x16("packSnorm2x16"); +constexpr const ImmutableString packSnorm4x8("packSnorm4x8"); +constexpr const ImmutableString packUnorm2x16("packUnorm2x16"); +constexpr const ImmutableString packUnorm4x8("packUnorm4x8"); +constexpr const ImmutableString pow("pow"); +constexpr const ImmutableString radians("radians"); +constexpr const ImmutableString reflect("reflect"); +constexpr const ImmutableString refract("refract"); +constexpr const ImmutableString refract_3B3B0B("refract(3B3B0B"); +constexpr const ImmutableString rgb_2_yuv("rgb_2_yuv"); +constexpr const ImmutableString round("round"); +constexpr const ImmutableString roundEven("roundEven"); +constexpr const ImmutableString sign("sign"); +constexpr const ImmutableString sin("sin"); +constexpr const ImmutableString sinh("sinh"); +constexpr const ImmutableString smoothstep("smoothstep"); +constexpr const ImmutableString smoothstep_0B0B3B("smoothstep(0B0B3B"); +constexpr const ImmutableString smoothstep_1B1B1B("smoothstep(1B1B1B"); +constexpr const ImmutableString smoothstep_3B3B3B("smoothstep(3B3B3B"); +constexpr const ImmutableString sqrt("sqrt"); +constexpr const ImmutableString step("step"); +constexpr const ImmutableString tan("tan"); +constexpr const ImmutableString tanh("tanh"); +constexpr const ImmutableString texelFetch("texelFetch"); +constexpr const ImmutableString texelFetchExt("texelFetch"); +constexpr const ImmutableString texelFetchExt_0O1C0C("texelFetch(0O1C0C"); +constexpr const ImmutableString texelFetchOffset("texelFetchOffset"); +constexpr const ImmutableString texelFetchOffset_0H1C0C1C("texelFetchOffset(0H1C0C1C"); +constexpr const ImmutableString texelFetchOffset_0I2C0C2C("texelFetchOffset(0I2C0C2C"); +constexpr const ImmutableString texelFetchOffset_0K2C0C1C("texelFetchOffset(0K2C0C1C"); +constexpr const ImmutableString texelFetchOffset_0Q1C0C1C("texelFetchOffset(0Q1C0C1C"); +constexpr const ImmutableString texelFetchOffset_0R2C0C2C("texelFetchOffset(0R2C0C2C"); +constexpr const ImmutableString texelFetchOffset_0T2C0C1C("texelFetchOffset(0T2C0C1C"); +constexpr const ImmutableString texelFetchOffset_0W1C0C1C("texelFetchOffset(0W1C0C1C"); +constexpr const ImmutableString texelFetchOffset_0X2C0C2C("texelFetchOffset(0X2C0C2C"); +constexpr const ImmutableString texelFetchOffset_0Z2C0C1C("texelFetchOffset(0Z2C0C1C"); +constexpr const ImmutableString texelFetch_0H1C0C("texelFetch(0H1C0C"); +constexpr const ImmutableString texelFetch_0I2C0C("texelFetch(0I2C0C"); +constexpr const ImmutableString texelFetch_0K2C0C("texelFetch(0K2C0C"); +constexpr const ImmutableString texelFetch_0L1C0C("texelFetch(0L1C0C"); +constexpr const ImmutableString texelFetch_0O1C0C("texelFetch(0O1C0C"); +constexpr const ImmutableString texelFetch_0P2C0C("texelFetch(0P2C0C"); +constexpr const ImmutableString texelFetch_0Q1C0C("texelFetch(0Q1C0C"); +constexpr const ImmutableString texelFetch_0T2C0C("texelFetch(0T2C0C"); +constexpr const ImmutableString texelFetch_0V2C0C("texelFetch(0V2C0C"); +constexpr const ImmutableString texelFetch_0X2C0C("texelFetch(0X2C0C"); +constexpr const ImmutableString texelFetch_0Z2C0C("texelFetch(0Z2C0C"); +constexpr const ImmutableString texture("texture"); +constexpr const ImmutableString texture2D("texture2D"); +constexpr const ImmutableString texture2DGradEXT("texture2DGradEXT"); +constexpr const ImmutableString texture2DGradEXT_0H1B1B1B("texture2DGradEXT(0H1B1B1B"); +constexpr const ImmutableString texture2DLod("texture2DLod"); +constexpr const ImmutableString texture2DLodEXT("texture2DLodEXT"); +constexpr const ImmutableString texture2DLodEXT_0H1B0B("texture2DLodEXT(0H1B0B"); +constexpr const ImmutableString texture2DLod_0H1B0B("texture2DLod(0H1B0B"); +constexpr const ImmutableString texture2DProj("texture2DProj"); +constexpr const ImmutableString texture2DProjGradEXT("texture2DProjGradEXT"); +constexpr const ImmutableString texture2DProjGradEXT_0H2B1B1B("texture2DProjGradEXT(0H2B1B1B"); +constexpr const ImmutableString texture2DProjGradEXT_0H3B1B1B("texture2DProjGradEXT(0H3B1B1B"); +constexpr const ImmutableString texture2DProjLod("texture2DProjLod"); +constexpr const ImmutableString texture2DProjLodEXT("texture2DProjLodEXT"); +constexpr const ImmutableString texture2DProjLodEXT_0H2B0B("texture2DProjLodEXT(0H2B0B"); +constexpr const ImmutableString texture2DProjLod_0H2B0B("texture2DProjLod(0H2B0B"); +constexpr const ImmutableString texture2DProj_0H2B0B("texture2DProj(0H2B0B"); +constexpr const ImmutableString texture2DRect("texture2DRect"); +constexpr const ImmutableString texture2DRectProj("texture2DRectProj"); +constexpr const ImmutableString texture3D("texture3D"); +constexpr const ImmutableString texture3DLod("texture3DLod"); +constexpr const ImmutableString texture3DProj("texture3DProj"); +constexpr const ImmutableString texture3DProjLod("texture3DProjLod"); +constexpr const ImmutableString texture3DProj_0I3B0B("texture3DProj(0I3B0B"); +constexpr const ImmutableString texture3D_0I2B0B("texture3D(0I2B0B"); +constexpr const ImmutableString textureCube("textureCube"); +constexpr const ImmutableString textureCubeGradEXT("textureCubeGradEXT"); +constexpr const ImmutableString textureCubeGradEXT_0J2B2B2B("textureCubeGradEXT(0J2B2B2B"); +constexpr const ImmutableString textureCubeLod("textureCubeLod"); +constexpr const ImmutableString textureCubeLodEXT("textureCubeLodEXT"); +constexpr const ImmutableString textureGather("textureGather"); +constexpr const ImmutableString textureGatherOffset("textureGatherOffset"); +constexpr const ImmutableString textureGatherOffset_0H1B1C0C("textureGatherOffset(0H1B1C0C"); +constexpr const ImmutableString textureGatherOffset_0K2B1C0C("textureGatherOffset(0K2B1C0C"); +constexpr const ImmutableString textureGatherOffset_0Q1B1C0C("textureGatherOffset(0Q1B1C0C"); +constexpr const ImmutableString textureGatherOffset_0T2B1C("textureGatherOffset(0T2B1C"); +constexpr const ImmutableString textureGatherOffset_0T2B1C0C("textureGatherOffset(0T2B1C0C"); +constexpr const ImmutableString textureGatherOffset_0W1B1C("textureGatherOffset(0W1B1C"); +constexpr const ImmutableString textureGatherOffset_0W1B1C0C("textureGatherOffset(0W1B1C0C"); +constexpr const ImmutableString textureGatherOffset_0Z2B1C0C("textureGatherOffset(0Z2B1C0C"); +constexpr const ImmutableString textureGatherOffset_0c1B0B1C("textureGatherOffset(0c1B0B1C"); +constexpr const ImmutableString textureGatherOffset_0e2B0B1C("textureGatherOffset(0e2B0B1C"); +constexpr const ImmutableString textureGather_0J2B0C("textureGather(0J2B0C"); +constexpr const ImmutableString textureGather_0S2B0C("textureGather(0S2B0C"); +constexpr const ImmutableString textureGather_0T2B0C("textureGather(0T2B0C"); +constexpr const ImmutableString textureGather_0Z2B0C("textureGather(0Z2B0C"); +constexpr const ImmutableString textureGrad("textureGrad"); +constexpr const ImmutableString textureGradOffset("textureGradOffset"); +constexpr const ImmutableString textureGradOffset_0H1B1B1B1C("textureGradOffset(0H1B1B1B1C"); +constexpr const ImmutableString textureGradOffset_0I2B2B2B2C("textureGradOffset(0I2B2B2B2C"); +constexpr const ImmutableString textureGradOffset_0K2B1B1B1C("textureGradOffset(0K2B1B1B1C"); +constexpr const ImmutableString textureGradOffset_0Q1B1B1B1C("textureGradOffset(0Q1B1B1B1C"); +constexpr const ImmutableString textureGradOffset_0R2B2B2B2C("textureGradOffset(0R2B2B2B2C"); +constexpr const ImmutableString textureGradOffset_0T2B1B1B1C("textureGradOffset(0T2B1B1B1C"); +constexpr const ImmutableString textureGradOffset_0W1B1B1B1C("textureGradOffset(0W1B1B1B1C"); +constexpr const ImmutableString textureGradOffset_0X2B2B2B2C("textureGradOffset(0X2B2B2B2C"); +constexpr const ImmutableString textureGradOffset_0Z2B1B1B1C("textureGradOffset(0Z2B1B1B1C"); +constexpr const ImmutableString textureGradOffset_0c2B1B1B1C("textureGradOffset(0c2B1B1B1C"); +constexpr const ImmutableString textureGradOffset_0e3B1B1B1C("textureGradOffset(0e3B1B1B1C"); +constexpr const ImmutableString textureGrad_0H1B1B1B("textureGrad(0H1B1B1B"); +constexpr const ImmutableString textureGrad_0I2B2B2B("textureGrad(0I2B2B2B"); +constexpr const ImmutableString textureGrad_0J2B2B2B("textureGrad(0J2B2B2B"); +constexpr const ImmutableString textureGrad_0K2B1B1B("textureGrad(0K2B1B1B"); +constexpr const ImmutableString textureGrad_0Q1B1B1B("textureGrad(0Q1B1B1B"); +constexpr const ImmutableString textureGrad_0R2B2B2B("textureGrad(0R2B2B2B"); +constexpr const ImmutableString textureGrad_0S2B2B2B("textureGrad(0S2B2B2B"); +constexpr const ImmutableString textureGrad_0T2B1B1B("textureGrad(0T2B1B1B"); +constexpr const ImmutableString textureGrad_0W1B1B1B("textureGrad(0W1B1B1B"); +constexpr const ImmutableString textureGrad_0X2B2B2B("textureGrad(0X2B2B2B"); +constexpr const ImmutableString textureGrad_0Y2B2B2B("textureGrad(0Y2B2B2B"); +constexpr const ImmutableString textureGrad_0Z2B1B1B("textureGrad(0Z2B1B1B"); +constexpr const ImmutableString textureGrad_0c2B1B1B("textureGrad(0c2B1B1B"); +constexpr const ImmutableString textureGrad_0d3B2B2B("textureGrad(0d3B2B2B"); +constexpr const ImmutableString textureGrad_0e3B1B1B("textureGrad(0e3B1B1B"); +constexpr const ImmutableString textureLod("textureLod"); +constexpr const ImmutableString textureLodOffset("textureLodOffset"); +constexpr const ImmutableString textureLodOffset_0H1B0B1C("textureLodOffset(0H1B0B1C"); +constexpr const ImmutableString textureLodOffset_0I2B0B2C("textureLodOffset(0I2B0B2C"); +constexpr const ImmutableString textureLodOffset_0K2B0B1C("textureLodOffset(0K2B0B1C"); +constexpr const ImmutableString textureLodOffset_0Q1B0B1C("textureLodOffset(0Q1B0B1C"); +constexpr const ImmutableString textureLodOffset_0R2B0B2C("textureLodOffset(0R2B0B2C"); +constexpr const ImmutableString textureLodOffset_0T2B0B1C("textureLodOffset(0T2B0B1C"); +constexpr const ImmutableString textureLodOffset_0W1B0B1C("textureLodOffset(0W1B0B1C"); +constexpr const ImmutableString textureLodOffset_0X2B0B2C("textureLodOffset(0X2B0B2C"); +constexpr const ImmutableString textureLodOffset_0Z2B0B1C("textureLodOffset(0Z2B0B1C"); +constexpr const ImmutableString textureLodOffset_0c2B0B1C("textureLodOffset(0c2B0B1C"); +constexpr const ImmutableString textureLod_0J2B0B("textureLod(0J2B0B"); +constexpr const ImmutableString textureLod_0Q1B0B("textureLod(0Q1B0B"); +constexpr const ImmutableString textureLod_0S2B0B("textureLod(0S2B0B"); +constexpr const ImmutableString textureLod_0W1B0B("textureLod(0W1B0B"); +constexpr const ImmutableString textureLod_0Y2B0B("textureLod(0Y2B0B"); +constexpr const ImmutableString textureLod_0Z2B0B("textureLod(0Z2B0B"); +constexpr const ImmutableString textureOffset("textureOffset"); +constexpr const ImmutableString textureOffset_0H1B1C0B("textureOffset(0H1B1C0B"); +constexpr const ImmutableString textureOffset_0I2B2C0B("textureOffset(0I2B2C0B"); +constexpr const ImmutableString textureOffset_0K2B1C0B("textureOffset(0K2B1C0B"); +constexpr const ImmutableString textureOffset_0Q1B1C0B("textureOffset(0Q1B1C0B"); +constexpr const ImmutableString textureOffset_0R2B2C0B("textureOffset(0R2B2C0B"); +constexpr const ImmutableString textureOffset_0T2B1C0B("textureOffset(0T2B1C0B"); +constexpr const ImmutableString textureOffset_0W1B1C0B("textureOffset(0W1B1C0B"); +constexpr const ImmutableString textureOffset_0X2B2C("textureOffset(0X2B2C"); +constexpr const ImmutableString textureOffset_0X2B2C0B("textureOffset(0X2B2C0B"); +constexpr const ImmutableString textureOffset_0Z2B1C0B("textureOffset(0Z2B1C0B"); +constexpr const ImmutableString textureOffset_0c2B1C0B("textureOffset(0c2B1C0B"); +constexpr const ImmutableString textureProj("textureProj"); +constexpr const ImmutableString textureProjGrad("textureProjGrad"); +constexpr const ImmutableString textureProjGradOffset("textureProjGradOffset"); +constexpr const ImmutableString textureProjGradOffset_0H2B1B1B1C( + "textureProjGradOffset(0H2B1B1B1C"); +constexpr const ImmutableString textureProjGradOffset_0H3B1B1B1C( + "textureProjGradOffset(0H3B1B1B1C"); +constexpr const ImmutableString textureProjGradOffset_0I3B2B2B2C( + "textureProjGradOffset(0I3B2B2B2C"); +constexpr const ImmutableString textureProjGradOffset_0Q2B1B1B1C( + "textureProjGradOffset(0Q2B1B1B1C"); +constexpr const ImmutableString textureProjGradOffset_0Q3B1B1B1C( + "textureProjGradOffset(0Q3B1B1B1C"); +constexpr const ImmutableString textureProjGradOffset_0R3B2B2B2C( + "textureProjGradOffset(0R3B2B2B2C"); +constexpr const ImmutableString textureProjGradOffset_0W2B1B1B1C( + "textureProjGradOffset(0W2B1B1B1C"); +constexpr const ImmutableString textureProjGradOffset_0W3B1B1B1C( + "textureProjGradOffset(0W3B1B1B1C"); +constexpr const ImmutableString textureProjGradOffset_0X3B2B2B2C( + "textureProjGradOffset(0X3B2B2B2C"); +constexpr const ImmutableString textureProjGradOffset_0c3B1B1B1C( + "textureProjGradOffset(0c3B1B1B1C"); +constexpr const ImmutableString textureProjGrad_0H2B1B1B("textureProjGrad(0H2B1B1B"); +constexpr const ImmutableString textureProjGrad_0H3B1B1B("textureProjGrad(0H3B1B1B"); +constexpr const ImmutableString textureProjGrad_0I3B2B2B("textureProjGrad(0I3B2B2B"); +constexpr const ImmutableString textureProjGrad_0Q2B1B1B("textureProjGrad(0Q2B1B1B"); +constexpr const ImmutableString textureProjGrad_0Q3B1B1B("textureProjGrad(0Q3B1B1B"); +constexpr const ImmutableString textureProjGrad_0R3B2B2B("textureProjGrad(0R3B2B2B"); +constexpr const ImmutableString textureProjGrad_0W2B1B1B("textureProjGrad(0W2B1B1B"); +constexpr const ImmutableString textureProjGrad_0W3B1B1B("textureProjGrad(0W3B1B1B"); +constexpr const ImmutableString textureProjGrad_0X3B2B2B("textureProjGrad(0X3B2B2B"); +constexpr const ImmutableString textureProjGrad_0c3B1B1B("textureProjGrad(0c3B1B1B"); +constexpr const ImmutableString textureProjLod("textureProjLod"); +constexpr const ImmutableString textureProjLodOffset("textureProjLodOffset"); +constexpr const ImmutableString textureProjLodOffset_0H2B0B1C("textureProjLodOffset(0H2B0B1C"); +constexpr const ImmutableString textureProjLodOffset_0H3B0B1C("textureProjLodOffset(0H3B0B1C"); +constexpr const ImmutableString textureProjLodOffset_0I3B0B2C("textureProjLodOffset(0I3B0B2C"); +constexpr const ImmutableString textureProjLodOffset_0Q2B0B1C("textureProjLodOffset(0Q2B0B1C"); +constexpr const ImmutableString textureProjLodOffset_0Q3B0B1C("textureProjLodOffset(0Q3B0B1C"); +constexpr const ImmutableString textureProjLodOffset_0R3B0B2C("textureProjLodOffset(0R3B0B2C"); +constexpr const ImmutableString textureProjLodOffset_0W2B0B1C("textureProjLodOffset(0W2B0B1C"); +constexpr const ImmutableString textureProjLodOffset_0W3B0B1C("textureProjLodOffset(0W3B0B1C"); +constexpr const ImmutableString textureProjLodOffset_0X3B0B2C("textureProjLodOffset(0X3B0B2C"); +constexpr const ImmutableString textureProjLodOffset_0c3B0B1C("textureProjLodOffset(0c3B0B1C"); +constexpr const ImmutableString textureProjLod_0H3B0B("textureProjLod(0H3B0B"); +constexpr const ImmutableString textureProjLod_0I3B0B("textureProjLod(0I3B0B"); +constexpr const ImmutableString textureProjLod_0Q2B0B("textureProjLod(0Q2B0B"); +constexpr const ImmutableString textureProjLod_0Q3B0B("textureProjLod(0Q3B0B"); +constexpr const ImmutableString textureProjOffset("textureProjOffset"); +constexpr const ImmutableString textureProjOffset_0H2B1C("textureProjOffset(0H2B1C"); +constexpr const ImmutableString textureProjOffset_0H2B1C0B("textureProjOffset(0H2B1C0B"); +constexpr const ImmutableString textureProjOffset_0H3B1C("textureProjOffset(0H3B1C"); +constexpr const ImmutableString textureProjOffset_0H3B1C0B("textureProjOffset(0H3B1C0B"); +constexpr const ImmutableString textureProjOffset_0I3B2C0B("textureProjOffset(0I3B2C0B"); +constexpr const ImmutableString textureProjOffset_0Q2B1C("textureProjOffset(0Q2B1C"); +constexpr const ImmutableString textureProjOffset_0Q2B1C0B("textureProjOffset(0Q2B1C0B"); +constexpr const ImmutableString textureProjOffset_0Q3B1C("textureProjOffset(0Q3B1C"); +constexpr const ImmutableString textureProjOffset_0Q3B1C0B("textureProjOffset(0Q3B1C0B"); +constexpr const ImmutableString textureProjOffset_0R3B2C0B("textureProjOffset(0R3B2C0B"); +constexpr const ImmutableString textureProjOffset_0W2B1C0B("textureProjOffset(0W2B1C0B"); +constexpr const ImmutableString textureProjOffset_0W3B1C("textureProjOffset(0W3B1C"); +constexpr const ImmutableString textureProjOffset_0W3B1C0B("textureProjOffset(0W3B1C0B"); +constexpr const ImmutableString textureProjOffset_0X3B2C("textureProjOffset(0X3B2C"); +constexpr const ImmutableString textureProjOffset_0X3B2C0B("textureProjOffset(0X3B2C0B"); +constexpr const ImmutableString textureProjOffset_0c3B1C0B("textureProjOffset(0c3B1C0B"); +constexpr const ImmutableString textureProj_0Q2B0B("textureProj(0Q2B0B"); +constexpr const ImmutableString textureProj_0R3B0B("textureProj(0R3B0B"); +constexpr const ImmutableString textureProj_0X3B0B("textureProj(0X3B0B"); +constexpr const ImmutableString textureSize("textureSize"); +constexpr const ImmutableString textureSizeExt("textureSize"); +constexpr const ImmutableString texture_0Q1B0B("texture(0Q1B0B"); +constexpr const ImmutableString texture_0c2B0B("texture(0c2B0B"); +constexpr const ImmutableString texture_0d3B0B("texture(0d3B0B"); +constexpr const ImmutableString transpose("transpose"); +constexpr const ImmutableString trunc("trunc"); +constexpr const ImmutableString uaddCarry("uaddCarry"); +constexpr const ImmutableString uaddCarry_2D2D2D("uaddCarry(2D2D2D"); +constexpr const ImmutableString uaddCarry_3D3D3D("uaddCarry(3D3D3D"); +constexpr const ImmutableString uintBitsToFloat("uintBitsToFloat"); +constexpr const ImmutableString umulExtended("umulExtended"); +constexpr const ImmutableString umulExtended_0D0D0D0D("umulExtended(0D0D0D0D"); +constexpr const ImmutableString umulExtended_1D1D1D1D("umulExtended(1D1D1D1D"); +constexpr const ImmutableString umulExtended_2D2D2D2D("umulExtended(2D2D2D2D"); +constexpr const ImmutableString umulExtended_3D3D3D3D("umulExtended(3D3D3D3D"); +constexpr const ImmutableString unpackHalf2x16("unpackHalf2x16"); +constexpr const ImmutableString unpackSnorm2x16("unpackSnorm2x16"); +constexpr const ImmutableString unpackSnorm4x8("unpackSnorm4x8"); +constexpr const ImmutableString unpackUnorm2x16("unpackUnorm2x16"); +constexpr const ImmutableString unpackUnorm4x8("unpackUnorm4x8"); +constexpr const ImmutableString usubBorrow("usubBorrow"); +constexpr const ImmutableString usubBorrow_0D0D0D("usubBorrow(0D0D0D"); +constexpr const ImmutableString usubBorrow_1D1D1D("usubBorrow(1D1D1D"); +constexpr const ImmutableString usubBorrow_3D3D3D("usubBorrow(3D3D3D"); +constexpr const ImmutableString yuv_2_rgb("yuv_2_rgb"); + +} // namespace BuiltInName + +// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend +// this from TVariable. Now symbol constructors taking an id have to be public even though they're +// not supposed to be accessible from outside of here. http://anglebug.com/2390 +namespace BuiltInVariable +{ + +constexpr const TVariable kVar_gl_BaseInstance( + BuiltInId::gl_BaseInstance, + BuiltInName::gl_BaseInstance, + SymbolType::BuiltIn, + TExtension::ANGLE_base_vertex_base_instance, + StaticType::Get<EbtInt, EbpHigh, EvqBaseInstance, 1, 1>()); +constexpr const TVariable kVar_gl_BaseVertex( + BuiltInId::gl_BaseVertex, + BuiltInName::gl_BaseVertex, + SymbolType::BuiltIn, + TExtension::ANGLE_base_vertex_base_instance, + StaticType::Get<EbtInt, EbpHigh, EvqBaseVertex, 1, 1>()); +constexpr const TVariable kVar_gl_DrawID(BuiltInId::gl_DrawID, + BuiltInName::gl_DrawID, + SymbolType::BuiltIn, + TExtension::ANGLE_multi_draw, + StaticType::Get<EbtInt, EbpHigh, EvqDrawID, 1, 1>()); +constexpr const TVariable kVar_gl_DrawIDESSL1(BuiltInId::gl_DrawIDESSL1, + BuiltInName::gl_DrawID, + SymbolType::BuiltIn, + TExtension::ANGLE_multi_draw, + StaticType::Get<EbtInt, EbpHigh, EvqDrawID, 1, 1>()); +constexpr const TVariable kVar_gl_FragColor( + BuiltInId::gl_FragColor, + BuiltInName::gl_FragColor, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpMedium, EvqFragColor, 4, 1>()); +constexpr const TVariable kVar_gl_FragCoord( + BuiltInId::gl_FragCoord, + BuiltInName::gl_FragCoord, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpMedium, EvqFragCoord, 4, 1>()); +constexpr const TVariable kVar_gl_FragDepth( + BuiltInId::gl_FragDepth, + BuiltInName::gl_FragDepth, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpHigh, EvqFragDepth, 1, 1>()); +constexpr const TVariable kVar_gl_FrontFacing( + BuiltInId::gl_FrontFacing, + BuiltInName::gl_FrontFacing, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtBool, EbpUndefined, EvqFrontFacing, 1, 1>()); +constexpr const TVariable kVar_gl_GlobalInvocationID( + BuiltInId::gl_GlobalInvocationID, + BuiltInName::gl_GlobalInvocationID, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobalInvocationID, 3, 1>()); +constexpr const TVariable kVar_gl_InstanceID( + BuiltInId::gl_InstanceID, + BuiltInName::gl_InstanceID, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpHigh, EvqInstanceID, 1, 1>()); +constexpr const TVariable kVar_gl_InvocationID( + BuiltInId::gl_InvocationID, + BuiltInName::gl_InvocationID, + SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpHigh, EvqInvocationID, 1, 1>()); +constexpr const TVariable kVar_gl_LastFragColor( + BuiltInId::gl_LastFragColor, + BuiltInName::gl_LastFragColor, + SymbolType::BuiltIn, + TExtension::NV_shader_framebuffer_fetch, + StaticType::Get<EbtFloat, EbpMedium, EvqLastFragColor, 4, 1>()); +constexpr const TVariable kVar_gl_LastFragColorARM( + BuiltInId::gl_LastFragColorARM, + BuiltInName::gl_LastFragColorARM, + SymbolType::BuiltIn, + TExtension::ARM_shader_framebuffer_fetch, + StaticType::Get<EbtFloat, EbpMedium, EvqLastFragColor, 4, 1>()); +constexpr const TVariable kVar_gl_Layer(BuiltInId::gl_Layer, + BuiltInName::gl_Layer, + SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpHigh, EvqLayer, 1, 1>()); +constexpr const TVariable kVar_gl_LayerGS(BuiltInId::gl_LayerGS, + BuiltInName::gl_Layer, + SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpHigh, EvqLayer, 1, 1>()); +constexpr const TVariable kVar_gl_LayerVS(BuiltInId::gl_LayerVS, + BuiltInName::gl_Layer, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpHigh, EvqLayer, 1, 1>()); +constexpr const TVariable kVar_gl_LocalInvocationID( + BuiltInId::gl_LocalInvocationID, + BuiltInName::gl_LocalInvocationID, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqLocalInvocationID, 3, 1>()); +constexpr const TVariable kVar_gl_LocalInvocationIndex( + BuiltInId::gl_LocalInvocationIndex, + BuiltInName::gl_LocalInvocationIndex, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqLocalInvocationIndex, 1, 1>()); +constexpr const TVariable kVar_gl_NumWorkGroups( + BuiltInId::gl_NumWorkGroups, + BuiltInName::gl_NumWorkGroups, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqNumWorkGroups, 3, 1>()); +constexpr const TVariable kVar_gl_PointCoord( + BuiltInId::gl_PointCoord, + BuiltInName::gl_PointCoord, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpMedium, EvqPointCoord, 2, 1>()); +constexpr const TVariable kVar_gl_PointSize( + BuiltInId::gl_PointSize, + BuiltInName::gl_PointSize, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpMedium, EvqPointSize, 1, 1>()); +constexpr const TVariable kVar_gl_Position(BuiltInId::gl_Position, + BuiltInName::gl_Position, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpHigh, EvqPosition, 4, 1>()); +constexpr const TVariable kVar_gl_PrimitiveID( + BuiltInId::gl_PrimitiveID, + BuiltInName::gl_PrimitiveID, + SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpHigh, EvqPrimitiveID, 1, 1>()); +constexpr const TVariable kVar_gl_PrimitiveIDGS( + BuiltInId::gl_PrimitiveIDGS, + BuiltInName::gl_PrimitiveID, + SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpHigh, EvqPrimitiveID, 1, 1>()); +constexpr const TVariable kVar_gl_PrimitiveIDIn( + BuiltInId::gl_PrimitiveIDIn, + BuiltInName::gl_PrimitiveIDIn, + SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpHigh, EvqPrimitiveIDIn, 1, 1>()); +constexpr const TVariable kVar_gl_SecondaryFragColorEXT( + BuiltInId::gl_SecondaryFragColorEXT, + BuiltInName::gl_SecondaryFragColorEXT, + SymbolType::BuiltIn, + TExtension::EXT_blend_func_extended, + StaticType::Get<EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4, 1>()); +constexpr const TVariable kVar_gl_VertexID(BuiltInId::gl_VertexID, + BuiltInName::gl_VertexID, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpHigh, EvqVertexID, 1, 1>()); +constexpr const TVariable kVar_gl_ViewID_OVR( + BuiltInId::gl_ViewID_OVR, + BuiltInName::gl_ViewID_OVR, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpHigh, EvqViewIDOVR, 1, 1>()); +constexpr const TVariable kVar_gl_ViewID_OVRESSL1( + BuiltInId::gl_ViewID_OVRESSL1, + BuiltInName::gl_ViewID_OVR, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpHigh, EvqViewIDOVR, 1, 1>()); +constexpr const TVariable kVar_gl_ViewportIndex( + BuiltInId::gl_ViewportIndex, + BuiltInName::gl_ViewportIndex, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpHigh, EvqViewportIndex, 1, 1>()); +constexpr const TVariable kVar_gl_WorkGroupID( + BuiltInId::gl_WorkGroupID, + BuiltInName::gl_WorkGroupID, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqWorkGroupID, 3, 1>()); +constexpr const TVariable kVar_gl_WorkGroupSize( + BuiltInId::gl_WorkGroupSize, + BuiltInName::gl_WorkGroupSize, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqWorkGroupSize, 3, 1>()); +constexpr const TVariable kVar_pt0B(BuiltInId::pt0B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0C(BuiltInId::pt0C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0D(BuiltInId::pt0D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0E(BuiltInId::pt0E, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0F( + BuiltInId::pt0F, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtAtomicCounter, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0G( + BuiltInId::pt0G, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtYuvCscStandardEXT, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0H(BuiltInId::pt0H, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler2D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0I(BuiltInId::pt0I, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler3D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0J( + BuiltInId::pt0J, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSamplerCube, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0K( + BuiltInId::pt0K, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler2DArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0L( + BuiltInId::pt0L, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSamplerExternalOES, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0M( + BuiltInId::pt0M, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSamplerExternal2DY2YEXT, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0N( + BuiltInId::pt0N, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler2DRect, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0O( + BuiltInId::pt0O, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler2DMS, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0P( + BuiltInId::pt0P, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler2DMSArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0Q( + BuiltInId::pt0Q, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtISampler2D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0R( + BuiltInId::pt0R, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtISampler3D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0S( + BuiltInId::pt0S, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtISamplerCube, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0T( + BuiltInId::pt0T, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtISampler2DArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0U( + BuiltInId::pt0U, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtISampler2DMS, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0V( + BuiltInId::pt0V, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtISampler2DMSArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0W( + BuiltInId::pt0W, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUSampler2D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0X( + BuiltInId::pt0X, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUSampler3D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0Y( + BuiltInId::pt0Y, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUSamplerCube, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0Z( + BuiltInId::pt0Z, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUSampler2DArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0a( + BuiltInId::pt0a, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUSampler2DMS, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0b( + BuiltInId::pt0b, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUSampler2DMSArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0c( + BuiltInId::pt0c, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler2DShadow, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0d( + BuiltInId::pt0d, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSamplerCubeShadow, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0e( + BuiltInId::pt0e, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtSampler2DArrayShadow, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0f(BuiltInId::pt0f, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtImage2D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0g(BuiltInId::pt0g, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtIImage2D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0h(BuiltInId::pt0h, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUImage2D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0i(BuiltInId::pt0i, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtImage3D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0j(BuiltInId::pt0j, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtIImage3D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0k(BuiltInId::pt0k, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUImage3D, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0l( + BuiltInId::pt0l, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtImage2DArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0m( + BuiltInId::pt0m, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtIImage2DArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0n( + BuiltInId::pt0n, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUImage2DArray, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0o(BuiltInId::pt0o, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtImageCube, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0p( + BuiltInId::pt0p, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtIImageCube, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt0q( + BuiltInId::pt0q, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUImageCube, EbpUndefined, EvqGlobal, 1, 1>()); +constexpr const TVariable kVar_pt1B(BuiltInId::pt1B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>()); +constexpr const TVariable kVar_pt1C(BuiltInId::pt1C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>()); +constexpr const TVariable kVar_pt1D(BuiltInId::pt1D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>()); +constexpr const TVariable kVar_pt1E(BuiltInId::pt1E, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>()); +constexpr const TVariable kVar_pt2B(BuiltInId::pt2B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>()); +constexpr const TVariable kVar_pt2C(BuiltInId::pt2C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>()); +constexpr const TVariable kVar_pt2D(BuiltInId::pt2D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>()); +constexpr const TVariable kVar_pt2E(BuiltInId::pt2E, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>()); +constexpr const TVariable kVar_pt3B(BuiltInId::pt3B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>()); +constexpr const TVariable kVar_pt3C(BuiltInId::pt3C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>()); +constexpr const TVariable kVar_pt3D(BuiltInId::pt3D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>()); +constexpr const TVariable kVar_pt3E(BuiltInId::pt3E, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>()); +constexpr const TVariable kVar_pt5B(BuiltInId::pt5B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>()); +constexpr const TVariable kVar_pt6B(BuiltInId::pt6B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>()); +constexpr const TVariable kVar_pt7B(BuiltInId::pt7B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>()); +constexpr const TVariable kVar_pt9B(BuiltInId::pt9B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>()); +constexpr const TVariable kVar_ptAB(BuiltInId::ptAB, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>()); +constexpr const TVariable kVar_ptBB(BuiltInId::ptBB, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>()); +constexpr const TVariable kVar_ptDB(BuiltInId::ptDB, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>()); +constexpr const TVariable kVar_ptEB(BuiltInId::ptEB, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>()); +constexpr const TVariable kVar_ptFB(BuiltInId::ptFB, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>()); +constexpr const TVariable kVar_pt_io_0C(BuiltInId::pt_io_0C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqInOut, 1, 1>()); +constexpr const TVariable kVar_pt_io_0D(BuiltInId::pt_io_0D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqInOut, 1, 1>()); +constexpr const TVariable kVar_pt_o_0B(BuiltInId::pt_o_0B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 1, 1>()); +constexpr const TVariable kVar_pt_o_0C(BuiltInId::pt_o_0C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqOut, 1, 1>()); +constexpr const TVariable kVar_pt_o_0D(BuiltInId::pt_o_0D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 1, 1>()); +constexpr const TVariable kVar_pt_o_1B(BuiltInId::pt_o_1B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 2, 1>()); +constexpr const TVariable kVar_pt_o_1C(BuiltInId::pt_o_1C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqOut, 2, 1>()); +constexpr const TVariable kVar_pt_o_1D(BuiltInId::pt_o_1D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 2, 1>()); +constexpr const TVariable kVar_pt_o_2B(BuiltInId::pt_o_2B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 3, 1>()); +constexpr const TVariable kVar_pt_o_2C(BuiltInId::pt_o_2C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqOut, 3, 1>()); +constexpr const TVariable kVar_pt_o_2D(BuiltInId::pt_o_2D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 3, 1>()); +constexpr const TVariable kVar_pt_o_3B(BuiltInId::pt_o_3B, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtFloat, EbpUndefined, EvqOut, 4, 1>()); +constexpr const TVariable kVar_pt_o_3C(BuiltInId::pt_o_3C, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpUndefined, EvqOut, 4, 1>()); +constexpr const TVariable kVar_pt_o_3D(BuiltInId::pt_o_3D, + BuiltInName::_empty, + SymbolType::BuiltIn, + TExtension::UNDEFINED, + StaticType::Get<EbtUInt, EbpUndefined, EvqOut, 4, 1>()); + +const TVariable *gl_BaseInstance() +{ + return &kVar_gl_BaseInstance; +} + +const TVariable *gl_BaseVertex() +{ + return &kVar_gl_BaseVertex; +} + +const TVariable *gl_DrawID() +{ + return &kVar_gl_DrawID; +} + +const TVariable *gl_DrawIDESSL1() +{ + return &kVar_gl_DrawIDESSL1; +} + +const TVariable *gl_FragColor() +{ + return &kVar_gl_FragColor; +} + +const TVariable *gl_FragCoord() +{ + return &kVar_gl_FragCoord; +} + +const TVariable *gl_FragDepth() +{ + return &kVar_gl_FragDepth; +} + +const TVariable *gl_FrontFacing() +{ + return &kVar_gl_FrontFacing; +} + +const TVariable *gl_GlobalInvocationID() +{ + return &kVar_gl_GlobalInvocationID; +} + +const TVariable *gl_InstanceID() +{ + return &kVar_gl_InstanceID; +} + +const TVariable *gl_InvocationID() +{ + return &kVar_gl_InvocationID; +} + +const TVariable *gl_LastFragColor() +{ + return &kVar_gl_LastFragColor; +} + +const TVariable *gl_LastFragColorARM() +{ + return &kVar_gl_LastFragColorARM; +} + +const TVariable *gl_Layer() +{ + return &kVar_gl_Layer; +} + +const TVariable *gl_LayerGS() +{ + return &kVar_gl_LayerGS; +} + +const TVariable *gl_LayerVS() +{ + return &kVar_gl_LayerVS; +} + +const TVariable *gl_LocalInvocationID() +{ + return &kVar_gl_LocalInvocationID; +} + +const TVariable *gl_LocalInvocationIndex() +{ + return &kVar_gl_LocalInvocationIndex; +} + +const TVariable *gl_NumWorkGroups() +{ + return &kVar_gl_NumWorkGroups; +} + +const TVariable *gl_PointCoord() +{ + return &kVar_gl_PointCoord; +} + +const TVariable *gl_PointSize() +{ + return &kVar_gl_PointSize; +} + +const TVariable *gl_Position() +{ + return &kVar_gl_Position; +} + +const TVariable *gl_PrimitiveID() +{ + return &kVar_gl_PrimitiveID; +} + +const TVariable *gl_PrimitiveIDGS() +{ + return &kVar_gl_PrimitiveIDGS; +} + +const TVariable *gl_PrimitiveIDIn() +{ + return &kVar_gl_PrimitiveIDIn; +} + +const TVariable *gl_SecondaryFragColorEXT() +{ + return &kVar_gl_SecondaryFragColorEXT; +} + +const TVariable *gl_VertexID() +{ + return &kVar_gl_VertexID; +} + +const TVariable *gl_ViewID_OVR() +{ + return &kVar_gl_ViewID_OVR; +} + +const TVariable *gl_ViewID_OVRESSL1() +{ + return &kVar_gl_ViewID_OVRESSL1; +} + +const TVariable *gl_ViewportIndex() +{ + return &kVar_gl_ViewportIndex; +} + +const TVariable *gl_WorkGroupID() +{ + return &kVar_gl_WorkGroupID; +} + +const TVariable *gl_WorkGroupSize() +{ + return &kVar_gl_WorkGroupSize; +} + +} // namespace BuiltInVariable + +namespace BuiltInParameters +{ + +constexpr const TVariable **empty = nullptr; +constexpr const TVariable *p0B0B0B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0B0B0E[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt0E}; +constexpr const TVariable *p0B0B1B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1B}; +constexpr const TVariable *p0B0B2B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p0B0B3B[3] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p0B0C[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0B1B[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt1B}; +constexpr const TVariable *p0B2B[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p0B3B[2] = {&BuiltInVariable::kVar_pt0B, &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p0B_o_0B[2] = {&BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt_o_0B}; +constexpr const TVariable *p0B_o_0C[2] = {&BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt_o_0C}; +constexpr const TVariable *p0C0C0C0C[4] = {&BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0C0C_o_0C_o_0C[4] = { + &BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt_o_0C, + &BuiltInVariable::kVar_pt_o_0C}; +constexpr const TVariable *p0D0C0C[3] = {&BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0D0D0C0C[4] = {&BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0D0D0D[3] = {&BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D, + &BuiltInVariable::kVar_pt0D}; +constexpr const TVariable *p0D0D_o_0D_o_0D[4] = { + &BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt_o_0D, + &BuiltInVariable::kVar_pt_o_0D}; +constexpr const TVariable *p0F[1] = {&BuiltInVariable::kVar_pt0F}; +constexpr const TVariable *p0H0C[2] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0H1B0B1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0H1B0C[3] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0H1B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0H1B1C0B[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0H1B1C0C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0H1C0C1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0H2B0B1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0H2B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0H2B1C0B[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0H3B0B1C[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0H3B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0H3B1C0B[4] = {&BuiltInVariable::kVar_pt0H, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0I0C[2] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0I2B0B2C[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0I2B2B2B2C[5] = { + &BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0I2B2C0B[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0I2C0C2C[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0I3B0B2C[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0I3B2B2B2C[5] = { + &BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0I3B2C0B[4] = {&BuiltInVariable::kVar_pt0I, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0J0C[2] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0J2B0B[3] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0J2B0C[3] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0J2B2B2B[4] = {&BuiltInVariable::kVar_pt0J, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p0K0C[2] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0K2B0B1C[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0K2B0C[3] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0K2B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0K2B1C0B[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0K2B1C0C[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0K2C0C1C[4] = {&BuiltInVariable::kVar_pt0K, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0L0C[2] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0L1B0B[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0L1C0C[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0L2B0B[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0L3B0B[3] = {&BuiltInVariable::kVar_pt0L, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0M0C[2] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0M1B0B[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0M1C0C[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0M2B0B[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0M3B0B[3] = {&BuiltInVariable::kVar_pt0M, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0N1B[2] = {&BuiltInVariable::kVar_pt0N, &BuiltInVariable::kVar_pt1B}; +constexpr const TVariable *p0N2B[2] = {&BuiltInVariable::kVar_pt0N, &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p0N3B[2] = {&BuiltInVariable::kVar_pt0N, &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p0O1C0C[3] = {&BuiltInVariable::kVar_pt0O, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0P2C0C[3] = {&BuiltInVariable::kVar_pt0P, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Q0C[2] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Q1B0B1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Q1B0C[3] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Q1B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Q1B1C0B[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0Q1B1C0C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Q1C0C1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Q2B0B1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Q2B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Q2B1C0B[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0Q3B0B1C[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Q3B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Q3B1C0B[4] = {&BuiltInVariable::kVar_pt0Q, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0R0C[2] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0R2B0B2C[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0R2B2B2B2C[5] = { + &BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0R2B2C0B[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0R2C0C2C[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0R3B0B2C[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0R3B2B2B2C[5] = { + &BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0R3B2C0B[4] = {&BuiltInVariable::kVar_pt0R, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0S0C[2] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0S2B0B[3] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0S2B0C[3] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0S2B2B2B[4] = {&BuiltInVariable::kVar_pt0S, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p0T0C[2] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0T2B0B1C[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0T2B0C[3] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0T2B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0T2B1C0B[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0T2B1C0C[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0T2C0C1C[4] = {&BuiltInVariable::kVar_pt0T, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0U1C0C[3] = {&BuiltInVariable::kVar_pt0U, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0V2C0C[3] = {&BuiltInVariable::kVar_pt0V, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0W0C[2] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0W1B0B1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0W1B0C[3] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0W1B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0W1B1C0B[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0W1B1C0C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0W1C0C1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0W2B0B1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0W2B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0W2B1C0B[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0W3B0B1C[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0W3B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0W3B1C0B[4] = {&BuiltInVariable::kVar_pt0W, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0X0C[2] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0X2B0B2C[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0X2B2B2B2C[5] = { + &BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0X2B2C0B[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0X2C0C2C[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0X3B0B2C[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0X3B2B2B2C[5] = { + &BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p0X3B2C0B[4] = {&BuiltInVariable::kVar_pt0X, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0Y0C[2] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Y2B0B[3] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0Y2B0C[3] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Y2B2B2B[4] = {&BuiltInVariable::kVar_pt0Y, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p0Z0C[2] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Z2B0B1C[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Z2B0C[3] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Z2B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0Z2B1C0B[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0Z2B1C0C[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0Z2C0C1C[4] = {&BuiltInVariable::kVar_pt0Z, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0a1C0C[3] = {&BuiltInVariable::kVar_pt0a, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0b2C0C[3] = {&BuiltInVariable::kVar_pt0b, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0c0C[2] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0c1B0B1C[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0c2B0B1C[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0c2B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0c2B1C0B[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0c3B0B1C[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0c3B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0c3B1C0B[4] = {&BuiltInVariable::kVar_pt0c, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0d0C[2] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0d2B0B[3] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0d3B0B[3] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p0d3B2B2B[4] = {&BuiltInVariable::kVar_pt0d, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p0e0C[2] = {&BuiltInVariable::kVar_pt0e, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p0e2B0B1C[4] = {&BuiltInVariable::kVar_pt0e, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0e3B1B1B1C[5] = { + &BuiltInVariable::kVar_pt0e, &BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p0f1C3B[3] = {&BuiltInVariable::kVar_pt0f, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p0g1C3C[3] = {&BuiltInVariable::kVar_pt0g, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt3C}; +constexpr const TVariable *p0h1C3D[3] = {&BuiltInVariable::kVar_pt0h, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt3D}; +constexpr const TVariable *p0i2C3B[3] = {&BuiltInVariable::kVar_pt0i, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p0j2C3C[3] = {&BuiltInVariable::kVar_pt0j, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3C}; +constexpr const TVariable *p0k2C3D[3] = {&BuiltInVariable::kVar_pt0k, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3D}; +constexpr const TVariable *p0l2C3B[3] = {&BuiltInVariable::kVar_pt0l, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p0m2C3C[3] = {&BuiltInVariable::kVar_pt0m, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3C}; +constexpr const TVariable *p0n2C3D[3] = {&BuiltInVariable::kVar_pt0n, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3D}; +constexpr const TVariable *p0o2C3B[3] = {&BuiltInVariable::kVar_pt0o, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p0p2C3C[3] = {&BuiltInVariable::kVar_pt0p, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3C}; +constexpr const TVariable *p0q2C3D[3] = {&BuiltInVariable::kVar_pt0q, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt3D}; +constexpr const TVariable *p1B0B0B[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p1B1B0B[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p1B1B1B[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1B}; +constexpr const TVariable *p1B1B1E[3] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt1E}; +constexpr const TVariable *p1B1C[2] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p1B2B[2] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p1B3B[2] = {&BuiltInVariable::kVar_pt1B, &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p1B_o_1B[2] = {&BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt_o_1B}; +constexpr const TVariable *p1B_o_1C[2] = {&BuiltInVariable::kVar_pt1B, + &BuiltInVariable::kVar_pt_o_1C}; +constexpr const TVariable *p1C0C0C[3] = {&BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p1C1C0C0C[4] = {&BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p1C1C1C[3] = {&BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt1C, + &BuiltInVariable::kVar_pt1C}; +constexpr const TVariable *p1C1C_o_1C_o_1C[4] = { + &BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt1C, &BuiltInVariable::kVar_pt_o_1C, + &BuiltInVariable::kVar_pt_o_1C}; +constexpr const TVariable *p1D0C0C[3] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p1D0D0D[3] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt0D, + &BuiltInVariable::kVar_pt0D}; +constexpr const TVariable *p1D1D0C0C[4] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt1D, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p1D1D1D[3] = {&BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt1D, + &BuiltInVariable::kVar_pt1D}; +constexpr const TVariable *p1D1D_o_1D_o_1D[4] = { + &BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt1D, &BuiltInVariable::kVar_pt_o_1D, + &BuiltInVariable::kVar_pt_o_1D}; +constexpr const TVariable *p1E1E[2] = {&BuiltInVariable::kVar_pt1E, &BuiltInVariable::kVar_pt1E}; +constexpr const TVariable *p2B0B0B[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p2B0G[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt0G}; +constexpr const TVariable *p2B1B[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt1B}; +constexpr const TVariable *p2B2B0B[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p2B2B2B[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p2B2B2E[3] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt2E}; +constexpr const TVariable *p2B2C[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p2B3B[2] = {&BuiltInVariable::kVar_pt2B, &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p2B_o_2B[2] = {&BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt_o_2B}; +constexpr const TVariable *p2B_o_2C[2] = {&BuiltInVariable::kVar_pt2B, + &BuiltInVariable::kVar_pt_o_2C}; +constexpr const TVariable *p2C0C0C[3] = {&BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p2C2C0C0C[4] = {&BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p2C2C2C[3] = {&BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt2C, + &BuiltInVariable::kVar_pt2C}; +constexpr const TVariable *p2C2C_o_2C_o_2C[4] = { + &BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt2C, &BuiltInVariable::kVar_pt_o_2C, + &BuiltInVariable::kVar_pt_o_2C}; +constexpr const TVariable *p2D0C0C[3] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p2D0D0D[3] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt0D, + &BuiltInVariable::kVar_pt0D}; +constexpr const TVariable *p2D2D0C0C[4] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt2D, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p2D2D2D[3] = {&BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt2D, + &BuiltInVariable::kVar_pt2D}; +constexpr const TVariable *p2D2D_o_2D_o_2D[4] = { + &BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt2D, &BuiltInVariable::kVar_pt_o_2D, + &BuiltInVariable::kVar_pt_o_2D}; +constexpr const TVariable *p2E2E[2] = {&BuiltInVariable::kVar_pt2E, &BuiltInVariable::kVar_pt2E}; +constexpr const TVariable *p3B0B0B[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt0B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p3B1B[2] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt1B}; +constexpr const TVariable *p3B2B[2] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt2B}; +constexpr const TVariable *p3B3B0B[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt0B}; +constexpr const TVariable *p3B3B3B[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt3B}; +constexpr const TVariable *p3B3B3E[3] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt3E}; +constexpr const TVariable *p3B3C[2] = {&BuiltInVariable::kVar_pt3B, &BuiltInVariable::kVar_pt3C}; +constexpr const TVariable *p3B_o_3B[2] = {&BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt_o_3B}; +constexpr const TVariable *p3B_o_3C[2] = {&BuiltInVariable::kVar_pt3B, + &BuiltInVariable::kVar_pt_o_3C}; +constexpr const TVariable *p3C0C0C[3] = {&BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p3C3C0C0C[4] = {&BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt3C, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p3C3C3C[3] = {&BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt3C, + &BuiltInVariable::kVar_pt3C}; +constexpr const TVariable *p3C3C_o_3C_o_3C[4] = { + &BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt3C, &BuiltInVariable::kVar_pt_o_3C, + &BuiltInVariable::kVar_pt_o_3C}; +constexpr const TVariable *p3D0C0C[3] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p3D0D0D[3] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt0D, + &BuiltInVariable::kVar_pt0D}; +constexpr const TVariable *p3D3D0C0C[4] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt3D, + &BuiltInVariable::kVar_pt0C, + &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p3D3D3D[3] = {&BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt3D, + &BuiltInVariable::kVar_pt3D}; +constexpr const TVariable *p3D3D_o_3D_o_3D[4] = { + &BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt3D, &BuiltInVariable::kVar_pt_o_3D, + &BuiltInVariable::kVar_pt_o_3D}; +constexpr const TVariable *p3E3E[2] = {&BuiltInVariable::kVar_pt3E, &BuiltInVariable::kVar_pt3E}; +constexpr const TVariable *p5B5B[2] = {&BuiltInVariable::kVar_pt5B, &BuiltInVariable::kVar_pt5B}; +constexpr const TVariable *p6B6B[2] = {&BuiltInVariable::kVar_pt6B, &BuiltInVariable::kVar_pt6B}; +constexpr const TVariable *p7B7B[2] = {&BuiltInVariable::kVar_pt7B, &BuiltInVariable::kVar_pt7B}; +constexpr const TVariable *p9B9B[2] = {&BuiltInVariable::kVar_pt9B, &BuiltInVariable::kVar_pt9B}; +constexpr const TVariable *pABAB[2] = {&BuiltInVariable::kVar_ptAB, &BuiltInVariable::kVar_ptAB}; +constexpr const TVariable *pBBBB[2] = {&BuiltInVariable::kVar_ptBB, &BuiltInVariable::kVar_ptBB}; +constexpr const TVariable *pDBDB[2] = {&BuiltInVariable::kVar_ptDB, &BuiltInVariable::kVar_ptDB}; +constexpr const TVariable *pEBEB[2] = {&BuiltInVariable::kVar_ptEB, &BuiltInVariable::kVar_ptEB}; +constexpr const TVariable *pFBFB[2] = {&BuiltInVariable::kVar_ptFB, &BuiltInVariable::kVar_ptFB}; +constexpr const TVariable *p_io_0C0C0C[3] = { + &BuiltInVariable::kVar_pt_io_0C, &BuiltInVariable::kVar_pt0C, &BuiltInVariable::kVar_pt0C}; +constexpr const TVariable *p_io_0D0D0D[3] = { + &BuiltInVariable::kVar_pt_io_0D, &BuiltInVariable::kVar_pt0D, &BuiltInVariable::kVar_pt0D}; + +} // namespace BuiltInParameters + +namespace UnmangledBuiltIns +{ + +constexpr const UnmangledBuiltIn ARB_texture_rectangle(TExtension::ARB_texture_rectangle); +constexpr const UnmangledBuiltIn EXT_YUV_target(TExtension::EXT_YUV_target); +constexpr const UnmangledBuiltIn EXT_geometry_shader(TExtension::EXT_geometry_shader); +constexpr const UnmangledBuiltIn EXT_shader_texture_lod(TExtension::EXT_shader_texture_lod); +constexpr const UnmangledBuiltIn OES_standard_derivatives(TExtension::OES_standard_derivatives); +constexpr const UnmangledBuiltIn OES_texture_3D(TExtension::OES_texture_3D); +constexpr const UnmangledBuiltIn UNDEFINED(TExtension::UNDEFINED); + +} // namespace UnmangledBuiltIns + +// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend +// this from TFunction. Now symbol constructors taking an id have to be public even though they're +// not supposed to be accessible from outside of here. http://anglebug.com/2390 +namespace BuiltInFunction +{ + +constexpr const TFunction kFunction_radians_0B( + BuiltInId::radians_Float1, + BuiltInName::radians, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpRadians, + true); +constexpr const TFunction kFunction_radians_1B( + BuiltInId::radians_Float2, + BuiltInName::radians, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpRadians, + true); +constexpr const TFunction kFunction_radians_2B( + BuiltInId::radians_Float3, + BuiltInName::radians, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpRadians, + true); +constexpr const TFunction kFunction_radians_3B( + BuiltInId::radians_Float4, + BuiltInName::radians, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpRadians, + true); +constexpr const TFunction kFunction_degrees_0B( + BuiltInId::degrees_Float1, + BuiltInName::degrees, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDegrees, + true); +constexpr const TFunction kFunction_degrees_1B( + BuiltInId::degrees_Float2, + BuiltInName::degrees, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpDegrees, + true); +constexpr const TFunction kFunction_degrees_2B( + BuiltInId::degrees_Float3, + BuiltInName::degrees, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpDegrees, + true); +constexpr const TFunction kFunction_degrees_3B( + BuiltInId::degrees_Float4, + BuiltInName::degrees, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpDegrees, + true); +constexpr const TFunction kFunction_sin_0B( + BuiltInId::sin_Float1, + BuiltInName::sin, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpSin, + true); +constexpr const TFunction kFunction_sin_1B( + BuiltInId::sin_Float2, + BuiltInName::sin, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpSin, + true); +constexpr const TFunction kFunction_sin_2B( + BuiltInId::sin_Float3, + BuiltInName::sin, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpSin, + true); +constexpr const TFunction kFunction_sin_3B( + BuiltInId::sin_Float4, + BuiltInName::sin, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpSin, + true); +constexpr const TFunction kFunction_cos_0B( + BuiltInId::cos_Float1, + BuiltInName::cos, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCos, + true); +constexpr const TFunction kFunction_cos_1B( + BuiltInId::cos_Float2, + BuiltInName::cos, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCos, + true); +constexpr const TFunction kFunction_cos_2B( + BuiltInId::cos_Float3, + BuiltInName::cos, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCos, + true); +constexpr const TFunction kFunction_cos_3B( + BuiltInId::cos_Float4, + BuiltInName::cos, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCos, + true); +constexpr const TFunction kFunction_tan_0B( + BuiltInId::tan_Float1, + BuiltInName::tan, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpTan, + true); +constexpr const TFunction kFunction_tan_1B( + BuiltInId::tan_Float2, + BuiltInName::tan, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpTan, + true); +constexpr const TFunction kFunction_tan_2B( + BuiltInId::tan_Float3, + BuiltInName::tan, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpTan, + true); +constexpr const TFunction kFunction_tan_3B( + BuiltInId::tan_Float4, + BuiltInName::tan, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpTan, + true); +constexpr const TFunction kFunction_asin_0B( + BuiltInId::asin_Float1, + BuiltInName::asin, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAsin, + true); +constexpr const TFunction kFunction_asin_1B( + BuiltInId::asin_Float2, + BuiltInName::asin, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAsin, + true); +constexpr const TFunction kFunction_asin_2B( + BuiltInId::asin_Float3, + BuiltInName::asin, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAsin, + true); +constexpr const TFunction kFunction_asin_3B( + BuiltInId::asin_Float4, + BuiltInName::asin, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAsin, + true); +constexpr const TFunction kFunction_acos_0B( + BuiltInId::acos_Float1, + BuiltInName::acos, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAcos, + true); +constexpr const TFunction kFunction_acos_1B( + BuiltInId::acos_Float2, + BuiltInName::acos, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAcos, + true); +constexpr const TFunction kFunction_acos_2B( + BuiltInId::acos_Float3, + BuiltInName::acos, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAcos, + true); +constexpr const TFunction kFunction_acos_3B( + BuiltInId::acos_Float4, + BuiltInName::acos, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAcos, + true); +constexpr const TFunction kFunction_atan_0B0B( + BuiltInId::atan_Float1_Float1, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_atan_1B1B( + BuiltInId::atan_Float2_Float2, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_atan_2B2B( + BuiltInId::atan_Float3_Float3, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_atan_3B3B( + BuiltInId::atan_Float4_Float4, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_atan_0B( + BuiltInId::atan_Float1, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_atan_1B( + BuiltInId::atan_Float2, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_atan_2B( + BuiltInId::atan_Float3, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_atan_3B( + BuiltInId::atan_Float4, + BuiltInName::atan, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAtan, + true); +constexpr const TFunction kFunction_sinh_0B( + BuiltInId::sinh_Float1, + BuiltInName::sinh, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpSinh, + true); +constexpr const TFunction kFunction_sinh_1B( + BuiltInId::sinh_Float2, + BuiltInName::sinh, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpSinh, + true); +constexpr const TFunction kFunction_sinh_2B( + BuiltInId::sinh_Float3, + BuiltInName::sinh, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpSinh, + true); +constexpr const TFunction kFunction_sinh_3B( + BuiltInId::sinh_Float4, + BuiltInName::sinh, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpSinh, + true); +constexpr const TFunction kFunction_cosh_0B( + BuiltInId::cosh_Float1, + BuiltInName::cosh, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCosh, + true); +constexpr const TFunction kFunction_cosh_1B( + BuiltInId::cosh_Float2, + BuiltInName::cosh, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCosh, + true); +constexpr const TFunction kFunction_cosh_2B( + BuiltInId::cosh_Float3, + BuiltInName::cosh, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCosh, + true); +constexpr const TFunction kFunction_cosh_3B( + BuiltInId::cosh_Float4, + BuiltInName::cosh, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCosh, + true); +constexpr const TFunction kFunction_tanh_0B( + BuiltInId::tanh_Float1, + BuiltInName::tanh, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpTanh, + true); +constexpr const TFunction kFunction_tanh_1B( + BuiltInId::tanh_Float2, + BuiltInName::tanh, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpTanh, + true); +constexpr const TFunction kFunction_tanh_2B( + BuiltInId::tanh_Float3, + BuiltInName::tanh, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpTanh, + true); +constexpr const TFunction kFunction_tanh_3B( + BuiltInId::tanh_Float4, + BuiltInName::tanh, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpTanh, + true); +constexpr const TFunction kFunction_asinh_0B( + BuiltInId::asinh_Float1, + BuiltInName::asinh, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAsinh, + true); +constexpr const TFunction kFunction_asinh_1B( + BuiltInId::asinh_Float2, + BuiltInName::asinh, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAsinh, + true); +constexpr const TFunction kFunction_asinh_2B( + BuiltInId::asinh_Float3, + BuiltInName::asinh, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAsinh, + true); +constexpr const TFunction kFunction_asinh_3B( + BuiltInId::asinh_Float4, + BuiltInName::asinh, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAsinh, + true); +constexpr const TFunction kFunction_acosh_0B( + BuiltInId::acosh_Float1, + BuiltInName::acosh, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAcosh, + true); +constexpr const TFunction kFunction_acosh_1B( + BuiltInId::acosh_Float2, + BuiltInName::acosh, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAcosh, + true); +constexpr const TFunction kFunction_acosh_2B( + BuiltInId::acosh_Float3, + BuiltInName::acosh, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAcosh, + true); +constexpr const TFunction kFunction_acosh_3B( + BuiltInId::acosh_Float4, + BuiltInName::acosh, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAcosh, + true); +constexpr const TFunction kFunction_atanh_0B( + BuiltInId::atanh_Float1, + BuiltInName::atanh, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtanh, + true); +constexpr const TFunction kFunction_atanh_1B( + BuiltInId::atanh_Float2, + BuiltInName::atanh, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAtanh, + true); +constexpr const TFunction kFunction_atanh_2B( + BuiltInId::atanh_Float3, + BuiltInName::atanh, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAtanh, + true); +constexpr const TFunction kFunction_atanh_3B( + BuiltInId::atanh_Float4, + BuiltInName::atanh, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAtanh, + true); +constexpr const TFunction kFunction_pow_0B0B( + BuiltInId::pow_Float1_Float1, + BuiltInName::pow, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpPow, + true); +constexpr const TFunction kFunction_pow_1B1B( + BuiltInId::pow_Float2_Float2, + BuiltInName::pow, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpPow, + true); +constexpr const TFunction kFunction_pow_2B2B( + BuiltInId::pow_Float3_Float3, + BuiltInName::pow, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpPow, + true); +constexpr const TFunction kFunction_pow_3B3B( + BuiltInId::pow_Float4_Float4, + BuiltInName::pow, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpPow, + true); +constexpr const TFunction kFunction_exp_0B( + BuiltInId::exp_Float1, + BuiltInName::exp, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpExp, + true); +constexpr const TFunction kFunction_exp_1B( + BuiltInId::exp_Float2, + BuiltInName::exp, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpExp, + true); +constexpr const TFunction kFunction_exp_2B( + BuiltInId::exp_Float3, + BuiltInName::exp, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpExp, + true); +constexpr const TFunction kFunction_exp_3B( + BuiltInId::exp_Float4, + BuiltInName::exp, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpExp, + true); +constexpr const TFunction kFunction_log_0B( + BuiltInId::log_Float1, + BuiltInName::log, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpLog, + true); +constexpr const TFunction kFunction_log_1B( + BuiltInId::log_Float2, + BuiltInName::log, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLog, + true); +constexpr const TFunction kFunction_log_2B( + BuiltInId::log_Float3, + BuiltInName::log, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLog, + true); +constexpr const TFunction kFunction_log_3B( + BuiltInId::log_Float4, + BuiltInName::log, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLog, + true); +constexpr const TFunction kFunction_exp2_0B( + BuiltInId::exp2_Float1, + BuiltInName::exp2, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpExp2, + true); +constexpr const TFunction kFunction_exp2_1B( + BuiltInId::exp2_Float2, + BuiltInName::exp2, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpExp2, + true); +constexpr const TFunction kFunction_exp2_2B( + BuiltInId::exp2_Float3, + BuiltInName::exp2, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpExp2, + true); +constexpr const TFunction kFunction_exp2_3B( + BuiltInId::exp2_Float4, + BuiltInName::exp2, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpExp2, + true); +constexpr const TFunction kFunction_log2_0B( + BuiltInId::log2_Float1, + BuiltInName::log2, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpLog2, + true); +constexpr const TFunction kFunction_log2_1B( + BuiltInId::log2_Float2, + BuiltInName::log2, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLog2, + true); +constexpr const TFunction kFunction_log2_2B( + BuiltInId::log2_Float3, + BuiltInName::log2, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLog2, + true); +constexpr const TFunction kFunction_log2_3B( + BuiltInId::log2_Float4, + BuiltInName::log2, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLog2, + true); +constexpr const TFunction kFunction_sqrt_0B( + BuiltInId::sqrt_Float1, + BuiltInName::sqrt, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpSqrt, + true); +constexpr const TFunction kFunction_sqrt_1B( + BuiltInId::sqrt_Float2, + BuiltInName::sqrt, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpSqrt, + true); +constexpr const TFunction kFunction_sqrt_2B( + BuiltInId::sqrt_Float3, + BuiltInName::sqrt, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpSqrt, + true); +constexpr const TFunction kFunction_sqrt_3B( + BuiltInId::sqrt_Float4, + BuiltInName::sqrt, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpSqrt, + true); +constexpr const TFunction kFunction_inversesqrt_0B( + BuiltInId::inversesqrt_Float1, + BuiltInName::inversesqrt, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpInversesqrt, + true); +constexpr const TFunction kFunction_inversesqrt_1B( + BuiltInId::inversesqrt_Float2, + BuiltInName::inversesqrt, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpInversesqrt, + true); +constexpr const TFunction kFunction_inversesqrt_2B( + BuiltInId::inversesqrt_Float3, + BuiltInName::inversesqrt, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpInversesqrt, + true); +constexpr const TFunction kFunction_inversesqrt_3B( + BuiltInId::inversesqrt_Float4, + BuiltInName::inversesqrt, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpInversesqrt, + true); +constexpr const TFunction kFunction_abs_0B( + BuiltInId::abs_Float1, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_abs_1B( + BuiltInId::abs_Float2, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_abs_2B( + BuiltInId::abs_Float3, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_abs_3B( + BuiltInId::abs_Float4, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_abs_0C(BuiltInId::abs_Int1, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_abs_1C(BuiltInId::abs_Int2, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_abs_2C(BuiltInId::abs_Int3, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_abs_3C(BuiltInId::abs_Int4, + BuiltInName::abs, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpAbs, + true); +constexpr const TFunction kFunction_sign_0B( + BuiltInId::sign_Float1, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_sign_1B( + BuiltInId::sign_Float2, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_sign_2B( + BuiltInId::sign_Float3, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_sign_3B( + BuiltInId::sign_Float4, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_sign_0C( + BuiltInId::sign_Int1, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_sign_1C( + BuiltInId::sign_Int2, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_sign_2C( + BuiltInId::sign_Int3, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_sign_3C( + BuiltInId::sign_Int4, + BuiltInName::sign, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpSign, + true); +constexpr const TFunction kFunction_floor_0B( + BuiltInId::floor_Float1, + BuiltInName::floor, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFloor, + true); +constexpr const TFunction kFunction_floor_1B( + BuiltInId::floor_Float2, + BuiltInName::floor, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFloor, + true); +constexpr const TFunction kFunction_floor_2B( + BuiltInId::floor_Float3, + BuiltInName::floor, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFloor, + true); +constexpr const TFunction kFunction_floor_3B( + BuiltInId::floor_Float4, + BuiltInName::floor, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFloor, + true); +constexpr const TFunction kFunction_trunc_0B( + BuiltInId::trunc_Float1, + BuiltInName::trunc, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpTrunc, + true); +constexpr const TFunction kFunction_trunc_1B( + BuiltInId::trunc_Float2, + BuiltInName::trunc, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpTrunc, + true); +constexpr const TFunction kFunction_trunc_2B( + BuiltInId::trunc_Float3, + BuiltInName::trunc, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpTrunc, + true); +constexpr const TFunction kFunction_trunc_3B( + BuiltInId::trunc_Float4, + BuiltInName::trunc, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpTrunc, + true); +constexpr const TFunction kFunction_round_0B( + BuiltInId::round_Float1, + BuiltInName::round, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpRound, + true); +constexpr const TFunction kFunction_round_1B( + BuiltInId::round_Float2, + BuiltInName::round, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpRound, + true); +constexpr const TFunction kFunction_round_2B( + BuiltInId::round_Float3, + BuiltInName::round, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpRound, + true); +constexpr const TFunction kFunction_round_3B( + BuiltInId::round_Float4, + BuiltInName::round, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpRound, + true); +constexpr const TFunction kFunction_roundEven_0B( + BuiltInId::roundEven_Float1, + BuiltInName::roundEven, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpRoundEven, + true); +constexpr const TFunction kFunction_roundEven_1B( + BuiltInId::roundEven_Float2, + BuiltInName::roundEven, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpRoundEven, + true); +constexpr const TFunction kFunction_roundEven_2B( + BuiltInId::roundEven_Float3, + BuiltInName::roundEven, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpRoundEven, + true); +constexpr const TFunction kFunction_roundEven_3B( + BuiltInId::roundEven_Float4, + BuiltInName::roundEven, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpRoundEven, + true); +constexpr const TFunction kFunction_ceil_0B( + BuiltInId::ceil_Float1, + BuiltInName::ceil, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCeil, + true); +constexpr const TFunction kFunction_ceil_1B( + BuiltInId::ceil_Float2, + BuiltInName::ceil, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCeil, + true); +constexpr const TFunction kFunction_ceil_2B( + BuiltInId::ceil_Float3, + BuiltInName::ceil, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCeil, + true); +constexpr const TFunction kFunction_ceil_3B( + BuiltInId::ceil_Float4, + BuiltInName::ceil, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCeil, + true); +constexpr const TFunction kFunction_fract_0B( + BuiltInId::fract_Float1, + BuiltInName::fract, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFract, + true); +constexpr const TFunction kFunction_fract_1B( + BuiltInId::fract_Float2, + BuiltInName::fract, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFract, + true); +constexpr const TFunction kFunction_fract_2B( + BuiltInId::fract_Float3, + BuiltInName::fract, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFract, + true); +constexpr const TFunction kFunction_fract_3B( + BuiltInId::fract_Float4, + BuiltInName::fract, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFract, + true); +constexpr const TFunction kFunction_mod_0B0B( + BuiltInId::mod_Float1_Float1, + BuiltInName::mod, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMod, + true); +constexpr const TFunction kFunction_mod_1B0B( + BuiltInId::mod_Float2_Float1, + BuiltInName::mod, + TExtension::UNDEFINED, + BuiltInParameters::p1B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMod, + true); +constexpr const TFunction kFunction_mod_2B0B( + BuiltInId::mod_Float3_Float1, + BuiltInName::mod, + TExtension::UNDEFINED, + BuiltInParameters::p2B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMod, + true); +constexpr const TFunction kFunction_mod_3B0B( + BuiltInId::mod_Float4_Float1, + BuiltInName::mod, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMod, + true); +constexpr const TFunction kFunction_mod_1B1B( + BuiltInId::mod_Float2_Float2, + BuiltInName::mod, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMod, + true); +constexpr const TFunction kFunction_mod_2B2B( + BuiltInId::mod_Float3_Float3, + BuiltInName::mod, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMod, + true); +constexpr const TFunction kFunction_mod_3B3B( + BuiltInId::mod_Float4_Float4, + BuiltInName::mod, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMod, + true); +constexpr const TFunction kFunction_min_0B0B( + BuiltInId::min_Float1_Float1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_1B0B( + BuiltInId::min_Float2_Float1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p1B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_2B0B( + BuiltInId::min_Float3_Float1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p2B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_3B0B( + BuiltInId::min_Float4_Float1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_1B1B( + BuiltInId::min_Float2_Float2, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_2B2B( + BuiltInId::min_Float3_Float3, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_3B3B( + BuiltInId::min_Float4_Float4, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_0C0C( + BuiltInId::min_Int1_Int1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_1C1C( + BuiltInId::min_Int2_Int2, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_2C2C( + BuiltInId::min_Int3_Int3, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_3C3C( + BuiltInId::min_Int4_Int4, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_1C0C( + BuiltInId::min_Int2_Int1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p1C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_2C0C( + BuiltInId::min_Int3_Int1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p2C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_3C0C( + BuiltInId::min_Int4_Int1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_0D0D( + BuiltInId::min_UInt1_UInt1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p0D0D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_1D1D( + BuiltInId::min_UInt2_UInt2, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_2D2D( + BuiltInId::min_UInt3_UInt3, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_3D3D( + BuiltInId::min_UInt4_UInt4, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_1D0D( + BuiltInId::min_UInt2_UInt1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p1D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_2D0D( + BuiltInId::min_UInt3_UInt1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p2D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_min_3D0D( + BuiltInId::min_UInt4_UInt1, + BuiltInName::min, + TExtension::UNDEFINED, + BuiltInParameters::p3D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMin, + true); +constexpr const TFunction kFunction_max_0B0B( + BuiltInId::max_Float1_Float1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_1B0B( + BuiltInId::max_Float2_Float1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p1B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_2B0B( + BuiltInId::max_Float3_Float1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p2B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_3B0B( + BuiltInId::max_Float4_Float1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_1B1B( + BuiltInId::max_Float2_Float2, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_2B2B( + BuiltInId::max_Float3_Float3, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_3B3B( + BuiltInId::max_Float4_Float4, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_0C0C( + BuiltInId::max_Int1_Int1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_1C1C( + BuiltInId::max_Int2_Int2, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_2C2C( + BuiltInId::max_Int3_Int3, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_3C3C( + BuiltInId::max_Int4_Int4, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_1C0C( + BuiltInId::max_Int2_Int1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p1C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_2C0C( + BuiltInId::max_Int3_Int1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p2C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_3C0C( + BuiltInId::max_Int4_Int1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_0D0D( + BuiltInId::max_UInt1_UInt1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p0D0D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_1D1D( + BuiltInId::max_UInt2_UInt2, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_2D2D( + BuiltInId::max_UInt3_UInt3, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_3D3D( + BuiltInId::max_UInt4_UInt4, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_1D0D( + BuiltInId::max_UInt2_UInt1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p1D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_2D0D( + BuiltInId::max_UInt3_UInt1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p2D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_max_3D0D( + BuiltInId::max_UInt4_UInt1, + BuiltInName::max, + TExtension::UNDEFINED, + BuiltInParameters::p3D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMax, + true); +constexpr const TFunction kFunction_clamp_0B0B0B( + BuiltInId::clamp_Float1_Float1_Float1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_1B0B0B( + BuiltInId::clamp_Float2_Float1_Float1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p1B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_2B0B0B( + BuiltInId::clamp_Float3_Float1_Float1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p2B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_3B0B0B( + BuiltInId::clamp_Float4_Float1_Float1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_1B1B1B( + BuiltInId::clamp_Float2_Float2_Float2, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B1B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_2B2B2B( + BuiltInId::clamp_Float3_Float3_Float3, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B2B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_3B3B3B( + BuiltInId::clamp_Float4_Float4_Float4, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B3B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_0C0C0C( + BuiltInId::clamp_Int1_Int1_Int1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_1C0C0C( + BuiltInId::clamp_Int2_Int1_Int1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p1C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_2C0C0C( + BuiltInId::clamp_Int3_Int1_Int1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p2C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_3C0C0C( + BuiltInId::clamp_Int4_Int1_Int1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_1C1C1C( + BuiltInId::clamp_Int2_Int2_Int2, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_2C2C2C( + BuiltInId::clamp_Int3_Int3_Int3, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C2C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_3C3C3C( + BuiltInId::clamp_Int4_Int4_Int4, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_0D0D0D( + BuiltInId::clamp_UInt1_UInt1_UInt1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p0D0D0D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_1D0D0D( + BuiltInId::clamp_UInt2_UInt1_UInt1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p1D0D0D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_2D0D0D( + BuiltInId::clamp_UInt3_UInt1_UInt1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p2D0D0D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_3D0D0D( + BuiltInId::clamp_UInt4_UInt1_UInt1, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p3D0D0D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_1D1D1D( + BuiltInId::clamp_UInt2_UInt2_UInt2, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D1D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_2D2D2D( + BuiltInId::clamp_UInt3_UInt3_UInt3, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D2D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_clamp_3D3D3D( + BuiltInId::clamp_UInt4_UInt4_UInt4, + BuiltInName::clamp, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D3D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpClamp, + true); +constexpr const TFunction kFunction_mix_0B0B0B( + BuiltInId::mix_Float1_Float1_Float1, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_1B1B0B( + BuiltInId::mix_Float2_Float2_Float1, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_2B2B0B( + BuiltInId::mix_Float3_Float3_Float1, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_3B3B0B( + BuiltInId::mix_Float4_Float4_Float1, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_1B1B1B( + BuiltInId::mix_Float2_Float2_Float2, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B1B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_2B2B2B( + BuiltInId::mix_Float3_Float3_Float3, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B2B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_3B3B3B( + BuiltInId::mix_Float4_Float4_Float4, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B3B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_0B0B0E( + BuiltInId::mix_Float1_Float1_Bool1, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B0E, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_1B1B1E( + BuiltInId::mix_Float2_Float2_Bool2, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B1E, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_2B2B2E( + BuiltInId::mix_Float3_Float3_Bool3, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B2E, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_mix_3B3B3E( + BuiltInId::mix_Float4_Float4_Bool4, + BuiltInName::mix, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B3E, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpMix, + true); +constexpr const TFunction kFunction_step_0B0B( + BuiltInId::step_Float1_Float1, + BuiltInName::step, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpStep, + true); +constexpr const TFunction kFunction_step_1B1B( + BuiltInId::step_Float2_Float2, + BuiltInName::step, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpStep, + true); +constexpr const TFunction kFunction_step_2B2B( + BuiltInId::step_Float3_Float3, + BuiltInName::step, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpStep, + true); +constexpr const TFunction kFunction_step_3B3B( + BuiltInId::step_Float4_Float4, + BuiltInName::step, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpStep, + true); +constexpr const TFunction kFunction_step_0B1B( + BuiltInId::step_Float1_Float2, + BuiltInName::step, + TExtension::UNDEFINED, + BuiltInParameters::p0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpStep, + true); +constexpr const TFunction kFunction_step_0B2B( + BuiltInId::step_Float1_Float3, + BuiltInName::step, + TExtension::UNDEFINED, + BuiltInParameters::p0B2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpStep, + true); +constexpr const TFunction kFunction_step_0B3B( + BuiltInId::step_Float1_Float4, + BuiltInName::step, + TExtension::UNDEFINED, + BuiltInParameters::p0B3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpStep, + true); +constexpr const TFunction kFunction_smoothstep_0B0B0B( + BuiltInId::smoothstep_Float1_Float1_Float1, + BuiltInName::smoothstep, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpSmoothstep, + true); +constexpr const TFunction kFunction_smoothstep_1B1B1B( + BuiltInId::smoothstep_Float2_Float2_Float2, + BuiltInName::smoothstep, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B1B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpSmoothstep, + true); +constexpr const TFunction kFunction_smoothstep_2B2B2B( + BuiltInId::smoothstep_Float3_Float3_Float3, + BuiltInName::smoothstep, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B2B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpSmoothstep, + true); +constexpr const TFunction kFunction_smoothstep_3B3B3B( + BuiltInId::smoothstep_Float4_Float4_Float4, + BuiltInName::smoothstep, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B3B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpSmoothstep, + true); +constexpr const TFunction kFunction_smoothstep_0B0B1B( + BuiltInId::smoothstep_Float1_Float1_Float2, + BuiltInName::smoothstep, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpSmoothstep, + true); +constexpr const TFunction kFunction_smoothstep_0B0B2B( + BuiltInId::smoothstep_Float1_Float1_Float3, + BuiltInName::smoothstep, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B2B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpSmoothstep, + true); +constexpr const TFunction kFunction_smoothstep_0B0B3B( + BuiltInId::smoothstep_Float1_Float1_Float4, + BuiltInName::smoothstep, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B3B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpSmoothstep, + true); +constexpr const TFunction kFunction_modf_0B0B( + BuiltInId::modf_Float1_Float1, + BuiltInName::modf, + TExtension::UNDEFINED, + BuiltInParameters::p0B_o_0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpModf, + false); +constexpr const TFunction kFunction_modf_1B1B( + BuiltInId::modf_Float2_Float2, + BuiltInName::modf, + TExtension::UNDEFINED, + BuiltInParameters::p1B_o_1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpModf, + false); +constexpr const TFunction kFunction_modf_2B2B( + BuiltInId::modf_Float3_Float3, + BuiltInName::modf, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpModf, + false); +constexpr const TFunction kFunction_modf_3B3B( + BuiltInId::modf_Float4_Float4, + BuiltInName::modf, + TExtension::UNDEFINED, + BuiltInParameters::p3B_o_3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpModf, + false); +constexpr const TFunction kFunction_isnan_0B( + BuiltInId::isnan_Float1, + BuiltInName::isnan, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpIsnan, + true); +constexpr const TFunction kFunction_isnan_1B( + BuiltInId::isnan_Float2, + BuiltInName::isnan, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpIsnan, + true); +constexpr const TFunction kFunction_isnan_2B( + BuiltInId::isnan_Float3, + BuiltInName::isnan, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpIsnan, + true); +constexpr const TFunction kFunction_isnan_3B( + BuiltInId::isnan_Float4, + BuiltInName::isnan, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpIsnan, + true); +constexpr const TFunction kFunction_isinf_0B( + BuiltInId::isinf_Float1, + BuiltInName::isinf, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpIsinf, + true); +constexpr const TFunction kFunction_isinf_1B( + BuiltInId::isinf_Float2, + BuiltInName::isinf, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpIsinf, + true); +constexpr const TFunction kFunction_isinf_2B( + BuiltInId::isinf_Float3, + BuiltInName::isinf, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpIsinf, + true); +constexpr const TFunction kFunction_isinf_3B( + BuiltInId::isinf_Float4, + BuiltInName::isinf, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpIsinf, + true); +constexpr const TFunction kFunction_floatBitsToInt_0B( + BuiltInId::floatBitsToInt_Float1, + BuiltInName::floatBitsToInt, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFloatBitsToInt, + true); +constexpr const TFunction kFunction_floatBitsToInt_1B( + BuiltInId::floatBitsToInt_Float2, + BuiltInName::floatBitsToInt, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFloatBitsToInt, + true); +constexpr const TFunction kFunction_floatBitsToInt_2B( + BuiltInId::floatBitsToInt_Float3, + BuiltInName::floatBitsToInt, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFloatBitsToInt, + true); +constexpr const TFunction kFunction_floatBitsToInt_3B( + BuiltInId::floatBitsToInt_Float4, + BuiltInName::floatBitsToInt, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFloatBitsToInt, + true); +constexpr const TFunction kFunction_floatBitsToUint_0B( + BuiltInId::floatBitsToUint_Float1, + BuiltInName::floatBitsToUint, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFloatBitsToUint, + true); +constexpr const TFunction kFunction_floatBitsToUint_1B( + BuiltInId::floatBitsToUint_Float2, + BuiltInName::floatBitsToUint, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFloatBitsToUint, + true); +constexpr const TFunction kFunction_floatBitsToUint_2B( + BuiltInId::floatBitsToUint_Float3, + BuiltInName::floatBitsToUint, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFloatBitsToUint, + true); +constexpr const TFunction kFunction_floatBitsToUint_3B( + BuiltInId::floatBitsToUint_Float4, + BuiltInName::floatBitsToUint, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFloatBitsToUint, + true); +constexpr const TFunction kFunction_intBitsToFloat_0C( + BuiltInId::intBitsToFloat_Int1, + BuiltInName::intBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpIntBitsToFloat, + true); +constexpr const TFunction kFunction_intBitsToFloat_1C( + BuiltInId::intBitsToFloat_Int2, + BuiltInName::intBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpIntBitsToFloat, + true); +constexpr const TFunction kFunction_intBitsToFloat_2C( + BuiltInId::intBitsToFloat_Int3, + BuiltInName::intBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpIntBitsToFloat, + true); +constexpr const TFunction kFunction_intBitsToFloat_3C( + BuiltInId::intBitsToFloat_Int4, + BuiltInName::intBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpIntBitsToFloat, + true); +constexpr const TFunction kFunction_uintBitsToFloat_0D( + BuiltInId::uintBitsToFloat_UInt1, + BuiltInName::uintBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpUintBitsToFloat, + true); +constexpr const TFunction kFunction_uintBitsToFloat_1D( + BuiltInId::uintBitsToFloat_UInt2, + BuiltInName::uintBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p1D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpUintBitsToFloat, + true); +constexpr const TFunction kFunction_uintBitsToFloat_2D( + BuiltInId::uintBitsToFloat_UInt3, + BuiltInName::uintBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpUintBitsToFloat, + true); +constexpr const TFunction kFunction_uintBitsToFloat_3D( + BuiltInId::uintBitsToFloat_UInt4, + BuiltInName::uintBitsToFloat, + TExtension::UNDEFINED, + BuiltInParameters::p3D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpUintBitsToFloat, + true); +constexpr const TFunction kFunction_frexp_0B0C( + BuiltInId::frexp_Float1_Int1, + BuiltInName::frexp, + TExtension::UNDEFINED, + BuiltInParameters::p0B_o_0C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFrexp, + false); +constexpr const TFunction kFunction_frexp_1B1C( + BuiltInId::frexp_Float2_Int2, + BuiltInName::frexp, + TExtension::UNDEFINED, + BuiltInParameters::p1B_o_1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFrexp, + false); +constexpr const TFunction kFunction_frexp_2B2C( + BuiltInId::frexp_Float3_Int3, + BuiltInName::frexp, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFrexp, + false); +constexpr const TFunction kFunction_frexp_3B3C( + BuiltInId::frexp_Float4_Int4, + BuiltInName::frexp, + TExtension::UNDEFINED, + BuiltInParameters::p3B_o_3C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFrexp, + false); +constexpr const TFunction kFunction_ldexp_0B0C( + BuiltInId::ldexp_Float1_Int1, + BuiltInName::ldexp, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpLdexp, + true); +constexpr const TFunction kFunction_ldexp_1B1C( + BuiltInId::ldexp_Float2_Int2, + BuiltInName::ldexp, + TExtension::UNDEFINED, + BuiltInParameters::p1B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLdexp, + true); +constexpr const TFunction kFunction_ldexp_2B2C( + BuiltInId::ldexp_Float3_Int3, + BuiltInName::ldexp, + TExtension::UNDEFINED, + BuiltInParameters::p2B2C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLdexp, + true); +constexpr const TFunction kFunction_ldexp_3B3C( + BuiltInId::ldexp_Float4_Int4, + BuiltInName::ldexp, + TExtension::UNDEFINED, + BuiltInParameters::p3B3C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLdexp, + true); +constexpr const TFunction kFunction_packSnorm2x16_1B( + BuiltInId::packSnorm2x16_Float2, + BuiltInName::packSnorm2x16, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpPackSnorm2x16, + true); +constexpr const TFunction kFunction_packUnorm2x16_1B( + BuiltInId::packUnorm2x16_Float2, + BuiltInName::packUnorm2x16, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpPackUnorm2x16, + true); +constexpr const TFunction kFunction_packHalf2x16_1B( + BuiltInId::packHalf2x16_Float2, + BuiltInName::packHalf2x16, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpPackHalf2x16, + true); +constexpr const TFunction kFunction_unpackSnorm2x16_0D( + BuiltInId::unpackSnorm2x16_UInt1, + BuiltInName::unpackSnorm2x16, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpUnpackSnorm2x16, + true); +constexpr const TFunction kFunction_unpackUnorm2x16_0D( + BuiltInId::unpackUnorm2x16_UInt1, + BuiltInName::unpackUnorm2x16, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpUnpackUnorm2x16, + true); +constexpr const TFunction kFunction_unpackHalf2x16_0D( + BuiltInId::unpackHalf2x16_UInt1, + BuiltInName::unpackHalf2x16, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpUnpackHalf2x16, + true); +constexpr const TFunction kFunction_packUnorm4x8_3B( + BuiltInId::packUnorm4x8_Float4, + BuiltInName::packUnorm4x8, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpPackUnorm4x8, + true); +constexpr const TFunction kFunction_packSnorm4x8_3B( + BuiltInId::packSnorm4x8_Float4, + BuiltInName::packSnorm4x8, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpPackSnorm4x8, + true); +constexpr const TFunction kFunction_unpackUnorm4x8_0D( + BuiltInId::unpackUnorm4x8_UInt1, + BuiltInName::unpackUnorm4x8, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpUnpackUnorm4x8, + true); +constexpr const TFunction kFunction_unpackSnorm4x8_0D( + BuiltInId::unpackSnorm4x8_UInt1, + BuiltInName::unpackSnorm4x8, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpUnpackSnorm4x8, + true); +constexpr const TFunction kFunction_length_0B( + BuiltInId::length_Float1, + BuiltInName::length, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpLength, + true); +constexpr const TFunction kFunction_length_1B( + BuiltInId::length_Float2, + BuiltInName::length, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpLength, + true); +constexpr const TFunction kFunction_length_2B( + BuiltInId::length_Float3, + BuiltInName::length, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpLength, + true); +constexpr const TFunction kFunction_length_3B( + BuiltInId::length_Float4, + BuiltInName::length, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpLength, + true); +constexpr const TFunction kFunction_distance_0B0B( + BuiltInId::distance_Float1_Float1, + BuiltInName::distance, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDistance, + true); +constexpr const TFunction kFunction_distance_1B1B( + BuiltInId::distance_Float2_Float2, + BuiltInName::distance, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDistance, + true); +constexpr const TFunction kFunction_distance_2B2B( + BuiltInId::distance_Float3_Float3, + BuiltInName::distance, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDistance, + true); +constexpr const TFunction kFunction_distance_3B3B( + BuiltInId::distance_Float4_Float4, + BuiltInName::distance, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDistance, + true); +constexpr const TFunction kFunction_dot_0B0B( + BuiltInId::dot_Float1_Float1, + BuiltInName::dot, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDot, + true); +constexpr const TFunction kFunction_dot_1B1B( + BuiltInId::dot_Float2_Float2, + BuiltInName::dot, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDot, + true); +constexpr const TFunction kFunction_dot_2B2B( + BuiltInId::dot_Float3_Float3, + BuiltInName::dot, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDot, + true); +constexpr const TFunction kFunction_dot_3B3B( + BuiltInId::dot_Float4_Float4, + BuiltInName::dot, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDot, + true); +constexpr const TFunction kFunction_cross_2B2B( + BuiltInId::cross_Float3_Float3, + BuiltInName::cross, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCross, + true); +constexpr const TFunction kFunction_normalize_0B( + BuiltInId::normalize_Float1, + BuiltInName::normalize, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpNormalize, + true); +constexpr const TFunction kFunction_normalize_1B( + BuiltInId::normalize_Float2, + BuiltInName::normalize, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpNormalize, + true); +constexpr const TFunction kFunction_normalize_2B( + BuiltInId::normalize_Float3, + BuiltInName::normalize, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpNormalize, + true); +constexpr const TFunction kFunction_normalize_3B( + BuiltInId::normalize_Float4, + BuiltInName::normalize, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpNormalize, + true); +constexpr const TFunction kFunction_faceforward_0B0B0B( + BuiltInId::faceforward_Float1_Float1_Float1, + BuiltInName::faceforward, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFaceforward, + true); +constexpr const TFunction kFunction_faceforward_1B1B1B( + BuiltInId::faceforward_Float2_Float2_Float2, + BuiltInName::faceforward, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B1B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFaceforward, + true); +constexpr const TFunction kFunction_faceforward_2B2B2B( + BuiltInId::faceforward_Float3_Float3_Float3, + BuiltInName::faceforward, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B2B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFaceforward, + true); +constexpr const TFunction kFunction_faceforward_3B3B3B( + BuiltInId::faceforward_Float4_Float4_Float4, + BuiltInName::faceforward, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B3B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFaceforward, + true); +constexpr const TFunction kFunction_reflect_0B0B( + BuiltInId::reflect_Float1_Float1, + BuiltInName::reflect, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpReflect, + true); +constexpr const TFunction kFunction_reflect_1B1B( + BuiltInId::reflect_Float2_Float2, + BuiltInName::reflect, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpReflect, + true); +constexpr const TFunction kFunction_reflect_2B2B( + BuiltInId::reflect_Float3_Float3, + BuiltInName::reflect, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpReflect, + true); +constexpr const TFunction kFunction_reflect_3B3B( + BuiltInId::reflect_Float4_Float4, + BuiltInName::reflect, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpReflect, + true); +constexpr const TFunction kFunction_refract_0B0B0B( + BuiltInId::refract_Float1_Float1_Float1, + BuiltInName::refract, + TExtension::UNDEFINED, + BuiltInParameters::p0B0B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpRefract, + true); +constexpr const TFunction kFunction_refract_1B1B0B( + BuiltInId::refract_Float2_Float2_Float1, + BuiltInName::refract, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpRefract, + true); +constexpr const TFunction kFunction_refract_2B2B0B( + BuiltInId::refract_Float3_Float3_Float1, + BuiltInName::refract, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpRefract, + true); +constexpr const TFunction kFunction_refract_3B3B0B( + BuiltInId::refract_Float4_Float4_Float1, + BuiltInName::refract, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpRefract, + true); +constexpr const TFunction kFunction_matrixCompMult_5B5B( + BuiltInId::matrixCompMult_Float2x2_Float2x2, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::p5B5B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_ABAB( + BuiltInId::matrixCompMult_Float3x3_Float3x3, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::pABAB, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_FBFB( + BuiltInId::matrixCompMult_Float4x4_Float4x4, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::pFBFB, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_9B9B( + BuiltInId::matrixCompMult_Float2x3_Float2x3, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::p9B9B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_6B6B( + BuiltInId::matrixCompMult_Float3x2_Float3x2, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::p6B6B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_DBDB( + BuiltInId::matrixCompMult_Float2x4_Float2x4, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::pDBDB, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_7B7B( + BuiltInId::matrixCompMult_Float4x2_Float4x2, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::p7B7B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_EBEB( + BuiltInId::matrixCompMult_Float3x4_Float3x4, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::pEBEB, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_matrixCompMult_BBBB( + BuiltInId::matrixCompMult_Float4x3_Float4x3, + BuiltInName::matrixCompMult, + TExtension::UNDEFINED, + BuiltInParameters::pBBBB, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>(), + EOpMulMatrixComponentWise, + true); +constexpr const TFunction kFunction_outerProduct_1B1B( + BuiltInId::outerProduct_Float2_Float2, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_2B2B( + BuiltInId::outerProduct_Float3_Float3, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_3B3B( + BuiltInId::outerProduct_Float4_Float4, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_2B1B( + BuiltInId::outerProduct_Float3_Float2, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p2B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_1B2B( + BuiltInId::outerProduct_Float2_Float3, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p1B2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_3B1B( + BuiltInId::outerProduct_Float4_Float2, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p3B1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_1B3B( + BuiltInId::outerProduct_Float2_Float4, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p1B3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_3B2B( + BuiltInId::outerProduct_Float4_Float3, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p3B2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_outerProduct_2B3B( + BuiltInId::outerProduct_Float3_Float4, + BuiltInName::outerProduct, + TExtension::UNDEFINED, + BuiltInParameters::p2B3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>(), + EOpOuterProduct, + true); +constexpr const TFunction kFunction_transpose_5B( + BuiltInId::transpose_Float2x2, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::p5B5B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_AB( + BuiltInId::transpose_Float3x3, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::pABAB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_FB( + BuiltInId::transpose_Float4x4, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::pFBFB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_6B( + BuiltInId::transpose_Float3x2, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::p6B6B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 3>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_9B( + BuiltInId::transpose_Float2x3, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::p9B9B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 2>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_7B( + BuiltInId::transpose_Float4x2, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::p7B7B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 4>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_DB( + BuiltInId::transpose_Float2x4, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::pDBDB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 2>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_BB( + BuiltInId::transpose_Float4x3, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::pBBBB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 4>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_transpose_EB( + BuiltInId::transpose_Float3x4, + BuiltInName::transpose, + TExtension::UNDEFINED, + BuiltInParameters::pEBEB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 3>(), + EOpTranspose, + true); +constexpr const TFunction kFunction_determinant_5B( + BuiltInId::determinant_Float2x2, + BuiltInName::determinant, + TExtension::UNDEFINED, + BuiltInParameters::p5B5B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDeterminant, + true); +constexpr const TFunction kFunction_determinant_AB( + BuiltInId::determinant_Float3x3, + BuiltInName::determinant, + TExtension::UNDEFINED, + BuiltInParameters::pABAB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDeterminant, + true); +constexpr const TFunction kFunction_determinant_FB( + BuiltInId::determinant_Float4x4, + BuiltInName::determinant, + TExtension::UNDEFINED, + BuiltInParameters::pFBFB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDeterminant, + true); +constexpr const TFunction kFunction_inverse_5B( + BuiltInId::inverse_Float2x2, + BuiltInName::inverse, + TExtension::UNDEFINED, + BuiltInParameters::p5B5B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 2>(), + EOpInverse, + true); +constexpr const TFunction kFunction_inverse_AB( + BuiltInId::inverse_Float3x3, + BuiltInName::inverse, + TExtension::UNDEFINED, + BuiltInParameters::pABAB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 3>(), + EOpInverse, + true); +constexpr const TFunction kFunction_inverse_FB( + BuiltInId::inverse_Float4x4, + BuiltInName::inverse, + TExtension::UNDEFINED, + BuiltInParameters::pFBFB, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 4>(), + EOpInverse, + true); +constexpr const TFunction kFunction_lessThan_1B1B( + BuiltInId::lessThan_Float2_Float2, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_2B2B( + BuiltInId::lessThan_Float3_Float3, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_3B3B( + BuiltInId::lessThan_Float4_Float4, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_1C1C( + BuiltInId::lessThan_Int2_Int2, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_2C2C( + BuiltInId::lessThan_Int3_Int3, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_3C3C( + BuiltInId::lessThan_Int4_Int4, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_1D1D( + BuiltInId::lessThan_UInt2_UInt2, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_2D2D( + BuiltInId::lessThan_UInt3_UInt3, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThan_3D3D( + BuiltInId::lessThan_UInt4_UInt4, + BuiltInName::lessThan, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLessThanComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_1B1B( + BuiltInId::lessThanEqual_Float2_Float2, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_2B2B( + BuiltInId::lessThanEqual_Float3_Float3, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_3B3B( + BuiltInId::lessThanEqual_Float4_Float4, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_1C1C( + BuiltInId::lessThanEqual_Int2_Int2, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_2C2C( + BuiltInId::lessThanEqual_Int3_Int3, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_3C3C( + BuiltInId::lessThanEqual_Int4_Int4, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_1D1D( + BuiltInId::lessThanEqual_UInt2_UInt2, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_2D2D( + BuiltInId::lessThanEqual_UInt3_UInt3, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_lessThanEqual_3D3D( + BuiltInId::lessThanEqual_UInt4_UInt4, + BuiltInName::lessThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLessThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_1B1B( + BuiltInId::greaterThan_Float2_Float2, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_2B2B( + BuiltInId::greaterThan_Float3_Float3, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_3B3B( + BuiltInId::greaterThan_Float4_Float4, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_1C1C( + BuiltInId::greaterThan_Int2_Int2, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_2C2C( + BuiltInId::greaterThan_Int3_Int3, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_3C3C( + BuiltInId::greaterThan_Int4_Int4, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_1D1D( + BuiltInId::greaterThan_UInt2_UInt2, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_2D2D( + BuiltInId::greaterThan_UInt3_UInt3, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThan_3D3D( + BuiltInId::greaterThan_UInt4_UInt4, + BuiltInName::greaterThan, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpGreaterThanComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_1B1B( + BuiltInId::greaterThanEqual_Float2_Float2, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_2B2B( + BuiltInId::greaterThanEqual_Float3_Float3, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_3B3B( + BuiltInId::greaterThanEqual_Float4_Float4, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_1C1C( + BuiltInId::greaterThanEqual_Int2_Int2, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_2C2C( + BuiltInId::greaterThanEqual_Int3_Int3, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_3C3C( + BuiltInId::greaterThanEqual_Int4_Int4, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_1D1D( + BuiltInId::greaterThanEqual_UInt2_UInt2, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_2D2D( + BuiltInId::greaterThanEqual_UInt3_UInt3, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_greaterThanEqual_3D3D( + BuiltInId::greaterThanEqual_UInt4_UInt4, + BuiltInName::greaterThanEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpGreaterThanEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_1B1B( + BuiltInId::equal_Float2_Float2, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_2B2B( + BuiltInId::equal_Float3_Float3, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_3B3B( + BuiltInId::equal_Float4_Float4, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_1C1C( + BuiltInId::equal_Int2_Int2, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_2C2C( + BuiltInId::equal_Int3_Int3, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_3C3C( + BuiltInId::equal_Int4_Int4, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_1D1D( + BuiltInId::equal_UInt2_UInt2, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_2D2D( + BuiltInId::equal_UInt3_UInt3, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_3D3D( + BuiltInId::equal_UInt4_UInt4, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_1E1E( + BuiltInId::equal_Bool2_Bool2, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p1E1E, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_2E2E( + BuiltInId::equal_Bool3_Bool3, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p2E2E, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_equal_3E3E( + BuiltInId::equal_Bool4_Bool4, + BuiltInName::equal, + TExtension::UNDEFINED, + BuiltInParameters::p3E3E, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_1B1B( + BuiltInId::notEqual_Float2_Float2, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_2B2B( + BuiltInId::notEqual_Float3_Float3, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2B2B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_3B3B( + BuiltInId::notEqual_Float4_Float4, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3B3B0B, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_1C1C( + BuiltInId::notEqual_Int2_Int2, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_2C2C( + BuiltInId::notEqual_Int3_Int3, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_3C3C( + BuiltInId::notEqual_Int4_Int4, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C3C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_1D1D( + BuiltInId::notEqual_UInt2_UInt2, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_2D2D( + BuiltInId::notEqual_UInt3_UInt3, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_3D3D( + BuiltInId::notEqual_UInt4_UInt4, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_1E1E( + BuiltInId::notEqual_Bool2_Bool2, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p1E1E, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_2E2E( + BuiltInId::notEqual_Bool3_Bool3, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p2E2E, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_notEqual_3E3E( + BuiltInId::notEqual_Bool4_Bool4, + BuiltInName::notEqual, + TExtension::UNDEFINED, + BuiltInParameters::p3E3E, + 2, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpNotEqualComponentWise, + true); +constexpr const TFunction kFunction_any_1E( + BuiltInId::any_Bool2, + BuiltInName::any, + TExtension::UNDEFINED, + BuiltInParameters::p1E1E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAny, + true); +constexpr const TFunction kFunction_any_2E( + BuiltInId::any_Bool3, + BuiltInName::any, + TExtension::UNDEFINED, + BuiltInParameters::p2E2E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAny, + true); +constexpr const TFunction kFunction_any_3E( + BuiltInId::any_Bool4, + BuiltInName::any, + TExtension::UNDEFINED, + BuiltInParameters::p3E3E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAny, + true); +constexpr const TFunction kFunction_all_1E( + BuiltInId::all_Bool2, + BuiltInName::all, + TExtension::UNDEFINED, + BuiltInParameters::p1E1E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAll, + true); +constexpr const TFunction kFunction_all_2E( + BuiltInId::all_Bool3, + BuiltInName::all, + TExtension::UNDEFINED, + BuiltInParameters::p2E2E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAll, + true); +constexpr const TFunction kFunction_all_3E( + BuiltInId::all_Bool4, + BuiltInName::all, + TExtension::UNDEFINED, + BuiltInParameters::p3E3E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAll, + true); +constexpr const TFunction kFunction_notFunc_1E( + BuiltInId::notFunc_Bool2, + BuiltInName::notFunc, + TExtension::UNDEFINED, + BuiltInParameters::p1E1E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 2, 1>(), + EOpLogicalNotComponentWise, + true); +constexpr const TFunction kFunction_notFunc_2E( + BuiltInId::notFunc_Bool3, + BuiltInName::notFunc, + TExtension::UNDEFINED, + BuiltInParameters::p2E2E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 3, 1>(), + EOpLogicalNotComponentWise, + true); +constexpr const TFunction kFunction_notFunc_3E( + BuiltInId::notFunc_Bool4, + BuiltInName::notFunc, + TExtension::UNDEFINED, + BuiltInParameters::p3E3E, + 1, + StaticType::Get<EbtBool, EbpUndefined, EvqGlobal, 4, 1>(), + EOpLogicalNotComponentWise, + true); +constexpr const TFunction kFunction_bitfieldExtract_0C0C0C( + BuiltInId::bitfieldExtract_Int1_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldExtract_1C0C0C( + BuiltInId::bitfieldExtract_Int2_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p1C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldExtract_2C0C0C( + BuiltInId::bitfieldExtract_Int3_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p2C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldExtract_3C0C0C( + BuiltInId::bitfieldExtract_Int4_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldExtract_0D0C0C( + BuiltInId::bitfieldExtract_UInt1_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldExtract_1D0C0C( + BuiltInId::bitfieldExtract_UInt2_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p1D0C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldExtract_2D0C0C( + BuiltInId::bitfieldExtract_UInt3_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p2D0C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldExtract_3D0C0C( + BuiltInId::bitfieldExtract_UInt4_Int1_Int1, + BuiltInName::bitfieldExtract, + TExtension::UNDEFINED, + BuiltInParameters::p3D0C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitfieldExtract, + true); +constexpr const TFunction kFunction_bitfieldInsert_0C0C0C0C( + BuiltInId::bitfieldInsert_Int1_Int1_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C0C0C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldInsert_1C1C0C0C( + BuiltInId::bitfieldInsert_Int2_Int2_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C0C0C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldInsert_2C2C0C0C( + BuiltInId::bitfieldInsert_Int3_Int3_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldInsert_3C3C0C0C( + BuiltInId::bitfieldInsert_Int4_Int4_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C0C0C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldInsert_0D0D0C0C( + BuiltInId::bitfieldInsert_UInt1_UInt1_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p0D0D0C0C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldInsert_1D1D0C0C( + BuiltInId::bitfieldInsert_UInt2_UInt2_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D0C0C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldInsert_2D2D0C0C( + BuiltInId::bitfieldInsert_UInt3_UInt3_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldInsert_3D3D0C0C( + BuiltInId::bitfieldInsert_UInt4_UInt4_Int1_Int1, + BuiltInName::bitfieldInsert, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D0C0C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitfieldInsert, + true); +constexpr const TFunction kFunction_bitfieldReverse_0C( + BuiltInId::bitfieldReverse_Int1, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitfieldReverse_1C( + BuiltInId::bitfieldReverse_Int2, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitfieldReverse_2C( + BuiltInId::bitfieldReverse_Int3, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitfieldReverse_3C( + BuiltInId::bitfieldReverse_Int4, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitfieldReverse_0D( + BuiltInId::bitfieldReverse_UInt1, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitfieldReverse_1D( + BuiltInId::bitfieldReverse_UInt2, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p1D0C0C, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitfieldReverse_2D( + BuiltInId::bitfieldReverse_UInt3, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitfieldReverse_3D( + BuiltInId::bitfieldReverse_UInt4, + BuiltInName::bitfieldReverse, + TExtension::UNDEFINED, + BuiltInParameters::p3D0C0C, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitfieldReverse, + true); +constexpr const TFunction kFunction_bitCount_0C( + BuiltInId::bitCount_Int1, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_bitCount_1C( + BuiltInId::bitCount_Int2, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_bitCount_2C( + BuiltInId::bitCount_Int3, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_bitCount_3C( + BuiltInId::bitCount_Int4, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_bitCount_0D( + BuiltInId::bitCount_UInt1, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_bitCount_1D( + BuiltInId::bitCount_UInt2, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p1D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_bitCount_2D( + BuiltInId::bitCount_UInt3, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_bitCount_3D( + BuiltInId::bitCount_UInt4, + BuiltInName::bitCount, + TExtension::UNDEFINED, + BuiltInParameters::p3D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpBitCount, + true); +constexpr const TFunction kFunction_findLSB_0C( + BuiltInId::findLSB_Int1, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findLSB_1C( + BuiltInId::findLSB_Int2, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findLSB_2C( + BuiltInId::findLSB_Int3, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findLSB_3C( + BuiltInId::findLSB_Int4, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findLSB_0D( + BuiltInId::findLSB_UInt1, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findLSB_1D( + BuiltInId::findLSB_UInt2, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p1D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findLSB_2D( + BuiltInId::findLSB_UInt3, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findLSB_3D( + BuiltInId::findLSB_UInt4, + BuiltInName::findLSB, + TExtension::UNDEFINED, + BuiltInParameters::p3D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFindLSB, + true); +constexpr const TFunction kFunction_findMSB_0C( + BuiltInId::findMSB_Int1, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_findMSB_1C( + BuiltInId::findMSB_Int2, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_findMSB_2C( + BuiltInId::findMSB_Int3, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_findMSB_3C( + BuiltInId::findMSB_Int4, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p3C0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_findMSB_0D( + BuiltInId::findMSB_UInt1, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p0D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_findMSB_1D( + BuiltInId::findMSB_UInt2, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p1D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_findMSB_2D( + BuiltInId::findMSB_UInt3, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_findMSB_3D( + BuiltInId::findMSB_UInt4, + BuiltInName::findMSB, + TExtension::UNDEFINED, + BuiltInParameters::p3D0C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFindMSB, + true); +constexpr const TFunction kFunction_uaddCarry_0D0D0D( + BuiltInId::uaddCarry_UInt1_UInt1_UInt1, + BuiltInName::uaddCarry, + TExtension::UNDEFINED, + BuiltInParameters::p0D0D_o_0D_o_0D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpUaddCarry, + false); +constexpr const TFunction kFunction_uaddCarry_1D1D1D( + BuiltInId::uaddCarry_UInt2_UInt2_UInt2, + BuiltInName::uaddCarry, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D_o_1D_o_1D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpUaddCarry, + false); +constexpr const TFunction kFunction_uaddCarry_2D2D2D( + BuiltInId::uaddCarry_UInt3_UInt3_UInt3, + BuiltInName::uaddCarry, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D_o_2D_o_2D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpUaddCarry, + false); +constexpr const TFunction kFunction_uaddCarry_3D3D3D( + BuiltInId::uaddCarry_UInt4_UInt4_UInt4, + BuiltInName::uaddCarry, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D_o_3D_o_3D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpUaddCarry, + false); +constexpr const TFunction kFunction_usubBorrow_0D0D0D( + BuiltInId::usubBorrow_UInt1_UInt1_UInt1, + BuiltInName::usubBorrow, + TExtension::UNDEFINED, + BuiltInParameters::p0D0D_o_0D_o_0D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpUsubBorrow, + false); +constexpr const TFunction kFunction_usubBorrow_1D1D1D( + BuiltInId::usubBorrow_UInt2_UInt2_UInt2, + BuiltInName::usubBorrow, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D_o_1D_o_1D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpUsubBorrow, + false); +constexpr const TFunction kFunction_usubBorrow_2D2D2D( + BuiltInId::usubBorrow_UInt3_UInt3_UInt3, + BuiltInName::usubBorrow, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D_o_2D_o_2D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpUsubBorrow, + false); +constexpr const TFunction kFunction_usubBorrow_3D3D3D( + BuiltInId::usubBorrow_UInt4_UInt4_UInt4, + BuiltInName::usubBorrow, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D_o_3D_o_3D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpUsubBorrow, + false); +constexpr const TFunction kFunction_umulExtended_0D0D0D0D( + BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1, + BuiltInName::umulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p0D0D_o_0D_o_0D, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpUmulExtended, + false); +constexpr const TFunction kFunction_umulExtended_1D1D1D1D( + BuiltInId::umulExtended_UInt2_UInt2_UInt2_UInt2, + BuiltInName::umulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p1D1D_o_1D_o_1D, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpUmulExtended, + false); +constexpr const TFunction kFunction_umulExtended_2D2D2D2D( + BuiltInId::umulExtended_UInt3_UInt3_UInt3_UInt3, + BuiltInName::umulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p2D2D_o_2D_o_2D, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpUmulExtended, + false); +constexpr const TFunction kFunction_umulExtended_3D3D3D3D( + BuiltInId::umulExtended_UInt4_UInt4_UInt4_UInt4, + BuiltInName::umulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p3D3D_o_3D_o_3D, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpUmulExtended, + false); +constexpr const TFunction kFunction_imulExtended_0C0C0C0C( + BuiltInId::imulExtended_Int1_Int1_Int1_Int1, + BuiltInName::imulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p0C0C_o_0C_o_0C, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpImulExtended, + false); +constexpr const TFunction kFunction_imulExtended_1C1C1C1C( + BuiltInId::imulExtended_Int2_Int2_Int2_Int2, + BuiltInName::imulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p1C1C_o_1C_o_1C, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpImulExtended, + false); +constexpr const TFunction kFunction_imulExtended_2C2C2C2C( + BuiltInId::imulExtended_Int3_Int3_Int3_Int3, + BuiltInName::imulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p2C2C_o_2C_o_2C, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpImulExtended, + false); +constexpr const TFunction kFunction_imulExtended_3C3C3C3C( + BuiltInId::imulExtended_Int4_Int4_Int4_Int4, + BuiltInName::imulExtended, + TExtension::UNDEFINED, + BuiltInParameters::p3C3C_o_3C_o_3C, + 4, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpImulExtended, + false); +constexpr const TFunction kFunction_texture2D_0H1B( + BuiltInId::texture2D_Sampler2D1_Float2, + BuiltInName::texture2D, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1B1B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProj_0H2B( + BuiltInId::texture2DProj_Sampler2D1_Float3, + BuiltInName::texture2DProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProj_0H3B( + BuiltInId::texture2DProj_Sampler2D1_Float4, + BuiltInName::texture2DProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureCube_0J2B( + BuiltInId::textureCube_SamplerCube1_Float3, + BuiltInName::textureCube, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B2B2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2D_0L1B( + BuiltInId::texture2D_SamplerExternalOES1_Float2, + BuiltInName::texture2D, + TExtension::UNDEFINED, + BuiltInParameters::p0L1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProj_0L2B( + BuiltInId::texture2DProj_SamplerExternalOES1_Float3, + BuiltInName::texture2DProj, + TExtension::UNDEFINED, + BuiltInParameters::p0L2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProj_0L3B( + BuiltInId::texture2DProj_SamplerExternalOES1_Float4, + BuiltInName::texture2DProj, + TExtension::UNDEFINED, + BuiltInParameters::p0L3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DRect_0N1B( + BuiltInId::texture2DRect_Sampler2DRect1_Float2, + BuiltInName::texture2DRect, + TExtension::ARB_texture_rectangle, + BuiltInParameters::p0N1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DRectProj_0N2B( + BuiltInId::texture2DRectProj_Sampler2DRect1_Float3, + BuiltInName::texture2DRectProj, + TExtension::ARB_texture_rectangle, + BuiltInParameters::p0N2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DRectProj_0N3B( + BuiltInId::texture2DRectProj_Sampler2DRect1_Float4, + BuiltInName::texture2DRectProj, + TExtension::ARB_texture_rectangle, + BuiltInParameters::p0N3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0N1B( + BuiltInId::texture_Sampler2DRect1_Float2, + BuiltInName::texture, + TExtension::ARB_texture_rectangle, + BuiltInParameters::p0N1B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0N2B( + BuiltInId::textureProj_Sampler2DRect1_Float3, + BuiltInName::textureProj, + TExtension::ARB_texture_rectangle, + BuiltInParameters::p0N2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0N3B( + BuiltInId::textureProj_Sampler2DRect1_Float4, + BuiltInName::textureProj, + TExtension::ARB_texture_rectangle, + BuiltInParameters::p0N3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DGradEXT_0H1B1B1B( + BuiltInId::texture2DGradEXT_Sampler2D1_Float2_Float2_Float2, + BuiltInName::texture2DGradEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0H1B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProjGradEXT_0H2B1B1B( + BuiltInId::texture2DProjGradEXT_Sampler2D1_Float3_Float2_Float2, + BuiltInName::texture2DProjGradEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0H2B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProjGradEXT_0H3B1B1B( + BuiltInId::texture2DProjGradEXT_Sampler2D1_Float4_Float2_Float2, + BuiltInName::texture2DProjGradEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0H3B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureCubeGradEXT_0J2B2B2B( + BuiltInId::textureCubeGradEXT_SamplerCube1_Float3_Float3_Float3, + BuiltInName::textureCubeGradEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0J2B2B2B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2D_0H1B0B( + BuiltInId::texture2D_Sampler2D1_Float2_Float1, + BuiltInName::texture2D, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProj_0H2B0B( + BuiltInId::texture2DProj_Sampler2D1_Float3_Float1, + BuiltInName::texture2DProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProj_0H3B0B( + BuiltInId::texture2DProj_Sampler2D1_Float4_Float1, + BuiltInName::texture2DProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureCube_0J2B0B( + BuiltInId::textureCube_SamplerCube1_Float3_Float1, + BuiltInName::textureCube, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_dFdxExt_0B( + BuiltInId::dFdxExt_Float1, + BuiltInName::dFdxExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdxExt_1B( + BuiltInId::dFdxExt_Float2, + BuiltInName::dFdxExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdxExt_2B( + BuiltInId::dFdxExt_Float3, + BuiltInName::dFdxExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdxExt_3B( + BuiltInId::dFdxExt_Float4, + BuiltInName::dFdxExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdyExt_0B( + BuiltInId::dFdyExt_Float1, + BuiltInName::dFdyExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_dFdyExt_1B( + BuiltInId::dFdyExt_Float2, + BuiltInName::dFdyExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_dFdyExt_2B( + BuiltInId::dFdyExt_Float3, + BuiltInName::dFdyExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_dFdyExt_3B( + BuiltInId::dFdyExt_Float4, + BuiltInName::dFdyExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_fwidthExt_0B( + BuiltInId::fwidthExt_Float1, + BuiltInName::fwidthExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_fwidthExt_1B( + BuiltInId::fwidthExt_Float2, + BuiltInName::fwidthExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_fwidthExt_2B( + BuiltInId::fwidthExt_Float3, + BuiltInName::fwidthExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_fwidthExt_3B( + BuiltInId::fwidthExt_Float4, + BuiltInName::fwidthExt, + TExtension::OES_standard_derivatives, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_texture2DLodEXT_0H1B0B( + BuiltInId::texture2DLodEXT_Sampler2D1_Float2_Float1, + BuiltInName::texture2DLodEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0H1B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProjLodEXT_0H2B0B( + BuiltInId::texture2DProjLodEXT_Sampler2D1_Float3_Float1, + BuiltInName::texture2DProjLodEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0H2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProjLodEXT_0H3B0B( + BuiltInId::texture2DProjLodEXT_Sampler2D1_Float4_Float1, + BuiltInName::texture2DProjLodEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0H3B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureCubeLodEXT_0J2B0B( + BuiltInId::textureCubeLodEXT_SamplerCube1_Float3_Float1, + BuiltInName::textureCubeLodEXT, + TExtension::EXT_shader_texture_lod, + BuiltInParameters::p0J2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture3D_0I2B( + BuiltInId::texture3D_Sampler3D1_Float3, + BuiltInName::texture3D, + TExtension::OES_texture_3D, + BuiltInParameters::p0I2B0B2C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture3D_0I2B0B( + BuiltInId::texture3D_Sampler3D1_Float3_Float1, + BuiltInName::texture3D, + TExtension::OES_texture_3D, + BuiltInParameters::p0I2B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture3DProj_0I3B( + BuiltInId::texture3DProj_Sampler3D1_Float4, + BuiltInName::texture3DProj, + TExtension::OES_texture_3D, + BuiltInParameters::p0I3B2C0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture3DProj_0I3B0B( + BuiltInId::texture3DProj_Sampler3D1_Float4_Float1, + BuiltInName::texture3DProj, + TExtension::OES_texture_3D, + BuiltInParameters::p0I3B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture3DLod_0I2B0B( + BuiltInId::texture3DLod_Sampler3D1_Float3_Float1, + BuiltInName::texture3DLod, + TExtension::OES_texture_3D, + BuiltInParameters::p0I2B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture3DProjLod_0I3B0B( + BuiltInId::texture3DProjLod_Sampler3D1_Float4_Float1, + BuiltInName::texture3DProjLod, + TExtension::OES_texture_3D, + BuiltInParameters::p0I3B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DLod_0H1B0B( + BuiltInId::texture2DLod_Sampler2D1_Float2_Float1, + BuiltInName::texture2DLod, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProjLod_0H2B0B( + BuiltInId::texture2DProjLod_Sampler2D1_Float3_Float1, + BuiltInName::texture2DProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture2DProjLod_0H3B0B( + BuiltInId::texture2DProjLod_Sampler2D1_Float4_Float1, + BuiltInName::texture2DProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureCubeLod_0J2B0B( + BuiltInId::textureCubeLod_SamplerCube1_Float3_Float1, + BuiltInName::textureCubeLod, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0H1B( + BuiltInId::texture_Sampler2D1_Float2, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1B1B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0Q1B( + BuiltInId::texture_ISampler2D1_Float2, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1B1B1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0W1B( + BuiltInId::texture_USampler2D1_Float2, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0I2B( + BuiltInId::texture_Sampler3D1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B0B2C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0R2B( + BuiltInId::texture_ISampler3D1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B0B2C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0X2B( + BuiltInId::texture_USampler3D1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B0B2C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0J2B( + BuiltInId::texture_SamplerCube1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B2B2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0S2B( + BuiltInId::texture_ISamplerCube1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0S2B0B, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0Y2B( + BuiltInId::texture_USamplerCube1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0Y2B2B2B, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0K2B( + BuiltInId::texture_Sampler2DArray1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0T2B( + BuiltInId::texture_ISampler2DArray1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1B1B1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0Z2B( + BuiltInId::texture_USampler2DArray1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1B1B1C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0H2B( + BuiltInId::textureProj_Sampler2D1_Float3, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0Q2B( + BuiltInId::textureProj_ISampler2D1_Float3, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B1B1B1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0W2B( + BuiltInId::textureProj_USampler2D1_Float3, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B1C0B, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0H3B( + BuiltInId::textureProj_Sampler2D1_Float4, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0Q3B( + BuiltInId::textureProj_ISampler2D1_Float4, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B1B1B1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0W3B( + BuiltInId::textureProj_USampler2D1_Float4, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B1B1B1C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0I3B( + BuiltInId::textureProj_Sampler3D1_Float4, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B2C0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0R3B( + BuiltInId::textureProj_ISampler3D1_Float4, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B0B2C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0X3B( + BuiltInId::textureProj_USampler3D1_Float4, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B2B2B2C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0H1B0B( + BuiltInId::textureLod_Sampler2D1_Float2_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0Q1B0B( + BuiltInId::textureLod_ISampler2D1_Float2_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0W1B0B( + BuiltInId::textureLod_USampler2D1_Float2_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0I2B0B( + BuiltInId::textureLod_Sampler3D1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0R2B0B( + BuiltInId::textureLod_ISampler3D1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B0B2C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0X2B0B( + BuiltInId::textureLod_USampler3D1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B0B2C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0J2B0B( + BuiltInId::textureLod_SamplerCube1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0S2B0B( + BuiltInId::textureLod_ISamplerCube1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0S2B0B, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0Y2B0B( + BuiltInId::textureLod_USamplerCube1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0Y2B0B, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0K2B0B( + BuiltInId::textureLod_Sampler2DArray1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0T2B0B( + BuiltInId::textureLod_ISampler2DArray1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0Z2B0B( + BuiltInId::textureLod_USampler2DArray1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0c2B( + BuiltInId::texture_Sampler2DShadow1_Float3, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B1B1B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0d3B( + BuiltInId::texture_SamplerCubeShadow1_Float4, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0d3B2B2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0e3B( + BuiltInId::texture_Sampler2DArrayShadow1_Float4, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0e3B1B1B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0c3B( + BuiltInId::textureProj_Sampler2DShadow1_Float4, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLod_0c2B0B( + BuiltInId::textureLod_Sampler2DShadow1_Float3_Float1, + BuiltInName::textureLod, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0H0C( + BuiltInId::textureSize_Sampler2D1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0H0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0Q0C( + BuiltInId::textureSize_ISampler2D1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0Q0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0W0C( + BuiltInId::textureSize_USampler2D1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0W0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0I0C( + BuiltInId::textureSize_Sampler3D1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0I0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0R0C( + BuiltInId::textureSize_ISampler3D1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0R0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0X0C( + BuiltInId::textureSize_USampler3D1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0X0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0J0C( + BuiltInId::textureSize_SamplerCube1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0J0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0S0C( + BuiltInId::textureSize_ISamplerCube1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0S0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0Y0C( + BuiltInId::textureSize_USamplerCube1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0Y0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0K0C( + BuiltInId::textureSize_Sampler2DArray1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0K0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0T0C( + BuiltInId::textureSize_ISampler2DArray1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0T0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0Z0C( + BuiltInId::textureSize_USampler2DArray1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0Z0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0c0C( + BuiltInId::textureSize_Sampler2DShadow1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0c0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0d0C( + BuiltInId::textureSize_SamplerCubeShadow1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0d0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0e0C( + BuiltInId::textureSize_Sampler2DArrayShadow1_Int1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0e0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0H2B0B( + BuiltInId::textureProjLod_Sampler2D1_Float3_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0Q2B0B( + BuiltInId::textureProjLod_ISampler2D1_Float3_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0W2B0B( + BuiltInId::textureProjLod_USampler2D1_Float3_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0H3B0B( + BuiltInId::textureProjLod_Sampler2D1_Float4_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0Q3B0B( + BuiltInId::textureProjLod_ISampler2D1_Float4_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0W3B0B( + BuiltInId::textureProjLod_USampler2D1_Float4_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0I3B0B( + BuiltInId::textureProjLod_Sampler3D1_Float4_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0R3B0B( + BuiltInId::textureProjLod_ISampler3D1_Float4_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B0B2C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0X3B0B( + BuiltInId::textureProjLod_USampler3D1_Float4_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B0B2C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLod_0c3B0B( + BuiltInId::textureProjLod_Sampler2DShadow1_Float4_Float1, + BuiltInName::textureProjLod, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0H1C0C( + BuiltInId::texelFetch_Sampler2D1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0H1C0C1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0Q1C0C( + BuiltInId::texelFetch_ISampler2D1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1C0C1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0W1C0C( + BuiltInId::texelFetch_USampler2D1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0W1C0C1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0I2C0C( + BuiltInId::texelFetch_Sampler3D1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0I2C0C2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0R2C0C( + BuiltInId::texelFetch_ISampler3D1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0R2C0C2C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0X2C0C( + BuiltInId::texelFetch_USampler3D1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0X2C0C2C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0K2C0C( + BuiltInId::texelFetch_Sampler2DArray1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0K2C0C1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0T2C0C( + BuiltInId::texelFetch_ISampler2DArray1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0T2C0C1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0Z2C0C( + BuiltInId::texelFetch_USampler2DArray1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2C0C1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0H1B1B1B( + BuiltInId::textureGrad_Sampler2D1_Float2_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0Q1B1B1B( + BuiltInId::textureGrad_ISampler2D1_Float2_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1B1B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0W1B1B1B( + BuiltInId::textureGrad_USampler2D1_Float2_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1B1B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0I2B2B2B( + BuiltInId::textureGrad_Sampler3D1_Float3_Float3_Float3, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B2B2B2C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0R2B2B2B( + BuiltInId::textureGrad_ISampler3D1_Float3_Float3_Float3, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B2B2B2C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0X2B2B2B( + BuiltInId::textureGrad_USampler3D1_Float3_Float3_Float3, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B2B2B2C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0J2B2B2B( + BuiltInId::textureGrad_SamplerCube1_Float3_Float3_Float3, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B2B2B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0S2B2B2B( + BuiltInId::textureGrad_ISamplerCube1_Float3_Float3_Float3, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0S2B2B2B, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0Y2B2B2B( + BuiltInId::textureGrad_USamplerCube1_Float3_Float3_Float3, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0Y2B2B2B, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0c2B1B1B( + BuiltInId::textureGrad_Sampler2DShadow1_Float3_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0d3B2B2B( + BuiltInId::textureGrad_SamplerCubeShadow1_Float4_Float3_Float3, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0d3B2B2B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0K2B1B1B( + BuiltInId::textureGrad_Sampler2DArray1_Float3_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0T2B1B1B( + BuiltInId::textureGrad_ISampler2DArray1_Float3_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1B1B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0Z2B1B1B( + BuiltInId::textureGrad_USampler2DArray1_Float3_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1B1B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGrad_0e3B1B1B( + BuiltInId::textureGrad_Sampler2DArrayShadow1_Float4_Float2_Float2, + BuiltInName::textureGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0e3B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0H2B1B1B( + BuiltInId::textureProjGrad_Sampler2D1_Float3_Float2_Float2, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0Q2B1B1B( + BuiltInId::textureProjGrad_ISampler2D1_Float3_Float2_Float2, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B1B1B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0W2B1B1B( + BuiltInId::textureProjGrad_USampler2D1_Float3_Float2_Float2, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B1B1B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0H3B1B1B( + BuiltInId::textureProjGrad_Sampler2D1_Float4_Float2_Float2, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0Q3B1B1B( + BuiltInId::textureProjGrad_ISampler2D1_Float4_Float2_Float2, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B1B1B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0W3B1B1B( + BuiltInId::textureProjGrad_USampler2D1_Float4_Float2_Float2, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B1B1B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0I3B2B2B( + BuiltInId::textureProjGrad_Sampler3D1_Float4_Float3_Float3, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B2B2B2C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0R3B2B2B( + BuiltInId::textureProjGrad_ISampler3D1_Float4_Float3_Float3, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B2B2B2C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0X3B2B2B( + BuiltInId::textureProjGrad_USampler3D1_Float4_Float3_Float3, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B2B2B2C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGrad_0c3B1B1B( + BuiltInId::textureProjGrad_Sampler2DShadow1_Float4_Float2_Float2, + BuiltInName::textureProjGrad, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B1B1B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0O( + BuiltInId::textureSize_Sampler2DMS1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0O1C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0U( + BuiltInId::textureSize_ISampler2DMS1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0U1C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0a( + BuiltInId::textureSize_USampler2DMS1, + BuiltInName::textureSize, + TExtension::UNDEFINED, + BuiltInParameters::p0a1C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSizeExt_0O( + BuiltInId::textureSizeExt_Sampler2DMS1, + BuiltInName::textureSizeExt, + TExtension::ANGLE_texture_multisample, + BuiltInParameters::p0O1C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSizeExt_0U( + BuiltInId::textureSizeExt_ISampler2DMS1, + BuiltInName::textureSizeExt, + TExtension::ANGLE_texture_multisample, + BuiltInParameters::p0U1C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSizeExt_0a( + BuiltInId::textureSizeExt_USampler2DMS1, + BuiltInName::textureSizeExt, + TExtension::ANGLE_texture_multisample, + BuiltInParameters::p0a1C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0P( + BuiltInId::textureSize_Sampler2DMSArray1, + BuiltInName::textureSize, + TExtension::OES_texture_storage_multisample_2d_array, + BuiltInParameters::p0P2C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0V( + BuiltInId::textureSize_ISampler2DMSArray1, + BuiltInName::textureSize, + TExtension::OES_texture_storage_multisample_2d_array, + BuiltInParameters::p0V2C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0b( + BuiltInId::textureSize_USampler2DMSArray1, + BuiltInName::textureSize, + TExtension::OES_texture_storage_multisample_2d_array, + BuiltInParameters::p0b2C0C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0H1B1C( + BuiltInId::textureOffset_Sampler2D1_Float2_Int2, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0Q1B1C( + BuiltInId::textureOffset_ISampler2D1_Float2_Int2, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0W1B1C( + BuiltInId::textureOffset_USampler2D1_Float2_Int2, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0I2B2C( + BuiltInId::textureOffset_Sampler3D1_Float3_Int3, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B2C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0R2B2C( + BuiltInId::textureOffset_ISampler3D1_Float3_Int3, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B2C0B, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0X2B2C( + BuiltInId::textureOffset_USampler3D1_Float3_Int3, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B2C0B, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0c2B1C( + BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B1C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0K2B1C( + BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B1C0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0T2B1C( + BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0Z2B1C( + BuiltInId::textureOffset_USampler2DArray1_Float3_Int2, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0H2B1C( + BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B1C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0Q2B1C( + BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B1C0B, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0W2B1C( + BuiltInId::textureProjOffset_USampler2D1_Float3_Int2, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B1C0B, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0H3B1C( + BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B1C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0Q3B1C( + BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B1C0B, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0W3B1C( + BuiltInId::textureProjOffset_USampler2D1_Float4_Int2, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B1C0B, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0I3B2C( + BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B2C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0R3B2C( + BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B2C0B, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0X3B2C( + BuiltInId::textureProjOffset_USampler3D1_Float4_Int3, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B2C0B, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0c3B1C( + BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B1C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0H1B0B1C( + BuiltInId::textureLodOffset_Sampler2D1_Float2_Float1_Int2, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0Q1B0B1C( + BuiltInId::textureLodOffset_ISampler2D1_Float2_Float1_Int2, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B0B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0W1B0B1C( + BuiltInId::textureLodOffset_USampler2D1_Float2_Float1_Int2, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B0B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0I2B0B2C( + BuiltInId::textureLodOffset_Sampler3D1_Float3_Float1_Int3, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B0B2C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0R2B0B2C( + BuiltInId::textureLodOffset_ISampler3D1_Float3_Float1_Int3, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B0B2C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0X2B0B2C( + BuiltInId::textureLodOffset_USampler3D1_Float3_Float1_Int3, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B0B2C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0c2B0B1C( + BuiltInId::textureLodOffset_Sampler2DShadow1_Float3_Float1_Int2, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0K2B0B1C( + BuiltInId::textureLodOffset_Sampler2DArray1_Float3_Float1_Int2, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0T2B0B1C( + BuiltInId::textureLodOffset_ISampler2DArray1_Float3_Float1_Int2, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B0B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureLodOffset_0Z2B0B1C( + BuiltInId::textureLodOffset_USampler2DArray1_Float3_Float1_Int2, + BuiltInName::textureLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B0B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0H2B0B1C( + BuiltInId::textureProjLodOffset_Sampler2D1_Float3_Float1_Int2, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0Q2B0B1C( + BuiltInId::textureProjLodOffset_ISampler2D1_Float3_Float1_Int2, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B0B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0W2B0B1C( + BuiltInId::textureProjLodOffset_USampler2D1_Float3_Float1_Int2, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B0B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0H3B0B1C( + BuiltInId::textureProjLodOffset_Sampler2D1_Float4_Float1_Int2, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0Q3B0B1C( + BuiltInId::textureProjLodOffset_ISampler2D1_Float4_Float1_Int2, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B0B1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0W3B0B1C( + BuiltInId::textureProjLodOffset_USampler2D1_Float4_Float1_Int2, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B0B1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0I3B0B2C( + BuiltInId::textureProjLodOffset_Sampler3D1_Float4_Float1_Int3, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B0B2C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0R3B0B2C( + BuiltInId::textureProjLodOffset_ISampler3D1_Float4_Float1_Int3, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B0B2C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0X3B0B2C( + BuiltInId::textureProjLodOffset_USampler3D1_Float4_Float1_Int3, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B0B2C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjLodOffset_0c3B0B1C( + BuiltInId::textureProjLodOffset_Sampler2DShadow1_Float4_Float1_Int2, + BuiltInName::textureProjLodOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0H1C0C1C( + BuiltInId::texelFetchOffset_Sampler2D1_Int2_Int1_Int2, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H1C0C1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0Q1C0C1C( + BuiltInId::texelFetchOffset_ISampler2D1_Int2_Int1_Int2, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1C0C1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0W1C0C1C( + BuiltInId::texelFetchOffset_USampler2D1_Int2_Int1_Int2, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W1C0C1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0I2C0C2C( + BuiltInId::texelFetchOffset_Sampler3D1_Int3_Int1_Int3, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I2C0C2C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0R2C0C2C( + BuiltInId::texelFetchOffset_ISampler3D1_Int3_Int1_Int3, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R2C0C2C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0X2C0C2C( + BuiltInId::texelFetchOffset_USampler3D1_Int3_Int1_Int3, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X2C0C2C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0K2C0C1C( + BuiltInId::texelFetchOffset_Sampler2DArray1_Int3_Int1_Int2, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0K2C0C1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0T2C0C1C( + BuiltInId::texelFetchOffset_ISampler2DArray1_Int3_Int1_Int2, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0T2C0C1C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchOffset_0Z2C0C1C( + BuiltInId::texelFetchOffset_USampler2DArray1_Int3_Int1_Int2, + BuiltInName::texelFetchOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2C0C1C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0H1B1B1B1C( + BuiltInId::textureGradOffset_Sampler2D1_Float2_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1B1B1C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0Q1B1B1B1C( + BuiltInId::textureGradOffset_ISampler2D1_Float2_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1B1B1C, + 5, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0W1B1B1B1C( + BuiltInId::textureGradOffset_USampler2D1_Float2_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1B1B1C, + 5, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0I2B2B2B2C( + BuiltInId::textureGradOffset_Sampler3D1_Float3_Float3_Float3_Int3, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B2B2B2C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0R2B2B2B2C( + BuiltInId::textureGradOffset_ISampler3D1_Float3_Float3_Float3_Int3, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B2B2B2C, + 5, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0X2B2B2B2C( + BuiltInId::textureGradOffset_USampler3D1_Float3_Float3_Float3_Int3, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B2B2B2C, + 5, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0c2B1B1B1C( + BuiltInId::textureGradOffset_Sampler2DShadow1_Float3_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B1B1B1C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0K2B1B1B1C( + BuiltInId::textureGradOffset_Sampler2DArray1_Float3_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B1B1B1C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0T2B1B1B1C( + BuiltInId::textureGradOffset_ISampler2DArray1_Float3_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1B1B1C, + 5, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0Z2B1B1B1C( + BuiltInId::textureGradOffset_USampler2DArray1_Float3_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1B1B1C, + 5, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGradOffset_0e3B1B1B1C( + BuiltInId::textureGradOffset_Sampler2DArrayShadow1_Float4_Float2_Float2_Int2, + BuiltInName::textureGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0e3B1B1B1C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0H2B1B1B1C( + BuiltInId::textureProjGradOffset_Sampler2D1_Float3_Float2_Float2_Int2, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B1B1B1C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0Q2B1B1B1C( + BuiltInId::textureProjGradOffset_ISampler2D1_Float3_Float2_Float2_Int2, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B1B1B1C, + 5, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0W2B1B1B1C( + BuiltInId::textureProjGradOffset_USampler2D1_Float3_Float2_Float2_Int2, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B1B1B1C, + 5, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0H3B1B1B1C( + BuiltInId::textureProjGradOffset_Sampler2D1_Float4_Float2_Float2_Int2, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B1B1B1C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0Q3B1B1B1C( + BuiltInId::textureProjGradOffset_ISampler2D1_Float4_Float2_Float2_Int2, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B1B1B1C, + 5, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0W3B1B1B1C( + BuiltInId::textureProjGradOffset_USampler2D1_Float4_Float2_Float2_Int2, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B1B1B1C, + 5, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0I3B2B2B2C( + BuiltInId::textureProjGradOffset_Sampler3D1_Float4_Float3_Float3_Int3, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B2B2B2C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0R3B2B2B2C( + BuiltInId::textureProjGradOffset_ISampler3D1_Float4_Float3_Float3_Int3, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B2B2B2C, + 5, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0X3B2B2B2C( + BuiltInId::textureProjGradOffset_USampler3D1_Float4_Float3_Float3_Int3, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B2B2B2C, + 5, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjGradOffset_0c3B1B1B1C( + BuiltInId::textureProjGradOffset_Sampler2DShadow1_Float4_Float2_Float2_Int2, + BuiltInName::textureProjGradOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B1B1B1C, + 5, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0H1B1C0B( + BuiltInId::textureOffset_Sampler2D1_Float2_Int2_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0Q1B1C0B( + BuiltInId::textureOffset_ISampler2D1_Float2_Int2_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1C0B, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0W1B1C0B( + BuiltInId::textureOffset_USampler2D1_Float2_Int2_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1C0B, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0I2B2C0B( + BuiltInId::textureOffset_Sampler3D1_Float3_Int3_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B2C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0R2B2C0B( + BuiltInId::textureOffset_ISampler3D1_Float3_Int3_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B2C0B, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0X2B2C0B( + BuiltInId::textureOffset_USampler3D1_Float3_Int3_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B2C0B, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0c2B1C0B( + BuiltInId::textureOffset_Sampler2DShadow1_Float3_Int2_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B1C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0K2B1C0B( + BuiltInId::textureOffset_Sampler2DArray1_Float3_Int2_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B1C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0T2B1C0B( + BuiltInId::textureOffset_ISampler2DArray1_Float3_Int2_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1C0B, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureOffset_0Z2B1C0B( + BuiltInId::textureOffset_USampler2DArray1_Float3_Int2_Float1, + BuiltInName::textureOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1C0B, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0H2B1C0B( + BuiltInId::textureProjOffset_Sampler2D1_Float3_Int2_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B1C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0Q2B1C0B( + BuiltInId::textureProjOffset_ISampler2D1_Float3_Int2_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B1C0B, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0W2B1C0B( + BuiltInId::textureProjOffset_USampler2D1_Float3_Int2_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B1C0B, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0H3B1C0B( + BuiltInId::textureProjOffset_Sampler2D1_Float4_Int2_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B1C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0Q3B1C0B( + BuiltInId::textureProjOffset_ISampler2D1_Float4_Int2_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B1C0B, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0W3B1C0B( + BuiltInId::textureProjOffset_USampler2D1_Float4_Int2_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B1C0B, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0I3B2C0B( + BuiltInId::textureProjOffset_Sampler3D1_Float4_Int3_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B2C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0R3B2C0B( + BuiltInId::textureProjOffset_ISampler3D1_Float4_Int3_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B2C0B, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0X3B2C0B( + BuiltInId::textureProjOffset_USampler3D1_Float4_Int3_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B2C0B, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProjOffset_0c3B1C0B( + BuiltInId::textureProjOffset_Sampler2DShadow1_Float4_Int2_Float1, + BuiltInName::textureProjOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B1C0B, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0L1B( + BuiltInId::texture_SamplerExternalOES1_Float2, + BuiltInName::texture, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0L2B( + BuiltInId::textureProj_SamplerExternalOES1_Float3, + BuiltInName::textureProj, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0L3B( + BuiltInId::textureProj_SamplerExternalOES1_Float4, + BuiltInName::textureProj, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0L0C( + BuiltInId::textureSize_SamplerExternalOES1_Int1, + BuiltInName::textureSize, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0L1C0C( + BuiltInId::texelFetch_SamplerExternalOES1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L1C0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0M1B( + BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2, + BuiltInName::texture, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M1B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0M2B( + BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3, + BuiltInName::textureProj, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0M3B( + BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4, + BuiltInName::textureProj, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M3B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_rgb_2_yuv_2B0G( + BuiltInId::rgb_2_yuv_Float3_YuvCscStandardEXT1, + BuiltInName::rgb_2_yuv, + TExtension::EXT_YUV_target, + BuiltInParameters::p2B0G, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_yuv_2_rgb_2B0G( + BuiltInId::yuv_2_rgb_Float3_YuvCscStandardEXT1, + BuiltInName::yuv_2_rgb, + TExtension::EXT_YUV_target, + BuiltInParameters::p2B0G, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureSize_0M0C( + BuiltInId::textureSize_SamplerExternal2DY2YEXT1_Int1, + BuiltInName::textureSize, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0M1C0C( + BuiltInId::texelFetch_SamplerExternal2DY2YEXT1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M1C0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0H1B0B( + BuiltInId::texture_Sampler2D1_Float2_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0Q1B0B( + BuiltInId::texture_ISampler2D1_Float2_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0W1B0B( + BuiltInId::texture_USampler2D1_Float2_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0I2B0B( + BuiltInId::texture_Sampler3D1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0I2B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0R2B0B( + BuiltInId::texture_ISampler3D1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0R2B0B2C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0X2B0B( + BuiltInId::texture_USampler3D1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0X2B0B2C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0J2B0B( + BuiltInId::texture_SamplerCube1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0S2B0B( + BuiltInId::texture_ISamplerCube1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0S2B0B, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0Y2B0B( + BuiltInId::texture_USamplerCube1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0Y2B0B, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0K2B0B( + BuiltInId::texture_Sampler2DArray1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0T2B0B( + BuiltInId::texture_ISampler2DArray1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0Z2B0B( + BuiltInId::texture_USampler2DArray1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0H2B0B( + BuiltInId::textureProj_Sampler2D1_Float3_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0Q2B0B( + BuiltInId::textureProj_ISampler2D1_Float3_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0Q2B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0W2B0B( + BuiltInId::textureProj_USampler2D1_Float3_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0W2B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0H3B0B( + BuiltInId::textureProj_Sampler2D1_Float4_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0H3B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0Q3B0B( + BuiltInId::textureProj_ISampler2D1_Float4_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0Q3B0B1C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0W3B0B( + BuiltInId::textureProj_USampler2D1_Float4_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0W3B0B1C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0I3B0B( + BuiltInId::textureProj_Sampler3D1_Float4_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0I3B0B2C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0R3B0B( + BuiltInId::textureProj_ISampler3D1_Float4_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0R3B0B2C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0X3B0B( + BuiltInId::textureProj_USampler3D1_Float4_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0X3B0B2C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0c2B0B( + BuiltInId::texture_Sampler2DShadow1_Float3_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0c2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0d3B0B( + BuiltInId::texture_SamplerCubeShadow1_Float4_Float1, + BuiltInName::texture, + TExtension::UNDEFINED, + BuiltInParameters::p0d3B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0c3B0B( + BuiltInId::textureProj_Sampler2DShadow1_Float4_Float1, + BuiltInName::textureProj, + TExtension::UNDEFINED, + BuiltInParameters::p0c3B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0L1B0B( + BuiltInId::texture_SamplerExternalOES1_Float2_Float1, + BuiltInName::texture, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L1B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0L2B0B( + BuiltInId::textureProj_SamplerExternalOES1_Float3_Float1, + BuiltInName::textureProj, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0L3B0B( + BuiltInId::textureProj_SamplerExternalOES1_Float4_Float1, + BuiltInName::textureProj, + TExtension::OES_EGL_image_external_essl3, + BuiltInParameters::p0L3B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texture_0M1B0B( + BuiltInId::texture_SamplerExternal2DY2YEXT1_Float2_Float1, + BuiltInName::texture, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M1B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0M2B0B( + BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float3_Float1, + BuiltInName::textureProj, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureProj_0M3B0B( + BuiltInId::textureProj_SamplerExternal2DY2YEXT1_Float4_Float1, + BuiltInName::textureProj, + TExtension::EXT_YUV_target, + BuiltInParameters::p0M3B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0O1C0C( + BuiltInId::texelFetch_Sampler2DMS1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0O1C0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0U1C0C( + BuiltInId::texelFetch_ISampler2DMS1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0U1C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0a1C0C( + BuiltInId::texelFetch_USampler2DMS1_Int2_Int1, + BuiltInName::texelFetch, + TExtension::UNDEFINED, + BuiltInParameters::p0a1C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchExt_0O1C0C( + BuiltInId::texelFetchExt_Sampler2DMS1_Int2_Int1, + BuiltInName::texelFetchExt, + TExtension::ANGLE_texture_multisample, + BuiltInParameters::p0O1C0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchExt_0U1C0C( + BuiltInId::texelFetchExt_ISampler2DMS1_Int2_Int1, + BuiltInName::texelFetchExt, + TExtension::ANGLE_texture_multisample, + BuiltInParameters::p0U1C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetchExt_0a1C0C( + BuiltInId::texelFetchExt_USampler2DMS1_Int2_Int1, + BuiltInName::texelFetchExt, + TExtension::ANGLE_texture_multisample, + BuiltInParameters::p0a1C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0P2C0C( + BuiltInId::texelFetch_Sampler2DMSArray1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::OES_texture_storage_multisample_2d_array, + BuiltInParameters::p0P2C0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0V2C0C( + BuiltInId::texelFetch_ISampler2DMSArray1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::OES_texture_storage_multisample_2d_array, + BuiltInParameters::p0V2C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_texelFetch_0b2C0C( + BuiltInId::texelFetch_USampler2DMSArray1_Int3_Int1, + BuiltInName::texelFetch, + TExtension::OES_texture_storage_multisample_2d_array, + BuiltInParameters::p0b2C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0H1B( + BuiltInId::textureGather_Sampler2D1_Float2, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1B1B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0Q1B( + BuiltInId::textureGather_ISampler2D1_Float2, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1B1B1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0W1B( + BuiltInId::textureGather_USampler2D1_Float2, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1C0C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0H1B0C( + BuiltInId::textureGather_Sampler2D1_Float2_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0Q1B0C( + BuiltInId::textureGather_ISampler2D1_Float2_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0W1B0C( + BuiltInId::textureGather_USampler2D1_Float2_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0K2B( + BuiltInId::textureGather_Sampler2DArray1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0T2B( + BuiltInId::textureGather_ISampler2DArray1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1B1B1C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0Z2B( + BuiltInId::textureGather_USampler2DArray1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1B1B1C, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0K2B0C( + BuiltInId::textureGather_Sampler2DArray1_Float3_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0T2B0C( + BuiltInId::textureGather_ISampler2DArray1_Float3_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0Z2B0C( + BuiltInId::textureGather_USampler2DArray1_Float3_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0J2B( + BuiltInId::textureGather_SamplerCube1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B2B2B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0S2B( + BuiltInId::textureGather_ISamplerCube1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0S2B0B, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0Y2B( + BuiltInId::textureGather_USamplerCube1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0Y2B2B2B, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0J2B0C( + BuiltInId::textureGather_SamplerCube1_Float3_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0J2B0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0S2B0C( + BuiltInId::textureGather_ISamplerCube1_Float3_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0S2B0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0Y2B0C( + BuiltInId::textureGather_USamplerCube1_Float3_Int1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0Y2B0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0c1B( + BuiltInId::textureGather_Sampler2DShadow1_Float2, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0c1B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0c1B0B( + BuiltInId::textureGather_Sampler2DShadow1_Float2_Float1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0c1B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0e2B( + BuiltInId::textureGather_Sampler2DArrayShadow1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0e2B0B1C, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0e2B0B( + BuiltInId::textureGather_Sampler2DArrayShadow1_Float3_Float1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0e2B0B1C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0d2B( + BuiltInId::textureGather_SamplerCubeShadow1_Float3, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0d2B0B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGather_0d2B0B( + BuiltInId::textureGather_SamplerCubeShadow1_Float3_Float1, + BuiltInName::textureGather, + TExtension::UNDEFINED, + BuiltInParameters::p0d2B0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0H1B1C( + BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1C0B, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0Q1B1C( + BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0W1B1C( + BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0H1B1C0C( + BuiltInId::textureGatherOffset_Sampler2D1_Float2_Int2_Int1, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0H1B1C0C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0Q1B1C0C( + BuiltInId::textureGatherOffset_ISampler2D1_Float2_Int2_Int1, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Q1B1C0C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0W1B1C0C( + BuiltInId::textureGatherOffset_USampler2D1_Float2_Int2_Int1, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0W1B1C0C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0K2B1C( + BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B1C0C, + 3, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0T2B1C( + BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0Z2B1C( + BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1C0C, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0K2B1C0C( + BuiltInId::textureGatherOffset_Sampler2DArray1_Float3_Int2_Int1, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0K2B1C0C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0T2B1C0C( + BuiltInId::textureGatherOffset_ISampler2DArray1_Float3_Int2_Int1, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0T2B1C0C, + 4, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0Z2B1C0C( + BuiltInId::textureGatherOffset_USampler2DArray1_Float3_Int2_Int1, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0Z2B1C0C, + 4, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0c1B0B1C( + BuiltInId::textureGatherOffset_Sampler2DShadow1_Float2_Float1_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0c1B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_textureGatherOffset_0e2B0B1C( + BuiltInId::textureGatherOffset_Sampler2DArrayShadow1_Float3_Float1_Int2, + BuiltInName::textureGatherOffset, + TExtension::UNDEFINED, + BuiltInParameters::p0e2B0B1C, + 4, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_dFdx_0B( + BuiltInId::dFdx_Float1, + BuiltInName::dFdx, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdx_1B( + BuiltInId::dFdx_Float2, + BuiltInName::dFdx, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdx_2B( + BuiltInId::dFdx_Float3, + BuiltInName::dFdx, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdx_3B( + BuiltInId::dFdx_Float4, + BuiltInName::dFdx, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpDFdx, + false); +constexpr const TFunction kFunction_dFdy_0B( + BuiltInId::dFdy_Float1, + BuiltInName::dFdy, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_dFdy_1B( + BuiltInId::dFdy_Float2, + BuiltInName::dFdy, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_dFdy_2B( + BuiltInId::dFdy_Float3, + BuiltInName::dFdy, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_dFdy_3B( + BuiltInId::dFdy_Float4, + BuiltInName::dFdy, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpDFdy, + false); +constexpr const TFunction kFunction_fwidth_0B( + BuiltInId::fwidth_Float1, + BuiltInName::fwidth, + TExtension::UNDEFINED, + BuiltInParameters::p0B0C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 1, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_fwidth_1B( + BuiltInId::fwidth_Float2, + BuiltInName::fwidth, + TExtension::UNDEFINED, + BuiltInParameters::p1B1B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 2, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_fwidth_2B( + BuiltInId::fwidth_Float3, + BuiltInName::fwidth, + TExtension::UNDEFINED, + BuiltInParameters::p2B_o_2C, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 3, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_fwidth_3B( + BuiltInId::fwidth_Float4, + BuiltInName::fwidth, + TExtension::UNDEFINED, + BuiltInParameters::p3B0B0B, + 1, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpFwidth, + false); +constexpr const TFunction kFunction_atomicCounter_0F( + BuiltInId::atomicCounter_AtomicCounter1, + BuiltInName::atomicCounter, + TExtension::UNDEFINED, + BuiltInParameters::p0F, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_atomicCounterIncrement_0F( + BuiltInId::atomicCounterIncrement_AtomicCounter1, + BuiltInName::atomicCounterIncrement, + TExtension::UNDEFINED, + BuiltInParameters::p0F, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_atomicCounterDecrement_0F( + BuiltInId::atomicCounterDecrement_AtomicCounter1, + BuiltInName::atomicCounterDecrement, + TExtension::UNDEFINED, + BuiltInParameters::p0F, + 1, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_atomicAdd_0D0D( + BuiltInId::atomicAdd_UInt1_UInt1, + BuiltInName::atomicAdd, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicAdd, + false); +constexpr const TFunction kFunction_atomicAdd_0C0C( + BuiltInId::atomicAdd_Int1_Int1, + BuiltInName::atomicAdd, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicAdd, + false); +constexpr const TFunction kFunction_atomicMin_0D0D( + BuiltInId::atomicMin_UInt1_UInt1, + BuiltInName::atomicMin, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicMin, + false); +constexpr const TFunction kFunction_atomicMin_0C0C( + BuiltInId::atomicMin_Int1_Int1, + BuiltInName::atomicMin, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicMin, + false); +constexpr const TFunction kFunction_atomicMax_0D0D( + BuiltInId::atomicMax_UInt1_UInt1, + BuiltInName::atomicMax, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicMax, + false); +constexpr const TFunction kFunction_atomicMax_0C0C( + BuiltInId::atomicMax_Int1_Int1, + BuiltInName::atomicMax, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicMax, + false); +constexpr const TFunction kFunction_atomicAnd_0D0D( + BuiltInId::atomicAnd_UInt1_UInt1, + BuiltInName::atomicAnd, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicAnd, + false); +constexpr const TFunction kFunction_atomicAnd_0C0C( + BuiltInId::atomicAnd_Int1_Int1, + BuiltInName::atomicAnd, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicAnd, + false); +constexpr const TFunction kFunction_atomicOr_0D0D( + BuiltInId::atomicOr_UInt1_UInt1, + BuiltInName::atomicOr, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicOr, + false); +constexpr const TFunction kFunction_atomicOr_0C0C( + BuiltInId::atomicOr_Int1_Int1, + BuiltInName::atomicOr, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicOr, + false); +constexpr const TFunction kFunction_atomicXor_0D0D( + BuiltInId::atomicXor_UInt1_UInt1, + BuiltInName::atomicXor, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicXor, + false); +constexpr const TFunction kFunction_atomicXor_0C0C( + BuiltInId::atomicXor_Int1_Int1, + BuiltInName::atomicXor, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicXor, + false); +constexpr const TFunction kFunction_atomicExchange_0D0D( + BuiltInId::atomicExchange_UInt1_UInt1, + BuiltInName::atomicExchange, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicExchange, + false); +constexpr const TFunction kFunction_atomicExchange_0C0C( + BuiltInId::atomicExchange_Int1_Int1, + BuiltInName::atomicExchange, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicExchange, + false); +constexpr const TFunction kFunction_atomicCompSwap_0D0D0D( + BuiltInId::atomicCompSwap_UInt1_UInt1_UInt1, + BuiltInName::atomicCompSwap, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0D0D0D, + 3, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicCompSwap, + false); +constexpr const TFunction kFunction_atomicCompSwap_0C0C0C( + BuiltInId::atomicCompSwap_Int1_Int1_Int1, + BuiltInName::atomicCompSwap, + TExtension::UNDEFINED, + BuiltInParameters::p_io_0C0C0C, + 3, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 1, 1>(), + EOpAtomicCompSwap, + false); +constexpr const TFunction kFunction_imageSize_0f( + BuiltInId::imageSize_Image2D1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0f1C3B, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0g( + BuiltInId::imageSize_IImage2D1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0g1C3C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0h( + BuiltInId::imageSize_UImage2D1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0h1C3D, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0i( + BuiltInId::imageSize_Image3D1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0i2C3B, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0j( + BuiltInId::imageSize_IImage3D1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0j2C3C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0k( + BuiltInId::imageSize_UImage3D1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0k2C3D, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0l( + BuiltInId::imageSize_Image2DArray1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0l2C3B, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0m( + BuiltInId::imageSize_IImage2DArray1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0m2C3C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0n( + BuiltInId::imageSize_UImage2DArray1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0n2C3D, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 3, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0o( + BuiltInId::imageSize_ImageCube1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0o2C3B, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0p( + BuiltInId::imageSize_IImageCube1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0p2C3C, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageSize_0q( + BuiltInId::imageSize_UImageCube1, + BuiltInName::imageSize, + TExtension::UNDEFINED, + BuiltInParameters::p0q2C3D, + 1, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 2, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0f1C( + BuiltInId::imageLoad_Image2D1_Int2, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0f1C3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0g1C( + BuiltInId::imageLoad_IImage2D1_Int2, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0g1C3C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0h1C( + BuiltInId::imageLoad_UImage2D1_Int2, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0h1C3D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0i2C( + BuiltInId::imageLoad_Image3D1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0i2C3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0j2C( + BuiltInId::imageLoad_IImage3D1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0j2C3C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0k2C( + BuiltInId::imageLoad_UImage3D1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0k2C3D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0l2C( + BuiltInId::imageLoad_Image2DArray1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0l2C3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0m2C( + BuiltInId::imageLoad_IImage2DArray1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0m2C3C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0n2C( + BuiltInId::imageLoad_UImage2DArray1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0n2C3D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0o2C( + BuiltInId::imageLoad_ImageCube1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0o2C3B, + 2, + StaticType::Get<EbtFloat, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0p2C( + BuiltInId::imageLoad_IImageCube1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0p2C3C, + 2, + StaticType::Get<EbtInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageLoad_0q2C( + BuiltInId::imageLoad_UImageCube1_Int3, + BuiltInName::imageLoad, + TExtension::UNDEFINED, + BuiltInParameters::p0q2C3D, + 2, + StaticType::Get<EbtUInt, EbpUndefined, EvqGlobal, 4, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0f1C3B( + BuiltInId::imageStore_Image2D1_Int2_Float4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0f1C3B, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0g1C3C( + BuiltInId::imageStore_IImage2D1_Int2_Int4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0g1C3C, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0h1C3D( + BuiltInId::imageStore_UImage2D1_Int2_UInt4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0h1C3D, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0i2C3B( + BuiltInId::imageStore_Image3D1_Int3_Float4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0i2C3B, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0j2C3C( + BuiltInId::imageStore_IImage3D1_Int3_Int4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0j2C3C, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0k2C3D( + BuiltInId::imageStore_UImage3D1_Int3_UInt4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0k2C3D, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0l2C3B( + BuiltInId::imageStore_Image2DArray1_Int3_Float4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0l2C3B, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0m2C3C( + BuiltInId::imageStore_IImage2DArray1_Int3_Int4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0m2C3C, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0n2C3D( + BuiltInId::imageStore_UImage2DArray1_Int3_UInt4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0n2C3D, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0o2C3B( + BuiltInId::imageStore_ImageCube1_Int3_Float4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0o2C3B, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0p2C3C( + BuiltInId::imageStore_IImageCube1_Int3_Int4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0p2C3C, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_imageStore_0q2C3D( + BuiltInId::imageStore_UImageCube1_Int3_UInt4, + BuiltInName::imageStore, + TExtension::UNDEFINED, + BuiltInParameters::p0q2C3D, + 3, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpCallBuiltInFunction, + false); +constexpr const TFunction kFunction_memoryBarrier_( + BuiltInId::memoryBarrier, + BuiltInName::memoryBarrier, + TExtension::UNDEFINED, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMemoryBarrier, + false); +constexpr const TFunction kFunction_memoryBarrierAtomicCounter_( + BuiltInId::memoryBarrierAtomicCounter, + BuiltInName::memoryBarrierAtomicCounter, + TExtension::UNDEFINED, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMemoryBarrierAtomicCounter, + false); +constexpr const TFunction kFunction_memoryBarrierBuffer_( + BuiltInId::memoryBarrierBuffer, + BuiltInName::memoryBarrierBuffer, + TExtension::UNDEFINED, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMemoryBarrierBuffer, + false); +constexpr const TFunction kFunction_memoryBarrierImage_( + BuiltInId::memoryBarrierImage, + BuiltInName::memoryBarrierImage, + TExtension::UNDEFINED, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMemoryBarrierImage, + false); +constexpr const TFunction kFunction_barrier_( + BuiltInId::barrier, + BuiltInName::barrier, + TExtension::UNDEFINED, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpBarrier, + false); +constexpr const TFunction kFunction_memoryBarrierShared_( + BuiltInId::memoryBarrierShared, + BuiltInName::memoryBarrierShared, + TExtension::UNDEFINED, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpMemoryBarrierShared, + false); +constexpr const TFunction kFunction_groupMemoryBarrier_( + BuiltInId::groupMemoryBarrier, + BuiltInName::groupMemoryBarrier, + TExtension::UNDEFINED, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpGroupMemoryBarrier, + false); +constexpr const TFunction kFunction_EmitVertex_( + BuiltInId::EmitVertex, + BuiltInName::EmitVertex, + TExtension::EXT_geometry_shader, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpEmitVertex, + false); +constexpr const TFunction kFunction_EndPrimitive_( + BuiltInId::EndPrimitive, + BuiltInName::EndPrimitive, + TExtension::EXT_geometry_shader, + BuiltInParameters::empty, + 0, + StaticType::Get<EbtVoid, EbpUndefined, EvqGlobal, 1, 1>(), + EOpEndPrimitive, + false); + +} // namespace BuiltInFunction + +void TSymbolTable::initializeBuiltInVariables(sh::GLenum shaderType, + ShShaderSpec spec, + const ShBuiltInResources &resources) +{ + const TSourceLoc zeroSourceLoc = {0, 0, 0, 0}; + TFieldList *fields_gl_DepthRangeParameters = new TFieldList(); + fields_gl_DepthRangeParameters->push_back( + new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1), BuiltInName::near, zeroSourceLoc, + SymbolType::BuiltIn)); + fields_gl_DepthRangeParameters->push_back( + new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1), BuiltInName::far, zeroSourceLoc, + SymbolType::BuiltIn)); + fields_gl_DepthRangeParameters->push_back( + new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1), BuiltInName::diff, zeroSourceLoc, + SymbolType::BuiltIn)); + TStructure *gl_DepthRangeParameters = + new TStructure(BuiltInId::gl_DepthRangeParameters, BuiltInName::gl_DepthRangeParameters, + TExtension::UNDEFINED, fields_gl_DepthRangeParameters); + mVar_gl_DepthRangeParameters = gl_DepthRangeParameters; + TType *type_gl_DepthRange = new TType(gl_DepthRangeParameters, false); + type_gl_DepthRange->setQualifier(EvqUniform); + type_gl_DepthRange->realize(); + mVar_gl_DepthRange = + new TVariable(BuiltInId::gl_DepthRange, BuiltInName::gl_DepthRange, SymbolType::BuiltIn, + TExtension::UNDEFINED, type_gl_DepthRange); + mVar_gl_MaxVertexAttribs = new TVariable( + BuiltInId::gl_MaxVertexAttribs, BuiltInName::gl_MaxVertexAttribs, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVertexAttribs); + mVar_gl_MaxVertexAttribs->shareConstPointer(unionArray); + } + mVar_gl_MaxVertexUniformVectors = + new TVariable(BuiltInId::gl_MaxVertexUniformVectors, + BuiltInName::gl_MaxVertexUniformVectors, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVertexUniformVectors); + mVar_gl_MaxVertexUniformVectors->shareConstPointer(unionArray); + } + mVar_gl_MaxVertexTextureImageUnits = + new TVariable(BuiltInId::gl_MaxVertexTextureImageUnits, + BuiltInName::gl_MaxVertexTextureImageUnits, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVertexTextureImageUnits); + mVar_gl_MaxVertexTextureImageUnits->shareConstPointer(unionArray); + } + mVar_gl_MaxCombinedTextureImageUnits = + new TVariable(BuiltInId::gl_MaxCombinedTextureImageUnits, + BuiltInName::gl_MaxCombinedTextureImageUnits, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxCombinedTextureImageUnits); + mVar_gl_MaxCombinedTextureImageUnits->shareConstPointer(unionArray); + } + mVar_gl_MaxTextureImageUnits = + new TVariable(BuiltInId::gl_MaxTextureImageUnits, BuiltInName::gl_MaxTextureImageUnits, + SymbolType::BuiltIn, TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxTextureImageUnits); + mVar_gl_MaxTextureImageUnits->shareConstPointer(unionArray); + } + mVar_gl_MaxFragmentUniformVectors = + new TVariable(BuiltInId::gl_MaxFragmentUniformVectors, + BuiltInName::gl_MaxFragmentUniformVectors, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxFragmentUniformVectors); + mVar_gl_MaxFragmentUniformVectors->shareConstPointer(unionArray); + } + mVar_gl_MaxVaryingVectors = new TVariable( + BuiltInId::gl_MaxVaryingVectors, BuiltInName::gl_MaxVaryingVectors, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVaryingVectors); + mVar_gl_MaxVaryingVectors->shareConstPointer(unionArray); + } + mVar_gl_MaxDrawBuffers = new TVariable( + BuiltInId::gl_MaxDrawBuffers, BuiltInName::gl_MaxDrawBuffers, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxDrawBuffers); + mVar_gl_MaxDrawBuffers->shareConstPointer(unionArray); + } + mVar_gl_MaxDualSourceDrawBuffersEXT = new TVariable( + BuiltInId::gl_MaxDualSourceDrawBuffersEXT, BuiltInName::gl_MaxDualSourceDrawBuffersEXT, + SymbolType::BuiltIn, TExtension::EXT_blend_func_extended, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxDualSourceDrawBuffers); + mVar_gl_MaxDualSourceDrawBuffersEXT->shareConstPointer(unionArray); + } + mVar_gl_MaxVertexOutputVectors = + new TVariable(BuiltInId::gl_MaxVertexOutputVectors, BuiltInName::gl_MaxVertexOutputVectors, + SymbolType::BuiltIn, TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVertexOutputVectors); + mVar_gl_MaxVertexOutputVectors->shareConstPointer(unionArray); + } + mVar_gl_MaxFragmentInputVectors = + new TVariable(BuiltInId::gl_MaxFragmentInputVectors, + BuiltInName::gl_MaxFragmentInputVectors, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxFragmentInputVectors); + mVar_gl_MaxFragmentInputVectors->shareConstPointer(unionArray); + } + mVar_gl_MinProgramTexelOffset = + new TVariable(BuiltInId::gl_MinProgramTexelOffset, BuiltInName::gl_MinProgramTexelOffset, + SymbolType::BuiltIn, TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MinProgramTexelOffset); + mVar_gl_MinProgramTexelOffset->shareConstPointer(unionArray); + } + mVar_gl_MaxProgramTexelOffset = + new TVariable(BuiltInId::gl_MaxProgramTexelOffset, BuiltInName::gl_MaxProgramTexelOffset, + SymbolType::BuiltIn, TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxProgramTexelOffset); + mVar_gl_MaxProgramTexelOffset->shareConstPointer(unionArray); + } + mVar_gl_MaxImageUnits = new TVariable( + BuiltInId::gl_MaxImageUnits, BuiltInName::gl_MaxImageUnits, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxImageUnits); + mVar_gl_MaxImageUnits->shareConstPointer(unionArray); + } + mVar_gl_MaxVertexImageUniforms = + new TVariable(BuiltInId::gl_MaxVertexImageUniforms, BuiltInName::gl_MaxVertexImageUniforms, + SymbolType::BuiltIn, TExtension::UNDEFINED, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVertexImageUniforms); + mVar_gl_MaxVertexImageUniforms->shareConstPointer(unionArray); + } + mVar_gl_MaxFragmentImageUniforms = + new TVariable(BuiltInId::gl_MaxFragmentImageUniforms, + BuiltInName::gl_MaxFragmentImageUniforms, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxFragmentImageUniforms); + mVar_gl_MaxFragmentImageUniforms->shareConstPointer(unionArray); + } + mVar_gl_MaxComputeImageUniforms = + new TVariable(BuiltInId::gl_MaxComputeImageUniforms, + BuiltInName::gl_MaxComputeImageUniforms, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxComputeImageUniforms); + mVar_gl_MaxComputeImageUniforms->shareConstPointer(unionArray); + } + mVar_gl_MaxCombinedImageUniforms = + new TVariable(BuiltInId::gl_MaxCombinedImageUniforms, + BuiltInName::gl_MaxCombinedImageUniforms, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxCombinedImageUniforms); + mVar_gl_MaxCombinedImageUniforms->shareConstPointer(unionArray); + } + mVar_gl_MaxCombinedShaderOutputResources = + new TVariable(BuiltInId::gl_MaxCombinedShaderOutputResources, + BuiltInName::gl_MaxCombinedShaderOutputResources, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxCombinedShaderOutputResources); + mVar_gl_MaxCombinedShaderOutputResources->shareConstPointer(unionArray); + } + mVar_gl_MaxComputeWorkGroupCount = + new TVariable(BuiltInId::gl_MaxComputeWorkGroupCount, + BuiltInName::gl_MaxComputeWorkGroupCount, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpHigh, EvqConst, 3, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[3]; + for (size_t index = 0u; index < 3; ++index) + { + unionArray[index].setIConst(resources.MaxComputeWorkGroupCount[index]); + } + mVar_gl_MaxComputeWorkGroupCount->shareConstPointer(unionArray); + } + mVar_gl_MaxComputeWorkGroupSize = + new TVariable(BuiltInId::gl_MaxComputeWorkGroupSize, + BuiltInName::gl_MaxComputeWorkGroupSize, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpHigh, EvqConst, 3, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[3]; + for (size_t index = 0u; index < 3; ++index) + { + unionArray[index].setIConst(resources.MaxComputeWorkGroupSize[index]); + } + mVar_gl_MaxComputeWorkGroupSize->shareConstPointer(unionArray); + } + mVar_gl_MaxComputeUniformComponents = + new TVariable(BuiltInId::gl_MaxComputeUniformComponents, + BuiltInName::gl_MaxComputeUniformComponents, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxComputeUniformComponents); + mVar_gl_MaxComputeUniformComponents->shareConstPointer(unionArray); + } + mVar_gl_MaxComputeTextureImageUnits = + new TVariable(BuiltInId::gl_MaxComputeTextureImageUnits, + BuiltInName::gl_MaxComputeTextureImageUnits, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxComputeTextureImageUnits); + mVar_gl_MaxComputeTextureImageUnits->shareConstPointer(unionArray); + } + mVar_gl_MaxComputeAtomicCounters = + new TVariable(BuiltInId::gl_MaxComputeAtomicCounters, + BuiltInName::gl_MaxComputeAtomicCounters, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxComputeAtomicCounters); + mVar_gl_MaxComputeAtomicCounters->shareConstPointer(unionArray); + } + mVar_gl_MaxComputeAtomicCounterBuffers = + new TVariable(BuiltInId::gl_MaxComputeAtomicCounterBuffers, + BuiltInName::gl_MaxComputeAtomicCounterBuffers, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxComputeAtomicCounterBuffers); + mVar_gl_MaxComputeAtomicCounterBuffers->shareConstPointer(unionArray); + } + mVar_gl_MaxVertexAtomicCounters = + new TVariable(BuiltInId::gl_MaxVertexAtomicCounters, + BuiltInName::gl_MaxVertexAtomicCounters, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVertexAtomicCounters); + mVar_gl_MaxVertexAtomicCounters->shareConstPointer(unionArray); + } + mVar_gl_MaxFragmentAtomicCounters = + new TVariable(BuiltInId::gl_MaxFragmentAtomicCounters, + BuiltInName::gl_MaxFragmentAtomicCounters, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxFragmentAtomicCounters); + mVar_gl_MaxFragmentAtomicCounters->shareConstPointer(unionArray); + } + mVar_gl_MaxCombinedAtomicCounters = + new TVariable(BuiltInId::gl_MaxCombinedAtomicCounters, + BuiltInName::gl_MaxCombinedAtomicCounters, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxCombinedAtomicCounters); + mVar_gl_MaxCombinedAtomicCounters->shareConstPointer(unionArray); + } + mVar_gl_MaxAtomicCounterBindings = + new TVariable(BuiltInId::gl_MaxAtomicCounterBindings, + BuiltInName::gl_MaxAtomicCounterBindings, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxAtomicCounterBindings); + mVar_gl_MaxAtomicCounterBindings->shareConstPointer(unionArray); + } + mVar_gl_MaxVertexAtomicCounterBuffers = + new TVariable(BuiltInId::gl_MaxVertexAtomicCounterBuffers, + BuiltInName::gl_MaxVertexAtomicCounterBuffers, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxVertexAtomicCounterBuffers); + mVar_gl_MaxVertexAtomicCounterBuffers->shareConstPointer(unionArray); + } + mVar_gl_MaxFragmentAtomicCounterBuffers = + new TVariable(BuiltInId::gl_MaxFragmentAtomicCounterBuffers, + BuiltInName::gl_MaxFragmentAtomicCounterBuffers, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxFragmentAtomicCounterBuffers); + mVar_gl_MaxFragmentAtomicCounterBuffers->shareConstPointer(unionArray); + } + mVar_gl_MaxCombinedAtomicCounterBuffers = + new TVariable(BuiltInId::gl_MaxCombinedAtomicCounterBuffers, + BuiltInName::gl_MaxCombinedAtomicCounterBuffers, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxCombinedAtomicCounterBuffers); + mVar_gl_MaxCombinedAtomicCounterBuffers->shareConstPointer(unionArray); + } + mVar_gl_MaxAtomicCounterBufferSize = + new TVariable(BuiltInId::gl_MaxAtomicCounterBufferSize, + BuiltInName::gl_MaxAtomicCounterBufferSize, SymbolType::BuiltIn, + TExtension::UNDEFINED, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxAtomicCounterBufferSize); + mVar_gl_MaxAtomicCounterBufferSize->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryInputComponents = new TVariable( + BuiltInId::gl_MaxGeometryInputComponents, BuiltInName::gl_MaxGeometryInputComponents, + SymbolType::BuiltIn, TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryInputComponents); + mVar_gl_MaxGeometryInputComponents->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryOutputComponents = new TVariable( + BuiltInId::gl_MaxGeometryOutputComponents, BuiltInName::gl_MaxGeometryOutputComponents, + SymbolType::BuiltIn, TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryOutputComponents); + mVar_gl_MaxGeometryOutputComponents->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryImageUniforms = new TVariable( + BuiltInId::gl_MaxGeometryImageUniforms, BuiltInName::gl_MaxGeometryImageUniforms, + SymbolType::BuiltIn, TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryImageUniforms); + mVar_gl_MaxGeometryImageUniforms->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryTextureImageUnits = new TVariable( + BuiltInId::gl_MaxGeometryTextureImageUnits, BuiltInName::gl_MaxGeometryTextureImageUnits, + SymbolType::BuiltIn, TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryTextureImageUnits); + mVar_gl_MaxGeometryTextureImageUnits->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryOutputVertices = new TVariable( + BuiltInId::gl_MaxGeometryOutputVertices, BuiltInName::gl_MaxGeometryOutputVertices, + SymbolType::BuiltIn, TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryOutputVertices); + mVar_gl_MaxGeometryOutputVertices->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryTotalOutputComponents = new TVariable( + BuiltInId::gl_MaxGeometryTotalOutputComponents, + BuiltInName::gl_MaxGeometryTotalOutputComponents, SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryTotalOutputComponents); + mVar_gl_MaxGeometryTotalOutputComponents->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryUniformComponents = new TVariable( + BuiltInId::gl_MaxGeometryUniformComponents, BuiltInName::gl_MaxGeometryUniformComponents, + SymbolType::BuiltIn, TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryUniformComponents); + mVar_gl_MaxGeometryUniformComponents->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryAtomicCounters = new TVariable( + BuiltInId::gl_MaxGeometryAtomicCounters, BuiltInName::gl_MaxGeometryAtomicCounters, + SymbolType::BuiltIn, TExtension::EXT_geometry_shader, + StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryAtomicCounters); + mVar_gl_MaxGeometryAtomicCounters->shareConstPointer(unionArray); + } + mVar_gl_MaxGeometryAtomicCounterBuffers = new TVariable( + BuiltInId::gl_MaxGeometryAtomicCounterBuffers, + BuiltInName::gl_MaxGeometryAtomicCounterBuffers, SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, StaticType::Get<EbtInt, EbpMedium, EvqConst, 1, 1>()); + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray[0].setIConst(resources.MaxGeometryAtomicCounterBuffers); + mVar_gl_MaxGeometryAtomicCounterBuffers->shareConstPointer(unionArray); + } + if (shaderType == GL_FRAGMENT_SHADER) + { + TType *type_gl_FragData = new TType(EbtFloat, EbpMedium, EvqFragData, 4); + if (spec != SH_WEBGL2_SPEC && spec != SH_WEBGL3_SPEC) + { + type_gl_FragData->makeArray(resources.MaxDrawBuffers); + } + else + { + type_gl_FragData->makeArray(1u); + } + type_gl_FragData->realize(); + mVar_gl_FragData = + new TVariable(BuiltInId::gl_FragData, BuiltInName::gl_FragData, SymbolType::BuiltIn, + TExtension::UNDEFINED, type_gl_FragData); + } + if ((shaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_blend_func_extended)) + { + TType *type_gl_SecondaryFragDataEXT = + new TType(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1); + type_gl_SecondaryFragDataEXT->makeArray(resources.MaxDualSourceDrawBuffers); + type_gl_SecondaryFragDataEXT->realize(); + mVar_gl_SecondaryFragDataEXT = new TVariable( + BuiltInId::gl_SecondaryFragDataEXT, BuiltInName::gl_SecondaryFragDataEXT, + SymbolType::BuiltIn, TExtension::EXT_blend_func_extended, type_gl_SecondaryFragDataEXT); + } + if ((shaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_frag_depth)) + { + TType *type_gl_FragDepthEXT = new TType( + EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepthEXT, 1); + type_gl_FragDepthEXT->realize(); + mVar_gl_FragDepthEXT = + new TVariable(BuiltInId::gl_FragDepthEXT, BuiltInName::gl_FragDepthEXT, + SymbolType::BuiltIn, TExtension::EXT_frag_depth, type_gl_FragDepthEXT); + } + TType *type_gl_LastFragData = new TType(EbtFloat, EbpMedium, EvqLastFragData, 4, 1); + type_gl_LastFragData->makeArray(resources.MaxDrawBuffers); + type_gl_LastFragData->realize(); + mVar_gl_LastFragData = + new TVariable(BuiltInId::gl_LastFragData, BuiltInName::gl_LastFragData, SymbolType::BuiltIn, + TExtension::EXT_shader_framebuffer_fetch, type_gl_LastFragData); + TType *type_gl_LastFragDataNV = new TType(EbtFloat, EbpMedium, EvqLastFragData, 4, 1); + type_gl_LastFragDataNV->makeArray(resources.MaxDrawBuffers); + type_gl_LastFragDataNV->realize(); + mVar_gl_LastFragDataNV = new TVariable( + BuiltInId::gl_LastFragDataNV, BuiltInName::gl_LastFragData, SymbolType::BuiltIn, + TExtension::NV_shader_framebuffer_fetch, type_gl_LastFragDataNV); + TFieldList *fields_gl_PerVertex = new TFieldList(); + fields_gl_PerVertex->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqPosition, 4, 1), + BuiltInName::gl_Position, zeroSourceLoc, + SymbolType::BuiltIn)); + TInterfaceBlock *gl_PerVertex = + new TInterfaceBlock(BuiltInId::gl_PerVertex, BuiltInName::gl_PerVertex, + TExtension::EXT_geometry_shader, fields_gl_PerVertex); + mVar_gl_PerVertex = gl_PerVertex; + if (shaderType == GL_GEOMETRY_SHADER_EXT) + { + TType *type_gl_in = new TType(gl_PerVertex, EvqPerVertexIn, TLayoutQualifier::Create()); + type_gl_in->makeArray(0u); + type_gl_in->realize(); + mVar_gl_in = new TVariable(BuiltInId::gl_in, BuiltInName::gl_in, SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, type_gl_in); + } + TFieldList *fields_gl_PerVertexOutBlock = new TFieldList(); + fields_gl_PerVertexOutBlock->push_back( + new TField(new TType(EbtFloat, EbpHigh, EvqPosition, 4, 1), BuiltInName::gl_Position, + zeroSourceLoc, SymbolType::BuiltIn)); + TInterfaceBlock *gl_PerVertexOutBlock = + new TInterfaceBlock(BuiltInId::gl_PerVertexOutBlock, BuiltInName::gl_PerVertex, + TExtension::EXT_geometry_shader, fields_gl_PerVertexOutBlock); + TType *type_gl_PositionGS = new TType(EbtFloat, EbpHigh, EvqPosition, 4); + type_gl_PositionGS->setInterfaceBlock(gl_PerVertexOutBlock); + type_gl_PositionGS->realize(); + mVar_gl_PositionGS = + new TVariable(BuiltInId::gl_PositionGS, BuiltInName::gl_Position, SymbolType::BuiltIn, + TExtension::EXT_geometry_shader, type_gl_PositionGS); +} + +const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name, int shaderVersion) const +{ + if (name.length() > 35) + { + return nullptr; + } + uint32_t nameHash = name.mangledNameHash(); + if ((nameHash >> 31) != 0) + { + // The name contains [ or {. + return nullptr; + } + if (shaderVersion >= 310) + { + switch (nameHash) + { + case 0x0a50832eu: + { + if (name.beginsWith(BuiltInName::ldexp)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_ldexp_1B1C; + } + break; + } + case 0x0a50a6eeu: + { + if (name.beginsWith(BuiltInName::frexp)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_frexp_2B2C; + } + break; + } + case 0x0a52bed1u: + { + if (name.beginsWith(BuiltInName::ldexp)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_ldexp_0B0C; + } + break; + } + case 0x0a53e9c4u: + { + if (name == BuiltInName::frexp_3B3C) + { + return &BuiltInFunction::kFunction_frexp_3B3C; + } + break; + } + case 0x0a54aa52u: + { + if (name.beginsWith(BuiltInName::ldexp)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_ldexp_2B2C; + } + break; + } + case 0x0a55008fu: + { + if (name.beginsWith(BuiltInName::frexp)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_frexp_1B1C; + } + break; + } + case 0x0a5799e7u: + { + if (name.beginsWith(BuiltInName::frexp)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_frexp_0B0C; + } + break; + } + case 0x0a57c201u: + { + if (name.beginsWith(BuiltInName::ldexp)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_ldexp_3B3C; + } + break; + } + case 0x0e500330u: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_3C; + } + break; + } + case 0x0e503089u: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_3D; + } + break; + } + case 0x0e508070u: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_0C; + } + break; + } + case 0x0e508a05u: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_0D; + } + break; + } + case 0x0e51917du: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_1C; + } + break; + } + case 0x0e51dc78u: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_1D; + } + break; + } + case 0x0e54832eu: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_2C; + } + break; + } + case 0x0e54b667u: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_2D; + } + break; + } + case 0x0e550f72u: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_1D; + } + break; + } + case 0x0e5514e7u: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_1C; + } + break; + } + case 0x0e5607c2u: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_0C; + } + break; + } + case 0x0e5650c7u: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_0D; + } + break; + } + case 0x0e56a99cu: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_2D; + } + break; + } + case 0x0e56cd55u: + { + if (name.beginsWith(BuiltInName::findMSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findMSB_2C; + } + break; + } + case 0x0e573680u: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_3D; + } + break; + } + case 0x0e574a59u: + { + if (name.beginsWith(BuiltInName::findLSB)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_findLSB_3C; + } + break; + } + case 0x10581cccu: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_2D; + } + break; + } + case 0x10584c2du: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_2C; + } + break; + } + case 0x105896f1u: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_1D; + } + break; + } + case 0x1058cbf7u: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_1C; + } + break; + } + case 0x1059a37cu: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_0D; + } + break; + } + case 0x1059dae9u: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_0C; + } + break; + } + case 0x105b1832u: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_3C; + } + break; + } + case 0x105b2810u: + { + if (name.beginsWith(BuiltInName::bitCount)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_bitCount_3D; + } + break; + } + case 0x106a2daeu: + { + if (name.beginsWith(BuiltInName::atomicOr)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_atomicOr_0D0D; + } + break; + } + case 0x106bd5b6u: + { + if (name.beginsWith(BuiltInName::atomicOr)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_atomicOr_0C0C; + } + break; + } + case 0x126520f8u: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0p; + } + break; + } + case 0x12653967u: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0q; + } + break; + } + case 0x1265b53eu: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0g; + } + break; + } + case 0x1265cbcau: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0k; + } + break; + } + case 0x1265cc8du: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0f; + } + break; + } + case 0x1265e196u: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0o; + } + break; + } + case 0x1265e603u: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0h; + } + break; + } + case 0x1265f559u: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0j; + } + break; + } + case 0x1265fcacu: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0i; + } + break; + } + case 0x12660ccfu: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0l; + } + break; + } + case 0x12661578u: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0m; + } + break; + } + case 0x12661be5u: + { + if (name.beginsWith(BuiltInName::imageSize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_imageSize_0n; + } + break; + } + case 0x12700109u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0h1C; + } + break; + } + case 0x1270b3f8u: + { + if (name.beginsWith(BuiltInName::atomicAdd)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicAdd_0C0C; + } + break; + } + case 0x1270b766u: + { + if (name.beginsWith(BuiltInName::atomicXor)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicXor_0C0C; + } + break; + } + case 0x12712664u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0n2C; + } + break; + } + case 0x12715f47u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0j2C; + } + break; + } + case 0x12717c89u: + { + if (name.beginsWith(BuiltInName::atomicMin)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicMin_0C0C; + } + break; + } + case 0x127258f0u: + { + if (name.beginsWith(BuiltInName::atomicAdd)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicAdd_0D0D; + } + break; + } + case 0x12731984u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0m2C; + } + break; + } + case 0x12737ed6u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0q2C; + } + break; + } + case 0x12739c87u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0f1C; + } + break; + } + case 0x1273d1adu: + { + if (name.beginsWith(BuiltInName::atomicMax)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicMax_0D0D; + } + break; + } + case 0x1273e62au: + { + if (name.beginsWith(BuiltInName::atomicMin)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicMin_0D0D; + } + break; + } + case 0x12744c0du: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0o2C; + } + break; + } + case 0x127474cau: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0k2C; + } + break; + } + case 0x127478d9u: + { + if (name.beginsWith(BuiltInName::atomicAnd)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicAnd_0C0C; + } + break; + } + case 0x1274d54bu: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0p2C; + } + break; + } + case 0x127539b2u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0i2C; + } + break; + } + case 0x12755603u: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0g1C; + } + break; + } + case 0x127648cau: + { + if (name.beginsWith(BuiltInName::atomicAnd)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicAnd_0D0D; + } + break; + } + case 0x1276656cu: + { + if (name.beginsWith(BuiltInName::imageLoad)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_imageLoad_0l2C; + } + break; + } + case 0x12771119u: + { + if (name.beginsWith(BuiltInName::atomicXor)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicXor_0D0D; + } + break; + } + case 0x1277882au: + { + if (name.beginsWith(BuiltInName::atomicMax)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_atomicMax_0C0C; + } + break; + } + case 0x1283ba95u: + { + if (name.beginsWith(BuiltInName::uaddCarry)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_uaddCarry_0D0D0D; + } + break; + } + case 0x12840dfbu: + { + if (name == BuiltInName::uaddCarry_2D2D2D) + { + return &BuiltInFunction::kFunction_uaddCarry_2D2D2D; + } + break; + } + case 0x12842566u: + { + if (name == BuiltInName::uaddCarry_3D3D3D) + { + return &BuiltInFunction::kFunction_uaddCarry_3D3D3D; + } + break; + } + case 0x12843bc0u: + { + if (name.beginsWith(BuiltInName::uaddCarry)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_uaddCarry_1D1D1D; + } + break; + } + case 0x1488078cu: + { + if (name.beginsWith(BuiltInName::imageStore)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_imageStore_0k2C3D; + } + break; + } + case 0x14880e11u: + { + if (name == BuiltInName::texelFetch_0V2C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0V2C0C; + } + break; + } + case 0x1488ffa7u: + { + if (name == BuiltInName::usubBorrow_3D3D3D) + { + return &BuiltInFunction::kFunction_usubBorrow_3D3D3D; + } + break; + } + case 0x1489244fu: + { + if (name.beginsWith(BuiltInName::texelFetch)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetch_0b2C0C; + } + break; + } + case 0x14896692u: + { + if (name.beginsWith(BuiltInName::usubBorrow)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_usubBorrow_2D2D2D; + } + break; + } + case 0x14896e41u: + { + if (name == BuiltInName::texelFetch_0O1C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0O1C0C; + } + break; + } + case 0x148a0cecu: + { + if (name == BuiltInName::imageStore_0p2C3C) + { + return &BuiltInFunction::kFunction_imageStore_0p2C3C; + } + break; + } + case 0x148ab5f1u: + { + if (name == BuiltInName::usubBorrow_1D1D1D) + { + return &BuiltInFunction::kFunction_usubBorrow_1D1D1D; + } + break; + } + case 0x148bb1bdu: + { + if (name.beginsWith(BuiltInName::imageStore)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_imageStore_0g1C3C; + } + break; + } + case 0x148c1e41u: + { + if (name.beginsWith(BuiltInName::imageStore)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_imageStore_0q2C3D; + } + break; + } + case 0x148d86dcu: + { + if (name.beginsWith(BuiltInName::imageStore)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_imageStore_0f1C3B; + } + break; + } + case 0x148dcfd5u: + { + if (name == BuiltInName::imageStore_0l2C3B) + { + return &BuiltInFunction::kFunction_imageStore_0l2C3B; + } + break; + } + case 0x148ddb10u: + { + if (name.beginsWith(BuiltInName::texelFetch)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetch_0a1C0C; + } + break; + } + case 0x148e37b8u: + { + if (name.beginsWith(BuiltInName::imageStore)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_imageStore_0m2C3C; + } + break; + } + case 0x148e668au: + { + if (name == BuiltInName::imageStore_0j2C3C) + { + return &BuiltInFunction::kFunction_imageStore_0j2C3C; + } + break; + } + case 0x148e872bu: + { + if (name == BuiltInName::texelFetch_0P2C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0P2C0C; + } + break; + } + case 0x148ed16fu: + { + if (name.beginsWith(BuiltInName::texelFetch)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetch_0U1C0C; + } + break; + } + case 0x148ed534u: + { + if (name == BuiltInName::imageStore_0n2C3D) + { + return &BuiltInFunction::kFunction_imageStore_0n2C3D; + } + break; + } + case 0x148f6fe1u: + { + if (name == BuiltInName::usubBorrow_0D0D0D) + { + return &BuiltInFunction::kFunction_usubBorrow_0D0D0D; + } + break; + } + case 0x148f7a82u: + { + if (name.beginsWith(BuiltInName::imageStore)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_imageStore_0o2C3B; + } + break; + } + case 0x148fd5f1u: + { + if (name.beginsWith(BuiltInName::imageStore)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_imageStore_0i2C3B; + } + break; + } + case 0x148ffee8u: + { + if (name == BuiltInName::imageStore_0h1C3D) + { + return &BuiltInFunction::kFunction_imageStore_0h1C3D; + } + break; + } + case 0x167394d8u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSize_0U; + } + break; + } + case 0x1673a791u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSize_0V; + } + break; + } + case 0x1673b4b7u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSize_0P; + } + break; + } + case 0x1673f496u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSize_0O; + } + break; + } + case 0x16752ab6u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSize_0a; + } + break; + } + case 0x1675566fu: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSize_0b; + } + break; + } + case 0x187b7b7cu: + { + if (name.beginsWith(BuiltInName::packSnorm4x8)) + { + ASSERT(name.length() == 15); + return &BuiltInFunction::kFunction_packSnorm4x8_3B; + } + break; + } + case 0x187c1f3fu: + { + if (name.beginsWith(BuiltInName::packUnorm4x8)) + { + ASSERT(name.length() == 15); + return &BuiltInFunction::kFunction_packUnorm4x8_3B; + } + break; + } + case 0x18a851efu: + { + if (name == BuiltInName::imulExtended_2C2C2C2C) + { + return &BuiltInFunction::kFunction_imulExtended_2C2C2C2C; + } + break; + } + case 0x18a93bdcu: + { + if (name == BuiltInName::umulExtended_0D0D0D0D) + { + return &BuiltInFunction::kFunction_umulExtended_0D0D0D0D; + } + break; + } + case 0x18a94b63u: + { + if (name == BuiltInName::umulExtended_3D3D3D3D) + { + return &BuiltInFunction::kFunction_umulExtended_3D3D3D3D; + } + break; + } + case 0x18aa71ceu: + { + if (name == BuiltInName::umulExtended_2D2D2D2D) + { + return &BuiltInFunction::kFunction_umulExtended_2D2D2D2D; + } + break; + } + case 0x18ab4baeu: + { + if (name == BuiltInName::umulExtended_1D1D1D1D) + { + return &BuiltInFunction::kFunction_umulExtended_1D1D1D1D; + } + break; + } + case 0x18ac1df0u: + { + if (name == BuiltInName::imulExtended_3C3C3C3C) + { + return &BuiltInFunction::kFunction_imulExtended_3C3C3C3C; + } + break; + } + case 0x18ac377fu: + { + if (name == BuiltInName::imulExtended_0C0C0C0C) + { + return &BuiltInFunction::kFunction_imulExtended_0C0C0C0C; + } + break; + } + case 0x18ae7b8cu: + { + if (name == BuiltInName::imulExtended_1C1C1C1C) + { + return &BuiltInFunction::kFunction_imulExtended_1C1C1C1C; + } + break; + } + case 0x1a7538dfu: + { + if (name.beginsWith(BuiltInName::memoryBarrier)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_memoryBarrier_; + } + break; + } + case 0x1a805162u: + { + if (name.beginsWith(BuiltInName::atomicCounter)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_atomicCounter_0F; + } + break; + } + case 0x1a910beau: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0Y2B; + } + break; + } + case 0x1a91963cu: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0d2B; + } + break; + } + case 0x1a926b0du: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0c1B; + } + break; + } + case 0x1a92a168u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0W1B; + } + break; + } + case 0x1a92a1ceu: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0H1B; + } + break; + } + case 0x1a92c882u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0Q1B; + } + break; + } + case 0x1a9418e8u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0S2B; + } + break; + } + case 0x1a94543du: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0K2B; + } + break; + } + case 0x1a94d27du: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0e2B; + } + break; + } + case 0x1a94eb48u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0Z2B; + } + break; + } + case 0x1a95f707u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0T2B; + } + break; + } + case 0x1a979ae3u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureGather_0J2B; + } + break; + } + case 0x1aa039c7u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0e2B0B; + } + break; + } + case 0x1aa133bcu: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0Q1B0C; + } + break; + } + case 0x1aa17115u: + { + if (name == BuiltInName::textureGather_0Z2B0C) + { + return &BuiltInFunction::kFunction_textureGather_0Z2B0C; + } + break; + } + case 0x1aa182eeu: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0c1B0B; + } + break; + } + case 0x1aa220b0u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0W1B0C; + } + break; + } + case 0x1aa2aafeu: + { + if (name == BuiltInName::textureGather_0T2B0C) + { + return &BuiltInFunction::kFunction_textureGather_0T2B0C; + } + break; + } + case 0x1aa353f8u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0d2B0B; + } + break; + } + case 0x1aa3ef46u: + { + if (name == BuiltInName::textureGather_0S2B0C) + { + return &BuiltInFunction::kFunction_textureGather_0S2B0C; + } + break; + } + case 0x1aa4986bu: + { + if (name == BuiltInName::textureGather_0J2B0C) + { + return &BuiltInFunction::kFunction_textureGather_0J2B0C; + } + break; + } + case 0x1aa4c59du: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0H1B0C; + } + break; + } + case 0x1aa78b86u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0K2B0C; + } + break; + } + case 0x1aa7fa48u: + { + if (name.beginsWith(BuiltInName::textureGather)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureGather_0Y2B0C; + } + break; + } + case 0x1c894fb3u: + { + if (name.beginsWith(BuiltInName::unpackSnorm4x8)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_unpackSnorm4x8_0D; + } + break; + } + case 0x1c8be3bau: + { + if (name.beginsWith(BuiltInName::unpackUnorm4x8)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_unpackUnorm4x8_0D; + } + break; + } + case 0x1c9986beu: + { + if (name.beginsWith(BuiltInName::atomicExchange)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_atomicExchange_0D0D; + } + break; + } + case 0x1c9b5eecu: + { + if (name.beginsWith(BuiltInName::atomicExchange)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_atomicExchange_0C0C; + } + break; + } + case 0x1ca86085u: + { + if (name.beginsWith(BuiltInName::atomicCompSwap)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_atomicCompSwap_0C0C0C; + } + break; + } + case 0x1caa900cu: + { + if (name == BuiltInName::atomicCompSwap_0D0D0D) + { + return &BuiltInFunction::kFunction_atomicCompSwap_0D0D0D; + } + break; + } + case 0x1cb84b0cu: + { + if (name == BuiltInName::bitfieldInsert_3D3D0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_3D3D0C0C; + } + break; + } + case 0x1cb880bfu: + { + if (name == BuiltInName::bitfieldInsert_3C3C0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_3C3C0C0C; + } + break; + } + case 0x1cb90fd0u: + { + if (name == BuiltInName::bitfieldInsert_1C1C0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_1C1C0C0C; + } + break; + } + case 0x1cb9fb13u: + { + if (name == BuiltInName::bitfieldInsert_1D1D0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_1D1D0C0C; + } + break; + } + case 0x1cbb43f5u: + { + if (name == BuiltInName::bitfieldInsert_0D0D0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_0D0D0C0C; + } + break; + } + case 0x1cbb9db3u: + { + if (name == BuiltInName::bitfieldInsert_2D2D0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_2D2D0C0C; + } + break; + } + case 0x1cbdf898u: + { + if (name == BuiltInName::bitfieldInsert_0C0C0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_0C0C0C0C; + } + break; + } + case 0x1cbfaf73u: + { + if (name == BuiltInName::bitfieldInsert_2C2C0C0C) + { + return &BuiltInFunction::kFunction_bitfieldInsert_2C2C0C0C; + } + break; + } + case 0x1e907f62u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_3D; + } + break; + } + case 0x1e9088f7u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_3C; + } + break; + } + case 0x1e91c654u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_0C; + } + break; + } + case 0x1e91e675u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_0D; + } + break; + } + case 0x1e96ddc2u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_1D; + } + break; + } + case 0x1e970da3u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_1C; + } + break; + } + case 0x1e9744d7u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_2D; + } + break; + } + case 0x1e9797d2u: + { + if (name.beginsWith(BuiltInName::bitfieldReverse)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_bitfieldReverse_2C; + } + break; + } + case 0x1eb0c64fu: + { + if (name.beginsWith(BuiltInName::bitfieldExtract)) + { + ASSERT(name.length() == 22); + return &BuiltInFunction::kFunction_bitfieldExtract_2C0C0C; + } + break; + } + case 0x1eb0f9fau: + { + if (name == BuiltInName::bitfieldExtract_0D0C0C) + { + return &BuiltInFunction::kFunction_bitfieldExtract_0D0C0C; + } + break; + } + case 0x1eb12f29u: + { + if (name.beginsWith(BuiltInName::bitfieldExtract)) + { + ASSERT(name.length() == 22); + return &BuiltInFunction::kFunction_bitfieldExtract_3D0C0C; + } + break; + } + case 0x1eb17d11u: + { + if (name == BuiltInName::bitfieldExtract_3C0C0C) + { + return &BuiltInFunction::kFunction_bitfieldExtract_3C0C0C; + } + break; + } + case 0x1eb17f7du: + { + if (name.beginsWith(BuiltInName::bitfieldExtract)) + { + ASSERT(name.length() == 22); + return &BuiltInFunction::kFunction_bitfieldExtract_0C0C0C; + } + break; + } + case 0x1eb19a50u: + { + if (name == BuiltInName::bitfieldExtract_1C0C0C) + { + return &BuiltInFunction::kFunction_bitfieldExtract_1C0C0C; + } + break; + } + case 0x1eb28b55u: + { + if (name.beginsWith(BuiltInName::bitfieldExtract)) + { + ASSERT(name.length() == 22); + return &BuiltInFunction::kFunction_bitfieldExtract_2D0C0C; + } + break; + } + case 0x1eb5f0c8u: + { + if (name.beginsWith(BuiltInName::bitfieldExtract)) + { + ASSERT(name.length() == 22); + return &BuiltInFunction::kFunction_bitfieldExtract_1D0C0C; + } + break; + } + case 0x249e7359u: + { + if (name.beginsWith(BuiltInName::memoryBarrierImage)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_memoryBarrierImage_; + } + break; + } + case 0x26a7e24bu: + { + if (name.beginsWith(BuiltInName::memoryBarrierBuffer)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_memoryBarrierBuffer_; + } + break; + } + case 0x26d00e91u: + { + if (name == BuiltInName::textureGatherOffset_0W1B1C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0W1B1C; + } + break; + } + case 0x26d0b451u: + { + if (name.beginsWith(BuiltInName::textureGatherOffset)) + { + ASSERT(name.length() == 26); + return &BuiltInFunction::kFunction_textureGatherOffset_0Q1B1C; + } + break; + } + case 0x26d0db41u: + { + if (name.beginsWith(BuiltInName::textureGatherOffset)) + { + ASSERT(name.length() == 26); + return &BuiltInFunction::kFunction_textureGatherOffset_0Z2B1C; + } + break; + } + case 0x26d1f440u: + { + if (name.beginsWith(BuiltInName::textureGatherOffset)) + { + ASSERT(name.length() == 26); + return &BuiltInFunction::kFunction_textureGatherOffset_0K2B1C; + } + break; + } + case 0x26d2d875u: + { + if (name == BuiltInName::textureGatherOffset_0T2B1C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0T2B1C; + } + break; + } + case 0x26d71952u: + { + if (name.beginsWith(BuiltInName::textureGatherOffset)) + { + ASSERT(name.length() == 26); + return &BuiltInFunction::kFunction_textureGatherOffset_0H1B1C; + } + break; + } + case 0x26e1982cu: + { + if (name == BuiltInName::textureGatherOffset_0T2B1C0C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0T2B1C0C; + } + break; + } + case 0x26e459f8u: + { + if (name == BuiltInName::textureGatherOffset_0K2B1C0C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0K2B1C0C; + } + break; + } + case 0x26e476d0u: + { + if (name == BuiltInName::textureGatherOffset_0H1B1C0C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0H1B1C0C; + } + break; + } + case 0x26e47c82u: + { + if (name == BuiltInName::textureGatherOffset_0Z2B1C0C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0Z2B1C0C; + } + break; + } + case 0x26e53ca1u: + { + if (name == BuiltInName::textureGatherOffset_0e2B0B1C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0e2B0B1C; + } + break; + } + case 0x26e567feu: + { + if (name == BuiltInName::textureGatherOffset_0Q1B1C0C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0Q1B1C0C; + } + break; + } + case 0x26e580eau: + { + if (name == BuiltInName::textureGatherOffset_0c1B0B1C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0c1B0B1C; + } + break; + } + case 0x26e737a0u: + { + if (name == BuiltInName::textureGatherOffset_0W1B1C0C) + { + return &BuiltInFunction::kFunction_textureGatherOffset_0W1B1C0C; + } + break; + } + case 0x2ccf8f34u: + { + if (name.beginsWith(BuiltInName::atomicCounterIncrement)) + { + ASSERT(name.length() == 25); + return &BuiltInFunction::kFunction_atomicCounterIncrement_0F; + } + break; + } + case 0x2ccfbbbeu: + { + if (name.beginsWith(BuiltInName::atomicCounterDecrement)) + { + ASSERT(name.length() == 25); + return &BuiltInFunction::kFunction_atomicCounterDecrement_0F; + } + break; + } + case 0x34ded18du: + { + if (name.beginsWith(BuiltInName::memoryBarrierAtomicCounter)) + { + ASSERT(name.length() == 27); + return &BuiltInFunction::kFunction_memoryBarrierAtomicCounter_; + } + break; + } + case 0x7e2bef7au: + { + if (name == BuiltInName::gl_in) + { + // Only initialized if shaderType == GL_GEOMETRY_SHADER_EXT + return mVar_gl_in; + } + break; + } + case 0x7e8166efu: + { + if (name == BuiltInName::gl_MaxImageUnits) + { + return mVar_gl_MaxImageUnits; + } + break; + } + case 0x7ecf4a1bu: + { + if (name == BuiltInName::gl_MaxVertexImageUniforms) + { + return mVar_gl_MaxVertexImageUniforms; + } + break; + } + case 0x7ed27574u: + { + if (name == BuiltInName::gl_MaxVertexAtomicCounters) + { + return mVar_gl_MaxVertexAtomicCounters; + } + break; + } + case 0x7ed2bd5cu: + { + if (name == BuiltInName::gl_MaxComputeImageUniforms) + { + return mVar_gl_MaxComputeImageUniforms; + } + break; + } + case 0x7ed77973u: + { + if (name == BuiltInName::gl_MaxComputeWorkGroupSize) + { + return mVar_gl_MaxComputeWorkGroupSize; + } + break; + } + case 0x7ed9ae57u: + { + if (name == BuiltInName::gl_MaxCombinedImageUniforms) + { + return mVar_gl_MaxCombinedImageUniforms; + } + break; + } + case 0x7ed9f437u: + { + if (name == BuiltInName::gl_MaxGeometryImageUniforms) + { + return mVar_gl_MaxGeometryImageUniforms; + } + break; + } + case 0x7edacc17u: + { + if (name == BuiltInName::gl_MaxAtomicCounterBindings) + { + return mVar_gl_MaxAtomicCounterBindings; + } + break; + } + case 0x7ede0db3u: + { + if (name == BuiltInName::gl_MaxComputeAtomicCounters) + { + return mVar_gl_MaxComputeAtomicCounters; + } + break; + } + case 0x7edeadeeu: + { + if (name == BuiltInName::gl_MaxComputeWorkGroupCount) + { + return mVar_gl_MaxComputeWorkGroupCount; + } + break; + } + case 0x7edf534au: + { + if (name == BuiltInName::gl_MaxFragmentImageUniforms) + { + return mVar_gl_MaxFragmentImageUniforms; + } + break; + } + case 0x7ee1b439u: + { + if (name == BuiltInName::gl_MaxGeometryOutputVertices) + { + return mVar_gl_MaxGeometryOutputVertices; + } + break; + } + case 0x7ee23dcau: + { + if (name == BuiltInName::gl_MaxFragmentAtomicCounters) + { + return mVar_gl_MaxFragmentAtomicCounters; + } + break; + } + case 0x7ee400c5u: + { + if (name == BuiltInName::gl_MaxCombinedAtomicCounters) + { + return mVar_gl_MaxCombinedAtomicCounters; + } + break; + } + case 0x7ee6d3cfu: + { + if (name == BuiltInName::gl_MaxGeometryAtomicCounters) + { + return mVar_gl_MaxGeometryAtomicCounters; + } + break; + } + case 0x7eec3ae1u: + { + if (name == BuiltInName::gl_MaxGeometryInputComponents) + { + return mVar_gl_MaxGeometryInputComponents; + } + break; + } + case 0x7eecdfadu: + { + if (name == BuiltInName::gl_MaxAtomicCounterBufferSize) + { + return mVar_gl_MaxAtomicCounterBufferSize; + } + break; + } + case 0x7ef00fc2u: + { + if (name == BuiltInName::gl_MaxComputeTextureImageUnits) + { + return mVar_gl_MaxComputeTextureImageUnits; + } + break; + } + case 0x7ef3740bu: + { + if (name == BuiltInName::gl_MaxComputeUniformComponents) + { + return mVar_gl_MaxComputeUniformComponents; + } + break; + } + case 0x7ef69ab4u: + { + if (name == BuiltInName::gl_MaxGeometryOutputComponents) + { + return mVar_gl_MaxGeometryOutputComponents; + } + break; + } + case 0x7ef9b17du: + { + if (name == BuiltInName::gl_MaxGeometryTextureImageUnits) + { + return mVar_gl_MaxGeometryTextureImageUnits; + } + break; + } + case 0x7efe1865u: + { + if (name == BuiltInName::gl_MaxGeometryUniformComponents) + { + return mVar_gl_MaxGeometryUniformComponents; + } + break; + } + case 0x7f008375u: + { + if (name == BuiltInName::gl_MaxVertexAtomicCounterBuffers) + { + return mVar_gl_MaxVertexAtomicCounterBuffers; + } + break; + } + case 0x7f0d626fu: + { + if (name == BuiltInName::gl_MaxComputeAtomicCounterBuffers) + { + return mVar_gl_MaxComputeAtomicCounterBuffers; + } + break; + } + case 0x7f11e359u: + { + if (name == BuiltInName::gl_MaxCombinedAtomicCounterBuffers) + { + return mVar_gl_MaxCombinedAtomicCounterBuffers; + } + break; + } + case 0x7f170f84u: + { + if (name == BuiltInName::gl_MaxGeometryAtomicCounterBuffers) + { + return mVar_gl_MaxGeometryAtomicCounterBuffers; + } + break; + } + case 0x7f17bd18u: + { + if (name == BuiltInName::gl_MaxFragmentAtomicCounterBuffers) + { + return mVar_gl_MaxFragmentAtomicCounterBuffers; + } + break; + } + case 0x7f1c60f8u: + { + if (name == BuiltInName::gl_MaxCombinedShaderOutputResources) + { + return mVar_gl_MaxCombinedShaderOutputResources; + } + break; + } + case 0x7f1cd073u: + { + if (name == BuiltInName::gl_MaxGeometryTotalOutputComponents) + { + return mVar_gl_MaxGeometryTotalOutputComponents; + } + break; + } + } + if (mShaderType == GL_COMPUTE_SHADER) + { + switch (nameHash) + { + case 0x0e41a660u: + { + if (name.beginsWith(BuiltInName::barrier)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_barrier_; + } + break; + } + case 0x249ee97cu: + { + if (name.beginsWith(BuiltInName::groupMemoryBarrier)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_groupMemoryBarrier_; + } + break; + } + case 0x26a4d8e6u: + { + if (name.beginsWith(BuiltInName::memoryBarrierShared)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_memoryBarrierShared_; + } + break; + } + case 0x7e736b62u: + { + if (name == BuiltInName::gl_WorkGroupID) + { + return &BuiltInVariable::kVar_gl_WorkGroupID; + } + break; + } + case 0x7e808e8fu: + { + if (name == BuiltInName::gl_WorkGroupSize) + { + return &BuiltInVariable::kVar_gl_WorkGroupSize; + } + break; + } + case 0x7e82b146u: + { + if (name == BuiltInName::gl_NumWorkGroups) + { + return &BuiltInVariable::kVar_gl_NumWorkGroups; + } + break; + } + case 0x7ea251edu: + { + if (name == BuiltInName::gl_LocalInvocationID) + { + return &BuiltInVariable::kVar_gl_LocalInvocationID; + } + break; + } + case 0x7ead13a8u: + { + if (name == BuiltInName::gl_GlobalInvocationID) + { + return &BuiltInVariable::kVar_gl_GlobalInvocationID; + } + break; + } + case 0x7ebcd395u: + { + if (name == BuiltInName::gl_LocalInvocationIndex) + { + return &BuiltInVariable::kVar_gl_LocalInvocationIndex; + } + break; + } + } + } + if (mShaderType == GL_GEOMETRY_SHADER_EXT) + { + switch (nameHash) + { + case 0x145d55c9u: + { + if (name.beginsWith(BuiltInName::EmitVertex)) + { + ASSERT(name.length() == 11); + return &BuiltInFunction::kFunction_EmitVertex_; + } + break; + } + case 0x186fcde2u: + { + if (name.beginsWith(BuiltInName::EndPrimitive)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_EndPrimitive_; + } + break; + } + case 0x7e400f84u: + { + if (name == BuiltInName::gl_Layer) + { + return &BuiltInVariable::kVar_gl_LayerGS; + } + break; + } + case 0x7e580bc5u: + { + if (name == BuiltInName::gl_Position) + { + return mVar_gl_PositionGS; + } + break; + } + case 0x7e67167au: + { + if (name == BuiltInName::gl_PerVertex) + { + return mVar_gl_PerVertex; + } + break; + } + case 0x7e742076u: + { + if (name == BuiltInName::gl_PrimitiveID) + { + return &BuiltInVariable::kVar_gl_PrimitiveIDGS; + } + break; + } + case 0x7e7fe684u: + { + if (name == BuiltInName::gl_InvocationID) + { + return &BuiltInVariable::kVar_gl_InvocationID; + } + break; + } + case 0x7e865240u: + { + if (name == BuiltInName::gl_PrimitiveIDIn) + { + return &BuiltInVariable::kVar_gl_PrimitiveIDIn; + } + break; + } + } + } + if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_geometry_shader)) + { + switch (nameHash) + { + case 0x7e400f84u: + { + if (name == BuiltInName::gl_Layer) + { + return &BuiltInVariable::kVar_gl_Layer; + } + break; + } + case 0x7e742076u: + { + if (name == BuiltInName::gl_PrimitiveID) + { + return &BuiltInVariable::kVar_gl_PrimitiveID; + } + break; + } + } + } + } + if (shaderVersion >= 300) + { + switch (nameHash) + { + case 0x06309dbcu: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_0C; + } + break; + } + case 0x0631d85fu: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_3C; + } + break; + } + case 0x06370c70u: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_2C; + } + break; + } + case 0x06378eb0u: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_1C; + } + break; + } + case 0x06408ba2u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_2D0D; + } + break; + } + case 0x0640f128u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_1C0C; + } + break; + } + case 0x06420bb0u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_0D0D; + } + break; + } + case 0x064236d1u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_2D2D; + } + break; + } + case 0x06425522u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_3C0C; + } + break; + } + case 0x06425db3u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_2C0C; + } + break; + } + case 0x06429550u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_2D2D; + } + break; + } + case 0x06429e9cu: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_2C0C; + } + break; + } + case 0x0642c869u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_3D3D; + } + break; + } + case 0x0642dbfeu: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_3C3C; + } + break; + } + case 0x064305b5u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_3D3D; + } + break; + } + case 0x06436c9au: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_1D0D; + } + break; + } + case 0x0643ebd5u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_3D0D; + } + break; + } + case 0x06441467u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_2C2C; + } + break; + } + case 0x0644176eu: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_1C1C; + } + break; + } + case 0x06443b94u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_2D0D; + } + break; + } + case 0x06448798u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_3C3C; + } + break; + } + case 0x0644a6dfu: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_1D1D; + } + break; + } + case 0x0644cd73u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_2C2C; + } + break; + } + case 0x06450593u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_1C0C; + } + break; + } + case 0x06452105u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_1D0D; + } + break; + } + case 0x06454045u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_0C0C; + } + break; + } + case 0x0645e25du: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_0C0C; + } + break; + } + case 0x06460349u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_1D1D; + } + break; + } + case 0x06472b16u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_3D0D; + } + break; + } + case 0x06473146u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_0D0D; + } + break; + } + case 0x06475b89u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_3C0C; + } + break; + } + case 0x0647bc75u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_1C1C; + } + break; + } + case 0x0654b2f8u: + { + if (name.beginsWith(BuiltInName::mix)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_mix_2B2B2E; + } + break; + } + case 0x0655a7e2u: + { + if (name == BuiltInName::mix_0B0B0E) + { + return &BuiltInFunction::kFunction_mix_0B0B0E; + } + break; + } + case 0x06567d08u: + { + if (name.beginsWith(BuiltInName::mix)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_mix_3B3B3E; + } + break; + } + case 0x0657f3adu: + { + if (name == BuiltInName::mix_1B1B1E) + { + return &BuiltInFunction::kFunction_mix_1B1B1E; + } + break; + } + case 0x0838025eu: + { + if (name.beginsWith(BuiltInName::tanh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_tanh_3B; + } + break; + } + case 0x0838944cu: + { + if (name.beginsWith(BuiltInName::tanh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_tanh_0B; + } + break; + } + case 0x08392747u: + { + if (name.beginsWith(BuiltInName::sinh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sinh_2B; + } + break; + } + case 0x08398f4au: + { + if (name.beginsWith(BuiltInName::sinh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sinh_1B; + } + break; + } + case 0x083991ddu: + { + if (name.beginsWith(BuiltInName::tanh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_tanh_1B; + } + break; + } + case 0x083aa373u: + { + if (name.beginsWith(BuiltInName::sinh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sinh_0B; + } + break; + } + case 0x083acb5eu: + { + if (name.beginsWith(BuiltInName::tanh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_tanh_2B; + } + break; + } + case 0x083acbf5u: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_1C; + } + break; + } + case 0x083b5c45u: + { + if (name.beginsWith(BuiltInName::cosh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_cosh_0B; + } + break; + } + case 0x083bd9f8u: + { + if (name.beginsWith(BuiltInName::sinh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sinh_3B; + } + break; + } + case 0x083c1656u: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_2C; + } + break; + } + case 0x083c57c4u: + { + if (name.beginsWith(BuiltInName::cosh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_cosh_1B; + } + break; + } + case 0x083d503bu: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_3C; + } + break; + } + case 0x083d8227u: + { + if (name.beginsWith(BuiltInName::cosh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_cosh_2B; + } + break; + } + case 0x083dd369u: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_0C; + } + break; + } + case 0x083ed2deu: + { + if (name.beginsWith(BuiltInName::cosh)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_cosh_3B; + } + break; + } + case 0x084807e9u: + { + if (name.beginsWith(BuiltInName::modf)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_modf_3B3B; + } + break; + } + case 0x084a908au: + { + if (name.beginsWith(BuiltInName::modf)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_modf_1B1B; + } + break; + } + case 0x084bf445u: + { + if (name.beginsWith(BuiltInName::modf)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_modf_0B0B; + } + break; + } + case 0x084fa835u: + { + if (name.beginsWith(BuiltInName::modf)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_modf_2B2B; + } + break; + } + case 0x0a400148u: + { + if (name.beginsWith(BuiltInName::asinh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_asinh_2B; + } + break; + } + case 0x0a406460u: + { + if (name.beginsWith(BuiltInName::isnan)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isnan_2B; + } + break; + } + case 0x0a407c52u: + { + if (name.beginsWith(BuiltInName::round)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_round_0B; + } + break; + } + case 0x0a412446u: + { + if (name.beginsWith(BuiltInName::trunc)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_trunc_0B; + } + break; + } + case 0x0a4125d1u: + { + if (name.beginsWith(BuiltInName::asinh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_asinh_3B; + } + break; + } + case 0x0a4189d9u: + { + if (name.beginsWith(BuiltInName::round)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_round_3B; + } + break; + } + case 0x0a41bc4bu: + { + if (name.beginsWith(BuiltInName::trunc)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_trunc_3B; + } + break; + } + case 0x0a4262ceu: + { + if (name.beginsWith(BuiltInName::isinf)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isinf_2B; + } + break; + } + case 0x0a42b872u: + { + if (name.beginsWith(BuiltInName::trunc)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_trunc_2B; + } + break; + } + case 0x0a430643u: + { + if (name.beginsWith(BuiltInName::atanh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_atanh_2B; + } + break; + } + case 0x0a43b397u: + { + if (name.beginsWith(BuiltInName::isinf)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isinf_3B; + } + break; + } + case 0x0a43edf9u: + { + if (name.beginsWith(BuiltInName::trunc)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_trunc_1B; + } + break; + } + case 0x0a4431a8u: + { + if (name.beginsWith(BuiltInName::atanh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_atanh_1B; + } + break; + } + case 0x0a443a26u: + { + if (name.beginsWith(BuiltInName::isinf)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isinf_0B; + } + break; + } + case 0x0a44ad91u: + { + if (name.beginsWith(BuiltInName::acosh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_acosh_1B; + } + break; + } + case 0x0a452617u: + { + if (name.beginsWith(BuiltInName::isinf)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isinf_1B; + } + break; + } + case 0x0a4561b0u: + { + if (name.beginsWith(BuiltInName::isnan)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isnan_3B; + } + break; + } + case 0x0a4582c9u: + { + if (name.beginsWith(BuiltInName::atanh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_atanh_0B; + } + break; + } + case 0x0a45fcfdu: + { + if (name.beginsWith(BuiltInName::atanh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_atanh_3B; + } + break; + } + case 0x0a461d10u: + { + if (name.beginsWith(BuiltInName::acosh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_acosh_0B; + } + break; + } + case 0x0a464ad3u: + { + if (name.beginsWith(BuiltInName::asinh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_asinh_0B; + } + break; + } + case 0x0a46778au: + { + if (name.beginsWith(BuiltInName::acosh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_acosh_3B; + } + break; + } + case 0x0a46ab3bu: + { + if (name.beginsWith(BuiltInName::isnan)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isnan_0B; + } + break; + } + case 0x0a46f2d2u: + { + if (name.beginsWith(BuiltInName::round)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_round_2B; + } + break; + } + case 0x0a4758c8u: + { + if (name.beginsWith(BuiltInName::round)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_round_1B; + } + break; + } + case 0x0a478c93u: + { + if (name.beginsWith(BuiltInName::acosh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_acosh_2B; + } + break; + } + case 0x0a47bb52u: + { + if (name.beginsWith(BuiltInName::asinh)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_asinh_1B; + } + break; + } + case 0x0a47fa7au: + { + if (name.beginsWith(BuiltInName::isnan)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_isnan_1B; + } + break; + } + case 0x0a524bc4u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_2D2D; + } + break; + } + case 0x0a5613e7u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_1D1D; + } + break; + } + case 0x0a56ba24u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_3D3D; + } + break; + } + case 0x0a601dd8u: + { + if (name == BuiltInName::clamp_2C2C2C) + { + return &BuiltInFunction::kFunction_clamp_2C2C2C; + } + break; + } + case 0x0a60570du: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_1D0D0D; + } + break; + } + case 0x0a60d0c5u: + { + if (name == BuiltInName::clamp_1C0C0C) + { + return &BuiltInFunction::kFunction_clamp_1C0C0C; + } + break; + } + case 0x0a621a2bu: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_0C0C0C; + } + break; + } + case 0x0a623042u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_2D0D0D; + } + break; + } + case 0x0a624f01u: + { + if (name == BuiltInName::clamp_3C0C0C) + { + return &BuiltInFunction::kFunction_clamp_3C0C0C; + } + break; + } + case 0x0a62ab50u: + { + if (name == BuiltInName::clamp_1C1C1C) + { + return &BuiltInFunction::kFunction_clamp_1C1C1C; + } + break; + } + case 0x0a631d0bu: + { + if (name == BuiltInName::clamp_1D1D1D) + { + return &BuiltInFunction::kFunction_clamp_1D1D1D; + } + break; + } + case 0x0a64f567u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_2D2D2D; + } + break; + } + case 0x0a656274u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_3C3C3C; + } + break; + } + case 0x0a65a625u: + { + if (name == BuiltInName::clamp_3D0D0D) + { + return &BuiltInFunction::kFunction_clamp_3D0D0D; + } + break; + } + case 0x0a660047u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_2C0C0C; + } + break; + } + case 0x0a660f60u: + { + if (name == BuiltInName::clamp_0D0D0D) + { + return &BuiltInFunction::kFunction_clamp_0D0D0D; + } + break; + } + case 0x0a674065u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_3D3D3D; + } + break; + } + case 0x0e503084u: + { + if (name.beginsWith(BuiltInName::inverse)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_inverse_5B; + } + break; + } + case 0x0e507cbdu: + { + if (name.beginsWith(BuiltInName::inverse)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_inverse_AB; + } + break; + } + case 0x0e50cc43u: + { + if (name.beginsWith(BuiltInName::inverse)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_inverse_FB; + } + break; + } + case 0x0e600d82u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0c2B; + } + break; + } + case 0x0e60445cu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0S2B; + } + break; + } + case 0x0e6044aeu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0e3B; + } + break; + } + case 0x0e60bb56u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0Q1B; + } + break; + } + case 0x0e61222eu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0K2B; + } + break; + } + case 0x0e61e49du: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0Z2B; + } + break; + } + case 0x0e625169u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0I2B; + } + break; + } + case 0x0e62790eu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0T2B; + } + break; + } + case 0x0e63b9efu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0M1B; + } + break; + } + case 0x0e6470f1u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0J2B; + } + break; + } + case 0x0e64854cu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0X2B; + } + break; + } + case 0x0e64ec86u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0W1B; + } + break; + } + case 0x0e65ea73u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0H1B; + } + break; + } + case 0x0e661665u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0L1B; + } + break; + } + case 0x0e663be3u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0N1B; + } + break; + } + case 0x0e67665bu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0d3B; + } + break; + } + case 0x0e67a979u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0R2B; + } + break; + } + case 0x0e67dce5u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_texture_0Y2B; + } + break; + } + case 0x106843efu: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_3D3D; + } + break; + } + case 0x10697de8u: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_2D2D; + } + break; + } + case 0x106ad530u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_1D1D; + } + break; + } + case 0x106d7bd6u: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_1D1D; + } + break; + } + case 0x106e2903u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_3D3D; + } + break; + } + case 0x106e7a45u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_2D2D; + } + break; + } + case 0x12601c9du: + { + if (name.beginsWith(BuiltInName::roundEven)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_roundEven_3B; + } + break; + } + case 0x12602fd7u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_AB; + } + break; + } + case 0x12614fd4u: + { + if (name.beginsWith(BuiltInName::roundEven)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_roundEven_2B; + } + break; + } + case 0x1264f5e4u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_EB; + } + break; + } + case 0x12650771u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_6B; + } + break; + } + case 0x12655b22u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_BB; + } + break; + } + case 0x12658f24u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_9B; + } + break; + } + case 0x1265cf4cu: + { + if (name.beginsWith(BuiltInName::roundEven)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_roundEven_1B; + } + break; + } + case 0x12661b07u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_FB; + } + break; + } + case 0x12665430u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_7B; + } + break; + } + case 0x1266c2deu: + { + if (name.beginsWith(BuiltInName::roundEven)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_roundEven_0B; + } + break; + } + case 0x1267db60u: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_5B; + } + break; + } + case 0x1267de6cu: + { + if (name.beginsWith(BuiltInName::transpose)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_transpose_DB; + } + break; + } + case 0x1273f9dbu: + { + if (name.beginsWith(BuiltInName::yuv_2_rgb)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_yuv_2_rgb_2B0G; + } + break; + } + case 0x127589a7u: + { + if (name.beginsWith(BuiltInName::rgb_2_yuv)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_rgb_2_yuv_2B0G; + } + break; + } + case 0x14882ba7u: + { + if (name.beginsWith(BuiltInName::textureLod)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_textureLod_0X2B0B; + } + break; + } + case 0x14885983u: + { + if (name.beginsWith(BuiltInName::texelFetch)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetch_0R2C0C; + } + break; + } + case 0x14885e67u: + { + if (name == BuiltInName::texelFetch_0Z2C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0Z2C0C; + } + break; + } + case 0x1488a5bfu: + { + if (name == BuiltInName::textureLod_0W1B0B) + { + return &BuiltInFunction::kFunction_textureLod_0W1B0B; + } + break; + } + case 0x14896e41u: + { + if (name == BuiltInName::texelFetchExt_0O1C0C) + { + return &BuiltInFunction::kFunction_texelFetchExt_0O1C0C; + } + break; + } + case 0x1489e510u: + { + if (name.beginsWith(BuiltInName::textureLod)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_textureLod_0T2B0B; + } + break; + } + case 0x148a14a7u: + { + if (name.beginsWith(BuiltInName::texelFetch)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetch_0M1C0C; + } + break; + } + case 0x148a66beu: + { + if (name == BuiltInName::textureLod_0S2B0B) + { + return &BuiltInFunction::kFunction_textureLod_0S2B0B; + } + break; + } + case 0x148a95e7u: + { + if (name.beginsWith(BuiltInName::textureLod)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_textureLod_0c2B0B; + } + break; + } + case 0x148b00dbu: + { + if (name == BuiltInName::textureLod_0J2B0B) + { + return &BuiltInFunction::kFunction_textureLod_0J2B0B; + } + break; + } + case 0x148b33b6u: + { + if (name.beginsWith(BuiltInName::textureLod)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_textureLod_0H1B0B; + } + break; + } + case 0x148bab65u: + { + if (name == BuiltInName::texelFetch_0I2C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0I2C0C; + } + break; + } + case 0x148cccafu: + { + if (name.beginsWith(BuiltInName::textureLod)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_textureLod_0R2B0B; + } + break; + } + case 0x148d0a7bu: + { + if (name == BuiltInName::texelFetch_0K2C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0K2C0C; + } + break; + } + case 0x148d335cu: + { + if (name.beginsWith(BuiltInName::textureLod)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_textureLod_0I2B0B; + } + break; + } + case 0x148ddb10u: + { + if (name.beginsWith(BuiltInName::texelFetchExt)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetchExt_0a1C0C; + } + break; + } + case 0x148e100eu: + { + if (name == BuiltInName::texelFetch_0X2C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0X2C0C; + } + break; + } + case 0x148e44d3u: + { + if (name == BuiltInName::textureLod_0Y2B0B) + { + return &BuiltInFunction::kFunction_textureLod_0Y2B0B; + } + break; + } + case 0x148e5d86u: + { + if (name == BuiltInName::texelFetch_0Q1C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0Q1C0C; + } + break; + } + case 0x148e6d96u: + { + if (name.beginsWith(BuiltInName::texelFetch)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetch_0W1C0C; + } + break; + } + case 0x148ed16fu: + { + if (name.beginsWith(BuiltInName::texelFetchExt)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_texelFetchExt_0U1C0C; + } + break; + } + case 0x148ed87fu: + { + if (name.beginsWith(BuiltInName::textureLod)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_textureLod_0K2B0B; + } + break; + } + case 0x148eff58u: + { + if (name == BuiltInName::texelFetch_0L1C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0L1C0C; + } + break; + } + case 0x148fa8bbu: + { + if (name == BuiltInName::textureLod_0Q1B0B) + { + return &BuiltInFunction::kFunction_textureLod_0Q1B0B; + } + break; + } + case 0x148fb13cu: + { + if (name == BuiltInName::texelFetch_0T2C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0T2C0C; + } + break; + } + case 0x148fd5b6u: + { + if (name == BuiltInName::texelFetch_0H1C0C) + { + return &BuiltInFunction::kFunction_texelFetch_0H1C0C; + } + break; + } + case 0x148fe911u: + { + if (name == BuiltInName::textureLod_0Z2B0B) + { + return &BuiltInFunction::kFunction_textureLod_0Z2B0B; + } + break; + } + case 0x167394d8u: + { + if (name.beginsWith(BuiltInName::textureSizeExt)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSizeExt_0U; + } + break; + } + case 0x1673f496u: + { + if (name.beginsWith(BuiltInName::textureSizeExt)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSizeExt_0O; + } + break; + } + case 0x1674ed12u: + { + if (name.beginsWith(BuiltInName::determinant)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_determinant_FB; + } + break; + } + case 0x16752ab6u: + { + if (name.beginsWith(BuiltInName::textureSizeExt)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_textureSizeExt_0a; + } + break; + } + case 0x1676ad75u: + { + if (name.beginsWith(BuiltInName::determinant)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_determinant_5B; + } + break; + } + case 0x167719ccu: + { + if (name.beginsWith(BuiltInName::determinant)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_determinant_AB; + } + break; + } + case 0x16803d05u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0I0C; + } + break; + } + case 0x168046b0u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0M0C; + } + break; + } + case 0x168093aau: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0T0C; + } + break; + } + case 0x168115fbu: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0e0C; + } + break; + } + case 0x16812c54u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_3D3D; + } + break; + } + case 0x16812eeeu: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0W3B; + } + break; + } + case 0x168174f7u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_1D1D; + } + break; + } + case 0x168178c7u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0H2B; + } + break; + } + case 0x1681d6b4u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_2D2D; + } + break; + } + case 0x1681f153u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0J0C; + } + break; + } + case 0x168245a4u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0S0C; + } + break; + } + case 0x1682b6c4u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0X3B; + } + break; + } + case 0x1682d0c8u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0M2B; + } + break; + } + case 0x1682d660u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0Y0C; + } + break; + } + case 0x16838d15u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0L2B; + } + break; + } + case 0x1683ecb1u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0M3B; + } + break; + } + case 0x16840064u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0H3B; + } + break; + } + case 0x168434eeu: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0H0C; + } + break; + } + case 0x16845c90u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0L0C; + } + break; + } + case 0x16846c6cu: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0W0C; + } + break; + } + case 0x16849618u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0Z0C; + } + break; + } + case 0x1684f1b3u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0d0C; + } + break; + } + case 0x1685011eu: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0Q2B; + } + break; + } + case 0x1685b785u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0N3B; + } + break; + } + case 0x1685ca01u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0I3B; + } + break; + } + case 0x16860d28u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0Q3B; + } + break; + } + case 0x16861104u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0K0C; + } + break; + } + case 0x16863c73u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0R0C; + } + break; + } + case 0x16865716u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0L3B; + } + break; + } + case 0x16869d00u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0Q0C; + } + break; + } + case 0x1686a82au: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0X0C; + } + break; + } + case 0x1686aa87u: + { + if (name.beginsWith(BuiltInName::textureSize)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureSize_0c0C; + } + break; + } + case 0x1686cb94u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0N2B; + } + break; + } + case 0x16875a59u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0c3B; + } + break; + } + case 0x1687c54du: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0R3B; + } + break; + } + case 0x1687d107u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureProj_0W2B; + } + break; + } + case 0x16a00e04u: + { + if (name == BuiltInName::textureGrad_0I2B2B2B) + { + return &BuiltInFunction::kFunction_textureGrad_0I2B2B2B; + } + break; + } + case 0x16a04ad9u: + { + if (name == BuiltInName::textureGrad_0X2B2B2B) + { + return &BuiltInFunction::kFunction_textureGrad_0X2B2B2B; + } + break; + } + case 0x16a1478fu: + { + if (name == BuiltInName::textureGrad_0e3B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0e3B1B1B; + } + break; + } + case 0x16a19c8du: + { + if (name == BuiltInName::textureGrad_0H1B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0H1B1B1B; + } + break; + } + case 0x16a1ec87u: + { + if (name == BuiltInName::textureGrad_0J2B2B2B) + { + return &BuiltInFunction::kFunction_textureGrad_0J2B2B2B; + } + break; + } + case 0x16a2ff3du: + { + if (name == BuiltInName::textureGrad_0Q1B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0Q1B1B1B; + } + break; + } + case 0x16a34692u: + { + if (name == BuiltInName::textureGrad_0R2B2B2B) + { + return &BuiltInFunction::kFunction_textureGrad_0R2B2B2B; + } + break; + } + case 0x16a3a842u: + { + if (name == BuiltInName::textureGrad_0c2B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0c2B1B1B; + } + break; + } + case 0x16a3b8f6u: + { + if (name == BuiltInName::textureGrad_0Y2B2B2B) + { + return &BuiltInFunction::kFunction_textureGrad_0Y2B2B2B; + } + break; + } + case 0x16a4a66cu: + { + if (name == BuiltInName::textureGrad_0W1B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0W1B1B1B; + } + break; + } + case 0x16a4e27cu: + { + if (name == BuiltInName::textureGrad_0d3B2B2B) + { + return &BuiltInFunction::kFunction_textureGrad_0d3B2B2B; + } + break; + } + case 0x16a66883u: + { + if (name == BuiltInName::textureGrad_0T2B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0T2B1B1B; + } + break; + } + case 0x16a68a81u: + { + if (name == BuiltInName::textureGrad_0S2B2B2B) + { + return &BuiltInFunction::kFunction_textureGrad_0S2B2B2B; + } + break; + } + case 0x16a6a742u: + { + if (name == BuiltInName::textureGrad_0Z2B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0Z2B1B1B; + } + break; + } + case 0x16a71104u: + { + if (name == BuiltInName::textureGrad_0K2B1B1B) + { + return &BuiltInFunction::kFunction_textureGrad_0K2B1B1B; + } + break; + } + case 0x187df788u: + { + if (name.beginsWith(BuiltInName::packHalf2x16)) + { + ASSERT(name.length() == 15); + return &BuiltInFunction::kFunction_packHalf2x16_1B; + } + break; + } + case 0x18887331u: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_2B3B; + } + break; + } + case 0x188880cbu: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_1B1B; + } + break; + } + case 0x1888c44du: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_3B2B; + } + break; + } + case 0x188916c3u: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_1B2B; + } + break; + } + case 0x188a12cau: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_1B3B; + } + break; + } + case 0x188db87au: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_2B2B; + } + break; + } + case 0x188e0232u: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_3B3B; + } + break; + } + case 0x188e2270u: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_2B1B; + } + break; + } + case 0x188f8feeu: + { + if (name.beginsWith(BuiltInName::outerProduct)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_outerProduct_3B1B; + } + break; + } + case 0x1a84fa77u: + { + if (name.beginsWith(BuiltInName::packSnorm2x16)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_packSnorm2x16_1B; + } + break; + } + case 0x1a873678u: + { + if (name.beginsWith(BuiltInName::packUnorm2x16)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_packUnorm2x16_1B; + } + break; + } + case 0x1a92589du: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_2D2D; + } + break; + } + case 0x1a95efdcu: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_1D1D; + } + break; + } + case 0x1a96ec62u: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_3D3D; + } + break; + } + case 0x1aa01270u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0Q1B1C; + } + break; + } + case 0x1aa05156u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0c2B1C; + } + break; + } + case 0x1aa11785u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0H1B1C; + } + break; + } + case 0x1aa26095u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0T2B1C; + } + break; + } + case 0x1aa31637u: + { + if (name == BuiltInName::textureOffset_0X2B2C) + { + return &BuiltInFunction::kFunction_textureOffset_0X2B2C; + } + break; + } + case 0x1aa385c2u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0Z2B1C; + } + break; + } + case 0x1aa41f4au: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0K2B1C; + } + break; + } + case 0x1aa541b7u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0W1B1C; + } + break; + } + case 0x1aa64995u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0I2B2C; + } + break; + } + case 0x1aa7a781u: + { + if (name.beginsWith(BuiltInName::textureOffset)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_textureOffset_0R2B2C; + } + break; + } + case 0x1c887424u: + { + if (name.beginsWith(BuiltInName::intBitsToFloat)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_intBitsToFloat_2C; + } + break; + } + case 0x1c887f5eu: + { + if (name.beginsWith(BuiltInName::floatBitsToInt)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_floatBitsToInt_2B; + } + break; + } + case 0x1c88f18cu: + { + if (name.beginsWith(BuiltInName::intBitsToFloat)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_intBitsToFloat_1C; + } + break; + } + case 0x1c89b11cu: + { + if (name.beginsWith(BuiltInName::floatBitsToInt)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_floatBitsToInt_1B; + } + break; + } + case 0x1c89e261u: + { + if (name.beginsWith(BuiltInName::intBitsToFloat)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_intBitsToFloat_0C; + } + break; + } + case 0x1c8ae0a5u: + { + if (name.beginsWith(BuiltInName::floatBitsToInt)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_floatBitsToInt_0B; + } + break; + } + case 0x1c8b20dau: + { + if (name.beginsWith(BuiltInName::intBitsToFloat)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_intBitsToFloat_3C; + } + break; + } + case 0x1c8dd4e6u: + { + if (name.beginsWith(BuiltInName::unpackHalf2x16)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_unpackHalf2x16_0D; + } + break; + } + case 0x1c8f60afu: + { + if (name.beginsWith(BuiltInName::floatBitsToInt)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_floatBitsToInt_3B; + } + break; + } + case 0x1c9876e4u: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_9B9B; + } + break; + } + case 0x1c99affcu: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_7B7B; + } + break; + } + case 0x1c9c8697u: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_6B6B; + } + break; + } + case 0x1c9ccd5au: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_BBBB; + } + break; + } + case 0x1c9ea241u: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_DBDB; + } + break; + } + case 0x1c9fa571u: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_EBEB; + } + break; + } + case 0x1ca81af6u: + { + if (name.beginsWith(BuiltInName::textureProjLod)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_textureProjLod_0c3B0B; + } + break; + } + case 0x1ca85d55u: + { + if (name == BuiltInName::textureProjLod_0Q3B0B) + { + return &BuiltInFunction::kFunction_textureProjLod_0Q3B0B; + } + break; + } + case 0x1ca8c89au: + { + if (name == BuiltInName::textureProjLod_0H3B0B) + { + return &BuiltInFunction::kFunction_textureProjLod_0H3B0B; + } + break; + } + case 0x1ca9ff27u: + { + if (name.beginsWith(BuiltInName::textureProjLod)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_textureProjLod_0W2B0B; + } + break; + } + case 0x1caa108bu: + { + if (name.beginsWith(BuiltInName::textureProjLod)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_textureProjLod_0H2B0B; + } + break; + } + case 0x1caa957cu: + { + if (name == BuiltInName::textureProjLod_0Q2B0B) + { + return &BuiltInFunction::kFunction_textureProjLod_0Q2B0B; + } + break; + } + case 0x1cab3a35u: + { + if (name.beginsWith(BuiltInName::textureProjLod)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_textureProjLod_0W3B0B; + } + break; + } + case 0x1cadb5feu: + { + if (name.beginsWith(BuiltInName::textureProjLod)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_textureProjLod_0X3B0B; + } + break; + } + case 0x1cae6ef8u: + { + if (name.beginsWith(BuiltInName::textureProjLod)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_textureProjLod_0R3B0B; + } + break; + } + case 0x1caf96afu: + { + if (name == BuiltInName::textureProjLod_0I3B0B) + { + return &BuiltInFunction::kFunction_textureProjLod_0I3B0B; + } + break; + } + case 0x1e903284u: + { + if (name.beginsWith(BuiltInName::floatBitsToUint)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_floatBitsToUint_0B; + } + break; + } + case 0x1e92e353u: + { + if (name.beginsWith(BuiltInName::uintBitsToFloat)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_uintBitsToFloat_3D; + } + break; + } + case 0x1e93c13fu: + { + if (name.beginsWith(BuiltInName::uintBitsToFloat)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_uintBitsToFloat_0D; + } + break; + } + case 0x1e95201fu: + { + if (name.beginsWith(BuiltInName::floatBitsToUint)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_floatBitsToUint_1B; + } + break; + } + case 0x1e95511bu: + { + if (name.beginsWith(BuiltInName::unpackSnorm2x16)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_unpackSnorm2x16_0D; + } + break; + } + case 0x1e95582au: + { + if (name.beginsWith(BuiltInName::uintBitsToFloat)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_uintBitsToFloat_1D; + } + break; + } + case 0x1e95b0a7u: + { + if (name.beginsWith(BuiltInName::uintBitsToFloat)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_uintBitsToFloat_2D; + } + break; + } + case 0x1e966adcu: + { + if (name.beginsWith(BuiltInName::floatBitsToUint)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_floatBitsToUint_2B; + } + break; + } + case 0x1e9718ffu: + { + if (name.beginsWith(BuiltInName::unpackUnorm2x16)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_unpackUnorm2x16_0D; + } + break; + } + case 0x1e97a505u: + { + if (name.beginsWith(BuiltInName::floatBitsToUint)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_floatBitsToUint_3B; + } + break; + } + case 0x1ec1a98bu: + { + if (name == BuiltInName::textureProjGrad_0Q2B1B1B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0Q2B1B1B; + } + break; + } + case 0x1ec2304bu: + { + if (name == BuiltInName::textureProjGrad_0X3B2B2B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0X3B2B2B; + } + break; + } + case 0x1ec25826u: + { + if (name == BuiltInName::textureProjGrad_0W2B1B1B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0W2B1B1B; + } + break; + } + case 0x1ec323fdu: + { + if (name == BuiltInName::textureProjGrad_0H3B1B1B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0H3B1B1B; + } + break; + } + case 0x1ec3ee61u: + { + if (name == BuiltInName::textureProjGrad_0I3B2B2B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0I3B2B2B; + } + break; + } + case 0x1ec578cfu: + { + if (name == BuiltInName::textureProjGrad_0R3B2B2B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0R3B2B2B; + } + break; + } + case 0x1ec5ab9du: + { + if (name == BuiltInName::textureProjGrad_0H2B1B1B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0H2B1B1B; + } + break; + } + case 0x1ec5fc9fu: + { + if (name == BuiltInName::textureProjGrad_0Q3B1B1B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0Q3B1B1B; + } + break; + } + case 0x1ec67b05u: + { + if (name == BuiltInName::textureProjGrad_0W3B1B1B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0W3B1B1B; + } + break; + } + case 0x1ec719d1u: + { + if (name == BuiltInName::textureProjGrad_0c3B1B1B) + { + return &BuiltInFunction::kFunction_textureProjGrad_0c3B1B1B; + } + break; + } + case 0x20a92dc6u: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_2D2D; + } + break; + } + case 0x20ae96edu: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_3D3D; + } + break; + } + case 0x20aedbacu: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_1D1D; + } + break; + } + case 0x20c8fa96u: + { + if (name == BuiltInName::texelFetchOffset_0I2C0C2C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0I2C0C2C; + } + break; + } + case 0x20c9733bu: + { + if (name == BuiltInName::textureLodOffset_0c2B0B1C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0c2B0B1C; + } + break; + } + case 0x20c9a178u: + { + if (name == BuiltInName::texelFetchOffset_0X2C0C2C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0X2C0C2C; + } + break; + } + case 0x20ca4914u: + { + if (name == BuiltInName::textureLodOffset_0Z2B0B1C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0Z2B0B1C; + } + break; + } + case 0x20cac068u: + { + if (name == BuiltInName::texelFetchOffset_0K2C0C1C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0K2C0C1C; + } + break; + } + case 0x20cb3102u: + { + if (name == BuiltInName::texelFetchOffset_0H1C0C1C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0H1C0C1C; + } + break; + } + case 0x20cb952du: + { + if (name == BuiltInName::texelFetchOffset_0Z2C0C1C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0Z2C0C1C; + } + break; + } + case 0x20cbf8d9u: + { + if (name == BuiltInName::texelFetchOffset_0W1C0C1C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0W1C0C1C; + } + break; + } + case 0x20cbfefau: + { + if (name == BuiltInName::texelFetchOffset_0R2C0C2C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0R2C0C2C; + } + break; + } + case 0x20cc1a52u: + { + if (name == BuiltInName::texelFetchOffset_0Q1C0C1C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0Q1C0C1C; + } + break; + } + case 0x20cc9477u: + { + if (name == BuiltInName::textureLodOffset_0H1B0B1C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0H1B0B1C; + } + break; + } + case 0x20ccf3edu: + { + if (name == BuiltInName::textureLodOffset_0Q1B0B1C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0Q1B0B1C; + } + break; + } + case 0x20cd0de3u: + { + if (name == BuiltInName::textureLodOffset_0K2B0B1C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0K2B0B1C; + } + break; + } + case 0x20cd8d8du: + { + if (name == BuiltInName::textureLodOffset_0T2B0B1C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0T2B0B1C; + } + break; + } + case 0x20cdc61au: + { + if (name == BuiltInName::textureLodOffset_0W1B0B1C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0W1B0B1C; + } + break; + } + case 0x20cde370u: + { + if (name == BuiltInName::textureLodOffset_0X2B0B2C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0X2B0B2C; + } + break; + } + case 0x20cde748u: + { + if (name == BuiltInName::textureLodOffset_0I2B0B2C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0I2B0B2C; + } + break; + } + case 0x20ceb3dau: + { + if (name == BuiltInName::textureLodOffset_0R2B0B2C) + { + return &BuiltInFunction::kFunction_textureLodOffset_0R2B0B2C; + } + break; + } + case 0x20cfe609u: + { + if (name == BuiltInName::texelFetchOffset_0T2C0C1C) + { + return &BuiltInFunction::kFunction_texelFetchOffset_0T2C0C1C; + } + break; + } + case 0x22c03489u: + { + if (name.beginsWith(BuiltInName::textureProjOffset)) + { + ASSERT(name.length() == 24); + return &BuiltInFunction::kFunction_textureProjOffset_0W2B1C; + } + break; + } + case 0x22c0a359u: + { + if (name == BuiltInName::textureProjOffset_0H2B1C) + { + return &BuiltInFunction::kFunction_textureProjOffset_0H2B1C; + } + break; + } + case 0x22c19992u: + { + if (name.beginsWith(BuiltInName::textureProjOffset)) + { + ASSERT(name.length() == 24); + return &BuiltInFunction::kFunction_textureProjOffset_0c3B1C; + } + break; + } + case 0x22c246a2u: + { + if (name == BuiltInName::textureProjOffset_0Q3B1C) + { + return &BuiltInFunction::kFunction_textureProjOffset_0Q3B1C; + } + break; + } + case 0x22c29005u: + { + if (name == BuiltInName::textureProjOffset_0Q2B1C) + { + return &BuiltInFunction::kFunction_textureProjOffset_0Q2B1C; + } + break; + } + case 0x22c2da46u: + { + if (name == BuiltInName::textureProjOffset_0H3B1C) + { + return &BuiltInFunction::kFunction_textureProjOffset_0H3B1C; + } + break; + } + case 0x22c3e359u: + { + if (name == BuiltInName::textureProjOffset_0W3B1C) + { + return &BuiltInFunction::kFunction_textureProjOffset_0W3B1C; + } + break; + } + case 0x22c43880u: + { + if (name.beginsWith(BuiltInName::textureProjOffset)) + { + ASSERT(name.length() == 24); + return &BuiltInFunction::kFunction_textureProjOffset_0R3B2C; + } + break; + } + case 0x22c458dcu: + { + if (name.beginsWith(BuiltInName::textureProjOffset)) + { + ASSERT(name.length() == 24); + return &BuiltInFunction::kFunction_textureProjOffset_0I3B2C; + } + break; + } + case 0x22c47909u: + { + if (name == BuiltInName::textureProjOffset_0X3B2C) + { + return &BuiltInFunction::kFunction_textureProjOffset_0X3B2C; + } + break; + } + case 0x22e0fe8cu: + { + if (name == BuiltInName::textureGradOffset_0W1B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0W1B1B1B1C; + } + break; + } + case 0x22e165b8u: + { + if (name == BuiltInName::textureGradOffset_0K2B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0K2B1B1B1C; + } + break; + } + case 0x22e28d80u: + { + if (name == BuiltInName::textureGradOffset_0T2B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0T2B1B1B1C; + } + break; + } + case 0x22e3ab1cu: + { + if (name == BuiltInName::textureGradOffset_0e3B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0e3B1B1B1C; + } + break; + } + case 0x22e3e9eau: + { + if (name == BuiltInName::textureGradOffset_0I2B2B2B2C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0I2B2B2B2C; + } + break; + } + case 0x22e5bb38u: + { + if (name == BuiltInName::textureGradOffset_0R2B2B2B2C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0R2B2B2B2C; + } + break; + } + case 0x22e5c876u: + { + if (name == BuiltInName::textureGradOffset_0Q1B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0Q1B1B1B1C; + } + break; + } + case 0x22e61729u: + { + if (name == BuiltInName::textureGradOffset_0X2B2B2B2C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0X2B2B2B2C; + } + break; + } + case 0x22e68293u: + { + if (name == BuiltInName::textureGradOffset_0Z2B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0Z2B1B1B1C; + } + break; + } + case 0x22e71012u: + { + if (name == BuiltInName::textureGradOffset_0H1B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0H1B1B1B1C; + } + break; + } + case 0x22e7429eu: + { + if (name == BuiltInName::textureGradOffset_0c2B1B1B1C) + { + return &BuiltInFunction::kFunction_textureGradOffset_0c2B1B1B1C; + } + break; + } + case 0x28e8b7d0u: + { + if (name == BuiltInName::textureProjLodOffset_0W3B0B1C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0W3B0B1C; + } + break; + } + case 0x28e91d51u: + { + if (name == BuiltInName::textureProjLodOffset_0R3B0B2C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0R3B0B2C; + } + break; + } + case 0x28e9a246u: + { + if (name == BuiltInName::textureProjLodOffset_0W2B0B1C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0W2B0B1C; + } + break; + } + case 0x28eab462u: + { + if (name == BuiltInName::textureProjLodOffset_0H2B0B1C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0H2B0B1C; + } + break; + } + case 0x28eb8605u: + { + if (name == BuiltInName::textureProjLodOffset_0I3B0B2C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0I3B0B2C; + } + break; + } + case 0x28ebf99eu: + { + if (name == BuiltInName::textureProjLodOffset_0H3B0B1C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0H3B0B1C; + } + break; + } + case 0x28ec29a7u: + { + if (name == BuiltInName::textureProjLodOffset_0Q3B0B1C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0Q3B0B1C; + } + break; + } + case 0x28eecd92u: + { + if (name == BuiltInName::textureProjLodOffset_0X3B0B2C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0X3B0B2C; + } + break; + } + case 0x28ef956cu: + { + if (name == BuiltInName::textureProjLodOffset_0Q2B0B1C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0Q2B0B1C; + } + break; + } + case 0x28efb13bu: + { + if (name == BuiltInName::textureProjLodOffset_0c3B0B1C) + { + return &BuiltInFunction::kFunction_textureProjLodOffset_0c3B0B1C; + } + break; + } + case 0x2b00aacdu: + { + if (name == BuiltInName::textureProjGradOffset_0c3B1B1B1C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0c3B1B1B1C; + } + break; + } + case 0x2b022418u: + { + if (name == BuiltInName::textureProjGradOffset_0H3B1B1B1C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0H3B1B1B1C; + } + break; + } + case 0x2b0252ccu: + { + if (name == BuiltInName::textureProjGradOffset_0X3B2B2B2C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0X3B2B2B2C; + } + break; + } + case 0x2b02af8fu: + { + if (name == BuiltInName::textureProjGradOffset_0I3B2B2B2C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0I3B2B2B2C; + } + break; + } + case 0x2b03ccf9u: + { + if (name == BuiltInName::textureProjGradOffset_0Q2B1B1B1C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0Q2B1B1B1C; + } + break; + } + case 0x2b03db51u: + { + if (name == BuiltInName::textureProjGradOffset_0W2B1B1B1C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0W2B1B1B1C; + } + break; + } + case 0x2b047dfau: + { + if (name == BuiltInName::textureProjGradOffset_0R3B2B2B2C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0R3B2B2B2C; + } + break; + } + case 0x2b06f874u: + { + if (name == BuiltInName::textureProjGradOffset_0Q3B1B1B1C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0Q3B1B1B1C; + } + break; + } + case 0x2b077535u: + { + if (name == BuiltInName::textureProjGradOffset_0H2B1B1B1C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0H2B1B1B1C; + } + break; + } + case 0x2b07f768u: + { + if (name == BuiltInName::textureProjGradOffset_0W3B1B1B1C) + { + return &BuiltInFunction::kFunction_textureProjGradOffset_0W3B1B1B1C; + } + break; + } + case 0x7ec10648u: + { + if (name == BuiltInName::gl_MaxProgramTexelOffset) + { + return mVar_gl_MaxProgramTexelOffset; + } + break; + } + case 0x7ec3c4d1u: + { + if (name == BuiltInName::gl_MinProgramTexelOffset) + { + return mVar_gl_MinProgramTexelOffset; + } + break; + } + case 0x7ec8d677u: + { + if (name == BuiltInName::gl_MaxVertexOutputVectors) + { + return mVar_gl_MaxVertexOutputVectors; + } + break; + } + case 0x7ed1aaebu: + { + if (name == BuiltInName::gl_MaxFragmentInputVectors) + { + return mVar_gl_MaxFragmentInputVectors; + } + break; + } + } + if (mShaderType == GL_FRAGMENT_SHADER) + { + switch (nameHash) + { + case 0x08394c88u: + { + if (name.beginsWith(BuiltInName::dFdy)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdy_0B; + } + break; + } + case 0x08398819u: + { + if (name.beginsWith(BuiltInName::dFdx)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdx_0B; + } + break; + } + case 0x083a7081u: + { + if (name.beginsWith(BuiltInName::dFdy)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdy_1B; + } + break; + } + case 0x083abe52u: + { + if (name.beginsWith(BuiltInName::dFdx)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdx_3B; + } + break; + } + case 0x083b9d7au: + { + if (name.beginsWith(BuiltInName::dFdy)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdy_2B; + } + break; + } + case 0x083c0d13u: + { + if (name.beginsWith(BuiltInName::dFdx)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdx_2B; + } + break; + } + case 0x083c6796u: + { + if (name.beginsWith(BuiltInName::dFdx)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdx_1B; + } + break; + } + case 0x083ced8bu: + { + if (name.beginsWith(BuiltInName::dFdy)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdy_3B; + } + break; + } + case 0x0c483e39u: + { + if (name.beginsWith(BuiltInName::fwidth)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidth_1B; + } + break; + } + case 0x0c4d354eu: + { + if (name.beginsWith(BuiltInName::fwidth)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidth_0B; + } + break; + } + case 0x0c4e7b0cu: + { + if (name.beginsWith(BuiltInName::fwidth)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidth_3B; + } + break; + } + case 0x0c4fa8b5u: + { + if (name.beginsWith(BuiltInName::fwidth)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidth_2B; + } + break; + } + case 0x0e7013d9u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0T2B0B; + } + break; + } + case 0x0e70d11du: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0W1B0B; + } + break; + } + case 0x0e70eff9u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0X2B0B; + } + break; + } + case 0x0e716d8fu: + { + if (name == BuiltInName::texture_0c2B0B) + { + return &BuiltInFunction::kFunction_texture_0c2B0B; + } + break; + } + case 0x0e71856cu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0M1B0B; + } + break; + } + case 0x0e723219u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0L1B0B; + } + break; + } + case 0x0e734ff8u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0Z2B0B; + } + break; + } + case 0x0e7386b0u: + { + if (name == BuiltInName::texture_0Q1B0B) + { + return &BuiltInFunction::kFunction_texture_0Q1B0B; + } + break; + } + case 0x0e740087u: + { + if (name == BuiltInName::texture_0d3B0B) + { + return &BuiltInFunction::kFunction_texture_0d3B0B; + } + break; + } + case 0x0e742a66u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0K2B0B; + } + break; + } + case 0x0e75399eu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0S2B0B; + } + break; + } + case 0x0e755c73u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0Y2B0B; + } + break; + } + case 0x0e75d15fu: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0J2B0B; + } + break; + } + case 0x0e76e7c1u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0H1B0B; + } + break; + } + case 0x0e7720c0u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0R2B0B; + } + break; + } + case 0x0e77d1c8u: + { + if (name.beginsWith(BuiltInName::texture)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture_0I2B0B; + } + break; + } + case 0x16900558u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0L3B0B; + } + break; + } + case 0x1690a3cfu: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0W3B0B; + } + break; + } + case 0x1690ae9fu: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0M3B0B; + } + break; + } + case 0x1691c2edu: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0M2B0B; + } + break; + } + case 0x16925badu: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0Q3B0B; + } + break; + } + case 0x1692d089u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0c3B0B; + } + break; + } + case 0x169350d8u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0I3B0B; + } + break; + } + case 0x16939955u: + { + if (name == BuiltInName::textureProj_0Q2B0B) + { + return &BuiltInFunction::kFunction_textureProj_0Q2B0B; + } + break; + } + case 0x1694622au: + { + if (name == BuiltInName::textureProj_0R3B0B) + { + return &BuiltInFunction::kFunction_textureProj_0R3B0B; + } + break; + } + case 0x169465e2u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0W2B0B; + } + break; + } + case 0x1695f573u: + { + if (name == BuiltInName::textureProj_0X3B0B) + { + return &BuiltInFunction::kFunction_textureProj_0X3B0B; + } + break; + } + case 0x16965fd9u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0H3B0B; + } + break; + } + case 0x1696f029u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0H2B0B; + } + break; + } + case 0x1697e9b9u: + { + if (name.beginsWith(BuiltInName::textureProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureProj_0L2B0B; + } + break; + } + case 0x1ab0a952u: + { + if (name == BuiltInName::textureOffset_0X2B2C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0X2B2C0B; + } + break; + } + case 0x1ab29724u: + { + if (name == BuiltInName::textureOffset_0Z2B1C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0Z2B1C0B; + } + break; + } + case 0x1ab55c9du: + { + if (name == BuiltInName::textureOffset_0Q1B1C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0Q1B1C0B; + } + break; + } + case 0x1ab5753fu: + { + if (name == BuiltInName::textureOffset_0T2B1C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0T2B1C0B; + } + break; + } + case 0x1ab57bbcu: + { + if (name == BuiltInName::textureOffset_0H1B1C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0H1B1C0B; + } + break; + } + case 0x1ab59b6cu: + { + if (name == BuiltInName::textureOffset_0I2B2C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0I2B2C0B; + } + break; + } + case 0x1ab5d795u: + { + if (name == BuiltInName::textureOffset_0W1B1C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0W1B1C0B; + } + break; + } + case 0x1ab63ddau: + { + if (name == BuiltInName::textureOffset_0K2B1C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0K2B1C0B; + } + break; + } + case 0x1ab63f72u: + { + if (name == BuiltInName::textureOffset_0R2B2C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0R2B2C0B; + } + break; + } + case 0x1ab7e533u: + { + if (name == BuiltInName::textureOffset_0c2B1C0B) + { + return &BuiltInFunction::kFunction_textureOffset_0c2B1C0B; + } + break; + } + case 0x22d11d67u: + { + if (name == BuiltInName::textureProjOffset_0Q3B1C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0Q3B1C0B; + } + break; + } + case 0x22d1425bu: + { + if (name == BuiltInName::textureProjOffset_0W2B1C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0W2B1C0B; + } + break; + } + case 0x22d17100u: + { + if (name == BuiltInName::textureProjOffset_0W3B1C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0W3B1C0B; + } + break; + } + case 0x22d1ca54u: + { + if (name == BuiltInName::textureProjOffset_0c3B1C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0c3B1C0B; + } + break; + } + case 0x22d6074cu: + { + if (name == BuiltInName::textureProjOffset_0R3B2C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0R3B2C0B; + } + break; + } + case 0x22d60cd3u: + { + if (name == BuiltInName::textureProjOffset_0X3B2C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0X3B2C0B; + } + break; + } + case 0x22d60e91u: + { + if (name == BuiltInName::textureProjOffset_0Q2B1C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0Q2B1C0B; + } + break; + } + case 0x22d62e81u: + { + if (name == BuiltInName::textureProjOffset_0H3B1C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0H3B1C0B; + } + break; + } + case 0x22d6b2e8u: + { + if (name == BuiltInName::textureProjOffset_0I3B2C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0I3B2C0B; + } + break; + } + case 0x22d6ee53u: + { + if (name == BuiltInName::textureProjOffset_0H2B1C0B) + { + return &BuiltInFunction::kFunction_textureProjOffset_0H2B1C0B; + } + break; + } + case 0x7e645c89u: + { + if (name == BuiltInName::gl_FragDepth) + { + return &BuiltInVariable::kVar_gl_FragDepth; + } + break; + } + } + } + if (mShaderType == GL_VERTEX_SHADER) + { + switch (nameHash) + { + case 0x7e5f8987u: + { + if (name == BuiltInName::gl_VertexID) + { + return &BuiltInVariable::kVar_gl_VertexID; + } + break; + } + case 0x7e6be47fu: + { + if (name == BuiltInName::gl_InstanceID) + { + return &BuiltInVariable::kVar_gl_InstanceID; + } + break; + } + } + } + if ((mShaderType == GL_VERTEX_SHADER) && (mResources.ANGLE_multi_draw)) + { + switch (nameHash) + { + case 0x7e4c3c42u: + { + if (name == BuiltInName::gl_DrawID) + { + return &BuiltInVariable::kVar_gl_DrawID; + } + break; + } + } + } + if ((mShaderType == GL_VERTEX_SHADER) && (mResources.ANGLE_base_vertex_base_instance)) + { + switch (nameHash) + { + case 0x7e695e00u: + { + if (name == BuiltInName::gl_BaseVertex) + { + return &BuiltInVariable::kVar_gl_BaseVertex; + } + break; + } + case 0x7e785b75u: + { + if (name == BuiltInName::gl_BaseInstance) + { + return &BuiltInVariable::kVar_gl_BaseInstance; + } + break; + } + } + } + if ((mResources.OVR_multiview || mResources.OVR_multiview2) && + mShaderType != GL_COMPUTE_SHADER) + { + switch (nameHash) + { + case 0x7e6f6de9u: + { + if (name == BuiltInName::gl_ViewID_OVR) + { + return &BuiltInVariable::kVar_gl_ViewID_OVR; + } + break; + } + } + } + } + if (shaderVersion == 100) + { + switch (nameHash) + { + case 0x1271689cu: + { + if (name.beginsWith(BuiltInName::texture2D)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture2D_0H1B; + } + break; + } + case 0x127728cau: + { + if (name.beginsWith(BuiltInName::texture2D)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture2D_0L1B; + } + break; + } + case 0x1680927du: + { + if (name.beginsWith(BuiltInName::textureCube)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_textureCube_0J2B; + } + break; + } + case 0x1a902408u: + { + if (name.beginsWith(BuiltInName::texture2DRect)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_texture2DRect_0N1B; + } + break; + } + case 0x1a92969du: + { + if (name.beginsWith(BuiltInName::texture2DProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_texture2DProj_0L2B; + } + break; + } + case 0x1a9584eau: + { + if (name.beginsWith(BuiltInName::texture2DProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_texture2DProj_0L3B; + } + break; + } + case 0x1a95bcc7u: + { + if (name.beginsWith(BuiltInName::texture2DProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_texture2DProj_0H3B; + } + break; + } + case 0x1a96b8d6u: + { + if (name.beginsWith(BuiltInName::texture2DProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_texture2DProj_0H2B; + } + break; + } + case 0x20cb8d71u: + { + if (name == BuiltInName::texture2DGradEXT_0H1B1B1B) + { + return &BuiltInFunction::kFunction_texture2DGradEXT_0H1B1B1B; + } + break; + } + case 0x22b53a05u: + { + if (name.beginsWith(BuiltInName::texture2DRectProj)) + { + ASSERT(name.length() == 22); + return &BuiltInFunction::kFunction_texture2DRectProj_0N3B; + } + break; + } + case 0x22b65e05u: + { + if (name.beginsWith(BuiltInName::texture2DRectProj)) + { + ASSERT(name.length() == 22); + return &BuiltInFunction::kFunction_texture2DRectProj_0N2B; + } + break; + } + case 0x24dbd51eu: + { + if (name == BuiltInName::textureCubeGradEXT_0J2B2B2B) + { + return &BuiltInFunction::kFunction_textureCubeGradEXT_0J2B2B2B; + } + break; + } + case 0x28e995cbu: + { + if (name == BuiltInName::texture2DProjGradEXT_0H3B1B1B) + { + return &BuiltInFunction::kFunction_texture2DProjGradEXT_0H3B1B1B; + } + break; + } + case 0x28ed5178u: + { + if (name == BuiltInName::texture2DProjGradEXT_0H2B1B1B) + { + return &BuiltInFunction::kFunction_texture2DProjGradEXT_0H2B1B1B; + } + break; + } + case 0x7e5a0c08u: + { + if (name == BuiltInName::gl_FragData) + { + // Only initialized if shaderType == GL_FRAGMENT_SHADER + return mVar_gl_FragData; + } + break; + } + case 0x7e7c38efu: + { + if (name == BuiltInName::gl_FragDepthEXT) + { + // Only initialized if (shaderType == GL_FRAGMENT_SHADER) && + // (mResources.EXT_frag_depth) + return mVar_gl_FragDepthEXT; + } + break; + } + case 0x7ea6cdf6u: + { + if (name == BuiltInName::gl_MaxVaryingVectors) + { + return mVar_gl_MaxVaryingVectors; + } + break; + } + case 0x7ebce486u: + { + if (name == BuiltInName::gl_SecondaryFragDataEXT) + { + // Only initialized if (shaderType == GL_FRAGMENT_SHADER) && + // (mResources.EXT_blend_func_extended) + return mVar_gl_SecondaryFragDataEXT; + } + break; + } + } + if (mShaderType == GL_FRAGMENT_SHADER) + { + switch (nameHash) + { + case 0x08394c88u: + { + if (name.beginsWith(BuiltInName::dFdyExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdyExt_0B; + } + break; + } + case 0x08398819u: + { + if (name.beginsWith(BuiltInName::dFdxExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdxExt_0B; + } + break; + } + case 0x083a7081u: + { + if (name.beginsWith(BuiltInName::dFdyExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdyExt_1B; + } + break; + } + case 0x083abe52u: + { + if (name.beginsWith(BuiltInName::dFdxExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdxExt_3B; + } + break; + } + case 0x083b9d7au: + { + if (name.beginsWith(BuiltInName::dFdyExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdyExt_2B; + } + break; + } + case 0x083c0d13u: + { + if (name.beginsWith(BuiltInName::dFdxExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdxExt_2B; + } + break; + } + case 0x083c6796u: + { + if (name.beginsWith(BuiltInName::dFdxExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdxExt_1B; + } + break; + } + case 0x083ced8bu: + { + if (name.beginsWith(BuiltInName::dFdyExt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_dFdyExt_3B; + } + break; + } + case 0x0c483e39u: + { + if (name.beginsWith(BuiltInName::fwidthExt)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidthExt_1B; + } + break; + } + case 0x0c4d354eu: + { + if (name.beginsWith(BuiltInName::fwidthExt)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidthExt_0B; + } + break; + } + case 0x0c4e7b0cu: + { + if (name.beginsWith(BuiltInName::fwidthExt)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidthExt_3B; + } + break; + } + case 0x0c4fa8b5u: + { + if (name.beginsWith(BuiltInName::fwidthExt)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_fwidthExt_2B; + } + break; + } + case 0x12764e24u: + { + if (name.beginsWith(BuiltInName::texture3D)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_texture3D_0I2B; + } + break; + } + case 0x12810dc6u: + { + if (name == BuiltInName::texture3D_0I2B0B) + { + return &BuiltInFunction::kFunction_texture3D_0I2B0B; + } + break; + } + case 0x12846ba6u: + { + if (name.beginsWith(BuiltInName::texture2D)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_texture2D_0H1B0B; + } + break; + } + case 0x1696a314u: + { + if (name.beginsWith(BuiltInName::textureCube)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_textureCube_0J2B0B; + } + break; + } + case 0x189e8416u: + { + if (name.beginsWith(BuiltInName::texture3DLod)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_texture3DLod_0I2B0B; + } + break; + } + case 0x1a93312fu: + { + if (name.beginsWith(BuiltInName::texture3DProj)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_texture3DProj_0I3B; + } + break; + } + case 0x1aa197a7u: + { + if (name.beginsWith(BuiltInName::texture2DProj)) + { + ASSERT(name.length() == 20); + return &BuiltInFunction::kFunction_texture2DProj_0H3B0B; + } + break; + } + case 0x1aa44389u: + { + if (name == BuiltInName::texture2DProj_0H2B0B) + { + return &BuiltInFunction::kFunction_texture2DProj_0H2B0B; + } + break; + } + case 0x1aa7eecdu: + { + if (name == BuiltInName::texture3DProj_0I3B0B) + { + return &BuiltInFunction::kFunction_texture3DProj_0I3B0B; + } + break; + } + case 0x1eb43b6cu: + { + if (name == BuiltInName::texture2DLodEXT_0H1B0B) + { + return &BuiltInFunction::kFunction_texture2DLodEXT_0H1B0B; + } + break; + } + case 0x20b9ceecu: + { + if (name.beginsWith(BuiltInName::texture3DProjLod)) + { + ASSERT(name.length() == 23); + return &BuiltInFunction::kFunction_texture3DProjLod_0I3B0B; + } + break; + } + case 0x22c206a5u: + { + if (name.beginsWith(BuiltInName::textureCubeLodEXT)) + { + ASSERT(name.length() == 24); + return &BuiltInFunction::kFunction_textureCubeLodEXT_0J2B0B; + } + break; + } + case 0x26d1d3beu: + { + if (name.beginsWith(BuiltInName::texture2DProjLodEXT)) + { + ASSERT(name.length() == 26); + return &BuiltInFunction::kFunction_texture2DProjLodEXT_0H3B0B; + } + break; + } + case 0x26d60d82u: + { + if (name == BuiltInName::texture2DProjLodEXT_0H2B0B) + { + return &BuiltInFunction::kFunction_texture2DProjLodEXT_0H2B0B; + } + break; + } + case 0x7e60c438u: + { + if (name == BuiltInName::gl_FragColor) + { + return &BuiltInVariable::kVar_gl_FragColor; + } + break; + } + } + } + if (mShaderType == GL_VERTEX_SHADER) + { + switch (nameHash) + { + case 0x18986fc2u: + { + if (name == BuiltInName::texture2DLod_0H1B0B) + { + return &BuiltInFunction::kFunction_texture2DLod_0H1B0B; + } + break; + } + case 0x1cac1f4du: + { + if (name.beginsWith(BuiltInName::textureCubeLod)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_textureCubeLod_0J2B0B; + } + break; + } + case 0x20b8a0c3u: + { + if (name.beginsWith(BuiltInName::texture2DProjLod)) + { + ASSERT(name.length() == 23); + return &BuiltInFunction::kFunction_texture2DProjLod_0H3B0B; + } + break; + } + case 0x20bc6337u: + { + if (name == BuiltInName::texture2DProjLod_0H2B0B) + { + return &BuiltInFunction::kFunction_texture2DProjLod_0H2B0B; + } + break; + } + } + } + if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_blend_func_extended)) + { + switch (nameHash) + { + case 0x7ec56cbeu: + { + if (name == BuiltInName::gl_SecondaryFragColorEXT) + { + return &BuiltInVariable::kVar_gl_SecondaryFragColorEXT; + } + break; + } + } + } + if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.EXT_shader_framebuffer_fetch)) + { + switch (nameHash) + { + case 0x7e7970c2u: + { + if (name == BuiltInName::gl_LastFragData) + { + return mVar_gl_LastFragData; + } + break; + } + } + } + if ((mShaderType == GL_FRAGMENT_SHADER) && (mResources.NV_shader_framebuffer_fetch)) + { + switch (nameHash) + { + case 0x7e7970c2u: + { + if (name == BuiltInName::gl_LastFragData) + { + return mVar_gl_LastFragDataNV; + } + break; + } + case 0x7e802016u: + { + if (name == BuiltInName::gl_LastFragColor) + { + return &BuiltInVariable::kVar_gl_LastFragColor; + } + break; + } + } + } + if ((mShaderType == GL_FRAGMENT_SHADER) && + (!mResources.EXT_shader_framebuffer_fetch && !mResources.NV_shader_framebuffer_fetch && + mResources.ARM_shader_framebuffer_fetch)) + { + switch (nameHash) + { + case 0x7e9f0a88u: + { + if (name == BuiltInName::gl_LastFragColorARM) + { + return &BuiltInVariable::kVar_gl_LastFragColorARM; + } + break; + } + } + } + if ((mShaderType == GL_VERTEX_SHADER) && (mResources.ANGLE_multi_draw)) + { + switch (nameHash) + { + case 0x7e4c3c42u: + { + if (name == BuiltInName::gl_DrawID) + { + return &BuiltInVariable::kVar_gl_DrawIDESSL1; + } + break; + } + } + } + if ((mResources.OVR_multiview || mResources.OVR_multiview2) && + mShaderType != GL_COMPUTE_SHADER) + { + switch (nameHash) + { + case 0x7e6f6de9u: + { + if (name == BuiltInName::gl_ViewID_OVR) + { + return &BuiltInVariable::kVar_gl_ViewID_OVRESSL1; + } + break; + } + } + } + } + switch (nameHash) + { + case 0x063055e6u: + { + if (name.beginsWith(BuiltInName::log)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_log_0B; + } + break; + } + case 0x06307fbcu: + { + if (name.beginsWith(BuiltInName::all)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_all_1E; + } + break; + } + case 0x0630826fu: + { + if (name.beginsWith(BuiltInName::notFunc)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_notFunc_3E; + } + break; + } + case 0x0630942fu: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_0B; + } + break; + } + case 0x06309ccau: + { + if (name.beginsWith(BuiltInName::tan)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_tan_1B; + } + break; + } + case 0x0630bc6au: + { + if (name.beginsWith(BuiltInName::cos)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_cos_2B; + } + break; + } + case 0x0630dce3u: + { + if (name.beginsWith(BuiltInName::log)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_log_3B; + } + break; + } + case 0x063194bfu: + { + if (name.beginsWith(BuiltInName::any)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_any_1E; + } + break; + } + case 0x0631a1ccu: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_3B; + } + break; + } + case 0x0631d12au: + { + if (name.beginsWith(BuiltInName::log)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_log_2B; + } + break; + } + case 0x06320b8bu: + { + if (name.beginsWith(BuiltInName::cos)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_cos_3B; + } + break; + } + case 0x0632fcb3u: + { + if (name.beginsWith(BuiltInName::any)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_any_3E; + } + break; + } + case 0x06330b41u: + { + if (name.beginsWith(BuiltInName::log)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_log_1B; + } + break; + } + case 0x063314b1u: + { + if (name.beginsWith(BuiltInName::sin)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_sin_1B; + } + break; + } + case 0x063415e2u: + { + if (name.beginsWith(BuiltInName::any)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_any_2E; + } + break; + } + case 0x06344570u: + { + if (name.beginsWith(BuiltInName::sin)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_sin_0B; + } + break; + } + case 0x0634cf9au: + { + if (name.beginsWith(BuiltInName::sin)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_sin_3B; + } + break; + } + case 0x06352335u: + { + if (name.beginsWith(BuiltInName::exp)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_exp_3B; + } + break; + } + case 0x063595b9u: + { + if (name.beginsWith(BuiltInName::exp)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_exp_0B; + } + break; + } + case 0x0635a80fu: + { + if (name.beginsWith(BuiltInName::tan)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_tan_2B; + } + break; + } + case 0x0635d3b3u: + { + if (name.beginsWith(BuiltInName::sin)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_sin_2B; + } + break; + } + case 0x0635eb79u: + { + if (name.beginsWith(BuiltInName::all)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_all_2E; + } + break; + } + case 0x06366a98u: + { + if (name.beginsWith(BuiltInName::cos)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_cos_0B; + } + break; + } + case 0x0636b1f1u: + { + if (name.beginsWith(BuiltInName::exp)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_exp_1B; + } + break; + } + case 0x0636dda0u: + { + if (name.beginsWith(BuiltInName::all)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_all_3E; + } + break; + } + case 0x0636e0efu: + { + if (name.beginsWith(BuiltInName::notFunc)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_notFunc_1E; + } + break; + } + case 0x063719d6u: + { + if (name.beginsWith(BuiltInName::tan)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_tan_3B; + } + break; + } + case 0x06371aefu: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_2B; + } + break; + } + case 0x06376a86u: + { + if (name.beginsWith(BuiltInName::notFunc)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_notFunc_2E; + } + break; + } + case 0x063770d0u: + { + if (name.beginsWith(BuiltInName::tan)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_tan_0B; + } + break; + } + case 0x063770dfu: + { + if (name.beginsWith(BuiltInName::abs)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_abs_1B; + } + break; + } + case 0x063786f1u: + { + if (name.beginsWith(BuiltInName::cos)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_cos_1B; + } + break; + } + case 0x0637ca4au: + { + if (name.beginsWith(BuiltInName::exp)) + { + ASSERT(name.length() == 6); + return &BuiltInFunction::kFunction_exp_2B; + } + break; + } + case 0x06400261u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_2B2B; + } + break; + } + case 0x06403847u: + { + if (name.beginsWith(BuiltInName::mod)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_mod_2B0B; + } + break; + } + case 0x064082ceu: + { + if (name.beginsWith(BuiltInName::mod)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_mod_1B0B; + } + break; + } + case 0x0640a98au: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_2B2B; + } + break; + } + case 0x064107b7u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_1B0B; + } + break; + } + case 0x06415ae6u: + { + if (name.beginsWith(BuiltInName::dot)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_dot_3B3B; + } + break; + } + case 0x06418e42u: + { + if (name.beginsWith(BuiltInName::pow)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_pow_3B3B; + } + break; + } + case 0x0641ceeeu: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_0B0B; + } + break; + } + case 0x0641f1d7u: + { + if (name.beginsWith(BuiltInName::mod)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_mod_1B1B; + } + break; + } + case 0x06421555u: + { + if (name.beginsWith(BuiltInName::dot)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_dot_1B1B; + } + break; + } + case 0x064225ceu: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_3B3B; + } + break; + } + case 0x064274eeu: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_1B1B; + } + break; + } + case 0x0642b54du: + { + if (name.beginsWith(BuiltInName::mod)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_mod_2B2B; + } + break; + } + case 0x064318fcu: + { + if (name.beginsWith(BuiltInName::pow)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_pow_2B2B; + } + break; + } + case 0x0643486cu: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_3B0B; + } + break; + } + case 0x06439435u: + { + if (name.beginsWith(BuiltInName::pow)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_pow_1B1B; + } + break; + } + case 0x06450933u: + { + if (name.beginsWith(BuiltInName::dot)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_dot_0B0B; + } + break; + } + case 0x0645114fu: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_1B0B; + } + break; + } + case 0x06457883u: + { + if (name.beginsWith(BuiltInName::mod)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_mod_3B3B; + } + break; + } + case 0x0645f03eu: + { + if (name.beginsWith(BuiltInName::mod)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_mod_3B0B; + } + break; + } + case 0x0645fd82u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_3B3B; + } + break; + } + case 0x0646155eu: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_1B1B; + } + break; + } + case 0x06462cf0u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_2B0B; + } + break; + } + case 0x06463219u: + { + if (name.beginsWith(BuiltInName::dot)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_dot_2B2B; + } + break; + } + case 0x06467507u: + { + if (name.beginsWith(BuiltInName::min)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_min_3B0B; + } + break; + } + case 0x06468fb1u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_2B0B; + } + break; + } + case 0x0646b392u: + { + if (name.beginsWith(BuiltInName::pow)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_pow_0B0B; + } + break; + } + case 0x06472996u: + { + if (name.beginsWith(BuiltInName::max)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_max_0B0B; + } + break; + } + case 0x064778feu: + { + if (name.beginsWith(BuiltInName::mod)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_mod_0B0B; + } + break; + } + case 0x0650f1c9u: + { + if (name.beginsWith(BuiltInName::mix)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_mix_1B1B0B; + } + break; + } + case 0x0653049du: + { + if (name.beginsWith(BuiltInName::mix)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_mix_2B2B0B; + } + break; + } + case 0x06549219u: + { + if (name.beginsWith(BuiltInName::mix)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_mix_2B2B2B; + } + break; + } + case 0x0655be57u: + { + if (name.beginsWith(BuiltInName::mix)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_mix_0B0B0B; + } + break; + } + case 0x06561bdcu: + { + if (name == BuiltInName::mix_3B3B0B) + { + return &BuiltInFunction::kFunction_mix_3B3B0B; + } + break; + } + case 0x06568deeu: + { + if (name == BuiltInName::mix_3B3B3B) + { + return &BuiltInFunction::kFunction_mix_3B3B3B; + } + break; + } + case 0x0657a0a8u: + { + if (name == BuiltInName::mix_1B1B1B) + { + return &BuiltInFunction::kFunction_mix_1B1B1B; + } + break; + } + case 0x08383aacu: + { + if (name.beginsWith(BuiltInName::acos)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_acos_3B; + } + break; + } + case 0x0838a17eu: + { + if (name.beginsWith(BuiltInName::ceil)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_ceil_2B; + } + break; + } + case 0x0838ac89u: + { + if (name.beginsWith(BuiltInName::exp2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_exp2_3B; + } + break; + } + case 0x0838dc31u: + { + if (name.beginsWith(BuiltInName::sqrt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sqrt_0B; + } + break; + } + case 0x08396a55u: + { + if (name.beginsWith(BuiltInName::acos)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_acos_2B; + } + break; + } + case 0x0839daf2u: + { + if (name.beginsWith(BuiltInName::exp2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_exp2_0B; + } + break; + } + case 0x0839e751u: + { + if (name.beginsWith(BuiltInName::acos)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_acos_1B; + } + break; + } + case 0x0839f1a7u: + { + if (name.beginsWith(BuiltInName::ceil)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_ceil_3B; + } + break; + } + case 0x083a07bau: + { + if (name.beginsWith(BuiltInName::sqrt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sqrt_3B; + } + break; + } + case 0x083a7922u: + { + if (name.beginsWith(BuiltInName::ceil)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_ceil_0B; + } + break; + } + case 0x083aea5fu: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_atan_2B; + } + break; + } + case 0x083af266u: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_1B; + } + break; + } + case 0x083afbc8u: + { + if (name.beginsWith(BuiltInName::acos)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_acos_0B; + } + break; + } + case 0x083b2b93u: + { + if (name.beginsWith(BuiltInName::exp2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_exp2_1B; + } + break; + } + case 0x083b577bu: + { + if (name.beginsWith(BuiltInName::sqrt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sqrt_2B; + } + break; + } + case 0x083b7e52u: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_atan_1B; + } + break; + } + case 0x083bcf76u: + { + if (name.beginsWith(BuiltInName::sqrt)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sqrt_1B; + } + break; + } + case 0x083c1fc5u: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_2B; + } + break; + } + case 0x083c624bu: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_atan_0B; + } + break; + } + case 0x083ca453u: + { + if (name.beginsWith(BuiltInName::asin)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_asin_0B; + } + break; + } + case 0x083cc6e1u: + { + if (name.beginsWith(BuiltInName::log2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_log2_2B; + } + break; + } + case 0x083d6eacu: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_3B; + } + break; + } + case 0x083dac10u: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_atan_3B; + } + break; + } + case 0x083dd4deu: + { + if (name.beginsWith(BuiltInName::sign)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_sign_0B; + } + break; + } + case 0x083df752u: + { + if (name.beginsWith(BuiltInName::asin)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_asin_1B; + } + break; + } + case 0x083e1b7au: + { + if (name.beginsWith(BuiltInName::log2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_log2_1B; + } + break; + } + case 0x083e6948u: + { + if (name.beginsWith(BuiltInName::asin)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_asin_2B; + } + break; + } + case 0x083f4babu: + { + if (name.beginsWith(BuiltInName::log2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_log2_0B; + } + break; + } + case 0x083f6552u: + { + if (name.beginsWith(BuiltInName::asin)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_asin_3B; + } + break; + } + case 0x083f6afdu: + { + if (name.beginsWith(BuiltInName::ceil)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_ceil_1B; + } + break; + } + case 0x083f8b90u: + { + if (name.beginsWith(BuiltInName::exp2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_exp2_2B; + } + break; + } + case 0x083fd32eu: + { + if (name.beginsWith(BuiltInName::log2)) + { + ASSERT(name.length() == 7); + return &BuiltInFunction::kFunction_log2_3B; + } + break; + } + case 0x08482806u: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_atan_3B3B; + } + break; + } + case 0x08491304u: + { + if (name.beginsWith(BuiltInName::step)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_step_0B1B; + } + break; + } + case 0x0849bcfdu: + { + if (name.beginsWith(BuiltInName::step)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_step_2B2B; + } + break; + } + case 0x084aa6bfu: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_atan_1B1B; + } + break; + } + case 0x084c10fau: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_atan_0B0B; + } + break; + } + case 0x084c9765u: + { + if (name.beginsWith(BuiltInName::step)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_step_1B1B; + } + break; + } + case 0x084e7af1u: + { + if (name.beginsWith(BuiltInName::step)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_step_3B3B; + } + break; + } + case 0x084e7be4u: + { + if (name.beginsWith(BuiltInName::step)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_step_0B0B; + } + break; + } + case 0x084ec1e6u: + { + if (name.beginsWith(BuiltInName::step)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_step_0B3B; + } + break; + } + case 0x084ee899u: + { + if (name.beginsWith(BuiltInName::atan)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_atan_2B2B; + } + break; + } + case 0x084feda7u: + { + if (name.beginsWith(BuiltInName::step)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_step_0B2B; + } + break; + } + case 0x0a402a9cu: + { + if (name.beginsWith(BuiltInName::fract)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_fract_0B; + } + break; + } + case 0x0a41745fu: + { + if (name.beginsWith(BuiltInName::fract)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_fract_3B; + } + break; + } + case 0x0a42a596u: + { + if (name.beginsWith(BuiltInName::fract)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_fract_2B; + } + break; + } + case 0x0a43465eu: + { + if (name.beginsWith(BuiltInName::floor)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_floor_0B; + } + break; + } + case 0x0a43be63u: + { + if (name.beginsWith(BuiltInName::floor)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_floor_3B; + } + break; + } + case 0x0a44da6bu: + { + if (name.beginsWith(BuiltInName::floor)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_floor_2B; + } + break; + } + case 0x0a45ecc0u: + { + if (name.beginsWith(BuiltInName::floor)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_floor_1B; + } + break; + } + case 0x0a4726f2u: + { + if (name.beginsWith(BuiltInName::fract)) + { + ASSERT(name.length() == 8); + return &BuiltInFunction::kFunction_fract_1B; + } + break; + } + case 0x0a513a26u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_3E3E; + } + break; + } + case 0x0a51bddcu: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_3B3B; + } + break; + } + case 0x0a527d10u: + { + if (name.beginsWith(BuiltInName::cross)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_cross_2B2B; + } + break; + } + case 0x0a542036u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_2C2C; + } + break; + } + case 0x0a54c30cu: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_2B2B; + } + break; + } + case 0x0a554046u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_1C1C; + } + break; + } + case 0x0a56874bu: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_3C3C; + } + break; + } + case 0x0a56fc88u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_2E2E; + } + break; + } + case 0x0a5744dcu: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_1E1E; + } + break; + } + case 0x0a57a8f5u: + { + if (name.beginsWith(BuiltInName::equal)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_equal_1B1B; + } + break; + } + case 0x0a619e65u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_3B3B3B; + } + break; + } + case 0x0a62e0c3u: + { + if (name == BuiltInName::clamp_1B0B0B) + { + return &BuiltInFunction::kFunction_clamp_1B0B0B; + } + break; + } + case 0x0a635d1au: + { + if (name == BuiltInName::clamp_1B1B1B) + { + return &BuiltInFunction::kFunction_clamp_1B1B1B; + } + break; + } + case 0x0a658fc9u: + { + if (name == BuiltInName::clamp_3B0B0B) + { + return &BuiltInFunction::kFunction_clamp_3B0B0B; + } + break; + } + case 0x0a65f6b4u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_0B0B0B; + } + break; + } + case 0x0a6670deu: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_2B0B0B; + } + break; + } + case 0x0a679af4u: + { + if (name.beginsWith(BuiltInName::clamp)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_clamp_2B2B2B; + } + break; + } + case 0x0c48bffau: + { + if (name.beginsWith(BuiltInName::length)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_length_0B; + } + break; + } + case 0x0c4924f7u: + { + if (name.beginsWith(BuiltInName::length)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_length_3B; + } + break; + } + case 0x0c4a38b6u: + { + if (name.beginsWith(BuiltInName::length)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_length_2B; + } + break; + } + case 0x0c4f6cbbu: + { + if (name.beginsWith(BuiltInName::length)) + { + ASSERT(name.length() == 9); + return &BuiltInFunction::kFunction_length_1B; + } + break; + } + case 0x0e507f22u: + { + if (name.beginsWith(BuiltInName::degrees)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_degrees_2B; + } + break; + } + case 0x0e519bd4u: + { + if (name.beginsWith(BuiltInName::degrees)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_degrees_3B; + } + break; + } + case 0x0e52b187u: + { + if (name.beginsWith(BuiltInName::degrees)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_degrees_0B; + } + break; + } + case 0x0e52e500u: + { + if (name.beginsWith(BuiltInName::radians)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_radians_0B; + } + break; + } + case 0x0e537b7au: + { + if (name.beginsWith(BuiltInName::radians)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_radians_3B; + } + break; + } + case 0x0e541edeu: + { + if (name.beginsWith(BuiltInName::degrees)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_degrees_1B; + } + break; + } + case 0x0e547683u: + { + if (name.beginsWith(BuiltInName::radians)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_radians_2B; + } + break; + } + case 0x0e55ac28u: + { + if (name.beginsWith(BuiltInName::radians)) + { + ASSERT(name.length() == 10); + return &BuiltInFunction::kFunction_radians_1B; + } + break; + } + case 0x0e620f44u: + { + if (name.beginsWith(BuiltInName::reflect)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_reflect_2B2B; + } + break; + } + case 0x0e631c50u: + { + if (name.beginsWith(BuiltInName::reflect)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_reflect_3B3B; + } + break; + } + case 0x0e63358eu: + { + if (name.beginsWith(BuiltInName::reflect)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_reflect_0B0B; + } + break; + } + case 0x0e665b7bu: + { + if (name.beginsWith(BuiltInName::reflect)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_reflect_1B1B; + } + break; + } + case 0x0e706684u: + { + if (name.beginsWith(BuiltInName::refract)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_refract_1B1B0B; + } + break; + } + case 0x0e71a4fcu: + { + if (name.beginsWith(BuiltInName::refract)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_refract_2B2B0B; + } + break; + } + case 0x0e71b28du: + { + if (name == BuiltInName::refract_3B3B0B) + { + return &BuiltInFunction::kFunction_refract_3B3B0B; + } + break; + } + case 0x0e73b594u: + { + if (name.beginsWith(BuiltInName::refract)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_refract_0B0B0B; + } + break; + } + case 0x1068425fu: + { + if (name.beginsWith(BuiltInName::distance)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_distance_3B3B; + } + break; + } + case 0x1068c0bfu: + { + if (name.beginsWith(BuiltInName::distance)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_distance_2B2B; + } + break; + } + case 0x1068f060u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_1E1E; + } + break; + } + case 0x10695fe7u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_2E2E; + } + break; + } + case 0x1069b2c0u: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_1B1B; + } + break; + } + case 0x106a110cu: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_3C3C; + } + break; + } + case 0x106a63f2u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_2C2C; + } + break; + } + case 0x106a713eu: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_2B2B; + } + break; + } + case 0x106ade94u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_1B1B; + } + break; + } + case 0x106b25c9u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_1C1C; + } + break; + } + case 0x106b4468u: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_1C1C; + } + break; + } + case 0x106b8219u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_3B3B; + } + break; + } + case 0x106bc4fcu: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_3E3E; + } + break; + } + case 0x106caf4fu: + { + if (name.beginsWith(BuiltInName::distance)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_distance_0B0B; + } + break; + } + case 0x106d2c39u: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_3B3B; + } + break; + } + case 0x106dabccu: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_2B2B; + } + break; + } + case 0x106eaf65u: + { + if (name.beginsWith(BuiltInName::notEqual)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_notEqual_3C3C; + } + break; + } + case 0x106faaeau: + { + if (name.beginsWith(BuiltInName::lessThan)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_lessThan_2C2C; + } + break; + } + case 0x106ff564u: + { + if (name.beginsWith(BuiltInName::distance)) + { + ASSERT(name.length() == 13); + return &BuiltInFunction::kFunction_distance_1B1B; + } + break; + } + case 0x126235c4u: + { + if (name.beginsWith(BuiltInName::normalize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_normalize_1B; + } + break; + } + case 0x12635a67u: + { + if (name.beginsWith(BuiltInName::normalize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_normalize_2B; + } + break; + } + case 0x1264aa3eu: + { + if (name.beginsWith(BuiltInName::normalize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_normalize_3B; + } + break; + } + case 0x12650243u: + { + if (name.beginsWith(BuiltInName::normalize)) + { + ASSERT(name.length() == 12); + return &BuiltInFunction::kFunction_normalize_0B; + } + break; + } + case 0x14888e72u: + { + if (name.beginsWith(BuiltInName::smoothstep)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_smoothstep_0B0B1B; + } + break; + } + case 0x1489436du: + { + if (name == BuiltInName::smoothstep_1B1B1B) + { + return &BuiltInFunction::kFunction_smoothstep_1B1B1B; + } + break; + } + case 0x1489bfb6u: + { + if (name == BuiltInName::smoothstep_3B3B3B) + { + return &BuiltInFunction::kFunction_smoothstep_3B3B3B; + } + break; + } + case 0x148a33b9u: + { + if (name.beginsWith(BuiltInName::smoothstep)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_smoothstep_2B2B2B; + } + break; + } + case 0x148de9b5u: + { + if (name.beginsWith(BuiltInName::smoothstep)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_smoothstep_0B0B0B; + } + break; + } + case 0x148e5c11u: + { + if (name == BuiltInName::smoothstep_0B0B3B) + { + return &BuiltInFunction::kFunction_smoothstep_0B0B3B; + } + break; + } + case 0x148f7bf9u: + { + if (name.beginsWith(BuiltInName::smoothstep)) + { + ASSERT(name.length() == 17); + return &BuiltInFunction::kFunction_smoothstep_0B0B2B; + } + break; + } + case 0x1670b92du: + { + if (name.beginsWith(BuiltInName::inversesqrt)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_inversesqrt_2B; + } + break; + } + case 0x1671d38eu: + { + if (name.beginsWith(BuiltInName::inversesqrt)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_inversesqrt_1B; + } + break; + } + case 0x16772b69u: + { + if (name.beginsWith(BuiltInName::inversesqrt)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_inversesqrt_0B; + } + break; + } + case 0x1677857cu: + { + if (name.beginsWith(BuiltInName::inversesqrt)) + { + ASSERT(name.length() == 14); + return &BuiltInFunction::kFunction_inversesqrt_3B; + } + break; + } + case 0x16817df9u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_1B1B; + } + break; + } + case 0x1681b963u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_3C3C; + } + break; + } + case 0x16829d5du: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_3B3B; + } + break; + } + case 0x16853112u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_2B2B; + } + break; + } + case 0x1685d025u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_2C2C; + } + break; + } + case 0x1685db46u: + { + if (name.beginsWith(BuiltInName::greaterThan)) + { + ASSERT(name.length() == 16); + return &BuiltInFunction::kFunction_greaterThan_1C1C; + } + break; + } + case 0x1690b84du: + { + if (name == BuiltInName::faceforward_3B3B3B) + { + return &BuiltInFunction::kFunction_faceforward_3B3B3B; + } + break; + } + case 0x1691c40bu: + { + if (name == BuiltInName::faceforward_1B1B1B) + { + return &BuiltInFunction::kFunction_faceforward_1B1B1B; + } + break; + } + case 0x1696babeu: + { + if (name == BuiltInName::faceforward_2B2B2B) + { + return &BuiltInFunction::kFunction_faceforward_2B2B2B; + } + break; + } + case 0x1697cde8u: + { + if (name.beginsWith(BuiltInName::faceforward)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_faceforward_0B0B0B; + } + break; + } + case 0x1a9481a8u: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_2C2C; + } + break; + } + case 0x1a94a164u: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_3C3C; + } + break; + } + case 0x1a95c72au: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_1B1B; + } + break; + } + case 0x1a9642f7u: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_3B3B; + } + break; + } + case 0x1a977782u: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_1C1C; + } + break; + } + case 0x1a97d055u: + { + if (name.beginsWith(BuiltInName::lessThanEqual)) + { + ASSERT(name.length() == 18); + return &BuiltInFunction::kFunction_lessThanEqual_2B2B; + } + break; + } + case 0x1c993bdfu: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_5B5B; + } + break; + } + case 0x1c9b357cu: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_FBFB; + } + break; + } + case 0x1c9e72dbu: + { + if (name.beginsWith(BuiltInName::matrixCompMult)) + { + ASSERT(name.length() == 19); + return &BuiltInFunction::kFunction_matrixCompMult_ABAB; + } + break; + } + case 0x20ab1dc0u: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_2C2C; + } + break; + } + case 0x20acdd3au: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_1B1B; + } + break; + } + case 0x20ad192cu: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_3C3C; + } + break; + } + case 0x20adfc96u: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_3B3B; + } + break; + } + case 0x20ae6ffbu: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_2B2B; + } + break; + } + case 0x20af1dd4u: + { + if (name.beginsWith(BuiltInName::greaterThanEqual)) + { + ASSERT(name.length() == 21); + return &BuiltInFunction::kFunction_greaterThanEqual_1C1C; + } + break; + } + case 0x7e6af03cu: + { + if (name == BuiltInName::gl_DepthRange) + { + return mVar_gl_DepthRange; + } + break; + } + case 0x7e8ab02eu: + { + if (name == BuiltInName::gl_MaxDrawBuffers) + { + return mVar_gl_MaxDrawBuffers; + } + break; + } + case 0x7e9ad799u: + { + if (name == BuiltInName::gl_MaxVertexAttribs) + { + return mVar_gl_MaxVertexAttribs; + } + break; + } + case 0x7ebaa8e5u: + { + if (name == BuiltInName::gl_MaxTextureImageUnits) + { + return mVar_gl_MaxTextureImageUnits; + } + break; + } + case 0x7ebeff64u: + { + if (name == BuiltInName::gl_DepthRangeParameters) + { + return mVar_gl_DepthRangeParameters; + } + break; + } + case 0x7ed35151u: + { + if (name == BuiltInName::gl_MaxVertexUniformVectors) + { + return mVar_gl_MaxVertexUniformVectors; + } + break; + } + case 0x7ee45ba1u: + { + if (name == BuiltInName::gl_MaxFragmentUniformVectors) + { + return mVar_gl_MaxFragmentUniformVectors; + } + break; + } + case 0x7eea039au: + { + if (name == BuiltInName::gl_MaxVertexTextureImageUnits) + { + return mVar_gl_MaxVertexTextureImageUnits; + } + break; + } + case 0x7ef1e608u: + { + if (name == BuiltInName::gl_MaxDualSourceDrawBuffersEXT) + { + return mVar_gl_MaxDualSourceDrawBuffersEXT; + } + break; + } + case 0x7ef84293u: + { + if (name == BuiltInName::gl_MaxCombinedTextureImageUnits) + { + return mVar_gl_MaxCombinedTextureImageUnits; + } + break; + } + } + if (mShaderType == GL_FRAGMENT_SHADER) + { + switch (nameHash) + { + case 0x7e64c010u: + { + if (name == BuiltInName::gl_FragCoord) + { + return &BuiltInVariable::kVar_gl_FragCoord; + } + break; + } + case 0x7e6c2088u: + { + if (name == BuiltInName::gl_PointCoord) + { + return &BuiltInVariable::kVar_gl_PointCoord; + } + break; + } + case 0x7e73011eu: + { + if (name == BuiltInName::gl_FrontFacing) + { + return &BuiltInVariable::kVar_gl_FrontFacing; + } + break; + } + } + } + if (mShaderType == GL_VERTEX_SHADER) + { + switch (nameHash) + { + case 0x7e580bc5u: + { + if (name == BuiltInName::gl_Position) + { + return &BuiltInVariable::kVar_gl_Position; + } + break; + } + case 0x7e63931cu: + { + if (name == BuiltInName::gl_PointSize) + { + return &BuiltInVariable::kVar_gl_PointSize; + } + break; + } + } + } + return nullptr; +} + +const UnmangledBuiltIn *TSymbolTable::getUnmangledBuiltInForShaderVersion( + const ImmutableString &name, + int shaderVersion) +{ + if (name.length() > 26) + { + return nullptr; + } + uint32_t nameHash = name.mangledNameHash(); + if (shaderVersion >= 310) + { + switch (nameHash) + { + case 0x7e2c727fu: + { + if (name == BuiltInName::ldexp) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2d0692u: + { + if (name == BuiltInName::frexp) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e399596u: + { + if (name == BuiltInName::findLSB) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e3bdf3fu: + { + if (name == BuiltInName::findMSB) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e41283bu: + { + if (name == BuiltInName::bitCount) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4690b3u: + { + if (name == BuiltInName::atomicOr) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4800e3u: + { + if (name == BuiltInName::atomicAdd) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4893a8u: + { + if (name == BuiltInName::atomicMax) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e49061fu: + { + if (name == BuiltInName::atomicMin) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4a45b6u: + { + if (name == BuiltInName::imageLoad) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4b6656u: + { + if (name == BuiltInName::imageSize) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4dea77u: + { + if (name == BuiltInName::atomicXor) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4e5094u: + { + if (name == BuiltInName::uaddCarry) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4f21aeu: + { + if (name == BuiltInName::atomicAnd) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5237e1u: + { + if (name == BuiltInName::texelFetch) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5276efu: + { + if (name == BuiltInName::imageStore) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e55de86u: + { + if (name == BuiltInName::usubBorrow) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5e217eu: + { + if (name == BuiltInName::textureSize) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e6273e5u: + { + if (name == BuiltInName::packSnorm4x8) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e62a9a0u: + { + if (name == BuiltInName::imulExtended) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e657e29u: + { + if (name == BuiltInName::packUnorm4x8) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e6746f4u: + { + if (name == BuiltInName::umulExtended) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e69d0dbu: + { + if (name == BuiltInName::memoryBarrier) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e6d0f32u: + { + if (name == BuiltInName::textureGather) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e6e00a5u: + { + if (name == BuiltInName::atomicCounter) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e71963eu: + { + if (name == BuiltInName::unpackUnorm4x8) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e73f1d1u: + { + if (name == BuiltInName::unpackSnorm4x8) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e75cfb1u: + { + if (name == BuiltInName::atomicExchange) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e778ffcu: + { + if (name == BuiltInName::atomicCompSwap) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e77c121u: + { + if (name == BuiltInName::bitfieldInsert) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e7f2cb2u: + { + if (name == BuiltInName::bitfieldReverse) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e7fa0c1u: + { + if (name == BuiltInName::bitfieldExtract) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e9269d7u: + { + if (name == BuiltInName::memoryBarrierImage) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e9b7f32u: + { + if (name == BuiltInName::memoryBarrierBuffer) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e9d8ad9u: + { + if (name == BuiltInName::textureGatherOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7eb323ddu: + { + if (name == BuiltInName::atomicCounterIncrement) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7eb6aed0u: + { + if (name == BuiltInName::atomicCounterDecrement) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7ed5b06bu: + { + if (name == BuiltInName::memoryBarrierAtomicCounter) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + } + if (mShaderType == GL_COMPUTE_SHADER) + { + switch (nameHash) + { + case 0x7e39f4e9u: + { + if (name == BuiltInName::barrier) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e93c6b9u: + { + if (name == BuiltInName::groupMemoryBarrier) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e9f4b19u: + { + if (name == BuiltInName::memoryBarrierShared) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + } + } + if (mShaderType == GL_GEOMETRY_SHADER_EXT) + { + switch (nameHash) + { + case 0x7e55adc2u: + { + if (name == BuiltInName::EmitVertex) + { + return &UnmangledBuiltIns::EXT_geometry_shader; + } + break; + } + case 0x7e65b2cau: + { + if (name == BuiltInName::EndPrimitive) + { + return &UnmangledBuiltIns::EXT_geometry_shader; + } + break; + } + } + } + } + if (shaderVersion >= 300) + { + switch (nameHash) + { + case 0x7e19507bu: + { + if (name == BuiltInName::abs) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1e492du: + { + if (name == BuiltInName::min) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1ea71bu: + { + if (name == BuiltInName::mix) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1ebe0eu: + { + if (name == BuiltInName::max) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e205c92u: + { + if (name == BuiltInName::tanh) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e206e40u: + { + if (name == BuiltInName::sign) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e209eadu: + { + if (name == BuiltInName::sinh) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e274509u: + { + if (name == BuiltInName::modf) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e27a4feu: + { + if (name == BuiltInName::cosh) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e28294fu: + { + if (name == BuiltInName::atanh) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2924b8u: + { + if (name == BuiltInName::isinf) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e297347u: + { + if (name == BuiltInName::equal) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2a7a64u: + { + if (name == BuiltInName::round) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2d5dcbu: + { + if (name == BuiltInName::clamp) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2d8df4u: + { + if (name == BuiltInName::isnan) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2dcbc6u: + { + if (name == BuiltInName::asinh) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2eab16u: + { + if (name == BuiltInName::trunc) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2f67c3u: + { + if (name == BuiltInName::acosh) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e39ebd7u: + { + if (name == BuiltInName::texture) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e3d828cu: + { + if (name == BuiltInName::inverse) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e403a20u: + { + if (name == BuiltInName::lessThan) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e413f93u: + { + if (name == BuiltInName::notEqual) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4d27c2u: + { + if (name == BuiltInName::rgb_2_yuv) + { + return &UnmangledBuiltIns::EXT_YUV_target; + } + break; + } + case 0x7e4d323bu: + { + if (name == BuiltInName::roundEven) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4e024cu: + { + if (name == BuiltInName::transpose) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4e33aeu: + { + if (name == BuiltInName::yuv_2_rgb) + { + return &UnmangledBuiltIns::EXT_YUV_target; + } + break; + } + case 0x7e501e0cu: + { + if (name == BuiltInName::textureLod) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5237e1u: + { + if (name == BuiltInName::texelFetch) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e582ffcu: + { + if (name == BuiltInName::greaterThan) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e599347u: + { + if (name == BuiltInName::textureGrad) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5ba531u: + { + if (name == BuiltInName::determinant) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5caafbu: + { + if (name == BuiltInName::textureProj) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5e217eu: + { + if (name == BuiltInName::textureSize) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e62daa3u: + { + if (name == BuiltInName::packHalf2x16) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e646b9bu: + { + if (name == BuiltInName::outerProduct) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e683586u: + { + if (name == BuiltInName::lessThanEqual) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e6a013du: + { + if (name == BuiltInName::packSnorm2x16) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e6b72b8u: + { + if (name == BuiltInName::packUnorm2x16) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e6c5187u: + { + if (name == BuiltInName::textureOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e715db5u: + { + if (name == BuiltInName::unpackHalf2x16) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e759618u: + { + if (name == BuiltInName::floatBitsToInt) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e75ae2fu: + { + if (name == BuiltInName::textureProjLod) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e76bea7u: + { + if (name == BuiltInName::matrixCompMult) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e77fc97u: + { + if (name == BuiltInName::intBitsToFloat) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e792d39u: + { + if (name == BuiltInName::unpackUnorm2x16) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e7b6a0eu: + { + if (name == BuiltInName::unpackSnorm2x16) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e7bc1fdu: + { + if (name == BuiltInName::textureProjGrad) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e7e0e81u: + { + if (name == BuiltInName::uintBitsToFloat) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e7e5132u: + { + if (name == BuiltInName::floatBitsToUint) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e80919du: + { + if (name == BuiltInName::texelFetchOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e81c71au: + { + if (name == BuiltInName::textureLodOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e876cccu: + { + if (name == BuiltInName::greaterThanEqual) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e8b5832u: + { + if (name == BuiltInName::textureGradOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e8d2d2du: + { + if (name == BuiltInName::textureProjOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7ea0be08u: + { + if (name == BuiltInName::textureProjLodOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7eac5717u: + { + if (name == BuiltInName::textureProjGradOffset) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + } + if (mShaderType == GL_FRAGMENT_SHADER) + { + switch (nameHash) + { + case 0x7e2624d4u: + { + if (name == BuiltInName::dFdy) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e265ea7u: + { + if (name == BuiltInName::dFdx) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e324ea1u: + { + if (name == BuiltInName::fwidth) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + } + } + } + if (shaderVersion == 100) + { + switch (nameHash) + { + case 0x7e48c50cu: + { + if (name == BuiltInName::texture2D) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5ffc48u: + { + if (name == BuiltInName::textureCube) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e69f545u: + { + if (name == BuiltInName::texture2DRect) + { + return &UnmangledBuiltIns::ARB_texture_rectangle; + } + break; + } + case 0x7e6e3735u: + { + if (name == BuiltInName::texture2DProj) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e868a22u: + { + if (name == BuiltInName::texture2DGradEXT) + { + return &UnmangledBuiltIns::EXT_shader_texture_lod; + } + break; + } + case 0x7e8b66e4u: + { + if (name == BuiltInName::texture2DRectProj) + { + return &UnmangledBuiltIns::ARB_texture_rectangle; + } + break; + } + case 0x7e90fa5bu: + { + if (name == BuiltInName::textureCubeGradEXT) + { + return &UnmangledBuiltIns::EXT_shader_texture_lod; + } + break; + } + case 0x7ea20b8fu: + { + if (name == BuiltInName::texture2DProjGradEXT) + { + return &UnmangledBuiltIns::EXT_shader_texture_lod; + } + break; + } + } + if (mShaderType == GL_FRAGMENT_SHADER) + { + switch (nameHash) + { + case 0x7e2624d4u: + { + if (name == BuiltInName::dFdyExt) + { + return &UnmangledBuiltIns::OES_standard_derivatives; + } + break; + } + case 0x7e265ea7u: + { + if (name == BuiltInName::dFdxExt) + { + return &UnmangledBuiltIns::OES_standard_derivatives; + } + break; + } + case 0x7e324ea1u: + { + if (name == BuiltInName::fwidthExt) + { + return &UnmangledBuiltIns::OES_standard_derivatives; + } + break; + } + case 0x7e4db1c8u: + { + if (name == BuiltInName::texture3D) + { + return &UnmangledBuiltIns::OES_texture_3D; + } + break; + } + case 0x7e63c1d1u: + { + if (name == BuiltInName::texture3DLod) + { + return &UnmangledBuiltIns::OES_texture_3D; + } + break; + } + case 0x7e687e40u: + { + if (name == BuiltInName::texture3DProj) + { + return &UnmangledBuiltIns::OES_texture_3D; + } + break; + } + case 0x7e7b843eu: + { + if (name == BuiltInName::texture2DLodEXT) + { + return &UnmangledBuiltIns::EXT_shader_texture_lod; + } + break; + } + case 0x7e85692eu: + { + if (name == BuiltInName::texture3DProjLod) + { + return &UnmangledBuiltIns::OES_texture_3D; + } + break; + } + case 0x7e8b81cau: + { + if (name == BuiltInName::textureCubeLodEXT) + { + return &UnmangledBuiltIns::EXT_shader_texture_lod; + } + break; + } + case 0x7e9ddba0u: + { + if (name == BuiltInName::texture2DProjLodEXT) + { + return &UnmangledBuiltIns::EXT_shader_texture_lod; + } + break; + } + } + } + if (mShaderType == GL_VERTEX_SHADER) + { + switch (nameHash) + { + case 0x7e67c7ceu: + { + if (name == BuiltInName::texture2DLod) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e758eddu: + { + if (name == BuiltInName::textureCubeLod) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e819b90u: + { + if (name == BuiltInName::texture2DProjLod) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + } + } + } + switch (nameHash) + { + case 0x7e1892eeu: + { + if (name == BuiltInName::all) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e19507bu: + { + if (name == BuiltInName::abs) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e195106u: + { + if (name == BuiltInName::notFunc) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e197102u: + { + if (name == BuiltInName::any) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e19ebdbu: + { + if (name == BuiltInName::log) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1acb4eu: + { + if (name == BuiltInName::pow) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1b921cu: + { + if (name == BuiltInName::exp) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1cf321u: + { + if (name == BuiltInName::tan) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1e492du: + { + if (name == BuiltInName::min) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1e8464u: + { + if (name == BuiltInName::dot) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1ea71bu: + { + if (name == BuiltInName::mix) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1ebe0eu: + { + if (name == BuiltInName::max) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1eee70u: + { + if (name == BuiltInName::mod) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1f0bccu: + { + if (name == BuiltInName::sin) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e1fdef3u: + { + if (name == BuiltInName::cos) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e203979u: + { + if (name == BuiltInName::atan) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e206e40u: + { + if (name == BuiltInName::sign) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e209ec1u: + { + if (name == BuiltInName::log2) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e21ff11u: + { + if (name == BuiltInName::acos) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e23152fu: + { + if (name == BuiltInName::ceil) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e23f4beu: + { + if (name == BuiltInName::sqrt) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e24bcdbu: + { + if (name == BuiltInName::exp2) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e26202fu: + { + if (name == BuiltInName::step) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e27ebd5u: + { + if (name == BuiltInName::asin) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e295733u: + { + if (name == BuiltInName::cross) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e297347u: + { + if (name == BuiltInName::equal) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2d5dcbu: + { + if (name == BuiltInName::clamp) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2dcb25u: + { + if (name == BuiltInName::floor) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e2f6df3u: + { + if (name == BuiltInName::fract) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e340894u: + { + if (name == BuiltInName::length) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e38233fu: + { + if (name == BuiltInName::refract) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e3c3cb3u: + { + if (name == BuiltInName::radians) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e3c8e91u: + { + if (name == BuiltInName::reflect) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e3d784cu: + { + if (name == BuiltInName::degrees) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e403a20u: + { + if (name == BuiltInName::lessThan) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e413f93u: + { + if (name == BuiltInName::notEqual) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4161fau: + { + if (name == BuiltInName::distance) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e4e7aa5u: + { + if (name == BuiltInName::normalize) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e54a2cfu: + { + if (name == BuiltInName::smoothstep) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e582ffcu: + { + if (name == BuiltInName::greaterThan) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5ae14bu: + { + if (name == BuiltInName::faceforward) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e5f4d0fu: + { + if (name == BuiltInName::inversesqrt) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e683586u: + { + if (name == BuiltInName::lessThanEqual) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e76bea7u: + { + if (name == BuiltInName::matrixCompMult) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + case 0x7e876cccu: + { + if (name == BuiltInName::greaterThanEqual) + { + return &UnmangledBuiltIns::UNDEFINED; + } + break; + } + } + return nullptr; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h new file mode 100644 index 0000000000..2168743e29 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h @@ -0,0 +1,78 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_builtin_symbols.py using data from builtin_variables.json and +// builtin_function_declarations.txt. +// +// 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. +// +// SymbolTable_autogen.h: +// Autogenerated member variables of TSymbolTable. + +#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ +#define COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ + +namespace sh +{ + +class TSymbolTableBase +{ + protected: + TSymbolTableBase() = default; + TStructure *mVar_gl_DepthRangeParameters = nullptr; + TVariable *mVar_gl_DepthRange = nullptr; + TVariable *mVar_gl_MaxVertexAttribs = nullptr; + TVariable *mVar_gl_MaxVertexUniformVectors = nullptr; + TVariable *mVar_gl_MaxVertexTextureImageUnits = nullptr; + TVariable *mVar_gl_MaxCombinedTextureImageUnits = nullptr; + TVariable *mVar_gl_MaxTextureImageUnits = nullptr; + TVariable *mVar_gl_MaxFragmentUniformVectors = nullptr; + TVariable *mVar_gl_MaxVaryingVectors = nullptr; + TVariable *mVar_gl_MaxDrawBuffers = nullptr; + TVariable *mVar_gl_MaxDualSourceDrawBuffersEXT = nullptr; + TVariable *mVar_gl_MaxVertexOutputVectors = nullptr; + TVariable *mVar_gl_MaxFragmentInputVectors = nullptr; + TVariable *mVar_gl_MinProgramTexelOffset = nullptr; + TVariable *mVar_gl_MaxProgramTexelOffset = nullptr; + TVariable *mVar_gl_MaxImageUnits = nullptr; + TVariable *mVar_gl_MaxVertexImageUniforms = nullptr; + TVariable *mVar_gl_MaxFragmentImageUniforms = nullptr; + TVariable *mVar_gl_MaxComputeImageUniforms = nullptr; + TVariable *mVar_gl_MaxCombinedImageUniforms = nullptr; + TVariable *mVar_gl_MaxCombinedShaderOutputResources = nullptr; + TVariable *mVar_gl_MaxComputeWorkGroupCount = nullptr; + TVariable *mVar_gl_MaxComputeWorkGroupSize = nullptr; + TVariable *mVar_gl_MaxComputeUniformComponents = nullptr; + TVariable *mVar_gl_MaxComputeTextureImageUnits = nullptr; + TVariable *mVar_gl_MaxComputeAtomicCounters = nullptr; + TVariable *mVar_gl_MaxComputeAtomicCounterBuffers = nullptr; + TVariable *mVar_gl_MaxVertexAtomicCounters = nullptr; + TVariable *mVar_gl_MaxFragmentAtomicCounters = nullptr; + TVariable *mVar_gl_MaxCombinedAtomicCounters = nullptr; + TVariable *mVar_gl_MaxAtomicCounterBindings = nullptr; + TVariable *mVar_gl_MaxVertexAtomicCounterBuffers = nullptr; + TVariable *mVar_gl_MaxFragmentAtomicCounterBuffers = nullptr; + TVariable *mVar_gl_MaxCombinedAtomicCounterBuffers = nullptr; + TVariable *mVar_gl_MaxAtomicCounterBufferSize = nullptr; + TVariable *mVar_gl_MaxGeometryInputComponents = nullptr; + TVariable *mVar_gl_MaxGeometryOutputComponents = nullptr; + TVariable *mVar_gl_MaxGeometryImageUniforms = nullptr; + TVariable *mVar_gl_MaxGeometryTextureImageUnits = nullptr; + TVariable *mVar_gl_MaxGeometryOutputVertices = nullptr; + TVariable *mVar_gl_MaxGeometryTotalOutputComponents = nullptr; + TVariable *mVar_gl_MaxGeometryUniformComponents = nullptr; + TVariable *mVar_gl_MaxGeometryAtomicCounters = nullptr; + TVariable *mVar_gl_MaxGeometryAtomicCounterBuffers = nullptr; + TVariable *mVar_gl_FragData = nullptr; + TVariable *mVar_gl_SecondaryFragDataEXT = nullptr; + TVariable *mVar_gl_FragDepthEXT = nullptr; + TVariable *mVar_gl_LastFragData = nullptr; + TVariable *mVar_gl_LastFragDataNV = nullptr; + TInterfaceBlock *mVar_gl_PerVertex = nullptr; + TVariable *mVar_gl_in = nullptr; + TVariable *mVar_gl_PositionGS = nullptr; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.cpp b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.cpp new file mode 100644 index 0000000000..3aeb80b708 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.cpp @@ -0,0 +1,27 @@ +// +// Copyright (c) 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. +// +// SymbolUniqueId.cpp: Encapsulates a unique id for a symbol. + +#include "compiler/translator/SymbolUniqueId.h" + +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +TSymbolUniqueId::TSymbolUniqueId(TSymbolTable *symbolTable) : mId(symbolTable->nextUniqueIdValue()) +{} + +TSymbolUniqueId::TSymbolUniqueId(const TSymbol &symbol) : mId(symbol.uniqueId().get()) {} + +TSymbolUniqueId &TSymbolUniqueId::operator=(const TSymbolUniqueId &) = default; + +bool TSymbolUniqueId::operator==(const TSymbolUniqueId &other) const +{ + return mId == other.mId; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.h b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.h new file mode 100644 index 0000000000..7d0979e266 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/SymbolUniqueId.h @@ -0,0 +1,58 @@ +// +// Copyright (c) 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. +// +// SymbolUniqueId.h: Encapsulates a unique id for a symbol. + +#ifndef COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_ +#define COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_ + +#include "compiler/translator/Common.h" + +namespace sh +{ + +class TSymbolTable; +class TSymbol; + +class TSymbolUniqueId +{ + public: + POOL_ALLOCATOR_NEW_DELETE + explicit TSymbolUniqueId(const TSymbol &symbol); + constexpr TSymbolUniqueId(const TSymbolUniqueId &) = default; + TSymbolUniqueId &operator =(const TSymbolUniqueId &); + bool operator==(const TSymbolUniqueId &) const; + + constexpr int get() const { return mId; } + + private: + friend class TSymbolTable; + explicit TSymbolUniqueId(TSymbolTable *symbolTable); + + friend class BuiltInId; + constexpr TSymbolUniqueId(int staticId) : mId(staticId) {} + + int mId; +}; + +enum class SymbolType +{ + BuiltIn, + UserDefined, + AngleInternal, + Empty // Meaning symbol without a name. +}; + +enum class SymbolClass +{ + Function, + Variable, + Struct, + InterfaceBlock +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_SYMBOLUNIQUEID_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.cpp new file mode 100644 index 0000000000..6ef502587c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.cpp @@ -0,0 +1,1554 @@ +// +// Copyright (c) 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. +// +// TextureFunctionHLSL: Class for writing implementations of ESSL texture functions into HLSL +// output. Some of the implementations are straightforward and just call the HLSL equivalent of the +// ESSL texture function, others do more work to emulate ESSL texture sampling or size query +// behavior. +// + +#include "compiler/translator/TextureFunctionHLSL.h" + +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/UtilsHLSL.h" + +namespace sh +{ + +namespace +{ + +void OutputIntTexCoordWrap(TInfoSinkBase &out, + const char *wrapMode, + const char *size, + const ImmutableString &texCoord, + const char *texCoordOffset, + const char *texCoordOutName) +{ + // GLES 3.0.4 table 3.22 specifies how the wrap modes work. We don't use the formulas verbatim + // but rather use equivalent formulas that map better to HLSL. + out << "int " << texCoordOutName << ";\n"; + out << "float " << texCoordOutName << "Offset = " << texCoord << " + float(" << texCoordOffset + << ") / " << size << ";\n"; + out << "bool " << texCoordOutName << "UseBorderColor = false;\n"; + + // CLAMP_TO_EDGE + out << "if (" << wrapMode << " == 0)\n"; + out << "{\n"; + out << " " << texCoordOutName << " = clamp(int(floor(" << size << " * " << texCoordOutName + << "Offset)), 0, int(" << size << ") - 1);\n"; + out << "}\n"; + + // CLAMP_TO_BORDER + out << "else if (" << wrapMode << " == 3)\n"; + out << "{\n"; + out << " int texCoordInt = int(floor(" << size << " * " << texCoordOutName << "Offset));\n"; + out << " " << texCoordOutName << " = clamp(texCoordInt, 0, int(" << size << ") - 1);\n"; + out << " " << texCoordOutName << "UseBorderColor = (texCoordInt != " << texCoordOutName + << ");\n"; + out << "}\n"; + + // MIRRORED_REPEAT + out << "else if (" << wrapMode << " == 2)\n"; + out << "{\n"; + out << " float coordWrapped = 1.0 - abs(frac(abs(" << texCoordOutName + << "Offset) * 0.5) * 2.0 - 1.0);\n"; + out << " " << texCoordOutName << " = int(floor(" << size << " * coordWrapped));\n"; + out << "}\n"; + + // REPEAT + out << "else\n"; + out << "{\n"; + out << " " << texCoordOutName << " = int(floor(" << size << " * frac(" << texCoordOutName + << "Offset)));\n"; + out << "}\n"; +} + +void OutputIntTexCoordWraps(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + ImmutableString *texCoordX, + ImmutableString *texCoordY, + ImmutableString *texCoordZ) +{ + // Convert from normalized floating-point to integer + out << "int wrapS = samplerMetadata[samplerIndex].wrapModes & 0x3;\n"; + if (textureFunction.offset) + { + OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "offset.x", "tix"); + } + else + { + OutputIntTexCoordWrap(out, "wrapS", "width", *texCoordX, "0", "tix"); + } + *texCoordX = ImmutableString("tix"); + out << "int wrapT = (samplerMetadata[samplerIndex].wrapModes >> 2) & 0x3;\n"; + if (textureFunction.offset) + { + OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "offset.y", "tiy"); + } + else + { + OutputIntTexCoordWrap(out, "wrapT", "height", *texCoordY, "0", "tiy"); + } + *texCoordY = ImmutableString("tiy"); + + bool tizAvailable = false; + + if (IsSamplerArray(textureFunction.sampler)) + { + *texCoordZ = ImmutableString("int(max(0, min(layers - 1, floor(0.5 + t.z))))"); + } + else if (!IsSamplerCube(textureFunction.sampler) && !IsSampler2D(textureFunction.sampler)) + { + out << "int wrapR = (samplerMetadata[samplerIndex].wrapModes >> 4) & 0x3;\n"; + if (textureFunction.offset) + { + OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "offset.z", "tiz"); + } + else + { + OutputIntTexCoordWrap(out, "wrapR", "depth", *texCoordZ, "0", "tiz"); + } + *texCoordZ = ImmutableString("tiz"); + tizAvailable = true; + } + + out << "bool useBorderColor = tixUseBorderColor || tiyUseBorderColor" + << (tizAvailable ? " || tizUseBorderColor" : "") << ";\n"; +} + +void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ImmutableString &textureReference, + const ImmutableString &samplerReference) +{ + out << textureReference; + if (IsIntegerSampler(textureFunction.sampler) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH) + { + out << ".Load("; + return; + } + + if (IsShadowSampler(textureFunction.sampler)) + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + case TextureFunctionHLSL::TextureFunction::BIAS: + case TextureFunctionHLSL::TextureFunction::LOD: + out << ".SampleCmp("; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + case TextureFunctionHLSL::TextureFunction::GRAD: + out << ".SampleCmpLevelZero("; + break; + default: + UNREACHABLE(); + } + } + else + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + out << ".Sample("; + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + out << ".SampleBias("; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + case TextureFunctionHLSL::TextureFunction::LOD0: + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << ".SampleLevel("; + break; + case TextureFunctionHLSL::TextureFunction::GRAD: + out << ".SampleGrad("; + break; + default: + UNREACHABLE(); + } + } + out << samplerReference << ", "; +} + +const char *GetSamplerCoordinateTypeString( + const TextureFunctionHLSL::TextureFunction &textureFunction, + int hlslCoords) +{ + // Gather[Red|Green|Blue|Alpha] accepts float texture coordinates on textures in integer or + // unsigned integer formats. + // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-to-gather + if ((IsIntegerSampler(textureFunction.sampler) && + textureFunction.method != TextureFunctionHLSL::TextureFunction::GATHER) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH) + { + switch (hlslCoords) + { + case 2: + if (IsSampler2DMS(textureFunction.sampler)) + { + return "int2"; + } + else + { + return "int3"; + } + case 3: + if (IsSampler2DMSArray(textureFunction.sampler)) + { + return "int3"; + } + else + { + return "int4"; + } + default: + UNREACHABLE(); + } + } + else + { + switch (hlslCoords) + { + case 2: + return "float2"; + case 3: + return "float3"; + case 4: + return "float4"; + default: + UNREACHABLE(); + } + } + return ""; +} + +int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunction, + ShShaderOutput outputType) +{ + if (outputType == SH_HLSL_3_0_OUTPUT) + { + int hlslCoords = 2; + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtSamplerExternalOES: + case EbtSampler2DMS: + hlslCoords = 2; + break; + case EbtSamplerCube: + hlslCoords = 3; + break; + default: + UNREACHABLE(); + } + + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + case TextureFunctionHLSL::TextureFunction::GRAD: + return hlslCoords; + case TextureFunctionHLSL::TextureFunction::BIAS: + case TextureFunctionHLSL::TextureFunction::LOD: + case TextureFunctionHLSL::TextureFunction::LOD0: + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + return 4; + default: + UNREACHABLE(); + } + } + else + { + if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) || + IsSamplerCube(textureFunction.sampler)) + { + return 3; + } + ASSERT(IsSampler2D(textureFunction.sampler)); + return 2; + } + return 0; +} + +void OutputTextureFunctionArgumentList(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType) +{ + if (outputType == SH_HLSL_3_0_OUTPUT) + { + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtSamplerExternalOES: + out << "sampler2D s"; + break; + case EbtSamplerCube: + out << "samplerCUBE s"; + break; + default: + UNREACHABLE(); + } + } + else + { + if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + out << TextureString(textureFunction.sampler) << " x, " + << SamplerString(textureFunction.sampler) << " s"; + } + else + { + ASSERT(outputType == SH_HLSL_4_1_OUTPUT); + // A bug in the D3D compiler causes some nested sampling operations to fail. + // See http://anglebug.com/1923 + // TODO(jmadill): Reinstate the const keyword when possible. + out << /*"const"*/ "uint samplerIndex"; + } + } + + if (textureFunction.method == + TextureFunctionHLSL::TextureFunction::FETCH) // Integer coordinates + { + switch (textureFunction.coords) + { + case 2: + out << ", int2 t"; + break; + case 3: + out << ", int3 t"; + break; + default: + UNREACHABLE(); + } + } + else // Floating-point coordinates (except textureSize) + { + switch (textureFunction.coords) + { + case 0: + break; // textureSize(gSampler2DMS sampler) + case 1: + out << ", int lod"; + break; // textureSize() + case 2: + out << ", float2 t"; + break; + case 3: + out << ", float3 t"; + break; + case 4: + out << ", float4 t"; + break; + default: + UNREACHABLE(); + } + } + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + case EbtSamplerExternalOES: + out << ", float2 ddx, float2 ddy"; + break; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + out << ", float3 ddx, float3 ddy"; + break; + default: + UNREACHABLE(); + } + } + + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + break; // Comes after the offset parameter + case TextureFunctionHLSL::TextureFunction::LOD: + out << ", float lod"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + break; // Comes after the offset parameter + case TextureFunctionHLSL::TextureFunction::SIZE: + break; + case TextureFunctionHLSL::TextureFunction::FETCH: + if (IsSampler2DMS(textureFunction.sampler) || + IsSampler2DMSArray(textureFunction.sampler)) + out << ", int index"; + else + out << ", int mip"; + break; + case TextureFunctionHLSL::TextureFunction::GRAD: + break; + case TextureFunctionHLSL::TextureFunction::GATHER: + break; + default: + UNREACHABLE(); + } + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER && + IsShadowSampler(textureFunction.sampler)) + { + out << ", float refZ"; + } + + if (textureFunction.offset) + { + switch (textureFunction.sampler) + { + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + out << ", int3 offset"; + break; + case EbtSampler2D: + case EbtSampler2DArray: + case EbtISampler2D: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + case EbtSamplerExternalOES: + out << ", int2 offset"; + break; + default: + // Offset is not supported for multisampled textures. + UNREACHABLE(); + } + } + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS || + textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << ", float bias"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GATHER && + !IsShadowSampler(textureFunction.sampler)) + { + out << ", int comp = 0"; + } +} + +void GetTextureReference(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType, + ImmutableString *textureReference, + ImmutableString *samplerReference) +{ + if (outputType == SH_HLSL_4_1_OUTPUT) + { + static const ImmutableString kTexturesStr("textures"); + static const ImmutableString kSamplersStr("samplers"); + static const ImmutableString kSamplerIndexStr("[samplerIndex]"); + static const ImmutableString kTextureIndexStr("[textureIndex]"); + static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]"); + ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler)); + + if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D) + { + ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() + + kSamplerIndexStr.length()); + textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr; + *textureReference = textureRefBuilder; + ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() + + kSamplerIndexStr.length()); + samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr; + *samplerReference = samplerRefBuilder; + } + else + { + out << " const uint textureIndex = samplerIndex - textureIndexOffset" + << suffix.data() << ";\n"; + ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() + + kTextureIndexStr.length()); + textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr; + *textureReference = textureRefBuilder; + + out << " const uint samplerArrayIndex = samplerIndex - samplerIndexOffset" + << suffix.data() << ";\n"; + ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() + + kSamplerArrayIndexStr.length()); + samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr; + *samplerReference = samplerRefBuilder; + } + } + else + { + *textureReference = ImmutableString("x"); + *samplerReference = ImmutableString("s"); + } +} + +void OutputTextureSizeFunctionBody(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ImmutableString &textureReference, + bool getDimensionsIgnoresBaseLevel) +{ + if (IsSampler2DMS(textureFunction.sampler)) + { + out << " uint width; uint height; uint samples;\n" + << " " << textureReference << ".GetDimensions(width, height, samples);\n"; + } + else if (IsSampler2DMSArray(textureFunction.sampler)) + { + out << " uint width; uint height; uint depth; uint samples;\n" + << " " << textureReference << ".GetDimensions(width, height, depth, samples);\n"; + } + else + { + if (getDimensionsIgnoresBaseLevel) + { + out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n"; + } + else + { + out << " int baseLevel = 0;\n"; + } + + if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) || + (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler))) + { + // "depth" stores either the number of layers in an array texture or 3D depth + out << " uint width; uint height; uint depth; uint numberOfLevels;\n" + << " " << textureReference + << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n" + << " width = max(width >> lod, 1);\n" + << " height = max(height >> lod, 1);\n"; + + if (!IsSamplerArray(textureFunction.sampler)) + { + out << " depth = max(depth >> lod, 1);\n"; + } + } + else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler)) + { + out << " uint width; uint height; uint numberOfLevels;\n" + << " " << textureReference + << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n" + << " width = max(width >> lod, 1);\n" + << " height = max(height >> lod, 1);\n"; + } + else + UNREACHABLE(); + } + + if (strcmp(textureFunction.getReturnType(), "int3") == 0) + { + out << " return int3(width, height, depth);\n"; + } + else + { + out << " return int2(width, height);\n"; + } +} + +void ProjectTextureCoordinates(const TextureFunctionHLSL::TextureFunction &textureFunction, + ImmutableString *texCoordX, + ImmutableString *texCoordY, + ImmutableString *texCoordZ) +{ + if (textureFunction.proj) + { + ImmutableString proj(""); + switch (textureFunction.coords) + { + case 3: + proj = ImmutableString(" / t.z"); + break; + case 4: + proj = ImmutableString(" / t.w"); + break; + default: + UNREACHABLE(); + } + ImmutableStringBuilder texCoordXBuilder(texCoordX->length() + proj.length() + 2u); + texCoordXBuilder << '(' << *texCoordX << proj << ')'; + *texCoordX = texCoordXBuilder; + ImmutableStringBuilder texCoordYBuilder(texCoordY->length() + proj.length() + 2u); + texCoordYBuilder << '(' << *texCoordY << proj << ')'; + *texCoordY = texCoordYBuilder; + ImmutableStringBuilder texCoordZBuilder(texCoordZ->length() + proj.length() + 2u); + texCoordZBuilder << '(' << *texCoordZ << proj << ')'; + *texCoordZ = texCoordZBuilder; + } +} + +void OutputIntegerTextureSampleFunctionComputations( + TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType, + const ImmutableString &textureReference, + ImmutableString *texCoordX, + ImmutableString *texCoordY, + ImmutableString *texCoordZ, + bool getDimensionsIgnoresBaseLevel) +{ + if (!IsIntegerSampler(textureFunction.sampler)) + { + return; + } + + if (getDimensionsIgnoresBaseLevel) + { + out << " int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n"; + } + else + { + out << " int baseLevel = 0;\n"; + } + + if (IsSamplerCube(textureFunction.sampler)) + { + out << " float width; float height; float layers; float levels;\n"; + + out << " uint mip = 0;\n"; + + out << " " << textureReference + << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n"; + + out << " bool xMajor = abs(t.x) >= abs(t.y) && abs(t.x) >= abs(t.z);\n"; + out << " bool yMajor = abs(t.y) >= abs(t.z) && abs(t.y) > abs(t.x);\n"; + out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n"; + out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || " + "(zMajor && t.z < 0.0f);\n"; + + // FACE_POSITIVE_X = 000b + // FACE_NEGATIVE_X = 001b + // FACE_POSITIVE_Y = 010b + // FACE_NEGATIVE_Y = 011b + // FACE_POSITIVE_Z = 100b + // FACE_NEGATIVE_Z = 101b + out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n"; + + out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n"; + out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n"; + out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n"; + + out << " float3 r = any(t) ? t : float3(1, 0, 0);\n"; + out << " t.x = (u * 0.5f / m) + 0.5f;\n"; + out << " t.y = (v * 0.5f / m) + 0.5f;\n"; + + // Mip level computation. + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD || + textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT) + { + // We would like to calculate tha maximum of how many texels we move in the major + // face's texture as we move across the screen in any direction. Namely, we want the + // length of the directional derivative of the function p (defined below), maximized + // over screen space directions. (For short: we want the norm of Dp.) For + // simplicity, assume that z-axis is the major axis. By symmetry, we can assume that + // the positive z direction is major. (The calculated value will be the same even if + // this is false.) Let r denote the function from screen position to cube texture + // coordinates. Then p can be written as p = s . P . r, where P(r) = (r.x, r.y)/r.z + // is the projection onto the major cube face, and s = diag(width, height)/2. (s + // linearly maps from the cube face into texture space, so that p(r) is in units of + // texels.) The derivative is + // Dp(r) = s |1 0 -r.x/r.z| + // |0 1 -r.y/r.z| |ddx(r) ddy(r)| / r.z + // = |dot(a, ddx(r)) dot(a, ddy(r))| + // |dot(b, ddx(r)) dot(b, ddy(r))| / (2 r.z) + // where a = w * vec3(1, 0, -r.x/r.z) + // b = h * vec3(0, 1, -r.y/r.z) + // We would like to know max(L(x)) over unit vectors x, where L(x) = |Dp(r) x|^2. + // Since ddx(r) and ddy(r) are unknown, the best we can do is to sample L in some + // directions and take the maximum across the samples. + // + // Some implementations use max(L(n1), L(n2)) where n1 = vec2(1,0) and n2 = + // vec2(0,1). + // + // Some implementations use max(L(n1), L(n2), L(n3), L(n4)), + // where n3 = (n1 + n2) / |n1 + n2| = (n1 + n2)/sqrt(2) + // n4 = (n1 - n2) / |n1 - n2| = (n1 - n2)/sqrt(2). + // In other words, two samples along the diagonal screen space directions have been + // added, giving a strictly better estimate of the true maximum. + // + // It turns out we can get twice the sample count very cheaply. + // We can use the linearity of Dp(r) to get these extra samples of L cheaply in + // terms of the already taken samples, L(n1) and L(n2): + // Denoting + // dpx = Dp(r)n1 + // dpy = Dp(r)n2 + // dpxx = dot(dpx, dpx) + // dpyy = dot(dpy, dpy) + // dpxy = dot(dpx, dpy) + // we obtain + // L(n3) = |Dp(r)n1 + Dp(r)n2|^2/2 = (dpxx + dpyy)/2 + dpxy + // L(n4) = |Dp(r)n1 - Dp(r)n2|^2/2 = (dpxx + dpyy)/2 - dpxy + // max(L(n1), L(n2), L(n3), L(n4)) + // = max(max(L(n1), L(n2)), max(L(n3), L(n4))) + // = max(max(dpxx, dpyy), (dpxx + dpyy)/2 + abs(dpxy)) + // So the extra cost is: one dot, one abs, one add, one multiply-add and one max. + // (All scalar.) + // + // In section 3.8.10.1, the OpenGL ES 3 specification defines the "scale factor", + // rho. In our terminology, this definition works out to taking sqrt(max(L(n1), + // L(n2))). Some implementations will use this estimate, here we use the strictly + // better sqrt(max(L(n1), L(n2), L(n3), L(n4))), since it's not much more expensive + // to calculate. + + // Swap coordinates such that we can assume that the positive z-axis is major, in + // what follows. + out << " float3 ddxr = xMajor ? ddx(r).yzx : yMajor ? ddx(r).zxy : ddx(r).xyz;\n" + " float3 ddyr = xMajor ? ddy(r).yzx : yMajor ? ddy(r).zxy : ddy(r).xyz;\n" + " r = xMajor ? r.yzx : yMajor ? r.zxy : r.xyz;\n"; + + out << " float2 s = 0.5*float2(width, height);\n" + " float2 dpx = s * (ddxr.xy - ddxr.z*r.xy/r.z)/r.z;\n" + " float2 dpy = s * (ddyr.xy - ddyr.z*r.xy/r.z)/r.z;\n" + " float dpxx = dot(dpx, dpx);\n;" + " float dpyy = dot(dpy, dpy);\n;" + " float dpxy = dot(dpx, dpy);\n" + " float ma = max(dpxx, dpyy);\n" + " float mb = 0.5 * (dpxx + dpyy) + abs(dpxy);\n" + " float mab = max(ma, mb);\n" + " float lod = 0.5f * log2(mab);\n"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + // ESSL 3.00.6 spec section 8.8: "For the cube version, the partial + // derivatives of P are assumed to be in the coordinate system used before + // texture coordinates are projected onto the appropriate cube face." + // ddx[0] and ddy[0] are the derivatives of t.x passed into the function + // ddx[1] and ddy[1] are the derivatives of t.y passed into the function + // ddx[2] and ddy[2] are the derivatives of t.z passed into the function + // Determine the derivatives of u, v and m + out << " float dudx = xMajor ? ddx[2] : (yMajor && t.y < 0.0f ? -ddx[0] " + ": ddx[0]);\n" + " float dudy = xMajor ? ddy[2] : (yMajor && t.y < 0.0f ? -ddy[0] " + ": ddy[0]);\n" + " float dvdx = yMajor ? ddx[2] : (negative ? ddx[1] : -ddx[1]);\n" + " float dvdy = yMajor ? ddy[2] : (negative ? ddy[1] : -ddy[1]);\n" + " float dmdx = xMajor ? ddx[0] : (yMajor ? ddx[1] : ddx[2]);\n" + " float dmdy = xMajor ? ddy[0] : (yMajor ? ddy[1] : ddy[2]);\n"; + // Now determine the derivatives of the face coordinates, using the + // derivatives calculated above. + // d / dx (u(x) * 0.5 / m(x) + 0.5) + // = 0.5 * (m(x) * u'(x) - u(x) * m'(x)) / m(x)^2 + out << " float dfacexdx = 0.5f * (m * dudx - u * dmdx) / (m * m);\n" + " float dfaceydx = 0.5f * (m * dvdx - v * dmdx) / (m * m);\n" + " float dfacexdy = 0.5f * (m * dudy - u * dmdy) / (m * m);\n" + " float dfaceydy = 0.5f * (m * dvdy - v * dmdy) / (m * m);\n" + " float2 sizeVec = float2(width, height);\n" + " float2 faceddx = float2(dfacexdx, dfaceydx) * sizeVec;\n" + " float2 faceddy = float2(dfacexdy, dfaceydy) * sizeVec;\n"; + // Optimization: instead of: log2(max(length(faceddx), length(faceddy))) + // we compute: log2(max(length(faceddx)^2, length(faceddy)^2)) / 2 + out << " float lengthfaceddx2 = dot(faceddx, faceddx);\n" + " float lengthfaceddy2 = dot(faceddy, faceddy);\n" + " float lod = log2(max(lengthfaceddx2, lengthfaceddy2)) * 0.5f;\n"; + } + out << " mip = uint(min(max(round(lod), 0), levels - 1));\n" + << " " << textureReference + << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n"; + } + + // Convert from normalized floating-point to integer + static const ImmutableString kXPrefix("int(floor(width * frac("); + static const ImmutableString kYPrefix("int(floor(height * frac("); + static const ImmutableString kSuffix(")))"); + ImmutableStringBuilder texCoordXBuilder(kXPrefix.length() + texCoordX->length() + + kSuffix.length()); + texCoordXBuilder << kXPrefix << *texCoordX << kSuffix; + *texCoordX = texCoordXBuilder; + ImmutableStringBuilder texCoordYBuilder(kYPrefix.length() + texCoordX->length() + + kSuffix.length()); + texCoordYBuilder << kYPrefix << *texCoordY << kSuffix; + *texCoordY = texCoordYBuilder; + *texCoordZ = ImmutableString("face"); + } + else if (textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH) + { + if (IsSamplerArray(textureFunction.sampler)) + { + out << " float width; float height; float layers; float levels;\n"; + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + + out << " " << textureReference + << ".GetDimensions(baseLevel, width, height, layers, levels);\n"; + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " float2 tSized = float2(t.x * width, t.y * height);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + out << " float2 sizeVec = float2(width, height);\n" + " float2 sizeDdx = ddx * sizeVec;\n" + " float2 sizeDdy = ddy * sizeVec;\n" + " float lod = log2(max(dot(sizeDdx, sizeDdx), " + "dot(sizeDdy, sizeDdy))) * 0.5f;\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " " << textureReference + << ".GetDimensions(baseLevel + mip, width, height, layers, levels);\n"; + } + else if (IsSampler2D(textureFunction.sampler)) + { + out << " float width; float height; float levels;\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + out << " " << textureReference + << ".GetDimensions(baseLevel, width, height, levels);\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " float2 tSized = float2(t.x * width, t.y * height);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + out << " float2 sizeVec = float2(width, height);\n" + " float2 sizeDdx = ddx * sizeVec;\n" + " float2 sizeDdy = ddy * sizeVec;\n" + " float lod = log2(max(dot(sizeDdx, sizeDdx), " + "dot(sizeDdy, sizeDdy))) * 0.5f;\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " " << textureReference + << ".GetDimensions(baseLevel + mip, width, height, levels);\n"; + } + else if (IsSampler3D(textureFunction.sampler)) + { + out << " float width; float height; float depth; float levels;\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + out << " " << textureReference + << ".GetDimensions(baseLevel, width, height, depth, levels);\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::IMPLICIT || + textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + out << " float3 sizeVec = float3(width, height, depth);\n" + " float3 sizeDdx = ddx * sizeVec;\n" + " float3 sizeDdy = ddy * sizeVec;\n" + " float lod = log2(max(dot(sizeDdx, sizeDdx), dot(sizeDdy, " + "sizeDdy))) * 0.5f;\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " " << textureReference + << ".GetDimensions(baseLevel + mip, width, height, depth, levels);\n"; + } + else + UNREACHABLE(); + + OutputIntTexCoordWraps(out, textureFunction, texCoordX, texCoordY, texCoordZ); + } +} + +void OutputTextureGatherFunctionBody(TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + ShShaderOutput outputType, + const ImmutableString &textureReference, + const ImmutableString &samplerReference, + const ImmutableString &texCoordX, + const ImmutableString &texCoordY, + const ImmutableString &texCoordZ) +{ + const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType); + ImmutableString samplerCoordTypeString( + GetSamplerCoordinateTypeString(textureFunction, hlslCoords)); + ImmutableStringBuilder samplerCoordBuilder( + samplerCoordTypeString.length() + strlen("(") + texCoordX.length() + strlen(", ") + + texCoordY.length() + strlen(", ") + texCoordZ.length() + strlen(")")); + + samplerCoordBuilder << samplerCoordTypeString << "(" << texCoordX << ", " << texCoordY; + if (hlslCoords >= 3) + { + if (textureFunction.coords < 3) + { + samplerCoordBuilder << ", 0"; + } + else + { + samplerCoordBuilder << ", " << texCoordZ; + } + } + samplerCoordBuilder << ")"; + + ImmutableString samplerCoordString(samplerCoordBuilder); + + if (IsShadowSampler(textureFunction.sampler)) + { + out << "return " << textureReference << ".GatherCmp(" << samplerReference << ", " + << samplerCoordString << ", refZ"; + if (textureFunction.offset) + { + out << ", offset"; + } + out << ");\n"; + return; + } + + constexpr std::array<const char *, 4> kHLSLGatherFunctions = { + {"GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha"}}; + + out << " switch(comp)\n" + " {\n"; + for (size_t component = 0; component < kHLSLGatherFunctions.size(); ++component) + { + out << " case " << component << ":\n" + << " return " << textureReference << "." << kHLSLGatherFunctions[component] + << "(" << samplerReference << ", " << samplerCoordString; + if (textureFunction.offset) + { + out << ", offset"; + } + out << ");\n"; + } + + out << " default:\n" + " return float4(0.0, 0.0, 0.0, 1.0);\n" + " }\n"; +} + +void OutputTextureSampleFunctionReturnStatement( + TInfoSinkBase &out, + const TextureFunctionHLSL::TextureFunction &textureFunction, + const ShShaderOutput outputType, + const ImmutableString &textureReference, + const ImmutableString &samplerReference, + const ImmutableString &texCoordX, + const ImmutableString &texCoordY, + const ImmutableString &texCoordZ) +{ + out << " return "; + + if (IsIntegerSampler(textureFunction.sampler) && !IsSamplerCube(textureFunction.sampler) && + textureFunction.method != TextureFunctionHLSL::TextureFunction::FETCH) + { + out << " useBorderColor ? "; + if (IsIntegerSamplerUnsigned(textureFunction.sampler)) + { + out << "asuint"; + } + out << "(samplerMetadata[samplerIndex].intBorderColor) : "; + } + + // HLSL intrinsic + if (outputType == SH_HLSL_3_0_OUTPUT) + { + switch (textureFunction.sampler) + { + case EbtSampler2D: + case EbtSamplerExternalOES: + out << "tex2D"; + break; + case EbtSamplerCube: + out << "texCUBE"; + break; + default: + UNREACHABLE(); + } + + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + out << "(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + out << "bias(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + out << "lod(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + out << "lod(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << "lod(" << samplerReference << ", "; + break; + case TextureFunctionHLSL::TextureFunction::GRAD: + out << "grad(" << samplerReference << ", "; + break; + default: + UNREACHABLE(); + } + } + else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + OutputHLSL4SampleFunctionPrefix(out, textureFunction, textureReference, samplerReference); + } + else + UNREACHABLE(); + + const int hlslCoords = GetHLSLCoordCount(textureFunction, outputType); + + out << GetSamplerCoordinateTypeString(textureFunction, hlslCoords) << "(" << texCoordX << ", " + << texCoordY; + + if (outputType == SH_HLSL_3_0_OUTPUT) + { + if (hlslCoords >= 3) + { + if (textureFunction.coords < 3) + { + out << ", 0"; + } + else + { + out << ", " << texCoordZ; + } + } + + if (hlslCoords == 4) + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::BIAS: + out << ", bias"; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + out << ", lod"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + out << ", 0"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << ", bias"; + break; + default: + UNREACHABLE(); + } + } + + out << ")"; + } + else if (outputType == SH_HLSL_4_1_OUTPUT || outputType == SH_HLSL_4_0_FL9_3_OUTPUT) + { + if (hlslCoords >= 3) + { + ASSERT(!IsIntegerSampler(textureFunction.sampler) || + !IsSamplerCube(textureFunction.sampler) || texCoordZ == "face"); + out << ", " << texCoordZ; + } + + if (textureFunction.method == TextureFunctionHLSL::TextureFunction::GRAD) + { + if (IsIntegerSampler(textureFunction.sampler)) + { + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction.sampler)) + { + // Compare value + if (textureFunction.proj) + { + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as + // Dref + out << "), " << texCoordZ; + } + else + { + switch (textureFunction.coords) + { + case 3: + out << "), t.z"; + break; + case 4: + out << "), t.w"; + break; + default: + UNREACHABLE(); + } + } + } + else + { + out << "), ddx, ddy"; + } + } + else if (IsIntegerSampler(textureFunction.sampler) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH) + { + if (IsSampler2DMS(textureFunction.sampler) || + IsSampler2DMSArray(textureFunction.sampler)) + out << "), index"; + else + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction.sampler)) + { + // Compare value + if (textureFunction.proj) + { + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as Dref + out << "), " << texCoordZ; + } + else + { + switch (textureFunction.coords) + { + case 3: + out << "), t.z"; + break; + case 4: + out << "), t.w"; + break; + default: + UNREACHABLE(); + } + } + } + else + { + switch (textureFunction.method) + { + case TextureFunctionHLSL::TextureFunction::IMPLICIT: + out << ")"; + break; + case TextureFunctionHLSL::TextureFunction::BIAS: + out << "), bias"; + break; + case TextureFunctionHLSL::TextureFunction::LOD: + out << "), lod"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0: + out << "), 0"; + break; + case TextureFunctionHLSL::TextureFunction::LOD0BIAS: + out << "), bias"; + break; + default: + UNREACHABLE(); + } + } + + if (textureFunction.offset && + (!IsIntegerSampler(textureFunction.sampler) || + textureFunction.method == TextureFunctionHLSL::TextureFunction::FETCH)) + { + out << ", offset"; + } + } + else + UNREACHABLE(); + + out << ");\n"; // Close the sample function call and return statement +} + +} // Anonymous namespace + +ImmutableString TextureFunctionHLSL::TextureFunction::name() const +{ + static const ImmutableString kGlTextureName("gl_texture"); + + ImmutableString suffix(TextureTypeSuffix(this->sampler)); + + ImmutableStringBuilder name(kGlTextureName.length() + suffix.length() + 4u + 6u + 5u); + + name << kGlTextureName; + + // We need to include full the sampler type in the function name to make the signature unique + // on D3D11, where samplers are passed to texture functions as indices. + name << suffix; + + if (proj) + { + name << "Proj"; + } + + if (offset) + { + name << "Offset"; + } + + switch (method) + { + case IMPLICIT: + break; + case BIAS: + break; // Extra parameter makes the signature unique + case LOD: + name << "Lod"; + break; + case LOD0: + name << "Lod0"; + break; + case LOD0BIAS: + name << "Lod0"; + break; // Extra parameter makes the signature unique + case SIZE: + name << "Size"; + break; + case FETCH: + name << "Fetch"; + break; + case GRAD: + name << "Grad"; + break; + case GATHER: + name << "Gather"; + break; + default: + UNREACHABLE(); + } + + return name; +} + +const char *TextureFunctionHLSL::TextureFunction::getReturnType() const +{ + if (method == TextureFunction::SIZE) + { + switch (sampler) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DShadow: + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + case EbtSamplerExternalOES: + case EbtSampler2DMS: + case EbtISampler2DMS: + case EbtUSampler2DMS: + return "int2"; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DMSArray: + case EbtISampler2DMSArray: + case EbtUSampler2DMSArray: + case EbtSampler2DArrayShadow: + return "int3"; + default: + UNREACHABLE(); + } + } + else // Sampling function + { + switch (sampler) + { + case EbtSampler2D: + case EbtSampler2DMS: + case EbtSampler2DMSArray: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSampler2DArray: + case EbtSamplerExternalOES: + return "float4"; + case EbtISampler2D: + case EbtISampler2DMS: + case EbtISampler2DMSArray: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + return "int4"; + case EbtUSampler2D: + case EbtUSampler2DMS: + case EbtUSampler2DMSArray: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + return "uint4"; + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + if (method == TextureFunctionHLSL::TextureFunction::GATHER) + { + return "float4"; + } + else + { + return "float"; + } + default: + UNREACHABLE(); + } + } + return ""; +} + +bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const +{ + return std::tie(sampler, coords, proj, offset, method) < + std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method); +} + +ImmutableString TextureFunctionHLSL::useTextureFunction(const ImmutableString &name, + TBasicType samplerType, + int coords, + size_t argumentCount, + bool lod0, + sh::GLenum shaderType) +{ + TextureFunction textureFunction; + textureFunction.sampler = samplerType; + textureFunction.coords = coords; + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = false; + textureFunction.offset = false; + + if (name == "texture2D" || name == "textureCube" || name == "texture") + { + textureFunction.method = TextureFunction::IMPLICIT; + } + else if (name == "texture2DProj" || name == "textureProj") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = true; + } + else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" || + name == "texture2DLodEXT" || name == "textureCubeLodEXT") + { + textureFunction.method = TextureFunction::LOD; + } + else if (name == "texture2DProjLod" || name == "textureProjLod" || + name == "texture2DProjLodEXT") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + } + else if (name == "textureSize") + { + textureFunction.method = TextureFunction::SIZE; + } + else if (name == "textureOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + } + else if (name == "textureProjOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + textureFunction.proj = true; + } + else if (name == "textureLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.offset = true; + } + else if (name == "textureProjLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + textureFunction.offset = true; + } + else if (name == "texelFetch") + { + textureFunction.method = TextureFunction::FETCH; + } + else if (name == "texelFetchOffset") + { + textureFunction.method = TextureFunction::FETCH; + textureFunction.offset = true; + } + else if (name == "textureGrad" || name == "texture2DGradEXT") + { + textureFunction.method = TextureFunction::GRAD; + } + else if (name == "textureGradOffset") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.offset = true; + } + else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || + name == "textureCubeGradEXT") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; + } + else if (name == "textureProjGradOffset") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; + textureFunction.offset = true; + } + else if (name == "textureGather") + { + textureFunction.method = TextureFunction::GATHER; + } + else if (name == "textureGatherOffset") + { + textureFunction.method = TextureFunction::GATHER; + textureFunction.offset = true; + } + else + UNREACHABLE(); + + if (textureFunction.method == + TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument + { + size_t mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments + + if (textureFunction.offset) + { + mandatoryArgumentCount++; + } + + bool bias = (argumentCount > mandatoryArgumentCount); // Bias argument is optional + + if (lod0 || shaderType == GL_VERTEX_SHADER || shaderType == GL_COMPUTE_SHADER) + { + if (bias) + { + textureFunction.method = TextureFunction::LOD0BIAS; + } + else + { + textureFunction.method = TextureFunction::LOD0; + } + } + else if (bias) + { + textureFunction.method = TextureFunction::BIAS; + } + } + + mUsesTexture.insert(textureFunction); + return textureFunction.name(); +} + +void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out, + const ShShaderOutput outputType, + bool getDimensionsIgnoresBaseLevel) +{ + for (const TextureFunction &textureFunction : mUsesTexture) + { + // Function header + out << textureFunction.getReturnType() << " " << textureFunction.name() << "("; + + OutputTextureFunctionArgumentList(out, textureFunction, outputType); + + out << ")\n" + "{\n"; + + // In some cases we use a variable to store the texture/sampler objects, but to work around + // a D3D11 compiler bug related to discard inside a loop that is conditional on texture + // sampling we need to call the function directly on references to the texture and sampler + // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture* + // tests. + ImmutableString textureReference(""); + ImmutableString samplerReference(""); + GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference); + + if (textureFunction.method == TextureFunction::SIZE) + { + OutputTextureSizeFunctionBody(out, textureFunction, textureReference, + getDimensionsIgnoresBaseLevel); + } + else + { + ImmutableString texCoordX("t.x"); + ImmutableString texCoordY("t.y"); + ImmutableString texCoordZ("t.z"); + if (textureFunction.method == TextureFunction::GATHER) + { + OutputTextureGatherFunctionBody(out, textureFunction, outputType, textureReference, + samplerReference, texCoordX, texCoordY, texCoordZ); + } + else + { + ProjectTextureCoordinates(textureFunction, &texCoordX, &texCoordY, &texCoordZ); + OutputIntegerTextureSampleFunctionComputations( + out, textureFunction, outputType, textureReference, &texCoordX, &texCoordY, + &texCoordZ, getDimensionsIgnoresBaseLevel); + OutputTextureSampleFunctionReturnStatement(out, textureFunction, outputType, + textureReference, samplerReference, + texCoordX, texCoordY, texCoordZ); + } + } + + out << "}\n" + "\n"; + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.h b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.h new file mode 100644 index 0000000000..98de98fff5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TextureFunctionHLSL.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 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. +// +// TextureFunctionHLSL: Class for writing implementations of ESSL texture functions into HLSL +// output. Some of the implementations are straightforward and just call the HLSL equivalent of the +// ESSL texture function, others do more work to emulate ESSL texture sampling or size query +// behavior. +// + +#ifndef COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_ +#define COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_ + +#include <set> + +#include "GLSLANG/ShaderLang.h" +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/InfoSink.h" + +namespace sh +{ + +class TextureFunctionHLSL final : angle::NonCopyable +{ + public: + struct TextureFunction + { + // See ESSL 3.00.6 section 8.8 for reference about what the different methods below do. + enum Method + { + IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) + BIAS, + LOD, + LOD0, + LOD0BIAS, + SIZE, // textureSize() + FETCH, + GRAD, + GATHER + }; + + ImmutableString name() const; + + bool operator<(const TextureFunction &rhs) const; + + const char *getReturnType() const; + + TBasicType sampler; + int coords; + bool proj; + bool offset; + Method method; + }; + + // Returns the name of the texture function implementation to call. + // The name that's passed in is the name of the GLSL texture function that it should implement. + ImmutableString useTextureFunction(const ImmutableString &name, + TBasicType samplerType, + int coords, + size_t argumentCount, + bool lod0, + sh::GLenum shaderType); + + void textureFunctionHeader(TInfoSinkBase &out, + const ShShaderOutput outputType, + bool getDimensionsIgnoresBaseLevel); + + private: + typedef std::set<TextureFunction> TextureFunctionSet; + TextureFunctionSet mUsesTexture; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TEXTUREFUNCTIONHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.cpp b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.cpp new file mode 100644 index 0000000000..9631a32cb6 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.cpp @@ -0,0 +1,184 @@ +// +// Copyright (c) 2002-2013 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/TranslatorESSL.h" + +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/OutputESSL.h" +#include "compiler/translator/tree_ops/EmulatePrecision.h" +#include "compiler/translator/tree_ops/RecordConstantPrecision.h" + +namespace sh +{ + +TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) + : TCompiler(type, spec, SH_ESSL_OUTPUT) +{} + +void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) +{ + if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION) + { + InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu); + } +} + +void TranslatorESSL::translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics * /*perfDiagnostics*/) +{ + TInfoSinkBase &sink = getInfoSink().obj; + + int shaderVer = getShaderVersion(); + if (shaderVer > 100) + { + sink << "#version " << shaderVer << " es\n"; + } + + // Write built-in extension behaviors. + writeExtensionBehavior(compileOptions); + + // Write pragmas after extensions because some drivers consider pragmas + // like non-preprocessor tokens. + writePragma(compileOptions); + + bool precisionEmulation = + getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision(&getSymbolTable()); + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(sink, shaderVer, SH_ESSL_OUTPUT); + } + + RecordConstantPrecision(root, &getSymbolTable()); + + // Write emulated built-in functions if needed. + if (!getBuiltInFunctionEmulator().isOutputEmpty()) + { + sink << "// BEGIN: Generated code for built-in function emulation\n\n"; + if (getShaderType() == GL_FRAGMENT_SHADER) + { + sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n" + << "#define emu_precision highp\n" + << "#else\n" + << "#define emu_precision mediump\n" + << "#endif\n\n"; + } + else + { + sink << "#define emu_precision highp\n"; + } + + getBuiltInFunctionEmulator().outputEmulatedFunctions(sink); + sink << "// END: Generated code for built-in function emulation\n\n"; + } + + // Write array bounds clamping emulation if needed. + getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + + if (getShaderType() == GL_COMPUTE_SHADER) + { + EmitWorkGroupSizeGLSL(*this, sink); + } + + if (getShaderType() == GL_GEOMETRY_SHADER_EXT) + { + WriteGeometryShaderLayoutQualifiers( + sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(), + getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices()); + } + + // Write translated shader. + TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), + &getSymbolTable(), getShaderType(), shaderVer, precisionEmulation, + compileOptions); + + root->traverse(&outputESSL); +} + +bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll() +{ + // If following the spec to the letter, we should not flatten this pragma. + // However, the spec's wording means that the pragma applies only to outputs. + // This contradicts the spirit of using the pragma, + // because if the pragma is used in a vertex shader, + // the only way to be able to link it to a fragment shader + // is to manually qualify each of fragment shader's inputs as invariant. + // Which defeats the purpose of this pragma - temporarily make all varyings + // invariant for debugging. + // Thus, we should be non-conformant to spec's letter here and flatten. + return true; +} + +void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions) +{ + TInfoSinkBase &sink = getInfoSink().obj; + const TExtensionBehavior &extBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end(); + ++iter) + { + if (iter->second != EBhUndefined) + { + const bool isMultiview = (iter->first == TExtension::OVR_multiview) || + (iter->first == TExtension::OVR_multiview2); + if (getResources().NV_shader_framebuffer_fetch && + iter->first == TExtension::EXT_shader_framebuffer_fetch) + { + sink << "#extension GL_NV_shader_framebuffer_fetch : " + << GetBehaviorString(iter->second) << "\n"; + } + else if (getResources().NV_draw_buffers && iter->first == TExtension::EXT_draw_buffers) + { + sink << "#extension GL_NV_draw_buffers : " << GetBehaviorString(iter->second) + << "\n"; + } + else if (isMultiview) + { + EmitMultiviewGLSL(*this, compileOptions, iter->second, sink); + } + else if (iter->first == TExtension::EXT_geometry_shader) + { + sink << "#ifdef GL_EXT_geometry_shader\n" + << "#extension GL_EXT_geometry_shader : " << GetBehaviorString(iter->second) + << "\n" + << "#elif defined GL_OES_geometry_shader\n" + << "#extension GL_OES_geometry_shader : " << GetBehaviorString(iter->second) + << "\n"; + if (iter->second == EBhRequire) + { + sink << "#else\n" + << "#error \"No geometry shader extensions available.\" // Only generate " + "this if the extension is \"required\"\n"; + } + sink << "#endif\n"; + } + else if (iter->first == TExtension::ANGLE_multi_draw) + { + // Don't emit anything. This extension is emulated + ASSERT((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0); + continue; + } + else if (iter->first == TExtension::ANGLE_base_vertex_base_instance) + { + // Don't emit anything. This extension is emulated + ASSERT((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0); + continue; + } + else + { + sink << "#extension " << GetExtensionNameString(iter->first) << " : " + << GetBehaviorString(iter->second) << "\n"; + } + } + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.h b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.h new file mode 100644 index 0000000000..24dc738513 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TranslatorESSL.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2002-2011 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_TRANSLATORESSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORESSL_H_ + +#include "compiler/translator/Compiler.h" + +namespace sh +{ + +class TranslatorESSL : public TCompiler +{ + public: + TranslatorESSL(sh::GLenum type, ShShaderSpec spec); + + protected: + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) override; + + void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) override; + bool shouldFlattenPragmaStdglInvariantAll() override; + + private: + void writeExtensionBehavior(ShCompileOptions compileOptions); +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TRANSLATORESSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.cpp new file mode 100644 index 0000000000..81b43b8245 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.cpp @@ -0,0 +1,334 @@ +// +// Copyright (c) 2002-2013 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/TranslatorGLSL.h" + +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/ExtensionGLSL.h" +#include "compiler/translator/OutputGLSL.h" +#include "compiler/translator/VersionGLSL.h" +#include "compiler/translator/tree_ops/EmulatePrecision.h" +#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h" +#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h" + +namespace sh +{ + +TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) + : TCompiler(type, spec, output) +{} + +void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) +{ + if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION) + { + InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType()); + } + + if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) + { + InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion()); + } + + if (compileOptions & SH_EMULATE_ATAN2_FLOAT_FUNCTION) + { + InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(emu); + } + + int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType()); + InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion); +} + +void TranslatorGLSL::translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics * /*perfDiagnostics*/) +{ + TInfoSinkBase &sink = getInfoSink().obj; + + // Write GLSL version. + writeVersion(root); + + // Write extension behaviour as needed + writeExtensionBehavior(root, compileOptions); + + // Write pragmas after extensions because some drivers consider pragmas + // like non-preprocessor tokens. + writePragma(compileOptions); + + // If flattening the global invariant pragma, write invariant declarations for built-in + // variables. It should be harmless to do this twice in the case that the shader also explicitly + // did this. However, it's important to emit invariant qualifiers only for those built-in + // variables that are actually used, to avoid affecting the behavior of the shader. + if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) != 0 && + getPragma().stdgl.invariantAll && + !sh::RemoveInvariant(getShaderType(), getShaderVersion(), getOutputType(), compileOptions)) + { + ASSERT(wereVariablesCollected()); + + switch (getShaderType()) + { + case GL_VERTEX_SHADER: + sink << "invariant gl_Position;\n"; + + // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment + // shaders if it's statically referenced. + conditionallyOutputInvariantDeclaration("gl_PointSize"); + break; + case GL_FRAGMENT_SHADER: + // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment + // shaders, so we can use simple logic to determine whether to declare these + // variables invariant. + conditionallyOutputInvariantDeclaration("gl_FragCoord"); + conditionallyOutputInvariantDeclaration("gl_PointCoord"); + break; + default: + // Currently not reached, but leave this in for future expansion. + ASSERT(false); + break; + } + } + + if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) + { + sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); + } + + if ((compileOptions & SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR) != 0) + { + sh::RewriteUnaryMinusOperatorFloat(root); + } + + bool precisionEmulation = + getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision(&getSymbolTable()); + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType()); + } + + // Write emulated built-in functions if needed. + if (!getBuiltInFunctionEmulator().isOutputEmpty()) + { + sink << "// BEGIN: Generated code for built-in function emulation\n\n"; + sink << "#define emu_precision\n\n"; + getBuiltInFunctionEmulator().outputEmulatedFunctions(sink); + sink << "// END: Generated code for built-in function emulation\n\n"; + } + + // Write array bounds clamping emulation if needed. + getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + + // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData + // if it's core profile shaders and they are used. + if (getShaderType() == GL_FRAGMENT_SHADER) + { + const bool mayHaveESSL1SecondaryOutputs = + IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) && + getShaderVersion() == 100; + const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType()); + + bool hasGLFragColor = false; + bool hasGLFragData = false; + bool hasGLSecondaryFragColor = false; + bool hasGLSecondaryFragData = false; + + for (const auto &outputVar : mOutputVariables) + { + if (declareGLFragmentOutputs) + { + if (outputVar.name == "gl_FragColor") + { + ASSERT(!hasGLFragColor); + hasGLFragColor = true; + continue; + } + else if (outputVar.name == "gl_FragData") + { + ASSERT(!hasGLFragData); + hasGLFragData = true; + continue; + } + } + if (mayHaveESSL1SecondaryOutputs) + { + if (outputVar.name == "gl_SecondaryFragColorEXT") + { + ASSERT(!hasGLSecondaryFragColor); + hasGLSecondaryFragColor = true; + continue; + } + else if (outputVar.name == "gl_SecondaryFragDataEXT") + { + ASSERT(!hasGLSecondaryFragData); + hasGLSecondaryFragData = true; + continue; + } + } + } + ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) && + (hasGLFragData || hasGLSecondaryFragData))); + if (hasGLFragColor) + { + sink << "out vec4 webgl_FragColor;\n"; + } + if (hasGLFragData) + { + sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; + } + if (hasGLSecondaryFragColor) + { + sink << "out vec4 angle_SecondaryFragColor;\n"; + } + if (hasGLSecondaryFragData) + { + sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers + << "];\n"; + } + } + + if (getShaderType() == GL_COMPUTE_SHADER) + { + EmitWorkGroupSizeGLSL(*this, sink); + } + + if (getShaderType() == GL_GEOMETRY_SHADER_EXT) + { + WriteGeometryShaderLayoutQualifiers( + sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(), + getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices()); + } + + // Write translated shader. + TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), + &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(), + compileOptions); + + root->traverse(&outputGLSL); +} + +bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll() +{ + // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't + // translate to that version, return true for the next higher version. + return IsGLSL130OrNewer(getOutputType()); +} + +bool TranslatorGLSL::shouldCollectVariables(ShCompileOptions compileOptions) +{ + return (compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) || + TCompiler::shouldCollectVariables(compileOptions); +} + +void TranslatorGLSL::writeVersion(TIntermNode *root) +{ + TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType()); + root->traverse(&versionGLSL); + int version = versionGLSL.getVersion(); + // We need to write version directive only if it is greater than 110. + // If there is no version directive in the shader, 110 is implied. + if (version > 110) + { + TInfoSinkBase &sink = getInfoSink().obj; + sink << "#version " << version << "\n"; + } +} + +void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions) +{ + TInfoSinkBase &sink = getInfoSink().obj; + const TExtensionBehavior &extBehavior = getExtensionBehavior(); + for (const auto &iter : extBehavior) + { + if (iter.second == EBhUndefined) + { + continue; + } + + if (getOutputType() == SH_GLSL_COMPATIBILITY_OUTPUT) + { + // For GLSL output, we don't need to emit most extensions explicitly, + // but some we need to translate in GL compatibility profile. + if (iter.first == TExtension::EXT_shader_texture_lod) + { + sink << "#extension GL_ARB_shader_texture_lod : " << GetBehaviorString(iter.second) + << "\n"; + } + + if (iter.first == TExtension::EXT_draw_buffers) + { + sink << "#extension GL_ARB_draw_buffers : " << GetBehaviorString(iter.second) + << "\n"; + } + + if (iter.first == TExtension::EXT_geometry_shader) + { + sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second) + << "\n"; + } + } + + const bool isMultiview = + (iter.first == TExtension::OVR_multiview) || (iter.first == TExtension::OVR_multiview2); + if (isMultiview) + { + EmitMultiviewGLSL(*this, compileOptions, iter.second, sink); + } + + // Support ANGLE_texture_multisample extension on GLSL300 + if (getShaderVersion() >= 300 && iter.first == TExtension::ANGLE_texture_multisample && + getOutputType() < SH_GLSL_330_CORE_OUTPUT) + { + sink << "#extension GL_ARB_texture_multisample : " << GetBehaviorString(iter.second) + << "\n"; + } + } + + // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330 + if (getShaderVersion() >= 300 && getOutputType() < SH_GLSL_330_CORE_OUTPUT && + getShaderType() != GL_COMPUTE_SHADER) + { + sink << "#extension GL_ARB_explicit_attrib_location : require\n"; + } + + // Need to enable gpu_shader5 to have index constant sampler array indexing + if (getOutputType() != SH_ESSL_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT && + getShaderVersion() == 100) + { + // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently + // support index constant sampler array indexing, but don't have the extension or + // on drivers that don't have the extension at all as it would break WebGL 1 for + // some users. + sink << "#extension GL_ARB_gpu_shader5 : enable\n"; + } + + TExtensionGLSL extensionGLSL(getOutputType()); + root->traverse(&extensionGLSL); + + for (const auto &ext : extensionGLSL.getEnabledExtensions()) + { + sink << "#extension " << ext << " : enable\n"; + } + for (const auto &ext : extensionGLSL.getRequiredExtensions()) + { + sink << "#extension " << ext << " : require\n"; + } +} + +void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName) +{ + if (isVaryingDefined(builtinVaryingName)) + { + TInfoSinkBase &sink = getInfoSink().obj; + sink << "invariant " << builtinVaryingName << ";\n"; + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.h b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.h new file mode 100644 index 0000000000..982d0e5ddc --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TranslatorGLSL.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2002-2010 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_TRANSLATORGLSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ + +#include "compiler/translator/Compiler.h" + +namespace sh +{ + +class TranslatorGLSL : public TCompiler +{ + public: + TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); + + protected: + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) override; + + void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) override; + bool shouldFlattenPragmaStdglInvariantAll() override; + bool shouldCollectVariables(ShCompileOptions compileOptions) override; + + private: + void writeVersion(TIntermNode *root); + void writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions); + void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName); +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp new file mode 100644 index 0000000000..c4be3b027c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.cpp @@ -0,0 +1,204 @@ +// +// Copyright (c) 2002-2013 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/TranslatorHLSL.h" + +#include "compiler/translator/OutputHLSL.h" +#include "compiler/translator/tree_ops/AddDefaultReturnStatements.h" +#include "compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h" +#include "compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h" +#include "compiler/translator/tree_ops/EmulatePrecision.h" +#include "compiler/translator/tree_ops/ExpandIntegerPowExpressions.h" +#include "compiler/translator/tree_ops/PruneEmptyCases.h" +#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h" +#include "compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h" +#include "compiler/translator/tree_ops/RewriteElseBlocks.h" +#include "compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h" +#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h" +#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h" +#include "compiler/translator/tree_ops/SeparateArrayConstructorStatements.h" +#include "compiler/translator/tree_ops/SeparateArrayInitialization.h" +#include "compiler/translator/tree_ops/SeparateDeclarations.h" +#include "compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h" +#include "compiler/translator/tree_ops/SimplifyLoopConditions.h" +#include "compiler/translator/tree_ops/SplitSequenceOperator.h" +#include "compiler/translator/tree_ops/UnfoldShortCircuitToIf.h" +#include "compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h" +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" + +namespace sh +{ + +TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) + : TCompiler(type, spec, output) +{} + +void TranslatorHLSL::translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) +{ + const ShBuiltInResources &resources = getResources(); + int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; + int maxDualSourceDrawBuffers = + resources.EXT_blend_func_extended ? resources.MaxDualSourceDrawBuffers : 0; + + sh::AddDefaultReturnStatements(root); + + // Note that SimplifyLoopConditions needs to be run before any other AST transformations that + // may need to generate new statements from loop conditions or loop expressions. + // Note that SeparateDeclarations has already been run in TCompiler::compileTreeImpl(). + SimplifyLoopConditions(root, + IntermNodePatternMatcher::kExpressionReturningArray | + IntermNodePatternMatcher::kUnfoldedShortCircuitExpression | + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue, + &getSymbolTable()); + + SplitSequenceOperator(root, + IntermNodePatternMatcher::kExpressionReturningArray | + IntermNodePatternMatcher::kUnfoldedShortCircuitExpression | + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue, + &getSymbolTable()); + + // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf. + UnfoldShortCircuitToIf(root, &getSymbolTable()); + + SeparateArrayConstructorStatements(root); + + SeparateExpressionsReturningArrays(root, &getSymbolTable()); + + // Note that SeparateDeclarations needs to be run before SeparateArrayInitialization. + SeparateArrayInitialization(root); + + // HLSL doesn't support arrays as return values, we'll need to make functions that have an array + // as a return value to use an out parameter to transfer the array data instead. + ArrayReturnValueToOutParameter(root, &getSymbolTable()); + + if (!shouldRunLoopAndIndexingValidation(compileOptions)) + { + // HLSL doesn't support dynamic indexing of vectors and matrices. + RemoveDynamicIndexing(root, &getSymbolTable(), perfDiagnostics); + } + + // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which + // use a vertex attribute as a condition, and some related computation in the else block. + if (getOutputType() == SH_HLSL_3_0_OUTPUT && getShaderType() == GL_VERTEX_SHADER) + { + sh::RewriteElseBlocks(root, &getSymbolTable()); + } + + // Work around an HLSL compiler frontend aliasing optimization bug. + // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed + // in the next release of d3dcompiler.dll, it would be nice to detect the DLL + // version and only apply the workaround if it is too old. + sh::BreakVariableAliasingInInnerLoops(root); + + // WrapSwitchStatementsInBlocks should be called after any AST transformations that might + // introduce variable declarations inside the main scope of any switch statement. It cannot + // result in no-op cases at the end of switch statements, because unreferenced variables + // have already been pruned. + WrapSwitchStatementsInBlocks(root); + + bool precisionEmulation = + getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision(&getSymbolTable()); + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(getInfoSink().obj, getShaderVersion(), + getOutputType()); + } + + if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0) + { + sh::ExpandIntegerPowExpressions(root, &getSymbolTable()); + } + + if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) + { + sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); + } + + if (((compileOptions & SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR) != 0) && + getShaderType() == GL_VERTEX_SHADER) + { + sh::RewriteUnaryMinusOperatorInt(root); + } + + if (getShaderVersion() >= 310) + { + // Due to ssbo also can be used as the argument of atomic memory functions, we should put + // RewriteExpressionsWithShaderStorageBlock before RewriteAtomicFunctionExpressions. + sh::RewriteExpressionsWithShaderStorageBlock(root, &getSymbolTable()); + sh::RewriteAtomicFunctionExpressions(root, &getSymbolTable(), getShaderVersion()); + } + + sh::OutputHLSL outputHLSL( + getShaderType(), getShaderVersion(), getExtensionBehavior(), getSourcePath(), + getOutputType(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(), compileOptions, + getComputeShaderLocalSize(), &getSymbolTable(), perfDiagnostics, mShaderStorageBlocks); + + outputHLSL.output(root, getInfoSink().obj); + + mShaderStorageBlockRegisterMap = outputHLSL.getShaderStorageBlockRegisterMap(); + mUniformBlockRegisterMap = outputHLSL.getUniformBlockRegisterMap(); + mUniformRegisterMap = outputHLSL.getUniformRegisterMap(); + mReadonlyImage2DRegisterIndex = outputHLSL.getReadonlyImage2DRegisterIndex(); + mImage2DRegisterIndex = outputHLSL.getImage2DRegisterIndex(); + mUsedImage2DFunctionNames = outputHLSL.getUsedImage2DFunctionNames(); +} + +bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll() +{ + // Not necessary when translating to HLSL. + return false; +} + +bool TranslatorHLSL::hasShaderStorageBlock(const std::string &uniformBlockName) const +{ + return (mShaderStorageBlockRegisterMap.count(uniformBlockName) > 0); +} + +unsigned int TranslatorHLSL::getShaderStorageBlockRegister( + const std::string &shaderStorageBlockName) const +{ + ASSERT(hasShaderStorageBlock(shaderStorageBlockName)); + return mShaderStorageBlockRegisterMap.find(shaderStorageBlockName)->second; +} + +bool TranslatorHLSL::hasUniformBlock(const std::string &uniformBlockName) const +{ + return (mUniformBlockRegisterMap.count(uniformBlockName) > 0); +} + +unsigned int TranslatorHLSL::getUniformBlockRegister(const std::string &uniformBlockName) const +{ + ASSERT(hasUniformBlock(uniformBlockName)); + return mUniformBlockRegisterMap.find(uniformBlockName)->second; +} + +const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const +{ + return &mUniformRegisterMap; +} + +unsigned int TranslatorHLSL::getReadonlyImage2DRegisterIndex() const +{ + return mReadonlyImage2DRegisterIndex; +} + +unsigned int TranslatorHLSL::getImage2DRegisterIndex() const +{ + return mImage2DRegisterIndex; +} + +const std::set<std::string> *TranslatorHLSL::getUsedImage2DFunctionNames() const +{ + return &mUsedImage2DFunctionNames; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.h b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.h new file mode 100644 index 0000000000..bb8b7f2855 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/TranslatorHLSL.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2002-2013 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_TRANSLATORHLSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ + +#include "compiler/translator/Compiler.h" + +namespace sh +{ + +class TranslatorHLSL : public TCompiler +{ + public: + TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); + TranslatorHLSL *getAsTranslatorHLSL() override { return this; } + + bool hasShaderStorageBlock(const std::string &interfaceBlockName) const; + unsigned int getShaderStorageBlockRegister(const std::string &interfaceBlockName) const; + + bool hasUniformBlock(const std::string &interfaceBlockName) const; + unsigned int getUniformBlockRegister(const std::string &interfaceBlockName) const; + + const std::map<std::string, unsigned int> *getUniformRegisterMap() const; + unsigned int getReadonlyImage2DRegisterIndex() const; + unsigned int getImage2DRegisterIndex() const; + const std::set<std::string> *getUsedImage2DFunctionNames() const; + + protected: + void translate(TIntermBlock *root, + ShCompileOptions compileOptions, + PerformanceDiagnostics *perfDiagnostics) override; + bool shouldFlattenPragmaStdglInvariantAll() override; + + // collectVariables needs to be run always so registers can be assigned. + bool shouldCollectVariables(ShCompileOptions compileOptions) override { return true; } + + std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap; + std::map<std::string, unsigned int> mUniformBlockRegisterMap; + std::map<std::string, unsigned int> mUniformRegisterMap; + unsigned int mReadonlyImage2DRegisterIndex; + unsigned int mImage2DRegisterIndex; + std::set<std::string> mUsedImage2DFunctionNames; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/Types.cpp b/gfx/angle/checkout/src/compiler/translator/Types.cpp new file mode 100644 index 0000000000..9d0374b170 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Types.cpp @@ -0,0 +1,970 @@ +// +// Copyright (c) 2002-2014 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. +// + +#if defined(_MSC_VER) +# pragma warning(disable : 4718) +#endif + +#include "compiler/translator/Types.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" + +#include <algorithm> +#include <climits> + +namespace sh +{ + +const char *getBasicString(TBasicType t) +{ + switch (t) + { + case EbtVoid: + return "void"; + case EbtFloat: + return "float"; + case EbtInt: + return "int"; + case EbtUInt: + return "uint"; + case EbtBool: + return "bool"; + case EbtYuvCscStandardEXT: + return "yuvCscStandardEXT"; + case EbtSampler2D: + return "sampler2D"; + case EbtSampler3D: + return "sampler3D"; + case EbtSamplerCube: + return "samplerCube"; + case EbtSamplerExternalOES: + return "samplerExternalOES"; + case EbtSamplerExternal2DY2YEXT: + return "__samplerExternal2DY2YEXT"; + case EbtSampler2DRect: + return "sampler2DRect"; + case EbtSampler2DArray: + return "sampler2DArray"; + case EbtSampler2DMS: + return "sampler2DMS"; + case EbtSampler2DMSArray: + return "sampler2DMSArray"; + case EbtISampler2D: + return "isampler2D"; + case EbtISampler3D: + return "isampler3D"; + case EbtISamplerCube: + return "isamplerCube"; + case EbtISampler2DArray: + return "isampler2DArray"; + case EbtISampler2DMS: + return "isampler2DMS"; + case EbtISampler2DMSArray: + return "isampler2DMSArray"; + case EbtUSampler2D: + return "usampler2D"; + case EbtUSampler3D: + return "usampler3D"; + case EbtUSamplerCube: + return "usamplerCube"; + case EbtUSampler2DArray: + return "usampler2DArray"; + case EbtUSampler2DMS: + return "usampler2DMS"; + case EbtUSampler2DMSArray: + return "usampler2DMSArray"; + case EbtSampler2DShadow: + return "sampler2DShadow"; + case EbtSamplerCubeShadow: + return "samplerCubeShadow"; + case EbtSampler2DArrayShadow: + return "sampler2DArrayShadow"; + case EbtStruct: + return "structure"; + case EbtInterfaceBlock: + return "interface block"; + case EbtImage2D: + return "image2D"; + case EbtIImage2D: + return "iimage2D"; + case EbtUImage2D: + return "uimage2D"; + case EbtImage3D: + return "image3D"; + case EbtIImage3D: + return "iimage3D"; + case EbtUImage3D: + return "uimage3D"; + case EbtImage2DArray: + return "image2DArray"; + case EbtIImage2DArray: + return "iimage2DArray"; + case EbtUImage2DArray: + return "uimage2DArray"; + case EbtImageCube: + return "imageCube"; + case EbtIImageCube: + return "iimageCube"; + case EbtUImageCube: + return "uimageCube"; + case EbtAtomicCounter: + return "atomic_uint"; + default: + UNREACHABLE(); + return "unknown type"; + } +} + +// TType implementation. +TType::TType() + : type(EbtVoid), + precision(EbpUndefined), + qualifier(EvqGlobal), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(0), + secondarySize(0), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) +{} + +TType::TType(TBasicType t, unsigned char ps, unsigned char ss) + : type(t), + precision(EbpUndefined), + qualifier(EvqGlobal), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(ps), + secondarySize(ss), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) +{} + +TType::TType(TBasicType t, TPrecision p, TQualifier q, unsigned char ps, unsigned char ss) + : type(t), + precision(p), + qualifier(q), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(ps), + secondarySize(ss), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) +{} + +TType::TType(const TPublicType &p) + : type(p.getBasicType()), + precision(p.precision), + qualifier(p.qualifier), + invariant(p.invariant), + memoryQualifier(p.memoryQualifier), + layoutQualifier(p.layoutQualifier), + primarySize(p.getPrimarySize()), + secondarySize(p.getSecondarySize()), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(nullptr) +{ + ASSERT(primarySize <= 4); + ASSERT(secondarySize <= 4); + if (p.isArray()) + { + mArraySizes = new TVector<unsigned int>(*p.arraySizes); + } + if (p.getUserDef()) + { + mStructure = p.getUserDef(); + mIsStructSpecifier = p.isStructSpecifier(); + } +} + +TType::TType(const TStructure *userDef, bool isStructSpecifier) + : type(EbtStruct), + precision(EbpUndefined), + qualifier(EvqTemporary), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(1), + secondarySize(1), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(userDef), + mIsStructSpecifier(isStructSpecifier), + mMangledName(nullptr) +{} + +TType::TType(const TInterfaceBlock *interfaceBlockIn, + TQualifier qualifierIn, + TLayoutQualifier layoutQualifierIn) + : type(EbtInterfaceBlock), + precision(EbpUndefined), + qualifier(qualifierIn), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(layoutQualifierIn), + primarySize(1), + secondarySize(1), + mArraySizes(nullptr), + mInterfaceBlock(interfaceBlockIn), + mStructure(0), + mIsStructSpecifier(false), + mMangledName(nullptr) +{} + +TType::TType(const TType &t) + : type(t.type), + precision(t.precision), + qualifier(t.qualifier), + invariant(t.invariant), + memoryQualifier(t.memoryQualifier), + layoutQualifier(t.layoutQualifier), + primarySize(t.primarySize), + secondarySize(t.secondarySize), + mArraySizes(t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr), + mInterfaceBlock(t.mInterfaceBlock), + mStructure(t.mStructure), + mIsStructSpecifier(t.mIsStructSpecifier), + mMangledName(t.mMangledName) +{} + +TType &TType::operator=(const TType &t) +{ + type = t.type; + precision = t.precision; + qualifier = t.qualifier; + invariant = t.invariant; + memoryQualifier = t.memoryQualifier; + layoutQualifier = t.layoutQualifier; + primarySize = t.primarySize; + secondarySize = t.secondarySize; + mArraySizes = t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr; + mInterfaceBlock = t.mInterfaceBlock; + mStructure = t.mStructure; + mIsStructSpecifier = t.mIsStructSpecifier; + mMangledName = t.mMangledName; + return *this; +} + +bool TType::canBeConstructed() const +{ + switch (type) + { + case EbtFloat: + case EbtInt: + case EbtUInt: + case EbtBool: + case EbtStruct: + return true; + default: + return false; + } +} + +const char *TType::getBuiltInTypeNameString() const +{ + if (isMatrix()) + { + switch (getCols()) + { + case 2: + switch (getRows()) + { + case 2: + return "mat2"; + case 3: + return "mat2x3"; + case 4: + return "mat2x4"; + default: + UNREACHABLE(); + return nullptr; + } + case 3: + switch (getRows()) + { + case 2: + return "mat3x2"; + case 3: + return "mat3"; + case 4: + return "mat3x4"; + default: + UNREACHABLE(); + return nullptr; + } + case 4: + switch (getRows()) + { + case 2: + return "mat4x2"; + case 3: + return "mat4x3"; + case 4: + return "mat4"; + default: + UNREACHABLE(); + return nullptr; + } + default: + UNREACHABLE(); + return nullptr; + } + } + if (isVector()) + { + switch (getBasicType()) + { + case EbtFloat: + switch (getNominalSize()) + { + case 2: + return "vec2"; + case 3: + return "vec3"; + case 4: + return "vec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtInt: + switch (getNominalSize()) + { + case 2: + return "ivec2"; + case 3: + return "ivec3"; + case 4: + return "ivec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtBool: + switch (getNominalSize()) + { + case 2: + return "bvec2"; + case 3: + return "bvec3"; + case 4: + return "bvec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtUInt: + switch (getNominalSize()) + { + case 2: + return "uvec2"; + case 3: + return "uvec3"; + case 4: + return "uvec4"; + default: + UNREACHABLE(); + return nullptr; + } + default: + UNREACHABLE(); + return nullptr; + } + } + ASSERT(getBasicType() != EbtStruct); + ASSERT(getBasicType() != EbtInterfaceBlock); + return getBasicString(); +} + +int TType::getDeepestStructNesting() const +{ + return mStructure ? mStructure->deepestNesting() : 0; +} + +bool TType::isNamelessStruct() const +{ + return mStructure && mStructure->symbolType() == SymbolType::Empty; +} + +bool TType::isStructureContainingArrays() const +{ + return mStructure ? mStructure->containsArrays() : false; +} + +bool TType::isStructureContainingMatrices() const +{ + return mStructure ? mStructure->containsMatrices() : false; +} + +bool TType::isStructureContainingType(TBasicType t) const +{ + return mStructure ? mStructure->containsType(t) : false; +} + +bool TType::isStructureContainingSamplers() const +{ + return mStructure ? mStructure->containsSamplers() : false; +} + +bool TType::canReplaceWithConstantUnion() const +{ + if (isArray()) + { + return false; + } + if (!mStructure) + { + return true; + } + if (isStructureContainingArrays()) + { + return false; + } + if (getObjectSize() > 16) + { + return false; + } + return true; +} + +// +// Recursively generate mangled names. +// +const char *TType::buildMangledName() const +{ + TString mangledName(1, GetSizeMangledName(primarySize, secondarySize)); + + char basicMangledName = GetBasicMangledName(type); + if (basicMangledName != '{') + { + mangledName += basicMangledName; + } + else + { + ASSERT(type == EbtStruct || type == EbtInterfaceBlock); + switch (type) + { + case EbtStruct: + mangledName += "{s"; + if (mStructure->symbolType() != SymbolType::Empty) + { + mangledName += mStructure->name().data(); + } + mangledName += mStructure->mangledFieldList(); + mangledName += '}'; + break; + case EbtInterfaceBlock: + mangledName += "{i"; + mangledName += mInterfaceBlock->name().data(); + mangledName += mInterfaceBlock->mangledFieldList(); + mangledName += '}'; + break; + default: + UNREACHABLE(); + break; + } + } + + if (mArraySizes) + { + for (unsigned int arraySize : *mArraySizes) + { + char buf[20]; + snprintf(buf, sizeof(buf), "%d", arraySize); + mangledName += '['; + mangledName += buf; + mangledName += ']'; + } + } + + // Copy string contents into a pool-allocated buffer, so we never need to call delete. + return AllocatePoolCharArray(mangledName.c_str(), mangledName.size()); +} + +size_t TType::getObjectSize() const +{ + size_t totalSize; + + if (getBasicType() == EbtStruct) + totalSize = mStructure->objectSize(); + else + totalSize = primarySize * secondarySize; + + if (totalSize == 0) + return 0; + + if (mArraySizes) + { + for (size_t arraySize : *mArraySizes) + { + if (arraySize > INT_MAX / totalSize) + totalSize = INT_MAX; + else + totalSize *= arraySize; + } + } + + return totalSize; +} + +int TType::getLocationCount() const +{ + int count = 1; + + if (getBasicType() == EbtStruct) + { + count = mStructure->getLocationCount(); + } + + if (count == 0) + { + return 0; + } + + if (mArraySizes) + { + for (unsigned int arraySize : *mArraySizes) + { + if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count)) + { + count = std::numeric_limits<int>::max(); + } + else + { + count *= static_cast<int>(arraySize); + } + } + } + + return count; +} + +unsigned int TType::getArraySizeProduct() const +{ + if (!mArraySizes) + return 1u; + + unsigned int product = 1u; + + for (unsigned int arraySize : *mArraySizes) + { + product *= arraySize; + } + return product; +} + +bool TType::isUnsizedArray() const +{ + if (!mArraySizes) + return false; + + for (unsigned int arraySize : *mArraySizes) + { + if (arraySize == 0u) + { + return true; + } + } + return false; +} + +bool TType::sameNonArrayType(const TType &right) const +{ + return (type == right.type && primarySize == right.primarySize && + secondarySize == right.secondarySize && mStructure == right.mStructure); +} + +bool TType::isElementTypeOf(const TType &arrayType) const +{ + if (!sameNonArrayType(arrayType)) + { + return false; + } + if (arrayType.getNumArraySizes() != getNumArraySizes() + 1u) + { + return false; + } + if (isArray()) + { + for (size_t i = 0; i < mArraySizes->size(); ++i) + { + if ((*mArraySizes)[i] != (*arrayType.mArraySizes)[i]) + { + return false; + } + } + } + return true; +} + +void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes) +{ + size_t newArraySizesSize = newArraySizes ? newArraySizes->size() : 0; + for (size_t i = 0u; i < getNumArraySizes(); ++i) + { + if ((*mArraySizes)[i] == 0) + { + if (i < newArraySizesSize) + { + ASSERT(newArraySizes != nullptr); + (*mArraySizes)[i] = (*newArraySizes)[i]; + } + else + { + (*mArraySizes)[i] = 1u; + } + } + } + invalidateMangledName(); +} + +void TType::sizeOutermostUnsizedArray(unsigned int arraySize) +{ + ASSERT(isArray()); + ASSERT(mArraySizes->back() == 0u); + mArraySizes->back() = arraySize; +} + +void TType::setBasicType(TBasicType t) +{ + if (type != t) + { + type = t; + invalidateMangledName(); + } +} + +void TType::setPrimarySize(unsigned char ps) +{ + if (primarySize != ps) + { + ASSERT(ps <= 4); + primarySize = ps; + invalidateMangledName(); + } +} + +void TType::setSecondarySize(unsigned char ss) +{ + if (secondarySize != ss) + { + ASSERT(ss <= 4); + secondarySize = ss; + invalidateMangledName(); + } +} + +void TType::makeArray(unsigned int s) +{ + if (!mArraySizes) + mArraySizes = new TVector<unsigned int>(); + + mArraySizes->push_back(s); + invalidateMangledName(); +} + +void TType::makeArrays(const TVector<unsigned int> &sizes) +{ + if (!mArraySizes) + mArraySizes = new TVector<unsigned int>(); + + mArraySizes->insert(mArraySizes->end(), sizes.begin(), sizes.end()); + invalidateMangledName(); +} + +void TType::setArraySize(size_t arrayDimension, unsigned int s) +{ + ASSERT(mArraySizes != nullptr); + ASSERT(arrayDimension < mArraySizes->size()); + if (mArraySizes->at(arrayDimension) != s) + { + (*mArraySizes)[arrayDimension] = s; + invalidateMangledName(); + } +} + +void TType::toArrayElementType() +{ + ASSERT(mArraySizes != nullptr); + if (mArraySizes->size() > 0) + { + mArraySizes->pop_back(); + invalidateMangledName(); + } +} + +void TType::setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn) +{ + if (mInterfaceBlock != interfaceBlockIn) + { + mInterfaceBlock = interfaceBlockIn; + invalidateMangledName(); + } +} + +const char *TType::getMangledName() const +{ + if (mMangledName == nullptr) + { + mMangledName = buildMangledName(); + } + + return mMangledName; +} + +void TType::realize() +{ + getMangledName(); +} + +void TType::invalidateMangledName() +{ + mMangledName = nullptr; +} + +void TType::createSamplerSymbols(const ImmutableString &namePrefix, + const TString &apiNamePrefix, + TVector<const TVariable *> *outputSymbols, + TMap<const TVariable *, TString> *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const +{ + if (isStructureContainingSamplers()) + { + if (isArray()) + { + TType elementType(*this); + elementType.toArrayElementType(); + for (unsigned int arrayIndex = 0u; arrayIndex < getOutermostArraySize(); ++arrayIndex) + { + std::stringstream elementName = sh::InitializeStream<std::stringstream>(); + elementName << namePrefix << "_" << arrayIndex; + TStringStream elementApiName; + elementApiName << apiNamePrefix << "[" << arrayIndex << "]"; + elementType.createSamplerSymbols(ImmutableString(elementName.str()), + elementApiName.str(), outputSymbols, + outputSymbolsToAPINames, symbolTable); + } + } + else + { + mStructure->createSamplerSymbols(namePrefix.data(), apiNamePrefix, outputSymbols, + outputSymbolsToAPINames, symbolTable); + } + return; + } + + ASSERT(IsSampler(type)); + TVariable *variable = + new TVariable(symbolTable, namePrefix, new TType(*this), SymbolType::AngleInternal); + outputSymbols->push_back(variable); + if (outputSymbolsToAPINames) + { + (*outputSymbolsToAPINames)[variable] = apiNamePrefix; + } +} + +TFieldListCollection::TFieldListCollection(const TFieldList *fields) + : mFields(fields), mObjectSize(0), mDeepestNesting(0) +{} + +bool TFieldListCollection::containsArrays() const +{ + for (const auto *field : *mFields) + { + const TType *fieldType = field->type(); + if (fieldType->isArray() || fieldType->isStructureContainingArrays()) + return true; + } + return false; +} + +bool TFieldListCollection::containsMatrices() const +{ + for (const auto *field : *mFields) + { + const TType *fieldType = field->type(); + if (fieldType->isMatrix() || fieldType->isStructureContainingMatrices()) + return true; + } + return false; +} + +bool TFieldListCollection::containsType(TBasicType type) const +{ + for (const auto *field : *mFields) + { + const TType *fieldType = field->type(); + if (fieldType->getBasicType() == type || fieldType->isStructureContainingType(type)) + return true; + } + return false; +} + +bool TFieldListCollection::containsSamplers() const +{ + for (const auto *field : *mFields) + { + const TType *fieldType = field->type(); + if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers()) + return true; + } + return false; +} + +TString TFieldListCollection::buildMangledFieldList() const +{ + TString mangledName; + for (const auto *field : *mFields) + { + mangledName += field->type()->getMangledName(); + } + return mangledName; +} + +size_t TFieldListCollection::calculateObjectSize() const +{ + size_t size = 0; + for (const TField *field : *mFields) + { + size_t fieldSize = field->type()->getObjectSize(); + if (fieldSize > INT_MAX - size) + size = INT_MAX; + else + size += fieldSize; + } + return size; +} + +size_t TFieldListCollection::objectSize() const +{ + if (mObjectSize == 0) + mObjectSize = calculateObjectSize(); + return mObjectSize; +} + +int TFieldListCollection::getLocationCount() const +{ + int count = 0; + for (const TField *field : *mFields) + { + int fieldCount = field->type()->getLocationCount(); + if (fieldCount > std::numeric_limits<int>::max() - count) + { + count = std::numeric_limits<int>::max(); + } + else + { + count += fieldCount; + } + } + return count; +} + +int TFieldListCollection::deepestNesting() const +{ + if (mDeepestNesting == 0) + mDeepestNesting = calculateDeepestNesting(); + return mDeepestNesting; +} + +const TString &TFieldListCollection::mangledFieldList() const +{ + if (mMangledFieldList.empty()) + mMangledFieldList = buildMangledFieldList(); + return mMangledFieldList; +} + +int TFieldListCollection::calculateDeepestNesting() const +{ + int maxNesting = 0; + for (size_t i = 0; i < mFields->size(); ++i) + maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting()); + return 1 + maxNesting; +} + +// TPublicType implementation. +void TPublicType::initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q) +{ + typeSpecifierNonArray = typeSpecifier; + layoutQualifier = TLayoutQualifier::Create(); + memoryQualifier = TMemoryQualifier::Create(); + qualifier = q; + invariant = false; + precision = EbpUndefined; + arraySizes = nullptr; +} + +void TPublicType::initializeBasicType(TBasicType basicType) +{ + typeSpecifierNonArray.type = basicType; + typeSpecifierNonArray.primarySize = 1; + typeSpecifierNonArray.secondarySize = 1; + layoutQualifier = TLayoutQualifier::Create(); + memoryQualifier = TMemoryQualifier::Create(); + qualifier = EvqTemporary; + invariant = false; + precision = EbpUndefined; + arraySizes = nullptr; +} + +bool TPublicType::isStructureContainingArrays() const +{ + if (!typeSpecifierNonArray.userDef) + { + return false; + } + + return typeSpecifierNonArray.userDef->containsArrays(); +} + +bool TPublicType::isStructureContainingType(TBasicType t) const +{ + if (!typeSpecifierNonArray.userDef) + { + return false; + } + + return typeSpecifierNonArray.userDef->containsType(t); +} + +void TPublicType::setArraySizes(TVector<unsigned int> *sizes) +{ + arraySizes = sizes; +} + +bool TPublicType::isArray() const +{ + return arraySizes && !arraySizes->empty(); +} + +void TPublicType::clearArrayness() +{ + arraySizes = nullptr; +} + +bool TPublicType::isAggregate() const +{ + return isArray() || typeSpecifierNonArray.isMatrix() || typeSpecifierNonArray.isVector(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/Types.h b/gfx/angle/checkout/src/compiler/translator/Types.h new file mode 100644 index 0000000000..2a78d1e114 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/Types.h @@ -0,0 +1,464 @@ +// +// Copyright (c) 2002-2013 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_TYPES_H_ +#define COMPILER_TRANSLATOR_TYPES_H_ + +#include "common/angleutils.h" +#include "common/debug.h" + +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/SymbolUniqueId.h" + +namespace sh +{ + +struct TPublicType; +class TType; +class TInterfaceBlock; +class TStructure; +class TSymbol; +class TVariable; +class TIntermSymbol; +class TSymbolTable; + +class TField : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TField(TType *type, const ImmutableString &name, const TSourceLoc &line, SymbolType symbolType) + : mType(type), mName(name), mLine(line), mSymbolType(symbolType) + { + ASSERT(mSymbolType != SymbolType::Empty); + } + + // TODO(alokp): We should only return const type. + // Fix it by tweaking grammar. + TType *type() { return mType; } + const TType *type() const { return mType; } + const ImmutableString &name() const { return mName; } + const TSourceLoc &line() const { return mLine; } + SymbolType symbolType() const { return mSymbolType; } + + private: + TType *mType; + const ImmutableString mName; + const TSourceLoc mLine; + const SymbolType mSymbolType; +}; + +typedef TVector<TField *> TFieldList; + +class TFieldListCollection : angle::NonCopyable +{ + public: + const TFieldList &fields() const { return *mFields; } + + bool containsArrays() const; + bool containsMatrices() const; + bool containsType(TBasicType t) const; + bool containsSamplers() const; + + size_t objectSize() const; + // How many locations the field list consumes as a uniform. + int getLocationCount() const; + int deepestNesting() const; + const TString &mangledFieldList() const; + + protected: + TFieldListCollection(const TFieldList *fields); + + const TFieldList *mFields; + + private: + size_t calculateObjectSize() const; + int calculateDeepestNesting() const; + TString buildMangledFieldList() const; + + mutable size_t mObjectSize; + mutable int mDeepestNesting; + mutable TString mMangledFieldList; +}; + +// +// Base class for things that have a type. +// +class TType +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TType(); + explicit TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1); + TType(TBasicType t, + TPrecision p, + TQualifier q = EvqTemporary, + unsigned char ps = 1, + unsigned char ss = 1); + explicit TType(const TPublicType &p); + TType(const TStructure *userDef, bool isStructSpecifier); + TType(const TInterfaceBlock *interfaceBlockIn, + TQualifier qualifierIn, + TLayoutQualifier layoutQualifierIn); + TType(const TType &t); + TType &operator=(const TType &t); + + constexpr TType(TBasicType t, + TPrecision p, + TQualifier q, + unsigned char ps, + unsigned char ss, + const char *mangledName) + : type(t), + precision(p), + qualifier(q), + invariant(false), + memoryQualifier(TMemoryQualifier::Create()), + layoutQualifier(TLayoutQualifier::Create()), + primarySize(ps), + secondarySize(ss), + mArraySizes(nullptr), + mInterfaceBlock(nullptr), + mStructure(nullptr), + mIsStructSpecifier(false), + mMangledName(mangledName) + {} + + constexpr TType(TType &&t) + : type(t.type), + precision(t.precision), + qualifier(t.qualifier), + invariant(t.invariant), + memoryQualifier(t.memoryQualifier), + layoutQualifier(t.layoutQualifier), + primarySize(t.primarySize), + secondarySize(t.secondarySize), + mArraySizes(t.mArraySizes), + mInterfaceBlock(t.mInterfaceBlock), + mStructure(t.mStructure), + mIsStructSpecifier(t.mIsStructSpecifier), + mMangledName(t.mMangledName) + {} + + constexpr TBasicType getBasicType() const { return type; } + void setBasicType(TBasicType t); + + TPrecision getPrecision() const { return precision; } + void setPrecision(TPrecision p) { precision = p; } + + constexpr TQualifier getQualifier() const { return qualifier; } + void setQualifier(TQualifier q) { qualifier = q; } + + bool isInvariant() const { return invariant; } + + void setInvariant(bool i) { invariant = i; } + + TMemoryQualifier getMemoryQualifier() const { return memoryQualifier; } + void setMemoryQualifier(const TMemoryQualifier &mq) { memoryQualifier = mq; } + + TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; } + void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; } + + int getNominalSize() const { return primarySize; } + int getSecondarySize() const { return secondarySize; } + int getCols() const + { + ASSERT(isMatrix()); + return primarySize; + } + int getRows() const + { + ASSERT(isMatrix()); + return secondarySize; + } + void setPrimarySize(unsigned char ps); + void setSecondarySize(unsigned char ss); + + // Full size of single instance of type + size_t getObjectSize() const; + + // Get how many locations this type consumes as a uniform. + int getLocationCount() const; + + bool isMatrix() const { return primarySize > 1 && secondarySize > 1; } + bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; } + bool isArray() const { return mArraySizes != nullptr && !mArraySizes->empty(); } + bool isArrayOfArrays() const { return isArray() && mArraySizes->size() > 1u; } + size_t getNumArraySizes() const { return isArray() ? mArraySizes->size() : 0; } + const TVector<unsigned int> *getArraySizes() const { return mArraySizes; } + unsigned int getArraySizeProduct() const; + bool isUnsizedArray() const; + unsigned int getOutermostArraySize() const + { + ASSERT(isArray()); + return mArraySizes->back(); + } + void makeArray(unsigned int s); + + // sizes contain new outermost array sizes. + void makeArrays(const TVector<unsigned int> &sizes); + // Here, the array dimension value 0 corresponds to the innermost array. + void setArraySize(size_t arrayDimension, unsigned int s); + + // Will set unsized array sizes according to newArraySizes. In case there are more + // unsized arrays than there are sizes in newArraySizes, defaults to setting any + // remaining array sizes to 1. + void sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes); + + // Will size the outermost array according to arraySize. + void sizeOutermostUnsizedArray(unsigned int arraySize); + + // Note that the array element type might still be an array type in GLSL ES version >= 3.10. + void toArrayElementType(); + + const TInterfaceBlock *getInterfaceBlock() const { return mInterfaceBlock; } + void setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn); + bool isInterfaceBlock() const { return type == EbtInterfaceBlock; } + + bool isVector() const { return primarySize > 1 && secondarySize == 1; } + bool isScalar() const + { + return primarySize == 1 && secondarySize == 1 && !mStructure && !isArray(); + } + bool isScalarFloat() const { return isScalar() && type == EbtFloat; } + bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); } + + bool canBeConstructed() const; + + const TStructure *getStruct() const { return mStructure; } + + static constexpr char GetSizeMangledName(unsigned char primarySize, unsigned char secondarySize) + { + unsigned int sizeKey = (secondarySize - 1u) * 4u + primarySize - 1u; + if (sizeKey < 10u) + { + return static_cast<char>('0' + sizeKey); + } + return static_cast<char>('A' + sizeKey - 10); + } + const char *getMangledName() const; + + bool sameNonArrayType(const TType &right) const; + + // Returns true if arrayType is an array made of this type. + bool isElementTypeOf(const TType &arrayType) const; + + bool operator==(const TType &right) const + { + size_t numArraySizesL = getNumArraySizes(); + size_t numArraySizesR = right.getNumArraySizes(); + bool arraySizesEqual = numArraySizesL == numArraySizesR && + (numArraySizesL == 0 || *mArraySizes == *right.mArraySizes); + return type == right.type && primarySize == right.primarySize && + secondarySize == right.secondarySize && arraySizesEqual && + mStructure == right.mStructure; + // don't check the qualifier, it's not ever what's being sought after + } + bool operator!=(const TType &right) const { return !operator==(right); } + bool operator<(const TType &right) const + { + if (type != right.type) + return type < right.type; + if (primarySize != right.primarySize) + return primarySize < right.primarySize; + if (secondarySize != right.secondarySize) + return secondarySize < right.secondarySize; + size_t numArraySizesL = getNumArraySizes(); + size_t numArraySizesR = right.getNumArraySizes(); + if (numArraySizesL != numArraySizesR) + return numArraySizesL < numArraySizesR; + for (size_t i = 0; i < numArraySizesL; ++i) + { + if ((*mArraySizes)[i] != (*right.mArraySizes)[i]) + return (*mArraySizes)[i] < (*right.mArraySizes)[i]; + } + if (mStructure != right.mStructure) + return mStructure < right.mStructure; + + return false; + } + + const char *getBasicString() const { return sh::getBasicString(type); } + + const char *getPrecisionString() const { return sh::getPrecisionString(precision); } + const char *getQualifierString() const { return sh::getQualifierString(qualifier); } + + const char *getBuiltInTypeNameString() const; + + // If this type is a struct, returns the deepest struct nesting of + // any field in the struct. For example: + // struct nesting1 { + // vec4 position; + // }; + // struct nesting2 { + // nesting1 field1; + // vec4 field2; + // }; + // For type "nesting2", this method would return 2 -- the number + // of structures through which indirection must occur to reach the + // deepest field (nesting2.field1.position). + int getDeepestStructNesting() const; + + bool isNamelessStruct() const; + + bool isStructureContainingArrays() const; + bool isStructureContainingMatrices() const; + bool isStructureContainingType(TBasicType t) const; + bool isStructureContainingSamplers() const; + + bool isStructSpecifier() const { return mIsStructSpecifier; } + + // Return true if variables of this type should be replaced with an inline constant value if + // such is available. False will be returned in cases where output doesn't support + // TIntermConstantUnion nodes of the type, or if the type contains a lot of fields and creating + // several copies of it in the output code is undesirable for performance. + bool canReplaceWithConstantUnion() const; + + // The char arrays passed in must be pool allocated or static. + void createSamplerSymbols(const ImmutableString &namePrefix, + const TString &apiNamePrefix, + TVector<const TVariable *> *outputSymbols, + TMap<const TVariable *, TString> *outputSymbolsToAPINames, + TSymbolTable *symbolTable) const; + + // Initializes all lazily-initialized members. + void realize(); + + bool isSampler() const { return IsSampler(type); } + bool isAtomicCounter() const { return IsAtomicCounter(type); } + + private: + void invalidateMangledName(); + const char *buildMangledName() const; + + TBasicType type; + TPrecision precision; + TQualifier qualifier; + bool invariant; + TMemoryQualifier memoryQualifier; + TLayoutQualifier layoutQualifier; + unsigned char primarySize; // size of vector or cols matrix + unsigned char secondarySize; // rows of a matrix + + // Used to make an array type. Outermost array size is stored at the end of the vector. Having 0 + // in this vector means an unsized array. + TVector<unsigned int> *mArraySizes; + + // This is set only in the following two cases: + // 1) Represents an interface block. + // 2) Represents the member variable of an unnamed interface block. + // It's nullptr also for members of named interface blocks. + const TInterfaceBlock *mInterfaceBlock; + + // nullptr unless this is a struct + const TStructure *mStructure; + bool mIsStructSpecifier; + + mutable const char *mMangledName; +}; + +// TTypeSpecifierNonArray stores all of the necessary fields for type_specifier_nonarray from the +// grammar +struct TTypeSpecifierNonArray +{ + TBasicType type; + unsigned char primarySize; // size of vector or cols of matrix + unsigned char secondarySize; // rows of matrix + const TStructure *userDef; + TSourceLoc line; + + // true if the type was defined by a struct specifier rather than a reference to a type name. + bool isStructSpecifier; + + void initialize(TBasicType aType, const TSourceLoc &aLine) + { + ASSERT(aType != EbtStruct); + type = aType; + primarySize = 1; + secondarySize = 1; + userDef = nullptr; + line = aLine; + isStructSpecifier = false; + } + + void initializeStruct(const TStructure *aUserDef, + bool aIsStructSpecifier, + const TSourceLoc &aLine) + { + type = EbtStruct; + primarySize = 1; + secondarySize = 1; + userDef = aUserDef; + line = aLine; + isStructSpecifier = aIsStructSpecifier; + } + + void setAggregate(unsigned char size) { primarySize = size; } + + void setMatrix(unsigned char columns, unsigned char rows) + { + ASSERT(columns > 1 && rows > 1 && columns <= 4 && rows <= 4); + primarySize = columns; + secondarySize = rows; + } + + bool isMatrix() const { return primarySize > 1 && secondarySize > 1; } + + bool isVector() const { return primarySize > 1 && secondarySize == 1; } +}; + +// +// This is a workaround for a problem with the yacc stack, It can't have +// types that it thinks have non-trivial constructors. It should +// just be used while recognizing the grammar, not anything else. Pointers +// could be used, but also trying to avoid lots of memory management overhead. +// +// Not as bad as it looks, there is no actual assumption that the fields +// match up or are name the same or anything like that. +// +struct TPublicType +{ + // Must have a trivial default constructor since it is used in YYSTYPE. + TPublicType() = default; + + void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q); + void initializeBasicType(TBasicType basicType); + + TBasicType getBasicType() const { return typeSpecifierNonArray.type; } + void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; } + + unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; } + unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; } + + const TStructure *getUserDef() const { return typeSpecifierNonArray.userDef; } + const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; } + + bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; } + + bool isStructureContainingArrays() const; + bool isStructureContainingType(TBasicType t) const; + void setArraySizes(TVector<unsigned int> *sizes); + bool isArray() const; + void clearArrayness(); + bool isAggregate() const; + + TTypeSpecifierNonArray typeSpecifierNonArray; + TLayoutQualifier layoutQualifier; + TMemoryQualifier memoryQualifier; + TQualifier qualifier; + bool invariant; + TPrecision precision; + + // Either nullptr or empty in case the type is not an array. The last element is the outermost + // array size. Note that due to bison restrictions, copies of the public type created by the + // copy constructor share the same arraySizes pointer. + const TVector<unsigned int> *arraySizes; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TYPES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.cpp new file mode 100644 index 0000000000..11e337dabd --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.cpp @@ -0,0 +1,1108 @@ +// +// Copyright (c) 2014 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. +// +// UtilsHLSL.cpp: +// Utility methods for GLSL to HLSL translation. +// + +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/StructureHLSL.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +void DisambiguateFunctionNameForParameterType(const TType ¶mType, + TString *disambiguatingStringOut) +{ + // Parameter types are only added to function names if they are ambiguous according to the + // native HLSL compiler. Other parameter types are not added to function names to avoid + // making function names longer. + if (paramType.getObjectSize() == 4 && paramType.getBasicType() == EbtFloat) + { + // Disambiguation is needed for float2x2 and float4 parameters. These are the only + // built-in types that HLSL thinks are identical. float2x3 and float3x2 are different + // types, for example. + *disambiguatingStringOut += "_" + TypeString(paramType); + } + else if (paramType.getBasicType() == EbtStruct) + { + // Disambiguation is needed for struct parameters, since HLSL thinks that structs with + // the same fields but a different name are identical. + ASSERT(paramType.getStruct()->symbolType() != SymbolType::Empty); + *disambiguatingStringOut += "_" + TypeString(paramType); + } +} + +} // anonymous namespace + +const char *SamplerString(const TBasicType type) +{ + if (IsShadowSampler(type)) + { + return "SamplerComparisonState"; + } + else + { + return "SamplerState"; + } +} + +const char *SamplerString(HLSLTextureGroup type) +{ + if (type >= HLSL_COMPARISON_SAMPLER_GROUP_BEGIN && type <= HLSL_COMPARISON_SAMPLER_GROUP_END) + { + return "SamplerComparisonState"; + } + else + { + return "SamplerState"; + } +} + +HLSLTextureGroup TextureGroup(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) + +{ + switch (type) + { + case EbtSampler2D: + return HLSL_TEXTURE_2D; + case EbtSamplerCube: + return HLSL_TEXTURE_CUBE; + case EbtSamplerExternalOES: + return HLSL_TEXTURE_2D; + case EbtSampler2DArray: + return HLSL_TEXTURE_2D_ARRAY; + case EbtSampler3D: + return HLSL_TEXTURE_3D; + case EbtSampler2DMS: + return HLSL_TEXTURE_2D_MS; + case EbtSampler2DMSArray: + return HLSL_TEXTURE_2D_MS_ARRAY; + case EbtISampler2D: + return HLSL_TEXTURE_2D_INT4; + case EbtISampler3D: + return HLSL_TEXTURE_3D_INT4; + case EbtISamplerCube: + return HLSL_TEXTURE_2D_ARRAY_INT4; + case EbtISampler2DArray: + return HLSL_TEXTURE_2D_ARRAY_INT4; + case EbtISampler2DMS: + return HLSL_TEXTURE_2D_MS_INT4; + case EbtISampler2DMSArray: + return HLSL_TEXTURE_2D_MS_ARRAY_INT4; + case EbtUSampler2D: + return HLSL_TEXTURE_2D_UINT4; + case EbtUSampler3D: + return HLSL_TEXTURE_3D_UINT4; + case EbtUSamplerCube: + return HLSL_TEXTURE_2D_ARRAY_UINT4; + case EbtUSampler2DArray: + return HLSL_TEXTURE_2D_ARRAY_UINT4; + case EbtUSampler2DMS: + return HLSL_TEXTURE_2D_MS_UINT4; + case EbtUSampler2DMSArray: + return HLSL_TEXTURE_2D_MS_ARRAY_UINT4; + case EbtSampler2DShadow: + return HLSL_TEXTURE_2D_COMPARISON; + case EbtSamplerCubeShadow: + return HLSL_TEXTURE_CUBE_COMPARISON; + case EbtSampler2DArrayShadow: + return HLSL_TEXTURE_2D_ARRAY_COMPARISON; + case EbtImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_TEXTURE_2D; + case EiifRGBA8: + return HLSL_TEXTURE_2D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_TEXTURE_2D_SNORM; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtIImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_TEXTURE_2D_INT4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtUImage2D: + { + switch (imageInternalFormat) + { + + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_TEXTURE_2D_UINT4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_TEXTURE_3D; + case EiifRGBA8: + return HLSL_TEXTURE_3D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_TEXTURE_3D_SNORM; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtIImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_TEXTURE_3D_INT4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtUImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_TEXTURE_3D_UINT4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtImage2DArray: + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_TEXTURE_2D_ARRAY; + case EiifRGBA8: + return HLSL_TEXTURE_2D_ARRAY_UNORN; + case EiifRGBA8_SNORM: + return HLSL_TEXTURE_2D_ARRAY_SNORM; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtIImage2DArray: + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_TEXTURE_2D_ARRAY_INT4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + case EbtUImage2DArray: + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_TEXTURE_2D_ARRAY_UINT4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } + } + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return HLSL_TEXTURE_UNKNOWN; +#endif + } +} + +const char *TextureString(const HLSLTextureGroup textureGroup) +{ + switch (textureGroup) + { + case HLSL_TEXTURE_2D: + return "Texture2D<float4>"; + case HLSL_TEXTURE_CUBE: + return "TextureCube<float4>"; + case HLSL_TEXTURE_2D_ARRAY: + return "Texture2DArray<float4>"; + case HLSL_TEXTURE_3D: + return "Texture3D<float4>"; + case HLSL_TEXTURE_2D_UNORM: + return "Texture2D<unorm float4>"; + case HLSL_TEXTURE_CUBE_UNORM: + return "TextureCube<unorm float4>"; + case HLSL_TEXTURE_2D_ARRAY_UNORN: + return "Texture2DArray<unorm float4>"; + case HLSL_TEXTURE_3D_UNORM: + return "Texture3D<unorm float4>"; + case HLSL_TEXTURE_2D_SNORM: + return "Texture2D<snorm float4>"; + case HLSL_TEXTURE_CUBE_SNORM: + return "TextureCube<snorm float4>"; + case HLSL_TEXTURE_2D_ARRAY_SNORM: + return "Texture2DArray<snorm float4>"; + case HLSL_TEXTURE_3D_SNORM: + return "Texture3D<snorm float4>"; + case HLSL_TEXTURE_2D_MS: + return "Texture2DMS<float4>"; + case HLSL_TEXTURE_2D_MS_ARRAY: + return "Texture2DMSArray<float4>"; + case HLSL_TEXTURE_2D_INT4: + return "Texture2D<int4>"; + case HLSL_TEXTURE_3D_INT4: + return "Texture3D<int4>"; + case HLSL_TEXTURE_2D_ARRAY_INT4: + return "Texture2DArray<int4>"; + case HLSL_TEXTURE_2D_MS_INT4: + return "Texture2DMS<int4>"; + case HLSL_TEXTURE_2D_MS_ARRAY_INT4: + return "Texture2DMSArray<int4>"; + case HLSL_TEXTURE_2D_UINT4: + return "Texture2D<uint4>"; + case HLSL_TEXTURE_3D_UINT4: + return "Texture3D<uint4>"; + case HLSL_TEXTURE_2D_ARRAY_UINT4: + return "Texture2DArray<uint4>"; + case HLSL_TEXTURE_2D_MS_UINT4: + return "Texture2DMS<uint4>"; + case HLSL_TEXTURE_2D_MS_ARRAY_UINT4: + return "Texture2DMSArray<uint4>"; + case HLSL_TEXTURE_2D_COMPARISON: + return "Texture2D"; + case HLSL_TEXTURE_CUBE_COMPARISON: + return "TextureCube"; + case HLSL_TEXTURE_2D_ARRAY_COMPARISON: + return "Texture2DArray"; + default: + UNREACHABLE(); + } + + return "<unknown read texture type>"; +} + +const char *TextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) +{ + return TextureString(TextureGroup(type, imageInternalFormat)); +} + +const char *TextureGroupSuffix(const HLSLTextureGroup type) +{ + switch (type) + { + case HLSL_TEXTURE_2D: + return "2D"; + case HLSL_TEXTURE_CUBE: + return "Cube"; + case HLSL_TEXTURE_2D_ARRAY: + return "2DArray"; + case HLSL_TEXTURE_3D: + return "3D"; + case HLSL_TEXTURE_2D_UNORM: + return "2D_unorm_float4_"; + case HLSL_TEXTURE_CUBE_UNORM: + return "Cube_unorm_float4_"; + case HLSL_TEXTURE_2D_ARRAY_UNORN: + return "2DArray_unorm_float4_"; + case HLSL_TEXTURE_3D_UNORM: + return "3D_unorm_float4_"; + case HLSL_TEXTURE_2D_SNORM: + return "2D_snorm_float4_"; + case HLSL_TEXTURE_CUBE_SNORM: + return "Cube_snorm_float4_"; + case HLSL_TEXTURE_2D_ARRAY_SNORM: + return "2DArray_snorm_float4_"; + case HLSL_TEXTURE_3D_SNORM: + return "3D_snorm_float4_"; + case HLSL_TEXTURE_2D_MS: + return "2DMS"; + case HLSL_TEXTURE_2D_MS_ARRAY: + return "2DMSArray"; + case HLSL_TEXTURE_2D_INT4: + return "2D_int4_"; + case HLSL_TEXTURE_3D_INT4: + return "3D_int4_"; + case HLSL_TEXTURE_2D_ARRAY_INT4: + return "2DArray_int4_"; + case HLSL_TEXTURE_2D_MS_INT4: + return "2DMS_int4_"; + case HLSL_TEXTURE_2D_MS_ARRAY_INT4: + return "2DMSArray_int4_"; + case HLSL_TEXTURE_2D_UINT4: + return "2D_uint4_"; + case HLSL_TEXTURE_3D_UINT4: + return "3D_uint4_"; + case HLSL_TEXTURE_2D_ARRAY_UINT4: + return "2DArray_uint4_"; + case HLSL_TEXTURE_2D_MS_UINT4: + return "2DMS_uint4_"; + case HLSL_TEXTURE_2D_MS_ARRAY_UINT4: + return "2DMSArray_uint4_"; + case HLSL_TEXTURE_2D_COMPARISON: + return "2D_comparison"; + case HLSL_TEXTURE_CUBE_COMPARISON: + return "Cube_comparison"; + case HLSL_TEXTURE_2D_ARRAY_COMPARISON: + return "2DArray_comparison"; + default: + UNREACHABLE(); + } + + return "<unknown texture type>"; +} + +const char *TextureGroupSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat) +{ + return TextureGroupSuffix(TextureGroup(type, imageInternalFormat)); +} + +const char *TextureTypeSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) +{ + switch (type) + { + case EbtISamplerCube: + return "Cube_int4_"; + case EbtUSamplerCube: + return "Cube_uint4_"; + case EbtSamplerExternalOES: + return "_External"; + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return "Cube_float4_"; + case EiifRGBA8: + return "Cube_unorm_float4_"; + case EiifRGBA8_SNORM: + return "Cube_snorm_float4_"; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return "Cube_int4_"; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return "Cube_uint4_"; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + default: + // All other types are identified by their group suffix + return TextureGroupSuffix(type, imageInternalFormat); + } +#if !UNREACHABLE_IS_NORETURN + UNREACHABLE(); + return "_TTS_invalid_"; +#endif +} + +HLSLRWTextureGroup RWTextureGroup(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat) + +{ + switch (type) + { + case EbtImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_RWTEXTURE_2D_FLOAT4; + case EiifRGBA8: + return HLSL_RWTEXTURE_2D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_RWTEXTURE_2D_SNORM; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtIImage2D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_RWTEXTURE_2D_INT4; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtUImage2D: + { + switch (imageInternalFormat) + { + + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_RWTEXTURE_2D_UINT4; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_RWTEXTURE_3D_FLOAT4; + case EiifRGBA8: + return HLSL_RWTEXTURE_3D_UNORM; + case EiifRGBA8_SNORM: + return HLSL_RWTEXTURE_3D_SNORM; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtIImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_RWTEXTURE_3D_INT4; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtUImage3D: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_RWTEXTURE_3D_UINT4; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtImage2DArray: + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return HLSL_RWTEXTURE_2D_ARRAY_FLOAT4; + case EiifRGBA8: + return HLSL_RWTEXTURE_2D_ARRAY_UNORN; + case EiifRGBA8_SNORM: + return HLSL_RWTEXTURE_2D_ARRAY_SNORM; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtIImage2DArray: + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return HLSL_RWTEXTURE_2D_ARRAY_INT4; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtUImage2DArray: + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return HLSL_RWTEXTURE_2D_ARRAY_UINT4; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + default: + UNREACHABLE(); + } + return HLSL_RWTEXTURE_UNKNOWN; +} + +const char *RWTextureString(const HLSLRWTextureGroup RWTextureGroup) +{ + switch (RWTextureGroup) + { + case HLSL_RWTEXTURE_2D_FLOAT4: + return "RWTexture2D<float4>"; + case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4: + return "RWTexture2DArray<float4>"; + case HLSL_RWTEXTURE_3D_FLOAT4: + return "RWTexture3D<float4>"; + case HLSL_RWTEXTURE_2D_UNORM: + return "RWTexture2D<unorm float4>"; + case HLSL_RWTEXTURE_2D_ARRAY_UNORN: + return "RWTexture2DArray<unorm float4>"; + case HLSL_RWTEXTURE_3D_UNORM: + return "RWTexture3D<unorm float4>"; + case HLSL_RWTEXTURE_2D_SNORM: + return "RWTexture2D<snorm float4>"; + case HLSL_RWTEXTURE_2D_ARRAY_SNORM: + return "RWTexture2DArray<snorm float4>"; + case HLSL_RWTEXTURE_3D_SNORM: + return "RWTexture3D<snorm float4>"; + case HLSL_RWTEXTURE_2D_UINT4: + return "RWTexture2D<uint4>"; + case HLSL_RWTEXTURE_2D_ARRAY_UINT4: + return "RWTexture2DArray<uint4>"; + case HLSL_RWTEXTURE_3D_UINT4: + return "RWTexture3D<uint4>"; + case HLSL_RWTEXTURE_2D_INT4: + return "RWTexture2D<int4>"; + case HLSL_RWTEXTURE_2D_ARRAY_INT4: + return "RWTexture2DArray<int4>"; + case HLSL_RWTEXTURE_3D_INT4: + return "RWTexture3D<int4>"; + default: + UNREACHABLE(); + } + + return "<unknown read and write texture type>"; +} + +const char *RWTextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat) +{ + return RWTextureString(RWTextureGroup(type, imageInternalFormat)); +} + +const char *RWTextureGroupSuffix(const HLSLRWTextureGroup type) +{ + switch (type) + { + case HLSL_RWTEXTURE_2D_FLOAT4: + return "RW2D_float4_"; + case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4: + return "RW2DArray_float4_"; + case HLSL_RWTEXTURE_3D_FLOAT4: + return "RW3D_float4_"; + case HLSL_RWTEXTURE_2D_UNORM: + return "RW2D_unorm_float4_"; + case HLSL_RWTEXTURE_2D_ARRAY_UNORN: + return "RW2DArray_unorm_float4_"; + case HLSL_RWTEXTURE_3D_UNORM: + return "RW3D_unorm_float4_"; + case HLSL_RWTEXTURE_2D_SNORM: + return "RW2D_snorm_float4_"; + case HLSL_RWTEXTURE_2D_ARRAY_SNORM: + return "RW2DArray_snorm_float4_"; + case HLSL_RWTEXTURE_3D_SNORM: + return "RW3D_snorm_float4_"; + case HLSL_RWTEXTURE_2D_UINT4: + return "RW2D_uint4_"; + case HLSL_RWTEXTURE_2D_ARRAY_UINT4: + return "RW2DArray_uint4_"; + case HLSL_RWTEXTURE_3D_UINT4: + return "RW3D_uint4_"; + case HLSL_RWTEXTURE_2D_INT4: + return "RW2D_int4_"; + case HLSL_RWTEXTURE_2D_ARRAY_INT4: + return "RW2DArray_int4_"; + case HLSL_RWTEXTURE_3D_INT4: + return "RW3D_int4_"; + default: + UNREACHABLE(); + } + + return "<unknown read and write resource>"; +} + +const char *RWTextureGroupSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat) +{ + return RWTextureGroupSuffix(RWTextureGroup(type, imageInternalFormat)); +} + +const char *RWTextureTypeSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat) +{ + switch (type) + { + case EbtImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32F: + case EiifRGBA16F: + case EiifR32F: + return "RWCube_float4_"; + case EiifRGBA8: + return "RWCube_unorm_float4_"; + case EiifRGBA8_SNORM: + return "RWCube_unorm_float4_"; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtIImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32I: + case EiifRGBA16I: + case EiifRGBA8I: + case EiifR32I: + return "RWCube_int4_"; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + case EbtUImageCube: + { + switch (imageInternalFormat) + { + case EiifRGBA32UI: + case EiifRGBA16UI: + case EiifRGBA8UI: + case EiifR32UI: + return "RWCube_uint4_"; + default: + UNREACHABLE(); + } +#if !UNREACHABLE_IS_NORETURN + break; +#endif + } + default: + // All other types are identified by their group suffix + return RWTextureGroupSuffix(type, imageInternalFormat); + } +#if !UNREACHABLE_IS_NORETURN + UNREACHABLE(); + return "_RWTS_invalid_"; +#endif +} + +TString DecorateField(const ImmutableString &string, const TStructure &structure) +{ + if (structure.symbolType() != SymbolType::BuiltIn) + { + return Decorate(string); + } + + return TString(string.data()); +} + +TString DecoratePrivate(const ImmutableString &privateText) +{ + return "dx_" + TString(privateText.data()); +} + +TString Decorate(const ImmutableString &string) +{ + if (!string.beginsWith("gl_")) + { + return "_" + TString(string.data()); + } + + return TString(string.data()); +} + +TString DecorateVariableIfNeeded(const TVariable &variable) +{ + if (variable.symbolType() == SymbolType::AngleInternal || + variable.symbolType() == SymbolType::Empty) + { + // Besides handling internal variables, we generate names for nameless parameters here. + const ImmutableString &name = variable.name(); + // The name should not have a prefix reserved for user-defined variables or functions. + ASSERT(!name.beginsWith("f_")); + ASSERT(!name.beginsWith("_")); + return TString(name.data()); + } + // For user defined variables, combine variable name with unique id + // so variables of the same name in different scopes do not get overwritten. + else if (variable.symbolType() == SymbolType::UserDefined && + variable.getType().getQualifier() == EvqTemporary) + { + return Decorate(variable.name()) + str(variable.uniqueId().get()); + } + else + { + return Decorate(variable.name()); + } +} + +TString DecorateFunctionIfNeeded(const TFunction *func) +{ + if (func->symbolType() == SymbolType::AngleInternal) + { + // The name should not have a prefix reserved for user-defined variables or functions. + ASSERT(!func->name().beginsWith("f_")); + ASSERT(!func->name().beginsWith("_")); + return TString(func->name().data()); + } + ASSERT(!func->name().beginsWith("gl_")); + // Add an additional f prefix to functions so that they're always disambiguated from variables. + // This is necessary in the corner case where a variable declaration hides a function that it + // uses in its initializer. + return "f_" + TString(func->name().data()); +} + +TString TypeString(const TType &type) +{ + const TStructure *structure = type.getStruct(); + if (structure) + { + if (structure->symbolType() != SymbolType::Empty) + { + return StructNameString(*structure); + } + else // Nameless structure, define in place + { + return StructureHLSL::defineNameless(*structure); + } + } + else if (type.isMatrix()) + { + int cols = type.getCols(); + int rows = type.getRows(); + return "float" + str(cols) + "x" + str(rows); + } + else + { + switch (type.getBasicType()) + { + case EbtFloat: + switch (type.getNominalSize()) + { + case 1: + return "float"; + case 2: + return "float2"; + case 3: + return "float3"; + case 4: + return "float4"; + } + case EbtInt: + switch (type.getNominalSize()) + { + case 1: + return "int"; + case 2: + return "int2"; + case 3: + return "int3"; + case 4: + return "int4"; + } + case EbtUInt: + switch (type.getNominalSize()) + { + case 1: + return "uint"; + case 2: + return "uint2"; + case 3: + return "uint3"; + case 4: + return "uint4"; + } + case EbtBool: + switch (type.getNominalSize()) + { + case 1: + return "bool"; + case 2: + return "bool2"; + case 3: + return "bool3"; + case 4: + return "bool4"; + } + case EbtVoid: + return "void"; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + return "sampler2D"; + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + return "samplerCUBE"; + case EbtSamplerExternalOES: + return "sampler2D"; + case EbtAtomicCounter: + // Multiple atomic_uints will be implemented as a single RWByteAddressBuffer + return "RWByteAddressBuffer"; + default: + break; + } + } + + UNREACHABLE(); + return "<unknown type>"; +} + +TString StructNameString(const TStructure &structure) +{ + if (structure.symbolType() == SymbolType::Empty) + { + return ""; + } + + // For structures at global scope we use a consistent + // translation so that we can link between shader stages. + if (structure.atGlobalScope()) + { + return Decorate(structure.name()); + } + + return "ss" + str(structure.uniqueId().get()) + "_" + TString(structure.name().data()); +} + +TString QualifiedStructNameString(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing) +{ + if (structure.symbolType() == SymbolType::Empty) + { + return ""; + } + + TString prefix = ""; + + // Structs packed with row-major matrices in HLSL are prefixed with "rm" + // GLSL column-major maps to HLSL row-major, and the converse is true + + if (useStd140Packing) + { + prefix += "std_"; + } + + if (useHLSLRowMajorPacking) + { + prefix += "rm_"; + } + + return prefix + StructNameString(structure); +} + +const char *InterpolationString(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqVaryingIn: + return ""; + case EvqFragmentIn: + return ""; + case EvqSmoothIn: + return "linear"; + case EvqFlatIn: + return "nointerpolation"; + case EvqCentroidIn: + return "centroid"; + case EvqVaryingOut: + return ""; + case EvqVertexOut: + return ""; + case EvqSmoothOut: + return "linear"; + case EvqFlatOut: + return "nointerpolation"; + case EvqCentroidOut: + return "centroid"; + default: + UNREACHABLE(); + } + + return ""; +} + +const char *QualifierString(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqIn: + return "in"; + case EvqOut: + return "inout"; // 'out' results in an HLSL error if not all fields are written, for + // GLSL it's undefined + case EvqInOut: + return "inout"; + case EvqConstReadOnly: + return "const"; + default: + UNREACHABLE(); + } + + return ""; +} + +TString DisambiguateFunctionName(const TFunction *func) +{ + TString disambiguatingString; + size_t paramCount = func->getParamCount(); + for (size_t i = 0; i < paramCount; ++i) + { + DisambiguateFunctionNameForParameterType(func->getParam(i)->getType(), + &disambiguatingString); + } + return disambiguatingString; +} + +TString DisambiguateFunctionName(const TIntermSequence *args) +{ + TString disambiguatingString; + for (TIntermNode *arg : *args) + { + ASSERT(arg->getAsTyped()); + DisambiguateFunctionNameForParameterType(arg->getAsTyped()->getType(), + &disambiguatingString); + } + return disambiguatingString; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.h b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.h new file mode 100644 index 0000000000..ebd7ab3dc0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/UtilsHLSL.h @@ -0,0 +1,135 @@ +// +// Copyright (c) 2014 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. +// +// UtilsHLSL.h: +// Utility methods for GLSL to HLSL translation. +// + +#ifndef COMPILER_TRANSLATOR_UTILSHLSL_H_ +#define COMPILER_TRANSLATOR_UTILSHLSL_H_ + +#include <vector> +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Types.h" + +#include "angle_gl.h" + +namespace sh +{ + +class TFunction; + +// HLSL Texture type for GLSL sampler type and readonly image type. +enum HLSLTextureGroup +{ + // read resources + HLSL_TEXTURE_2D, + HLSL_TEXTURE_MIN = HLSL_TEXTURE_2D, + + HLSL_TEXTURE_CUBE, + HLSL_TEXTURE_2D_ARRAY, + HLSL_TEXTURE_3D, + HLSL_TEXTURE_2D_UNORM, + HLSL_TEXTURE_CUBE_UNORM, + HLSL_TEXTURE_2D_ARRAY_UNORN, + HLSL_TEXTURE_3D_UNORM, + HLSL_TEXTURE_2D_SNORM, + HLSL_TEXTURE_CUBE_SNORM, + HLSL_TEXTURE_2D_ARRAY_SNORM, + HLSL_TEXTURE_3D_SNORM, + HLSL_TEXTURE_2D_MS, + HLSL_TEXTURE_2D_MS_ARRAY, + HLSL_TEXTURE_2D_INT4, + HLSL_TEXTURE_3D_INT4, + HLSL_TEXTURE_2D_ARRAY_INT4, + HLSL_TEXTURE_2D_MS_INT4, + HLSL_TEXTURE_2D_MS_ARRAY_INT4, + HLSL_TEXTURE_2D_UINT4, + HLSL_TEXTURE_3D_UINT4, + HLSL_TEXTURE_2D_ARRAY_UINT4, + HLSL_TEXTURE_2D_MS_UINT4, + HLSL_TEXTURE_2D_MS_ARRAY_UINT4, + + // Comparison samplers + + HLSL_TEXTURE_2D_COMPARISON, + HLSL_TEXTURE_CUBE_COMPARISON, + HLSL_TEXTURE_2D_ARRAY_COMPARISON, + + HLSL_COMPARISON_SAMPLER_GROUP_BEGIN = HLSL_TEXTURE_2D_COMPARISON, + HLSL_COMPARISON_SAMPLER_GROUP_END = HLSL_TEXTURE_2D_ARRAY_COMPARISON, + + HLSL_TEXTURE_UNKNOWN, + HLSL_TEXTURE_MAX = HLSL_TEXTURE_UNKNOWN +}; + +// HLSL RWTexture type for GLSL read and write image type. +enum HLSLRWTextureGroup +{ + // read/write resource + HLSL_RWTEXTURE_2D_FLOAT4, + HLSL_RWTEXTURE_MIN = HLSL_RWTEXTURE_2D_FLOAT4, + HLSL_RWTEXTURE_2D_ARRAY_FLOAT4, + HLSL_RWTEXTURE_3D_FLOAT4, + HLSL_RWTEXTURE_2D_UNORM, + HLSL_RWTEXTURE_2D_ARRAY_UNORN, + HLSL_RWTEXTURE_3D_UNORM, + HLSL_RWTEXTURE_2D_SNORM, + HLSL_RWTEXTURE_2D_ARRAY_SNORM, + HLSL_RWTEXTURE_3D_SNORM, + HLSL_RWTEXTURE_2D_UINT4, + HLSL_RWTEXTURE_2D_ARRAY_UINT4, + HLSL_RWTEXTURE_3D_UINT4, + HLSL_RWTEXTURE_2D_INT4, + HLSL_RWTEXTURE_2D_ARRAY_INT4, + HLSL_RWTEXTURE_3D_INT4, + + HLSL_RWTEXTURE_UNKNOWN, + HLSL_RWTEXTURE_MAX = HLSL_RWTEXTURE_UNKNOWN +}; + +HLSLTextureGroup TextureGroup(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +const char *TextureString(const HLSLTextureGroup textureGroup); +const char *TextureString(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +const char *TextureGroupSuffix(const HLSLTextureGroup type); +const char *TextureGroupSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +const char *TextureTypeSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified); +HLSLRWTextureGroup RWTextureGroup(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat); +const char *RWTextureString(const HLSLRWTextureGroup textureGroup); +const char *RWTextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat); +const char *RWTextureGroupSuffix(const HLSLRWTextureGroup type); +const char *RWTextureGroupSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat); +const char *RWTextureTypeSuffix(const TBasicType type, + TLayoutImageInternalFormat imageInternalFormat); + +const char *SamplerString(const TBasicType type); +const char *SamplerString(HLSLTextureGroup type); + +// Adds a prefix to user-defined names to avoid naming clashes. +TString Decorate(const ImmutableString &string); +TString DecorateVariableIfNeeded(const TVariable &variable); +TString DecorateFunctionIfNeeded(const TFunction *func); +TString DecorateField(const ImmutableString &string, const TStructure &structure); +TString DecoratePrivate(const ImmutableString &privateText); +TString TypeString(const TType &type); +TString StructNameString(const TStructure &structure); +TString QualifiedStructNameString(const TStructure &structure, + bool useHLSLRowMajorPacking, + bool useStd140Packing); +const char *InterpolationString(TQualifier qualifier); +const char *QualifierString(TQualifier qualifier); +// Parameters may need to be included in function names to disambiguate between overloaded +// functions. +TString DisambiguateFunctionName(const TFunction *func); +TString DisambiguateFunctionName(const TIntermSequence *args); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateAST.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateAST.cpp new file mode 100644 index 0000000000..c0ec114741 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateAST.cpp @@ -0,0 +1,251 @@ +// +// 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. +// + +#include "compiler/translator/ValidateAST.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class ValidateAST : public TIntermTraverser +{ + public: + static bool validate(TIntermNode *root, + TDiagnostics *diagnostics, + const ValidateASTOptions &options); + + void visitSymbol(TIntermSymbol *node) override; + void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; + bool visitSwitch(Visit visit, TIntermSwitch *node) override; + bool visitCase(Visit visit, TIntermCase *node) override; + void visitFunctionPrototype(TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitLoop(Visit visit, TIntermLoop *node) override; + bool visitBranch(Visit visit, TIntermBranch *node) override; + void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override; + + private: + ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options); + + // Visit as a generic node + void visitNode(Visit visit, TIntermNode *node); + + void expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count); + + bool validateInternal(); + + ValidateASTOptions mOptions; + TDiagnostics *mDiagnostics; + + // For validateSingleParent: + std::map<TIntermNode *, TIntermNode *> mParent; + bool mSingleParentFailed = false; + + // For validateNullNodes + bool mNullNodesFailed = false; +}; + +bool ValidateAST::validate(TIntermNode *root, + TDiagnostics *diagnostics, + const ValidateASTOptions &options) +{ + ValidateAST validate(root, diagnostics, options); + root->traverse(&validate); + return validate.validateInternal(); +} + +ValidateAST::ValidateAST(TIntermNode *root, + TDiagnostics *diagnostics, + const ValidateASTOptions &options) + : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics) +{ + if (mOptions.validateSingleParent) + { + mParent[root] = nullptr; + } +} + +void ValidateAST::visitNode(Visit visit, TIntermNode *node) +{ + if (visit == PreVisit && mOptions.validateSingleParent) + { + size_t childCount = node->getChildCount(); + for (size_t i = 0; i < childCount; ++i) + { + TIntermNode *child = node->getChildNode(i); + if (mParent.find(child) != mParent.end()) + { + // If child is visited twice but through the same parent, the problem is in one of + // the ancestors. + if (mParent[child] != node) + { + mDiagnostics->error(node->getLine(), "Found child with two parents", + "<validateSingleParent>"); + mSingleParentFailed = true; + } + } + + mParent[child] = node; + } + } +} + +void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count) +{ + if (visit == PreVisit && mOptions.validateNullNodes) + { + size_t childCount = node->getChildCount(); + if (childCount < least_count) + { + mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>"); + mNullNodesFailed = true; + } + + for (size_t i = 0; i < childCount; ++i) + { + if (node->getChildNode(i) == nullptr) + { + mDiagnostics->error(node->getLine(), "Found nullptr child", "<validateNullNodes>"); + mNullNodesFailed = true; + } + } + } +} + +void ValidateAST::visitSymbol(TIntermSymbol *node) +{ + visitNode(PreVisit, node); +} + +void ValidateAST::visitConstantUnion(TIntermConstantUnion *node) +{ + visitNode(PreVisit, node); +} + +bool ValidateAST::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitBinary(Visit visit, TIntermBinary *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitUnary(Visit visit, TIntermUnary *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitTernary(Visit visit, TIntermTernary *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitIfElse(Visit visit, TIntermIfElse *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitSwitch(Visit visit, TIntermSwitch *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitCase(Visit visit, TIntermCase *node) +{ + visitNode(visit, node); + return true; +} + +void ValidateAST::visitFunctionPrototype(TIntermFunctionPrototype *node) +{ + visitNode(PreVisit, node); +} + +bool ValidateAST::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitAggregate(Visit visit, TIntermAggregate *node) +{ + visitNode(visit, node); + expectNonNullChildren(visit, node, 0); + return true; +} + +bool ValidateAST::visitBlock(Visit visit, TIntermBlock *node) +{ + visitNode(visit, node); + expectNonNullChildren(visit, node, 0); + return true; +} + +bool ValidateAST::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + visitNode(visit, node); + expectNonNullChildren(visit, node, 0); + return true; +} + +bool ValidateAST::visitLoop(Visit visit, TIntermLoop *node) +{ + visitNode(visit, node); + return true; +} + +bool ValidateAST::visitBranch(Visit visit, TIntermBranch *node) +{ + visitNode(visit, node); + return true; +} + +void ValidateAST::visitPreprocessorDirective(TIntermPreprocessorDirective *node) +{ + visitNode(PreVisit, node); +} + +bool ValidateAST::validateInternal() +{ + return !mSingleParentFailed && !mNullNodesFailed; +} + +} // anonymous namespace + +bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options) +{ + return ValidateAST::validate(root, diagnostics, options); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateAST.h b/gfx/angle/checkout/src/compiler/translator/ValidateAST.h new file mode 100644 index 0000000000..7314f6e653 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateAST.h @@ -0,0 +1,58 @@ +// +// 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. +// + +#ifndef COMPILER_TRANSLATOR_VALIDATEAST_H_ +#define COMPILER_TRANSLATOR_VALIDATEAST_H_ + +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" + +namespace sh +{ +class TDiagnostics; +class TIntermNode; + +// The following options (stored in Compiler) tell the validator what to validate. Some validations +// are conditional to certain passes. +struct ValidateASTOptions +{ + // TODO: add support for the flags marked with TODO. http://anglebug.com/2733 + + // Check that every node always has only one parent, + bool validateSingleParent = true; + // Check that all EOpCallFunctionInAST have their corresponding function definitions in the AST, + // with matching symbol ids. There should also be at least a prototype declaration before the + // function is called. + bool validateFunctionCall = true; // TODO + // Check that there are no null nodes where they are not allowed, for example as children of + // TIntermDeclaration or TIntermBlock. + bool validateNullNodes = true; + // Check that symbols that reference variables have consistent qualifiers and symbol ids with + // the variable declaration. For example, references to function out parameters should be + // EvqOut. + bool validateQualifiers = true; // TODO + // Check that variable declarations that can't have initializers don't have initializers + // (varyings, uniforms for example). + bool validateInitializers = true; // TODO + // Check that there is only one TFunction with each function name referenced in the nodes (no + // two TFunctions with the same name, taking internal/non-internal namespaces into account). + bool validateUniqueFunctions = true; // TODO + // Check that references to user-defined structs are matched with the corresponding struct + // declaration. + bool validateStructUsage = true; // TODO + // Check that expression nodes have the correct type considering their operand(s). + bool validateExpressionTypes = true; // TODO + // If SeparateDeclarations has been run, check for the absence of multi declarations as well. + bool validateMultiDeclarations = false; // TODO +}; + +// Check for errors and output error messages on the context. +// Returns true if there are no errors. +bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.cpp new file mode 100644 index 0000000000..4ffb832d99 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.cpp @@ -0,0 +1,141 @@ +// +// Copyright (c) 2002-2015 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/ValidateGlobalInitializer.h" + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +const int kMaxAllowedTraversalDepth = 256; + +class ValidateGlobalInitializerTraverser : public TIntermTraverser +{ + public: + ValidateGlobalInitializerTraverser(int shaderVersion); + + void visitSymbol(TIntermSymbol *node) override; + void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitUnary(Visit visit, TIntermUnary *node) override; + + bool isValid() const { return mIsValid && mMaxDepth < mMaxAllowedDepth; } + bool issueWarning() const { return mIssueWarning; } + + private: + int mShaderVersion; + bool mIsValid; + bool mIssueWarning; +}; + +void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node) +{ + // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3): + // Global initializers must be constant expressions. + switch (node->getType().getQualifier()) + { + case EvqConst: + break; + case EvqGlobal: + case EvqTemporary: + case EvqUniform: + // We allow these cases to be compatible with legacy ESSL 1.00 content. + // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal + // with. + if (mShaderVersion >= 300) + { + mIsValid = false; + } + else + { + mIssueWarning = true; + } + break; + default: + mIsValid = false; + } +} + +void ValidateGlobalInitializerTraverser::visitConstantUnion(TIntermConstantUnion *node) +{ + // Constant unions that are not constant expressions may result from folding a ternary + // expression. + switch (node->getType().getQualifier()) + { + case EvqConst: + break; + case EvqTemporary: + if (mShaderVersion >= 300) + { + mIsValid = false; + } + else + { + mIssueWarning = true; + } + break; + default: + UNREACHABLE(); + } +} + +bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + // Disallow calls to user-defined functions and texture lookup functions in global variable + // initializers. + // This is done simply by disabling all function calls - built-in math functions don't use + // the function call ops. + if (node->isFunctionCall()) + { + mIsValid = false; + } + return true; +} + +bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (node->isAssignment()) + { + mIsValid = false; + } + return true; +} + +bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (node->isAssignment()) + { + mIsValid = false; + } + return true; +} + +ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(int shaderVersion) + : TIntermTraverser(true, false, false, nullptr), + mShaderVersion(shaderVersion), + mIsValid(true), + mIssueWarning(false) +{ + setMaxAllowedDepth(kMaxAllowedTraversalDepth); +} + +} // namespace + +bool ValidateGlobalInitializer(TIntermTyped *initializer, int shaderVersion, bool *warning) +{ + ValidateGlobalInitializerTraverser validate(shaderVersion); + initializer->traverse(&validate); + ASSERT(warning != nullptr); + *warning = validate.issueWarning(); + return validate.isValid(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.h b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.h new file mode 100644 index 0000000000..b830760ca4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateGlobalInitializer.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2002-2015 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_VALIDATEGLOBALINITIALIZER_H_ +#define COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_ + +namespace sh +{ + +class TIntermTyped; + +// Returns true if the initializer is valid. +bool ValidateGlobalInitializer(TIntermTyped *initializer, int shaderVersion, bool *warning); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VALIDATEGLOBALINITIALIZER_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.cpp new file mode 100644 index 0000000000..ac8d5c14ed --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.cpp @@ -0,0 +1,442 @@ +// +// Copyright (c) 2002-2013 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/ValidateLimitations.h" + +#include "angle_gl.h" +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +int GetLoopSymbolId(TIntermLoop *loop) +{ + // Here we assume all the operations are valid, because the loop node is + // already validated before this call. + TIntermSequence *declSeq = loop->getInit()->getAsDeclarationNode()->getSequence(); + TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); + TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); + + return symbol->uniqueId().get(); +} + +// Traverses a node to check if it represents a constant index expression. +// Definition: +// constant-index-expressions are a superset of constant-expressions. +// Constant-index-expressions can include loop indices as defined in +// GLSL ES 1.0 spec, Appendix A, section 4. +// The following are constant-index-expressions: +// - Constant expressions +// - Loop indices as defined in section 4 +// - Expressions composed of both of the above +class ValidateConstIndexExpr : public TIntermTraverser +{ + public: + ValidateConstIndexExpr(const std::vector<int> &loopSymbols) + : TIntermTraverser(true, false, false), mValid(true), mLoopSymbolIds(loopSymbols) + {} + + // Returns true if the parsed node represents a constant index expression. + bool isValid() const { return mValid; } + + void visitSymbol(TIntermSymbol *symbol) override + { + // Only constants and loop indices are allowed in a + // constant index expression. + if (mValid) + { + bool isLoopSymbol = std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), + symbol->uniqueId().get()) != mLoopSymbolIds.end(); + mValid = (symbol->getQualifier() == EvqConst) || isLoopSymbol; + } + } + + private: + bool mValid; + const std::vector<int> mLoopSymbolIds; +}; + +// Traverses intermediate tree to ensure that the shader does not exceed the +// minimum functionality mandated in GLSL 1.0 spec, Appendix A. +class ValidateLimitationsTraverser : public TLValueTrackingTraverser +{ + public: + ValidateLimitationsTraverser(sh::GLenum shaderType, + TSymbolTable *symbolTable, + TDiagnostics *diagnostics); + + void visitSymbol(TIntermSymbol *node) override; + bool visitBinary(Visit, TIntermBinary *) override; + bool visitLoop(Visit, TIntermLoop *) override; + + private: + void error(TSourceLoc loc, const char *reason, const char *token); + void error(TSourceLoc loc, const char *reason, const ImmutableString &token); + + bool isLoopIndex(TIntermSymbol *symbol); + bool validateLoopType(TIntermLoop *node); + + bool validateForLoopHeader(TIntermLoop *node); + // If valid, return the index symbol id; Otherwise, return -1. + int validateForLoopInit(TIntermLoop *node); + bool validateForLoopCond(TIntermLoop *node, int indexSymbolId); + bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId); + + // Returns true if indexing does not exceed the minimum functionality + // mandated in GLSL 1.0 spec, Appendix A, Section 5. + bool isConstExpr(TIntermNode *node); + bool isConstIndexExpr(TIntermNode *node); + bool validateIndexing(TIntermBinary *node); + + sh::GLenum mShaderType; + TDiagnostics *mDiagnostics; + std::vector<int> mLoopSymbolIds; +}; + +ValidateLimitationsTraverser::ValidateLimitationsTraverser(sh::GLenum shaderType, + TSymbolTable *symbolTable, + TDiagnostics *diagnostics) + : TLValueTrackingTraverser(true, false, false, symbolTable), + mShaderType(shaderType), + mDiagnostics(diagnostics) +{ + ASSERT(diagnostics); +} + +void ValidateLimitationsTraverser::visitSymbol(TIntermSymbol *node) +{ + if (isLoopIndex(node) && isLValueRequiredHere()) + { + error(node->getLine(), + "Loop index cannot be statically assigned to within the body of the loop", + node->getName()); + } +} + +bool ValidateLimitationsTraverser::visitBinary(Visit, TIntermBinary *node) +{ + // Check indexing. + switch (node->getOp()) + { + case EOpIndexDirect: + case EOpIndexIndirect: + validateIndexing(node); + break; + default: + break; + } + return true; +} + +bool ValidateLimitationsTraverser::visitLoop(Visit, TIntermLoop *node) +{ + if (!validateLoopType(node)) + return false; + + if (!validateForLoopHeader(node)) + return false; + + TIntermNode *body = node->getBody(); + if (body != nullptr) + { + mLoopSymbolIds.push_back(GetLoopSymbolId(node)); + body->traverse(this); + mLoopSymbolIds.pop_back(); + } + + // The loop is fully processed - no need to visit children. + return false; +} + +void ValidateLimitationsTraverser::error(TSourceLoc loc, const char *reason, const char *token) +{ + mDiagnostics->error(loc, reason, token); +} + +void ValidateLimitationsTraverser::error(TSourceLoc loc, + const char *reason, + const ImmutableString &token) +{ + error(loc, reason, token.data()); +} + +bool ValidateLimitationsTraverser::isLoopIndex(TIntermSymbol *symbol) +{ + return std::find(mLoopSymbolIds.begin(), mLoopSymbolIds.end(), symbol->uniqueId().get()) != + mLoopSymbolIds.end(); +} + +bool ValidateLimitationsTraverser::validateLoopType(TIntermLoop *node) +{ + TLoopType type = node->getType(); + if (type == ELoopFor) + return true; + + // Reject while and do-while loops. + error(node->getLine(), "This type of loop is not allowed", type == ELoopWhile ? "while" : "do"); + return false; +} + +bool ValidateLimitationsTraverser::validateForLoopHeader(TIntermLoop *node) +{ + ASSERT(node->getType() == ELoopFor); + + // + // The for statement has the form: + // for ( init-declaration ; condition ; expression ) statement + // + int indexSymbolId = validateForLoopInit(node); + if (indexSymbolId < 0) + return false; + if (!validateForLoopCond(node, indexSymbolId)) + return false; + if (!validateForLoopExpr(node, indexSymbolId)) + return false; + + return true; +} + +int ValidateLimitationsTraverser::validateForLoopInit(TIntermLoop *node) +{ + TIntermNode *init = node->getInit(); + if (init == nullptr) + { + error(node->getLine(), "Missing init declaration", "for"); + return -1; + } + + // + // init-declaration has the form: + // type-specifier identifier = constant-expression + // + TIntermDeclaration *decl = init->getAsDeclarationNode(); + if (decl == nullptr) + { + error(init->getLine(), "Invalid init declaration", "for"); + return -1; + } + // To keep things simple do not allow declaration list. + TIntermSequence *declSeq = decl->getSequence(); + if (declSeq->size() != 1) + { + error(decl->getLine(), "Invalid init declaration", "for"); + return -1; + } + TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode(); + if ((declInit == nullptr) || (declInit->getOp() != EOpInitialize)) + { + error(decl->getLine(), "Invalid init declaration", "for"); + return -1; + } + TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); + if (symbol == nullptr) + { + error(declInit->getLine(), "Invalid init declaration", "for"); + return -1; + } + // The loop index has type int or float. + TBasicType type = symbol->getBasicType(); + if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) + { + error(symbol->getLine(), "Invalid type for loop index", getBasicString(type)); + return -1; + } + // The loop index is initialized with constant expression. + if (!isConstExpr(declInit->getRight())) + { + error(declInit->getLine(), "Loop index cannot be initialized with non-constant expression", + symbol->getName()); + return -1; + } + + return symbol->uniqueId().get(); +} + +bool ValidateLimitationsTraverser::validateForLoopCond(TIntermLoop *node, int indexSymbolId) +{ + TIntermNode *cond = node->getCondition(); + if (cond == nullptr) + { + error(node->getLine(), "Missing condition", "for"); + return false; + } + // + // condition has the form: + // loop_index relational_operator constant_expression + // + TIntermBinary *binOp = cond->getAsBinaryNode(); + if (binOp == nullptr) + { + error(node->getLine(), "Invalid condition", "for"); + return false; + } + // Loop index should be to the left of relational operator. + TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode(); + if (symbol == nullptr) + { + error(binOp->getLine(), "Invalid condition", "for"); + return false; + } + if (symbol->uniqueId().get() != indexSymbolId) + { + error(symbol->getLine(), "Expected loop index", symbol->getName()); + return false; + } + // Relational operator is one of: > >= < <= == or !=. + switch (binOp->getOp()) + { + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + break; + default: + error(binOp->getLine(), "Invalid relational operator", + GetOperatorString(binOp->getOp())); + break; + } + // Loop index must be compared with a constant. + if (!isConstExpr(binOp->getRight())) + { + error(binOp->getLine(), "Loop index cannot be compared with non-constant expression", + symbol->getName()); + return false; + } + + return true; +} + +bool ValidateLimitationsTraverser::validateForLoopExpr(TIntermLoop *node, int indexSymbolId) +{ + TIntermNode *expr = node->getExpression(); + if (expr == nullptr) + { + error(node->getLine(), "Missing expression", "for"); + return false; + } + + // for expression has one of the following forms: + // loop_index++ + // loop_index-- + // loop_index += constant_expression + // loop_index -= constant_expression + // ++loop_index + // --loop_index + // The last two forms are not specified in the spec, but I am assuming + // its an oversight. + TIntermUnary *unOp = expr->getAsUnaryNode(); + TIntermBinary *binOp = unOp ? nullptr : expr->getAsBinaryNode(); + + TOperator op = EOpNull; + TIntermSymbol *symbol = nullptr; + if (unOp != nullptr) + { + op = unOp->getOp(); + symbol = unOp->getOperand()->getAsSymbolNode(); + } + else if (binOp != nullptr) + { + op = binOp->getOp(); + symbol = binOp->getLeft()->getAsSymbolNode(); + } + + // The operand must be loop index. + if (symbol == nullptr) + { + error(expr->getLine(), "Invalid expression", "for"); + return false; + } + if (symbol->uniqueId().get() != indexSymbolId) + { + error(symbol->getLine(), "Expected loop index", symbol->getName()); + return false; + } + + // The operator is one of: ++ -- += -=. + switch (op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + ASSERT((unOp != nullptr) && (binOp == nullptr)); + break; + case EOpAddAssign: + case EOpSubAssign: + ASSERT((unOp == nullptr) && (binOp != nullptr)); + break; + default: + error(expr->getLine(), "Invalid operator", GetOperatorString(op)); + return false; + } + + // Loop index must be incremented/decremented with a constant. + if (binOp != nullptr) + { + if (!isConstExpr(binOp->getRight())) + { + error(binOp->getLine(), "Loop index cannot be modified by non-constant expression", + symbol->getName()); + return false; + } + } + + return true; +} + +bool ValidateLimitationsTraverser::isConstExpr(TIntermNode *node) +{ + ASSERT(node != nullptr); + return node->getAsConstantUnion() != nullptr && node->getAsTyped()->getQualifier() == EvqConst; +} + +bool ValidateLimitationsTraverser::isConstIndexExpr(TIntermNode *node) +{ + ASSERT(node != nullptr); + + ValidateConstIndexExpr validate(mLoopSymbolIds); + node->traverse(&validate); + return validate.isValid(); +} + +bool ValidateLimitationsTraverser::validateIndexing(TIntermBinary *node) +{ + ASSERT((node->getOp() == EOpIndexDirect) || (node->getOp() == EOpIndexIndirect)); + + bool valid = true; + TIntermTyped *index = node->getRight(); + // The index expession must be a constant-index-expression unless + // the operand is a uniform in a vertex shader. + TIntermTyped *operand = node->getLeft(); + bool skip = (mShaderType == GL_VERTEX_SHADER) && (operand->getQualifier() == EvqUniform); + if (!skip && !isConstIndexExpr(index)) + { + error(index->getLine(), "Index expression must be constant", "[]"); + valid = false; + } + return valid; +} + +} // namespace + +bool ValidateLimitations(TIntermNode *root, + GLenum shaderType, + TSymbolTable *symbolTable, + TDiagnostics *diagnostics) +{ + ValidateLimitationsTraverser validate(shaderType, symbolTable, diagnostics); + root->traverse(&validate); + return diagnostics->numErrors() == 0; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.h b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.h new file mode 100644 index 0000000000..d219ed680a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateLimitations.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2010 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_VALIDATELIMITATIONS_H_ +#define COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +class TDiagnostics; + +// Returns true if the given shader does not exceed the minimum functionality mandated in GLSL ES +// 1.00 spec Appendix A. +bool ValidateLimitations(TIntermNode *root, + GLenum shaderType, + TSymbolTable *symbolTable, + TDiagnostics *diagnostics); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.cpp new file mode 100644 index 0000000000..a06babd3bd --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.cpp @@ -0,0 +1,30 @@ +// +// Copyright (c) 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. +// +// ValidateMaxParameters checks if function definitions have more than a set number of parameters. + +#include "compiler/translator/ValidateMaxParameters.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Symbol.h" + +namespace sh +{ + +bool ValidateMaxParameters(TIntermBlock *root, unsigned int maxParameters) +{ + for (TIntermNode *node : *root->getSequence()) + { + TIntermFunctionDefinition *definition = node->getAsFunctionDefinition(); + if (definition != nullptr && + definition->getFunctionPrototype()->getFunction()->getParamCount() > maxParameters) + { + return false; + } + } + return true; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.h b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.h new file mode 100644 index 0000000000..dec7597da4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateMaxParameters.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 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. +// +// ValidateMaxParameters checks if function definitions have more than a set number of parameters. + +#ifndef COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_ +#define COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_ + +namespace sh +{ + +class TIntermBlock; + +// Return true if valid. +bool ValidateMaxParameters(TIntermBlock *root, unsigned int maxParameters); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.cpp new file mode 100644 index 0000000000..98802554d6 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.cpp @@ -0,0 +1,184 @@ +// +// Copyright (c) 2013 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. +// +// ValidateOutputs validates fragment shader outputs. It checks for conflicting locations, +// out-of-range locations, that locations are specified when using multiple outputs, and YUV output +// validity. + +#include "compiler/translator/ValidateOutputs.h" + +#include <set> + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics) +{ + diagnostics->error(symbol.getLine(), reason, symbol.getName().data()); +} + +class ValidateOutputsTraverser : public TIntermTraverser +{ + public: + ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, int maxDrawBuffers); + + void validate(TDiagnostics *diagnostics) const; + + void visitSymbol(TIntermSymbol *) override; + + private: + int mMaxDrawBuffers; + bool mAllowUnspecifiedOutputLocationResolution; + bool mUsesFragDepth; + + typedef std::vector<TIntermSymbol *> OutputVector; + OutputVector mOutputs; + OutputVector mUnspecifiedLocationOutputs; + OutputVector mYuvOutputs; + std::set<int> mVisitedSymbols; // Visited symbol ids. +}; + +ValidateOutputsTraverser::ValidateOutputsTraverser(const TExtensionBehavior &extBehavior, + int maxDrawBuffers) + : TIntermTraverser(true, false, false), + mMaxDrawBuffers(maxDrawBuffers), + mAllowUnspecifiedOutputLocationResolution( + IsExtensionEnabled(extBehavior, TExtension::EXT_blend_func_extended)), + mUsesFragDepth(false) +{} + +void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol) +{ + if (symbol->variable().symbolType() == SymbolType::Empty) + return; + + if (mVisitedSymbols.count(symbol->uniqueId().get()) == 1) + return; + + mVisitedSymbols.insert(symbol->uniqueId().get()); + + TQualifier qualifier = symbol->getQualifier(); + if (qualifier == EvqFragmentOut) + { + if (symbol->getType().getLayoutQualifier().location != -1) + { + mOutputs.push_back(symbol); + } + else if (symbol->getType().getLayoutQualifier().yuv == true) + { + mYuvOutputs.push_back(symbol); + } + else + { + mUnspecifiedLocationOutputs.push_back(symbol); + } + } + else if (qualifier == EvqFragDepth || qualifier == EvqFragDepthEXT) + { + mUsesFragDepth = true; + } +} + +void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const +{ + ASSERT(diagnostics); + OutputVector validOutputs(mMaxDrawBuffers, nullptr); + OutputVector validSecondaryOutputs(mMaxDrawBuffers, nullptr); + + for (const auto &symbol : mOutputs) + { + const TType &type = symbol->getType(); + ASSERT(!type.isArrayOfArrays()); // Disallowed in GLSL ES 3.10 section 4.3.6. + const size_t elementCount = + static_cast<size_t>(type.isArray() ? type.getOutermostArraySize() : 1u); + const size_t location = static_cast<size_t>(type.getLayoutQualifier().location); + + ASSERT(type.getLayoutQualifier().location != -1); + + OutputVector *validOutputsToUse = &validOutputs; + // The default index is 0, so we only assign the output to secondary outputs in case the + // index is explicitly set to 1. + if (type.getLayoutQualifier().index == 1) + { + validOutputsToUse = &validSecondaryOutputs; + } + + if (location + elementCount <= validOutputsToUse->size()) + { + for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++) + { + const size_t offsetLocation = location + elementIndex; + if ((*validOutputsToUse)[offsetLocation]) + { + std::stringstream strstr = sh::InitializeStream<std::stringstream>(); + strstr << "conflicting output locations with previously defined output '" + << (*validOutputsToUse)[offsetLocation]->getName() << "'"; + error(*symbol, strstr.str().c_str(), diagnostics); + } + else + { + (*validOutputsToUse)[offsetLocation] = symbol; + } + } + } + else + { + if (elementCount > 0) + { + error(*symbol, + elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS" + : "output location must be < MAX_DRAW_BUFFERS", + diagnostics); + } + } + } + + if (!mAllowUnspecifiedOutputLocationResolution && + ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) || + mUnspecifiedLocationOutputs.size() > 1)) + { + for (const auto &symbol : mUnspecifiedLocationOutputs) + { + error(*symbol, + "must explicitly specify all locations when using multiple fragment outputs", + diagnostics); + } + } + + if (!mYuvOutputs.empty() && (mYuvOutputs.size() > 1 || mUsesFragDepth || !mOutputs.empty() || + !mUnspecifiedLocationOutputs.empty())) + { + for (const auto &symbol : mYuvOutputs) + { + error(*symbol, + "not allowed to specify yuv qualifier when using depth or multiple color " + "fragment outputs", + diagnostics); + } + } +} + +} // anonymous namespace + +bool ValidateOutputs(TIntermBlock *root, + const TExtensionBehavior &extBehavior, + int maxDrawBuffers, + TDiagnostics *diagnostics) +{ + ValidateOutputsTraverser validateOutputs(extBehavior, maxDrawBuffers); + root->traverse(&validateOutputs); + int numErrorsBefore = diagnostics->numErrors(); + validateOutputs.validate(diagnostics); + return (diagnostics->numErrors() == numErrorsBefore); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.h b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.h new file mode 100644 index 0000000000..e41ccd990c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateOutputs.h @@ -0,0 +1,30 @@ +// +// Copyright (c) 2013 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. +// +// ValidateOutputs validates fragment shader outputs. It checks for conflicting locations, +// out-of-range locations, that locations are specified when using multiple outputs, and YUV output +// validity. +// + +#ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ +#define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ + +#include "compiler/translator/ExtensionBehavior.h" + +namespace sh +{ + +class TIntermBlock; +class TDiagnostics; + +// Returns true if the shader has no conflicting or otherwise erroneous fragment outputs. +bool ValidateOutputs(TIntermBlock *root, + const TExtensionBehavior &extBehavior, + int maxDrawBuffers, + TDiagnostics *diagnostics); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.cpp new file mode 100644 index 0000000000..37c33a867c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.cpp @@ -0,0 +1,315 @@ +// +// Copyright (c) 2002-2015 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/ValidateSwitch.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +const int kMaxAllowedTraversalDepth = 256; + +class ValidateSwitch : public TIntermTraverser +{ + public: + static bool validate(TBasicType switchType, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc); + + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitDeclaration(Visit, TIntermDeclaration *) override; + bool visitBlock(Visit visit, TIntermBlock *) override; + bool visitBinary(Visit, TIntermBinary *) override; + bool visitUnary(Visit, TIntermUnary *) override; + bool visitTernary(Visit, TIntermTernary *) override; + bool visitSwizzle(Visit, TIntermSwizzle *) override; + bool visitIfElse(Visit visit, TIntermIfElse *) override; + bool visitSwitch(Visit, TIntermSwitch *) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit, TIntermBranch *) override; + + private: + ValidateSwitch(TBasicType switchType, TDiagnostics *context); + + bool validateInternal(const TSourceLoc &loc); + + TBasicType mSwitchType; + TDiagnostics *mDiagnostics; + bool mCaseTypeMismatch; + bool mFirstCaseFound; + bool mStatementBeforeCase; + bool mLastStatementWasCase; + int mControlFlowDepth; + bool mCaseInsideControlFlow; + int mDefaultCount; + std::set<int> mCasesSigned; + std::set<unsigned int> mCasesUnsigned; + bool mDuplicateCases; +}; + +bool ValidateSwitch::validate(TBasicType switchType, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc) +{ + ValidateSwitch validate(switchType, diagnostics); + ASSERT(statementList); + statementList->traverse(&validate); + return validate.validateInternal(loc); +} + +ValidateSwitch::ValidateSwitch(TBasicType switchType, TDiagnostics *diagnostics) + : TIntermTraverser(true, false, true, nullptr), + mSwitchType(switchType), + mDiagnostics(diagnostics), + mCaseTypeMismatch(false), + mFirstCaseFound(false), + mStatementBeforeCase(false), + mLastStatementWasCase(false), + mControlFlowDepth(0), + mCaseInsideControlFlow(false), + mDefaultCount(0), + mDuplicateCases(false) +{ + setMaxAllowedDepth(kMaxAllowedTraversalDepth); +} + +void ValidateSwitch::visitSymbol(TIntermSymbol *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; +} + +void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *) +{ + // Conditions of case labels are not traversed, so this is some other constant + // Could be just a statement like "0;" + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; +} + +bool ValidateSwitch::visitDeclaration(Visit, TIntermDeclaration *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitBlock(Visit visit, TIntermBlock *) +{ + if (getParentNode() != nullptr) + { + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + if (visit == PreVisit) + ++mControlFlowDepth; + if (visit == PostVisit) + --mControlFlowDepth; + } + return true; +} + +bool ValidateSwitch::visitBinary(Visit, TIntermBinary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitUnary(Visit, TIntermUnary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitTernary(Visit, TIntermTernary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitSwizzle(Visit, TIntermSwizzle *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitIfElse(Visit visit, TIntermIfElse *) +{ + if (visit == PreVisit) + ++mControlFlowDepth; + if (visit == PostVisit) + --mControlFlowDepth; + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + // Don't go into nested switch statements + return false; +} + +bool ValidateSwitch::visitCase(Visit, TIntermCase *node) +{ + const char *nodeStr = node->hasCondition() ? "case" : "default"; + if (mControlFlowDepth > 0) + { + mDiagnostics->error(node->getLine(), "label statement nested inside control flow", nodeStr); + mCaseInsideControlFlow = true; + } + mFirstCaseFound = true; + mLastStatementWasCase = true; + if (!node->hasCondition()) + { + ++mDefaultCount; + if (mDefaultCount > 1) + { + mDiagnostics->error(node->getLine(), "duplicate default label", nodeStr); + } + } + else + { + TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion(); + if (condition == nullptr) + { + // This can happen in error cases. + return false; + } + TBasicType conditionType = condition->getBasicType(); + if (conditionType != mSwitchType) + { + mDiagnostics->error(condition->getLine(), + "case label type does not match switch init-expression type", + nodeStr); + mCaseTypeMismatch = true; + } + + if (conditionType == EbtInt) + { + int iConst = condition->getIConst(0); + if (mCasesSigned.find(iConst) != mCasesSigned.end()) + { + mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr); + mDuplicateCases = true; + } + else + { + mCasesSigned.insert(iConst); + } + } + else if (conditionType == EbtUInt) + { + unsigned int uConst = condition->getUConst(0); + if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end()) + { + mDiagnostics->error(condition->getLine(), "duplicate case label", nodeStr); + mDuplicateCases = true; + } + else + { + mCasesUnsigned.insert(uConst); + } + } + // Other types are possible only in error cases, where the error has already been generated + // when parsing the case statement. + } + // Don't traverse the condition of the case statement + return false; +} + +bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *) +{ + if (getParentNode() != nullptr) + { + // This is not the statementList node, but some other node. + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + } + return true; +} + +bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *) +{ + if (visit == PreVisit) + ++mControlFlowDepth; + if (visit == PostVisit) + --mControlFlowDepth; + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitBranch(Visit, TIntermBranch *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::validateInternal(const TSourceLoc &loc) +{ + if (mStatementBeforeCase) + { + mDiagnostics->error(loc, "statement before the first label", "switch"); + } + if (mLastStatementWasCase) + { + // There have been some differences between versions of GLSL ES specs on whether this should + // be an error or not, but as of early 2018 the latest discussion is that this is an error + // also on GLSL ES versions newer than 3.00. + mDiagnostics->error( + loc, "no statement between the last label and the end of the switch statement", + "switch"); + } + if (getMaxDepth() >= kMaxAllowedTraversalDepth) + { + mDiagnostics->error(loc, "too complex expressions inside a switch statement", "switch"); + } + return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow && + !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases && + getMaxDepth() < kMaxAllowedTraversalDepth; +} + +} // anonymous namespace + +bool ValidateSwitchStatementList(TBasicType switchType, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc) +{ + return ValidateSwitch::validate(switchType, diagnostics, statementList, loc); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.h b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.h new file mode 100644 index 0000000000..757820a164 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateSwitch.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 2002-2015 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_VALIDATESWITCH_H_ +#define COMPILER_TRANSLATOR_VALIDATESWITCH_H_ + +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" + +namespace sh +{ +class TDiagnostics; +class TIntermBlock; + +// Check for errors and output error messages on the context. +// Returns true if there are no errors. +bool ValidateSwitchStatementList(TBasicType switchType, + TDiagnostics *diagnostics, + TIntermBlock *statementList, + const TSourceLoc &loc); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.cpp new file mode 100644 index 0000000000..394e35c8d8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.cpp @@ -0,0 +1,179 @@ +// +// Copyright (c) 2002-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. +// +// The ValidateVaryingLocations function checks if there exists location conflicts on shader +// varyings. +// + +#include "ValidateVaryingLocations.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics) +{ + diagnostics->error(symbol.getLine(), reason, symbol.getName().data()); +} + +int GetLocationCount(const TIntermSymbol *varying, bool ignoreVaryingArraySize) +{ + const auto &varyingType = varying->getType(); + if (varyingType.getStruct() != nullptr) + { + ASSERT(!varyingType.isArray()); + int totalLocation = 0; + for (const auto *field : varyingType.getStruct()->fields()) + { + const auto *fieldType = field->type(); + ASSERT(fieldType->getStruct() == nullptr && !fieldType->isArray()); + + totalLocation += fieldType->getSecondarySize(); + } + return totalLocation; + } + // [GL_EXT_shader_io_blocks SPEC Chapter 4.4.1] + // Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation + // evaluation inputs all have an additional level of arrayness relative to other shader inputs + // and outputs. This outer array level is removed from the type before considering how many + // locations the type consumes. + else if (ignoreVaryingArraySize) + { + // Array-of-arrays cannot be inputs or outputs of a geometry shader. + // (GL_EXT_geometry_shader SPEC issues(5)) + ASSERT(!varyingType.isArrayOfArrays()); + return varyingType.getSecondarySize(); + } + else + { + return varyingType.getSecondarySize() * static_cast<int>(varyingType.getArraySizeProduct()); + } +} + +using VaryingVector = std::vector<const TIntermSymbol *>; + +void ValidateShaderInterface(TDiagnostics *diagnostics, + VaryingVector &varyingVector, + bool ignoreVaryingArraySize) +{ + // Location conflicts can only happen when there are two or more varyings in varyingVector. + if (varyingVector.size() <= 1) + { + return; + } + + std::map<int, const TIntermSymbol *> locationMap; + for (const TIntermSymbol *varying : varyingVector) + { + const int location = varying->getType().getLayoutQualifier().location; + ASSERT(location >= 0); + + const int elementCount = GetLocationCount(varying, ignoreVaryingArraySize); + for (int elementIndex = 0; elementIndex < elementCount; ++elementIndex) + { + const int offsetLocation = location + elementIndex; + if (locationMap.find(offsetLocation) != locationMap.end()) + { + std::stringstream strstr = sh::InitializeStream<std::stringstream>(); + strstr << "'" << varying->getName() + << "' conflicting location with previously defined '" + << locationMap[offsetLocation]->getName() << "'"; + error(*varying, strstr.str().c_str(), diagnostics); + } + else + { + locationMap[offsetLocation] = varying; + } + } + } +} + +class ValidateVaryingLocationsTraverser : public TIntermTraverser +{ + public: + ValidateVaryingLocationsTraverser(GLenum shaderType); + void validate(TDiagnostics *diagnostics); + + private: + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + + VaryingVector mInputVaryingsWithLocation; + VaryingVector mOutputVaryingsWithLocation; + GLenum mShaderType; +}; + +ValidateVaryingLocationsTraverser::ValidateVaryingLocationsTraverser(GLenum shaderType) + : TIntermTraverser(true, false, false), mShaderType(shaderType) +{} + +bool ValidateVaryingLocationsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + const TIntermSequence &sequence = *(node->getSequence()); + ASSERT(!sequence.empty()); + + const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode(); + if (symbol == nullptr) + { + return false; + } + + if (symbol->variable().symbolType() == SymbolType::Empty) + { + return false; + } + + // Collect varyings that have explicit 'location' qualifiers. + const TQualifier qualifier = symbol->getQualifier(); + if (symbol->getType().getLayoutQualifier().location != -1) + { + if (IsVaryingIn(qualifier)) + { + mInputVaryingsWithLocation.push_back(symbol); + } + else if (IsVaryingOut(qualifier)) + { + mOutputVaryingsWithLocation.push_back(symbol); + } + } + + return false; +} + +bool ValidateVaryingLocationsTraverser::visitFunctionDefinition(Visit visit, + TIntermFunctionDefinition *node) +{ + // We stop traversing function definitions because varyings cannot be defined in a function. + return false; +} + +void ValidateVaryingLocationsTraverser::validate(TDiagnostics *diagnostics) +{ + ASSERT(diagnostics); + + ValidateShaderInterface(diagnostics, mInputVaryingsWithLocation, + mShaderType == GL_GEOMETRY_SHADER_EXT); + ValidateShaderInterface(diagnostics, mOutputVaryingsWithLocation, false); +} + +} // anonymous namespace + +bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics, GLenum shaderType) +{ + ValidateVaryingLocationsTraverser varyingValidator(shaderType); + root->traverse(&varyingValidator); + int numErrorsBefore = diagnostics->numErrors(); + varyingValidator.validate(diagnostics); + return (diagnostics->numErrors() == numErrorsBefore); +} + +} // namespace sh
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.h b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.h new file mode 100644 index 0000000000..1e53977c68 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/ValidateVaryingLocations.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2002-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. +// +// The ValidateVaryingLocations function checks if there exists location conflicts on shader +// varyings. +// + +#ifndef COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_ +#define COMPILER_TRANSLATOR_VALIDATEVARYINGLOCATIONS_H_ + +#include "GLSLANG/ShaderVars.h" + +namespace sh +{ + +class TIntermBlock; +class TDiagnostics; + +bool ValidateVaryingLocations(TIntermBlock *root, TDiagnostics *diagnostics, GLenum shaderType); + +} // namespace sh + +#endif
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/VariablePacker.cpp b/gfx/angle/checkout/src/compiler/translator/VariablePacker.cpp new file mode 100644 index 0000000000..123da4b35e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/VariablePacker.cpp @@ -0,0 +1,413 @@ +// +// Copyright (c) 2002-2012 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. +// +// Check whether variables fit within packing limits according to the packing rules from the GLSL ES +// 1.00.17 spec, Appendix A, section 7. + +#include <algorithm> + +#include "angle_gl.h" + +#include "common/utilities.h" +#include "compiler/translator/VariablePacker.h" + +namespace sh +{ + +namespace +{ + +// Expand the variable so that struct variables are split into their individual fields. +// Will not set the mappedName or staticUse fields on the expanded variables. +void ExpandVariable(const ShaderVariable &variable, + const std::string &name, + std::vector<ShaderVariable> *expanded); + +void ExpandStructVariable(const ShaderVariable &variable, + const std::string &name, + std::vector<ShaderVariable> *expanded) +{ + ASSERT(variable.isStruct()); + + const std::vector<ShaderVariable> &fields = variable.fields; + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const ShaderVariable &field = fields[fieldIndex]; + ExpandVariable(field, name + "." + field.name, expanded); + } +} + +void ExpandStructArrayVariable(const ShaderVariable &variable, + unsigned int arrayNestingIndex, + const std::string &name, + std::vector<ShaderVariable> *expanded) +{ + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. + const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex); + for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement) + { + const std::string elementName = name + ArrayString(arrayElement); + if (arrayNestingIndex + 1u < variable.arraySizes.size()) + { + ExpandStructArrayVariable(variable, arrayNestingIndex + 1u, elementName, expanded); + } + else + { + ExpandStructVariable(variable, elementName, expanded); + } + } +} + +void ExpandVariable(const ShaderVariable &variable, + const std::string &name, + std::vector<ShaderVariable> *expanded) +{ + if (variable.isStruct()) + { + if (variable.isArray()) + { + ExpandStructArrayVariable(variable, 0u, name, expanded); + } + else + { + ExpandStructVariable(variable, name, expanded); + } + } + else + { + ShaderVariable expandedVar = variable; + expandedVar.name = name; + + expanded->push_back(expandedVar); + } +} + +int GetVariablePackingRows(const ShaderVariable &variable) +{ + return GetTypePackingRows(variable.type) * variable.getArraySizeProduct(); +} + +class VariablePacker +{ + public: + bool checkExpandedVariablesWithinPackingLimits(unsigned int maxVectors, + std::vector<sh::ShaderVariable> *variables); + + private: + static const int kNumColumns = 4; + static const unsigned kColumnMask = (1 << kNumColumns) - 1; + + unsigned makeColumnFlags(int column, int numComponentsPerRow); + void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); + bool searchColumn(int column, int numRows, int *destRow, int *destSize); + + int topNonFullRow_; + int bottomNonFullRow_; + int maxRows_; + std::vector<unsigned> rows_; +}; + +struct TVariableInfoComparer +{ + bool operator()(const sh::ShaderVariable &lhs, const sh::ShaderVariable &rhs) const + { + int lhsSortOrder = gl::VariableSortOrder(lhs.type); + int rhsSortOrder = gl::VariableSortOrder(rhs.type); + if (lhsSortOrder != rhsSortOrder) + { + return lhsSortOrder < rhsSortOrder; + } + // Sort by largest first. + return lhs.getArraySizeProduct() > rhs.getArraySizeProduct(); + } +}; + +unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow) +{ + return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & kColumnMask) >> column; +} + +void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow) +{ + unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow); + for (int r = 0; r < numRows; ++r) + { + int row = topRow + r; + ASSERT((rows_[row] & columnFlags) == 0); + rows_[row] |= columnFlags; + } +} + +bool VariablePacker::searchColumn(int column, int numRows, int *destRow, int *destSize) +{ + ASSERT(destRow); + + for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; ++topNonFullRow_) + { + } + + for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; --bottomNonFullRow_) + { + } + + if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) + { + return false; + } + + unsigned columnFlags = makeColumnFlags(column, 1); + int topGoodRow = 0; + int smallestGoodTop = -1; + int smallestGoodSize = maxRows_ + 1; + int bottomRow = bottomNonFullRow_ + 1; + bool found = false; + for (int row = topNonFullRow_; row <= bottomRow; ++row) + { + bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false; + if (rowEmpty) + { + if (!found) + { + topGoodRow = row; + found = true; + } + } + else + { + if (found) + { + int size = row - topGoodRow; + if (size >= numRows && size < smallestGoodSize) + { + smallestGoodSize = size; + smallestGoodTop = topGoodRow; + } + } + found = false; + } + } + if (smallestGoodTop < 0) + { + return false; + } + + *destRow = smallestGoodTop; + if (destSize) + { + *destSize = smallestGoodSize; + } + return true; +} + +bool VariablePacker::checkExpandedVariablesWithinPackingLimits( + unsigned int maxVectors, + std::vector<sh::ShaderVariable> *variables) +{ + ASSERT(maxVectors > 0); + maxRows_ = maxVectors; + topNonFullRow_ = 0; + bottomNonFullRow_ = maxRows_ - 1; + + // Check whether each variable fits in the available vectors. + for (const sh::ShaderVariable &variable : *variables) + { + // Structs should have been expanded before reaching here. + ASSERT(!variable.isStruct()); + if (variable.getArraySizeProduct() > maxVectors / GetTypePackingRows(variable.type)) + { + return false; + } + } + + // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific + // order by type, then by size of array, largest first. + std::sort(variables->begin(), variables->end(), TVariableInfoComparer()); + rows_.clear(); + rows_.resize(maxVectors, 0); + + // Packs the 4 column variables. + size_t ii = 0; + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + if (GetTypePackingComponentsPerRow(variable.type) != 4) + { + break; + } + topNonFullRow_ += GetVariablePackingRows(variable); + } + + if (topNonFullRow_ > maxRows_) + { + return false; + } + + // Packs the 3 column variables. + int num3ColumnRows = 0; + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + if (GetTypePackingComponentsPerRow(variable.type) != 3) + { + break; + } + num3ColumnRows += GetVariablePackingRows(variable); + } + + if (topNonFullRow_ + num3ColumnRows > maxRows_) + { + return false; + } + + fillColumns(topNonFullRow_, num3ColumnRows, 0, 3); + + // Packs the 2 column variables. + int top2ColumnRow = topNonFullRow_ + num3ColumnRows; + int twoColumnRowsAvailable = maxRows_ - top2ColumnRow; + int rowsAvailableInColumns01 = twoColumnRowsAvailable; + int rowsAvailableInColumns23 = twoColumnRowsAvailable; + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + if (GetTypePackingComponentsPerRow(variable.type) != 2) + { + break; + } + int numRows = GetVariablePackingRows(variable); + if (numRows <= rowsAvailableInColumns01) + { + rowsAvailableInColumns01 -= numRows; + } + else if (numRows <= rowsAvailableInColumns23) + { + rowsAvailableInColumns23 -= numRows; + } + else + { + return false; + } + } + + int numRowsUsedInColumns01 = twoColumnRowsAvailable - rowsAvailableInColumns01; + int numRowsUsedInColumns23 = twoColumnRowsAvailable - rowsAvailableInColumns23; + fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2); + fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, 2, 2); + + // Packs the 1 column variables. + for (; ii < variables->size(); ++ii) + { + const sh::ShaderVariable &variable = (*variables)[ii]; + ASSERT(1 == GetTypePackingComponentsPerRow(variable.type)); + int numRows = GetVariablePackingRows(variable); + int smallestColumn = -1; + int smallestSize = maxRows_ + 1; + int topRow = -1; + for (int column = 0; column < kNumColumns; ++column) + { + int row = 0; + int size = 0; + if (searchColumn(column, numRows, &row, &size)) + { + if (size < smallestSize) + { + smallestSize = size; + smallestColumn = column; + topRow = row; + } + } + } + + if (smallestColumn < 0) + { + return false; + } + + fillColumns(topRow, numRows, smallestColumn, 1); + } + + ASSERT(variables->size() == ii); + + return true; +} + +} // anonymous namespace + +int GetTypePackingComponentsPerRow(sh::GLenum type) +{ + switch (type) + { + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_BOOL_VEC4: + case GL_UNSIGNED_INT_VEC4: + return 4; + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_BOOL_VEC3: + case GL_UNSIGNED_INT_VEC3: + return 3; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_BOOL_VEC2: + case GL_UNSIGNED_INT_VEC2: + return 2; + default: + ASSERT(gl::VariableComponentCount(type) == 1); + return 1; + } +} + +int GetTypePackingRows(sh::GLenum type) +{ + switch (type) + { + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x3: + case GL_FLOAT_MAT4x2: + return 4; + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + return 3; + case GL_FLOAT_MAT2: + return 2; + default: + ASSERT(gl::VariableRowCount(type) == 1); + return 1; + } +} + +template <typename T> +bool CheckVariablesInPackingLimits(unsigned int maxVectors, const std::vector<T> &variables) +{ + VariablePacker packer; + std::vector<sh::ShaderVariable> expandedVariables; + for (const ShaderVariable &variable : variables) + { + ExpandVariable(variable, variable.name, &expandedVariables); + } + return packer.checkExpandedVariablesWithinPackingLimits(maxVectors, &expandedVariables); +} + +template bool CheckVariablesInPackingLimits<ShaderVariable>( + unsigned int maxVectors, + const std::vector<ShaderVariable> &variables); +template bool CheckVariablesInPackingLimits<Uniform>(unsigned int maxVectors, + const std::vector<Uniform> &variables); + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/VariablePacker.h b/gfx/angle/checkout/src/compiler/translator/VariablePacker.h new file mode 100644 index 0000000000..36b2104cd0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/VariablePacker.h @@ -0,0 +1,32 @@ +// +// Copyright (c) 2002-2012 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. +// +// Check whether variables fit within packing limits according to the packing rules from the GLSL ES +// 1.00.17 spec, Appendix A, section 7. + +#ifndef COMPILER_TRANSLATOR_VARIABLEPACKER_H_ +#define COMPILER_TRANSLATOR_VARIABLEPACKER_H_ + +#include <vector> + +#include <GLSLANG/ShaderLang.h> + +namespace sh +{ + +// Gets how many components in a row a data type takes. +int GetTypePackingComponentsPerRow(sh::GLenum type); + +// Gets how many rows a data type takes. +int GetTypePackingRows(sh::GLenum type); + +// Returns true if the passed in variables pack in maxVectors. +// T should be ShaderVariable or one of the subclasses of ShaderVariable. +template <typename T> +bool CheckVariablesInPackingLimits(unsigned int maxVectors, const std::vector<T> &variables); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/VersionGLSL.cpp b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.cpp new file mode 100644 index 0000000000..eb431c3117 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.cpp @@ -0,0 +1,149 @@ +// +// Copyright (c) 2002-2012 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/VersionGLSL.h" + +#include "angle_gl.h" +#include "compiler/translator/Symbol.h" + +namespace sh +{ + +namespace +{ +constexpr const ImmutableString kGlPointCoordString("gl_PointCoord"); +} // anonymous namespace + +int ShaderOutputTypeToGLSLVersion(ShShaderOutput output) +{ + switch (output) + { + case SH_GLSL_130_OUTPUT: + return GLSL_VERSION_130; + case SH_GLSL_140_OUTPUT: + return GLSL_VERSION_140; + case SH_GLSL_150_CORE_OUTPUT: + return GLSL_VERSION_150; + case SH_GLSL_330_CORE_OUTPUT: + return GLSL_VERSION_330; + case SH_GLSL_400_CORE_OUTPUT: + return GLSL_VERSION_400; + case SH_GLSL_410_CORE_OUTPUT: + return GLSL_VERSION_410; + case SH_GLSL_420_CORE_OUTPUT: + return GLSL_VERSION_420; + case SH_GLSL_430_CORE_OUTPUT: + return GLSL_VERSION_430; + case SH_GLSL_440_CORE_OUTPUT: + return GLSL_VERSION_440; + case SH_GLSL_450_CORE_OUTPUT: + return GLSL_VERSION_450; + case SH_GLSL_COMPATIBILITY_OUTPUT: + return GLSL_VERSION_110; + default: + UNREACHABLE(); + return 0; + } +} + +// We need to scan for the following: +// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders +// but only at the global scope. +// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader +// but inside any scope. +// 3. Call to a matrix constructor with another matrix as argument. +// (These constructors were reserved in GLSL version 1.10.) +// 4. Arrays as "out" function parameters. +// GLSL spec section 6.1.1: "When calling a function, expressions that do +// not evaluate to l-values cannot be passed to parameters declared as +// out or inout." +// GLSL 1.1 section 5.8: "Other binary or unary expressions, +// non-dereferenced arrays, function names, swizzles with repeated fields, +// and constants cannot be l-values." +// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that +// are built-in types, entire structures or arrays... are all l-values." +// +TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output) + : TIntermTraverser(true, false, false) +{ + mVersion = ShaderOutputTypeToGLSLVersion(output); + if (pragma.stdgl.invariantAll) + { + ensureVersionIsAtLeast(GLSL_VERSION_120); + } + if (type == GL_COMPUTE_SHADER) + { + ensureVersionIsAtLeast(GLSL_VERSION_430); + } +} + +void TVersionGLSL::visitSymbol(TIntermSymbol *node) +{ + if (node->variable().symbolType() == SymbolType::BuiltIn && + node->getName() == kGlPointCoordString) + { + ensureVersionIsAtLeast(GLSL_VERSION_120); + } +} + +bool TVersionGLSL::visitDeclaration(Visit, TIntermDeclaration *node) +{ + const TIntermSequence &sequence = *(node->getSequence()); + if (sequence.front()->getAsTyped()->getType().isInvariant()) + { + ensureVersionIsAtLeast(GLSL_VERSION_120); + } + return true; +} + +bool TVersionGLSL::visitInvariantDeclaration(Visit, TIntermInvariantDeclaration *node) +{ + ensureVersionIsAtLeast(GLSL_VERSION_120); + return true; +} + +void TVersionGLSL::visitFunctionPrototype(TIntermFunctionPrototype *node) +{ + size_t paramCount = node->getFunction()->getParamCount(); + for (size_t i = 0; i < paramCount; ++i) + { + const TVariable *param = node->getFunction()->getParam(i); + const TType &type = param->getType(); + if (type.isArray()) + { + TQualifier qualifier = type.getQualifier(); + if ((qualifier == EvqOut) || (qualifier == EvqInOut)) + { + ensureVersionIsAtLeast(GLSL_VERSION_120); + break; + } + } + } +} + +bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node) +{ + if (node->getOp() == EOpConstruct && node->getType().isMatrix()) + { + const TIntermSequence &sequence = *(node->getSequence()); + if (sequence.size() == 1) + { + TIntermTyped *typed = sequence.front()->getAsTyped(); + if (typed && typed->isMatrix()) + { + ensureVersionIsAtLeast(GLSL_VERSION_120); + } + } + } + return true; +} + +void TVersionGLSL::ensureVersionIsAtLeast(int version) +{ + mVersion = std::max(version, mVersion); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/VersionGLSL.h b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.h new file mode 100644 index 0000000000..f05da966f4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/VersionGLSL.h @@ -0,0 +1,76 @@ +// +// Copyright (c) 2002-2013 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_VERSIONGLSL_H_ +#define COMPILER_TRANSLATOR_VERSIONGLSL_H_ + +#include "compiler/translator/tree_util/IntermTraverse.h" + +#include "compiler/translator/Pragma.h" + +namespace sh +{ + +static const int GLSL_VERSION_110 = 110; +static const int GLSL_VERSION_120 = 120; +static const int GLSL_VERSION_130 = 130; +static const int GLSL_VERSION_140 = 140; +static const int GLSL_VERSION_150 = 150; +static const int GLSL_VERSION_330 = 330; +static const int GLSL_VERSION_400 = 400; +static const int GLSL_VERSION_410 = 410; +static const int GLSL_VERSION_420 = 420; +static const int GLSL_VERSION_430 = 430; +static const int GLSL_VERSION_440 = 440; +static const int GLSL_VERSION_450 = 450; + +int ShaderOutputTypeToGLSLVersion(ShShaderOutput output); + +// Traverses the intermediate tree to return the minimum GLSL version +// required to legally access all built-in features used in the shader. +// GLSL 1.1 which is mandated by OpenGL 2.0 provides: +// - #version and #extension to declare version and extensions. +// - built-in functions refract, exp, and log. +// - updated step() to compare x < edge instead of x <= edge. +// GLSL 1.2 which is mandated by OpenGL 2.1 provides: +// - many changes to reduce differences when compared to the ES specification. +// - invariant keyword and its support. +// - c++ style name hiding rules. +// - built-in variable gl_PointCoord for fragment shaders. +// - matrix constructors taking matrix as argument. +// - array as "out" function parameters +// +// TODO: ES3 equivalent versions of GLSL +class TVersionGLSL : public TIntermTraverser +{ + public: + TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output); + + // If output is core profile, returns 150. + // If output is legacy profile, + // Returns 120 if the following is used the shader: + // - "invariant", + // - "gl_PointCoord", + // - matrix/matrix constructors + // - array "out" parameters + // Else 110 is returned. + int getVersion() const { return mVersion; } + + void visitSymbol(TIntermSymbol *node) override; + bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitInvariantDeclaration(Visit, TIntermInvariantDeclaration *node) override; + void visitFunctionPrototype(TIntermFunctionPrototype *node) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; + + private: + void ensureVersionIsAtLeast(int version); + + int mVersion; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_VERSIONGLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayout.cpp b/gfx/angle/checkout/src/compiler/translator/blocklayout.cpp new file mode 100644 index 0000000000..7d0609ec82 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/blocklayout.cpp @@ -0,0 +1,606 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.cpp: +// Implementation for block layout classes and methods. +// + +#include "compiler/translator/blocklayout.h" + +#include "common/mathutil.h" +#include "common/utilities.h" +#include "compiler/translator/Common.h" + +namespace sh +{ + +namespace +{ +class BlockLayoutMapVisitor : public BlockEncoderVisitor +{ + public: + BlockLayoutMapVisitor(BlockLayoutMap *blockInfoOut, + const std::string &instanceName, + BlockLayoutEncoder *encoder) + : BlockEncoderVisitor(instanceName, instanceName, encoder), mInfoOut(blockInfoOut) + {} + + void encodeVariable(const ShaderVariable &variable, + const BlockMemberInfo &variableInfo, + const std::string &name, + const std::string &mappedName) override + { + ASSERT(!gl::IsSamplerType(variable.type)); + (*mInfoOut)[name] = variableInfo; + } + + private: + BlockLayoutMap *mInfoOut; +}; + +template <typename VarT> +void GetInterfaceBlockInfo(const std::vector<VarT> &fields, + const std::string &prefix, + BlockLayoutEncoder *encoder, + bool inRowMajorLayout, + BlockLayoutMap *blockInfoOut) +{ + BlockLayoutMapVisitor visitor(blockInfoOut, prefix, encoder); + TraverseShaderVariables(fields, inRowMajorLayout, &visitor); +} + +void TraverseStructVariable(const ShaderVariable &variable, + bool isRowMajorLayout, + ShaderVariableVisitor *visitor) +{ + const std::vector<ShaderVariable> &fields = variable.fields; + + visitor->enterStructAccess(variable, isRowMajorLayout); + TraverseShaderVariables(fields, isRowMajorLayout, visitor); + visitor->exitStructAccess(variable, isRowMajorLayout); +} + +void TraverseStructArrayVariable(const ShaderVariable &variable, + bool inRowMajorLayout, + ShaderVariableVisitor *visitor) +{ + visitor->enterArray(variable); + + // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the + // innermost. We make a special case for unsized arrays. + const unsigned int currentArraySize = variable.getNestedArraySize(0); + unsigned int count = std::max(currentArraySize, 1u); + for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement) + { + visitor->enterArrayElement(variable, arrayElement); + ShaderVariable elementVar = variable; + elementVar.indexIntoArray(arrayElement); + + if (variable.arraySizes.size() > 1u) + { + TraverseStructArrayVariable(elementVar, inRowMajorLayout, visitor); + } + else + { + TraverseStructVariable(elementVar, inRowMajorLayout, visitor); + } + + visitor->exitArrayElement(variable, arrayElement); + } + + visitor->exitArray(variable); +} + +void TraverseArrayOfArraysVariable(const ShaderVariable &variable, + unsigned int arrayNestingIndex, + bool isRowMajorMatrix, + ShaderVariableVisitor *visitor) +{ + visitor->enterArray(variable); + + const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex); + unsigned int count = std::max(currentArraySize, 1u); + for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement) + { + visitor->enterArrayElement(variable, arrayElement); + + ShaderVariable elementVar = variable; + elementVar.indexIntoArray(arrayElement); + + if (arrayNestingIndex + 2u < variable.arraySizes.size()) + { + TraverseArrayOfArraysVariable(elementVar, arrayNestingIndex, isRowMajorMatrix, visitor); + } + else + { + if (gl::IsSamplerType(variable.type)) + { + visitor->visitSampler(elementVar); + } + else + { + visitor->visitVariable(elementVar, isRowMajorMatrix); + } + } + + visitor->exitArrayElement(variable, arrayElement); + } + + visitor->exitArray(variable); +} + +std::string CollapseNameStack(const std::vector<std::string> &nameStack) +{ + std::stringstream strstr = sh::InitializeStream<std::stringstream>(); + for (const std::string &part : nameStack) + { + strstr << part; + } + return strstr.str(); +} + +size_t GetStd430BaseAlignment(GLenum variableType, bool isRowMajor) +{ + GLenum flippedType = isRowMajor ? variableType : gl::TransposeMatrixType(variableType); + size_t numComponents = static_cast<size_t>(gl::VariableColumnCount(flippedType)); + return ComponentAlignment(numComponents); +} + +class BaseAlignmentVisitor : public ShaderVariableVisitor +{ + public: + BaseAlignmentVisitor() = default; + void visitVariable(const ShaderVariable &variable, bool isRowMajor) override + { + size_t baseAlignment = GetStd430BaseAlignment(variable.type, isRowMajor); + mCurrentAlignment = std::max(mCurrentAlignment, baseAlignment); + } + + // This is in components rather than bytes. + size_t getBaseAlignment() const { return mCurrentAlignment; } + + private: + size_t mCurrentAlignment = 0; +}; +} // anonymous namespace + +// BlockLayoutEncoder implementation. +BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0) {} + +BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix) +{ + int arrayStride; + int matrixStride; + + getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride); + + const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * kBytesPerComponent), + static_cast<int>(arrayStride * kBytesPerComponent), + static_cast<int>(matrixStride * kBytesPerComponent), + isRowMajorMatrix); + + advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride); + + return memberInfo; +} + +size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor) +{ + size_t currentOffset = mCurrentOffset; + mCurrentOffset = 0; + BlockEncoderVisitor visitor("", "", this); + enterAggregateType(structVar); + TraverseShaderVariables(structVar.fields, isRowMajor, &visitor); + exitAggregateType(structVar); + size_t structVarSize = getCurrentOffset(); + mCurrentOffset = currentOffset; + return structVarSize; +} + +// static +size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info) +{ + return (info.offset / kBytesPerComponent) / kComponentsPerRegister; +} + +// static +size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info) +{ + return (info.offset / kBytesPerComponent) % kComponentsPerRegister; +} + +void BlockLayoutEncoder::align(size_t baseAlignment) +{ + mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, baseAlignment); +} + +// DummyBlockEncoder implementation. +void DummyBlockEncoder::getBlockLayoutInfo(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) +{ + *arrayStrideOut = 0; + *matrixStrideOut = 0; +} + +// Std140BlockEncoder implementation. +Std140BlockEncoder::Std140BlockEncoder() {} + +void Std140BlockEncoder::enterAggregateType(const ShaderVariable &structVar) +{ + align(getBaseAlignment(structVar)); +} + +void Std140BlockEncoder::exitAggregateType(const ShaderVariable &structVar) +{ + align(getBaseAlignment(structVar)); +} + +void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) +{ + // We assume we are only dealing with 4 byte components (no doubles or half-words currently) + ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent); + + size_t baseAlignment = 0; + int matrixStride = 0; + int arrayStride = 0; + + if (gl::IsMatrixType(type)) + { + baseAlignment = getTypeBaseAlignment(type, isRowMajorMatrix); + matrixStride = getTypeBaseAlignment(type, isRowMajorMatrix); + + if (!arraySizes.empty()) + { + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + arrayStride = getTypeBaseAlignment(type, isRowMajorMatrix) * numRegisters; + } + } + else if (!arraySizes.empty()) + { + baseAlignment = getTypeBaseAlignment(type, false); + arrayStride = getTypeBaseAlignment(type, false); + } + else + { + const size_t numComponents = static_cast<size_t>(gl::VariableComponentCount(type)); + baseAlignment = ComponentAlignment(numComponents); + } + + mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); + + *matrixStrideOut = matrixStride; + *arrayStrideOut = arrayStride; +} + +void Std140BlockEncoder::advanceOffset(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) +{ + if (!arraySizes.empty()) + { + mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes); + } + else if (gl::IsMatrixType(type)) + { + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + mCurrentOffset += matrixStride * numRegisters; + } + else + { + mCurrentOffset += gl::VariableComponentCount(type); + } +} + +size_t Std140BlockEncoder::getBaseAlignment(const ShaderVariable &variable) const +{ + return kComponentsPerRegister; +} + +size_t Std140BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const +{ + return kComponentsPerRegister; +} + +// Std430BlockEncoder implementation. +Std430BlockEncoder::Std430BlockEncoder() {} + +size_t Std430BlockEncoder::getBaseAlignment(const ShaderVariable &shaderVar) const +{ + if (shaderVar.isStruct()) + { + BaseAlignmentVisitor visitor; + TraverseShaderVariables(shaderVar.fields, false, &visitor); + return visitor.getBaseAlignment(); + } + + return GetStd430BaseAlignment(shaderVar.type, shaderVar.isRowMajorLayout); +} + +size_t Std430BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const +{ + return GetStd430BaseAlignment(type, isRowMajorMatrix); +} + +void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields, + const std::string &prefix, + BlockLayoutEncoder *encoder, + BlockLayoutMap *blockInfoOut) +{ + // Matrix packing is always recorded in individual fields, so they'll set the row major layout + // flag to true if needed. + GetInterfaceBlockInfo(fields, prefix, encoder, false, blockInfoOut); +} + +void GetUniformBlockInfo(const std::vector<Uniform> &uniforms, + const std::string &prefix, + BlockLayoutEncoder *encoder, + BlockLayoutMap *blockInfoOut) +{ + // Matrix packing is always recorded in individual fields, so they'll set the row major layout + // flag to true if needed. + GetInterfaceBlockInfo(uniforms, prefix, encoder, false, blockInfoOut); +} + +// VariableNameVisitor implementation. +VariableNameVisitor::VariableNameVisitor(const std::string &namePrefix, + const std::string &mappedNamePrefix) +{ + if (!namePrefix.empty()) + { + mNameStack.push_back(namePrefix + "."); + } + + if (!mappedNamePrefix.empty()) + { + mMappedNameStack.push_back(mappedNamePrefix + "."); + } +} + +VariableNameVisitor::~VariableNameVisitor() = default; + +void VariableNameVisitor::enterStruct(const ShaderVariable &structVar) +{ + mNameStack.push_back(structVar.name); + mMappedNameStack.push_back(structVar.mappedName); +} + +void VariableNameVisitor::exitStruct(const ShaderVariable &structVar) +{ + mNameStack.pop_back(); + mMappedNameStack.pop_back(); +} + +void VariableNameVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) +{ + mNameStack.push_back("."); + mMappedNameStack.push_back("."); +} + +void VariableNameVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) +{ + mNameStack.pop_back(); + mMappedNameStack.pop_back(); +} + +void VariableNameVisitor::enterArray(const ShaderVariable &arrayVar) +{ + if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct()) + { + mNameStack.push_back(arrayVar.name); + mMappedNameStack.push_back(arrayVar.mappedName); + } +} + +void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar) +{ + if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct()) + { + mNameStack.pop_back(); + mMappedNameStack.pop_back(); + } +} + +void VariableNameVisitor::enterArrayElement(const ShaderVariable &arrayVar, + unsigned int arrayElement) +{ + std::stringstream strstr = sh::InitializeStream<std::stringstream>(); + strstr << "[" << arrayElement << "]"; + std::string elementString = strstr.str(); + mNameStack.push_back(elementString); + mMappedNameStack.push_back(elementString); +} + +void VariableNameVisitor::exitArrayElement(const ShaderVariable &arrayVar, + unsigned int arrayElement) +{ + mNameStack.pop_back(); + mMappedNameStack.pop_back(); +} + +std::string VariableNameVisitor::collapseNameStack() const +{ + return CollapseNameStack(mNameStack); +} + +std::string VariableNameVisitor::collapseMappedNameStack() const +{ + return CollapseNameStack(mMappedNameStack); +} + +void VariableNameVisitor::visitSampler(const sh::ShaderVariable &sampler) +{ + if (!sampler.hasParentArrayIndex()) + { + mNameStack.push_back(sampler.name); + mMappedNameStack.push_back(sampler.mappedName); + } + + std::string name = collapseNameStack(); + std::string mappedName = collapseMappedNameStack(); + + if (!sampler.hasParentArrayIndex()) + { + mNameStack.pop_back(); + mMappedNameStack.pop_back(); + } + + visitNamedSampler(sampler, name, mappedName); +} + +void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor) +{ + if (!variable.hasParentArrayIndex()) + { + mNameStack.push_back(variable.name); + mMappedNameStack.push_back(variable.mappedName); + } + + std::string name = collapseNameStack(); + std::string mappedName = collapseMappedNameStack(); + + if (!variable.hasParentArrayIndex()) + { + mNameStack.pop_back(); + mMappedNameStack.pop_back(); + } + + visitNamedVariable(variable, isRowMajor, name, mappedName); +} + +// BlockEncoderVisitor implementation. +BlockEncoderVisitor::BlockEncoderVisitor(const std::string &namePrefix, + const std::string &mappedNamePrefix, + BlockLayoutEncoder *encoder) + : VariableNameVisitor(namePrefix, mappedNamePrefix), mEncoder(encoder) +{} + +BlockEncoderVisitor::~BlockEncoderVisitor() = default; + +void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) +{ + mStructStackSize++; + if (!mIsTopLevelArrayStrideReady) + { + size_t structSize = mEncoder->getShaderVariableSize(structVar, isRowMajor); + mTopLevelArrayStride *= structSize; + mIsTopLevelArrayStrideReady = true; + } + + VariableNameVisitor::enterStructAccess(structVar, isRowMajor); + mEncoder->enterAggregateType(structVar); +} + +void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) +{ + mStructStackSize--; + mEncoder->exitAggregateType(structVar); + VariableNameVisitor::exitStructAccess(structVar, isRowMajor); +} + +void BlockEncoderVisitor::enterArrayElement(const sh::ShaderVariable &arrayVar, + unsigned int arrayElement) +{ + if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex()) + { + // From the ES 3.1 spec "7.3.1.1 Naming Active Resources": + // For an active shader storage block member declared as an array of an aggregate type, + // an entry will be generated only for the first array element, regardless of its type. + // Such block members are referred to as top-level arrays. If the block member is an + // aggregate type, the enumeration rules are then applied recursively. + if (arrayElement == 0) + { + mTopLevelArraySize = arrayVar.getOutermostArraySize(); + mTopLevelArrayStride = arrayVar.getInnerArraySizeProduct(); + mIsTopLevelArrayStrideReady = false; + } + else + { + mSkipEnabled = true; + } + } + VariableNameVisitor::enterArrayElement(arrayVar, arrayElement); +} + +void BlockEncoderVisitor::exitArrayElement(const sh::ShaderVariable &arrayVar, + unsigned int arrayElement) +{ + if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex()) + { + mTopLevelArraySize = 1; + mTopLevelArrayStride = 0; + mIsTopLevelArrayStrideReady = true; + mSkipEnabled = false; + } + VariableNameVisitor::exitArrayElement(arrayVar, arrayElement); +} + +void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable, + bool isRowMajor, + const std::string &name, + const std::string &mappedName) +{ + std::vector<unsigned int> innermostArraySize; + + if (variable.isArray()) + { + innermostArraySize.push_back(variable.getNestedArraySize(0)); + } + BlockMemberInfo variableInfo = + mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor); + if (!mIsTopLevelArrayStrideReady) + { + ASSERT(mTopLevelArrayStride); + mTopLevelArrayStride *= variableInfo.arrayStride; + mIsTopLevelArrayStrideReady = true; + } + variableInfo.topLevelArrayStride = mTopLevelArrayStride; + encodeVariable(variable, variableInfo, name, mappedName); +} + +void TraverseShaderVariable(const ShaderVariable &variable, + bool isRowMajorLayout, + ShaderVariableVisitor *visitor) +{ + bool rowMajorLayout = (isRowMajorLayout || variable.isRowMajorLayout); + bool isRowMajor = rowMajorLayout && gl::IsMatrixType(variable.type); + + if (variable.isStruct()) + { + visitor->enterStruct(variable); + if (variable.isArray()) + { + TraverseStructArrayVariable(variable, rowMajorLayout, visitor); + } + else + { + TraverseStructVariable(variable, rowMajorLayout, visitor); + } + visitor->exitStruct(variable); + } + else if (variable.isArrayOfArrays()) + { + TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor); + } + else if (gl::IsSamplerType(variable.type)) + { + visitor->visitSampler(variable); + } + else + { + visitor->visitVariable(variable, isRowMajor); + } +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayout.h b/gfx/angle/checkout/src/compiler/translator/blocklayout.h new file mode 100644 index 0000000000..30d5d1c3a5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/blocklayout.h @@ -0,0 +1,302 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.h: +// Methods and classes related to uniform layout and packing in GLSL and HLSL. +// + +#ifndef COMMON_BLOCKLAYOUT_H_ +#define COMMON_BLOCKLAYOUT_H_ + +#include <cstddef> +#include <map> +#include <vector> + +#include <GLSLANG/ShaderLang.h> +#include "angle_gl.h" + +namespace sh +{ +struct ShaderVariable; +struct InterfaceBlockField; +struct Uniform; +struct Varying; +struct InterfaceBlock; + +struct BlockMemberInfo +{ + constexpr BlockMemberInfo() = default; + + constexpr BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) + : offset(offset), + arrayStride(arrayStride), + matrixStride(matrixStride), + isRowMajorMatrix(isRowMajorMatrix) + {} + + constexpr BlockMemberInfo(int offset, + int arrayStride, + int matrixStride, + bool isRowMajorMatrix, + int topLevelArrayStride) + : offset(offset), + arrayStride(arrayStride), + matrixStride(matrixStride), + isRowMajorMatrix(isRowMajorMatrix), + topLevelArrayStride(topLevelArrayStride) + {} + + // A single integer identifying the offset of an active variable. + int offset = -1; + + // A single integer identifying the stride between array elements in an active variable. + int arrayStride = -1; + + // A single integer identifying the stride between columns of a column-major matrix or rows of a + // row-major matrix. + int matrixStride = -1; + + // A single integer identifying whether an active variable is a row-major matrix. + bool isRowMajorMatrix = false; + + // A single integer identifying the number of active array elements of the top-level shader + // storage block member containing the active variable. + int topLevelArrayStride = -1; +}; + +constexpr size_t ComponentAlignment(size_t numComponents) +{ + return (numComponents == 3u ? 4u : numComponents); +} + +constexpr BlockMemberInfo kDefaultBlockMemberInfo; + +class BlockLayoutEncoder +{ + public: + BlockLayoutEncoder(); + virtual ~BlockLayoutEncoder() {} + + BlockMemberInfo encodeType(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix); + + size_t getCurrentOffset() const { return mCurrentOffset * kBytesPerComponent; } + size_t getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor); + + // Called when entering/exiting a structure variable. + virtual void enterAggregateType(const ShaderVariable &structVar) = 0; + virtual void exitAggregateType(const ShaderVariable &structVar) = 0; + + static constexpr size_t kBytesPerComponent = 4u; + static constexpr unsigned int kComponentsPerRegister = 4u; + + static size_t GetBlockRegister(const BlockMemberInfo &info); + static size_t GetBlockRegisterElement(const BlockMemberInfo &info); + + protected: + void align(size_t baseAlignment); + + virtual void getBlockLayoutInfo(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) = 0; + virtual void advanceOffset(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) = 0; + + size_t mCurrentOffset; +}; + +// Will return default values for everything. +class DummyBlockEncoder : public BlockLayoutEncoder +{ + public: + DummyBlockEncoder() = default; + + void enterAggregateType(const ShaderVariable &structVar) override {} + void exitAggregateType(const ShaderVariable &structVar) override {} + + protected: + void getBlockLayoutInfo(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) override; + + void advanceOffset(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) override + {} +}; + +// Block layout according to the std140 block layout +// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification + +class Std140BlockEncoder : public BlockLayoutEncoder +{ + public: + Std140BlockEncoder(); + + void enterAggregateType(const ShaderVariable &structVar) override; + void exitAggregateType(const ShaderVariable &structVar) override; + + protected: + void getBlockLayoutInfo(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) override; + void advanceOffset(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) override; + + virtual size_t getBaseAlignment(const ShaderVariable &variable) const; + virtual size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const; +}; + +class Std430BlockEncoder : public Std140BlockEncoder +{ + public: + Std430BlockEncoder(); + + protected: + size_t getBaseAlignment(const ShaderVariable &variable) const override; + size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const override; +}; + +using BlockLayoutMap = std::map<std::string, BlockMemberInfo>; + +void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields, + const std::string &prefix, + BlockLayoutEncoder *encoder, + BlockLayoutMap *blockInfoOut); + +// Used for laying out the default uniform block on the Vulkan backend. +void GetUniformBlockInfo(const std::vector<Uniform> &uniforms, + const std::string &prefix, + BlockLayoutEncoder *encoder, + BlockLayoutMap *blockInfoOut); + +class ShaderVariableVisitor +{ + public: + virtual ~ShaderVariableVisitor() {} + + virtual void enterStruct(const ShaderVariable &structVar) {} + virtual void exitStruct(const ShaderVariable &structVar) {} + + virtual void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) {} + virtual void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) {} + + virtual void enterArray(const ShaderVariable &arrayVar) {} + virtual void exitArray(const ShaderVariable &arrayVar) {} + + virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {} + virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {} + + virtual void visitSampler(const sh::ShaderVariable &sampler) {} + + virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0; + + protected: + ShaderVariableVisitor() {} +}; + +class VariableNameVisitor : public ShaderVariableVisitor +{ + public: + VariableNameVisitor(const std::string &namePrefix, const std::string &mappedNamePrefix); + ~VariableNameVisitor() override; + + void enterStruct(const ShaderVariable &structVar) override; + void exitStruct(const ShaderVariable &structVar) override; + void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; + void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; + void enterArray(const ShaderVariable &arrayVar) override; + void exitArray(const ShaderVariable &arrayVar) override; + void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; + void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; + + protected: + virtual void visitNamedSampler(const sh::ShaderVariable &sampler, + const std::string &name, + const std::string &mappedName) + {} + virtual void visitNamedVariable(const ShaderVariable &variable, + bool isRowMajor, + const std::string &name, + const std::string &mappedName) = 0; + + std::string collapseNameStack() const; + std::string collapseMappedNameStack() const; + + private: + void visitSampler(const sh::ShaderVariable &sampler) final; + void visitVariable(const ShaderVariable &variable, bool isRowMajor) final; + + std::vector<std::string> mNameStack; + std::vector<std::string> mMappedNameStack; +}; + +class BlockEncoderVisitor : public VariableNameVisitor +{ + public: + BlockEncoderVisitor(const std::string &namePrefix, + const std::string &mappedNamePrefix, + BlockLayoutEncoder *encoder); + ~BlockEncoderVisitor() override; + + void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; + void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; + void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; + void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; + + void visitNamedVariable(const ShaderVariable &variable, + bool isRowMajor, + const std::string &name, + const std::string &mappedName) override; + + virtual void encodeVariable(const ShaderVariable &variable, + const BlockMemberInfo &variableInfo, + const std::string &name, + const std::string &mappedName) + {} + + protected: + int mTopLevelArraySize = 1; + int mTopLevelArrayStride = 0; + bool mIsTopLevelArrayStrideReady = true; + bool mSkipEnabled = false; + + private: + BlockLayoutEncoder *mEncoder; + unsigned int mStructStackSize = 0; +}; + +void TraverseShaderVariable(const ShaderVariable &variable, + bool isRowMajorLayout, + ShaderVariableVisitor *visitor); + +template <typename T> +void TraverseShaderVariables(const std::vector<T> &vars, + bool isRowMajorLayout, + ShaderVariableVisitor *visitor) +{ + for (const T &var : vars) + { + TraverseShaderVariable(var, isRowMajorLayout, visitor); + } +} +} // namespace sh + +#endif // COMMON_BLOCKLAYOUT_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.cpp b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.cpp new file mode 100644 index 0000000000..dde403699c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.cpp @@ -0,0 +1,167 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.cpp: +// Implementation for block layout classes and methods. +// + +#include "compiler/translator/blocklayoutHLSL.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace sh +{ + +HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices) + : mEncoderStrategy(strategy), mTransposeMatrices(transposeMatrices) +{} + +void HLSLBlockEncoder::enterAggregateType(const ShaderVariable &structVar) +{ + align(kComponentsPerRegister); +} + +void HLSLBlockEncoder::exitAggregateType(const ShaderVariable &structVar) {} + +void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) +{ + GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); + + // We assume we are only dealing with 4 byte components (no doubles or half-words currently) + ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent); + + int matrixStride = 0; + int arrayStride = 0; + + // if variables are not to be packed, or we're about to + // pack a matrix or array, skip to the start of the next + // register + if (!isPacked() || gl::IsMatrixType(type) || !arraySizes.empty()) + { + align(kComponentsPerRegister); + } + + if (gl::IsMatrixType(type)) + { + matrixStride = kComponentsPerRegister; + + if (!arraySizes.empty()) + { + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + arrayStride = kComponentsPerRegister * numRegisters; + } + } + else if (!arraySizes.empty()) + { + arrayStride = kComponentsPerRegister; + } + else if (isPacked()) + { + int numComponents = gl::VariableComponentCount(type); + if ((numComponents + (mCurrentOffset % kComponentsPerRegister)) > kComponentsPerRegister) + { + align(kComponentsPerRegister); + } + } + + *matrixStrideOut = matrixStride; + *arrayStrideOut = arrayStride; +} + +void HLSLBlockEncoder::advanceOffset(GLenum typeIn, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) +{ + GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); + + if (!arraySizes.empty()) + { + unsigned int arraySize = gl::ArraySizeProduct(arraySizes); + if (arraySize > 0) + { + mCurrentOffset += arrayStride * (arraySize - 1); + } + } + + if (gl::IsMatrixType(type)) + { + ASSERT(matrixStride == kComponentsPerRegister); + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix); + mCurrentOffset += kComponentsPerRegister * (numRegisters - 1); + mCurrentOffset += numComponents; + } + else if (isPacked()) + { + mCurrentOffset += gl::VariableComponentCount(type); + } + else + { + mCurrentOffset += kComponentsPerRegister; + } +} + +void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) +{ + mCurrentOffset += (numRegisters * kComponentsPerRegister); +} + +HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor( + ShShaderOutput outputType) +{ + switch (outputType) + { + case SH_HLSL_3_0_OUTPUT: + return ENCODE_LOOSE; + case SH_HLSL_4_1_OUTPUT: + case SH_HLSL_4_0_FL9_3_OUTPUT: + return ENCODE_PACKED; + default: + UNREACHABLE(); + return ENCODE_PACKED; + } +} + +template <class ShaderVarType> +void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder) +{ + if (variable.isStruct()) + { + for (size_t arrayElement = 0; arrayElement < variable.getArraySizeProduct(); arrayElement++) + { + encoder->enterAggregateType(variable); + + for (const ShaderVariable &field : variable.fields) + { + HLSLVariableRegisterCount(field, encoder); + } + + encoder->exitAggregateType(variable); + } + } + else + { + // We operate only on varyings and uniforms, which do not have matrix layout qualifiers + encoder->encodeType(variable.type, variable.arraySizes, false); + } +} + +unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType) +{ + HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType), true); + HLSLVariableRegisterCount(variable, &encoder); + + const size_t registerBytes = (encoder.kBytesPerComponent * encoder.kComponentsPerRegister); + return static_cast<unsigned int>( + rx::roundUp<size_t>(encoder.getCurrentOffset(), registerBytes) / registerBytes); +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.h b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.h new file mode 100644 index 0000000000..98d93fccb0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/blocklayoutHLSL.h @@ -0,0 +1,68 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.h: +// Methods and classes related to uniform layout and packing in GLSL and HLSL. +// + +#ifndef COMMON_BLOCKLAYOUTHLSL_H_ +#define COMMON_BLOCKLAYOUTHLSL_H_ + +#include <cstddef> +#include <vector> + +#include <GLSLANG/ShaderLang.h> +#include "angle_gl.h" +#include "blocklayout.h" + +namespace sh +{ +// Block layout packed according to the D3D9 or default D3D10+ register packing rules +// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx +// The strategy should be ENCODE_LOOSE for D3D9 constant blocks, and ENCODE_PACKED +// for everything else (D3D10+ constant blocks and all attributes/varyings). + +class HLSLBlockEncoder : public BlockLayoutEncoder +{ + public: + enum HLSLBlockEncoderStrategy + { + ENCODE_PACKED, + ENCODE_LOOSE + }; + + HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy, bool transposeMatrices); + + void enterAggregateType(const ShaderVariable &structVar) override; + void exitAggregateType(const ShaderVariable &structVar) override; + void skipRegisters(unsigned int numRegisters); + + bool isPacked() const { return mEncoderStrategy == ENCODE_PACKED; } + + static HLSLBlockEncoderStrategy GetStrategyFor(ShShaderOutput outputType); + + protected: + void getBlockLayoutInfo(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int *arrayStrideOut, + int *matrixStrideOut) override; + void advanceOffset(GLenum type, + const std::vector<unsigned int> &arraySizes, + bool isRowMajorMatrix, + int arrayStride, + int matrixStride) override; + + HLSLBlockEncoderStrategy mEncoderStrategy; + bool mTransposeMatrices; +}; + +// This method returns the number of used registers for a ShaderVariable. It is dependent on the +// HLSLBlockEncoder class to count the number of used registers in a struct (which are individually +// packed according to the same rules). +unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType); +} // namespace sh + +#endif // COMMON_BLOCKLAYOUTHLSL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp b/gfx/angle/checkout/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp new file mode 100644 index 0000000000..c61e77a110 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp @@ -0,0 +1,881 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_emulated_builtin_function_tables.py using data from +// emulated_builtin_function_data_hlsl.json. +// +// 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. +// +// emulated_builtin_functions_hlsl: +// HLSL code for emulating GLSL builtin functions not present in HLSL. + +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.h" + +namespace sh +{ + +namespace +{ + +struct FunctionPair +{ + constexpr FunctionPair(const TSymbolUniqueId &idIn, const char *bodyIn) + : id(idIn.get()), body(bodyIn) + {} + + int id; + const char *body; +}; + +constexpr FunctionPair g_hlslFunctions[] = { + {BuiltInId::mod_Float1_Float1, + "float mod_emu(float x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {BuiltInId::mod_Float2_Float2, + "float2 mod_emu(float2 x, float2 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {BuiltInId::mod_Float2_Float1, + "float2 mod_emu(float2 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {BuiltInId::mod_Float3_Float3, + "float3 mod_emu(float3 x, float3 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {BuiltInId::mod_Float3_Float1, + "float3 mod_emu(float3 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {BuiltInId::mod_Float4_Float4, + "float4 mod_emu(float4 x, float4 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {BuiltInId::mod_Float4_Float1, + "float4 mod_emu(float4 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n"}, + {BuiltInId::frexp_Float1_Int1, + "float frexp_emu(float x, out int exp)\n" + "{\n" + " float fexp;\n" + " float mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int(fexp);\n" + " return mantissa;\n" + "}\n"}, + {BuiltInId::frexp_Float2_Int2, + "float2 frexp_emu(float2 x, out int2 exp)\n" + "{\n" + " float2 fexp;\n" + " float2 mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int2(fexp);\n" + " return mantissa;\n" + "}\n"}, + {BuiltInId::frexp_Float3_Int3, + "float3 frexp_emu(float3 x, out int3 exp)\n" + "{\n" + " float3 fexp;\n" + " float3 mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int3(fexp);\n" + " return mantissa;\n" + "}\n"}, + {BuiltInId::frexp_Float4_Int4, + "float4 frexp_emu(float4 x, out int4 exp)\n" + "{\n" + " float4 fexp;\n" + " float4 mantissa = frexp(abs(x), fexp) * sign(x);\n" + " exp = int4(fexp);\n" + " return mantissa;\n" + "}\n"}, + {BuiltInId::ldexp_Float1_Int1, + "float ldexp_emu(float x, int exp)\n" + "{\n" + " return ldexp(x, float(exp));\n" + "}\n"}, + {BuiltInId::ldexp_Float2_Int2, + "float2 ldexp_emu(float2 x, int2 exp)\n" + "{\n" + " return ldexp(x, float2(exp));\n" + "}\n"}, + {BuiltInId::ldexp_Float3_Int3, + "float3 ldexp_emu(float3 x, int3 exp)\n" + "{\n" + " return ldexp(x, float3(exp));\n" + "}\n"}, + {BuiltInId::ldexp_Float4_Int4, + "float4 ldexp_emu(float4 x, int4 exp)\n" + "{\n" + " return ldexp(x, float4(exp));\n" + "}\n"}, + {BuiltInId::faceforward_Float1_Float1_Float1, + "float faceforward_emu(float N, float I, float Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {BuiltInId::faceforward_Float2_Float2_Float2, + "float2 faceforward_emu(float2 N, float2 I, float2 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {BuiltInId::faceforward_Float3_Float3_Float3, + "float3 faceforward_emu(float3 N, float3 I, float3 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {BuiltInId::faceforward_Float4_Float4_Float4, + "float4 faceforward_emu(float4 N, float4 I, float4 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n"}, + {BuiltInId::atan_Float1_Float1, + "float atan_emu(float y, float x)\n" + "{\n" + " if(x == 0 && y == 0) x = 1;\n" + " return atan2(y, x);\n" + "}\n"}, + {BuiltInId::atan_Float2_Float2, + "float2 atan_emu(float2 y, float2 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" + "}\n"}, + {BuiltInId::atan_Float3_Float3, + "float3 atan_emu(float3 y, float3 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" + "}\n"}, + {BuiltInId::atan_Float4_Float4, + "float4 atan_emu(float4 y, float4 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" + " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], \n" + " x[2]), atan2(y[3], x[3]));\n" + "}\n"}, + {BuiltInId::asinh_Float1, + "float asinh_emu(in float x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {BuiltInId::asinh_Float2, + "float2 asinh_emu(in float2 x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {BuiltInId::asinh_Float3, + "float3 asinh_emu(in float3 x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {BuiltInId::asinh_Float4, + "float4 asinh_emu(in float4 x)\n" + "{\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"}, + {BuiltInId::acosh_Float1, + "float acosh_emu(in float x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {BuiltInId::acosh_Float2, + "float2 acosh_emu(in float2 x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {BuiltInId::acosh_Float3, + "float3 acosh_emu(in float3 x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {BuiltInId::acosh_Float4, + "float4 acosh_emu(in float4 x)\n" + "{\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"}, + {BuiltInId::atanh_Float1, + "float atanh_emu(in float x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {BuiltInId::atanh_Float2, + "float2 atanh_emu(in float2 x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {BuiltInId::atanh_Float3, + "float3 atanh_emu(in float3 x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {BuiltInId::atanh_Float4, + "float4 atanh_emu(in float4 x)\n" + "{\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"}, + {BuiltInId::roundEven_Float1, + "float roundEven_emu(in float x)\n" + "{\n" + " return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n" + "}\n"}, + {BuiltInId::roundEven_Float2, + "float2 roundEven_emu(in float2 x)\n" + "{\n" + " float2 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " return v;\n" + "}\n"}, + {BuiltInId::roundEven_Float3, + "float3 roundEven_emu(in float3 x)\n" + "{\n" + " float3 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " return v;\n" + "}\n"}, + {BuiltInId::roundEven_Float4, + "float4 roundEven_emu(in float4 x)\n" + "{\n" + " float4 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n" + " return v;\n" + "}\n"}, + {BuiltInId::packSnorm2x16_Float2, + "int webgl_toSnorm16(in float x) {\n" + " return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n" + "}\n" + "uint packSnorm2x16_emu(in float2 v)\n" + "{\n" + " int x = webgl_toSnorm16(v.x);\n" + " int y = webgl_toSnorm16(v.y);\n" + " return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n" + "}\n"}, + {BuiltInId::packUnorm2x16_Float2, + "uint webgl_toUnorm16(in float x) {\n" + " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n" + "}\n" + "uint packUnorm2x16_emu(in float2 v)\n" + "{\n" + " uint x = webgl_toUnorm16(v.x);\n" + " uint y = webgl_toUnorm16(v.y);\n" + " return (y << 16) | x;\n" + "}\n"}, + {BuiltInId::packHalf2x16_Float2, + "uint packHalf2x16_emu(in float2 v)\n" + "{\n" + " uint x = f32tof16(v.x);\n" + " uint y = f32tof16(v.y);\n" + " return (y << 16) | x;\n" + "}\n"}, + {BuiltInId::unpackSnorm2x16_UInt1, + "float webgl_fromSnorm16(in uint x) {\n" + " int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n" + " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n" + "}\n" + "float2 unpackSnorm2x16_emu(in uint u)\n" + "{\n" + " uint y = (u >> 16);\n" + " uint x = u;\n" + " return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));\n" + "}\n"}, + {BuiltInId::unpackUnorm2x16_UInt1, + "float webgl_fromUnorm16(in uint x) {\n" + " return float(x) / 65535.0;\n" + "}\n" + "float2 unpackUnorm2x16_emu(in uint u)\n" + "{\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));\n" + "}\n"}, + {BuiltInId::unpackHalf2x16_UInt1, + "float2 unpackHalf2x16_emu(in uint u)\n" + "{\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(f16tof32(x), f16tof32(y));\n" + "}\n"}, + {BuiltInId::packSnorm4x8_Float4, + "int webgl_toSnorm8(in float x) {\n" + " return int(round(clamp(x, -1.0, 1.0) * 127.0));\n" + "}\n" + "uint packSnorm4x8_emu(in float4 v)\n" + "{\n" + " int x = webgl_toSnorm8(v.x);\n" + " int y = webgl_toSnorm8(v.y);\n" + " int z = webgl_toSnorm8(v.z);\n" + " int w = webgl_toSnorm8(v.w);\n" + " return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) \n" + " | ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);\n" + "}\n"}, + {BuiltInId::packUnorm4x8_Float4, + "uint webgl_toUnorm8(in float x) {\n" + " return uint(round(clamp(x, 0.0, 1.0) * 255.0));\n" + "}\n" + "uint packUnorm4x8_emu(in float4 v)\n" + "{\n" + " uint x = webgl_toUnorm8(v.x);\n" + " uint y = webgl_toUnorm8(v.y);\n" + " uint z = webgl_toUnorm8(v.z);\n" + " uint w = webgl_toUnorm8(v.w);\n" + " return (w << 24) | (z << 16) | (y << 8) | x;\n" + "}\n"}, + {BuiltInId::unpackSnorm4x8_UInt1, + "float webgl_fromSnorm8(in uint x) {\n" + " int xi = asint(x & 0x7fu) - asint(x & 0x80u);\n" + " return clamp(float(xi) / 127.0, -1.0, 1.0);\n" + "}\n" + "float4 unpackSnorm4x8_emu(in uint u)\n" + "{\n" + " uint w = (u >> 24);\n" + " uint z = (u >> 16);\n" + " uint y = (u >> 8);\n" + " uint x = u;\n" + " return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), \n" + " webgl_fromSnorm8(z), webgl_fromSnorm8(w));\n" + "}\n"}, + {BuiltInId::unpackUnorm4x8_UInt1, + "float webgl_fromUnorm8(in uint x) {\n" + " return float(x) / 255.0;\n" + "}\n" + "float4 unpackUnorm4x8_emu(in uint u)\n" + "{\n" + " uint w = (u >> 24) & 0xffu;\n" + " uint z = (u >> 16) & 0xffu;\n" + " uint y = (u >> 8) & 0xffu;\n" + " uint x = u & 0xffu;\n" + " return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), \n" + " webgl_fromUnorm8(z), webgl_fromUnorm8(w));\n" + "}\n"}, + // The matrix resulting from outer product needs to be transposed + // (matrices are stored as transposed to simplify element access in HLSL). + // So the function should return transpose(c * r) where c is a column vector + // and r is a row vector. This can be simplified by using the following + // formula: + // transpose(c * r) = transpose(r) * transpose(c) + // transpose(r) and transpose(c) are in a sense free, since to get the + // transpose of r, we simply can build a column matrix out of the original + // vector instead of a row matrix. + {BuiltInId::outerProduct_Float2_Float2, + "float2x2 outerProduct_emu(in float2 c, in float2 r)\n" + "{\n" + " return mul(float2x1(r), float1x2(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float3_Float3, + "float3x3 outerProduct_emu(in float3 c, in float3 r)\n" + "{\n" + " return mul(float3x1(r), float1x3(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float4_Float4, + "float4x4 outerProduct_emu(in float4 c, in float4 r)\n" + "{\n" + " return mul(float4x1(r), float1x4(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float3_Float2, + "float2x3 outerProduct_emu(in float3 c, in float2 r)\n" + "{\n" + " return mul(float2x1(r), float1x3(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float2_Float3, + "float3x2 outerProduct_emu(in float2 c, in float3 r)\n" + "{\n" + " return mul(float3x1(r), float1x2(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float4_Float2, + "float2x4 outerProduct_emu(in float4 c, in float2 r)\n" + "{\n" + " return mul(float2x1(r), float1x4(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float2_Float4, + "float4x2 outerProduct_emu(in float2 c, in float4 r)\n" + "{\n" + " return mul(float4x1(r), float1x2(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float4_Float3, + "float3x4 outerProduct_emu(in float4 c, in float3 r)\n" + "{\n" + " return mul(float3x1(r), float1x4(c));\n" + "}\n"}, + {BuiltInId::outerProduct_Float3_Float4, + "float4x3 outerProduct_emu(in float3 c, in float4 r)\n" + "{\n" + " return mul(float4x1(r), float1x3(c));\n" + "}\n"}, + // Remember here that the parameter matrix is actually the transpose + // of the matrix that we're trying to invert, and the resulting matrix + // should also be the transpose of the inverse. + // When accessing the parameter matrix with m[a][b] it can be thought of so + // that a is the column and b is the row of the matrix that we're inverting. + // We calculate the inverse as the adjugate matrix divided by the + // determinant of the matrix being inverted. However, as the result needs + // to be transposed, we actually use of the transpose of the adjugate matrix + // which happens to be the cofactor matrix. That's stored in 'cof'. + // We don't need to care about divide-by-zero since results are undefined + // for singular or poorly-conditioned matrices. + {BuiltInId::inverse_Float2x2, + "float2x2 inverse_emu(in float2x2 m)\n" + "{\n" + " float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n" + " return cof / determinant(transpose(m));\n" + "}\n"}, + // cofAB is the cofactor for column A and row B. + {BuiltInId::inverse_Float3x3, + "float3x3 inverse_emu(in float3x3 m)\n" + "{\n" + " float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n" + " float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n" + " float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n" + " float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n" + " float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n" + " float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n" + " float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n" + " float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n" + " float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n" + " float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"}, + {BuiltInId::inverse_Float4x4, + "float4x4 inverse_emu(in float4x4 m)\n" + "{\n" + " float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * \n" + " m[1][2] * m[2][3]\n" + " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * \n" + " m[1][3];\n" + " float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * \n" + " m[1][2] * m[2][3]\n" + " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * \n" + " m[1][3]);\n" + " float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * \n" + " m[1][1] * m[2][3]\n" + " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * \n" + " m[1][3];\n" + " float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * \n" + " m[1][1] * m[2][2]\n" + " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * \n" + " m[1][2]);\n" + " float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * \n" + " m[0][2] * m[2][3]\n" + " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * \n" + " m[0][3]);\n" + " float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * \n" + " m[0][2] * m[2][3]\n" + " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * \n" + " m[0][3];\n" + " float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * \n" + " m[0][1] * m[2][3]\n" + " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * \n" + " m[0][3]);\n" + " float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * \n" + " m[0][1] * m[2][2]\n" + " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * \n" + " m[0][2];\n" + " float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * \n" + " m[0][3];\n" + " float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * \n" + " m[0][3]);\n" + " float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * \n" + " m[0][1] * m[1][3]\n" + " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * \n" + " m[0][3];\n" + " float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * \n" + " m[0][1] * m[1][2]\n" + " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * \n" + " m[0][2]);\n" + " float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * \n" + " m[0][3]);\n" + " float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * \n" + " m[0][2] * m[1][3]\n" + " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * \n" + " m[0][3];\n" + " float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * \n" + " m[0][1] * m[1][3]\n" + " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * \n" + " m[0][3]);\n" + " float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * \n" + " m[0][1] * m[1][2]\n" + " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * \n" + " m[0][2];\n" + " float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31,\n" + " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"}, + // Emulate ESSL3 variant of mix that takes last argument as boolean vector. + // genType mix(genType x, genType y, genBType a): Selects which vector each returned component + // comes from. For a component of 'a' that is false, the corresponding component of 'x' is + // returned. For a component of 'a' that is true, the corresponding component of 'y' is + // returned. + {BuiltInId::mix_Float1_Float1_Bool1, + "float mix_emu(float x, float y, bool a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {BuiltInId::mix_Float2_Float2_Bool2, + "float2 mix_emu(float2 x, float2 y, bool2 a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {BuiltInId::mix_Float3_Float3_Bool3, + "float3 mix_emu(float3 x, float3 y, bool3 a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {BuiltInId::mix_Float4_Float4_Bool4, + "float4 mix_emu(float4 x, float4 y, bool4 a)\n" + "{\n" + " return a ? y : x;\n" + "}\n"}, + {BuiltInId::bitfieldExtract_UInt1_Int1_Int1, + "uint bitfieldExtract_emu(uint value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return 0u;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {BuiltInId::bitfieldExtract_UInt2_Int1_Int1, + "uint2 bitfieldExtract_emu(uint2 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return uint2(0u, 0u);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {BuiltInId::bitfieldExtract_UInt3_Int1_Int1, + "uint3 bitfieldExtract_emu(uint3 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return uint3(0u, 0u, 0u);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {BuiltInId::bitfieldExtract_UInt4_Int1_Int1, + "uint4 bitfieldExtract_emu(uint4 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return uint4(0u, 0u, 0u, 0u);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " return (value & mask) >> offset;\n" + "}\n"}, + {BuiltInId::bitfieldExtract_Int1_Int1_Int1, + "int bitfieldExtract_emu(int value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return 0;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32 && (resultUnsigned & maskMsb) != 0)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::bitfieldExtract_Int2_Int1_Int1, + "int2 bitfieldExtract_emu(int2 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return int2(0, 0);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint2 resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::bitfieldExtract_Int3_Int1_Int1, + "int3 bitfieldExtract_emu(int3 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return int3(0, 0, 0);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint3 resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::bitfieldExtract_Int4_Int1_Int1, + "int4 bitfieldExtract_emu(int4 value, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return int4(0, 0, 0, 0);\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint mask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint4 resultUnsigned = (asuint(value) & mask) >> offset;\n" + " if (bits != 32)\n" + " {\n" + " uint higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;\n" + " resultUnsigned |= ((resultUnsigned & maskMsb) >> (bits - 1)) * higherBitsMask;\n" + " }\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_UInt1_UInt1_Int1_Int1, + "uint bitfieldInsert_emu(uint base, uint insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_UInt2_UInt2_Int1_Int1, + "uint2 bitfieldInsert_emu(uint2 base, uint2 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_UInt3_UInt3_Int1_Int1, + "uint3 bitfieldInsert_emu(uint3 base, uint3 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_UInt4_UInt4_Int1_Int1, + "uint4 bitfieldInsert_emu(uint4 base, uint4 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " return (base & baseMask) | ((insert << offset) & insertMask);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_Int1_Int1_Int1_Int1, + "int bitfieldInsert_emu(int base, int insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_Int2_Int2_Int1_Int1, + "int2 bitfieldInsert_emu(int2 base, int2 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint2 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_Int3_Int3_Int1_Int1, + "int3 bitfieldInsert_emu(int3 base, int3 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint3 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::bitfieldInsert_Int4_Int4_Int1_Int1, + "int4 bitfieldInsert_emu(int4 base, int4 insert, int offset, int bits)\n" + "{\n" + " if (offset < 0 || bits <= 0 || offset >= 32 || bits > 32 || offset + bits > 32)\n" + " {\n" + " return base;\n" + " }\n" + " uint maskMsb = (1u << (bits - 1));\n" + " uint insertMask = ((maskMsb - 1u) | maskMsb) << offset;\n" + " uint baseMask = ~insertMask;\n" + " uint4 resultUnsigned = (asuint(base) & baseMask) | ((asuint(insert) << offset) & \n" + " insertMask);\n" + " return asint(resultUnsigned);\n" + "}\n"}, + {BuiltInId::uaddCarry_UInt1_UInt1_UInt1, + "uint uaddCarry_emu(uint x, uint y, out uint carry)\n" + "{\n" + " carry = uint(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {BuiltInId::uaddCarry_UInt2_UInt2_UInt2, + "uint2 uaddCarry_emu(uint2 x, uint2 y, out uint2 carry)\n" + "{\n" + " carry = uint2(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {BuiltInId::uaddCarry_UInt3_UInt3_UInt3, + "uint3 uaddCarry_emu(uint3 x, uint3 y, out uint3 carry)\n" + "{\n" + " carry = uint3(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {BuiltInId::uaddCarry_UInt4_UInt4_UInt4, + "uint4 uaddCarry_emu(uint4 x, uint4 y, out uint4 carry)\n" + "{\n" + " carry = uint4(x > (0xffffffffu - y));\n" + " return x + y;\n" + "}\n"}, + {BuiltInId::usubBorrow_UInt1_UInt1_UInt1, + "uint usubBorrow_emu(uint x, uint y, out uint borrow)\n" + "{\n" + " borrow = uint(x < y);\n" + " return x - y;\n" + "}\n"}, + {BuiltInId::usubBorrow_UInt2_UInt2_UInt2, + "uint2 usubBorrow_emu(uint2 x, uint2 y, out uint2 borrow)\n" + "{\n" + " borrow = uint2(x < y);\n" + " return x - y;\n" + "}\n"}, + {BuiltInId::usubBorrow_UInt3_UInt3_UInt3, + "uint3 usubBorrow_emu(uint3 x, uint3 y, out uint3 borrow)\n" + "{\n" + " borrow = uint3(x < y);\n" + " return x - y;\n" + "}\n"}, + {BuiltInId::usubBorrow_UInt4_UInt4_UInt4, + "uint4 usubBorrow_emu(uint4 x, uint4 y, out uint4 borrow)\n" + "{\n" + " borrow = uint4(x < y);\n" + " return x - y;\n" + "}\n"}, + // We emulate tanh just to avoid overflow on large arguments. + {BuiltInId::tanh_Float1, + "float tanh_emu(float x)\n" + "{\n" + " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n" + "}\n"}, + {BuiltInId::tanh_Float2, + "float2 tanh_emu(float2 x)\n" + "{\n" + " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n" + "}\n"}, + {BuiltInId::tanh_Float3, + "float3 tanh_emu(float3 x)\n" + "{\n" + " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n" + "}\n"}, + {BuiltInId::tanh_Float4, + "float4 tanh_emu(float4 x)\n" + "{\n" + " return (abs(x) > 15.0) ? sign(x) : tanh(x);\n" + "}\n"}, +}; +} // anonymous namespace + +const char *FindHLSLFunction(int uniqueId) +{ + for (size_t index = 0; index < ArraySize(g_hlslFunctions); ++index) + { + const auto &function = g_hlslFunctions[index]; + if (function.id == uniqueId) + { + return function.body; + } + } + + return nullptr; +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/glslang.h b/gfx/angle/checkout/src/compiler/translator/glslang.h new file mode 100644 index 0000000000..e54c31ba3e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/glslang.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 2010 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_GLSLANG_H_ +#define COMPILER_TRANSLATOR_GLSLANG_H_ + +namespace sh +{ +class TParseContext; +} + +extern int glslang_initialize(sh::TParseContext *context); +extern int glslang_finalize(sh::TParseContext *context); + +extern int glslang_scan(size_t count, + const char *const string[], + const int length[], + sh::TParseContext *context); +extern int glslang_parse(sh::TParseContext *context); + +#endif // COMPILER_TRANSLATOR_GLSLANG_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/glslang_lex.cpp b/gfx/angle/checkout/src/compiler/translator/glslang_lex.cpp new file mode 100644 index 0000000000..3a65f1ebce --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/glslang_lex.cpp @@ -0,0 +1,4108 @@ +#line 17 "./glslang.l" +// +// Copyright (c) 2012-2013 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +/* clang-format off */ + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wswitch-enum" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#elif defined(_MSC_VER) +#pragma warning(disable: 4005) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4244) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#pragma warning(disable: 4702) +#endif +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +// Flex isn't semi-colon clean. +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif + + + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + + + + + + + + + + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + + + + + + + + + + + + + + + + + + +#ifdef yyget_lval +#define yyget_lval_ALREADY_DEFINED +#else +#define yyget_lval yyget_lval +#endif + + +#ifdef yyset_lval +#define yyset_lval_ALREADY_DEFINED +#else +#define yyset_lval yyset_lval +#endif + + + + + +#ifdef yyget_lloc +#define yyget_lloc_ALREADY_DEFINED +#else +#define yyget_lloc yyget_lloc +#endif + + +#ifdef yyset_lloc +#define yyset_lloc_ALREADY_DEFINED +#else +#define yyset_lloc yyset_lloc +#endif + + + + + + + + + + + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + + + + + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + + + + + + + + + + + + + + + + + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + + + + + + + + + + + + + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + + + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + + + + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + + + + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + + + + + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + + +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + + + + + + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + + + + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 247 +#define YY_END_OF_BUFFER 248 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[891] = + { 0, + 0, 0, 0, 0, 248, 246, 245, 245, 229, 235, + 240, 224, 225, 233, 232, 221, 230, 228, 234, 187, + 187, 222, 218, 236, 223, 237, 241, 184, 226, 227, + 239, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 219, 238, 220, 231, 244, 243, 247, + 242, 215, 201, 220, 209, 204, 199, 207, 197, 208, + 198, 193, 200, 192, 186, 187, 0, 190, 0, 227, + 219, 226, 216, 212, 214, 213, 217, 184, 205, 211, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + + 184, 184, 184, 184, 13, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 16, 184, + 184, 24, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 206, 210, 242, + 0, 196, 192, 0, 195, 189, 0, 191, 185, 202, + 203, 184, 184, 144, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 14, 184, + + 184, 184, 184, 184, 184, 184, 184, 184, 184, 29, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 25, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 0, + 193, 0, 192, 194, 188, 184, 184, 184, 184, 32, + 184, 184, 184, 19, 181, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 17, 147, 184, 184, 184, + 184, 22, 184, 184, 151, 162, 184, 184, 184, 184, + + 184, 184, 184, 184, 184, 184, 184, 184, 184, 159, + 4, 37, 38, 39, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 150, + 33, 184, 184, 30, 184, 184, 184, 184, 184, 184, + 184, 49, 50, 51, 31, 184, 184, 184, 184, 184, + 184, 184, 184, 11, 184, 55, 56, 57, 184, 145, + 184, 184, 7, 184, 184, 184, 184, 171, 172, 173, + 184, 34, 184, 163, 28, 174, 175, 176, 2, 168, + 169, 170, 184, 184, 184, 26, 166, 184, 184, 184, + + 184, 184, 52, 53, 54, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 112, 184, 184, 184, + 184, 184, 184, 184, 184, 160, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 146, 184, 184, + 183, 58, 59, 60, 184, 184, 15, 184, 184, 184, + 117, 184, 184, 9, 184, 184, 115, 184, 184, 184, + 161, 156, 118, 184, 184, 184, 184, 184, 184, 152, + 184, 184, 184, 184, 184, 87, 40, 43, 45, 44, + 41, 47, 46, 48, 42, 184, 184, 184, 184, 167, + 143, 184, 184, 154, 184, 184, 184, 36, 113, 27, + + 180, 23, 155, 86, 184, 165, 18, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 20, 35, 184, 184, 184, 184, 184, + 184, 119, 92, 98, 184, 184, 184, 184, 184, 89, + 91, 3, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 148, 184, 184, 184, 184, 184, 8, + 184, 184, 10, 184, 184, 184, 184, 184, 184, 21, + 106, 12, 157, 120, 93, 100, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 153, + 184, 184, 184, 104, 110, 107, 184, 184, 184, 184, + + 184, 184, 184, 149, 121, 94, 99, 184, 184, 164, + 184, 108, 184, 184, 184, 184, 6, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 103, 158, 1, 184, + 184, 184, 184, 184, 184, 182, 184, 116, 5, 177, + 61, 64, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 105, 184, 184, 184, 184, + 184, 184, 101, 184, 184, 184, 184, 184, 134, 69, + 70, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 114, 184, 184, 184, 102, + 136, 74, 75, 184, 184, 184, 184, 109, 184, 184, + + 184, 184, 184, 184, 184, 129, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 68, 184, 184, + 184, 184, 62, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 130, 122, 184, + 95, 184, 184, 184, 73, 184, 184, 71, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 131, 184, 184, 78, 184, 184, 76, 184, + 184, 123, 96, 184, 125, 184, 126, 184, 184, 184, + 184, 184, 184, 111, 184, 184, 184, 184, 66, 184, + 65, 140, 184, 184, 124, 97, 184, 184, 184, 184, + + 184, 184, 184, 184, 184, 184, 184, 184, 138, 141, + 184, 132, 184, 67, 184, 184, 184, 184, 184, 184, + 184, 184, 139, 142, 184, 184, 184, 184, 135, 72, + 184, 184, 184, 178, 184, 184, 184, 79, 184, 184, + 137, 77, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 83, 184, 184, 184, 184, 184, 184, 184, 184, + 84, 184, 184, 184, 184, 80, 184, 85, 88, 184, + 127, 128, 90, 184, 184, 184, 63, 184, 184, 184, + 179, 184, 133, 81, 184, 184, 184, 184, 82, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 1, 1, 1, 5, 6, 1, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 1, 31, 32, 33, 34, 35, 36, + 37, 37, 37, 37, 37, 37, 38, 37, 39, 37, + 37, 40, 41, 42, 43, 37, 37, 44, 45, 37, + 46, 1, 47, 48, 49, 1, 50, 51, 52, 53, + + 54, 55, 56, 57, 58, 37, 59, 60, 61, 62, + 63, 64, 37, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[78] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 2, 3, 1, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, + 5, 5, 5, 5, 6, 7, 8, 8, 8, 8, + 8, 8, 9, 8, 8, 1, 1, 1, 8, 5, + 5, 5, 5, 6, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, + 8, 8, 8, 1, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[900] = + { 0, + 0, 0, 77, 0, 1094, 1095, 1095, 1095, 1065, 127, + 151, 1095, 1095, 1064, 148, 1095, 147, 145, 1063, 167, + 158, 1061, 1095, 167, 1061, 145, 1095, 0, 1095, 1095, + 149, 1039, 147, 135, 155, 162, 146, 174, 1024, 172, + 178, 179, 169, 196, 1018, 198, 1031, 200, 197, 213, + 202, 113, 1016, 1095, 153, 1095, 1095, 1095, 1095, 1095, + 0, 1095, 1095, 1095, 1095, 1095, 1095, 1095, 1095, 1095, + 1095, 237, 1095, 241, 237, 271, 243, 1095, 0, 1095, + 1095, 1095, 1055, 1095, 1095, 1095, 1054, 0, 1095, 1095, + 1015, 1013, 1018, 197, 1015, 1023, 1021, 1021, 1008, 1011, + + 1022, 226, 1016, 1004, 1001, 1014, 1001, 998, 998, 1004, + 136, 235, 998, 1008, 994, 1000, 1003, 1004, 0, 996, + 1006, 230, 1005, 986, 999, 980, 216, 984, 997, 988, + 243, 981, 237, 993, 995, 250, 984, 259, 971, 980, + 253, 259, 984, 980, 982, 971, 974, 250, 255, 269, + 983, 971, 983, 266, 976, 975, 963, 1095, 1095, 0, + 318, 1095, 296, 323, 1095, 1095, 325, 324, 206, 1095, + 1095, 981, 972, 0, 968, 963, 967, 976, 970, 972, + 298, 956, 956, 967, 959, 271, 969, 966, 966, 964, + 961, 953, 959, 946, 944, 956, 942, 958, 0, 955, + + 943, 950, 947, 951, 952, 945, 942, 931, 930, 943, + 946, 934, 945, 941, 929, 935, 926, 336, 931, 934, + 925, 932, 921, 925, 916, 930, 929, 920, 926, 294, + 910, 913, 911, 910, 920, 910, 905, 903, 905, 915, + 901, 903, 900, 911, 910, 913, 895, 301, 903, 899, + 897, 906, 885, 349, 903, 905, 894, 886, 919, 354, + 370, 368, 383, 1095, 1095, 890, 881, 891, 890, 0, + 888, 892, 379, 0, 0, 880, 878, 878, 879, 874, + 882, 871, 888, 877, 382, 0, 0, 871, 881, 880, + 880, 0, 865, 385, 0, 0, 867, 390, 874, 875, + + 866, 860, 859, 860, 859, 859, 337, 393, 854, 0, + 0, 850, 849, 848, 850, 851, 856, 850, 846, 859, + 854, 854, 852, 851, 845, 839, 841, 840, 844, 849, + 835, 838, 833, 841, 846, 834, 831, 843, 834, 0, + 0, 840, 836, 0, 828, 828, 833, 824, 831, 396, + 828, 0, 0, 0, 0, 818, 830, 829, 816, 817, + 826, 827, 827, 0, 812, 0, 0, 0, 813, 0, + 821, 812, 0, 811, 812, 806, 816, 0, 0, 0, + 807, 0, 803, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 813, 400, 812, 0, 0, 810, 806, 803, + + 847, 846, 0, 0, 0, 793, 403, 409, 412, 798, + 794, 799, 790, 788, 801, 786, 0, 786, 799, 788, + 784, 790, 785, 792, 792, 0, 789, 786, 790, 774, + 772, 775, 781, 787, 782, 781, 769, 0, 771, 772, + 0, 0, 0, 0, 769, 772, 0, 766, 776, 767, + 0, 777, 757, 0, 766, 761, 0, 754, 754, 767, + 0, 769, 0, 418, 784, 783, 782, 747, 746, 0, + 763, 762, 757, 794, 785, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 744, 757, 744, 741, 0, + 0, 746, 745, 0, 742, 749, 748, 0, 734, 0, + + 0, 0, 0, 0, 731, 0, 0, 730, 741, 423, + 734, 740, 739, 736, 731, 728, 748, 734, 719, 719, + 732, 717, 729, 0, 0, 722, 747, 746, 745, 710, + 709, 406, 411, 0, 721, 724, 722, 711, 707, 722, + 0, 0, 718, 715, 714, 704, 703, 693, 710, 696, + 427, 704, 707, 0, 726, 725, 724, 689, 688, 0, + 702, 689, 0, 699, 692, 684, 685, 691, 694, 0, + 0, 0, 0, 716, 715, 0, 690, 693, 678, 685, + 676, 683, 684, 684, 683, 669, 447, 680, 680, 0, + 681, 670, 669, 0, 0, 0, 696, 695, 694, 659, + + 658, 654, 662, 0, 692, 691, 0, 666, 669, 0, + 450, 0, 647, 668, 682, 654, 0, 650, 649, 658, + 658, 646, 660, 644, 658, 653, 0, 0, 0, 672, + 671, 670, 635, 634, 633, 0, 633, 0, 0, 417, + 446, 659, 643, 646, 629, 641, 629, 628, 637, 637, + 656, 655, 654, 619, 618, 0, 623, 613, 616, 617, + 616, 626, 0, 629, 625, 627, 623, 610, 643, 438, + 0, 618, 621, 611, 612, 604, 611, 602, 625, 611, + 607, 609, 607, 607, 606, 0, 594, 593, 603, 0, + 625, 450, 0, 600, 603, 600, 585, 0, 601, 600, + + 584, 576, 584, 574, 582, 0, 579, 578, 601, 587, + 585, 585, 578, 568, 571, 585, 569, 602, 580, 581, + 578, 575, 587, 562, 576, 575, 559, 558, 557, 580, + 566, 564, 564, 567, 562, 543, 542, 0, 572, 542, + 570, 540, 544, 543, 576, 554, 551, 0, 555, 548, + 549, 539, 538, 519, 502, 515, 499, 162, 258, 258, + 257, 290, 0, 298, 316, 363, 353, 369, 0, 359, + 381, 0, 0, 392, 0, 396, 0, 404, 407, 396, + 403, 406, 407, 0, 401, 411, 403, 420, 448, 428, + 0, 0, 442, 443, 0, 0, 444, 445, 431, 430, + + 433, 446, 438, 451, 452, 431, 432, 440, 0, 0, + 456, 466, 438, 468, 460, 454, 442, 460, 454, 443, + 444, 452, 0, 0, 483, 469, 467, 468, 0, 0, + 472, 461, 467, 0, 468, 454, 477, 0, 465, 490, + 0, 0, 480, 487, 472, 470, 471, 463, 480, 487, + 488, 0, 486, 470, 506, 470, 501, 527, 475, 476, + 0, 493, 495, 496, 487, 0, 510, 0, 0, 518, + 0, 0, 0, 490, 491, 485, 0, 511, 487, 488, + 0, 542, 0, 0, 515, 526, 518, 521, 0, 1095, + 561, 567, 573, 579, 583, 589, 590, 596, 599 + + } ; + +static const flex_int16_t yy_def[900] = + { 0, + 890, 1, 890, 3, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 891, 890, 890, 890, 890, 890, 890, 892, 890, 890, + 890, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 890, 890, 890, 890, 890, 890, 890, + 893, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 894, 890, 895, 20, 891, 896, 890, 897, 890, + 890, 890, 890, 890, 890, 890, 890, 892, 890, 890, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 890, 890, 893, + 898, 890, 895, 899, 890, 890, 890, 896, 897, 890, + 890, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 890, + 898, 890, 899, 890, 890, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, + 892, 892, 892, 892, 892, 892, 892, 892, 892, 0, + 890, 890, 890, 890, 890, 890, 890, 890, 890 + + } ; + +static const flex_int16_t yy_nxt[1173] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 22, 23, 24, 25, 26, 27, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 28, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 28, 53, 28, 54, 55, 56, 57, 58, 59, 60, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + + 58, 58, 58, 58, 58, 58, 58, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 58, 58, 58, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 58, 58, 58, 58, 63, 64, 65, 68, 70, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 155, + 74, 81, 86, 87, 71, 69, 89, 156, 66, 74, + 158, 75, 75, 75, 75, 75, 75, 75, 75, 76, + 76, 82, 77, 83, 84, 195, 90, 95, 92, 96, + + 78, 77, 97, 98, 99, 107, 196, 108, 100, 78, + 79, 77, 93, 94, 101, 103, 109, 102, 128, 104, + 77, 116, 129, 110, 105, 78, 792, 159, 126, 117, + 106, 111, 119, 112, 78, 120, 113, 79, 121, 122, + 118, 127, 114, 123, 124, 130, 125, 133, 265, 137, + 144, 152, 167, 145, 167, 153, 138, 139, 131, 175, + 140, 146, 134, 176, 154, 135, 141, 142, 147, 143, + 148, 161, 162, 265, 149, 164, 165, 216, 150, 166, + 890, 151, 184, 74, 197, 217, 185, 186, 224, 207, + 161, 162, 208, 209, 164, 165, 210, 198, 211, 229, + + 221, 225, 237, 226, 166, 77, 222, 890, 233, 239, + 246, 247, 248, 78, 793, 230, 231, 238, 250, 794, + 249, 234, 240, 255, 77, 256, 251, 260, 795, 260, + 164, 165, 262, 890, 262, 890, 280, 281, 78, 168, + 168, 168, 168, 168, 168, 168, 168, 168, 168, 164, + 165, 274, 312, 313, 314, 345, 326, 401, 402, 264, + 327, 796, 797, 346, 275, 352, 353, 354, 261, 261, + 261, 261, 261, 261, 261, 261, 261, 261, 264, 890, + 798, 890, 263, 263, 263, 263, 263, 263, 263, 263, + 263, 263, 890, 799, 890, 366, 367, 368, 378, 379, + + 380, 386, 387, 388, 800, 162, 390, 391, 392, 403, + 404, 405, 442, 443, 444, 465, 466, 467, 165, 477, + 478, 479, 801, 802, 162, 480, 481, 482, 483, 484, + 485, 468, 469, 527, 528, 529, 579, 165, 555, 556, + 557, 581, 597, 598, 599, 803, 580, 676, 804, 530, + 531, 582, 805, 806, 558, 559, 807, 677, 600, 601, + 808, 602, 630, 631, 632, 651, 652, 653, 708, 809, + 810, 811, 812, 813, 814, 709, 678, 710, 633, 634, + 729, 654, 655, 679, 815, 680, 681, 730, 816, 731, + 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, + + 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, + 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, + 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, + 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, + 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, + 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, + 887, 888, 889, 76, 76, 791, 76, 790, 789, 76, + 88, 88, 88, 88, 88, 88, 160, 160, 160, 160, + 160, 160, 72, 788, 72, 72, 163, 787, 163, 163, + 168, 786, 168, 169, 169, 169, 169, 261, 785, 261, + + 263, 784, 263, 783, 782, 781, 780, 779, 778, 777, + 776, 775, 774, 773, 772, 771, 770, 769, 768, 767, + 766, 765, 764, 763, 762, 761, 760, 759, 758, 757, + 756, 755, 754, 753, 752, 751, 750, 749, 748, 747, + 746, 745, 744, 743, 742, 741, 740, 739, 738, 737, + 736, 735, 734, 733, 732, 728, 727, 726, 725, 724, + 723, 722, 721, 720, 719, 718, 717, 716, 715, 714, + 713, 712, 711, 707, 706, 705, 704, 703, 702, 701, + 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, + 690, 689, 688, 687, 686, 685, 684, 683, 682, 675, + + 674, 673, 672, 671, 670, 669, 668, 667, 666, 665, + 664, 663, 662, 661, 660, 659, 658, 657, 656, 650, + 649, 648, 647, 646, 645, 644, 643, 642, 641, 640, + 639, 638, 637, 636, 635, 629, 628, 627, 626, 625, + 624, 623, 622, 621, 620, 619, 618, 617, 616, 615, + 614, 613, 612, 611, 610, 609, 608, 607, 606, 605, + 604, 603, 596, 595, 594, 593, 592, 591, 590, 589, + 588, 587, 586, 585, 584, 583, 578, 577, 576, 575, + 574, 573, 572, 571, 570, 569, 568, 567, 566, 565, + 564, 563, 562, 561, 560, 554, 553, 552, 551, 550, + + 549, 548, 547, 546, 545, 544, 543, 542, 541, 540, + 539, 538, 537, 536, 535, 534, 533, 532, 526, 525, + 524, 523, 522, 521, 520, 519, 518, 517, 516, 515, + 514, 513, 512, 511, 510, 509, 508, 507, 506, 505, + 504, 503, 502, 501, 500, 499, 498, 497, 496, 495, + 494, 493, 492, 491, 490, 489, 488, 487, 486, 476, + 475, 474, 473, 472, 471, 470, 464, 463, 462, 461, + 460, 459, 458, 457, 456, 455, 454, 453, 452, 451, + 450, 449, 448, 447, 446, 445, 441, 440, 439, 438, + 437, 436, 435, 434, 433, 432, 431, 430, 429, 428, + + 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, + 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, + 407, 406, 400, 399, 398, 397, 396, 395, 394, 393, + 389, 385, 384, 383, 382, 381, 377, 376, 375, 374, + 373, 372, 371, 370, 369, 365, 364, 363, 362, 361, + 360, 359, 358, 357, 356, 355, 351, 350, 349, 348, + 347, 344, 343, 342, 341, 340, 339, 338, 337, 336, + 335, 334, 333, 332, 331, 330, 329, 328, 325, 324, + 323, 322, 321, 320, 319, 318, 317, 316, 315, 311, + 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, + + 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, + 290, 289, 288, 287, 286, 285, 284, 283, 282, 279, + 278, 277, 276, 273, 272, 271, 270, 269, 268, 267, + 266, 259, 258, 257, 254, 253, 252, 245, 244, 243, + 242, 241, 236, 235, 232, 228, 227, 223, 220, 219, + 218, 215, 214, 213, 212, 206, 205, 204, 203, 202, + 201, 200, 199, 194, 193, 192, 191, 190, 189, 188, + 187, 183, 182, 181, 180, 179, 178, 177, 174, 173, + 172, 171, 170, 157, 136, 132, 115, 91, 85, 80, + 73, 67, 62, 890, 5, 890, 890, 890, 890, 890, + + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890 + } ; + +static const flex_int16_t yy_chk[1173] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 10, 10, 11, 15, 17, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 52, + 21, 24, 26, 26, 17, 15, 31, 52, 11, 20, + 55, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 24, 21, 24, 24, 111, 31, 34, 33, 34, + + 21, 20, 34, 34, 35, 37, 111, 37, 35, 20, + 20, 21, 33, 33, 35, 36, 37, 35, 43, 36, + 20, 40, 43, 38, 36, 21, 758, 55, 42, 40, + 36, 38, 41, 38, 20, 41, 38, 20, 41, 41, + 40, 42, 38, 41, 41, 44, 41, 46, 169, 48, + 49, 51, 77, 49, 77, 51, 48, 48, 44, 94, + 48, 49, 46, 94, 51, 46, 48, 48, 49, 48, + 50, 72, 72, 169, 50, 74, 74, 127, 50, 75, + 75, 50, 102, 76, 112, 127, 102, 102, 133, 122, + 72, 72, 122, 122, 74, 74, 122, 112, 122, 136, + + 131, 133, 141, 133, 75, 76, 131, 75, 138, 142, + 148, 148, 149, 76, 759, 136, 136, 141, 150, 760, + 149, 138, 142, 154, 76, 154, 150, 161, 761, 161, + 163, 163, 164, 168, 164, 168, 186, 186, 76, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 163, + 163, 181, 218, 218, 218, 248, 230, 307, 307, 168, + 230, 762, 764, 248, 181, 254, 254, 254, 260, 260, + 260, 260, 260, 260, 260, 260, 260, 260, 168, 261, + 765, 261, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 263, 766, 263, 273, 273, 273, 285, 285, + + 285, 294, 294, 294, 767, 261, 298, 298, 298, 308, + 308, 308, 350, 350, 350, 394, 394, 394, 263, 407, + 407, 407, 768, 770, 261, 408, 408, 408, 409, 409, + 409, 394, 394, 464, 464, 464, 532, 263, 510, 510, + 510, 533, 551, 551, 551, 771, 532, 640, 774, 464, + 464, 533, 776, 778, 510, 510, 779, 640, 551, 551, + 780, 551, 587, 587, 587, 611, 611, 611, 670, 781, + 782, 783, 785, 786, 787, 670, 641, 670, 587, 587, + 692, 611, 611, 641, 788, 641, 641, 692, 789, 692, + 790, 793, 794, 797, 798, 799, 800, 801, 802, 803, + + 804, 805, 806, 807, 808, 811, 812, 813, 814, 815, + 816, 817, 818, 819, 820, 821, 822, 825, 826, 827, + 828, 831, 832, 833, 835, 836, 837, 839, 840, 843, + 844, 845, 846, 847, 848, 849, 850, 851, 853, 854, + 855, 856, 857, 858, 859, 860, 862, 863, 864, 865, + 867, 870, 874, 875, 876, 878, 879, 880, 882, 885, + 886, 887, 888, 891, 891, 757, 891, 756, 755, 891, + 892, 892, 892, 892, 892, 892, 893, 893, 893, 893, + 893, 893, 894, 754, 894, 894, 895, 753, 895, 895, + 896, 752, 896, 897, 897, 897, 897, 898, 751, 898, + + 899, 750, 899, 749, 747, 746, 745, 744, 743, 742, + 741, 740, 739, 737, 736, 735, 734, 733, 732, 731, + 730, 729, 728, 727, 726, 725, 724, 723, 722, 721, + 720, 719, 718, 717, 716, 715, 714, 713, 712, 711, + 710, 709, 708, 707, 705, 704, 703, 702, 701, 700, + 699, 697, 696, 695, 694, 691, 689, 688, 687, 685, + 684, 683, 682, 681, 680, 679, 678, 677, 676, 675, + 674, 673, 672, 669, 668, 667, 666, 665, 664, 662, + 661, 660, 659, 658, 657, 655, 654, 653, 652, 651, + 650, 649, 648, 647, 646, 645, 644, 643, 642, 637, + + 635, 634, 633, 632, 631, 630, 626, 625, 624, 623, + 622, 621, 620, 619, 618, 616, 615, 614, 613, 609, + 608, 606, 605, 603, 602, 601, 600, 599, 598, 597, + 593, 592, 591, 589, 588, 586, 585, 584, 583, 582, + 581, 580, 579, 578, 577, 575, 574, 569, 568, 567, + 566, 565, 564, 562, 561, 559, 558, 557, 556, 555, + 553, 552, 550, 549, 548, 547, 546, 545, 544, 543, + 540, 539, 538, 537, 536, 535, 531, 530, 529, 528, + 527, 526, 523, 522, 521, 520, 519, 518, 517, 516, + 515, 514, 513, 512, 511, 509, 508, 505, 499, 497, + + 496, 495, 493, 492, 489, 488, 487, 486, 475, 474, + 473, 472, 471, 469, 468, 467, 466, 465, 462, 460, + 459, 458, 456, 455, 453, 452, 450, 449, 448, 446, + 445, 440, 439, 437, 436, 435, 434, 433, 432, 431, + 430, 429, 428, 427, 425, 424, 423, 422, 421, 420, + 419, 418, 416, 415, 414, 413, 412, 411, 410, 406, + 402, 401, 400, 399, 398, 395, 393, 383, 381, 377, + 376, 375, 374, 372, 371, 369, 365, 363, 362, 361, + 360, 359, 358, 357, 356, 351, 349, 348, 347, 346, + 345, 343, 342, 339, 338, 337, 336, 335, 334, 333, + + 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, + 322, 321, 320, 319, 318, 317, 316, 315, 314, 313, + 312, 309, 306, 305, 304, 303, 302, 301, 300, 299, + 297, 293, 291, 290, 289, 288, 284, 283, 282, 281, + 280, 279, 278, 277, 276, 272, 271, 269, 268, 267, + 266, 259, 258, 257, 256, 255, 253, 252, 251, 250, + 249, 247, 246, 245, 244, 243, 242, 241, 240, 239, + 238, 237, 236, 235, 234, 233, 232, 231, 229, 228, + 227, 226, 225, 224, 223, 222, 221, 220, 219, 217, + 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, + + 206, 205, 204, 203, 202, 201, 200, 198, 197, 196, + 195, 194, 193, 192, 191, 190, 189, 188, 187, 185, + 184, 183, 182, 180, 179, 178, 177, 176, 175, 173, + 172, 157, 156, 155, 153, 152, 151, 147, 146, 145, + 144, 143, 140, 139, 137, 135, 134, 132, 130, 129, + 128, 126, 125, 124, 123, 121, 120, 118, 117, 116, + 115, 114, 113, 110, 109, 108, 107, 106, 105, 104, + 103, 101, 100, 99, 98, 97, 96, 95, 93, 92, + 91, 87, 83, 53, 47, 45, 39, 32, 25, 22, + 19, 14, 9, 5, 890, 890, 890, 890, 890, 890, + + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, + 890, 890 + } ; + + +/* Table of booleans, true if rule could match eol. */ +static const flex_int32_t yy_rule_can_match_eol[248] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* +// +// Copyright (c) 2002-2013 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. +// + +This file contains the Lex specification for GLSL ES. +Based on ANSI C grammar, Lex specification: +http://www.lysator.liu.se/c/ANSI-C-grammar-l.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). +*/ + +#include "compiler/preprocessor/Token.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/translator/glslang.h" +#include "compiler/translator/length_limits.h" +#include "compiler/translator/util.h" + +using namespace sh; + +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +// Workaround for flex using the register keyword, deprecated in C++11. +#ifdef __cplusplus +#if __cplusplus > 199711L +#define register +#endif +#endif + +#define YY_NO_INPUT +#define YY_USER_ACTION \ + yylloc->first_file = yylloc->last_file = yycolumn; \ + yylloc->first_line = yylloc->last_line = yylineno; + +#define YY_INPUT(buf, result, max_size) \ + result = string_input(buf, max_size, yyscanner); + +static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner); +static int check_type(yyscan_t yyscanner); +static int reserved_word(yyscan_t yyscanner); +static int ES2_reserved_ES3_keyword(TParseContext *context, int token); +static int ES2_keyword_ES3_reserved(TParseContext *context, int token); +static int ES2_ident_ES3_keyword(TParseContext *context, int token); +static int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token); +static int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token); +static int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token); +static int ES2_extension_ES3_keyword_else_reserved(TParseContext *context, TExtension extension, int token); +static int ES3_extension_keyword_else_ident(TParseContext *context, TExtension extension, int token); +static int ES2_ident_ES3_reserved_ES3_1_extension_keyword(TParseContext *context, TExtension extension, int token); +static int ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(TParseContext *context, TExtension extension, int token); +static int uint_constant(TParseContext *context); +static int int_constant(TParseContext *context); +static int float_constant(yyscan_t yyscanner); +static int floatsuffix_check(TParseContext* context); +static int yuvcscstandardext_constant(TParseContext *context); + + + + +#define INITIAL 0 +#define FIELDS 1 + + + + + + +#define YY_EXTRA_TYPE TParseContext* + + + + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + + + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + + + YYSTYPE * yylval_r; + + + + YYLTYPE * yylloc_r; + + + }; /* end struct yyguts_t */ + + + + +static int yy_init_globals ( yyscan_t yyscanner ); + + + + + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + + + # define yylloc yyg->yylloc_r + + + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + + + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + + +int yylex_destroy ( yyscan_t yyscanner ); + + + +int yyget_debug ( yyscan_t yyscanner ); + + + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + + + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + + + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + + + +FILE *yyget_in ( yyscan_t yyscanner ); + + + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + + + +FILE *yyget_out ( yyscan_t yyscanner ); + + + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + + + int yyget_leng ( yyscan_t yyscanner ); + + + +char *yyget_text ( yyscan_t yyscanner ); + + + +int yyget_lineno ( yyscan_t yyscanner ); + + + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + + + + +int yyget_column ( yyscan_t yyscanner ); + + + + + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + + + + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + + + + YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); + + + + void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); + + + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + + + + + + + + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + + + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + + + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + + + +/* end tables serialization structures and prototypes */ + + + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + + + + + + + + + + + + + + + + + +extern int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + + + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + + + +#define YY_RULE_SETUP \ + YY_USER_ACTION + + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + + + + yylval = yylval_param; + + + + yylloc = yylloc_param; + + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { + + + + TParseContext* context = yyextra; + + + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 891 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 890 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +{ return INVARIANT; } + YY_BREAK +case 2: +YY_RULE_SETUP +{ return HIGH_PRECISION; } + YY_BREAK +case 3: +YY_RULE_SETUP +{ return MEDIUM_PRECISION; } + YY_BREAK +case 4: +YY_RULE_SETUP +{ return LOW_PRECISION; } + YY_BREAK +case 5: +YY_RULE_SETUP +{ return PRECISION; } + YY_BREAK +case 6: +YY_RULE_SETUP +{ return ES2_keyword_ES3_reserved(context, ATTRIBUTE); } + YY_BREAK +case 7: +YY_RULE_SETUP +{ return CONST_QUAL; } + YY_BREAK +case 8: +YY_RULE_SETUP +{ return UNIFORM; } + YY_BREAK +case 9: +YY_RULE_SETUP +{ return ES2_and_ES3_ident_ES3_1_keyword(context, BUFFER); } + YY_BREAK +case 10: +YY_RULE_SETUP +{ return ES2_keyword_ES3_reserved(context, VARYING); } + YY_BREAK +case 11: +YY_RULE_SETUP +{ return BREAK; } + YY_BREAK +case 12: +YY_RULE_SETUP +{ return CONTINUE; } + YY_BREAK +case 13: +YY_RULE_SETUP +{ return DO; } + YY_BREAK +case 14: +YY_RULE_SETUP +{ return FOR; } + YY_BREAK +case 15: +YY_RULE_SETUP +{ return WHILE; } + YY_BREAK +case 16: +YY_RULE_SETUP +{ return IF; } + YY_BREAK +case 17: +YY_RULE_SETUP +{ return ELSE; } + YY_BREAK +case 18: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, SWITCH); } + YY_BREAK +case 19: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, CASE); } + YY_BREAK +case 20: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, DEFAULT); } + YY_BREAK +case 21: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, CENTROID); } + YY_BREAK +case 22: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, FLAT); } + YY_BREAK +case 23: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SMOOTH); } + YY_BREAK +case 24: +YY_RULE_SETUP +{ return IN_QUAL; } + YY_BREAK +case 25: +YY_RULE_SETUP +{ return OUT_QUAL; } + YY_BREAK +case 26: +YY_RULE_SETUP +{ return INOUT_QUAL; } + YY_BREAK +case 27: +YY_RULE_SETUP +{ return ES2_and_ES3_ident_ES3_1_keyword(context, SHARED); } + YY_BREAK +case 28: +YY_RULE_SETUP +{ return FLOAT_TYPE; } + YY_BREAK +case 29: +YY_RULE_SETUP +{ return INT_TYPE; } + YY_BREAK +case 30: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UINT_TYPE); } + YY_BREAK +case 31: +YY_RULE_SETUP +{ return VOID_TYPE; } + YY_BREAK +case 32: +YY_RULE_SETUP +{ return BOOL_TYPE; } + YY_BREAK +case 33: +YY_RULE_SETUP +{ yylval->lex.b = true; return BOOLCONSTANT; } + YY_BREAK +case 34: +YY_RULE_SETUP +{ yylval->lex.b = false; return BOOLCONSTANT; } + YY_BREAK +case 35: +YY_RULE_SETUP +{ return DISCARD; } + YY_BREAK +case 36: +YY_RULE_SETUP +{ return RETURN; } + YY_BREAK +case 37: +YY_RULE_SETUP +{ return MATRIX2; } + YY_BREAK +case 38: +YY_RULE_SETUP +{ return MATRIX3; } + YY_BREAK +case 39: +YY_RULE_SETUP +{ return MATRIX4; } + YY_BREAK +case 40: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX2); } + YY_BREAK +case 41: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX3); } + YY_BREAK +case 42: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX4); } + YY_BREAK +case 43: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX2x3); } + YY_BREAK +case 44: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX3x2); } + YY_BREAK +case 45: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX2x4); } + YY_BREAK +case 46: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX4x2); } + YY_BREAK +case 47: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX3x4); } + YY_BREAK +case 48: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX4x3); } + YY_BREAK +case 49: +YY_RULE_SETUP +{ return VEC2; } + YY_BREAK +case 50: +YY_RULE_SETUP +{ return VEC3; } + YY_BREAK +case 51: +YY_RULE_SETUP +{ return VEC4; } + YY_BREAK +case 52: +YY_RULE_SETUP +{ return IVEC2; } + YY_BREAK +case 53: +YY_RULE_SETUP +{ return IVEC3; } + YY_BREAK +case 54: +YY_RULE_SETUP +{ return IVEC4; } + YY_BREAK +case 55: +YY_RULE_SETUP +{ return BVEC2; } + YY_BREAK +case 56: +YY_RULE_SETUP +{ return BVEC3; } + YY_BREAK +case 57: +YY_RULE_SETUP +{ return BVEC4; } + YY_BREAK +case 58: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UVEC2); } + YY_BREAK +case 59: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UVEC3); } + YY_BREAK +case 60: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UVEC4); } + YY_BREAK +case 61: +YY_RULE_SETUP +{ return SAMPLER2D; } + YY_BREAK +case 62: +YY_RULE_SETUP +{ return SAMPLERCUBE; } + YY_BREAK +case 63: +YY_RULE_SETUP +{ return SAMPLER_EXTERNAL_OES; } + YY_BREAK +case 64: +YY_RULE_SETUP +{ return ES2_extension_ES3_keyword_else_reserved(context, TExtension::OES_texture_3D, SAMPLER3D); } + YY_BREAK +case 65: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); } + YY_BREAK +case 66: +YY_RULE_SETUP +{ return SAMPLER2DRECT; } + YY_BREAK +case 67: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); } + YY_BREAK +case 68: +YY_RULE_SETUP +{ return ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(context, TExtension::ANGLE_texture_multisample, SAMPLER2DMS); } + YY_BREAK +case 69: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLER2D); } + YY_BREAK +case 70: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLER3D); } + YY_BREAK +case 71: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); } + YY_BREAK +case 72: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); } + YY_BREAK +case 73: +YY_RULE_SETUP +{ return ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(context, TExtension::ANGLE_texture_multisample, ISAMPLER2DMS); } + YY_BREAK +case 74: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLER2D); } + YY_BREAK +case 75: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLER3D); } + YY_BREAK +case 76: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLERCUBE); } + YY_BREAK +case 77: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); } + YY_BREAK +case 78: +YY_RULE_SETUP +{ return ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(context, TExtension::ANGLE_texture_multisample, USAMPLER2DMS); } + YY_BREAK +case 79: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); } + YY_BREAK +case 80: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); } + YY_BREAK +case 81: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); } + YY_BREAK +case 82: +YY_RULE_SETUP +{ return ES3_extension_keyword_else_ident(context, TExtension::EXT_YUV_target, SAMPLEREXTERNAL2DY2YEXT); } + YY_BREAK +case 83: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_extension_keyword(context, TExtension::OES_texture_storage_multisample_2d_array, SAMPLER2DMSARRAY); } + YY_BREAK +case 84: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_extension_keyword(context, TExtension::OES_texture_storage_multisample_2d_array, ISAMPLER2DMSARRAY); } + YY_BREAK +case 85: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_extension_keyword(context, TExtension::OES_texture_storage_multisample_2d_array, USAMPLER2DMSARRAY); } + YY_BREAK +case 86: +YY_RULE_SETUP +{ return STRUCT; } + YY_BREAK +case 87: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, LAYOUT); } + YY_BREAK +case 88: +YY_RULE_SETUP +{ return ES3_extension_keyword_else_ident(context, TExtension::EXT_YUV_target, YUVCSCSTANDARDEXT); } + YY_BREAK +case 89: +YY_RULE_SETUP +{ return yuvcscstandardext_constant(context); } + YY_BREAK +case 90: +YY_RULE_SETUP +{ return yuvcscstandardext_constant(context); } + YY_BREAK +case 91: +YY_RULE_SETUP +{ return yuvcscstandardext_constant(context); } + YY_BREAK +case 92: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2D); } + YY_BREAK +case 93: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2D); } + YY_BREAK +case 94: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2D); } + YY_BREAK +case 95: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE2DARRAY); } + YY_BREAK +case 96: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE2DARRAY); } + YY_BREAK +case 97: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE2DARRAY); } + YY_BREAK +case 98: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGE3D); } + YY_BREAK +case 99: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGE3D); } + YY_BREAK +case 100: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGE3D); } + YY_BREAK +case 101: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IIMAGECUBE); } + YY_BREAK +case 102: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, UIMAGECUBE); } + YY_BREAK +case 103: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, IMAGECUBE); } + YY_BREAK +case 104: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, READONLY); } + YY_BREAK +case 105: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, WRITEONLY); } + YY_BREAK +case 106: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, COHERENT); } + YY_BREAK +case 107: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, RESTRICT); } + YY_BREAK +case 108: +YY_RULE_SETUP +{ return ES2_and_ES3_reserved_ES3_1_keyword(context, VOLATILE); } + YY_BREAK +case 109: +YY_RULE_SETUP +{ return ES2_ident_ES3_reserved_ES3_1_keyword(context, ATOMICUINT); } + YY_BREAK +/* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */ +case 110: +case 111: +case 112: +case 113: +case 114: +case 115: +case 116: +case 117: +case 118: +case 119: +case 120: +case 121: +case 122: +case 123: +case 124: +case 125: +case 126: +case 127: +case 128: +case 129: +case 130: +case 131: +case 132: +case 133: +case 134: +case 135: +case 136: +case 137: +case 138: +case 139: +case 140: +case 141: +case 142: +YY_RULE_SETUP +{ + if (context->getShaderVersion() < 300) { + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); + } + return reserved_word(yyscanner); +} + YY_BREAK +/* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */ +case 143: +YY_RULE_SETUP +{ + if (context->getShaderVersion() >= 300) + { + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); + } + + return reserved_word(yyscanner); +} + YY_BREAK +/* Reserved keywords */ +case 144: +case 145: +case 146: +case 147: +case 148: +case 149: +case 150: +case 151: +case 152: +case 153: +case 154: +case 155: +case 156: +case 157: +case 158: +case 159: +case 160: +case 161: +case 162: +case 163: +case 164: +case 165: +case 166: +case 167: +case 168: +case 169: +case 170: +case 171: +case 172: +case 173: +case 174: +case 175: +case 176: +case 177: +case 178: +case 179: +case 180: +case 181: +case 182: +case 183: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 184: +YY_RULE_SETUP +{ + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); +} + YY_BREAK +case 185: +YY_RULE_SETUP +{ return int_constant(context); } + YY_BREAK +case 186: +YY_RULE_SETUP +{ return int_constant(context); } + YY_BREAK +case 187: +YY_RULE_SETUP +{ return int_constant(context); } + YY_BREAK +case 188: +YY_RULE_SETUP +{ return uint_constant(context); } + YY_BREAK +case 189: +YY_RULE_SETUP +{ return uint_constant(context); } + YY_BREAK +case 190: +YY_RULE_SETUP +{ return uint_constant(context); } + YY_BREAK +case 191: +YY_RULE_SETUP +{ return float_constant(yyscanner); } + YY_BREAK +case 192: +YY_RULE_SETUP +{ return float_constant(yyscanner); } + YY_BREAK +case 193: +YY_RULE_SETUP +{ return float_constant(yyscanner); } + YY_BREAK +case 194: +YY_RULE_SETUP +{ return floatsuffix_check(context); } + YY_BREAK +case 195: +YY_RULE_SETUP +{ return floatsuffix_check(context); } + YY_BREAK +case 196: +YY_RULE_SETUP +{ return floatsuffix_check(context); } + YY_BREAK +case 197: +YY_RULE_SETUP +{ return ADD_ASSIGN; } + YY_BREAK +case 198: +YY_RULE_SETUP +{ return SUB_ASSIGN; } + YY_BREAK +case 199: +YY_RULE_SETUP +{ return MUL_ASSIGN; } + YY_BREAK +case 200: +YY_RULE_SETUP +{ return DIV_ASSIGN; } + YY_BREAK +case 201: +YY_RULE_SETUP +{ return MOD_ASSIGN; } + YY_BREAK +case 202: +YY_RULE_SETUP +{ return LEFT_ASSIGN; } + YY_BREAK +case 203: +YY_RULE_SETUP +{ return RIGHT_ASSIGN; } + YY_BREAK +case 204: +YY_RULE_SETUP +{ return AND_ASSIGN; } + YY_BREAK +case 205: +YY_RULE_SETUP +{ return XOR_ASSIGN; } + YY_BREAK +case 206: +YY_RULE_SETUP +{ return OR_ASSIGN; } + YY_BREAK +case 207: +YY_RULE_SETUP +{ return INC_OP; } + YY_BREAK +case 208: +YY_RULE_SETUP +{ return DEC_OP; } + YY_BREAK +case 209: +YY_RULE_SETUP +{ return AND_OP; } + YY_BREAK +case 210: +YY_RULE_SETUP +{ return OR_OP; } + YY_BREAK +case 211: +YY_RULE_SETUP +{ return XOR_OP; } + YY_BREAK +case 212: +YY_RULE_SETUP +{ return LE_OP; } + YY_BREAK +case 213: +YY_RULE_SETUP +{ return GE_OP; } + YY_BREAK +case 214: +YY_RULE_SETUP +{ return EQ_OP; } + YY_BREAK +case 215: +YY_RULE_SETUP +{ return NE_OP; } + YY_BREAK +case 216: +YY_RULE_SETUP +{ return LEFT_OP; } + YY_BREAK +case 217: +YY_RULE_SETUP +{ return RIGHT_OP; } + YY_BREAK +case 218: +YY_RULE_SETUP +{ return SEMICOLON; } + YY_BREAK +case 219: +YY_RULE_SETUP +{ return LEFT_BRACE; } + YY_BREAK +case 220: +YY_RULE_SETUP +{ return RIGHT_BRACE; } + YY_BREAK +case 221: +YY_RULE_SETUP +{ return COMMA; } + YY_BREAK +case 222: +YY_RULE_SETUP +{ return COLON; } + YY_BREAK +case 223: +YY_RULE_SETUP +{ return EQUAL; } + YY_BREAK +case 224: +YY_RULE_SETUP +{ return LEFT_PAREN; } + YY_BREAK +case 225: +YY_RULE_SETUP +{ return RIGHT_PAREN; } + YY_BREAK +case 226: +YY_RULE_SETUP +{ return LEFT_BRACKET; } + YY_BREAK +case 227: +YY_RULE_SETUP +{ return RIGHT_BRACKET; } + YY_BREAK +case 228: +YY_RULE_SETUP +{ BEGIN(FIELDS); return DOT; } + YY_BREAK +case 229: +YY_RULE_SETUP +{ return BANG; } + YY_BREAK +case 230: +YY_RULE_SETUP +{ return DASH; } + YY_BREAK +case 231: +YY_RULE_SETUP +{ return TILDE; } + YY_BREAK +case 232: +YY_RULE_SETUP +{ return PLUS; } + YY_BREAK +case 233: +YY_RULE_SETUP +{ return STAR; } + YY_BREAK +case 234: +YY_RULE_SETUP +{ return SLASH; } + YY_BREAK +case 235: +YY_RULE_SETUP +{ return PERCENT; } + YY_BREAK +case 236: +YY_RULE_SETUP +{ return LEFT_ANGLE; } + YY_BREAK +case 237: +YY_RULE_SETUP +{ return RIGHT_ANGLE; } + YY_BREAK +case 238: +YY_RULE_SETUP +{ return VERTICAL_BAR; } + YY_BREAK +case 239: +YY_RULE_SETUP +{ return CARET; } + YY_BREAK +case 240: +YY_RULE_SETUP +{ return AMPERSAND; } + YY_BREAK +case 241: +YY_RULE_SETUP +{ return QUESTION; } + YY_BREAK +case 242: +YY_RULE_SETUP +{ + BEGIN(INITIAL); + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return FIELD_SELECTION; +} + YY_BREAK +case 243: +YY_RULE_SETUP +{} + YY_BREAK +case 244: +YY_RULE_SETUP +{ + yyextra->error(*yylloc, "Illegal character at fieldname start", yytext); + return 0; +} + YY_BREAK +case 245: +/* rule 245 can match eol */ +YY_RULE_SETUP +{ } + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(FIELDS): +{ yyterminate(); } + YY_BREAK +case 246: +YY_RULE_SETUP +{ assert(false); return 0; } + YY_BREAK +case 247: +YY_RULE_SETUP +ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + + + + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + size_t result = 0; + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + result, num_to_read ); + yyg->yy_n_chars = static_cast<int>(result); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 891 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 891 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 890); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + + + b->yy_is_interactive = 0; + + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + + + + + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + + + + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + + + + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + + + + + + + + + + + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + + + +/* Accessor methods (get/set functions) to struct members. */ + + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + + + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + + + + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + + + + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + + + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + + + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + + + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + + + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + + + + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + + + + + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + + + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + + + + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + + + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + + +/* Accessor methods for yylval and yylloc */ + + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + + + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + + + + +YYLTYPE *yyget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + + + +void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + + + + + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + + + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + + + + + + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + + + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + + + +/* + * Internal utility routines. + */ + + + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + + + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + + + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + + + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + + + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + + +#define YYTABLES_NAME "yytables" + + + + + + + + +yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) { + angle::pp::Token token; + yyget_extra(yyscanner)->getPreprocessor().lex(&token); + yy_size_t len = token.type == angle::pp::Token::LAST ? 0 : token.text.size(); + if (len < max_size) + memcpy(buf, token.text.c_str(), len); + yyset_column(token.location.file, yyscanner); + yyset_lineno(token.location.line, yyscanner); + + if (len >= max_size) + YY_FATAL_ERROR("Input buffer overflow"); + else if (len > 0) + buf[len++] = ' '; + return len; +} + +int check_type(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + int token = IDENTIFIER; + // Note that the ImmutableString used here isn't static or pool allocated - but it's fine since yytext is valid for the duration of its use. + const TSymbol* symbol = yyextra->symbolTable.find(ImmutableString(yytext, yyleng), yyextra->getShaderVersion()); + if (symbol && symbol->isStruct()) + { + token = TYPE_NAME; + } + yylval->lex.symbol = symbol; + return token; +} + +int reserved_word(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + yyextra->error(*yylloc, "Illegal use of reserved word", yytext); + return 0; +} + +int ES2_reserved_ES3_keyword(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + if (context->getShaderVersion() < 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_keyword_ES3_reserved(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + if (context->getShaderVersion() >= 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_ident_ES3_reserved_ES3_1_keyword(TParseContext *context, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + if (context->getShaderVersion() < 300) + { + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); + } + else if (context->getShaderVersion() == 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_ident_ES3_keyword(TParseContext *context, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name + if (context->getShaderVersion() < 300) + { + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); + } + + return token; +} + +int ES2_and_ES3_reserved_ES3_1_keyword(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + if (context->getShaderVersion() < 310) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_and_ES3_ident_ES3_1_keyword(TParseContext *context, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // not a reserved word in GLSL ES 1.00 and GLSL ES 3.00, so could be used as an identifier/type name + if (context->getShaderVersion() < 310) + { + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); + } + + return token; +} + +int ES2_extension_ES3_keyword_else_reserved(TParseContext *context, TExtension extension, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // Available with extension or ES 3.00 and above, reserved otherwise + if (context->isExtensionEnabled(extension) || context->getShaderVersion() >= 300) + { + return token; + } + + return reserved_word(yyscanner); +} + +int ES3_extension_keyword_else_ident(TParseContext *context, TExtension extension, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // a reserved word in GLSL ES 3.00 with enabled extension, otherwise could be used as an identifier/type name + if (context->getShaderVersion() >= 300 && context->isExtensionEnabled(extension)) + { + return token; + } + + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); +} + +int ES2_ident_ES3_reserved_ES3_1_extension_keyword(TParseContext *context, TExtension extension, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // a keyword in GLSL ES 3.10 with enabled extension + if (context->getShaderVersion() >= 310 && context->isExtensionEnabled(extension)) + { + return token; + } + // a reserved word in GLSL ES 3.00+ + if (context->getShaderVersion() >= 300) + { + return reserved_word(yyscanner); + } + + // Otherwise can be used as an identifier/type name + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); +} + +int ES3_extension_and_ES3_1_keyword_ES3_reserved_else_ident(TParseContext *context, TExtension extension, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // A keyword in GLSL ES 3.00 with enabled extension or in GLSL ES 3.10 + if (context->getShaderVersion() >= 310 || (context->getShaderVersion() == 300 && context->isExtensionEnabled(extension))) + { + return token; + } + + if(context->getShaderVersion() == 300) + { + return reserved_word(yyscanner); + } + + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); +} + +int uint_constant(TParseContext *context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + + if (context->getShaderVersion() < 300) + { + context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext); + return 0; + } + + if (!atoi_clamp(yytext, &(yylval->lex.u))) + yyextra->error(*yylloc, "Integer overflow", yytext); + + return UINTCONSTANT; +} + +int floatsuffix_check(TParseContext* context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + + if (context->getShaderVersion() < 300) + { + context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); + return 0; + } + + std::string text = yytext; + text.resize(text.size() - 1); + if (!strtof_clamp(text, &(yylval->lex.f))) + yyextra->warning(*yylloc, "Float overflow", yytext); + + return(FLOATCONSTANT); +} + +void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) { + context->error(*lloc, reason, yyget_text(scanner)); +} + +int int_constant(TParseContext *context) { + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + + unsigned int u; + if (!atoi_clamp(yytext, &u)) + { + if (context->getShaderVersion() >= 300) + yyextra->error(*yylloc, "Integer overflow", yytext); + else + yyextra->warning(*yylloc, "Integer overflow", yytext); + } + yylval->lex.i = static_cast<int>(u); + return INTCONSTANT; +} + +int float_constant(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + if (!strtof_clamp(yytext, &(yylval->lex.f))) + yyextra->warning(*yylloc, "Float overflow", yytext); + return FLOATCONSTANT; +} + +int yuvcscstandardext_constant(TParseContext *context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->getScanner(); + yyscan_t yyscanner = (yyscan_t) context->getScanner(); + + // a reserved word in GLSL ES 3.00 with enabled extension, otherwise could be used as an identifier/type name + if (context->getShaderVersion() >= 300 && context->isExtensionEnabled(TExtension::EXT_YUV_target)) + { + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return YUVCSCSTANDARDEXTCONSTANT; + } + + yylval->lex.string = AllocatePoolCharArray(yytext, yyleng); + return check_type(yyscanner); +} + +int glslang_initialize(TParseContext* context) { + yyscan_t scanner = NULL; + if (yylex_init_extra(context, &scanner)) + return 1; + + context->setScanner(scanner); + return 0; +} + +int glslang_finalize(TParseContext* context) { + yyscan_t scanner = context->getScanner(); + if (scanner == NULL) return 0; + + context->setScanner(NULL); + yylex_destroy(scanner); + + return 0; +} + +int glslang_scan(size_t count, const char* const string[], const int length[], + TParseContext* context) { + yyrestart(NULL, context->getScanner()); + yyset_column(0, context->getScanner()); + yyset_lineno(1, context->getScanner()); + + // Initialize preprocessor. + angle::pp::Preprocessor *preprocessor = &context->getPreprocessor(); + + if (!preprocessor->init(count, string, length)) + return 1; + + // Define extension macros. + const TExtensionBehavior& extBehavior = context->extensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { + preprocessor->predefineMacro(GetExtensionNameString(iter->first), 1); + } + if (context->getFragmentPrecisionHigh()) + preprocessor->predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1); + + preprocessor->setMaxTokenSize(sh::GetGlobalMaxTokenSize(context->getShaderSpec())); + + return 0; +} + diff --git a/gfx/angle/checkout/src/compiler/translator/glslang_tab.cpp b/gfx/angle/checkout/src/compiler/translator/glslang_tab.cpp new file mode 100644 index 0000000000..bf4efe8cb7 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/glslang_tab.cpp @@ -0,0 +1,5201 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 2 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Copy the first part of user declarations. */ + +// +// Copyright (c) 2002-2014 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. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// clang-format off + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4244) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#pragma warning(disable: 4702) +#endif + +#include "angle_gl.h" +#include "compiler/translator/Declarator.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/ParseContext.h" +#include "GLSLANG/ShaderLang.h" + +#define YYENABLE_NLS 0 + +using namespace sh; + + + + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "glslang_tab.h". */ +#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED +# define YY_YY_GLSLANG_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ + + +#define YYLTYPE TSourceLoc +#define YYLTYPE_IS_DECLARED 1 +#define YYLTYPE_IS_TRIVIAL 1 + + + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + INVARIANT = 258, + HIGH_PRECISION = 259, + MEDIUM_PRECISION = 260, + LOW_PRECISION = 261, + PRECISION = 262, + ATTRIBUTE = 263, + CONST_QUAL = 264, + BOOL_TYPE = 265, + FLOAT_TYPE = 266, + INT_TYPE = 267, + UINT_TYPE = 268, + BREAK = 269, + CONTINUE = 270, + DO = 271, + ELSE = 272, + FOR = 273, + IF = 274, + DISCARD = 275, + RETURN = 276, + SWITCH = 277, + CASE = 278, + DEFAULT = 279, + BVEC2 = 280, + BVEC3 = 281, + BVEC4 = 282, + IVEC2 = 283, + IVEC3 = 284, + IVEC4 = 285, + VEC2 = 286, + VEC3 = 287, + VEC4 = 288, + UVEC2 = 289, + UVEC3 = 290, + UVEC4 = 291, + MATRIX2 = 292, + MATRIX3 = 293, + MATRIX4 = 294, + IN_QUAL = 295, + OUT_QUAL = 296, + INOUT_QUAL = 297, + UNIFORM = 298, + BUFFER = 299, + VARYING = 300, + MATRIX2x3 = 301, + MATRIX3x2 = 302, + MATRIX2x4 = 303, + MATRIX4x2 = 304, + MATRIX3x4 = 305, + MATRIX4x3 = 306, + CENTROID = 307, + FLAT = 308, + SMOOTH = 309, + READONLY = 310, + WRITEONLY = 311, + COHERENT = 312, + RESTRICT = 313, + VOLATILE = 314, + SHARED = 315, + STRUCT = 316, + VOID_TYPE = 317, + WHILE = 318, + SAMPLER2D = 319, + SAMPLERCUBE = 320, + SAMPLER_EXTERNAL_OES = 321, + SAMPLER2DRECT = 322, + SAMPLER2DARRAY = 323, + ISAMPLER2D = 324, + ISAMPLER3D = 325, + ISAMPLERCUBE = 326, + ISAMPLER2DARRAY = 327, + USAMPLER2D = 328, + USAMPLER3D = 329, + USAMPLERCUBE = 330, + USAMPLER2DARRAY = 331, + SAMPLER2DMS = 332, + ISAMPLER2DMS = 333, + USAMPLER2DMS = 334, + SAMPLER2DMSARRAY = 335, + ISAMPLER2DMSARRAY = 336, + USAMPLER2DMSARRAY = 337, + SAMPLER3D = 338, + SAMPLER3DRECT = 339, + SAMPLER2DSHADOW = 340, + SAMPLERCUBESHADOW = 341, + SAMPLER2DARRAYSHADOW = 342, + SAMPLEREXTERNAL2DY2YEXT = 343, + IMAGE2D = 344, + IIMAGE2D = 345, + UIMAGE2D = 346, + IMAGE3D = 347, + IIMAGE3D = 348, + UIMAGE3D = 349, + IMAGE2DARRAY = 350, + IIMAGE2DARRAY = 351, + UIMAGE2DARRAY = 352, + IMAGECUBE = 353, + IIMAGECUBE = 354, + UIMAGECUBE = 355, + ATOMICUINT = 356, + LAYOUT = 357, + YUVCSCSTANDARDEXT = 358, + YUVCSCSTANDARDEXTCONSTANT = 359, + IDENTIFIER = 360, + TYPE_NAME = 361, + FLOATCONSTANT = 362, + INTCONSTANT = 363, + UINTCONSTANT = 364, + BOOLCONSTANT = 365, + FIELD_SELECTION = 366, + LEFT_OP = 367, + RIGHT_OP = 368, + INC_OP = 369, + DEC_OP = 370, + LE_OP = 371, + GE_OP = 372, + EQ_OP = 373, + NE_OP = 374, + AND_OP = 375, + OR_OP = 376, + XOR_OP = 377, + MUL_ASSIGN = 378, + DIV_ASSIGN = 379, + ADD_ASSIGN = 380, + MOD_ASSIGN = 381, + LEFT_ASSIGN = 382, + RIGHT_ASSIGN = 383, + AND_ASSIGN = 384, + XOR_ASSIGN = 385, + OR_ASSIGN = 386, + SUB_ASSIGN = 387, + LEFT_PAREN = 388, + RIGHT_PAREN = 389, + LEFT_BRACKET = 390, + RIGHT_BRACKET = 391, + LEFT_BRACE = 392, + RIGHT_BRACE = 393, + DOT = 394, + COMMA = 395, + COLON = 396, + EQUAL = 397, + SEMICOLON = 398, + BANG = 399, + DASH = 400, + TILDE = 401, + PLUS = 402, + STAR = 403, + SLASH = 404, + PERCENT = 405, + LEFT_ANGLE = 406, + RIGHT_ANGLE = 407, + VERTICAL_BAR = 408, + CARET = 409, + AMPERSAND = 410, + QUESTION = 411 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ + + + struct { + union { + const char *string; // pool allocated. + float f; + int i; + unsigned int u; + bool b; + }; + const TSymbol* symbol; + } lex; + struct { + TOperator op; + union { + TIntermNode *intermNode; + TIntermNodePair nodePair; + TIntermTyped *intermTypedNode; + TIntermAggregate *intermAggregate; + TIntermBlock *intermBlock; + TIntermDeclaration *intermDeclaration; + TIntermFunctionPrototype *intermFunctionPrototype; + TIntermSwitch *intermSwitch; + TIntermCase *intermCase; + }; + union { + TVector<unsigned int> *arraySizes; + TTypeSpecifierNonArray typeSpecifierNonArray; + TPublicType type; + TPrecision precision; + TLayoutQualifier layoutQualifier; + TQualifier qualifier; + TFunction *function; + TFunctionLookup *functionLookup; + TParameter param; + TDeclarator *declarator; + TDeclaratorList *declaratorList; + TFieldList *fieldList; + TQualifierWrapperBase *qualifierWrapper; + TTypeQualifierBuilder *typeQualifierBuilder; + }; + } interm; + + +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + +/* Location type. */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + +int yyparse (TParseContext* context, void *scanner); + +#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + + +extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner); +extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, const char* reason); + +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (N) { \ + (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).last_file = YYRHSLOC(Rhs, N).last_file; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + } \ + else { \ + (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \ + (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ + (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \ + (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \ + } \ + } while (0) + +#define VERTEX_ONLY(S, L) do { \ + if (context->getShaderType() != GL_VERTEX_SHADER) { \ + context->error(L, " supported in vertex shaders only", S); \ + } \ +} while (0) + +#define COMPUTE_ONLY(S, L) do { \ + if (context->getShaderType() != GL_COMPUTE_SHADER) { \ + context->error(L, " supported in compute shaders only", S); \ + } \ +} while (0) + +#define ES2_ONLY(S, L) do { \ + if (context->getShaderVersion() != 100) { \ + context->error(L, " supported in GLSL ES 1.00 only", S); \ + } \ +} while (0) + +#define ES3_OR_NEWER(TOKEN, LINE, REASON) do { \ + if (context->getShaderVersion() < 300) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 and above only", TOKEN); \ + } \ +} while (0) + +#define ES3_1_ONLY(TOKEN, LINE, REASON) do { \ + if (context->getShaderVersion() != 310) { \ + context->error(LINE, REASON " supported in GLSL ES 3.10 only", TOKEN); \ + } \ +} while (0) + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 138 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 2973 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 157 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 95 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 300 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 426 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 411 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 248, 248, 249, 252, 259, 262, 267, 272, 277, + 282, 291, 297, 300, 303, 306, 309, 312, 318, 325, + 331, 334, 342, 345, 351, 354, 360, 364, 371, 379, + 382, 385, 391, 394, 397, 400, 407, 408, 409, 410, + 418, 419, 422, 425, 432, 433, 436, 442, 443, 447, + 454, 455, 458, 461, 464, 470, 471, 474, 480, 481, + 488, 489, 496, 497, 504, 505, 511, 512, 518, 519, + 525, 526, 532, 533, 539, 540, 541, 542, 546, 547, + 548, 552, 556, 560, 564, 571, 574, 580, 587, 594, + 597, 600, 604, 608, 612, 616, 620, 627, 634, 637, + 644, 652, 669, 679, 682, 688, 692, 696, 700, 707, + 714, 717, 721, 725, 730, 737, 741, 745, 749, 754, + 761, 765, 771, 774, 780, 784, 791, 797, 801, 805, + 808, 811, 820, 825, 829, 832, 835, 838, 841, 845, + 848, 852, 855, 858, 861, 864, 867, 874, 881, 884, + 887, 893, 900, 903, 909, 912, 915, 918, 924, 927, + 934, 939, 946, 951, 962, 965, 968, 971, 974, 977, + 981, 985, 989, 993, 997, 1001, 1005, 1009, 1013, 1017, + 1021, 1025, 1029, 1033, 1037, 1041, 1045, 1049, 1053, 1057, + 1061, 1068, 1071, 1074, 1077, 1080, 1083, 1086, 1089, 1092, + 1095, 1098, 1101, 1104, 1107, 1110, 1113, 1116, 1119, 1122, + 1125, 1128, 1131, 1141, 1148, 1155, 1158, 1161, 1164, 1167, + 1170, 1173, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197, + 1205, 1205, 1208, 1208, 1214, 1217, 1223, 1226, 1233, 1237, + 1243, 1246, 1252, 1256, 1260, 1261, 1267, 1268, 1269, 1270, + 1271, 1272, 1273, 1277, 1281, 1281, 1281, 1288, 1289, 1293, + 1293, 1294, 1294, 1299, 1303, 1310, 1314, 1321, 1322, 1326, + 1332, 1336, 1345, 1345, 1352, 1355, 1361, 1365, 1371, 1371, + 1376, 1376, 1380, 1380, 1388, 1391, 1397, 1400, 1406, 1410, + 1417, 1420, 1423, 1426, 1429, 1437, 1443, 1449, 1452, 1458, + 1458 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "INVARIANT", "HIGH_PRECISION", + "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "ATTRIBUTE", + "CONST_QUAL", "BOOL_TYPE", "FLOAT_TYPE", "INT_TYPE", "UINT_TYPE", + "BREAK", "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", + "SWITCH", "CASE", "DEFAULT", "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3", + "IVEC4", "VEC2", "VEC3", "VEC4", "UVEC2", "UVEC3", "UVEC4", "MATRIX2", + "MATRIX3", "MATRIX4", "IN_QUAL", "OUT_QUAL", "INOUT_QUAL", "UNIFORM", + "BUFFER", "VARYING", "MATRIX2x3", "MATRIX3x2", "MATRIX2x4", "MATRIX4x2", + "MATRIX3x4", "MATRIX4x3", "CENTROID", "FLAT", "SMOOTH", "READONLY", + "WRITEONLY", "COHERENT", "RESTRICT", "VOLATILE", "SHARED", "STRUCT", + "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE", "SAMPLER_EXTERNAL_OES", + "SAMPLER2DRECT", "SAMPLER2DARRAY", "ISAMPLER2D", "ISAMPLER3D", + "ISAMPLERCUBE", "ISAMPLER2DARRAY", "USAMPLER2D", "USAMPLER3D", + "USAMPLERCUBE", "USAMPLER2DARRAY", "SAMPLER2DMS", "ISAMPLER2DMS", + "USAMPLER2DMS", "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY", + "USAMPLER2DMSARRAY", "SAMPLER3D", "SAMPLER3DRECT", "SAMPLER2DSHADOW", + "SAMPLERCUBESHADOW", "SAMPLER2DARRAYSHADOW", "SAMPLEREXTERNAL2DY2YEXT", + "IMAGE2D", "IIMAGE2D", "UIMAGE2D", "IMAGE3D", "IIMAGE3D", "UIMAGE3D", + "IMAGE2DARRAY", "IIMAGE2DARRAY", "UIMAGE2DARRAY", "IMAGECUBE", + "IIMAGECUBE", "UIMAGECUBE", "ATOMICUINT", "LAYOUT", "YUVCSCSTANDARDEXT", + "YUVCSCSTANDARDEXTCONSTANT", "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT", + "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", "FIELD_SELECTION", + "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", + "NE_OP", "AND_OP", "OR_OP", "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", + "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", + "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", "RIGHT_PAREN", + "LEFT_BRACKET", "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", + "COMMA", "COLON", "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", + "STAR", "SLASH", "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", + "CARET", "AMPERSAND", "QUESTION", "$accept", "identifier", + "variable_identifier", "primary_expression", "postfix_expression", + "integer_expression", "function_call", "function_call_or_method", + "function_call_generic", "function_call_header_no_parameters", + "function_call_header_with_parameters", "function_call_header", + "function_identifier", "unary_expression", "unary_operator", + "multiplicative_expression", "additive_expression", "shift_expression", + "relational_expression", "equality_expression", "and_expression", + "exclusive_or_expression", "inclusive_or_expression", + "logical_and_expression", "logical_xor_expression", + "logical_or_expression", "conditional_expression", + "assignment_expression", "assignment_operator", "expression", + "constant_expression", "enter_struct", "declaration", + "function_prototype", "function_declarator", + "function_header_with_parameters", "function_header", + "parameter_declarator", "parameter_declaration", + "parameter_type_specifier", "init_declarator_list", "single_declaration", + "fully_specified_type", "interpolation_qualifier", "type_qualifier", + "invariant_qualifier", "single_type_qualifier", "storage_qualifier", + "type_specifier", "precision_qualifier", "layout_qualifier", + "layout_qualifier_id_list", "layout_qualifier_id", + "type_specifier_no_prec", "array_specifier", "type_specifier_nonarray", + "struct_specifier", "$@1", "$@2", "struct_declaration_list", + "struct_declaration", "struct_declarator_list", "struct_declarator", + "initializer", "declaration_statement", "statement", "simple_statement", + "compound_statement_with_scope", "$@3", "$@4", "statement_no_new_scope", + "statement_with_scope", "$@5", "$@6", "compound_statement_no_new_scope", + "statement_list", "expression_statement", "selection_statement", + "selection_rest_statement", "switch_statement", "$@7", "case_label", + "condition", "iteration_statement", "$@8", "$@9", "$@10", + "for_init_statement", "conditionopt", "for_rest_statement", + "jump_statement", "translation_unit", "external_declaration", + "function_definition", "$@11", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411 +}; +# endif + +#define YYPACT_NINF -361 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-361))) + +#define YYTABLE_NINF -260 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 2569, -361, -361, -361, -361, 126, -361, -361, -361, -361, + -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, + -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, + -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, + -361, -361, -361, -361, -361, -361, -361, -361, -61, -361, + -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, + -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, + -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, + -361, -361, -361, -361, -361, -361, -361, -108, -361, -361, + -361, -69, -99, -45, 2673, -119, -361, 2, -361, 1397, + -361, -361, -361, -361, -361, -361, -361, -80, -361, 2465, + -361, -361, 2867, -361, -361, -361, -24, -40, -361, -17, + -361, 2673, -361, -361, -361, 2673, 39, 39, -361, -5, + -96, -56, -361, 2673, -361, -361, 1495, -32, -361, -361, + -9, 2673, -361, -361, -2, -51, -361, 420, -361, -361, + -361, -361, -80, -65, -361, 1873, -60, -361, -361, 2673, + 39, 2123, -361, -361, 27, -361, -361, -361, -361, -361, + 1873, 1873, 1873, -361, -361, -361, -361, -361, -361, -361, + -67, -361, -361, -361, 28, -48, 1997, 33, -361, 1873, + 15, 22, 58, -89, 54, 24, 34, 38, 67, 72, + -95, -361, 59, -361, 1622, -361, 2237, 2673, 66, -361, + -40, 53, 55, -361, 64, 69, 56, 1749, 71, 1873, + 68, 75, 62, -361, -361, 26, -361, -361, -86, -361, + -69, 77, -361, -361, -361, -361, 565, -361, -361, -361, + -361, -361, -361, -32, 1873, -57, -361, -361, 1873, 39, + -80, -50, -361, -83, -361, -361, -361, -43, -361, -361, + 1873, 2770, -361, -361, 1873, 81, -361, -361, -361, 1873, + 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, + 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, -361, + -361, 80, -361, 2351, -361, -361, -361, -361, -361, 74, + -361, 1873, -361, -361, -21, 1873, 76, -361, -361, -361, + 710, -361, -361, -361, -361, -361, -361, -361, -361, -361, + -361, -361, 1873, 1873, -361, -361, -361, -361, 1873, -361, + -16, -32, 39, -361, -101, -361, -361, 82, 65, -361, + 86, -361, -361, -361, -361, -361, 15, 15, 22, 22, + 58, 58, 58, 58, -89, -89, 54, 24, 34, 38, + 67, 72, 40, -361, -361, 157, -17, 1000, 1145, -34, + -361, -30, -361, 1271, 710, -361, -361, -361, -361, -361, + 1873, -361, -361, 1873, 88, -361, -361, -361, -361, 1271, + 74, -361, 65, 39, 2673, 89, 84, 90, -361, 1873, + -361, 85, 91, 207, -361, 92, 93, 855, -361, 95, + -29, 1873, 855, 74, -361, 1873, -361, -361, -361, -361, + 96, 65, -361, -361, -361, -361 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 0, 126, 148, 149, 150, 0, 132, 134, 168, 165, + 166, 167, 172, 173, 174, 175, 176, 177, 169, 170, + 171, 178, 179, 180, 181, 182, 183, 135, 136, 137, + 139, 140, 133, 184, 185, 186, 187, 188, 189, 138, + 123, 122, 141, 142, 143, 144, 145, 146, 0, 164, + 191, 193, 212, 214, 194, 197, 198, 199, 200, 203, + 204, 205, 206, 195, 201, 207, 196, 202, 208, 192, + 209, 210, 211, 213, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 0, 190, 229, + 298, 299, 0, 99, 98, 0, 110, 115, 130, 0, + 131, 124, 127, 120, 129, 128, 147, 158, 228, 0, + 295, 297, 0, 2, 3, 232, 0, 0, 89, 0, + 97, 0, 106, 100, 108, 0, 109, 0, 90, 2, + 116, 0, 95, 0, 125, 121, 0, 159, 1, 296, + 0, 0, 230, 157, 154, 0, 152, 0, 300, 101, + 105, 107, 103, 111, 102, 0, 117, 88, 96, 0, + 0, 0, 234, 10, 4, 8, 6, 7, 9, 31, + 0, 0, 0, 160, 38, 37, 39, 36, 5, 12, + 32, 14, 19, 20, 0, 0, 25, 0, 40, 0, + 44, 47, 50, 55, 58, 60, 62, 64, 66, 68, + 70, 87, 0, 29, 0, 91, 0, 0, 0, 151, + 0, 0, 0, 280, 0, 0, 0, 0, 0, 0, + 0, 0, 254, 263, 267, 40, 72, 85, 0, 243, + 0, 147, 246, 265, 245, 244, 0, 247, 248, 249, + 250, 251, 252, 104, 0, 112, 242, 119, 0, 0, + 240, 0, 238, 0, 235, 33, 34, 0, 16, 17, + 0, 0, 23, 22, 0, 164, 26, 28, 35, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, + 162, 0, 233, 0, 155, 156, 153, 291, 290, 261, + 282, 0, 294, 292, 0, 0, 0, 275, 278, 253, + 0, 75, 76, 78, 77, 80, 81, 82, 83, 84, + 79, 74, 0, 0, 268, 264, 266, 114, 0, 118, + 0, 241, 0, 236, 0, 92, 11, 0, 18, 30, + 15, 21, 27, 41, 42, 43, 46, 45, 48, 49, + 53, 54, 51, 52, 56, 57, 59, 61, 63, 65, + 67, 69, 0, 163, 231, 0, 0, 0, 0, 0, + 293, 0, 274, 0, 255, 73, 86, 113, 237, 239, + 0, 93, 13, 0, 0, 260, 262, 285, 284, 287, + 261, 272, 276, 0, 0, 0, 0, 0, 71, 0, + 286, 0, 0, 271, 269, 0, 0, 0, 256, 0, + 0, 288, 0, 261, 273, 0, 258, 279, 257, 94, + 0, 289, 283, 270, 277, 281 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -361, -47, -361, -361, -361, -361, -361, -361, -28, -361, + -361, -361, -361, 42, -361, -87, -85, -140, -88, -55, + -49, -52, -44, -42, -39, -361, -131, -146, -361, -159, + -196, -361, 14, 17, -361, -361, -361, 117, 122, 120, + -361, -361, -337, -361, -90, -361, -93, -361, -92, 242, + -361, -361, 41, 0, -115, -361, -361, -361, -361, -123, + -150, 4, -78, -232, -113, -226, -348, -149, -361, -361, + -155, -360, -361, -361, -116, -46, -110, -361, -361, -361, + -361, -361, -130, -361, -361, -361, -361, -361, -361, -361, + -361, -361, 151, -361, -361 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 250, 178, 179, 180, 337, 181, 182, 183, 184, + 185, 186, 187, 225, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 226, 227, 322, 228, + 202, 133, 229, 230, 92, 93, 94, 122, 123, 124, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 145, 146, 203, 137, 107, 108, 207, 141, 161, + 162, 251, 252, 247, 232, 233, 234, 235, 310, 396, + 417, 365, 366, 367, 418, 236, 237, 238, 404, 239, + 405, 240, 395, 241, 373, 299, 368, 389, 401, 402, + 242, 109, 110, 111, 119 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 106, 116, 126, 148, 125, 201, 134, 135, 291, 246, + 326, 254, 327, 257, 90, 156, 329, 91, 206, 386, + 143, 127, 334, 306, 128, 117, 287, 276, 277, 126, + 403, 125, 134, 126, 380, 120, 393, 243, 245, 136, + 266, 160, 381, 159, 113, 114, 155, 258, 259, 160, + 130, 159, 393, 423, 323, 136, 254, 324, 304, 416, + 335, 288, 278, 279, 416, 144, 134, 249, 260, 160, + 136, 159, 261, 201, 118, 204, 115, 244, 204, 152, + 153, 157, 248, 209, 293, 328, 263, 158, 201, 210, + 332, 336, 264, 333, 106, 121, 377, 323, 246, 106, + 390, 338, 246, 204, 391, 420, 323, 129, 114, 106, + 323, 323, 140, 142, 160, 160, 159, 159, 342, 323, + 147, 106, 370, 90, 332, 106, 91, 378, 154, 362, + 2, 3, 4, 106, 205, 331, 350, 351, 352, 353, + 208, 106, 369, 254, 113, 114, 371, 231, 326, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 106, + -30, 106, 262, 269, 270, 271, 267, 272, 321, 273, + 274, 275, 280, 281, 294, 295, 375, 376, 188, 282, + 323, 383, 246, 424, 397, 346, 347, 285, 283, 348, + 349, 284, 354, 355, 286, 289, 297, 300, 298, 302, + 309, 160, 301, 159, 305, 323, 106, 106, 308, 307, + -29, -259, 255, 256, 392, -24, 363, 372, 382, -31, + 384, 399, 408, 407, 413, 412, 409, 356, 411, 222, + 392, 268, 358, 341, 357, 415, 231, 398, 419, 425, + 410, 359, 150, 149, 360, 151, 188, 112, 361, 201, + 385, 296, 421, 330, 379, 387, 414, 422, 388, 400, + 139, 188, 0, 0, 374, 0, 0, 0, 0, 246, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 106, 0, 0, 0, 0, 0, 394, + 0, 134, 135, 0, 0, 0, 0, 0, 0, 0, + 231, 343, 344, 345, 188, 188, 188, 188, 188, 188, + 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 406, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 231, 231, 0, + 0, 0, 0, 231, 231, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, + 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, + 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 188, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 211, 212, 213, 0, 214, 215, + 216, 217, 218, 219, 220, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 221, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 163, 164, 89, 165, 166, 167, + 168, 169, 0, 0, 170, 171, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 0, 0, 0, 222, 223, 0, + 0, 0, 0, 224, 174, 175, 176, 177, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 211, + 212, 213, 0, 214, 215, 216, 217, 218, 219, 220, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 221, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 163, + 164, 89, 165, 166, 167, 168, 169, 0, 0, 170, + 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, + 0, 0, 222, 325, 0, 0, 0, 0, 224, 174, + 175, 176, 177, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 211, 212, 213, 0, 214, 215, + 216, 217, 218, 219, 220, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 221, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 163, 164, 89, 165, 166, 167, + 168, 169, 0, 0, 170, 171, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 0, 0, 0, 222, 0, 0, + 0, 0, 0, 224, 174, 175, 176, 177, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 211, + 212, 213, 0, 214, 215, 216, 217, 218, 219, 220, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 221, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 163, + 164, 89, 165, 166, 167, 168, 169, 0, 0, 170, + 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, + 0, 0, 147, 0, 0, 0, 0, 0, 224, 174, + 175, 176, 177, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 211, 212, 213, 0, 214, 215, + 216, 217, 218, 219, 220, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 221, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 163, 164, 89, 165, 166, 167, + 168, 169, 0, 0, 170, 171, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 224, 174, 175, 176, 177, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 0, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 163, + 164, 89, 165, 166, 167, 168, 169, 0, 0, 170, + 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 3, 4, 172, 6, + 7, 8, 9, 10, 11, 0, 0, 0, 224, 174, + 175, 176, 177, 0, 0, 0, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 0, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 0, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 163, 164, 89, 165, 166, + 167, 168, 169, 0, 0, 170, 171, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 172, 6, 7, 8, 9, 10, + 11, 0, 0, 0, 0, 174, 175, 176, 177, 0, + 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 0, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 0, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 0, 131, 89, 0, 8, 9, 10, 11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 0, 0, 0, 0, 0, + 132, 33, 34, 35, 36, 37, 38, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 48, 49, 0, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 0, 88, 163, + 164, 89, 165, 166, 167, 168, 169, 0, 0, 170, + 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, + 0, 173, 8, 9, 10, 11, 0, 0, 0, 174, + 175, 176, 177, 0, 0, 0, 0, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 0, 0, 0, 0, 0, 0, 33, 34, + 35, 36, 37, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 48, 49, 0, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 0, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 0, 88, 163, 164, 89, 165, + 166, 167, 168, 169, 0, 0, 170, 171, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 0, 0, 290, 8, + 9, 10, 11, 0, 0, 0, 174, 175, 176, 177, + 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, + 0, 0, 0, 0, 0, 33, 34, 35, 36, 37, + 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 0, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 0, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 0, 88, 163, 164, 89, 165, 166, 167, 168, + 169, 0, 0, 170, 171, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 8, 9, 10, 11, 0, 0, 0, + 0, 0, 303, 174, 175, 176, 177, 0, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 0, 0, 0, 0, 0, 0, 33, + 34, 35, 36, 37, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 48, 49, 0, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 0, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 0, 88, 163, 164, 89, + 165, 166, 167, 168, 169, 0, 0, 170, 171, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 172, 8, 9, 10, + 11, 0, 0, 0, 0, 0, 0, 174, 175, 176, + 177, 0, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, + 0, 0, 0, 33, 34, 35, 36, 37, 38, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 48, 265, + 0, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 0, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 0, + 88, 163, 164, 89, 165, 166, 167, 168, 169, 0, + 0, 170, 171, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 172, 6, 7, 8, 9, 10, 11, 0, 0, 0, + 0, 174, 175, 176, 177, 0, 0, 0, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 0, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 0, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 0, 0, 89, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 0, 6, 7, 8, 9, 10, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 253, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 0, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 0, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 0, 0, 89, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 3, 4, 0, 6, + 7, 8, 9, 10, 11, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 292, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 0, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 0, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 0, 0, 89, 0, 0, + 0, 0, 0, 0, 0, 138, 0, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 364, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 0, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 0, + 0, 89, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 0, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 0, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 0, 0, 89, 1, 2, 3, 4, + 0, 6, 7, 8, 9, 10, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 0, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 0, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 0, 0, 89, + 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, + 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 48, 49, 0, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 0, 88, 0, 339, 89, 8, 9, 10, + 11, 340, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, + 0, 0, 0, 33, 34, 35, 36, 37, 38, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 48, 49, + 0, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 0, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 0, + 88, 0, 0, 89 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 48, 94, 119, 94, 136, 99, 99, 204, 155, + 236, 161, 244, 172, 0, 130, 248, 0, 141, 367, + 60, 140, 105, 219, 143, 133, 121, 116, 117, 121, + 390, 121, 125, 125, 135, 134, 373, 152, 153, 135, + 186, 133, 143, 133, 105, 106, 142, 114, 115, 141, + 97, 141, 389, 413, 140, 135, 206, 143, 217, 407, + 143, 156, 151, 152, 412, 105, 159, 159, 135, 161, + 135, 161, 139, 204, 143, 135, 137, 142, 135, 126, + 127, 137, 142, 134, 207, 142, 134, 143, 219, 140, + 140, 134, 140, 143, 94, 140, 328, 140, 244, 99, + 134, 260, 248, 135, 134, 134, 140, 105, 106, 109, + 140, 140, 112, 137, 206, 207, 206, 207, 264, 140, + 137, 121, 143, 109, 140, 125, 109, 143, 133, 288, + 4, 5, 6, 133, 143, 250, 276, 277, 278, 279, + 142, 141, 301, 293, 105, 106, 305, 147, 374, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 159, + 133, 161, 134, 148, 149, 150, 133, 145, 142, 147, + 112, 113, 118, 119, 108, 109, 322, 323, 136, 155, + 140, 141, 328, 415, 380, 272, 273, 120, 154, 274, + 275, 153, 280, 281, 122, 136, 143, 133, 143, 143, + 138, 293, 133, 293, 133, 140, 206, 207, 133, 141, + 133, 137, 170, 171, 373, 134, 136, 141, 136, 133, + 63, 133, 138, 134, 17, 134, 136, 282, 143, 137, + 389, 189, 284, 261, 283, 142, 236, 383, 143, 143, + 399, 285, 125, 121, 286, 125, 204, 5, 287, 380, + 366, 210, 411, 249, 332, 368, 405, 412, 368, 389, + 109, 219, -1, -1, 310, -1, -1, -1, -1, 415, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 373, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 293, -1, -1, -1, -1, -1, 389, + -1, 394, 394, -1, -1, -1, -1, -1, -1, -1, + 310, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 393, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 367, 368, -1, + -1, -1, -1, 373, 374, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 389, + -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 407, -1, -1, + -1, -1, 412, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 380, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, -1, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, -1, -1, 114, 115, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 133, -1, -1, -1, 137, 138, -1, + -1, -1, -1, 143, 144, 145, 146, 147, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, -1, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, -1, -1, 114, + 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 133, -1, + -1, -1, 137, 138, -1, -1, -1, -1, 143, 144, + 145, 146, 147, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, -1, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, -1, -1, 114, 115, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 133, -1, -1, -1, 137, -1, -1, + -1, -1, -1, 143, 144, 145, 146, 147, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, -1, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, -1, -1, 114, + 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 133, -1, + -1, -1, 137, -1, -1, -1, -1, -1, 143, 144, + 145, 146, 147, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, -1, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, -1, -1, 114, 115, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 133, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 143, 144, 145, 146, 147, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, -1, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, -1, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, -1, -1, 114, + 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, 4, 5, 6, 133, 8, + 9, 10, 11, 12, 13, -1, -1, -1, 143, 144, + 145, 146, 147, -1, -1, -1, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, -1, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, -1, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, -1, -1, 114, 115, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 4, 5, 6, 133, 8, 9, 10, 11, 12, + 13, -1, -1, -1, -1, 144, 145, 146, 147, -1, + -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + -1, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, -1, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, -1, 105, 106, -1, 10, 11, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, -1, -1, -1, -1, -1, + 143, 46, 47, 48, 49, 50, 51, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 61, 62, -1, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, -1, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, -1, 103, 104, + 105, 106, 107, 108, 109, 110, 111, -1, -1, 114, + 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 133, -1, + -1, 136, 10, 11, 12, 13, -1, -1, -1, 144, + 145, 146, 147, -1, -1, -1, -1, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, -1, -1, -1, -1, -1, -1, 46, 47, + 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 61, 62, -1, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, -1, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, -1, 103, 104, 105, 106, 107, + 108, 109, 110, 111, -1, -1, 114, 115, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 133, -1, -1, 136, 10, + 11, 12, 13, -1, -1, -1, 144, 145, 146, 147, + -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, -1, + -1, -1, -1, -1, -1, 46, 47, 48, 49, 50, + 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 61, 62, -1, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, -1, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, -1, 103, 104, 105, 106, 107, 108, 109, 110, + 111, -1, -1, 114, 115, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 133, 10, 11, 12, 13, -1, -1, -1, + -1, -1, 143, 144, 145, 146, 147, -1, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, -1, -1, -1, -1, -1, -1, 46, + 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 61, 62, -1, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, -1, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, -1, 103, 104, 105, 106, + 107, 108, 109, 110, 111, -1, -1, 114, 115, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 133, 10, 11, 12, + 13, -1, -1, -1, -1, -1, -1, 144, 145, 146, + 147, -1, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, -1, -1, -1, + -1, -1, -1, 46, 47, 48, 49, 50, 51, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, + -1, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, -1, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, -1, + 103, 104, 105, 106, 107, 108, 109, 110, 111, -1, + -1, 114, 115, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, + 133, 8, 9, 10, 11, 12, 13, -1, -1, -1, + -1, 144, 145, 146, 147, -1, -1, -1, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, -1, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, -1, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, -1, -1, 106, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 4, 5, 6, -1, 8, 9, 10, 11, 12, + 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 138, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + -1, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, -1, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, -1, -1, 106, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, 4, 5, 6, -1, 8, + 9, 10, 11, 12, 13, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 138, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, -1, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, -1, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, -1, -1, 106, -1, -1, + -1, -1, -1, -1, -1, 0, -1, -1, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 138, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, -1, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, -1, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, -1, + -1, 106, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, -1, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, -1, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, -1, -1, 106, 3, 4, 5, 6, + -1, 8, 9, 10, 11, 12, 13, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, -1, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, -1, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, -1, -1, 106, + 10, 11, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + -1, -1, -1, -1, -1, -1, 46, 47, 48, 49, + 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 61, 62, -1, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, -1, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, -1, 103, -1, 105, 106, 10, 11, 12, + 13, 111, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, -1, -1, -1, + -1, -1, -1, 46, 47, 48, 49, 50, 51, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, + -1, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, -1, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, -1, + 103, -1, -1, 106 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 106, + 189, 190, 191, 192, 193, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 210, 212, 213, 248, + 249, 250, 206, 105, 106, 137, 158, 133, 143, 251, + 134, 140, 194, 195, 196, 201, 205, 140, 143, 105, + 158, 105, 143, 188, 203, 205, 135, 211, 0, 249, + 210, 215, 137, 60, 105, 208, 209, 137, 231, 195, + 194, 196, 158, 158, 133, 142, 211, 137, 143, 201, + 205, 216, 217, 104, 105, 107, 108, 109, 110, 111, + 114, 115, 133, 136, 144, 145, 146, 147, 159, 160, + 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 187, 210, 135, 143, 216, 214, 142, 134, + 140, 14, 15, 16, 18, 19, 20, 21, 22, 23, + 24, 63, 137, 138, 143, 170, 183, 184, 186, 189, + 190, 210, 221, 222, 223, 224, 232, 233, 234, 236, + 238, 240, 247, 211, 142, 211, 184, 220, 142, 205, + 158, 218, 219, 138, 217, 170, 170, 186, 114, 115, + 135, 139, 134, 134, 140, 62, 184, 133, 170, 148, + 149, 150, 145, 147, 112, 113, 116, 117, 151, 152, + 118, 119, 155, 154, 153, 120, 122, 121, 156, 136, + 136, 187, 138, 216, 108, 109, 209, 143, 143, 242, + 133, 133, 143, 143, 186, 133, 187, 141, 133, 138, + 225, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 142, 185, 140, 143, 138, 222, 220, 142, 220, + 218, 211, 140, 143, 105, 143, 134, 162, 186, 105, + 111, 165, 184, 170, 170, 170, 172, 172, 173, 173, + 174, 174, 174, 174, 175, 175, 176, 177, 178, 179, + 180, 181, 186, 136, 138, 228, 229, 230, 243, 186, + 143, 186, 141, 241, 232, 184, 184, 220, 143, 219, + 135, 143, 136, 141, 63, 231, 223, 221, 233, 244, + 134, 134, 186, 199, 201, 239, 226, 187, 184, 133, + 239, 245, 246, 228, 235, 237, 158, 134, 138, 136, + 186, 143, 134, 17, 224, 142, 223, 227, 231, 143, + 134, 186, 227, 228, 220, 143 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 157, 158, 158, 159, 160, 160, 160, 160, 160, + 160, 160, 161, 161, 161, 161, 161, 161, 162, 163, + 164, 164, 165, 165, 166, 166, 167, 167, 168, 169, + 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, + 172, 172, 172, 172, 173, 173, 173, 174, 174, 174, + 175, 175, 175, 175, 175, 176, 176, 176, 177, 177, + 178, 178, 179, 179, 180, 180, 181, 181, 182, 182, + 183, 183, 184, 184, 185, 185, 185, 185, 185, 185, + 185, 185, 185, 185, 185, 186, 186, 187, 188, 189, + 189, 189, 189, 189, 189, 189, 189, 190, 191, 191, + 192, 192, 193, 194, 194, 195, 195, 195, 195, 196, + 197, 197, 197, 197, 197, 198, 198, 198, 198, 198, + 199, 199, 200, 200, 201, 201, 202, 203, 203, 203, + 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 205, 206, 206, + 206, 207, 208, 208, 209, 209, 209, 209, 210, 210, + 211, 211, 211, 211, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 214, 213, 215, 213, 216, 216, 217, 217, 218, 218, + 219, 219, 220, 221, 222, 222, 223, 223, 223, 223, + 223, 223, 223, 224, 225, 226, 224, 227, 227, 229, + 228, 230, 228, 231, 231, 232, 232, 233, 233, 234, + 235, 235, 237, 236, 238, 238, 239, 239, 241, 240, + 242, 240, 243, 240, 244, 244, 245, 245, 246, 246, + 247, 247, 247, 247, 247, 248, 248, 249, 249, 251, + 250 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 4, 1, 3, 2, 2, 1, 1, + 1, 3, 2, 2, 2, 1, 2, 3, 2, 1, + 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, + 1, 3, 3, 3, 1, 3, 3, 1, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 5, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 2, 2, + 2, 4, 5, 6, 9, 2, 3, 2, 1, 1, + 2, 3, 3, 2, 3, 2, 1, 2, 1, 1, + 1, 3, 4, 6, 5, 1, 2, 3, 5, 4, + 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 3, 1, 3, 3, 1, 1, 2, + 2, 3, 3, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 6, 0, 5, 1, 2, 3, 4, 1, 3, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 0, 0, 5, 1, 1, 0, + 2, 0, 2, 2, 3, 1, 2, 1, 2, 5, + 3, 1, 0, 6, 3, 2, 1, 4, 0, 6, + 0, 8, 0, 7, 1, 1, 1, 0, 2, 3, + 2, 2, 2, 3, 2, 1, 2, 1, 1, 0, + 3 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, context, scanner, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + +/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ + +YY_ATTRIBUTE_UNUSED +static unsigned +yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) +{ + unsigned res = 0; + int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; + if (0 <= yylocp->first_line) + { + res += YYFPRINTF (yyo, "%d", yylocp->first_line); + if (0 <= yylocp->first_column) + res += YYFPRINTF (yyo, ".%d", yylocp->first_column); + } + if (0 <= yylocp->last_line) + { + if (yylocp->first_line < yylocp->last_line) + { + res += YYFPRINTF (yyo, "-%d", yylocp->last_line); + if (0 <= end_col) + res += YYFPRINTF (yyo, ".%d", end_col); + } + else if (0 <= end_col && yylocp->first_column < end_col) + res += YYFPRINTF (yyo, "-%d", end_col); + } + return res; + } + +# define YY_LOCATION_PRINT(File, Loc) \ + yy_location_print_ (File, &(Loc)) + +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, context, scanner); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context, void *scanner) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (yylocationp); + YYUSE (context); + YYUSE (scanner); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context, void *scanner) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context, scanner); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, TParseContext* context, void *scanner) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , context, scanner); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, yylsp, Rule, context, scanner); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, TParseContext* context, void *scanner) +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (context); + YYUSE (scanner); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (TParseContext* context, void *scanner) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + +/* Location data for the lookahead symbol. */ +static YYLTYPE yyloc_default +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + = { 1, 1, 1, 1 } +# endif +; +YYLTYPE yylloc = yyloc_default; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + 'yyls': related to locations. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[3]; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yylsp = yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + yylsp[0] = yylloc; + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, &yylloc, scanner); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: + + { + // The symbol table search was done in the lexical phase + (yyval.interm.intermTypedNode) = context->parseVariableIdentifier((yylsp[0]), ImmutableString((yyvsp[0].lex).string), (yyvsp[0].lex).symbol); + } + + break; + + case 5: + + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 6: + + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray->setIConst((yyvsp[0].lex).i); + (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0])); + } + + break; + + case 7: + + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray->setUConst((yyvsp[0].lex).u); + (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0])); + } + + break; + + case 8: + + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray->setFConst((yyvsp[0].lex).f); + (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0])); + } + + break; + + case 9: + + { + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray->setBConst((yyvsp[0].lex).b); + (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0])); + } + + break; + + case 10: + + { + if (!context->checkCanUseExtension((yylsp[0]), TExtension::EXT_YUV_target)) + { + context->error((yylsp[0]), "unsupported value", ImmutableString((yyvsp[0].lex).string)); + } + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray->setYuvCscStandardEXTConst(getYuvCscStandardEXT(ImmutableString((yyvsp[0].lex).string))); + (yyval.interm.intermTypedNode) = context->addScalarLiteral(unionArray, (yylsp[0])); + } + + break; + + case 11: + + { + (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); + } + + break; + + case 12: + + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 13: + + { + (yyval.interm.intermTypedNode) = context->addIndexExpression((yyvsp[-3].interm.intermTypedNode), (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); + } + + break; + + case 14: + + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 15: + + { + (yyval.interm.intermTypedNode) = context->addFieldSelectionExpression((yyvsp[-2].interm.intermTypedNode), (yylsp[-1]), ImmutableString((yyvsp[0].lex).string), (yylsp[0])); + } + + break; + + case 16: + + { + (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode), (yylsp[0])); + } + + break; + + case 17: + + { + (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode), (yylsp[0])); + } + + break; + + case 18: + + { + context->checkIsScalarInteger((yyvsp[0].interm.intermTypedNode), "[]"); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 19: + + { + (yyval.interm.intermTypedNode) = context->addFunctionCallOrMethod((yyvsp[0].interm.functionLookup), (yylsp[0])); + } + + break; + + case 20: + + { + (yyval.interm.functionLookup) = (yyvsp[0].interm.functionLookup); + } + + break; + + case 21: + + { + ES3_OR_NEWER("", (yylsp[0]), "methods"); + (yyval.interm.functionLookup) = (yyvsp[0].interm.functionLookup); + (yyval.interm.functionLookup)->setThisNode((yyvsp[-2].interm.intermTypedNode)); + } + + break; + + case 22: + + { + (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup); + } + + break; + + case 23: + + { + (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup); + } + + break; + + case 24: + + { + (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup); + } + + break; + + case 25: + + { + (yyval.interm.functionLookup) = (yyvsp[0].interm.functionLookup); + } + + break; + + case 26: + + { + (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup); + (yyval.interm.functionLookup)->addArgument((yyvsp[0].interm.intermTypedNode)); + } + + break; + + case 27: + + { + (yyval.interm.functionLookup) = (yyvsp[-2].interm.functionLookup); + (yyval.interm.functionLookup)->addArgument((yyvsp[0].interm.intermTypedNode)); + } + + break; + + case 28: + + { + (yyval.interm.functionLookup) = (yyvsp[-1].interm.functionLookup); + } + + break; + + case 29: + + { + (yyval.interm.functionLookup) = context->addConstructorFunc((yyvsp[0].interm.type)); + } + + break; + + case 30: + + { + (yyval.interm.functionLookup) = context->addNonConstructorFunc(ImmutableString((yyvsp[0].lex).string), (yyvsp[0].lex).symbol); + } + + break; + + case 31: + + { + (yyval.interm.functionLookup) = context->addNonConstructorFunc(ImmutableString((yyvsp[0].lex).string), (yyvsp[0].lex).symbol); + } + + break; + + case 32: + + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 33: + + { + (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPreIncrement, (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 34: + + { + (yyval.interm.intermTypedNode) = context->addUnaryMathLValue(EOpPreDecrement, (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 35: + + { + (yyval.interm.intermTypedNode) = context->addUnaryMath((yyvsp[-1].interm.op), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 36: + + { (yyval.interm.op) = EOpPositive; } + + break; + + case 37: + + { (yyval.interm.op) = EOpNegative; } + + break; + + case 38: + + { (yyval.interm.op) = EOpLogicalNot; } + + break; + + case 39: + + { + ES3_OR_NEWER("~", (yyloc), "bit-wise operator"); + (yyval.interm.op) = EOpBitwiseNot; + } + + break; + + case 40: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 41: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 42: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 43: + + { + ES3_OR_NEWER("%", (yylsp[-1]), "integer modulus operator"); + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpIMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 44: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 45: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 46: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 47: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 48: + + { + ES3_OR_NEWER("<<", (yylsp[-1]), "bit-wise operator"); + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitShiftLeft, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 49: + + { + ES3_OR_NEWER(">>", (yylsp[-1]), "bit-wise operator"); + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitShiftRight, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 50: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 51: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 52: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 53: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 54: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 55: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 56: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 57: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpNotEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 58: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 59: + + { + ES3_OR_NEWER("&", (yylsp[-1]), "bit-wise operator"); + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 60: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 61: + + { + ES3_OR_NEWER("^", (yylsp[-1]), "bit-wise operator"); + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 62: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 63: + + { + ES3_OR_NEWER("|", (yylsp[-1]), "bit-wise operator"); + (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 64: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 65: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 66: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 67: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 68: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 69: + + { + (yyval.interm.intermTypedNode) = context->addBinaryMathBooleanResult(EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 70: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 71: + + { + (yyval.interm.intermTypedNode) = context->addTernarySelection((yyvsp[-4].interm.intermTypedNode), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-3])); + } + + break; + + case 72: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 73: + + { + (yyval.interm.intermTypedNode) = context->addAssign((yyvsp[-1].interm.op), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 74: + + { (yyval.interm.op) = EOpAssign; } + + break; + + case 75: + + { (yyval.interm.op) = EOpMulAssign; } + + break; + + case 76: + + { (yyval.interm.op) = EOpDivAssign; } + + break; + + case 77: + + { + ES3_OR_NEWER("%=", (yyloc), "integer modulus operator"); + (yyval.interm.op) = EOpIModAssign; + } + + break; + + case 78: + + { (yyval.interm.op) = EOpAddAssign; } + + break; + + case 79: + + { (yyval.interm.op) = EOpSubAssign; } + + break; + + case 80: + + { + ES3_OR_NEWER("<<=", (yyloc), "bit-wise operator"); + (yyval.interm.op) = EOpBitShiftLeftAssign; + } + + break; + + case 81: + + { + ES3_OR_NEWER(">>=", (yyloc), "bit-wise operator"); + (yyval.interm.op) = EOpBitShiftRightAssign; + } + + break; + + case 82: + + { + ES3_OR_NEWER("&=", (yyloc), "bit-wise operator"); + (yyval.interm.op) = EOpBitwiseAndAssign; + } + + break; + + case 83: + + { + ES3_OR_NEWER("^=", (yyloc), "bit-wise operator"); + (yyval.interm.op) = EOpBitwiseXorAssign; + } + + break; + + case 84: + + { + ES3_OR_NEWER("|=", (yyloc), "bit-wise operator"); + (yyval.interm.op) = EOpBitwiseOrAssign; + } + + break; + + case 85: + + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 86: + + { + (yyval.interm.intermTypedNode) = context->addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); + } + + break; + + case 87: + + { + context->checkIsConst((yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 88: + + { + context->enterStructDeclaration((yylsp[-1]), ImmutableString((yyvsp[-1].lex).string)); + (yyval.lex) = (yyvsp[-1].lex); + } + + break; + + case 89: + + { + (yyval.interm.intermNode) = context->addFunctionPrototypeDeclaration(*((yyvsp[-1].interm).function), (yylsp[-1])); + } + + break; + + case 90: + + { + (yyval.interm.intermNode) = (yyvsp[-1].interm).intermDeclaration; + } + + break; + + case 91: + + { + context->parseDefaultPrecisionQualifier((yyvsp[-2].interm.precision), (yyvsp[-1].interm.type), (yylsp[-3])); + (yyval.interm.intermNode) = nullptr; + } + + break; + + case 92: + + { + ES3_OR_NEWER(ImmutableString((yyvsp[-3].lex).string), (yylsp[-4]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-4].interm.typeQualifierBuilder), (yylsp[-3]), ImmutableString((yyvsp[-3].lex).string), (yyvsp[-2].interm.fieldList), kEmptyImmutableString, (yyloc), NULL, (yyloc)); + } + + break; + + case 93: + + { + ES3_OR_NEWER(ImmutableString((yyvsp[-4].lex).string), (yylsp[-5]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-5].interm.typeQualifierBuilder), (yylsp[-4]), ImmutableString((yyvsp[-4].lex).string), (yyvsp[-3].interm.fieldList), ImmutableString((yyvsp[-1].lex).string), (yylsp[-1]), NULL, (yyloc)); + } + + break; + + case 94: + + { + ES3_OR_NEWER(ImmutableString((yyvsp[-7].lex).string), (yylsp[-8]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-8].interm.typeQualifierBuilder), (yylsp[-7]), ImmutableString((yyvsp[-7].lex).string), (yyvsp[-6].interm.fieldList), ImmutableString((yyvsp[-4].lex).string), (yylsp[-4]), (yyvsp[-2].interm.intermTypedNode), (yylsp[-3])); + } + + break; + + case 95: + + { + context->parseGlobalLayoutQualifier(*(yyvsp[-1].interm.typeQualifierBuilder)); + (yyval.interm.intermNode) = nullptr; + } + + break; + + case 96: + + { + (yyval.interm.intermNode) = context->parseInvariantDeclaration(*(yyvsp[-2].interm.typeQualifierBuilder), (yylsp[-1]), ImmutableString((yyvsp[-1].lex).string), (yyvsp[-1].lex).symbol); + } + + break; + + case 97: + + { + (yyval.interm).function = context->parseFunctionDeclarator((yylsp[0]), (yyvsp[-1].interm.function)); + context->exitFunctionDeclaration(); + } + + break; + + case 98: + + { + (yyval.interm.function) = (yyvsp[0].interm.function); + } + + break; + + case 99: + + { + (yyval.interm.function) = (yyvsp[0].interm.function); + } + + break; + + case 100: + + { + // Add the parameter + (yyval.interm.function) = (yyvsp[-1].interm.function); + if ((yyvsp[0].interm.param).type->getBasicType() != EbtVoid) + { + (yyvsp[-1].interm.function)->addParameter((yyvsp[0].interm.param).createVariable(&context->symbolTable)); + } + } + + break; + + case 101: + + { + (yyval.interm.function) = (yyvsp[-2].interm.function); + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + if ((yyvsp[0].interm.param).type->getBasicType() == EbtVoid) + { + // This parameter > first is void + context->error((yylsp[-1]), "cannot be a parameter type except for '(void)'", "void"); + } + else + { + (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm.param).createVariable(&context->symbolTable)); + } + } + + break; + + case 102: + + { + (yyval.interm.function) = context->parseFunctionHeader((yyvsp[-2].interm.type), ImmutableString((yyvsp[-1].lex).string), (yylsp[-1])); + + context->symbolTable.push(); + context->enterFunctionDeclaration(); + } + + break; + + case 103: + + { + (yyval.interm.param) = context->parseParameterDeclarator((yyvsp[-1].interm.type), ImmutableString((yyvsp[0].lex).string), (yylsp[0])); + } + + break; + + case 104: + + { + (yyval.interm.param) = context->parseParameterArrayDeclarator(ImmutableString((yyvsp[-1].lex).string), (yylsp[-1]), *((yyvsp[0].interm.arraySizes)), (yylsp[0]), &(yyvsp[-2].interm.type)); + } + + break; + + case 105: + + { + (yyval.interm.param) = (yyvsp[0].interm.param); + context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.param).type); + } + + break; + + case 106: + + { + (yyval.interm.param) = (yyvsp[0].interm.param); + (yyval.interm.param).type->setQualifier(EvqIn); + } + + break; + + case 107: + + { + (yyval.interm.param) = (yyvsp[0].interm.param); + context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.param).type); + } + + break; + + case 108: + + { + (yyval.interm.param) = (yyvsp[0].interm.param); + (yyval.interm.param).type->setQualifier(EvqIn); + } + + break; + + case 109: + + { + TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; + (yyval.interm.param) = param; + } + + break; + + case 110: + + { + (yyval.interm) = (yyvsp[0].interm); + } + + break; + + case 111: + + { + (yyval.interm) = (yyvsp[-2].interm); + context->parseDeclarator((yyval.interm).type, (yylsp[0]), ImmutableString((yyvsp[0].lex).string), (yyval.interm).intermDeclaration); + } + + break; + + case 112: + + { + (yyval.interm) = (yyvsp[-3].interm); + context->parseArrayDeclarator((yyval.interm).type, (yylsp[-1]), ImmutableString((yyvsp[-1].lex).string), (yylsp[0]), *((yyvsp[0].interm.arraySizes)), (yyval.interm).intermDeclaration); + } + + break; + + case 113: + + { + ES3_OR_NEWER("=", (yylsp[-1]), "first-class arrays (array initializer)"); + (yyval.interm) = (yyvsp[-5].interm); + context->parseArrayInitDeclarator((yyval.interm).type, (yylsp[-3]), ImmutableString((yyvsp[-3].lex).string), (yylsp[-2]), *((yyvsp[-2].interm.arraySizes)), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode), (yyval.interm).intermDeclaration); + } + + break; + + case 114: + + { + (yyval.interm) = (yyvsp[-4].interm); + context->parseInitDeclarator((yyval.interm).type, (yylsp[-2]), ImmutableString((yyvsp[-2].lex).string), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode), (yyval.interm).intermDeclaration); + } + + break; + + case 115: + + { + (yyval.interm).type = (yyvsp[0].interm.type); + (yyval.interm).intermDeclaration = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), kEmptyImmutableString); + } + + break; + + case 116: + + { + (yyval.interm).type = (yyvsp[-1].interm.type); + (yyval.interm).intermDeclaration = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), ImmutableString((yyvsp[0].lex).string)); + } + + break; + + case 117: + + { + (yyval.interm).type = (yyvsp[-2].interm.type); + (yyval.interm).intermDeclaration = context->parseSingleArrayDeclaration((yyval.interm).type, (yylsp[-1]), ImmutableString((yyvsp[-1].lex).string), (yylsp[0]), *((yyvsp[0].interm.arraySizes))); + } + + break; + + case 118: + + { + ES3_OR_NEWER("[]", (yylsp[-2]), "first-class arrays (array initializer)"); + (yyval.interm).type = (yyvsp[-4].interm.type); + (yyval.interm).intermDeclaration = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-3]), ImmutableString((yyvsp[-3].lex).string), (yylsp[-2]), *((yyvsp[-2].interm.arraySizes)), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + } + + break; + + case 119: + + { + (yyval.interm).type = (yyvsp[-3].interm.type); + (yyval.interm).intermDeclaration = context->parseSingleInitDeclaration((yyval.interm).type, (yylsp[-2]), ImmutableString((yyvsp[-2].lex).string), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + } + + break; + + case 120: + + { + context->addFullySpecifiedType(&(yyvsp[0].interm.type)); + (yyval.interm.type) = (yyvsp[0].interm.type); + } + + break; + + case 121: + + { + (yyval.interm.type) = context->addFullySpecifiedType(*(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.type)); + } + + break; + + case 122: + + { + (yyval.interm.qualifier) = EvqSmooth; + } + + break; + + case 123: + + { + (yyval.interm.qualifier) = EvqFlat; + } + + break; + + case 124: + + { + (yyval.interm.typeQualifierBuilder) = context->createTypeQualifierBuilder((yylsp[0])); + (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper)); + } + + break; + + case 125: + + { + (yyval.interm.typeQualifierBuilder) = (yyvsp[-1].interm.typeQualifierBuilder); + (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper)); + } + + break; + + case 126: + + { + // empty + } + + break; + + case 127: + + { + context->checkLocalVariableConstStorageQualifier(*(yyvsp[0].interm.qualifierWrapper)); + (yyval.interm.qualifierWrapper) = (yyvsp[0].interm.qualifierWrapper); + } + + break; + + case 128: + + { + context->checkIsAtGlobalLevel((yylsp[0]), "layout"); + (yyval.interm.qualifierWrapper) = new TLayoutQualifierWrapper((yyvsp[0].interm.layoutQualifier), (yylsp[0])); + } + + break; + + case 129: + + { + (yyval.interm.qualifierWrapper) = new TPrecisionQualifierWrapper((yyvsp[0].interm.precision), (yylsp[0])); + } + + break; + + case 130: + + { + (yyval.interm.qualifierWrapper) = new TInterpolationQualifierWrapper((yyvsp[0].interm.qualifier), (yylsp[0])); + } + + break; + + case 131: + + { + context->checkIsAtGlobalLevel((yylsp[0]), "invariant"); + (yyval.interm.qualifierWrapper) = new TInvariantQualifierWrapper((yylsp[0])); + } + + break; + + case 132: + + { + VERTEX_ONLY("attribute", (yylsp[0])); + ES2_ONLY("attribute", (yylsp[0])); + (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqAttribute, (yylsp[0])); + } + + break; + + case 133: + + { + ES2_ONLY("varying", (yylsp[0])); + (yyval.interm.qualifierWrapper) = context->parseVaryingQualifier((yylsp[0])); + } + + break; + + case 134: + + { + (yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper(EvqConst, (yylsp[0])); + } + + break; + + case 135: + + { + (yyval.interm.qualifierWrapper) = context->parseInQualifier((yylsp[0])); + } + + break; + + case 136: + + { + (yyval.interm.qualifierWrapper) = context->parseOutQualifier((yylsp[0])); + } + + break; + + case 137: + + { + (yyval.interm.qualifierWrapper) = context->parseInOutQualifier((yylsp[0])); + } + + break; + + case 138: + + { + ES3_OR_NEWER("centroid", (yylsp[0]), "storage qualifier"); + (yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper(EvqCentroid, (yylsp[0])); + } + + break; + + case 139: + + { + (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqUniform, (yylsp[0])); + } + + break; + + case 140: + + { + ES3_1_ONLY("buffer", (yylsp[0]), "storage qualifier"); + (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqBuffer, (yylsp[0])); + } + + break; + + case 141: + + { + (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqReadOnly, (yylsp[0])); + } + + break; + + case 142: + + { + (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqWriteOnly, (yylsp[0])); + } + + break; + + case 143: + + { + (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqCoherent, (yylsp[0])); + } + + break; + + case 144: + + { + (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqRestrict, (yylsp[0])); + } + + break; + + case 145: + + { + (yyval.interm.qualifierWrapper) = new TMemoryQualifierWrapper(EvqVolatile, (yylsp[0])); + } + + break; + + case 146: + + { + COMPUTE_ONLY("shared", (yylsp[0])); + (yyval.interm.qualifierWrapper) = context->parseGlobalStorageQualifier(EvqShared, (yylsp[0])); + } + + break; + + case 147: + + { + (yyval.interm.type) = (yyvsp[0].interm.type); + (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[0].interm.type).getBasicType()); + } + + break; + + case 148: + + { + (yyval.interm.precision) = EbpHigh; + } + + break; + + case 149: + + { + (yyval.interm.precision) = EbpMedium; + } + + break; + + case 150: + + { + (yyval.interm.precision) = EbpLow; + } + + break; + + case 151: + + { + ES3_OR_NEWER("layout", (yylsp[-3]), "qualifier"); + (yyval.interm.layoutQualifier) = (yyvsp[-1].interm.layoutQualifier); + } + + break; + + case 152: + + { + (yyval.interm.layoutQualifier) = (yyvsp[0].interm.layoutQualifier); + } + + break; + + case 153: + + { + (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[-2].interm.layoutQualifier), (yyvsp[0].interm.layoutQualifier), (yylsp[0])); + } + + break; + + case 154: + + { + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString((yyvsp[0].lex).string), (yylsp[0])); + } + + break; + + case 155: + + { + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString((yyvsp[-2].lex).string), (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0])); + } + + break; + + case 156: + + { + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString((yyvsp[-2].lex).string), (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0])); + } + + break; + + case 157: + + { + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(ImmutableString("shared"), (yylsp[0])); + } + + break; + + case 158: + + { + (yyval.interm.type).initialize((yyvsp[0].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); + } + + break; + + case 159: + + { + (yyval.interm.type).initialize((yyvsp[-1].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); + (yyval.interm.type).setArraySizes((yyvsp[0].interm.arraySizes)); + } + + break; + + case 160: + + { + ES3_OR_NEWER("[]", (yylsp[-1]), "implicitly sized array"); + (yyval.interm.arraySizes) = new TVector<unsigned int>(); + (yyval.interm.arraySizes)->push_back(0u); + } + + break; + + case 161: + + { + (yyval.interm.arraySizes) = new TVector<unsigned int>(); + unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); + // Make the type an array even if size check failed. + // This ensures useless error messages regarding a variable's non-arrayness won't follow. + (yyval.interm.arraySizes)->push_back(size); + } + + break; + + case 162: + + { + ES3_1_ONLY("[]", (yylsp[-1]), "arrays of arrays"); + (yyval.interm.arraySizes) = (yyvsp[-2].interm.arraySizes); + (yyval.interm.arraySizes)->insert((yyval.interm.arraySizes)->begin(), 0u); + } + + break; + + case 163: + + { + ES3_1_ONLY("[]", (yylsp[-2]), "arrays of arrays"); + (yyval.interm.arraySizes) = (yyvsp[-3].interm.arraySizes); + unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); + // Make the type an array even if size check failed. + // This ensures useless error messages regarding a variable's non-arrayness won't follow. + (yyval.interm.arraySizes)->insert((yyval.interm.arraySizes)->begin(), size); + } + + break; + + case 164: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtVoid, (yylsp[0])); + } + + break; + + case 165: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + } + + break; + + case 166: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); + } + + break; + + case 167: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); + } + + break; + + case 168: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); + } + + break; + + case 169: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); + } + + break; + + case 170: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); + } + + break; + + case 171: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); + } + + break; + + case 172: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); + } + + break; + + case 173: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); + } + + break; + + case 174: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); + } + + break; + + case 175: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); + } + + break; + + case 176: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); + } + + break; + + case 177: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); + } + + break; + + case 178: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); + } + + break; + + case 179: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); + } + + break; + + case 180: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); + } + + break; + + case 181: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(2, 2); + } + + break; + + case 182: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(3, 3); + } + + break; + + case 183: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(4, 4); + } + + break; + + case 184: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(2, 3); + } + + break; + + case 185: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(3, 2); + } + + break; + + case 186: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(2, 4); + } + + break; + + case 187: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(4, 2); + } + + break; + + case 188: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(3, 4); + } + + break; + + case 189: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(4, 3); + } + + break; + + case 190: + + { + if (!context->checkCanUseExtension((yylsp[0]), TExtension::EXT_YUV_target)) + { + context->error((yylsp[0]), "unsupported type", "yuvCscStandardEXT"); + } + (yyval.interm.typeSpecifierNonArray).initialize(EbtYuvCscStandardEXT, (yylsp[0])); + } + + break; + + case 191: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2D, (yylsp[0])); + } + + break; + + case 192: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler3D, (yylsp[0])); + } + + break; + + case 193: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCube, (yylsp[0])); + } + + break; + + case 194: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArray, (yylsp[0])); + } + + break; + + case 195: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DMS, (yylsp[0])); + } + + break; + + case 196: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DMSArray, (yylsp[0])); + } + + break; + + case 197: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2D, (yylsp[0])); + } + + break; + + case 198: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler3D, (yylsp[0])); + } + + break; + + case 199: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtISamplerCube, (yylsp[0])); + } + + break; + + case 200: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DArray, (yylsp[0])); + } + + break; + + case 201: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DMS, (yylsp[0])); + } + + break; + + case 202: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DMSArray, (yylsp[0])); + } + + break; + + case 203: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2D, (yylsp[0])); + } + + break; + + case 204: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler3D, (yylsp[0])); + } + + break; + + case 205: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSamplerCube, (yylsp[0])); + } + + break; + + case 206: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DArray, (yylsp[0])); + } + + break; + + case 207: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DMS, (yylsp[0])); + } + + break; + + case 208: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DMSArray, (yylsp[0])); + } + + break; + + case 209: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DShadow, (yylsp[0])); + } + + break; + + case 210: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCubeShadow, (yylsp[0])); + } + + break; + + case 211: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArrayShadow, (yylsp[0])); + } + + break; + + case 212: + + { + constexpr std::array<TExtension, 3u> extensions{ { TExtension::NV_EGL_stream_consumer_external, + TExtension::OES_EGL_image_external_essl3, + TExtension::OES_EGL_image_external } }; + if (!context->checkCanUseOneOfExtensions((yylsp[0]), extensions)) + { + context->error((yylsp[0]), "unsupported type", "samplerExternalOES"); + } + (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerExternalOES, (yylsp[0])); + } + + break; + + case 213: + + { + if (!context->checkCanUseExtension((yylsp[0]), TExtension::EXT_YUV_target)) + { + context->error((yylsp[0]), "unsupported type", "__samplerExternal2DY2YEXT"); + } + (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerExternal2DY2YEXT, (yylsp[0])); + } + + break; + + case 214: + + { + if (!context->checkCanUseExtension((yylsp[0]), TExtension::ARB_texture_rectangle)) + { + context->error((yylsp[0]), "unsupported type", "sampler2DRect"); + } + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DRect, (yylsp[0])); + } + + break; + + case 215: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtImage2D, (yylsp[0])); + } + + break; + + case 216: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtIImage2D, (yylsp[0])); + } + + break; + + case 217: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUImage2D, (yylsp[0])); + } + + break; + + case 218: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtImage3D, (yylsp[0])); + } + + break; + + case 219: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtIImage3D, (yylsp[0])); + } + + break; + + case 220: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUImage3D, (yylsp[0])); + } + + break; + + case 221: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtImage2DArray, (yylsp[0])); + } + + break; + + case 222: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtIImage2DArray, (yylsp[0])); + } + + break; + + case 223: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUImage2DArray, (yylsp[0])); + } + + break; + + case 224: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtImageCube, (yylsp[0])); + } + + break; + + case 225: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtIImageCube, (yylsp[0])); + } + + break; + + case 226: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtUImageCube, (yylsp[0])); + } + + break; + + case 227: + + { + (yyval.interm.typeSpecifierNonArray).initialize(EbtAtomicCounter, (yylsp[0])); + } + + break; + + case 228: + + { + (yyval.interm.typeSpecifierNonArray) = (yyvsp[0].interm.typeSpecifierNonArray); + } + + break; + + case 229: + + { + // This is for user defined type names. The lexical phase looked up the type. + const TStructure *structure = static_cast<const TStructure*>((yyvsp[0].lex).symbol); + (yyval.interm.typeSpecifierNonArray).initializeStruct(structure, false, (yylsp[0])); + } + + break; + + case 230: + + { context->enterStructDeclaration((yylsp[-1]), ImmutableString((yyvsp[-1].lex).string)); } + + break; + + case 231: + + { + (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-5]), (yylsp[-4]), ImmutableString((yyvsp[-4].lex).string), (yyvsp[-1].interm.fieldList)); + } + + break; + + case 232: + + { context->enterStructDeclaration((yylsp[0]), kEmptyImmutableString); } + + break; + + case 233: + + { + (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-4]), (yyloc), kEmptyImmutableString, (yyvsp[-1].interm.fieldList)); + } + + break; + + case 234: + + { + (yyval.interm.fieldList) = context->addStructFieldList((yyvsp[0].interm.fieldList), (yylsp[0])); + } + + break; + + case 235: + + { + (yyval.interm.fieldList) = context->combineStructFieldLists((yyvsp[-1].interm.fieldList), (yyvsp[0].interm.fieldList), (yylsp[0])); + } + + break; + + case 236: + + { + (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[-2].interm.type), (yyvsp[-1].interm.declaratorList)); + } + + break; + + case 237: + + { + // ES3 Only, but errors should be handled elsewhere + (yyval.interm.fieldList) = context->addStructDeclaratorListWithQualifiers(*(yyvsp[-3].interm.typeQualifierBuilder), &(yyvsp[-2].interm.type), (yyvsp[-1].interm.declaratorList)); + } + + break; + + case 238: + + { + (yyval.interm.declaratorList) = new TDeclaratorList(); + (yyval.interm.declaratorList)->push_back((yyvsp[0].interm.declarator)); + } + + break; + + case 239: + + { + (yyval.interm.declaratorList)->push_back((yyvsp[0].interm.declarator)); + } + + break; + + case 240: + + { + (yyval.interm.declarator) = context->parseStructDeclarator(ImmutableString((yyvsp[0].lex).string), (yylsp[0])); + } + + break; + + case 241: + + { + (yyval.interm.declarator) = context->parseStructArrayDeclarator(ImmutableString((yyvsp[-1].lex).string), (yylsp[-1]), (yyvsp[0].interm.arraySizes)); + } + + break; + + case 242: + + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } + + break; + + case 243: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 244: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); } + + break; + + case 245: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 246: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 247: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 248: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 249: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermSwitch); } + + break; + + case 250: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermCase); } + + break; + + case 251: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 252: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 253: + + { + (yyval.interm.intermBlock) = new TIntermBlock(); + (yyval.interm.intermBlock)->setLine((yyloc)); + } + + break; + + case 254: + + { context->symbolTable.push(); } + + break; + + case 255: + + { context->symbolTable.pop(); } + + break; + + case 256: + + { + (yyvsp[-2].interm.intermBlock)->setLine((yyloc)); + (yyval.interm.intermBlock) = (yyvsp[-2].interm.intermBlock); + } + + break; + + case 257: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); } + + break; + + case 258: + + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 259: + + { context->symbolTable.push(); } + + break; + + case 260: + + { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); } + + break; + + case 261: + + { context->symbolTable.push(); } + + break; + + case 262: + + { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } + + break; + + case 263: + + { + (yyval.interm.intermBlock) = new TIntermBlock(); + (yyval.interm.intermBlock)->setLine((yyloc)); + } + + break; + + case 264: + + { + (yyvsp[-1].interm.intermBlock)->setLine((yyloc)); + (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock); + } + + break; + + case 265: + + { + (yyval.interm.intermBlock) = new TIntermBlock(); + context->appendStatement((yyval.interm.intermBlock), (yyvsp[0].interm.intermNode)); + } + + break; + + case 266: + + { + (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock); + context->appendStatement((yyval.interm.intermBlock), (yyvsp[0].interm.intermNode)); + } + + break; + + case 267: + + { (yyval.interm.intermNode) = context->addEmptyStatement((yyloc)); } + + break; + + case 268: + + { (yyval.interm.intermNode) = (yyvsp[-1].interm.intermTypedNode); } + + break; + + case 269: + + { + (yyval.interm.intermNode) = context->addIfElse((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yylsp[-4])); + } + + break; + + case 270: + + { + (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); + (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode); + } + + break; + + case 271: + + { + (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode); + (yyval.interm.nodePair).node2 = nullptr; + } + + break; + + case 272: + + { context->incrSwitchNestingLevel(); } + + break; + + case 273: + + { + (yyval.interm.intermSwitch) = context->addSwitch((yyvsp[-3].interm.intermTypedNode), (yyvsp[0].interm.intermBlock), (yylsp[-5])); + context->decrSwitchNestingLevel(); + } + + break; + + case 274: + + { + (yyval.interm.intermCase) = context->addCase((yyvsp[-1].interm.intermTypedNode), (yylsp[-2])); + } + + break; + + case 275: + + { + (yyval.interm.intermCase) = context->addDefault((yylsp[-1])); + } + + break; + + case 276: + + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermTypedNode); + context->checkIsScalarBool((yyvsp[0].interm.intermTypedNode)->getLine(), (yyvsp[0].interm.intermTypedNode)); + } + + break; + + case 277: + + { + (yyval.interm.intermNode) = context->addConditionInitializer((yyvsp[-3].interm.type), ImmutableString((yyvsp[-2].lex).string), (yyvsp[0].interm.intermTypedNode), (yylsp[-2])); + } + + break; + + case 278: + + { context->symbolTable.push(); context->incrLoopNestingLevel(); } + + break; + + case 279: + + { + context->symbolTable.pop(); + (yyval.interm.intermNode) = context->addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5])); + context->decrLoopNestingLevel(); + } + + break; + + case 280: + + { context->incrLoopNestingLevel(); } + + break; + + case 281: + + { + (yyval.interm.intermNode) = context->addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4])); + context->decrLoopNestingLevel(); + } + + break; + + case 282: + + { context->symbolTable.push(); context->incrLoopNestingLevel(); } + + break; + + case 283: + + { + context->symbolTable.pop(); + (yyval.interm.intermNode) = context->addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), (yyvsp[-2].interm.nodePair).node1, reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6])); + context->decrLoopNestingLevel(); + } + + break; + + case 284: + + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } + + break; + + case 285: + + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } + + break; + + case 286: + + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } + + break; + + case 287: + + { + (yyval.interm.intermNode) = nullptr; + } + + break; + + case 288: + + { + (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermNode); + (yyval.interm.nodePair).node2 = 0; + } + + break; + + case 289: + + { + (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); + (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode); + } + + break; + + case 290: + + { + (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1])); + } + + break; + + case 291: + + { + (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1])); + } + + break; + + case 292: + + { + (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1])); + } + + break; + + case 293: + + { + (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2])); + } + + break; + + case 294: + + { + (yyval.interm.intermNode) = context->addBranch(EOpKill, (yylsp[-1])); + } + + break; + + case 295: + + { + (yyval.interm.intermBlock) = new TIntermBlock(); + (yyval.interm.intermBlock)->setLine((yyloc)); + (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode)); + context->setTreeRoot((yyval.interm.intermBlock)); + } + + break; + + case 296: + + { + (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode)); + } + + break; + + case 297: + + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } + + break; + + case 298: + + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } + + break; + + case 299: + + { + context->parseFunctionDefinitionHeader((yylsp[0]), (yyvsp[0].interm).function, &((yyvsp[0].interm).intermFunctionPrototype)); + } + + break; + + case 300: + + { + (yyval.interm.intermNode) = context->addFunctionDefinition((yyvsp[-2].interm).intermFunctionPrototype, (yyvsp[0].interm.intermBlock), (yylsp[-2])); + } + + break; + + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, context, scanner, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (&yylloc, context, scanner, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + yyerror_range[1] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, context, scanner); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[1] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[1] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, context, scanner); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + yyerror_range[2] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, yyerror_range, 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, context, scanner, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, context, scanner); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, context, scanner); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} + + + +int glslang_parse(TParseContext* context) { + return yyparse(context, context->getScanner()); +} diff --git a/gfx/angle/checkout/src/compiler/translator/glslang_tab.h b/gfx/angle/checkout/src/compiler/translator/glslang_tab.h new file mode 100644 index 0000000000..5ffee8a4c5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/glslang_tab.h @@ -0,0 +1,284 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED +#define YY_YY_GLSLANG_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ + +#define YYLTYPE TSourceLoc +#define YYLTYPE_IS_DECLARED 1 +#define YYLTYPE_IS_TRIVIAL 1 + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE +enum yytokentype +{ + INVARIANT = 258, + HIGH_PRECISION = 259, + MEDIUM_PRECISION = 260, + LOW_PRECISION = 261, + PRECISION = 262, + ATTRIBUTE = 263, + CONST_QUAL = 264, + BOOL_TYPE = 265, + FLOAT_TYPE = 266, + INT_TYPE = 267, + UINT_TYPE = 268, + BREAK = 269, + CONTINUE = 270, + DO = 271, + ELSE = 272, + FOR = 273, + IF = 274, + DISCARD = 275, + RETURN = 276, + SWITCH = 277, + CASE = 278, + DEFAULT = 279, + BVEC2 = 280, + BVEC3 = 281, + BVEC4 = 282, + IVEC2 = 283, + IVEC3 = 284, + IVEC4 = 285, + VEC2 = 286, + VEC3 = 287, + VEC4 = 288, + UVEC2 = 289, + UVEC3 = 290, + UVEC4 = 291, + MATRIX2 = 292, + MATRIX3 = 293, + MATRIX4 = 294, + IN_QUAL = 295, + OUT_QUAL = 296, + INOUT_QUAL = 297, + UNIFORM = 298, + BUFFER = 299, + VARYING = 300, + MATRIX2x3 = 301, + MATRIX3x2 = 302, + MATRIX2x4 = 303, + MATRIX4x2 = 304, + MATRIX3x4 = 305, + MATRIX4x3 = 306, + CENTROID = 307, + FLAT = 308, + SMOOTH = 309, + READONLY = 310, + WRITEONLY = 311, + COHERENT = 312, + RESTRICT = 313, + VOLATILE = 314, + SHARED = 315, + STRUCT = 316, + VOID_TYPE = 317, + WHILE = 318, + SAMPLER2D = 319, + SAMPLERCUBE = 320, + SAMPLER_EXTERNAL_OES = 321, + SAMPLER2DRECT = 322, + SAMPLER2DARRAY = 323, + ISAMPLER2D = 324, + ISAMPLER3D = 325, + ISAMPLERCUBE = 326, + ISAMPLER2DARRAY = 327, + USAMPLER2D = 328, + USAMPLER3D = 329, + USAMPLERCUBE = 330, + USAMPLER2DARRAY = 331, + SAMPLER2DMS = 332, + ISAMPLER2DMS = 333, + USAMPLER2DMS = 334, + SAMPLER2DMSARRAY = 335, + ISAMPLER2DMSARRAY = 336, + USAMPLER2DMSARRAY = 337, + SAMPLER3D = 338, + SAMPLER3DRECT = 339, + SAMPLER2DSHADOW = 340, + SAMPLERCUBESHADOW = 341, + SAMPLER2DARRAYSHADOW = 342, + SAMPLEREXTERNAL2DY2YEXT = 343, + IMAGE2D = 344, + IIMAGE2D = 345, + UIMAGE2D = 346, + IMAGE3D = 347, + IIMAGE3D = 348, + UIMAGE3D = 349, + IMAGE2DARRAY = 350, + IIMAGE2DARRAY = 351, + UIMAGE2DARRAY = 352, + IMAGECUBE = 353, + IIMAGECUBE = 354, + UIMAGECUBE = 355, + ATOMICUINT = 356, + LAYOUT = 357, + YUVCSCSTANDARDEXT = 358, + YUVCSCSTANDARDEXTCONSTANT = 359, + IDENTIFIER = 360, + TYPE_NAME = 361, + FLOATCONSTANT = 362, + INTCONSTANT = 363, + UINTCONSTANT = 364, + BOOLCONSTANT = 365, + FIELD_SELECTION = 366, + LEFT_OP = 367, + RIGHT_OP = 368, + INC_OP = 369, + DEC_OP = 370, + LE_OP = 371, + GE_OP = 372, + EQ_OP = 373, + NE_OP = 374, + AND_OP = 375, + OR_OP = 376, + XOR_OP = 377, + MUL_ASSIGN = 378, + DIV_ASSIGN = 379, + ADD_ASSIGN = 380, + MOD_ASSIGN = 381, + LEFT_ASSIGN = 382, + RIGHT_ASSIGN = 383, + AND_ASSIGN = 384, + XOR_ASSIGN = 385, + OR_ASSIGN = 386, + SUB_ASSIGN = 387, + LEFT_PAREN = 388, + RIGHT_PAREN = 389, + LEFT_BRACKET = 390, + RIGHT_BRACKET = 391, + LEFT_BRACE = 392, + RIGHT_BRACE = 393, + DOT = 394, + COMMA = 395, + COLON = 396, + EQUAL = 397, + SEMICOLON = 398, + BANG = 399, + DASH = 400, + TILDE = 401, + PLUS = 402, + STAR = 403, + SLASH = 404, + PERCENT = 405, + LEFT_ANGLE = 406, + RIGHT_ANGLE = 407, + VERTICAL_BAR = 408, + CARET = 409, + AMPERSAND = 410, + QUESTION = 411 +}; +#endif + +/* Value type. */ +#if !defined YYSTYPE && !defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ + + struct + { + union + { + const char *string; // pool allocated. + float f; + int i; + unsigned int u; + bool b; + }; + const TSymbol *symbol; + } lex; + struct + { + TOperator op; + union + { + TIntermNode *intermNode; + TIntermNodePair nodePair; + TIntermTyped *intermTypedNode; + TIntermAggregate *intermAggregate; + TIntermBlock *intermBlock; + TIntermDeclaration *intermDeclaration; + TIntermFunctionPrototype *intermFunctionPrototype; + TIntermSwitch *intermSwitch; + TIntermCase *intermCase; + }; + union + { + TVector<unsigned int> *arraySizes; + TTypeSpecifierNonArray typeSpecifierNonArray; + TPublicType type; + TPrecision precision; + TLayoutQualifier layoutQualifier; + TQualifier qualifier; + TFunction *function; + TFunctionLookup *functionLookup; + TParameter param; + TDeclarator *declarator; + TDeclaratorList *declaratorList; + TFieldList *fieldList; + TQualifierWrapperBase *qualifierWrapper; + TTypeQualifierBuilder *typeQualifierBuilder; + }; + } interm; +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + +/* Location type. */ +#if !defined YYLTYPE && !defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + +int yyparse(TParseContext *context, void *scanner); + +#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */ diff --git a/gfx/angle/checkout/src/compiler/translator/length_limits.h b/gfx/angle/checkout/src/compiler/translator/length_limits.h new file mode 100644 index 0000000000..fcda639d71 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/length_limits.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2011-2014 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. +// + +// +// length_limits.h +// + +#ifndef COMPILER_TRANSLATOR_LENGTHLIMITS_H_ +#define COMPILER_TRANSLATOR_LENGTHLIMITS_H_ + +#include "GLSLANG/ShaderLang.h" + +// These constants are factored out from the rest of the headers to +// make it easier to reference them from the compiler sources. + +namespace sh +{ + +size_t GetGlobalMaxTokenSize(ShShaderSpec spec); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_LENGTHLIMITS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp new file mode 100644 index 0000000000..25a52983a3 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 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. +// + +#include "compiler/translator/tree_ops/AddAndTrueToLoopCondition.h" + +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// An AST traverser that rewrites for and while loops by replacing "condition" with +// "condition && true" to work around condition bug on Intel Mac. +class AddAndTrueToLoopConditionTraverser : public TIntermTraverser +{ + public: + AddAndTrueToLoopConditionTraverser() : TIntermTraverser(true, false, false) {} + + bool visitLoop(Visit, TIntermLoop *loop) override + { + // do-while loop doesn't have this bug. + if (loop->getType() != ELoopFor && loop->getType() != ELoopWhile) + { + return true; + } + + // For loop may not have a condition. + if (loop->getCondition() == nullptr) + { + return true; + } + + // Constant true. + TIntermTyped *trueValue = CreateBoolNode(true); + + // CONDITION && true. + TIntermBinary *andOp = new TIntermBinary(EOpLogicalAnd, loop->getCondition(), trueValue); + loop->setCondition(andOp); + + return true; + } +}; + +} // anonymous namespace + +void AddAndTrueToLoopCondition(TIntermNode *root) +{ + AddAndTrueToLoopConditionTraverser traverser; + root->traverse(&traverser); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h new file mode 100644 index 0000000000..3a9efc2133 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 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. +// + +// Rewrite condition in for and while loops to work around driver bug on Intel Mac. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_ADDANDTRUETOLOOPCONDITION_H_ +#define COMPILER_TRANSLATOR_TREEOPS_ADDANDTRUETOLOOPCONDITION_H_ + +class TIntermNode; +namespace sh +{ + +void AddAndTrueToLoopCondition(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_ADDANDTRUETOLOOPCONDITION_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp new file mode 100644 index 0000000000..636ce37506 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 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. +// +// AddDefaultReturnStatements.cpp: Add default return statements to functions that do not end in a +// return. +// + +#include "compiler/translator/tree_ops/AddDefaultReturnStatements.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +bool NeedsReturnStatement(TIntermFunctionDefinition *node, TType *returnType) +{ + *returnType = node->getFunctionPrototype()->getType(); + if (returnType->getBasicType() == EbtVoid) + { + return false; + } + + TIntermBlock *bodyNode = node->getBody(); + TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode(); + if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn) + { + return false; + } + + return true; +} + +} // anonymous namespace + +void AddDefaultReturnStatements(TIntermBlock *root) +{ + TType returnType; + for (TIntermNode *node : *root->getSequence()) + { + TIntermFunctionDefinition *definition = node->getAsFunctionDefinition(); + if (definition != nullptr && NeedsReturnStatement(definition, &returnType)) + { + TIntermBranch *branch = new TIntermBranch(EOpReturn, CreateZeroNode(returnType)); + + TIntermBlock *bodyNode = definition->getBody(); + bodyNode->getSequence()->push_back(branch); + } + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h new file mode 100644 index 0000000000..6d537978f5 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 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. +// +// AddDefaultReturnStatements.h: Add default return statements to functions that do not end in a +// return. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_ADDDEFAULTRETURNSTATEMENTS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_ADDDEFAULTRETURNSTATEMENTS_H_ + +class TIntermBlock; + +namespace sh +{ + +void AddDefaultReturnStatements(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_ADDDEFAULTRETURNSTATEMENTS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp new file mode 100644 index 0000000000..824908b0e6 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp @@ -0,0 +1,228 @@ +// +// Copyright (c) 2002-2015 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. +// +// The ArrayReturnValueToOutParameter function changes return values of an array type to out +// parameters in function definitions, prototypes, and call sites. + +#include "compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h" + +#include <map> + +#include "compiler/translator/StaticType.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kReturnValueVariableName("angle_return"); + +class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser +{ + public: + static void apply(TIntermNode *root, TSymbolTable *symbolTable); + + private: + ArrayReturnValueToOutParameterTraverser(TSymbolTable *symbolTable); + + void visitFunctionPrototype(TIntermFunctionPrototype *node) override; + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBranch(Visit visit, TIntermBranch *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + + TIntermAggregate *createReplacementCall(TIntermAggregate *originalCall, + TIntermTyped *returnValueTarget); + + // Set when traversal is inside a function with array return value. + TIntermFunctionDefinition *mFunctionWithArrayReturnValue; + + struct ChangedFunction + { + const TVariable *returnValueVariable; + const TFunction *func; + }; + + // Map from function symbol ids to the changed function. + std::map<int, ChangedFunction> mChangedFunctions; +}; + +TIntermAggregate *ArrayReturnValueToOutParameterTraverser::createReplacementCall( + TIntermAggregate *originalCall, + TIntermTyped *returnValueTarget) +{ + TIntermSequence *replacementArguments = new TIntermSequence(); + TIntermSequence *originalArguments = originalCall->getSequence(); + for (auto &arg : *originalArguments) + { + replacementArguments->push_back(arg); + } + replacementArguments->push_back(returnValueTarget); + ASSERT(originalCall->getFunction()); + const TSymbolUniqueId &originalId = originalCall->getFunction()->uniqueId(); + TIntermAggregate *replacementCall = TIntermAggregate::CreateFunctionCall( + *mChangedFunctions[originalId.get()].func, replacementArguments); + replacementCall->setLine(originalCall->getLine()); + return replacementCall; +} + +void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, TSymbolTable *symbolTable) +{ + ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam(symbolTable); + root->traverse(&arrayReturnValueToOutParam); + arrayReturnValueToOutParam.updateTree(); +} + +ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser( + TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mFunctionWithArrayReturnValue(nullptr) +{} + +bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition( + Visit visit, + TIntermFunctionDefinition *node) +{ + if (node->getFunctionPrototype()->isArray() && visit == PreVisit) + { + // Replacing the function header is done on visitFunctionPrototype(). + mFunctionWithArrayReturnValue = node; + } + if (visit == PostVisit) + { + mFunctionWithArrayReturnValue = nullptr; + } + return true; +} + +void ArrayReturnValueToOutParameterTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node) +{ + if (node->isArray()) + { + // Replace the whole prototype node with another node that has the out parameter + // added. Also set the function to return void. + const TSymbolUniqueId &functionId = node->getFunction()->uniqueId(); + if (mChangedFunctions.find(functionId.get()) == mChangedFunctions.end()) + { + TType *returnValueVariableType = new TType(node->getType()); + returnValueVariableType->setQualifier(EvqOut); + ChangedFunction changedFunction; + changedFunction.returnValueVariable = + new TVariable(mSymbolTable, kReturnValueVariableName, returnValueVariableType, + SymbolType::AngleInternal); + TFunction *func = new TFunction(mSymbolTable, node->getFunction()->name(), + node->getFunction()->symbolType(), + StaticType::GetBasic<EbtVoid>(), false); + for (size_t i = 0; i < node->getFunction()->getParamCount(); ++i) + { + func->addParameter(node->getFunction()->getParam(i)); + } + func->addParameter(changedFunction.returnValueVariable); + changedFunction.func = func; + mChangedFunctions[functionId.get()] = changedFunction; + } + TIntermFunctionPrototype *replacement = + new TIntermFunctionPrototype(mChangedFunctions[functionId.get()].func); + replacement->setLine(node->getLine()); + + queueReplacement(replacement, OriginalNode::IS_DROPPED); + } +} + +bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + ASSERT(!node->isArray() || node->getOp() != EOpCallInternalRawFunction); + if (visit == PreVisit && node->isArray() && node->getOp() == EOpCallFunctionInAST) + { + // Handle call sites where the returned array is not assigned. + // Examples where f() is a function returning an array: + // 1. f(); + // 2. another_array == f(); + // 3. another_function(f()); + // 4. return f(); + // Cases 2 to 4 are already converted to simpler cases by + // SeparateExpressionsReturningArrays, so we only need to worry about the case where a + // function call returning an array forms an expression by itself. + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + if (parentBlock) + { + // replace + // f(); + // with + // type s0[size]; f(s0); + TIntermSequence replacements; + + // type s0[size]; + TIntermDeclaration *returnValueDeclaration = nullptr; + TVariable *returnValue = DeclareTempVariable(mSymbolTable, new TType(node->getType()), + EvqTemporary, &returnValueDeclaration); + replacements.push_back(returnValueDeclaration); + + // f(s0); + TIntermSymbol *returnValueSymbol = CreateTempSymbolNode(returnValue); + replacements.push_back(createReplacementCall(node, returnValueSymbol)); + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentBlock, node, replacements)); + } + return false; + } + return true; +} + +bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node) +{ + if (mFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn) + { + // Instead of returning a value, assign to the out parameter and then return. + TIntermSequence replacements; + + TIntermTyped *expression = node->getExpression(); + ASSERT(expression != nullptr); + const TSymbolUniqueId &functionId = + mFunctionWithArrayReturnValue->getFunction()->uniqueId(); + ASSERT(mChangedFunctions.find(functionId.get()) != mChangedFunctions.end()); + TIntermSymbol *returnValueSymbol = + new TIntermSymbol(mChangedFunctions[functionId.get()].returnValueVariable); + TIntermBinary *replacementAssignment = + new TIntermBinary(EOpAssign, returnValueSymbol, expression); + replacementAssignment->setLine(expression->getLine()); + replacements.push_back(replacementAssignment); + + TIntermBranch *replacementBranch = new TIntermBranch(EOpReturn, nullptr); + replacementBranch->setLine(node->getLine()); + replacements.push_back(replacementBranch); + + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements)); + } + return false; +} + +bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (node->getOp() == EOpAssign && node->getLeft()->isArray()) + { + TIntermAggregate *rightAgg = node->getRight()->getAsAggregate(); + ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpCallInternalRawFunction); + if (rightAgg != nullptr && rightAgg->getOp() == EOpCallFunctionInAST) + { + TIntermAggregate *replacementCall = createReplacementCall(rightAgg, node->getLeft()); + queueReplacement(replacementCall, OriginalNode::IS_DROPPED); + } + } + return false; +} + +} // namespace + +void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable) +{ + ArrayReturnValueToOutParameterTraverser::apply(root, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h new file mode 100644 index 0000000000..9ceb02c76a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2002-2015 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. +// +// The ArrayReturnValueToOutParameter function changes return values of an array type to out +// parameters in function definitions, prototypes and call sites. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_ARRAYRETURNVALUETOOUTPARAMETER_H_ +#define COMPILER_TRANSLATOR_TREEOPS_ARRAYRETURNVALUETOOUTPARAMETER_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_ARRAYRETURNVALUETOOUTPARAMETER_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp new file mode 100644 index 0000000000..19f53a7383 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp @@ -0,0 +1,107 @@ +// +// Copyright (c) 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. +// + +// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend +// may record a variable as aliasing another. Sometimes the alias information gets garbled +// so we work around this issue by breaking the aliasing chain in inner loops. + +#include "BreakVariableAliasingInInnerLoops.h" + +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +// A HLSL compiler developer gave us more details on the root cause and the workaround needed: +// The root problem is that if the HLSL compiler is applying aliasing information even on +// incomplete simulations (in this case, a single pass). The bug is triggered by an assignment +// that comes from a series of assignments, possibly with swizzled or ternary operators with +// known conditionals, where the source is before the loop. +// So, a workaround is to add a +0 term to variables the first time they are assigned to in +// an inner loop (if they are declared in an outside scope, otherwise there is no need). +// This will break the aliasing chain. + +// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because +// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure +// assignment don't need a workaround. + +namespace sh +{ + +namespace +{ + +class AliasingBreaker : public TIntermTraverser +{ + public: + AliasingBreaker() : TIntermTraverser(true, false, true) {} + + protected: + bool visitBinary(Visit visit, TIntermBinary *binary) + { + if (visit != PreVisit) + { + return false; + } + + if (mLoopLevel < 2 || !binary->isAssignment()) + { + return true; + } + + TIntermTyped *B = binary->getRight(); + TType type = B->getType(); + + if (!type.isScalar() && !type.isVector() && !type.isMatrix()) + { + return true; + } + + if (type.isArray() || IsSampler(type.getBasicType())) + { + return true; + } + + // We have a scalar / vector / matrix assignment with loop depth 2. + // Transform it from + // A = B + // to + // A = (B + typeof<B>(0)); + + TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, CreateZeroNode(type)); + bPlusZero->setLine(B->getLine()); + + binary->replaceChildNode(B, bPlusZero); + + return true; + } + + bool visitLoop(Visit visit, TIntermLoop *loop) + { + if (visit == PreVisit) + { + mLoopLevel++; + } + else + { + ASSERT(mLoopLevel > 0); + mLoopLevel--; + } + + return true; + } + + private: + int mLoopLevel = 0; +}; + +} // anonymous namespace + +void BreakVariableAliasingInInnerLoops(TIntermNode *root) +{ + AliasingBreaker breaker; + root->traverse(&breaker); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h new file mode 100644 index 0000000000..cdbdb7aa96 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 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. +// + +// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend +// may record a variable as aliasing another. Sometimes the alias information gets garbled +// so we work around this issue by breaking the aliasing chain in inner loops. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_BREAKVARIABLEALIASINGININNERLOOPS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_BREAKVARIABLEALIASINGININNERLOOPS_H_ + +class TIntermNode; + +namespace sh +{ + +void BreakVariableAliasingInInnerLoops(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_BREAKVARIABLEALIASINGININNERLOOPS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp new file mode 100644 index 0000000000..d721160a32 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp @@ -0,0 +1,54 @@ +// +// Copyright (c) 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/ClampFragDepth.h" + +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.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 +{ + +void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable) +{ + // Only clamp gl_FragDepth if it's used in the shader. + if (!FindSymbolNode(root, ImmutableString("gl_FragDepth"))) + { + return; + } + + 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 = new TIntermSequence(); + 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); + + RunAtTheEndOfShader(root, assignFragDepth, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h new file mode 100644 index 0000000000..70d1f7336a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 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_CLAMPFRAGDEPTH_H_ +#define COMPILER_TRANSLATOR_TREEOPS_CLAMPFRAGDEPTH_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_CLAMPFRAGDEPTH_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp new file mode 100644 index 0000000000..3966aabd83 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp @@ -0,0 +1,48 @@ +// +// Copyright (c) 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. +// +// ClampPointSize.cpp: Limit the value that is written to gl_PointSize. +// + +#include "compiler/translator/tree_ops/ClampPointSize.h" + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.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 +{ + +void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable) +{ + // Only clamp gl_PointSize if it's used in the shader. + if (!FindSymbolNode(root, ImmutableString("gl_PointSize"))) + { + return; + } + + TIntermSymbol *pointSizeNode = new TIntermSymbol(BuiltInVariable::gl_PointSize()); + + TConstantUnion *maxPointSizeConstant = new TConstantUnion(); + maxPointSizeConstant->setFConst(maxPointSize); + TIntermConstantUnion *maxPointSizeNode = + new TIntermConstantUnion(maxPointSizeConstant, TType(EbtFloat, EbpHigh, EvqConst)); + + // min(gl_PointSize, maxPointSize) + TIntermSequence *minArguments = new TIntermSequence(); + minArguments->push_back(pointSizeNode->deepCopy()); + minArguments->push_back(maxPointSizeNode); + TIntermTyped *clampedPointSize = + CreateBuiltInFunctionCallNode("min", minArguments, *symbolTable, 100); + + // gl_PointSize = min(gl_PointSize, maxPointSize) + TIntermBinary *assignPointSize = new TIntermBinary(EOpAssign, pointSizeNode, clampedPointSize); + + RunAtTheEndOfShader(root, assignPointSize, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h new file mode 100644 index 0000000000..5bc7cd4d43 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 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. +// +// ClampPointSize.h: Limit the value that is written to gl_PointSize. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_CLAMPPOINTSIZE_H_ +#define COMPILER_TRANSLATOR_TREEOPS_CLAMPPOINTSIZE_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_CLAMPPOINTSIZE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp new file mode 100644 index 0000000000..91ffe5966a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp @@ -0,0 +1,186 @@ +// +// Copyright (c) 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. +// +// Applies the necessary AST transformations to support multiview rendering through instancing. +// Check the header file For more information. +// + +#include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h" + +#include "compiler/translator/StaticType.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_ops/InitializeVariables.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.h" +#include "compiler/translator/tree_util/FindMain.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/tree_util/ReplaceVariable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kViewIDVariableName("ViewID_OVR"); +constexpr const ImmutableString kInstanceIDVariableName("InstanceID"); +constexpr const ImmutableString kMultiviewBaseViewLayerIndexVariableName( + "multiviewBaseViewLayerIndex"); + +// Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence. +void InitializeViewIDAndInstanceID(const TVariable *viewID, + const TVariable *instanceID, + unsigned numberOfViews, + const TSymbolTable &symbolTable, + TIntermSequence *initializers) +{ + // Create an unsigned numberOfViews node. + TConstantUnion *numberOfViewsUnsignedConstant = new TConstantUnion(); + numberOfViewsUnsignedConstant->setUConst(numberOfViews); + TIntermConstantUnion *numberOfViewsUint = + new TIntermConstantUnion(numberOfViewsUnsignedConstant, TType(EbtUInt, EbpHigh, EvqConst)); + + // Create a uint(gl_InstanceID) node. + TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence(); + glInstanceIDSymbolCastArguments->push_back(new TIntermSymbol(BuiltInVariable::gl_InstanceID())); + TIntermAggregate *glInstanceIDAsUint = TIntermAggregate::CreateConstructor( + TType(EbtUInt, EbpHigh, EvqTemporary), glInstanceIDSymbolCastArguments); + + // Create a uint(gl_InstanceID) / numberOfViews node. + TIntermBinary *normalizedInstanceID = + new TIntermBinary(EOpDiv, glInstanceIDAsUint, numberOfViewsUint); + + // Create an int(uint(gl_InstanceID) / numberOfViews) node. + TIntermSequence *normalizedInstanceIDCastArguments = new TIntermSequence(); + normalizedInstanceIDCastArguments->push_back(normalizedInstanceID); + TIntermAggregate *normalizedInstanceIDAsInt = TIntermAggregate::CreateConstructor( + TType(EbtInt, EbpHigh, EvqTemporary), normalizedInstanceIDCastArguments); + + // Create an InstanceID = int(uint(gl_InstanceID) / numberOfViews) node. + TIntermBinary *instanceIDInitializer = + new TIntermBinary(EOpAssign, new TIntermSymbol(instanceID), normalizedInstanceIDAsInt); + initializers->push_back(instanceIDInitializer); + + // Create a uint(gl_InstanceID) % numberOfViews node. + TIntermBinary *normalizedViewID = + new TIntermBinary(EOpIMod, glInstanceIDAsUint->deepCopy(), numberOfViewsUint->deepCopy()); + + // Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node. + TIntermBinary *viewIDInitializer = + new TIntermBinary(EOpAssign, new TIntermSymbol(viewID), normalizedViewID); + initializers->push_back(viewIDInitializer); +} + +// Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch is +// added to the end of the initializers' sequence. +void SelectViewIndexInVertexShader(const TVariable *viewID, + const TVariable *multiviewBaseViewLayerIndex, + TIntermSequence *initializers, + const TSymbolTable &symbolTable) +{ + // Create an int(ViewID_OVR) node. + TIntermSequence *viewIDSymbolCastArguments = new TIntermSequence(); + viewIDSymbolCastArguments->push_back(new TIntermSymbol(viewID)); + TIntermAggregate *viewIDAsInt = TIntermAggregate::CreateConstructor( + TType(EbtInt, EbpHigh, EvqTemporary), viewIDSymbolCastArguments); + + // Create a gl_ViewportIndex node. + TIntermSymbol *viewportIndexSymbol = new TIntermSymbol(BuiltInVariable::gl_ViewportIndex()); + + // Create a { gl_ViewportIndex = int(ViewID_OVR) } node. + TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock(); + viewportIndexInitializerInBlock->appendStatement( + new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt)); + + // Create a gl_Layer node. + TIntermSymbol *layerSymbol = new TIntermSymbol(BuiltInVariable::gl_LayerVS()); + + // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node + TIntermBinary *sumOfViewIDAndBaseViewIndex = new TIntermBinary( + EOpAdd, viewIDAsInt->deepCopy(), new TIntermSymbol(multiviewBaseViewLayerIndex)); + + // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node. + TIntermBlock *layerInitializerInBlock = new TIntermBlock(); + layerInitializerInBlock->appendStatement( + new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex)); + + // Create a node to compare whether the base view index uniform is less than zero. + TIntermBinary *multiviewBaseViewLayerIndexZeroComparison = + new TIntermBinary(EOpLessThan, new TIntermSymbol(multiviewBaseViewLayerIndex), + CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst))); + + // Create an if-else statement to select the code path. + TIntermIfElse *multiviewBranch = + new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison, + viewportIndexInitializerInBlock, layerInitializerInBlock); + + initializers->push_back(multiviewBranch); +} + +} // namespace + +void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, + unsigned numberOfViews, + GLenum shaderType, + ShCompileOptions compileOptions, + ShShaderOutput shaderOutput, + TSymbolTable *symbolTable) +{ + ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER); + + TQualifier viewIDQualifier = (shaderType == GL_VERTEX_SHADER) ? EvqFlatOut : EvqFlatIn; + const TVariable *viewID = + new TVariable(symbolTable, kViewIDVariableName, + new TType(EbtUInt, EbpHigh, viewIDQualifier), SymbolType::AngleInternal); + + DeclareGlobalVariable(root, viewID); + ReplaceVariable(root, BuiltInVariable::gl_ViewID_OVR(), viewID); + if (shaderType == GL_VERTEX_SHADER) + { + // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of + // InstanceID and ViewID. + const TType *instanceIDVariableType = StaticType::Get<EbtInt, EbpHigh, EvqGlobal, 1, 1>(); + const TVariable *instanceID = + new TVariable(symbolTable, kInstanceIDVariableName, instanceIDVariableType, + SymbolType::AngleInternal); + DeclareGlobalVariable(root, instanceID); + ReplaceVariable(root, BuiltInVariable::gl_InstanceID(), instanceID); + + TIntermSequence *initializers = new TIntermSequence(); + InitializeViewIDAndInstanceID(viewID, instanceID, numberOfViews, *symbolTable, + initializers); + + // The AST transformation which adds the expression to select the viewport index should + // be done only for the GLSL and ESSL output. + const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u; + // Assert that if the view is selected in the vertex shader, then the output is + // either GLSL or ESSL. + ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput)); + if (selectView) + { + // Add a uniform to switch between side-by-side and layered rendering. + const TType *baseLayerIndexVariableType = + StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>(); + const TVariable *multiviewBaseViewLayerIndex = + new TVariable(symbolTable, kMultiviewBaseViewLayerIndexVariableName, + baseLayerIndexVariableType, SymbolType::AngleInternal); + DeclareGlobalVariable(root, multiviewBaseViewLayerIndex); + + // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's + // initialization. + SelectViewIndexInVertexShader(viewID, multiviewBaseViewLayerIndex, initializers, + *symbolTable); + } + + // Insert initializers at the beginning of main(). + TIntermBlock *initializersBlock = new TIntermBlock(); + initializersBlock->getSequence()->swap(*initializers); + TIntermBlock *mainBody = FindMainBody(root); + mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock); + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h new file mode 100644 index 0000000000..9501ea58b3 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 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. +// +// Regardless of the shader type, the following AST transformations are applied: +// - Add declaration of View_ID_OVR. +// - Replace every occurrence of gl_ViewID_OVR with ViewID_OVR, mark ViewID_OVR as internal and +// declare it as a flat varying. +// +// If the shader type is a vertex shader, the following AST transformations are applied: +// - Replace every occurrence of gl_InstanceID with InstanceID, mark InstanceID as internal and set +// its qualifier to EvqTemporary. +// - Add initializers of ViewID_OVR and InstanceID to the beginning of the body of main. The pass +// should be executed before any variables get collected so that usage of gl_InstanceID is recorded. +// - If the output is ESSL or GLSL and the SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is +// enabled, the expression +// "if (multiviewBaseViewLayerIndex < 0) { +// gl_ViewportIndex = int(ViewID_OVR); +// } else { +// gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex; +// }" +// is added after ViewID and InstanceID are initialized. Also, MultiviewRenderPath is added as a +// uniform. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_ +#define COMPILER_TRANSLATOR_TREEOPS_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_ + +#include "GLSLANG/ShaderLang.h" +#include "angle_gl.h" + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, + unsigned numberOfViews, + GLenum shaderType, + ShCompileOptions compileOptions, + ShShaderOutput shaderOutput, + TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp new file mode 100644 index 0000000000..8f48d3e352 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp @@ -0,0 +1,167 @@ +// +// Copyright (c) 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. +// +// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate +// function that is called in the beginning of main(). This enables initialization of globals with +// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing +// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be +// done after DeferGlobalInitializers is run. Note that it's important that the function definition +// is at the end of the shader, as some globals may be declared after main(). +// +// It can also initialize all uninitialized globals. +// + +#include "compiler/translator/tree_ops/DeferGlobalInitializers.h" + +#include <vector> + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_ops/InitializeVariables.h" +#include "compiler/translator/tree_util/FindMain.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/ReplaceVariable.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kInitGlobalsString("initGlobals"); + +void GetDeferredInitializers(TIntermDeclaration *declaration, + bool initializeUninitializedGlobals, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TIntermSequence *deferredInitializersOut, + std::vector<const TVariable *> *variablesToReplaceOut, + TSymbolTable *symbolTable) +{ + // SeparateDeclarations should have already been run. + ASSERT(declaration->getSequence()->size() == 1); + + TIntermNode *declarator = declaration->getSequence()->back(); + TIntermBinary *init = declarator->getAsBinaryNode(); + if (init) + { + TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode(); + ASSERT(symbolNode); + TIntermTyped *expression = init->getRight(); + + if (expression->getQualifier() != EvqConst || !expression->hasConstantValue()) + { + // For variables which are not constant, defer their real initialization until + // after we initialize uniforms. + // Deferral is done also in any cases where the variable can not be converted to a + // constant union, since otherwise there's a chance that HLSL output will generate extra + // statements from the initializer expression. + + // Change const global to a regular global if its initialization is deferred. + // This can happen if ANGLE has not been able to fold the constant expression used + // as an initializer. + ASSERT(symbolNode->getQualifier() == EvqConst || + symbolNode->getQualifier() == EvqGlobal); + if (symbolNode->getQualifier() == EvqConst) + { + variablesToReplaceOut->push_back(&symbolNode->variable()); + } + + TIntermBinary *deferredInit = + new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight()); + deferredInitializersOut->push_back(deferredInit); + + // Remove the initializer from the global scope and just declare the global instead. + declaration->replaceChildNode(init, symbolNode); + } + } + else if (initializeUninitializedGlobals) + { + TIntermSymbol *symbolNode = declarator->getAsSymbolNode(); + ASSERT(symbolNode); + + // Ignore ANGLE internal variables and nameless declarations. + if (symbolNode->variable().symbolType() == SymbolType::AngleInternal || + symbolNode->variable().symbolType() == SymbolType::Empty) + return; + + if (symbolNode->getQualifier() == EvqGlobal) + { + TIntermSequence *initCode = CreateInitCode(symbolNode, canUseLoopsToInitialize, + highPrecisionSupported, symbolTable); + deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(), + initCode->end()); + } + } +} + +void InsertInitCallToMain(TIntermBlock *root, + TIntermSequence *deferredInitializers, + TSymbolTable *symbolTable) +{ + TIntermBlock *initGlobalsBlock = new TIntermBlock(); + initGlobalsBlock->getSequence()->swap(*deferredInitializers); + + TFunction *initGlobalsFunction = + new TFunction(symbolTable, kInitGlobalsString, SymbolType::AngleInternal, + StaticType::GetBasic<EbtVoid>(), false); + + TIntermFunctionPrototype *initGlobalsFunctionPrototype = + CreateInternalFunctionPrototypeNode(*initGlobalsFunction); + root->getSequence()->insert(root->getSequence()->begin(), initGlobalsFunctionPrototype); + TIntermFunctionDefinition *initGlobalsFunctionDefinition = + CreateInternalFunctionDefinitionNode(*initGlobalsFunction, initGlobalsBlock); + root->appendStatement(initGlobalsFunctionDefinition); + + TIntermAggregate *initGlobalsCall = + TIntermAggregate::CreateFunctionCall(*initGlobalsFunction, new TIntermSequence()); + + TIntermBlock *mainBody = FindMainBody(root); + mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall); +} + +} // namespace + +void DeferGlobalInitializers(TIntermBlock *root, + bool initializeUninitializedGlobals, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TSymbolTable *symbolTable) +{ + TIntermSequence *deferredInitializers = new TIntermSequence(); + std::vector<const TVariable *> variablesToReplace; + + // Loop over all global statements and process the declarations. This is simpler than using a + // traverser. + for (TIntermNode *statement : *root->getSequence()) + { + TIntermDeclaration *declaration = statement->getAsDeclarationNode(); + if (declaration) + { + GetDeferredInitializers(declaration, initializeUninitializedGlobals, + canUseLoopsToInitialize, highPrecisionSupported, + deferredInitializers, &variablesToReplace, symbolTable); + } + } + + // Add the function with initialization and the call to that. + if (!deferredInitializers->empty()) + { + InsertInitCallToMain(root, deferredInitializers, symbolTable); + } + + // Replace constant variables with non-constant global variables. + for (const TVariable *var : variablesToReplace) + { + TType *replacementType = new TType(var->getType()); + replacementType->setQualifier(EvqGlobal); + TVariable *replacement = + new TVariable(symbolTable, var->name(), replacementType, var->symbolType()); + ReplaceVariable(root, var, replacement); + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h new file mode 100644 index 0000000000..b0e4547857 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 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. +// +// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate +// function that is called in the beginning of main(). This enables initialization of globals with +// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing +// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be +// done after DeferGlobalInitializers is run. Note that it's important that the function definition +// is at the end of the shader, as some globals may be declared after main(). +// +// It can also initialize all uninitialized globals. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_DEFERGLOBALINITIALIZERS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_DEFERGLOBALINITIALIZERS_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void DeferGlobalInitializers(TIntermBlock *root, + bool initializeUninitializedGlobals, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_DEFERGLOBALINITIALIZERS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp new file mode 100644 index 0000000000..d562136999 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp @@ -0,0 +1,131 @@ +// +// Copyright (c) 2002-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. +// +// gl_FragColor needs to broadcast to all color buffers in ES2 if +// GL_EXT_draw_buffers is explicitly enabled in a fragment shader. +// +// We emulate this by replacing all gl_FragColor with gl_FragData[0], and in the end +// of main() function, assigning gl_FragData[1], ..., gl_FragData[maxDrawBuffers-1] +// with gl_FragData[0]. +// + +#include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h" + +#include "compiler/translator/Symbol.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/tree_util/RunAtTheEndOfShader.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kGlFragDataString("gl_FragData"); + +class GLFragColorBroadcastTraverser : public TIntermTraverser +{ + public: + GLFragColorBroadcastTraverser(int maxDrawBuffers, TSymbolTable *symbolTable, int shaderVersion) + : TIntermTraverser(true, false, false, symbolTable), + mGLFragColorUsed(false), + mMaxDrawBuffers(maxDrawBuffers), + mShaderVersion(shaderVersion) + {} + + void broadcastGLFragColor(TIntermBlock *root); + + bool isGLFragColorUsed() const { return mGLFragColorUsed; } + + protected: + void visitSymbol(TIntermSymbol *node) override; + + TIntermBinary *constructGLFragDataNode(int index) const; + TIntermBinary *constructGLFragDataAssignNode(int index) const; + + private: + bool mGLFragColorUsed; + int mMaxDrawBuffers; + const int mShaderVersion; +}; + +TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const +{ + TIntermSymbol *symbol = + ReferenceBuiltInVariable(kGlFragDataString, *mSymbolTable, mShaderVersion); + TIntermTyped *indexNode = CreateIndexNode(index); + + TIntermBinary *binary = new TIntermBinary(EOpIndexDirect, symbol, indexNode); + return binary; +} + +TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const +{ + TIntermTyped *fragDataIndex = constructGLFragDataNode(index); + TIntermTyped *fragDataZero = constructGLFragDataNode(0); + + return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero); +} + +void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node) +{ + if (node->variable().symbolType() == SymbolType::BuiltIn && node->getName() == "gl_FragColor") + { + queueReplacement(constructGLFragDataNode(0), OriginalNode::IS_DROPPED); + mGLFragColorUsed = true; + } +} + +void GLFragColorBroadcastTraverser::broadcastGLFragColor(TIntermBlock *root) +{ + ASSERT(mMaxDrawBuffers > 1); + if (!mGLFragColorUsed) + { + return; + } + + TIntermBlock *broadcastBlock = new TIntermBlock(); + // Now insert statements + // gl_FragData[1] = gl_FragData[0]; + // ... + // gl_FragData[maxDrawBuffers - 1] = gl_FragData[0]; + for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex) + { + broadcastBlock->appendStatement(constructGLFragDataAssignNode(colorIndex)); + } + RunAtTheEndOfShader(root, broadcastBlock, mSymbolTable); +} + +} // namespace + +void EmulateGLFragColorBroadcast(TIntermBlock *root, + int maxDrawBuffers, + std::vector<sh::OutputVariable> *outputVariables, + TSymbolTable *symbolTable, + int shaderVersion) +{ + ASSERT(maxDrawBuffers > 1); + GLFragColorBroadcastTraverser traverser(maxDrawBuffers, symbolTable, shaderVersion); + root->traverse(&traverser); + if (traverser.isGLFragColorUsed()) + { + traverser.updateTree(); + traverser.broadcastGLFragColor(root); + for (auto &var : *outputVariables) + { + if (var.name == "gl_FragColor") + { + // TODO(zmo): Find a way to keep the original variable information. + var.name = "gl_FragData"; + var.mappedName = "gl_FragData"; + var.arraySizes.push_back(maxDrawBuffers); + ASSERT(var.arraySizes.size() == 1u); + } + } + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h new file mode 100644 index 0000000000..f6bf549bac --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2002-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. +// +// Emulate gl_FragColor broadcast behaviors in ES2 where +// GL_EXT_draw_buffers is explicitly enabled in a fragment shader. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_EMULATEGLFRAGCOLORBROADCAST_H_ +#define COMPILER_TRANSLATOR_TREEOPS_EMULATEGLFRAGCOLORBROADCAST_H_ + +#include <vector> + +namespace sh +{ +struct OutputVariable; +class TIntermBlock; +class TSymbolTable; + +// Replace all gl_FragColor with gl_FragData[0], and in the end of main() function, +// assign gl_FragData[1] ... gl_FragData[maxDrawBuffers - 1] with gl_FragData[0]. +// If gl_FragColor is in outputVariables, it is replaced by gl_FragData. +void EmulateGLFragColorBroadcast(TIntermBlock *root, + int maxDrawBuffers, + std::vector<OutputVariable> *outputVariables, + TSymbolTable *symbolTable, + int shaderVersion); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_EMULATEGLFRAGCOLORBROADCAST_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp new file mode 100644 index 0000000000..8134ea79c3 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.cpp @@ -0,0 +1,213 @@ +// +// 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. +// +// EmulateGLDrawID is an AST traverser to convert the gl_DrawID builtin +// to a uniform int +// +// EmulateGLBaseVertex is an AST traverser to convert the gl_BaseVertex builtin +// to a uniform int +// +// EmulateGLBaseInstance is an AST traverser to convert the gl_BaseInstance builtin +// to a uniform int +// + +#include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h" + +#include "angle_gl.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/Symbol.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/BuiltIn_autogen.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/tree_util/ReplaceVariable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kEmulatedGLDrawIDName("angle_DrawID"); + +class FindGLDrawIDTraverser : public TIntermTraverser +{ + public: + FindGLDrawIDTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {} + + const TVariable *getGLDrawIDBuiltinVariable() { return mVariable; } + + protected: + void visitSymbol(TIntermSymbol *node) override + { + if (&node->variable() == BuiltInVariable::gl_DrawID() || + &node->variable() == BuiltInVariable::gl_DrawIDESSL1()) + { + mVariable = &node->variable(); + } + } + + private: + const TVariable *mVariable; +}; + +constexpr const ImmutableString kEmulatedGLBaseVertexName("angle_BaseVertex"); + +class FindGLBaseVertexTraverser : public TIntermTraverser +{ + public: + FindGLBaseVertexTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {} + + const TVariable *getGLBaseVertexBuiltinVariable() { return mVariable; } + + protected: + void visitSymbol(TIntermSymbol *node) override + { + if (&node->variable() == BuiltInVariable::gl_BaseVertex()) + { + mVariable = &node->variable(); + } + } + + private: + const TVariable *mVariable; +}; + +constexpr const ImmutableString kEmulatedGLBaseInstanceName("angle_BaseInstance"); + +class FindGLBaseInstanceTraverser : public TIntermTraverser +{ + public: + FindGLBaseInstanceTraverser() : TIntermTraverser(true, false, false), mVariable(nullptr) {} + + const TVariable *getGLBaseInstanceBuiltinVariable() { return mVariable; } + + protected: + void visitSymbol(TIntermSymbol *node) override + { + if (&node->variable() == BuiltInVariable::gl_BaseInstance()) + { + mVariable = &node->variable(); + } + } + + private: + const TVariable *mVariable; +}; + +} // namespace + +void EmulateGLDrawID(TIntermBlock *root, + TSymbolTable *symbolTable, + std::vector<sh::Uniform> *uniforms, + bool shouldCollect) +{ + FindGLDrawIDTraverser traverser; + root->traverse(&traverser); + const TVariable *builtInVariable = traverser.getGLDrawIDBuiltinVariable(); + if (builtInVariable) + { + const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>(); + const TVariable *drawID = + new TVariable(symbolTable, kEmulatedGLDrawIDName, type, SymbolType::AngleInternal); + + // AngleInternal variables don't get collected + if (shouldCollect) + { + Uniform uniform; + uniform.name = kEmulatedGLDrawIDName.data(); + uniform.mappedName = kEmulatedGLDrawIDName.data(); + uniform.type = GLVariableType(*type); + uniform.precision = GLVariablePrecision(*type); + uniform.staticUse = symbolTable->isStaticallyUsed(*builtInVariable); + uniform.active = true; + uniform.binding = type->getLayoutQualifier().binding; + uniform.location = type->getLayoutQualifier().location; + uniform.offset = type->getLayoutQualifier().offset; + uniform.readonly = type->getMemoryQualifier().readonly; + uniform.writeonly = type->getMemoryQualifier().writeonly; + uniforms->push_back(uniform); + } + + DeclareGlobalVariable(root, drawID); + ReplaceVariable(root, builtInVariable, drawID); + } +} + +void EmulateGLBaseVertex(TIntermBlock *root, + TSymbolTable *symbolTable, + std::vector<sh::Uniform> *uniforms, + bool shouldCollect) +{ + FindGLBaseVertexTraverser traverser; + root->traverse(&traverser); + const TVariable *builtInVariable = traverser.getGLBaseVertexBuiltinVariable(); + if (builtInVariable) + { + const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>(); + const TVariable *baseVertex = + new TVariable(symbolTable, kEmulatedGLBaseVertexName, type, SymbolType::AngleInternal); + + // AngleInternal variables don't get collected + if (shouldCollect) + { + Uniform uniform; + uniform.name = kEmulatedGLBaseVertexName.data(); + uniform.mappedName = kEmulatedGLBaseVertexName.data(); + uniform.type = GLVariableType(*type); + uniform.precision = GLVariablePrecision(*type); + uniform.staticUse = symbolTable->isStaticallyUsed(*builtInVariable); + uniform.active = true; + uniform.binding = type->getLayoutQualifier().binding; + uniform.location = type->getLayoutQualifier().location; + uniform.offset = type->getLayoutQualifier().offset; + uniform.readonly = type->getMemoryQualifier().readonly; + uniform.writeonly = type->getMemoryQualifier().writeonly; + uniforms->push_back(uniform); + } + + DeclareGlobalVariable(root, baseVertex); + ReplaceVariable(root, builtInVariable, baseVertex); + } +} + +void EmulateGLBaseInstance(TIntermBlock *root, + TSymbolTable *symbolTable, + std::vector<sh::Uniform> *uniforms, + bool shouldCollect) +{ + FindGLBaseInstanceTraverser traverser; + root->traverse(&traverser); + const TVariable *builtInVariable = traverser.getGLBaseInstanceBuiltinVariable(); + if (builtInVariable) + { + const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>(); + const TVariable *baseInstance = new TVariable(symbolTable, kEmulatedGLBaseInstanceName, + type, SymbolType::AngleInternal); + + // AngleInternal variables don't get collected + if (shouldCollect) + { + Uniform uniform; + uniform.name = kEmulatedGLBaseInstanceName.data(); + uniform.mappedName = kEmulatedGLBaseInstanceName.data(); + uniform.type = GLVariableType(*type); + uniform.precision = GLVariablePrecision(*type); + uniform.staticUse = symbolTable->isStaticallyUsed(*builtInVariable); + uniform.active = true; + uniform.binding = type->getLayoutQualifier().binding; + uniform.location = type->getLayoutQualifier().location; + uniform.offset = type->getLayoutQualifier().offset; + uniform.readonly = type->getMemoryQualifier().readonly; + uniform.writeonly = type->getMemoryQualifier().writeonly; + uniforms->push_back(uniform); + } + + DeclareGlobalVariable(root, baseInstance); + ReplaceVariable(root, builtInVariable, baseInstance); + } +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h new file mode 100644 index 0000000000..8134db9873 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h @@ -0,0 +1,47 @@ +// +// 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. +// +// EmulateGLDrawID is an AST traverser to convert the gl_DrawID builtin +// to a uniform int +// +// EmulateGLBaseVertex is an AST traverser to convert the gl_BaseVertex builtin +// to a uniform int +// +// EmulateGLBaseInstance is an AST traverser to convert the gl_BaseInstance builtin +// to a uniform int +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_EMULATEMULTIDRAWSHADERBUILTINS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_EMULATEMULTIDRAWSHADERBUILTINS_H_ + +#include <GLSLANG/ShaderLang.h> +#include <vector> + +#include "compiler/translator/HashNames.h" + +namespace sh +{ +struct Uniform; +class TIntermBlock; +class TSymbolTable; + +void EmulateGLDrawID(TIntermBlock *root, + TSymbolTable *symbolTable, + std::vector<sh::Uniform> *uniforms, + bool shouldCollect); + +void EmulateGLBaseVertex(TIntermBlock *root, + TSymbolTable *symbolTable, + std::vector<sh::Uniform> *uniforms, + bool shouldCollect); + +void EmulateGLBaseInstance(TIntermBlock *root, + TSymbolTable *symbolTable, + std::vector<sh::Uniform> *uniforms, + bool shouldCollect); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_EMULATEMULTIDRAWSHADERBUILTINS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp new file mode 100644 index 0000000000..ba19bd112e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp @@ -0,0 +1,776 @@ +// +// Copyright (c) 2002-2014 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/EmulatePrecision.h" + +#include "compiler/translator/FunctionLookup.h" + +#include <memory> + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kParamXName("x"); +constexpr const ImmutableString kParamYName("y"); +constexpr const ImmutableString kAngleFrmString("angle_frm"); +constexpr const ImmutableString kAngleFrlString("angle_frl"); + +class RoundingHelperWriter : angle::NonCopyable +{ + public: + static RoundingHelperWriter *createHelperWriter(const ShShaderOutput outputLanguage); + + void writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion); + void writeCompoundAssignmentHelper(TInfoSinkBase &sink, + const char *lType, + const char *rType, + const char *opStr, + const char *opNameStr); + + virtual ~RoundingHelperWriter() {} + + protected: + RoundingHelperWriter(const ShShaderOutput outputLanguage) : mOutputLanguage(outputLanguage) {} + RoundingHelperWriter() = delete; + + const ShShaderOutput mOutputLanguage; + + private: + virtual std::string getTypeString(const char *glslType) = 0; + virtual void writeFloatRoundingHelpers(TInfoSinkBase &sink) = 0; + virtual void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) = 0; + virtual void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) = 0; +}; + +class RoundingHelperWriterGLSL : public RoundingHelperWriter +{ + public: + RoundingHelperWriterGLSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriter(outputLanguage) + {} + + private: + std::string getTypeString(const char *glslType) override; + void writeFloatRoundingHelpers(TInfoSinkBase &sink) override; + void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override; + void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) override; +}; + +class RoundingHelperWriterESSL : public RoundingHelperWriterGLSL +{ + public: + RoundingHelperWriterESSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriterGLSL(outputLanguage) + {} + + private: + std::string getTypeString(const char *glslType) override; +}; + +class RoundingHelperWriterHLSL : public RoundingHelperWriter +{ + public: + RoundingHelperWriterHLSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriter(outputLanguage) + {} + + private: + std::string getTypeString(const char *glslType) override; + void writeFloatRoundingHelpers(TInfoSinkBase &sink) override; + void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override; + void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) override; +}; + +RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOutput outputLanguage) +{ + ASSERT(EmulatePrecision::SupportedInLanguage(outputLanguage)); + switch (outputLanguage) + { + case SH_HLSL_4_1_OUTPUT: + return new RoundingHelperWriterHLSL(outputLanguage); + case SH_ESSL_OUTPUT: + return new RoundingHelperWriterESSL(outputLanguage); + default: + return new RoundingHelperWriterGLSL(outputLanguage); + } +} + +void RoundingHelperWriter::writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion) +{ + // Write the angle_frm functions that round floating point numbers to + // half precision, and angle_frl functions that round them to minimum lowp + // precision. + + writeFloatRoundingHelpers(sink); + writeVectorRoundingHelpers(sink, 2); + writeVectorRoundingHelpers(sink, 3); + writeVectorRoundingHelpers(sink, 4); + if (shaderVersion > 100) + { + for (unsigned int columns = 2; columns <= 4; ++columns) + { + for (unsigned int rows = 2; rows <= 4; ++rows) + { + writeMatrixRoundingHelper(sink, columns, rows, "angle_frm"); + writeMatrixRoundingHelper(sink, columns, rows, "angle_frl"); + } + } + } + else + { + for (unsigned int size = 2; size <= 4; ++size) + { + writeMatrixRoundingHelper(sink, size, size, "angle_frm"); + writeMatrixRoundingHelper(sink, size, size, "angle_frl"); + } + } +} + +void RoundingHelperWriter::writeCompoundAssignmentHelper(TInfoSinkBase &sink, + const char *lType, + const char *rType, + const char *opStr, + const char *opNameStr) +{ + std::string lTypeStr = getTypeString(lType); + std::string rTypeStr = getTypeString(rType); + + // Note that y should be passed through angle_frm at the function call site, + // but x can't be passed through angle_frm there since it is an inout parameter. + // So only pass x and the result through angle_frm here. + // clang-format off + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frm(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frl(angle_frl(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + // clang-format on +} + +std::string RoundingHelperWriterGLSL::getTypeString(const char *glslType) +{ + return glslType; +} + +std::string RoundingHelperWriterESSL::getTypeString(const char *glslType) +{ + std::stringstream typeStrStr = sh::InitializeStream<std::stringstream>(); + typeStrStr << "highp " << glslType; + return typeStrStr.str(); +} + +void RoundingHelperWriterGLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink) +{ + // Unoptimized version of angle_frm for single floats: + // + // int webgl_maxNormalExponent(in int exponentBits) + // { + // int possibleExponents = int(exp2(float(exponentBits))); + // int exponentBias = possibleExponents / 2 - 1; + // int allExponentBitsOne = possibleExponents - 1; + // return (allExponentBitsOne - 1) - exponentBias; + // } + // + // float angle_frm(in float x) + // { + // int mantissaBits = 10; + // int exponentBits = 5; + // float possibleMantissas = exp2(float(mantissaBits)); + // float mantissaMax = 2.0 - 1.0 / possibleMantissas; + // int maxNE = webgl_maxNormalExponent(exponentBits); + // float max = exp2(float(maxNE)) * mantissaMax; + // if (x > max) + // { + // return max; + // } + // if (x < -max) + // { + // return -max; + // } + // float exponent = floor(log2(abs(x))); + // if (abs(x) == 0.0 || exponent < -float(maxNE)) + // { + // return 0.0 * sign(x) + // } + // x = x * exp2(-(exponent - float(mantissaBits))); + // x = sign(x) * floor(abs(x)); + // return x * exp2(exponent - float(mantissaBits)); + // } + + // All numbers with a magnitude less than 2^-15 are subnormal, and are + // flushed to zero. + + // Note the constant numbers below: + // a) 65504 is the maximum possible mantissa (1.1111111111 in binary) times + // 2^15, the maximum normal exponent. + // b) 10.0 is the number of mantissa bits. + // c) -25.0 is the minimum normal half-float exponent -15.0 minus the number + // of mantissa bits. + // d) + 1e-30 is to make sure the argument of log2() won't be zero. It can + // only affect the result of log2 on x where abs(x) < 1e-22. Since these + // numbers will be flushed to zero either way (2^-15 is the smallest + // normal positive number), this does not introduce any error. + + std::string floatType = getTypeString("float"); + + // clang-format off + sink << + floatType << " angle_frm(in " << floatType << " x) {\n" + " x = clamp(x, -65504.0, 65504.0);\n" + " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n" + " bool isNonZero = (exponent >= -25.0);\n" + " x = x * exp2(-exponent);\n" + " x = sign(x) * floor(abs(x));\n" + " return x * exp2(exponent) * float(isNonZero);\n" + "}\n"; + + sink << + floatType << " angle_frl(in " << floatType << " x) {\n" + " x = clamp(x, -2.0, 2.0);\n" + " x = x * 256.0;\n" + " x = sign(x) * floor(abs(x));\n" + " return x * 0.00390625;\n" + "}\n"; + // clang-format on +} + +void RoundingHelperWriterGLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink, + const unsigned int size) +{ + std::stringstream vecTypeStrStr = sh::InitializeStream<std::stringstream>(); + vecTypeStrStr << "vec" << size; + std::string vecType = getTypeString(vecTypeStrStr.str().c_str()); + + // clang-format off + sink << + vecType << " angle_frm(in " << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * vec" << size << "(isNonZero);\n" + "}\n"; + + sink << + vecType << " angle_frl(in " << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; + // clang-format on +} + +void RoundingHelperWriterGLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) +{ + std::stringstream matTypeStrStr = sh::InitializeStream<std::stringstream>(); + matTypeStrStr << "mat" << columns; + if (rows != columns) + { + matTypeStrStr << "x" << rows; + } + std::string matType = getTypeString(matTypeStrStr.str().c_str()); + + sink << matType << " " << functionName << "(in " << matType << " m) {\n" + << " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < columns; ++i) + { + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; + } + + sink << " return rounded;\n" + "}\n"; +} + +static const char *GetHLSLTypeStr(const char *floatTypeStr) +{ + if (strcmp(floatTypeStr, "float") == 0) + { + return "float"; + } + if (strcmp(floatTypeStr, "vec2") == 0) + { + return "float2"; + } + if (strcmp(floatTypeStr, "vec3") == 0) + { + return "float3"; + } + if (strcmp(floatTypeStr, "vec4") == 0) + { + return "float4"; + } + if (strcmp(floatTypeStr, "mat2") == 0) + { + return "float2x2"; + } + if (strcmp(floatTypeStr, "mat3") == 0) + { + return "float3x3"; + } + if (strcmp(floatTypeStr, "mat4") == 0) + { + return "float4x4"; + } + if (strcmp(floatTypeStr, "mat2x3") == 0) + { + return "float2x3"; + } + if (strcmp(floatTypeStr, "mat2x4") == 0) + { + return "float2x4"; + } + if (strcmp(floatTypeStr, "mat3x2") == 0) + { + return "float3x2"; + } + if (strcmp(floatTypeStr, "mat3x4") == 0) + { + return "float3x4"; + } + if (strcmp(floatTypeStr, "mat4x2") == 0) + { + return "float4x2"; + } + if (strcmp(floatTypeStr, "mat4x3") == 0) + { + return "float4x3"; + } + UNREACHABLE(); + return nullptr; +} + +std::string RoundingHelperWriterHLSL::getTypeString(const char *glslType) +{ + return GetHLSLTypeStr(glslType); +} + +void RoundingHelperWriterHLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink) +{ + // In HLSL scalars are the same as 1-vectors. + writeVectorRoundingHelpers(sink, 1); +} + +void RoundingHelperWriterHLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink, + const unsigned int size) +{ + std::stringstream vecTypeStrStr = sh::InitializeStream<std::stringstream>(); + vecTypeStrStr << "float" << size; + std::string vecType = vecTypeStrStr.str(); + + // clang-format off + sink << + vecType << " angle_frm(" << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bool" << size << " isNonZero = exponent < -25.0;\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * (float" << size << ")(isNonZero);\n" + "}\n"; + + sink << + vecType << " angle_frl(" << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; + // clang-format on +} + +void RoundingHelperWriterHLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) +{ + std::stringstream matTypeStrStr = sh::InitializeStream<std::stringstream>(); + matTypeStrStr << "float" << columns << "x" << rows; + std::string matType = matTypeStrStr.str(); + + sink << matType << " " << functionName << "(" << matType << " m) {\n" + << " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < columns; ++i) + { + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; + } + + sink << " return rounded;\n" + "}\n"; +} + +bool canRoundFloat(const TType &type) +{ + return type.getBasicType() == EbtFloat && !type.isArray() && + (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium); +} + +bool ParentUsesResult(TIntermNode *parent, TIntermTyped *node) +{ + if (!parent) + { + return false; + } + + TIntermBlock *blockParent = parent->getAsBlock(); + // If the parent is a block, the result is not assigned anywhere, + // so rounding it is not needed. In particular, this can avoid a lot of + // unnecessary rounding of unused return values of assignment. + if (blockParent) + { + return false; + } + TIntermBinary *binaryParent = parent->getAsBinaryNode(); + if (binaryParent && binaryParent->getOp() == EOpComma && (binaryParent->getRight() != node)) + { + return false; + } + return true; +} + +bool ParentConstructorTakesCareOfRounding(TIntermNode *parent, TIntermTyped *node) +{ + if (!parent) + { + return false; + } + TIntermAggregate *parentConstructor = parent->getAsAggregate(); + if (!parentConstructor || parentConstructor->getOp() != EOpConstruct) + { + return false; + } + if (parentConstructor->getPrecision() != node->getPrecision()) + { + return false; + } + return canRoundFloat(parentConstructor->getType()); +} + +} // namespace + +EmulatePrecision::EmulatePrecision(TSymbolTable *symbolTable) + : TLValueTrackingTraverser(true, true, true, symbolTable), mDeclaringVariables(false) +{} + +void EmulatePrecision::visitSymbol(TIntermSymbol *node) +{ + TIntermNode *parent = getParentNode(); + if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) && + !ParentConstructorTakesCareOfRounding(parent, node) && !mDeclaringVariables && + !isLValueRequiredHere()) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); + } +} + +bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) +{ + bool visitChildren = true; + + TOperator op = node->getOp(); + + // RHS of initialize is not being declared. + if (op == EOpInitialize && visit == InVisit) + mDeclaringVariables = false; + + if ((op == EOpIndexDirectStruct) && visit == InVisit) + visitChildren = false; + + if (visit != PreVisit) + return visitChildren; + + const TType &type = node->getType(); + bool roundFloat = canRoundFloat(type); + + if (roundFloat) + { + switch (op) + { + // Math operators that can result in a float may need to apply rounding to the return + // value. Note that in the case of assignment, the rounding is applied to its return + // value here, not the value being assigned. + case EOpAssign: + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + { + TIntermNode *parent = getParentNode(); + if (!ParentUsesResult(parent, node) || + ParentConstructorTakesCareOfRounding(parent, node)) + { + break; + } + TIntermNode *replacement = createRoundingFunctionCallNode(node); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); + break; + } + + // Compound assignment cases need to replace the operator with a function call. + case EOpAddAssign: + { + mEmulateCompoundAdd.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "add"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + case EOpSubAssign: + { + mEmulateCompoundSub.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "sub"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + { + mEmulateCompoundMul.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "mul"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + case EOpDivAssign: + { + mEmulateCompoundDiv.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "div"); + queueReplacement(replacement, OriginalNode::IS_DROPPED); + break; + } + default: + // The rest of the binary operations should not need precision emulation. + break; + } + } + return visitChildren; +} + +bool EmulatePrecision::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + // Variable or interface block declaration. + if (visit == PreVisit) + { + mDeclaringVariables = true; + } + else if (visit == InVisit) + { + mDeclaringVariables = true; + } + else + { + mDeclaringVariables = false; + } + return true; +} + +bool EmulatePrecision::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) +{ + return false; +} + +bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (visit != PreVisit) + return true; + + // User-defined function return values are not rounded. The calculations that produced + // the value inside the function definition should have been rounded. + TOperator op = node->getOp(); + if (op == EOpCallInternalRawFunction || op == EOpCallFunctionInAST || + (op == EOpConstruct && node->getBasicType() == EbtStruct)) + { + return true; + } + + TIntermNode *parent = getParentNode(); + if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) && + !ParentConstructorTakesCareOfRounding(parent, node)) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); + } + return true; +} + +bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node) +{ + switch (node->getOp()) + { + case EOpNegative: + case EOpLogicalNot: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpLogicalNotComponentWise: + break; + default: + if (canRoundFloat(node->getType()) && visit == PreVisit) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + queueReplacement(replacement, OriginalNode::BECOMES_CHILD); + } + break; + } + + return true; +} + +void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink, + const int shaderVersion, + const ShShaderOutput outputLanguage) +{ + std::unique_ptr<RoundingHelperWriter> roundingHelperWriter( + RoundingHelperWriter::createHelperWriter(outputLanguage)); + + roundingHelperWriter->writeCommonRoundingHelpers(sink, shaderVersion); + + EmulationSet::const_iterator it; + for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++) + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "+", "add"); + for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++) + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "-", "sub"); + for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++) + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "/", "div"); + for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++) + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "*", "mul"); +} + +// static +bool EmulatePrecision::SupportedInLanguage(const ShShaderOutput outputLanguage) +{ + switch (outputLanguage) + { + case SH_HLSL_4_1_OUTPUT: + case SH_ESSL_OUTPUT: + return true; + default: + // Other languages not yet supported + return (outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT || + sh::IsGLSL130OrNewer(outputLanguage)); + } +} + +const TFunction *EmulatePrecision::getInternalFunction(const ImmutableString &functionName, + const TType &returnType, + TIntermSequence *arguments, + const TVector<const TVariable *> ¶meters, + bool knownToNotHaveSideEffects) +{ + ImmutableString mangledName = TFunctionLookup::GetMangledName(functionName.data(), *arguments); + if (mInternalFunctions.find(mangledName) == mInternalFunctions.end()) + { + TFunction *func = new TFunction(mSymbolTable, functionName, SymbolType::AngleInternal, + new TType(returnType), knownToNotHaveSideEffects); + ASSERT(parameters.size() == arguments->size()); + for (size_t i = 0; i < parameters.size(); ++i) + { + func->addParameter(parameters[i]); + } + mInternalFunctions[mangledName] = func; + } + return mInternalFunctions[mangledName]; +} + +TIntermAggregate *EmulatePrecision::createRoundingFunctionCallNode(TIntermTyped *roundedChild) +{ + const ImmutableString *roundFunctionName = &kAngleFrmString; + if (roundedChild->getPrecision() == EbpLow) + roundFunctionName = &kAngleFrlString; + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(roundedChild); + + TVector<const TVariable *> parameters; + TType *paramType = new TType(roundedChild->getType()); + paramType->setPrecision(EbpHigh); + paramType->setQualifier(EvqIn); + parameters.push_back(new TVariable(mSymbolTable, kParamXName, + static_cast<const TType *>(paramType), + SymbolType::AngleInternal)); + + return TIntermAggregate::CreateRawFunctionCall( + *getInternalFunction(*roundFunctionName, roundedChild->getType(), arguments, parameters, + true), + arguments); +} + +TIntermAggregate *EmulatePrecision::createCompoundAssignmentFunctionCallNode(TIntermTyped *left, + TIntermTyped *right, + const char *opNameStr) +{ + std::stringstream strstr = sh::InitializeStream<std::stringstream>(); + if (left->getPrecision() == EbpMedium) + strstr << "angle_compound_" << opNameStr << "_frm"; + else + strstr << "angle_compound_" << opNameStr << "_frl"; + ImmutableString functionName = ImmutableString(strstr.str()); + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(left); + arguments->push_back(right); + + TVector<const TVariable *> parameters; + TType *leftParamType = new TType(left->getType()); + leftParamType->setPrecision(EbpHigh); + leftParamType->setQualifier(EvqOut); + parameters.push_back(new TVariable(mSymbolTable, kParamXName, + static_cast<const TType *>(leftParamType), + SymbolType::AngleInternal)); + TType *rightParamType = new TType(right->getType()); + rightParamType->setPrecision(EbpHigh); + rightParamType->setQualifier(EvqIn); + parameters.push_back(new TVariable(mSymbolTable, kParamYName, + static_cast<const TType *>(rightParamType), + SymbolType::AngleInternal)); + + return TIntermAggregate::CreateRawFunctionCall( + *getInternalFunction(functionName, left->getType(), arguments, parameters, false), + arguments); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h new file mode 100644 index 0000000000..10501fa1d0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h @@ -0,0 +1,85 @@ +// +// Copyright (c) 2002-2014 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_EMULATE_PRECISION_H_ +#define COMPILER_TRANSLATOR_TREEOPS_EMULATE_PRECISION_H_ + +#include "GLSLANG/ShaderLang.h" +#include "common/angleutils.h" +#include "compiler/translator/Compiler.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +// This class gathers all compound assignments from the AST and can then write +// the functions required for their precision emulation. This way there is no +// need to write a huge number of variations of the emulated compound assignment +// to every translated shader with emulation enabled. + +namespace sh +{ + +class EmulatePrecision : public TLValueTrackingTraverser +{ + public: + EmulatePrecision(TSymbolTable *symbolTable); + + void visitSymbol(TIntermSymbol *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + + void writeEmulationHelpers(TInfoSinkBase &sink, + const int shaderVersion, + const ShShaderOutput outputLanguage); + + static bool SupportedInLanguage(const ShShaderOutput outputLanguage); + + private: + struct TypePair + { + TypePair(const char *l, const char *r) : lType(l), rType(r) {} + + const char *lType; + const char *rType; + }; + + struct TypePairComparator + { + bool operator()(const TypePair &l, const TypePair &r) const + { + if (l.lType == r.lType) + return l.rType < r.rType; + return l.lType < r.lType; + } + }; + + const TFunction *getInternalFunction(const ImmutableString &functionName, + const TType &returnType, + TIntermSequence *arguments, + const TVector<const TVariable *> ¶meters, + bool knownToNotHaveSideEffects); + TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild); + TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, + TIntermTyped *right, + const char *opNameStr); + + typedef std::set<TypePair, TypePairComparator> EmulationSet; + EmulationSet mEmulateCompoundAdd; + EmulationSet mEmulateCompoundSub; + EmulationSet mEmulateCompoundMul; + EmulationSet mEmulateCompoundDiv; + + // Map from mangled name to function. + TMap<ImmutableString, const TFunction *> mInternalFunctions; + + bool mDeclaringVariables; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_EMULATE_PRECISION_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp new file mode 100644 index 0000000000..73791c1ce1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp @@ -0,0 +1,145 @@ +// +// Copyright (c) 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. +// +// Implementation of the integer pow expressions HLSL bug workaround. +// See header for more info. + +#include "compiler/translator/tree_ops/ExpandIntegerPowExpressions.h" + +#include <cmath> +#include <cstdlib> + +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root, TSymbolTable *symbolTable); + + private: + Traverser(TSymbolTable *symbolTable); + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root, TSymbolTable *symbolTable) +{ + Traverser traverser(symbolTable); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable) +{} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFound) + { + return false; + } + + // Test 0: skip non-pow operators. + if (node->getOp() != EOpPow) + { + return true; + } + + const TIntermSequence *sequence = node->getSequence(); + ASSERT(sequence->size() == 2u); + const TIntermConstantUnion *constantExponent = sequence->at(1)->getAsConstantUnion(); + + // Test 1: check for a single constant. + if (!constantExponent || constantExponent->getNominalSize() != 1) + { + return true; + } + + float exponentValue = constantExponent->getConstantValue()->getFConst(); + + // Test 2: exponentValue is in the problematic range. + if (exponentValue < -5.0f || exponentValue > 9.0f) + { + return true; + } + + // Test 3: exponentValue is integer or pretty close to an integer. + if (std::abs(exponentValue - std::round(exponentValue)) > 0.0001f) + { + return true; + } + + // Test 4: skip -1, 0, and 1 + int exponent = static_cast<int>(std::round(exponentValue)); + int n = std::abs(exponent); + if (n < 2) + { + return true; + } + + // Potential problem case detected, apply workaround. + + TIntermTyped *lhs = sequence->at(0)->getAsTyped(); + ASSERT(lhs); + + TIntermDeclaration *lhsVariableDeclaration = nullptr; + TVariable *lhsVariable = + DeclareTempVariable(mSymbolTable, lhs, EvqTemporary, &lhsVariableDeclaration); + insertStatementInParentBlock(lhsVariableDeclaration); + + // Create a chain of n-1 multiples. + TIntermTyped *current = CreateTempSymbolNode(lhsVariable); + for (int i = 1; i < n; ++i) + { + TIntermBinary *mul = new TIntermBinary(EOpMul, current, CreateTempSymbolNode(lhsVariable)); + mul->setLine(node->getLine()); + current = mul; + } + + // For negative pow, compute the reciprocal of the positive pow. + if (exponent < 0) + { + TConstantUnion *oneVal = new TConstantUnion(); + oneVal->setFConst(1.0f); + TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType()); + TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current); + current = div; + } + + queueReplacement(current, OriginalNode::IS_DROPPED); + mFound = true; + return false; +} + +} // anonymous namespace + +void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable) +{ + Traverser::Apply(root, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h new file mode 100644 index 0000000000..7ee5adab3c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 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. +// +// This mutating tree traversal works around a bug in the HLSL compiler optimizer with "pow" that +// manifests under the following conditions: +// +// - If pow() has a literal exponent value +// - ... and this value is integer or within 10e-6 of an integer +// - ... and it is in {-4, -3, -2, 2, 3, 4, 5, 6, 7, 8} +// +// The workaround is to replace the pow with a series of multiplies. +// See http://anglebug.com/851 + +#ifndef COMPILER_TRANSLATOR_TREEOPS_EXPANDINTEGERPOWEXPRESSIONS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_EXPANDINTEGERPOWEXPRESSIONS_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_EXPANDINTEGERPOWEXPRESSIONS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp new file mode 100644 index 0000000000..5d57e1e716 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp @@ -0,0 +1,115 @@ +// +// Copyright (c) 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. +// +// FoldExpressions.cpp: Fold expressions. This may fold expressions so that the qualifier of the +// folded node differs from the qualifier of the original expression, so it needs to be done after +// parsing and validation of qualifiers is complete. Expressions that are folded: +// 1. Ternary ops with a constant condition. +// 2. Sequence aka comma ops where the left side has no side effects. +// 3. Any expressions containing any of the above. + +#include "compiler/translator/tree_ops/FoldExpressions.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class FoldExpressionsTraverser : public TIntermTraverser +{ + public: + FoldExpressionsTraverser(TDiagnostics *diagnostics) + : TIntermTraverser(true, false, false), mDiagnostics(diagnostics), mDidReplace(false) + {} + + bool didReplace() { return mDidReplace; } + + void nextIteration() { mDidReplace = false; } + + protected: + bool visitTernary(Visit visit, TIntermTernary *node) override + { + TIntermTyped *folded = node->fold(mDiagnostics); + if (folded != node) + { + queueReplacement(folded, OriginalNode::IS_DROPPED); + mDidReplace = true; + return false; + } + return true; + } + + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + TIntermTyped *folded = node->fold(mDiagnostics); + if (folded != node) + { + queueReplacement(folded, OriginalNode::IS_DROPPED); + mDidReplace = true; + return false; + } + return true; + } + + bool visitBinary(Visit visit, TIntermBinary *node) override + { + TIntermTyped *folded = node->fold(mDiagnostics); + if (folded != node) + { + queueReplacement(folded, OriginalNode::IS_DROPPED); + mDidReplace = true; + return false; + } + return true; + } + + bool visitUnary(Visit visit, TIntermUnary *node) override + { + TIntermTyped *folded = node->fold(mDiagnostics); + if (folded != node) + { + queueReplacement(folded, OriginalNode::IS_DROPPED); + mDidReplace = true; + return false; + } + return true; + } + + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override + { + TIntermTyped *folded = node->fold(mDiagnostics); + if (folded != node) + { + queueReplacement(folded, OriginalNode::IS_DROPPED); + mDidReplace = true; + return false; + } + return true; + } + + private: + TDiagnostics *mDiagnostics; + bool mDidReplace; +}; + +} // anonymous namespace + +void FoldExpressions(TIntermBlock *root, TDiagnostics *diagnostics) +{ + FoldExpressionsTraverser traverser(diagnostics); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + traverser.updateTree(); + } while (traverser.didReplace()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h new file mode 100644 index 0000000000..42d026afb8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 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. +// +// FoldExpressions.h: Fold expressions. This may fold expressions so that the qualifier of the +// folded node differs from the qualifier of the original expression, so it needs to be done after +// parsing and validation of qualifiers is complete. Expressions that are folded: 1. Ternary ops +// with a constant condition. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_FOLDEXPRESSIONS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_FOLDEXPRESSIONS_H_ + +namespace sh +{ + +class TIntermBlock; +class TDiagnostics; + +void FoldExpressions(TIntermBlock *root, TDiagnostics *diagnostics); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_FOLDEXPRESSIONS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp new file mode 100644 index 0000000000..21b0bed658 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp @@ -0,0 +1,311 @@ +// +// Copyright (c) 2002-2013 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/InitializeVariables.h" + +#include "angle_gl.h" +#include "common/debug.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/FindMain.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable); + +void AddStructZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable); + +TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode) +{ + TIntermTyped *zero = CreateZeroNode(initializedNode->getType()); + return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero); +} + +void AddZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + if (initializedNode->isArray()) + { + AddArrayZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported, + initSequenceOut, symbolTable); + } + else if (initializedNode->getType().isStructureContainingArrays() || + initializedNode->getType().isNamelessStruct()) + { + AddStructZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported, + initSequenceOut, symbolTable); + } + else + { + initSequenceOut->push_back(CreateZeroInitAssignment(initializedNode)); + } +} + +void AddStructZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + ASSERT(initializedNode->getBasicType() == EbtStruct); + const TStructure *structType = initializedNode->getType().getStruct(); + for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i) + { + TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct, + initializedNode->deepCopy(), CreateIndexNode(i)); + // Structs can't be defined inside structs, so the type of a struct field can't be a + // nameless struct. + ASSERT(!element->getType().isNamelessStruct()); + AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported, + initSequenceOut, symbolTable); + } +} + +void AddArrayZeroInitStatementList(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i) + { + TIntermBinary *element = + new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i)); + AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported, + initSequenceOut, symbolTable); + } +} + +void AddArrayZeroInitForLoop(const TIntermTyped *initializedNode, + bool highPrecisionSupported, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + ASSERT(initializedNode->isArray()); + const TType *mediumpIndexType = StaticType::Get<EbtInt, EbpMedium, EvqTemporary, 1, 1>(); + const TType *highpIndexType = StaticType::Get<EbtInt, EbpHigh, EvqTemporary, 1, 1>(); + TVariable *indexVariable = + CreateTempVariable(symbolTable, highPrecisionSupported ? highpIndexType : mediumpIndexType); + + TIntermSymbol *indexSymbolNode = CreateTempSymbolNode(indexVariable); + TIntermDeclaration *indexInit = + CreateTempInitDeclarationNode(indexVariable, CreateZeroNode(indexVariable->getType())); + TIntermConstantUnion *arraySizeNode = CreateIndexNode(initializedNode->getOutermostArraySize()); + TIntermBinary *indexSmallerThanSize = + new TIntermBinary(EOpLessThan, indexSymbolNode->deepCopy(), arraySizeNode); + TIntermUnary *indexIncrement = + new TIntermUnary(EOpPreIncrement, indexSymbolNode->deepCopy(), nullptr); + + TIntermBlock *forLoopBody = new TIntermBlock(); + TIntermSequence *forLoopBodySeq = forLoopBody->getSequence(); + + TIntermBinary *element = new TIntermBinary(EOpIndexIndirect, initializedNode->deepCopy(), + indexSymbolNode->deepCopy()); + AddZeroInitSequence(element, true, highPrecisionSupported, forLoopBodySeq, symbolTable); + + TIntermLoop *forLoop = + new TIntermLoop(ELoopFor, indexInit, indexSmallerThanSize, indexIncrement, forLoopBody); + initSequenceOut->push_back(forLoop); +} + +void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TIntermSequence *initSequenceOut, + TSymbolTable *symbolTable) +{ + // The array elements are assigned one by one to keep the AST compatible with ESSL 1.00 which + // doesn't have array assignment. We'll do this either with a for loop or just a list of + // statements assigning to each array index. Note that it is important to have the array init in + // the right order to workaround http://crbug.com/709317 + bool isSmallArray = initializedNode->getOutermostArraySize() <= 1u || + (initializedNode->getBasicType() != EbtStruct && + !initializedNode->getType().isArrayOfArrays() && + initializedNode->getOutermostArraySize() <= 3u); + if (initializedNode->getQualifier() == EvqFragData || + initializedNode->getQualifier() == EvqFragmentOut || isSmallArray || + !canUseLoopsToInitialize) + { + // Fragment outputs should not be indexed by non-constant indices. + // Also it doesn't make sense to use loops to initialize very small arrays. + AddArrayZeroInitStatementList(initializedNode, canUseLoopsToInitialize, + highPrecisionSupported, initSequenceOut, symbolTable); + } + else + { + AddArrayZeroInitForLoop(initializedNode, highPrecisionSupported, initSequenceOut, + symbolTable); + } +} + +void InsertInitCode(TIntermSequence *mainBody, + const InitVariableList &variables, + TSymbolTable *symbolTable, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + bool canUseLoopsToInitialize, + bool highPrecisionSupported) +{ + for (const auto &var : variables) + { + // Note that tempVariableName will reference a short-lived char array here - that's fine + // since we're only using it to find symbols. + ImmutableString tempVariableName(var.name.c_str(), var.name.length()); + + TIntermTyped *initializedSymbol = nullptr; + if (var.isBuiltIn()) + { + initializedSymbol = + ReferenceBuiltInVariable(tempVariableName, *symbolTable, shaderVersion); + if (initializedSymbol->getQualifier() == EvqFragData && + !IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers)) + { + // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be + // written to. + // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up + // with a good way to do it. Right now "gl_FragData" in symbol table is initialized + // to have the array size of MaxDrawBuffers, and the initialization happens before + // the shader sets the extensions it is using. + initializedSymbol = + new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0)); + } + } + else + { + initializedSymbol = ReferenceGlobalVariable(tempVariableName, *symbolTable); + } + ASSERT(initializedSymbol != nullptr); + + TIntermSequence *initCode = CreateInitCode(initializedSymbol, canUseLoopsToInitialize, + highPrecisionSupported, symbolTable); + mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end()); + } +} + +class InitializeLocalsTraverser : public TIntermTraverser +{ + public: + InitializeLocalsTraverser(int shaderVersion, + TSymbolTable *symbolTable, + bool canUseLoopsToInitialize, + bool highPrecisionSupported) + : TIntermTraverser(true, false, false, symbolTable), + mShaderVersion(shaderVersion), + mCanUseLoopsToInitialize(canUseLoopsToInitialize), + mHighPrecisionSupported(highPrecisionSupported) + {} + + protected: + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override + { + for (TIntermNode *declarator : *node->getSequence()) + { + if (!mInGlobalScope && !declarator->getAsBinaryNode()) + { + TIntermSymbol *symbol = declarator->getAsSymbolNode(); + ASSERT(symbol); + if (symbol->variable().symbolType() == SymbolType::Empty) + { + continue; + } + + // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not + // support array constructors or assigning arrays. + bool arrayConstructorUnavailable = + (symbol->isArray() || symbol->getType().isStructureContainingArrays()) && + mShaderVersion == 100; + // Nameless struct constructors can't be referred to, so they also need to be + // initialized one element at a time. + // TODO(oetuaho): Check if it makes sense to initialize using a loop, even if we + // could use an initializer. It could at least reduce code size for very large + // arrays, but could hurt runtime performance. + if (arrayConstructorUnavailable || symbol->getType().isNamelessStruct()) + { + // SimplifyLoopConditions should have been run so the parent node of this node + // should not be a loop. + ASSERT(getParentNode()->getAsLoopNode() == nullptr); + // SeparateDeclarations should have already been run, so we don't need to worry + // about further declarators in this declaration depending on the effects of + // this declarator. + ASSERT(node->getSequence()->size() == 1); + insertStatementsInParentBlock( + TIntermSequence(), *CreateInitCode(symbol, mCanUseLoopsToInitialize, + mHighPrecisionSupported, mSymbolTable)); + } + else + { + TIntermBinary *init = + new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType())); + queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD); + } + } + } + return false; + } + + private: + int mShaderVersion; + bool mCanUseLoopsToInitialize; + bool mHighPrecisionSupported; +}; + +} // namespace + +TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TSymbolTable *symbolTable) +{ + TIntermSequence *initCode = new TIntermSequence(); + AddZeroInitSequence(initializedSymbol, canUseLoopsToInitialize, highPrecisionSupported, + initCode, symbolTable); + return initCode; +} + +void InitializeUninitializedLocals(TIntermBlock *root, + int shaderVersion, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TSymbolTable *symbolTable) +{ + InitializeLocalsTraverser traverser(shaderVersion, symbolTable, canUseLoopsToInitialize, + highPrecisionSupported); + root->traverse(&traverser); + traverser.updateTree(); +} + +void InitializeVariables(TIntermBlock *root, + const InitVariableList &vars, + TSymbolTable *symbolTable, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + bool canUseLoopsToInitialize, + bool highPrecisionSupported) +{ + TIntermBlock *body = FindMainBody(root); + InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior, + canUseLoopsToInitialize, highPrecisionSupported); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h new file mode 100644 index 0000000000..06695f93c9 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2013 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_INITIALIZEVARIABLES_H_ +#define COMPILER_TRANSLATOR_TREEOPS_INITIALIZEVARIABLES_H_ + +#include <GLSLANG/ShaderLang.h> + +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/IntermNode.h" + +namespace sh +{ +class TSymbolTable; + +typedef std::vector<sh::ShaderVariable> InitVariableList; + +// For all of the functions below: If canUseLoopsToInitialize is set, for loops are used instead of +// a large number of initializers where it can make sense, such as for initializing large arrays. + +// Return a sequence of assignment operations to initialize "initializedSymbol". initializedSymbol +// may be an array, struct or any combination of these, as long as it contains only basic types. +TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TSymbolTable *symbolTable); + +// Initialize all uninitialized local variables, so that undefined behavior is avoided. +void InitializeUninitializedLocals(TIntermBlock *root, + int shaderVersion, + bool canUseLoopsToInitialize, + bool highPrecisionSupported, + TSymbolTable *symbolTable); + +// This function can initialize all the types that CreateInitCode is able to initialize. All +// variables must be globals which can be found in the symbol table. For now it is used for the +// following two scenarios: +// 1. Initializing gl_Position; +// 2. Initializing output variables referred to in the shader source. +// Note: The type of each lvalue in an initializer is retrieved from the symbol table. gl_FragData +// requires special handling because the number of indices which can be initialized is determined by +// enabled extensions. +void InitializeVariables(TIntermBlock *root, + const InitVariableList &vars, + TSymbolTable *symbolTable, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + bool canUseLoopsToInitialize, + bool highPrecisionSupported); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_INITIALIZEVARIABLES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp new file mode 100644 index 0000000000..9c544491ec --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.cpp @@ -0,0 +1,101 @@ +// +// 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. +// +// NameEmbeddedUniformStructs: Gives nameless uniform struct internal names. +// + +#include "compiler/translator/tree_ops/NameEmbeddedUniformStructs.h" + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ +namespace +{ +// This traverser translates embedded uniform structs into a specifier and declaration. +// This makes the declarations easier to move into uniform blocks. +class Traverser : public TIntermTraverser +{ + public: + explicit Traverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable) + {} + + bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override + { + ASSERT(visit == PreVisit); + + if (!mInGlobalScope) + { + return false; + } + + const TIntermSequence &sequence = *(decl->getSequence()); + ASSERT(sequence.size() == 1); + TIntermTyped *declarator = sequence.front()->getAsTyped(); + const TType &type = declarator->getType(); + + if (type.isStructSpecifier() && type.getQualifier() == EvqUniform) + { + const TStructure *structure = type.getStruct(); + + if (structure->symbolType() == SymbolType::Empty) + { + doReplacement(decl, declarator, structure); + } + } + + return false; + } + + private: + void doReplacement(TIntermDeclaration *decl, + TIntermTyped *declarator, + const TStructure *oldStructure) + { + // struct <structName> { ... }; + TStructure *structure = new TStructure(mSymbolTable, kEmptyImmutableString, + &oldStructure->fields(), SymbolType::AngleInternal); + TType *namedType = new TType(structure, true); + namedType->setQualifier(EvqGlobal); + + TVariable *structVariable = + new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty); + TIntermSymbol *structDeclarator = new TIntermSymbol(structVariable); + TIntermDeclaration *structDeclaration = new TIntermDeclaration; + structDeclaration->appendDeclarator(structDeclarator); + + TIntermSequence *newSequence = new TIntermSequence; + newSequence->push_back(structDeclaration); + + // uniform <structName> <structUniformName>; + TIntermSymbol *asSymbol = declarator->getAsSymbolNode(); + if (asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty) + { + TIntermDeclaration *namedDecl = new TIntermDeclaration; + TType *uniformType = new TType(structure, false); + uniformType->setQualifier(EvqUniform); + + TVariable *newVar = new TVariable(mSymbolTable, asSymbol->getName(), uniformType, + asSymbol->variable().symbolType()); + TIntermSymbol *newSymbol = new TIntermSymbol(newVar); + namedDecl->appendDeclarator(newSymbol); + + newSequence->push_back(namedDecl); + } + + mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence); + } +}; +} // anonymous namespace + +void NameEmbeddedStructUniforms(TIntermBlock *root, TSymbolTable *symbolTable) +{ + Traverser nameStructs(symbolTable); + root->traverse(&nameStructs); + nameStructs.updateTree(); +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h new file mode 100644 index 0000000000..0ada189501 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/NameEmbeddedUniformStructs.h @@ -0,0 +1,25 @@ +// +// 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. +// +// NameEmbeddedUniformStructs: Gives nameless uniform struct internal names. +// +// For example: +// uniform struct { int a; } uni; +// becomes: +// struct s1 { int a; }; +// uniform s1 uni; +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_NAMEEMBEDDEDUNIFORMSTRUCTS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_NAMEEMBEDDEDUNIFORMSTRUCTS_H_ + +namespace sh +{ +class TIntermBlock; +class TSymbolTable; +void NameEmbeddedStructUniforms(TIntermBlock *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_NAMEEMBEDDEDUNIFORMSTRUCTS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp new file mode 100644 index 0000000000..7dd756ca2d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp @@ -0,0 +1,127 @@ +// +// Copyright (c) 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. +// +// PruneEmptyCases.cpp: The PruneEmptyCases function prunes cases that are followed by nothing from +// the AST. + +#include "compiler/translator/tree_ops/PruneEmptyCases.h" + +#include "compiler/translator/Symbol.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +bool AreEmptyBlocks(TIntermSequence *statements); + +bool IsEmptyBlock(TIntermNode *node) +{ + TIntermBlock *asBlock = node->getAsBlock(); + if (asBlock) + { + return AreEmptyBlocks(asBlock->getSequence()); + } + // Empty declarations should have already been pruned, otherwise they would need to be handled + // here. Note that declarations for struct types do contain a nameless child node. + ASSERT(node->getAsDeclarationNode() == nullptr || + !node->getAsDeclarationNode()->getSequence()->empty()); + // Pure literal statements should also already be pruned. + ASSERT(node->getAsConstantUnion() == nullptr); + return false; +} + +// Return true if all statements in "statements" consist only of empty blocks and no-op statements. +// Returns true also if there are no statements. +bool AreEmptyBlocks(TIntermSequence *statements) +{ + for (size_t i = 0u; i < statements->size(); ++i) + { + if (!IsEmptyBlock(statements->at(i))) + { + return false; + } + } + return true; +} + +class PruneEmptyCasesTraverser : private TIntermTraverser +{ + public: + static void apply(TIntermBlock *root); + + private: + PruneEmptyCasesTraverser(); + bool visitSwitch(Visit visit, TIntermSwitch *node) override; +}; + +void PruneEmptyCasesTraverser::apply(TIntermBlock *root) +{ + PruneEmptyCasesTraverser prune; + root->traverse(&prune); + prune.updateTree(); +} + +PruneEmptyCasesTraverser::PruneEmptyCasesTraverser() : TIntermTraverser(true, false, false) {} + +bool PruneEmptyCasesTraverser::visitSwitch(Visit visit, TIntermSwitch *node) +{ + // This may mutate the statementList, but that's okay, since traversal has not yet reached + // there. + TIntermBlock *statementList = node->getStatementList(); + TIntermSequence *statements = statementList->getSequence(); + + // Iterate block children in reverse order. Cases that are only followed by other cases or empty + // blocks are marked for pruning. + size_t i = statements->size(); + size_t lastNoOpInStatementList = i; + while (i > 0) + { + --i; + TIntermNode *statement = statements->at(i); + if (statement->getAsCaseNode() || IsEmptyBlock(statement)) + { + lastNoOpInStatementList = i; + } + else + { + break; + } + } + if (lastNoOpInStatementList == 0) + { + // Remove the entire switch statement, extracting the init expression if needed. + TIntermTyped *init = node->getInit(); + if (init->hasSideEffects()) + { + queueReplacement(init, OriginalNode::IS_DROPPED); + } + else + { + TIntermSequence emptyReplacement; + ASSERT(getParentNode()->getAsBlock()); + mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), + node, emptyReplacement)); + } + return false; + } + if (lastNoOpInStatementList < statements->size()) + { + statements->erase(statements->begin() + lastNoOpInStatementList, statements->end()); + } + + return true; +} + +} // namespace + +void PruneEmptyCases(TIntermBlock *root) +{ + PruneEmptyCasesTraverser::apply(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h new file mode 100644 index 0000000000..0b88ac181c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h @@ -0,0 +1,19 @@ +// +// Copyright (c) 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. +// +// PruneEmptyCases.h: The PruneEmptyCases function prunes cases that are followed by nothing from +// the AST. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_PRUNEEMPTYCASES_H_ +#define COMPILER_TRANSLATOR_TREEOPS_PRUNEEMPTYCASES_H_ + +namespace sh +{ +class TIntermBlock; + +void PruneEmptyCases(TIntermBlock *root); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_PRUNEEMPTYCASES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp new file mode 100644 index 0000000000..620c3f481b --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp @@ -0,0 +1,166 @@ +// +// Copyright (c) 2002-2015 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. +// +// PruneNoOps.cpp: The PruneNoOps function prunes: +// 1. Empty declarations "int;". Empty declarators will be pruned as well, so for example: +// int , a; +// is turned into +// int a; +// 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision for float, +// so float literal statements would end up with no precision which is invalid ESSL. + +#include "compiler/translator/tree_ops/PruneNoOps.h" + +#include "compiler/translator/Symbol.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +bool IsNoOp(TIntermNode *node) +{ + if (node->getAsConstantUnion() != nullptr) + { + return true; + } + bool isEmptyDeclaration = node->getAsDeclarationNode() != nullptr && + node->getAsDeclarationNode()->getSequence()->empty(); + if (isEmptyDeclaration) + { + return true; + } + return false; +} + +class PruneNoOpsTraverser : private TIntermTraverser +{ + public: + static void apply(TIntermBlock *root, TSymbolTable *symbolTable); + + private: + PruneNoOpsTraverser(TSymbolTable *symbolTable); + bool visitDeclaration(Visit, TIntermDeclaration *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + bool visitLoop(Visit visit, TIntermLoop *loop) override; +}; + +void PruneNoOpsTraverser::apply(TIntermBlock *root, TSymbolTable *symbolTable) +{ + PruneNoOpsTraverser prune(symbolTable); + root->traverse(&prune); + prune.updateTree(); +} + +PruneNoOpsTraverser::PruneNoOpsTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable) +{} + +bool PruneNoOpsTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + TIntermSequence *sequence = node->getSequence(); + if (sequence->size() >= 1) + { + TIntermSymbol *declaratorSymbol = sequence->front()->getAsSymbolNode(); + // Prune declarations without a variable name, unless it's an interface block declaration. + if (declaratorSymbol != nullptr && + declaratorSymbol->variable().symbolType() == SymbolType::Empty && + !declaratorSymbol->isInterfaceBlock()) + { + if (sequence->size() > 1) + { + // Generate a replacement that will remove the empty declarator in the beginning of + // a declarator list. Example of a declaration that will be changed: + // float, a; + // will be changed to + // float a; + // This applies also to struct declarations. + TIntermSequence emptyReplacement; + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(node, declaratorSymbol, emptyReplacement)); + } + else if (declaratorSymbol->getBasicType() != EbtStruct) + { + // If there are entirely empty non-struct declarations, they result in + // TIntermDeclaration nodes without any children in the parsing stage. These are + // handled in visitBlock and visitLoop. + UNREACHABLE(); + } + else if (declaratorSymbol->getQualifier() != EvqGlobal && + declaratorSymbol->getQualifier() != EvqTemporary) + { + // Single struct declarations may just declare the struct type and no variables, so + // they should not be pruned. Here we handle an empty struct declaration with a + // qualifier, for example like this: + // const struct a { int i; }; + // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so we + // convert the declaration to a regular struct declaration. This is okay, since ESSL + // 1.00 spec section 4.1.8 says about structs that "The optional qualifiers only + // apply to any declarators, and are not part of the type being defined for name." + + // Create a new variable to use in the declarator so that the variable and node + // types are kept consistent. + TType *type = new TType(declaratorSymbol->getType()); + if (mInGlobalScope) + { + type->setQualifier(EvqGlobal); + } + else + { + type->setQualifier(EvqTemporary); + } + TVariable *variable = + new TVariable(mSymbolTable, kEmptyImmutableString, type, SymbolType::Empty); + queueReplacementWithParent(node, declaratorSymbol, new TIntermSymbol(variable), + OriginalNode::IS_DROPPED); + } + } + } + return false; +} + +bool PruneNoOpsTraverser::visitBlock(Visit visit, TIntermBlock *node) +{ + TIntermSequence *statements = node->getSequence(); + + for (TIntermNode *statement : *statements) + { + if (IsNoOp(statement)) + { + TIntermSequence emptyReplacement; + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(node, statement, emptyReplacement)); + } + } + + return true; +} + +bool PruneNoOpsTraverser::visitLoop(Visit visit, TIntermLoop *loop) +{ + TIntermTyped *expr = loop->getExpression(); + if (expr != nullptr && IsNoOp(expr)) + { + loop->setExpression(nullptr); + } + TIntermNode *init = loop->getInit(); + if (init != nullptr && IsNoOp(init)) + { + loop->setInit(nullptr); + } + + return true; +} + +} // namespace + +void PruneNoOps(TIntermBlock *root, TSymbolTable *symbolTable) +{ + PruneNoOpsTraverser::apply(root, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h new file mode 100644 index 0000000000..83a6c66589 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2002-2015 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. +// +// PruneNoOps.h: The PruneNoOps function prunes: +// 1. Empty declarations "int;". Empty declarators will be pruned as well, so for example: +// int , a; +// is turned into +// int a; +// 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision for float, +// so float literal statements would end up with no precision which is invalid ESSL. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_PRUNENOOPS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_PRUNENOOPS_H_ + +namespace sh +{ +class TIntermBlock; +class TSymbolTable; + +void PruneNoOps(TIntermBlock *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_PRUNENOOPS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp new file mode 100644 index 0000000000..9e7b0a0330 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp @@ -0,0 +1,167 @@ +// +// Copyright (c) 2002-2015 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. +// +// During parsing, all constant expressions are folded to constant union nodes. The expressions that +// have been folded may have had precision qualifiers, which should affect the precision of the +// consuming operation. If the folded constant union nodes are written to output as such they won't +// have any precision qualifiers, and their effect on the precision of the consuming operation is +// lost. +// +// RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants +// and hoists the constants outside the containing expression as precision qualified named variables +// in case that is required for correct precision propagation. +// + +#include "compiler/translator/tree_ops/RecordConstantPrecision.h" + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class RecordConstantPrecisionTraverser : public TIntermTraverser +{ + public: + RecordConstantPrecisionTraverser(TSymbolTable *symbolTable); + + void visitConstantUnion(TIntermConstantUnion *node) override; + + void nextIteration(); + + bool foundHigherPrecisionConstant() const { return mFoundHigherPrecisionConstant; } + + protected: + bool operandAffectsParentOperationPrecision(TIntermTyped *operand); + + bool mFoundHigherPrecisionConstant; +}; + +RecordConstantPrecisionTraverser::RecordConstantPrecisionTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mFoundHigherPrecisionConstant(false) +{} + +bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TIntermTyped *operand) +{ + if (getParentNode()->getAsCaseNode() || getParentNode()->getAsBlock()) + { + return false; + } + + const TIntermBinary *parentAsBinary = getParentNode()->getAsBinaryNode(); + if (parentAsBinary != nullptr) + { + // If the constant is assigned or is used to initialize a variable, or if it's an index, + // its precision has no effect. + switch (parentAsBinary->getOp()) + { + case EOpInitialize: + case EOpAssign: + case EOpIndexDirect: + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + case EOpIndexIndirect: + return false; + default: + break; + } + + TIntermTyped *otherOperand = parentAsBinary->getRight(); + if (otherOperand == operand) + { + otherOperand = parentAsBinary->getLeft(); + } + // If the precision of the other child is at least as high as the precision of the constant, + // the precision of the constant has no effect. + if (otherOperand->getAsConstantUnion() == nullptr && + otherOperand->getPrecision() >= operand->getPrecision()) + { + return false; + } + } + + TIntermAggregate *parentAsAggregate = getParentNode()->getAsAggregate(); + if (parentAsAggregate != nullptr) + { + if (!parentAsAggregate->gotPrecisionFromChildren()) + { + // This can be either: + // * a call to an user-defined function + // * a call to a texture function + // * some other kind of aggregate + // In any of these cases the constant precision has no effect. + return false; + } + if (parentAsAggregate->isConstructor() && parentAsAggregate->getBasicType() == EbtBool) + { + return false; + } + // If the precision of operands does affect the result, but the precision of any of the + // other children has a precision that's at least as high as the precision of the constant, + // the precision of the constant has no effect. + TIntermSequence *parameters = parentAsAggregate->getSequence(); + for (TIntermNode *parameter : *parameters) + { + const TIntermTyped *typedParameter = parameter->getAsTyped(); + if (parameter != operand && typedParameter != nullptr && + parameter->getAsConstantUnion() == nullptr && + typedParameter->getPrecision() >= operand->getPrecision()) + { + return false; + } + } + } + return true; +} + +void RecordConstantPrecisionTraverser::visitConstantUnion(TIntermConstantUnion *node) +{ + if (mFoundHigherPrecisionConstant) + return; + + // If the constant has lowp or undefined precision, it can't increase the precision of consuming + // operations. + if (node->getPrecision() < EbpMedium) + return; + + // It's possible the node has no effect on the precision of the consuming expression, depending + // on the consuming expression, and the precision of the other parameters of the expression. + if (!operandAffectsParentOperationPrecision(node)) + return; + + // Make the constant a precision-qualified named variable to make sure it affects the precision + // of the consuming expression. + TIntermDeclaration *variableDeclaration = nullptr; + TVariable *variable = DeclareTempVariable(mSymbolTable, node, EvqConst, &variableDeclaration); + insertStatementInParentBlock(variableDeclaration); + queueReplacement(CreateTempSymbolNode(variable), OriginalNode::IS_DROPPED); + mFoundHigherPrecisionConstant = true; +} + +void RecordConstantPrecisionTraverser::nextIteration() +{ + mFoundHigherPrecisionConstant = false; +} + +} // namespace + +void RecordConstantPrecision(TIntermNode *root, TSymbolTable *symbolTable) +{ + RecordConstantPrecisionTraverser traverser(symbolTable); + // Iterate as necessary, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundHigherPrecisionConstant()) + traverser.updateTree(); + } while (traverser.foundHigherPrecisionConstant()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h new file mode 100644 index 0000000000..5b15db5e48 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2002-2015 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. +// +// During parsing, all constant expressions are folded to constant union nodes. The expressions that +// have been folded may have had precision qualifiers, which should affect the precision of the +// consuming operation. If the folded constant union nodes are written to output as such they won't +// have any precision qualifiers, and their effect on the precision of the consuming operation is +// lost. +// +// RecordConstantPrecision is an AST traverser that inspects the precision qualifiers of constants +// and hoists the constants outside the containing expression as precision qualified named variables +// in case that is required for correct precision propagation. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_ +#define COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_ + +namespace sh +{ +class TIntermNode; +class TSymbolTable; + +void RecordConstantPrecision(TIntermNode *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_RECORDCONSTANTPRECISION_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp new file mode 100644 index 0000000000..dd700246db --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp @@ -0,0 +1,87 @@ +// +// Copyright (c) 2002-2014 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/RegenerateStructNames.h" + +#include "common/debug.h" +#include "compiler/translator/ImmutableStringBuilder.h" + +namespace sh +{ + +namespace +{ +constexpr const ImmutableString kPrefix("_webgl_struct_"); +} // anonymous namespace + +void RegenerateStructNames::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 RegenerateStructNames::visitBlock(Visit, TIntermBlock *block) +{ + ++mScopeDepth; + TIntermSequence &sequence = *(block->getSequence()); + for (TIntermNode *node : sequence) + { + node->traverse(this); + } + --mScopeDepth; + return false; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h new file mode 100644 index 0000000000..4c53cd50e8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2002-2014 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_REGENERATESTRUCTNAMES_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REGENERATESTRUCTNAMES_H_ + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +#include <set> + +namespace sh +{ + +class RegenerateStructNames : public TIntermTraverser +{ + public: + RegenerateStructNames(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's declared globally, push its ID in this set. + std::set<int> mDeclaredGlobalStructs; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REGENERATESTRUCTNAMES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp new file mode 100644 index 0000000000..473159f89c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp @@ -0,0 +1,83 @@ +// +// Copyright (c) 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. +// +// RemoveArrayLengthMethod.cpp: +// Fold array length expressions, including cases where the "this" node has side effects. +// Example: +// int i = (a = b).length(); +// int j = (func()).length(); +// becomes: +// (a = b); +// int i = <constant array length>; +// func(); +// int j = <constant array length>; +// +// Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps +// have been done to expressions containing calls of the array length method. +// +// Does nothing to length method calls done on runtime-sized arrays. + +#include "compiler/translator/tree_ops/RemoveArrayLengthMethod.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class RemoveArrayLengthTraverser : public TIntermTraverser +{ + public: + RemoveArrayLengthTraverser() : TIntermTraverser(true, false, false), mFoundArrayLength(false) {} + + bool visitUnary(Visit visit, TIntermUnary *node) override; + + void nextIteration() { mFoundArrayLength = false; } + + bool foundArrayLength() const { return mFoundArrayLength; } + + private: + bool mFoundArrayLength; +}; + +bool RemoveArrayLengthTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + // The only case where we leave array length() in place is for runtime-sized arrays. + if (node->getOp() == EOpArrayLength && !node->getOperand()->getType().isUnsizedArray()) + { + mFoundArrayLength = true; + if (!node->getOperand()->hasSideEffects()) + { + queueReplacement(node->fold(nullptr), OriginalNode::IS_DROPPED); + return false; + } + insertStatementInParentBlock(node->getOperand()->deepCopy()); + TConstantUnion *constArray = new TConstantUnion[1]; + constArray->setIConst(node->getOperand()->getOutermostArraySize()); + queueReplacement(new TIntermConstantUnion(constArray, node->getType()), + OriginalNode::IS_DROPPED); + return false; + } + return true; +} + +} // anonymous namespace + +void RemoveArrayLengthMethod(TIntermBlock *root) +{ + RemoveArrayLengthTraverser traverser; + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundArrayLength()) + traverser.updateTree(); + } while (traverser.foundArrayLength()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h new file mode 100644 index 0000000000..6376828749 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 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. +// +// RemoveArrayLengthMethod.h: +// Fold array length expressions, including cases where the "this" node has side effects. +// Example: +// int i = (a = b).length(); +// int j = (func()).length(); +// becomes: +// (a = b); +// int i = <constant array length>; +// func(); +// int j = <constant array length>; +// +// Must be run after SplitSequenceOperator, SimplifyLoopConditions and SeparateDeclarations steps +// have been done to expressions containing calls of the array length method. +// +// Does nothing to length method calls done on runtime-sized arrays. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEARRAYLENGTHMETHOD_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REMOVEARRAYLENGTHMETHOD_H_ + +namespace sh +{ + +class TIntermBlock; + +void RemoveArrayLengthMethod(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEARRAYLENGTHMETHOD_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp new file mode 100644 index 0000000000..879d29eba0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp @@ -0,0 +1,543 @@ +// +// Copyright (c) 2002-2015 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. +// +// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of non-SSBO vectors and +// matrices, replacing them with calls to functions that choose which component to return or write. +// We don't need to consider dynamic indexing in SSBO since it can be directly as part of the offset +// of RWByteAddressBuffer. +// + +#include "compiler/translator/tree_ops/RemoveDynamicIndexing.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +const TType *kIndexType = StaticType::Get<EbtInt, EbpHigh, EvqIn, 1, 1>(); + +constexpr const ImmutableString kBaseName("base"); +constexpr const ImmutableString kIndexName("index"); +constexpr const ImmutableString kValueName("value"); + +std::string GetIndexFunctionName(const TType &type, bool write) +{ + TInfoSinkBase nameSink; + nameSink << "dyn_index_"; + if (write) + { + nameSink << "write_"; + } + if (type.isMatrix()) + { + nameSink << "mat" << type.getCols() << "x" << type.getRows(); + } + else + { + switch (type.getBasicType()) + { + case EbtInt: + nameSink << "ivec"; + break; + case EbtBool: + nameSink << "bvec"; + break; + case EbtUInt: + nameSink << "uvec"; + break; + case EbtFloat: + nameSink << "vec"; + break; + default: + UNREACHABLE(); + } + nameSink << type.getNominalSize(); + } + return nameSink.str(); +} + +TIntermConstantUnion *CreateIntConstantNode(int i) +{ + TConstantUnion *constant = new TConstantUnion(); + constant->setIConst(i); + return new TIntermConstantUnion(constant, TType(EbtInt, EbpHigh)); +} + +TIntermTyped *EnsureSignedInt(TIntermTyped *node) +{ + if (node->getBasicType() == EbtInt) + return node; + + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(node); + return TIntermAggregate::CreateConstructor(TType(EbtInt), arguments); +} + +TType *GetFieldType(const TType &indexedType) +{ + if (indexedType.isMatrix()) + { + TType *fieldType = new TType(indexedType.getBasicType(), indexedType.getPrecision()); + fieldType->setPrimarySize(static_cast<unsigned char>(indexedType.getRows())); + return fieldType; + } + else + { + return new TType(indexedType.getBasicType(), indexedType.getPrecision()); + } +} + +const TType *GetBaseType(const TType &type, bool write) +{ + TType *baseType = new TType(type); + // Conservatively use highp here, even if the indexed type is not highp. That way the code can't + // end up using mediump version of an indexing function for a highp value, if both mediump and + // highp values are being indexed in the shader. For HLSL precision doesn't matter, but in + // principle this code could be used with multiple backends. + baseType->setPrecision(EbpHigh); + baseType->setQualifier(EvqInOut); + if (!write) + baseType->setQualifier(EvqIn); + return baseType; +} + +// Generate a read or write function for one field in a vector/matrix. +// Out-of-range indices are clamped. This is consistent with how ANGLE handles out-of-range +// indices in other places. +// Note that indices can be either int or uint. We create only int versions of the functions, +// and convert uint indices to int at the call site. +// read function example: +// float dyn_index_vec2(in vec2 base, in int index) +// { +// switch(index) +// { +// case (0): +// return base[0]; +// case (1): +// return base[1]; +// default: +// break; +// } +// if (index < 0) +// return base[0]; +// return base[1]; +// } +// write function example: +// void dyn_index_write_vec2(inout vec2 base, in int index, in float value) +// { +// switch(index) +// { +// case (0): +// base[0] = value; +// return; +// case (1): +// base[1] = value; +// return; +// default: +// break; +// } +// if (index < 0) +// { +// base[0] = value; +// return; +// } +// base[1] = value; +// } +// Note that else is not used in above functions to avoid the RewriteElseBlocks transformation. +TIntermFunctionDefinition *GetIndexFunctionDefinition(const TType &type, + bool write, + const TFunction &func, + TSymbolTable *symbolTable) +{ + ASSERT(!type.isArray()); + + int numCases = 0; + if (type.isMatrix()) + { + numCases = type.getCols(); + } + else + { + numCases = type.getNominalSize(); + } + + std::string functionName = GetIndexFunctionName(type, write); + TIntermFunctionPrototype *prototypeNode = CreateInternalFunctionPrototypeNode(func); + + TIntermSymbol *baseParam = new TIntermSymbol(func.getParam(0)); + TIntermSymbol *indexParam = new TIntermSymbol(func.getParam(1)); + TIntermSymbol *valueParam = nullptr; + if (write) + { + valueParam = new TIntermSymbol(func.getParam(2)); + } + + TIntermBlock *statementList = new TIntermBlock(); + for (int i = 0; i < numCases; ++i) + { + TIntermCase *caseNode = new TIntermCase(CreateIntConstantNode(i)); + statementList->getSequence()->push_back(caseNode); + + TIntermBinary *indexNode = + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(i)); + if (write) + { + TIntermBinary *assignNode = + new TIntermBinary(EOpAssign, indexNode, valueParam->deepCopy()); + statementList->getSequence()->push_back(assignNode); + TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr); + statementList->getSequence()->push_back(returnNode); + } + else + { + TIntermBranch *returnNode = new TIntermBranch(EOpReturn, indexNode); + statementList->getSequence()->push_back(returnNode); + } + } + + // Default case + TIntermCase *defaultNode = new TIntermCase(nullptr); + statementList->getSequence()->push_back(defaultNode); + TIntermBranch *breakNode = new TIntermBranch(EOpBreak, nullptr); + statementList->getSequence()->push_back(breakNode); + + TIntermSwitch *switchNode = new TIntermSwitch(indexParam->deepCopy(), statementList); + + TIntermBlock *bodyNode = new TIntermBlock(); + bodyNode->getSequence()->push_back(switchNode); + + TIntermBinary *cond = + new TIntermBinary(EOpLessThan, indexParam->deepCopy(), CreateIntConstantNode(0)); + + // Two blocks: one accesses (either reads or writes) the first element and returns, + // the other accesses the last element. + TIntermBlock *useFirstBlock = new TIntermBlock(); + TIntermBlock *useLastBlock = new TIntermBlock(); + TIntermBinary *indexFirstNode = + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(0)); + TIntermBinary *indexLastNode = + new TIntermBinary(EOpIndexDirect, baseParam->deepCopy(), CreateIndexNode(numCases - 1)); + if (write) + { + TIntermBinary *assignFirstNode = + new TIntermBinary(EOpAssign, indexFirstNode, valueParam->deepCopy()); + useFirstBlock->getSequence()->push_back(assignFirstNode); + TIntermBranch *returnNode = new TIntermBranch(EOpReturn, nullptr); + useFirstBlock->getSequence()->push_back(returnNode); + + TIntermBinary *assignLastNode = + new TIntermBinary(EOpAssign, indexLastNode, valueParam->deepCopy()); + useLastBlock->getSequence()->push_back(assignLastNode); + } + else + { + TIntermBranch *returnFirstNode = new TIntermBranch(EOpReturn, indexFirstNode); + useFirstBlock->getSequence()->push_back(returnFirstNode); + + TIntermBranch *returnLastNode = new TIntermBranch(EOpReturn, indexLastNode); + useLastBlock->getSequence()->push_back(returnLastNode); + } + TIntermIfElse *ifNode = new TIntermIfElse(cond, useFirstBlock, nullptr); + bodyNode->getSequence()->push_back(ifNode); + bodyNode->getSequence()->push_back(useLastBlock); + + TIntermFunctionDefinition *indexingFunction = + new TIntermFunctionDefinition(prototypeNode, bodyNode); + return indexingFunction; +} + +class RemoveDynamicIndexingTraverser : public TLValueTrackingTraverser +{ + public: + RemoveDynamicIndexingTraverser(TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics); + + bool visitBinary(Visit visit, TIntermBinary *node) override; + + void insertHelperDefinitions(TIntermNode *root); + + void nextIteration(); + + bool usedTreeInsertion() const { return mUsedTreeInsertion; } + + protected: + // Maps of types that are indexed to the indexing function ids used for them. Note that these + // can not store multiple variants of the same type with different precisions - only one + // precision gets stored. + std::map<TType, TFunction *> mIndexedVecAndMatrixTypes; + std::map<TType, TFunction *> mWrittenVecAndMatrixTypes; + + bool mUsedTreeInsertion; + + // When true, the traverser will remove side effects from any indexing expression. + // This is done so that in code like + // V[j++][i]++. + // where V is an array of vectors, j++ will only be evaluated once. + bool mRemoveIndexSideEffectsInSubtree; + + PerformanceDiagnostics *mPerfDiagnostics; +}; + +RemoveDynamicIndexingTraverser::RemoveDynamicIndexingTraverser( + TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics) + : TLValueTrackingTraverser(true, false, false, symbolTable), + mUsedTreeInsertion(false), + mRemoveIndexSideEffectsInSubtree(false), + mPerfDiagnostics(perfDiagnostics) +{} + +void RemoveDynamicIndexingTraverser::insertHelperDefinitions(TIntermNode *root) +{ + TIntermBlock *rootBlock = root->getAsBlock(); + ASSERT(rootBlock != nullptr); + TIntermSequence insertions; + for (auto &type : mIndexedVecAndMatrixTypes) + { + insertions.push_back( + GetIndexFunctionDefinition(type.first, false, *type.second, mSymbolTable)); + } + for (auto &type : mWrittenVecAndMatrixTypes) + { + insertions.push_back( + GetIndexFunctionDefinition(type.first, true, *type.second, mSymbolTable)); + } + rootBlock->insertChildNodes(0, insertions); +} + +// Create a call to dyn_index_*() based on an indirect indexing op node +TIntermAggregate *CreateIndexFunctionCall(TIntermBinary *node, + TIntermTyped *index, + TFunction *indexingFunction) +{ + ASSERT(node->getOp() == EOpIndexIndirect); + TIntermSequence *arguments = new TIntermSequence(); + arguments->push_back(node->getLeft()); + arguments->push_back(index); + + TIntermAggregate *indexingCall = + TIntermAggregate::CreateFunctionCall(*indexingFunction, arguments); + indexingCall->setLine(node->getLine()); + return indexingCall; +} + +TIntermAggregate *CreateIndexedWriteFunctionCall(TIntermBinary *node, + TVariable *index, + TVariable *writtenValue, + TFunction *indexedWriteFunction) +{ + ASSERT(node->getOp() == EOpIndexIndirect); + TIntermSequence *arguments = new TIntermSequence(); + // Deep copy the child nodes so that two pointers to the same node don't end up in the tree. + arguments->push_back(node->getLeft()->deepCopy()); + arguments->push_back(CreateTempSymbolNode(index)); + arguments->push_back(CreateTempSymbolNode(writtenValue)); + + TIntermAggregate *indexedWriteCall = + TIntermAggregate::CreateFunctionCall(*indexedWriteFunction, arguments); + indexedWriteCall->setLine(node->getLine()); + return indexedWriteCall; +} + +bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (mUsedTreeInsertion) + return false; + + if (node->getOp() == EOpIndexIndirect) + { + if (mRemoveIndexSideEffectsInSubtree) + { + ASSERT(node->getRight()->hasSideEffects()); + // In case we're just removing index side effects, convert + // v_expr[index_expr] + // to this: + // int s0 = index_expr; v_expr[s0]; + // Now v_expr[s0] can be safely executed several times without unintended side effects. + TIntermDeclaration *indexVariableDeclaration = nullptr; + TVariable *indexVariable = DeclareTempVariable(mSymbolTable, node->getRight(), + EvqTemporary, &indexVariableDeclaration); + insertStatementInParentBlock(indexVariableDeclaration); + mUsedTreeInsertion = true; + + // Replace the index with the temp variable + TIntermSymbol *tempIndex = CreateTempSymbolNode(indexVariable); + queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED); + } + else if (IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(node)) + { + mPerfDiagnostics->warning(node->getLine(), + "Performance: dynamic indexing of vectors and " + "matrices is emulated and can be slow.", + "[]"); + bool write = isLValueRequiredHere(); + +#if defined(ANGLE_ENABLE_ASSERTS) + // Make sure that IntermNodePatternMatcher is consistent with the slightly differently + // implemented checks in this traverser. + IntermNodePatternMatcher matcher( + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue); + ASSERT(matcher.match(node, getParentNode(), isLValueRequiredHere()) == write); +#endif + + const TType &type = node->getLeft()->getType(); + ImmutableString indexingFunctionName(GetIndexFunctionName(type, false)); + TFunction *indexingFunction = nullptr; + if (mIndexedVecAndMatrixTypes.find(type) == mIndexedVecAndMatrixTypes.end()) + { + indexingFunction = + new TFunction(mSymbolTable, indexingFunctionName, SymbolType::AngleInternal, + GetFieldType(type), true); + indexingFunction->addParameter(new TVariable( + mSymbolTable, kBaseName, GetBaseType(type, false), SymbolType::AngleInternal)); + indexingFunction->addParameter( + new TVariable(mSymbolTable, kIndexName, kIndexType, SymbolType::AngleInternal)); + mIndexedVecAndMatrixTypes[type] = indexingFunction; + } + else + { + indexingFunction = mIndexedVecAndMatrixTypes[type]; + } + + if (write) + { + // Convert: + // v_expr[index_expr]++; + // to this: + // int s0 = index_expr; float s1 = dyn_index(v_expr, s0); s1++; + // dyn_index_write(v_expr, s0, s1); + // This works even if index_expr has some side effects. + if (node->getLeft()->hasSideEffects()) + { + // If v_expr has side effects, those need to be removed before proceeding. + // Otherwise the side effects of v_expr would be evaluated twice. + // The only case where an l-value can have side effects is when it is + // indexing. For example, it can be V[j++] where V is an array of vectors. + mRemoveIndexSideEffectsInSubtree = true; + return true; + } + + TIntermBinary *leftBinary = node->getLeft()->getAsBinaryNode(); + if (leftBinary != nullptr && + IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(leftBinary)) + { + // This is a case like: + // mat2 m; + // m[a][b]++; + // Process the child node m[a] first. + return true; + } + + // TODO(oetuaho@nvidia.com): This is not optimal if the expression using the value + // only writes it and doesn't need the previous value. http://anglebug.com/1116 + + TFunction *indexedWriteFunction = nullptr; + if (mWrittenVecAndMatrixTypes.find(type) == mWrittenVecAndMatrixTypes.end()) + { + ImmutableString functionName( + GetIndexFunctionName(node->getLeft()->getType(), true)); + indexedWriteFunction = + new TFunction(mSymbolTable, functionName, SymbolType::AngleInternal, + StaticType::GetBasic<EbtVoid>(), false); + indexedWriteFunction->addParameter(new TVariable(mSymbolTable, kBaseName, + GetBaseType(type, true), + SymbolType::AngleInternal)); + indexedWriteFunction->addParameter(new TVariable( + mSymbolTable, kIndexName, kIndexType, SymbolType::AngleInternal)); + TType *valueType = GetFieldType(type); + valueType->setQualifier(EvqIn); + indexedWriteFunction->addParameter(new TVariable( + mSymbolTable, kValueName, static_cast<const TType *>(valueType), + SymbolType::AngleInternal)); + mWrittenVecAndMatrixTypes[type] = indexedWriteFunction; + } + else + { + indexedWriteFunction = mWrittenVecAndMatrixTypes[type]; + } + + TIntermSequence insertionsBefore; + TIntermSequence insertionsAfter; + + // Store the index in a temporary signed int variable. + // s0 = index_expr; + TIntermTyped *indexInitializer = EnsureSignedInt(node->getRight()); + TIntermDeclaration *indexVariableDeclaration = nullptr; + TVariable *indexVariable = DeclareTempVariable( + mSymbolTable, indexInitializer, EvqTemporary, &indexVariableDeclaration); + insertionsBefore.push_back(indexVariableDeclaration); + + // s1 = dyn_index(v_expr, s0); + TIntermAggregate *indexingCall = CreateIndexFunctionCall( + node, CreateTempSymbolNode(indexVariable), indexingFunction); + TIntermDeclaration *fieldVariableDeclaration = nullptr; + TVariable *fieldVariable = DeclareTempVariable( + mSymbolTable, indexingCall, EvqTemporary, &fieldVariableDeclaration); + insertionsBefore.push_back(fieldVariableDeclaration); + + // dyn_index_write(v_expr, s0, s1); + TIntermAggregate *indexedWriteCall = CreateIndexedWriteFunctionCall( + node, indexVariable, fieldVariable, indexedWriteFunction); + insertionsAfter.push_back(indexedWriteCall); + insertStatementsInParentBlock(insertionsBefore, insertionsAfter); + + // replace the node with s1 + queueReplacement(CreateTempSymbolNode(fieldVariable), OriginalNode::IS_DROPPED); + mUsedTreeInsertion = true; + } + else + { + // The indexed value is not being written, so we can simply convert + // v_expr[index_expr] + // into + // dyn_index(v_expr, index_expr) + // If the index_expr is unsigned, we'll convert it to signed. + ASSERT(!mRemoveIndexSideEffectsInSubtree); + TIntermAggregate *indexingCall = CreateIndexFunctionCall( + node, EnsureSignedInt(node->getRight()), indexingFunction); + queueReplacement(indexingCall, OriginalNode::IS_DROPPED); + } + } + } + return !mUsedTreeInsertion; +} + +void RemoveDynamicIndexingTraverser::nextIteration() +{ + mUsedTreeInsertion = false; + mRemoveIndexSideEffectsInSubtree = false; +} + +} // namespace + +void RemoveDynamicIndexing(TIntermNode *root, + TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics) +{ + RemoveDynamicIndexingTraverser traverser(symbolTable, perfDiagnostics); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + traverser.updateTree(); + } while (traverser.usedTreeInsertion()); + // TODO(oetuaho@nvidia.com): It might be nicer to add the helper definitions also in the middle + // of traversal. Now the tree ends up in an inconsistent state in the middle, since there are + // function call nodes with no corresponding definition nodes. This needs special handling in + // TIntermLValueTrackingTraverser, and creates intricacies that are not easily apparent from a + // superficial reading of the code. + traverser.insertHelperDefinitions(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h new file mode 100644 index 0000000000..500c88ed12 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2002-2015 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. +// +// RemoveDynamicIndexing is an AST traverser to remove dynamic indexing of non-SSBO vectors and +// matrices, replacing them with calls to functions that choose which component to return or write. +// We don't need to consider dynamic indexing in SSBO since it can be directly as part of the offset +// of RWByteAddressBuffer. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; +class PerformanceDiagnostics; + +void RemoveDynamicIndexing(TIntermNode *root, + TSymbolTable *symbolTable, + PerformanceDiagnostics *perfDiagnostics); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEDYNAMICINDEXING_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp new file mode 100644 index 0000000000..e40fe95929 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 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. +// + +#include "compiler/translator/tree_ops/RemoveInvariantDeclaration.h" + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// An AST traverser that removes invariant declaration for input in fragment shader +// when GLSL >= 4.20 and for output in vertex shader when GLSL < 4.2. +class RemoveInvariantDeclarationTraverser : public TIntermTraverser +{ + public: + RemoveInvariantDeclarationTraverser() : TIntermTraverser(true, false, false) {} + + private: + bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override + { + TIntermSequence emptyReplacement; + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, emptyReplacement)); + return false; + } +}; + +} // anonymous namespace + +void RemoveInvariantDeclaration(TIntermNode *root) +{ + RemoveInvariantDeclarationTraverser traverser; + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h new file mode 100644 index 0000000000..3281014ad0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 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. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEINVARIANTDECLARATION_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REMOVEINVARIANTDECLARATION_H_ + +class TIntermNode; +namespace sh +{ + +void RemoveInvariantDeclaration(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEINVARIANTDECLARATION_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp new file mode 100644 index 0000000000..c270ff0f4a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp @@ -0,0 +1,101 @@ +// +// Copyright (c) 2002-2015 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. +// +// RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a +// constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series +// OpenGL drivers. +// + +#include "compiler/translator/tree_ops/RemovePow.h" + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +bool IsProblematicPow(TIntermTyped *node) +{ + TIntermAggregate *agg = node->getAsAggregate(); + if (agg != nullptr && agg->getOp() == EOpPow) + { + ASSERT(agg->getSequence()->size() == 2); + return agg->getSequence()->at(1)->getAsConstantUnion() != nullptr; + } + return false; +} + +// Traverser that converts all pow operations simultaneously. +class RemovePowTraverser : public TIntermTraverser +{ + public: + RemovePowTraverser(TSymbolTable *symbolTable); + + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + void nextIteration() { mNeedAnotherIteration = false; } + bool needAnotherIteration() const { return mNeedAnotherIteration; } + + protected: + bool mNeedAnotherIteration; +}; + +RemovePowTraverser::RemovePowTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), mNeedAnotherIteration(false) +{} + +bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (IsProblematicPow(node)) + { + TIntermTyped *x = node->getSequence()->at(0)->getAsTyped(); + TIntermTyped *y = node->getSequence()->at(1)->getAsTyped(); + + TIntermSequence *logArgs = new TIntermSequence(); + logArgs->push_back(x); + TIntermTyped *log = CreateBuiltInFunctionCallNode("log2", logArgs, *mSymbolTable, 100); + log->setLine(node->getLine()); + + TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType()); + TIntermBinary *mul = new TIntermBinary(op, y, log); + mul->setLine(node->getLine()); + + TIntermSequence *expArgs = new TIntermSequence(); + expArgs->push_back(mul); + TIntermTyped *exp = CreateBuiltInFunctionCallNode("exp2", expArgs, *mSymbolTable, 100); + exp->setLine(node->getLine()); + + queueReplacement(exp, OriginalNode::IS_DROPPED); + + // If the x parameter also needs to be replaced, we need to do that in another traversal, + // since it's parent node will change in a way that's not handled correctly by updateTree(). + if (IsProblematicPow(x)) + { + mNeedAnotherIteration = true; + return false; + } + } + return true; +} + +} // namespace + +void RemovePow(TIntermNode *root, TSymbolTable *symbolTable) +{ + RemovePowTraverser traverser(symbolTable); + // Iterate as necessary, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + traverser.updateTree(); + } while (traverser.needAnotherIteration()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h new file mode 100644 index 0000000000..bb0e990656 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2002-2015 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. +// +// RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a +// constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series +// OpenGL drivers. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEPOW_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REMOVEPOW_H_ + +namespace sh +{ +class TIntermNode; +class TSymbolTable; + +void RemovePow(TIntermNode *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEPOW_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp new file mode 100644 index 0000000000..9af46770f8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp @@ -0,0 +1,270 @@ +// +// Copyright (c) 2002-2015 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. +// +// RemoveSwitchFallThrough.cpp: Remove fall-through from switch statements. +// Note that it is unsafe to do further AST transformations on the AST generated +// by this function. It leaves duplicate nodes in the AST making replacements +// unreliable. + +#include "compiler/translator/tree_ops/RemoveSwitchFallThrough.h" + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class RemoveSwitchFallThroughTraverser : public TIntermTraverser +{ + public: + static TIntermBlock *removeFallThrough(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics); + + private: + RemoveSwitchFallThroughTraverser(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics); + + void visitSymbol(TIntermSymbol *node) override; + void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitDeclaration(Visit, TIntermDeclaration *node) override; + bool visitBinary(Visit, TIntermBinary *node) override; + bool visitUnary(Visit, TIntermUnary *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitSwizzle(Visit, TIntermSwizzle *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; + bool visitSwitch(Visit, TIntermSwitch *node) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitBlock(Visit, TIntermBlock *node) override; + bool visitLoop(Visit, TIntermLoop *node) override; + bool visitBranch(Visit, TIntermBranch *node) override; + + void outputSequence(TIntermSequence *sequence, size_t startIndex); + void handlePreviousCase(); + + TIntermBlock *mStatementList; + TIntermBlock *mStatementListOut; + bool mLastStatementWasBreak; + TIntermBlock *mPreviousCase; + std::vector<TIntermBlock *> mCasesSharingBreak; + PerformanceDiagnostics *mPerfDiagnostics; +}; + +TIntermBlock *RemoveSwitchFallThroughTraverser::removeFallThrough( + TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics) +{ + RemoveSwitchFallThroughTraverser rm(statementList, perfDiagnostics); + ASSERT(statementList); + statementList->traverse(&rm); + ASSERT(rm.mPreviousCase || statementList->getSequence()->empty()); + if (!rm.mLastStatementWasBreak && rm.mPreviousCase) + { + // Make sure that there's a branch at the end of the final case inside the switch statement. + // This also ensures that any cases that fall through to the final case will get the break. + TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr); + rm.mPreviousCase->getSequence()->push_back(finalBreak); + rm.mLastStatementWasBreak = true; + } + rm.handlePreviousCase(); + return rm.mStatementListOut; +} + +RemoveSwitchFallThroughTraverser::RemoveSwitchFallThroughTraverser( + TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics) + : TIntermTraverser(true, false, false), + mStatementList(statementList), + mLastStatementWasBreak(false), + mPreviousCase(nullptr), + mPerfDiagnostics(perfDiagnostics) +{ + mStatementListOut = new TIntermBlock(); +} + +void RemoveSwitchFallThroughTraverser::visitSymbol(TIntermSymbol *node) +{ + // Note that this assumes that switch statements which don't begin by a case statement + // have already been weeded out in validation. + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; +} + +void RemoveSwitchFallThroughTraverser::visitConstantUnion(TIntermConstantUnion *node) +{ + // Conditions of case labels are not traversed, so this is a constant statement like "0;". + // These are no-ops so there's no need to add them back to the statement list. Should have + // already been pruned out of the AST, in fact. + UNREACHABLE(); +} + +bool RemoveSwitchFallThroughTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitBinary(Visit, TIntermBinary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitUnary(Visit, TIntermUnary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitTernary(Visit, TIntermTernary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitSwizzle(Visit, TIntermSwizzle *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitIfElse(Visit, TIntermIfElse *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitSwitch(Visit, TIntermSwitch *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + // Don't go into nested switch statements + return false; +} + +void RemoveSwitchFallThroughTraverser::outputSequence(TIntermSequence *sequence, size_t startIndex) +{ + for (size_t i = startIndex; i < sequence->size(); ++i) + { + mStatementListOut->getSequence()->push_back(sequence->at(i)); + } +} + +void RemoveSwitchFallThroughTraverser::handlePreviousCase() +{ + if (mPreviousCase) + mCasesSharingBreak.push_back(mPreviousCase); + if (mLastStatementWasBreak) + { + for (size_t i = 0; i < mCasesSharingBreak.size(); ++i) + { + ASSERT(!mCasesSharingBreak.at(i)->getSequence()->empty()); + if (mCasesSharingBreak.at(i)->getSequence()->size() == 1) + { + // Fall-through is allowed in case the label has no statements. + outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0); + } + else + { + // Include all the statements that this case can fall through under the same label. + if (mCasesSharingBreak.size() > i + 1u) + { + mPerfDiagnostics->warning(mCasesSharingBreak.at(i)->getLine(), + "Performance: non-empty fall-through cases in " + "switch statements generate extra code.", + "switch"); + } + for (size_t j = i; j < mCasesSharingBreak.size(); ++j) + { + size_t startIndex = + j > i ? 1 : 0; // Add the label only from the first sequence. + outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex); + } + } + } + mCasesSharingBreak.clear(); + } + mLastStatementWasBreak = false; + mPreviousCase = nullptr; +} + +bool RemoveSwitchFallThroughTraverser::visitCase(Visit, TIntermCase *node) +{ + handlePreviousCase(); + mPreviousCase = new TIntermBlock(); + mPreviousCase->getSequence()->push_back(node); + mPreviousCase->setLine(node->getLine()); + // Don't traverse the condition of the case statement + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitAggregate(Visit, TIntermAggregate *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool DoesBlockAlwaysBreak(TIntermBlock *node) +{ + if (node->getSequence()->empty()) + { + return false; + } + + TIntermBlock *lastStatementAsBlock = node->getSequence()->back()->getAsBlock(); + if (lastStatementAsBlock) + { + return DoesBlockAlwaysBreak(lastStatementAsBlock); + } + + TIntermBranch *lastStatementAsBranch = node->getSequence()->back()->getAsBranchNode(); + return lastStatementAsBranch != nullptr; +} + +bool RemoveSwitchFallThroughTraverser::visitBlock(Visit, TIntermBlock *node) +{ + if (node != mStatementList) + { + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = DoesBlockAlwaysBreak(node); + return false; + } + return true; +} + +bool RemoveSwitchFallThroughTraverser::visitLoop(Visit, TIntermLoop *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThroughTraverser::visitBranch(Visit, TIntermBranch *node) +{ + mPreviousCase->getSequence()->push_back(node); + // TODO: Verify that accepting return or continue statements here doesn't cause problems. + mLastStatementWasBreak = true; + return false; +} + +} // anonymous namespace + +TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics) +{ + return RemoveSwitchFallThroughTraverser::removeFallThrough(statementList, perfDiagnostics); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h new file mode 100644 index 0000000000..58cad0c856 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 2002-2015 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. +// +// RemoveSwitchFallThrough.h: Remove fall-through from switch statements. +// Note that it is unsafe to do further AST transformations on the AST generated +// by this function. It leaves duplicate nodes in the AST making replacements +// unreliable. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVESWITCHFALLTHROUGH_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REMOVESWITCHFALLTHROUGH_H_ + +namespace sh +{ + +class TIntermBlock; +class PerformanceDiagnostics; + +// When given a statementList from a switch AST node, return an updated +// statementList that has fall-through removed. +TIntermBlock *RemoveSwitchFallThrough(TIntermBlock *statementList, + PerformanceDiagnostics *perfDiagnostics); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVESWITCHFALLTHROUGH_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp new file mode 100644 index 0000000000..28471a309d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp @@ -0,0 +1,371 @@ +// +// Copyright (c) 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. +// +// RemoveUnreferencedVariables.cpp: +// Drop variables that are declared but never referenced in the AST. This avoids adding unnecessary +// initialization code for them. Also removes unreferenced struct types. +// + +#include "compiler/translator/tree_ops/RemoveUnreferencedVariables.h" + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class CollectVariableRefCountsTraverser : public TIntermTraverser +{ + public: + CollectVariableRefCountsTraverser(); + + using RefCountMap = std::unordered_map<int, unsigned int>; + RefCountMap &getSymbolIdRefCounts() { return mSymbolIdRefCounts; } + RefCountMap &getStructIdRefCounts() { return mStructIdRefCounts; } + + void visitSymbol(TIntermSymbol *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + void visitFunctionPrototype(TIntermFunctionPrototype *node) override; + + private: + void incrementStructTypeRefCount(const TType &type); + + RefCountMap mSymbolIdRefCounts; + + // Structure reference counts are counted from symbols, constructors, function calls, function + // return values and from interface block and structure fields. We need to track both function + // calls and function return values since there's a compiler option not to prune unused + // functions. The type of a constant union may also be a struct, but statements that are just a + // constant union are always pruned, and if the constant union is used somehow it will get + // counted by something else. + RefCountMap mStructIdRefCounts; +}; + +CollectVariableRefCountsTraverser::CollectVariableRefCountsTraverser() + : TIntermTraverser(true, false, false) +{} + +void CollectVariableRefCountsTraverser::incrementStructTypeRefCount(const TType &type) +{ + if (type.isInterfaceBlock()) + { + const auto *block = type.getInterfaceBlock(); + ASSERT(block); + + // We can end up incrementing ref counts of struct types referenced from an interface block + // multiple times for the same block. This doesn't matter, because interface blocks can't be + // pruned so we'll never do the reverse operation. + for (const auto &field : block->fields()) + { + ASSERT(!field->type()->isInterfaceBlock()); + incrementStructTypeRefCount(*field->type()); + } + return; + } + + const auto *structure = type.getStruct(); + if (structure != nullptr) + { + auto structIter = mStructIdRefCounts.find(structure->uniqueId().get()); + if (structIter == mStructIdRefCounts.end()) + { + mStructIdRefCounts[structure->uniqueId().get()] = 1u; + + for (const auto &field : structure->fields()) + { + incrementStructTypeRefCount(*field->type()); + } + + return; + } + ++(structIter->second); + } +} + +void CollectVariableRefCountsTraverser::visitSymbol(TIntermSymbol *node) +{ + incrementStructTypeRefCount(node->getType()); + + auto iter = mSymbolIdRefCounts.find(node->uniqueId().get()); + if (iter == mSymbolIdRefCounts.end()) + { + mSymbolIdRefCounts[node->uniqueId().get()] = 1u; + return; + } + ++(iter->second); +} + +bool CollectVariableRefCountsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + // This tracks struct references in both function calls and constructors. + incrementStructTypeRefCount(node->getType()); + return true; +} + +void CollectVariableRefCountsTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node) +{ + incrementStructTypeRefCount(node->getType()); + size_t paramCount = node->getFunction()->getParamCount(); + for (size_t i = 0; i < paramCount; ++i) + { + incrementStructTypeRefCount(node->getFunction()->getParam(i)->getType()); + } +} + +// Traverser that removes all unreferenced variables on one traversal. +class RemoveUnreferencedVariablesTraverser : public TIntermTraverser +{ + public: + RemoveUnreferencedVariablesTraverser( + CollectVariableRefCountsTraverser::RefCountMap *symbolIdRefCounts, + CollectVariableRefCountsTraverser::RefCountMap *structIdRefCounts, + TSymbolTable *symbolTable); + + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + void visitSymbol(TIntermSymbol *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + // Traverse loop and block nodes in reverse order. Note that this traverser does not track + // parent block positions, so insertStatementInParentBlock is unusable! + void traverseBlock(TIntermBlock *block) override; + void traverseLoop(TIntermLoop *loop) override; + + private: + void removeVariableDeclaration(TIntermDeclaration *node, TIntermTyped *declarator); + void decrementStructTypeRefCount(const TType &type); + + CollectVariableRefCountsTraverser::RefCountMap *mSymbolIdRefCounts; + CollectVariableRefCountsTraverser::RefCountMap *mStructIdRefCounts; + bool mRemoveReferences; +}; + +RemoveUnreferencedVariablesTraverser::RemoveUnreferencedVariablesTraverser( + CollectVariableRefCountsTraverser::RefCountMap *symbolIdRefCounts, + CollectVariableRefCountsTraverser::RefCountMap *structIdRefCounts, + TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), + mSymbolIdRefCounts(symbolIdRefCounts), + mStructIdRefCounts(structIdRefCounts), + mRemoveReferences(false) +{} + +void RemoveUnreferencedVariablesTraverser::decrementStructTypeRefCount(const TType &type) +{ + auto *structure = type.getStruct(); + if (structure != nullptr) + { + ASSERT(mStructIdRefCounts->find(structure->uniqueId().get()) != mStructIdRefCounts->end()); + unsigned int structRefCount = --(*mStructIdRefCounts)[structure->uniqueId().get()]; + + if (structRefCount == 0) + { + for (const auto &field : structure->fields()) + { + decrementStructTypeRefCount(*field->type()); + } + } + } +} + +void RemoveUnreferencedVariablesTraverser::removeVariableDeclaration(TIntermDeclaration *node, + TIntermTyped *declarator) +{ + if (declarator->getType().isStructSpecifier() && !declarator->getType().isNamelessStruct()) + { + unsigned int structId = declarator->getType().getStruct()->uniqueId().get(); + unsigned int structRefCountInThisDeclarator = 1u; + if (declarator->getAsBinaryNode() && + declarator->getAsBinaryNode()->getRight()->getAsAggregate()) + { + ASSERT(declarator->getAsBinaryNode()->getLeft()->getType().getStruct() == + declarator->getType().getStruct()); + ASSERT(declarator->getAsBinaryNode()->getRight()->getType().getStruct() == + declarator->getType().getStruct()); + structRefCountInThisDeclarator = 2u; + } + if ((*mStructIdRefCounts)[structId] > structRefCountInThisDeclarator) + { + // If this declaration declares a named struct type that is used elsewhere, we need to + // keep it. We can still change the declarator though so that it doesn't declare an + // unreferenced variable. + + // Note that since we're not removing the entire declaration, the struct's reference + // count will end up being one less than the correct refcount. But since the struct + // declaration is kept, the incorrect refcount can't cause any other problems. + + if (declarator->getAsSymbolNode() && + declarator->getAsSymbolNode()->variable().symbolType() == SymbolType::Empty) + { + // Already an empty declaration - nothing to do. + return; + } + TVariable *emptyVariable = + new TVariable(mSymbolTable, kEmptyImmutableString, new TType(declarator->getType()), + SymbolType::Empty); + queueReplacementWithParent(node, declarator, new TIntermSymbol(emptyVariable), + OriginalNode::IS_DROPPED); + return; + } + } + + if (getParentNode()->getAsBlock()) + { + TIntermSequence emptyReplacement; + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, emptyReplacement)); + } + else + { + ASSERT(getParentNode()->getAsLoopNode()); + queueReplacement(nullptr, OriginalNode::IS_DROPPED); + } +} + +bool RemoveUnreferencedVariablesTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + if (visit == PreVisit) + { + // SeparateDeclarations should have already been run. + ASSERT(node->getSequence()->size() == 1u); + + TIntermTyped *declarator = node->getSequence()->back()->getAsTyped(); + ASSERT(declarator); + + // We can only remove variables that are not a part of the shader interface. + TQualifier qualifier = declarator->getQualifier(); + if (qualifier != EvqTemporary && qualifier != EvqGlobal && qualifier != EvqConst) + { + return true; + } + + bool canRemoveVariable = false; + TIntermSymbol *symbolNode = declarator->getAsSymbolNode(); + if (symbolNode != nullptr) + { + canRemoveVariable = (*mSymbolIdRefCounts)[symbolNode->uniqueId().get()] == 1u || + symbolNode->variable().symbolType() == SymbolType::Empty; + } + TIntermBinary *initNode = declarator->getAsBinaryNode(); + if (initNode != nullptr) + { + ASSERT(initNode->getLeft()->getAsSymbolNode()); + int symbolId = initNode->getLeft()->getAsSymbolNode()->uniqueId().get(); + canRemoveVariable = + (*mSymbolIdRefCounts)[symbolId] == 1u && !initNode->getRight()->hasSideEffects(); + } + + if (canRemoveVariable) + { + removeVariableDeclaration(node, declarator); + mRemoveReferences = true; + } + return true; + } + ASSERT(visit == PostVisit); + mRemoveReferences = false; + return true; +} + +void RemoveUnreferencedVariablesTraverser::visitSymbol(TIntermSymbol *node) +{ + if (mRemoveReferences) + { + ASSERT(mSymbolIdRefCounts->find(node->uniqueId().get()) != mSymbolIdRefCounts->end()); + --(*mSymbolIdRefCounts)[node->uniqueId().get()]; + + decrementStructTypeRefCount(node->getType()); + } +} + +bool RemoveUnreferencedVariablesTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (visit == PreVisit && mRemoveReferences) + { + decrementStructTypeRefCount(node->getType()); + } + return true; +} + +void RemoveUnreferencedVariablesTraverser::traverseBlock(TIntermBlock *node) +{ + // We traverse blocks in reverse order. This way reference counts can be decremented when + // removing initializers, and variables that become unused when initializers are removed can be + // removed on the same traversal. + + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + + if (preVisit) + visit = visitBlock(PreVisit, node); + + if (visit) + { + for (auto iter = sequence->rbegin(); iter != sequence->rend(); ++iter) + { + (*iter)->traverse(this); + if (visit && inVisit) + { + if ((iter + 1) != sequence->rend()) + visit = visitBlock(InVisit, node); + } + } + } + + if (visit && postVisit) + visitBlock(PostVisit, node); +} + +void RemoveUnreferencedVariablesTraverser::traverseLoop(TIntermLoop *node) +{ + // We traverse loops in reverse order as well. The loop body gets traversed before the init + // node. + + ScopedNodeInTraversalPath addToPath(this, node); + + bool visit = true; + + if (preVisit) + visit = visitLoop(PreVisit, node); + + if (visit) + { + // We don't need to traverse loop expressions or conditions since they can't be declarations + // in the AST (loops which have a declaration in their condition get transformed in the + // parsing stage). + ASSERT(node->getExpression() == nullptr || + node->getExpression()->getAsDeclarationNode() == nullptr); + ASSERT(node->getCondition() == nullptr || + node->getCondition()->getAsDeclarationNode() == nullptr); + + if (node->getBody()) + node->getBody()->traverse(this); + + if (node->getInit()) + node->getInit()->traverse(this); + } + + if (visit && postVisit) + visitLoop(PostVisit, node); +} + +} // namespace + +void RemoveUnreferencedVariables(TIntermBlock *root, TSymbolTable *symbolTable) +{ + CollectVariableRefCountsTraverser collector; + root->traverse(&collector); + RemoveUnreferencedVariablesTraverser traverser(&collector.getSymbolIdRefCounts(), + &collector.getStructIdRefCounts(), symbolTable); + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h new file mode 100644 index 0000000000..6888b2f2a0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 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. +// +// RemoveUnreferencedVariables.h: +// Drop variables that are declared but never referenced in the AST. This avoids adding unnecessary +// initialization code for them. Also removes unreferenced struct types. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REMOVEUNREFERENCEDVARIABLES_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REMOVEUNREFERENCEDVARIABLES_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void RemoveUnreferencedVariables(TIntermBlock *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REMOVEUNREFERENCEDVARIABLES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp new file mode 100644 index 0000000000..8e76c4862c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.cpp @@ -0,0 +1,462 @@ +// +// 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. +// +// RewriteAtomicCounters: Emulate atomic counter buffers with storage buffers. +// + +#include "compiler/translator/tree_ops/RewriteAtomicCounters.h" + +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ +namespace +{ +// DeclareAtomicCountersBuffer adds a storage buffer that's used with atomic counters. +const TVariable *DeclareAtomicCountersBuffer(TIntermBlock *root, TSymbolTable *symbolTable) +{ + // Define `uint counters[];` as the only field in the interface block. + TFieldList *fieldList = new TFieldList; + TType *counterType = new TType(EbtUInt); + counterType->makeArray(0); + + TField *countersField = new TField(counterType, ImmutableString("counters"), TSourceLoc(), + SymbolType::AngleInternal); + + fieldList->push_back(countersField); + + TMemoryQualifier coherentMemory = TMemoryQualifier::Create(); + coherentMemory.coherent = true; + + // Define a storage block "ANGLEAtomicCounters" with instance name "atomicCounters". + return DeclareInterfaceBlock(root, symbolTable, fieldList, EvqBuffer, coherentMemory, + "ANGLEAtomicCounters", "atomicCounters"); +} + +TIntermBinary *CreateAtomicCounterRef(const TVariable *atomicCounters, TIntermTyped *offset) +{ + TIntermSymbol *atomicCountersRef = new TIntermSymbol(atomicCounters); + TConstantUnion *firstFieldIndex = new TConstantUnion; + firstFieldIndex->setIConst(0); + TIntermConstantUnion *firstFieldRef = + new TIntermConstantUnion(firstFieldIndex, *StaticType::GetBasic<EbtUInt>()); + TIntermBinary *firstField = + new TIntermBinary(EOpIndexDirectInterfaceBlock, atomicCountersRef, firstFieldRef); + return new TIntermBinary(EOpIndexDirect, firstField, offset); +} + +TIntermConstantUnion *CreateUIntConstant(uint32_t value) +{ + const TType *constantType = StaticType::GetBasic<EbtUInt, 1>(); + TConstantUnion *constantValue = new TConstantUnion; + constantValue->setUConst(value); + return new TIntermConstantUnion(constantValue, *constantType); +} + +// Traverser that: +// +// 1. Converts the |atomic_uint| types to |uint|. +// 2. Substitutes the |uniform atomic_uint| declarations with a global declaration that holds the +// offset. +// 3. Substitutes |atomicVar[n]| with |offset + n|. +class RewriteAtomicCountersTraverser : public TIntermTraverser +{ + public: + RewriteAtomicCountersTraverser(TSymbolTable *symbolTable, const TVariable *atomicCounters) + : TIntermTraverser(true, true, true, symbolTable), + mAtomicCounters(atomicCounters), + mCurrentAtomicCounterOffset(0), + mCurrentAtomicCounterDecl(nullptr), + mCurrentAtomicCounterDeclParent(nullptr) + {} + + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override + { + const TIntermSequence &sequence = *(node->getSequence()); + + TIntermTyped *variable = sequence.front()->getAsTyped(); + const TType &type = variable->getType(); + bool isAtomicCounter = type.getQualifier() == EvqUniform && type.isAtomicCounter(); + + if (visit == PreVisit || visit == InVisit) + { + if (isAtomicCounter) + { + // We only support one atomic counter buffer, so the binding should necessarily be + // 0. + ASSERT(type.getLayoutQualifier().binding == 0); + + mCurrentAtomicCounterDecl = node; + mCurrentAtomicCounterDeclParent = getParentNode()->getAsBlock(); + mCurrentAtomicCounterOffset = type.getLayoutQualifier().offset; + } + } + else if (visit == PostVisit) + { + mCurrentAtomicCounterDecl = nullptr; + mCurrentAtomicCounterDeclParent = nullptr; + mCurrentAtomicCounterOffset = 0; + } + return true; + } + + void visitFunctionPrototype(TIntermFunctionPrototype *node) override + { + const TFunction *function = node->getFunction(); + // Go over the parameters and replace the atomic arguments with a uint type. If this is + // the function definition, keep the replaced variable for future encounters. + mAtomicCounterFunctionParams.clear(); + for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex) + { + const TVariable *param = function->getParam(paramIndex); + TVariable *replacement = convertFunctionParameter(node, param); + if (replacement) + { + mAtomicCounterFunctionParams[param] = replacement; + } + } + + if (mAtomicCounterFunctionParams.empty()) + { + return; + } + + // Create a new function prototype and replace this with it. + TFunction *replacementFunction = new TFunction( + mSymbolTable, function->name(), SymbolType::UserDefined, + new TType(function->getReturnType()), function->isKnownToNotHaveSideEffects()); + for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex) + { + const TVariable *param = function->getParam(paramIndex); + TVariable *replacement = nullptr; + if (param->getType().isAtomicCounter()) + { + ASSERT(mAtomicCounterFunctionParams.count(param) != 0); + replacement = mAtomicCounterFunctionParams[param]; + } + else + { + replacement = new TVariable(mSymbolTable, param->name(), + new TType(param->getType()), SymbolType::UserDefined); + } + replacementFunction->addParameter(replacement); + } + + TIntermFunctionPrototype *replacementPrototype = + new TIntermFunctionPrototype(replacementFunction); + queueReplacement(replacementPrototype, OriginalNode::IS_DROPPED); + + mReplacedFunctions[function] = replacementFunction; + } + + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + if (visit == PreVisit) + { + mAtomicCounterFunctionCallArgs.clear(); + } + + if (visit != PostVisit) + { + return true; + } + + if (node->getOp() == EOpCallBuiltInFunction) + { + convertBuiltinFunction(node); + } + else if (node->getOp() == EOpCallFunctionInAST) + { + convertASTFunction(node); + } + + return true; + } + + void visitSymbol(TIntermSymbol *symbol) override + { + const TVariable *symbolVariable = &symbol->variable(); + + if (mCurrentAtomicCounterDecl) + { + declareAtomicCounter(symbolVariable); + return; + } + + if (!symbol->getType().isAtomicCounter()) + { + return; + } + + // The symbol is either referencing a global atomic counter, or is a function parameter. In + // either case, it could be an array. The are the following possibilities: + // + // layout(..) uniform atomic_uint ac; + // layout(..) uniform atomic_uint acArray[N]; + // + // void func(inout atomic_uint c) + // { + // otherFunc(c); + // } + // + // void funcArray(inout atomic_uint cArray[N]) + // { + // otherFuncArray(cArray); + // otherFunc(cArray[n]); + // } + // + // void funcGlobal() + // { + // func(ac); + // func(acArray[n]); + // funcArray(acArray); + // atomicIncrement(ac); + // atomicIncrement(acArray[n]); + // } + // + // This should translate to: + // + // buffer ANGLEAtomicCounters + // { + // uint counters[]; + // } atomicCounters; + // + // const uint ac = <offset>; + // const uint acArray = <offset>; + // + // void func(inout uint c) + // { + // otherFunc(c); + // } + // + // void funcArray(inout uint cArray) + // { + // otherFuncArray(cArray); + // otherFunc(cArray + n); + // } + // + // void funcGlobal() + // { + // func(ac); + // func(acArray+n); + // funcArray(acArray); + // atomicAdd(atomicCounters.counters[ac]); + // atomicAdd(atomicCounters.counters[ac+n]); + // } + // + // In all cases, the argument transformation is stored in |mAtomicCounterFunctionCallArgs|. + // In the function call's PostVisit, if it's a builtin, the look up in + // |atomicCounters.counters| is done as well as the builtin function change. Otherwise, + // the transformed argument is passed on as is. + // + + TIntermTyped *offset = nullptr; + if (mAtomicCounterOffsets.count(symbolVariable) != 0) + { + offset = new TIntermSymbol(mAtomicCounterOffsets[symbolVariable]); + } + else + { + ASSERT(mAtomicCounterFunctionParams.count(symbolVariable) != 0); + offset = new TIntermSymbol(mAtomicCounterFunctionParams[symbolVariable]); + } + + TIntermNode *argument = symbol; + + TIntermNode *parent = getParentNode(); + ASSERT(parent); + + TIntermBinary *arrayExpression = parent->getAsBinaryNode(); + if (arrayExpression) + { + ASSERT(arrayExpression->getOp() == EOpIndexDirect || + arrayExpression->getOp() == EOpIndexIndirect); + + offset = new TIntermBinary(EOpAdd, offset, arrayExpression->getRight()->deepCopy()); + argument = arrayExpression; + } + + mAtomicCounterFunctionCallArgs[argument] = offset; + } + + private: + void declareAtomicCounter(const TVariable *symbolVariable) + { + // Create a global variable that contains the offset of this atomic counter declaration. + TType *uintType = new TType(*StaticType::GetBasic<EbtUInt, 1>()); + uintType->setQualifier(EvqConst); + TVariable *offset = + new TVariable(mSymbolTable, symbolVariable->name(), uintType, SymbolType::UserDefined); + + ASSERT(mCurrentAtomicCounterOffset % 4 == 0); + TIntermConstantUnion *offsetInitValue = CreateIndexNode(mCurrentAtomicCounterOffset / 4); + + TIntermSymbol *offsetSymbol = new TIntermSymbol(offset); + TIntermBinary *offsetInit = new TIntermBinary(EOpInitialize, offsetSymbol, offsetInitValue); + + TIntermDeclaration *offsetDeclaration = new TIntermDeclaration(); + offsetDeclaration->appendDeclarator(offsetInit); + + // Replace the atomic_uint declaration with the offset declaration. + TIntermSequence replacement; + replacement.push_back(offsetDeclaration); + mMultiReplacements.emplace_back(mCurrentAtomicCounterDeclParent, mCurrentAtomicCounterDecl, + replacement); + + // Remember the offset variable. + mAtomicCounterOffsets[symbolVariable] = offset; + } + + TVariable *convertFunctionParameter(TIntermNode *parent, const TVariable *param) + { + if (!param->getType().isAtomicCounter()) + { + return nullptr; + } + + const TType *newType = StaticType::GetBasic<EbtUInt>(); + + TVariable *replacementVar = + new TVariable(mSymbolTable, param->name(), newType, SymbolType::UserDefined); + + return replacementVar; + } + + void convertBuiltinFunction(TIntermAggregate *node) + { + // If the function is |memoryBarrierAtomicCounter|, simply replace it with + // |memoryBarrierBuffer|. + if (node->getFunction()->name() == "memoryBarrierAtomicCounter") + { + TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode( + "memoryBarrierBuffer", new TIntermSequence, *mSymbolTable, 310); + queueReplacement(substituteCall, OriginalNode::IS_DROPPED); + return; + } + + // If it's an |atomicCounter*| function, replace the function with an |atomic*| equivalent. + if (!node->getFunction()->isAtomicCounterFunction()) + { + return; + } + + const ImmutableString &functionName = node->getFunction()->name(); + TIntermSequence *arguments = node->getSequence(); + + // Note: atomicAdd(0) is used for atomic reads. + uint32_t valueChange = 0; + constexpr char kAtomicAddFunction[] = "atomicAdd"; + bool isDecrement = false; + + if (functionName == "atomicCounterIncrement") + { + valueChange = 1; + } + else if (functionName == "atomicCounterDecrement") + { + // uint values are required to wrap around, so 0xFFFFFFFFu is used as -1. + valueChange = std::numeric_limits<uint32_t>::max(); + static_assert(static_cast<uint32_t>(-1) == std::numeric_limits<uint32_t>::max(), + "uint32_t max is not -1"); + + isDecrement = true; + } + else + { + ASSERT(functionName == "atomicCounter"); + } + + const TIntermNode *param = (*arguments)[0]; + ASSERT(mAtomicCounterFunctionCallArgs.count(param) != 0); + + TIntermTyped *offset = mAtomicCounterFunctionCallArgs[param]; + + TIntermSequence *substituteArguments = new TIntermSequence; + substituteArguments->push_back(CreateAtomicCounterRef(mAtomicCounters, offset)); + substituteArguments->push_back(CreateUIntConstant(valueChange)); + + TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode( + kAtomicAddFunction, substituteArguments, *mSymbolTable, 310); + + // Note that atomicCounterDecrement returns the *new* value instead of the prior value, + // unlike atomicAdd. So we need to do a -1 on the result as well. + if (isDecrement) + { + substituteCall = new TIntermBinary(EOpSub, substituteCall, CreateUIntConstant(1)); + } + + queueReplacement(substituteCall, OriginalNode::IS_DROPPED); + } + + void convertASTFunction(TIntermAggregate *node) + { + // See if the function needs replacement at all. + const TFunction *function = node->getFunction(); + if (mReplacedFunctions.count(function) == 0) + { + return; + } + + // atomic_uint arguments to this call are staged to be replaced at the same time. + TFunction *substituteFunction = mReplacedFunctions[function]; + TIntermSequence *substituteArguments = new TIntermSequence; + + for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex) + { + TIntermNode *param = node->getChildNode(paramIndex); + + TIntermNode *replacement = nullptr; + if (param->getAsTyped()->getType().isAtomicCounter()) + { + ASSERT(mAtomicCounterFunctionCallArgs.count(param) != 0); + replacement = mAtomicCounterFunctionCallArgs[param]; + } + else + { + replacement = param->getAsTyped()->deepCopy(); + } + substituteArguments->push_back(replacement); + } + + TIntermTyped *substituteCall = + TIntermAggregate::CreateFunctionCall(*substituteFunction, substituteArguments); + + queueReplacement(substituteCall, OriginalNode::IS_DROPPED); + } + + private: + const TVariable *mAtomicCounters; + + // A map from the atomic_uint variable to the offset declaration. + std::unordered_map<const TVariable *, TVariable *> mAtomicCounterOffsets; + // A map from functions with atomic_uint parameters to one where that's replaced with uint. + std::unordered_map<const TFunction *, TFunction *> mReplacedFunctions; + // A map from atomic_uint function parameters to their replacement uint parameter for the + // current function definition. + std::unordered_map<const TVariable *, TVariable *> mAtomicCounterFunctionParams; + // A map from atomic_uint function call arguments to their replacement for the current + // non-builtin function call. + std::unordered_map<const TIntermNode *, TIntermTyped *> mAtomicCounterFunctionCallArgs; + + uint32_t mCurrentAtomicCounterOffset; + TIntermDeclaration *mCurrentAtomicCounterDecl; + TIntermAggregateBase *mCurrentAtomicCounterDeclParent; +}; + +} // anonymous namespace + +void RewriteAtomicCounters(TIntermBlock *root, TSymbolTable *symbolTable) +{ + const TVariable *atomicCounters = DeclareAtomicCountersBuffer(root, symbolTable); + + RewriteAtomicCountersTraverser traverser(symbolTable, atomicCounters); + root->traverse(&traverser); + traverser.updateTree(); +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.h new file mode 100644 index 0000000000..905b258bd7 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicCounters.h @@ -0,0 +1,21 @@ +// +// 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. +// +// RewriteAtomicCounters: Change atomic counter buffers to storage buffers, with atomic counter +// variables being offsets into the uint array of that storage buffer. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEATOMICCOUNTERS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITEATOMICCOUNTERS_H_ + +namespace sh +{ +class TIntermBlock; +class TSymbolTable; +class TVariable; + +void RewriteAtomicCounters(TIntermBlock *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEATOMICCOUNTERS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp new file mode 100644 index 0000000000..f47e790b0a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.cpp @@ -0,0 +1,182 @@ +// +// Copyright (c) 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. +// +// Implementation of the function RewriteAtomicFunctionExpressions. +// See the header for more details. + +#include "RewriteAtomicFunctionExpressions.h" + +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/util.h" + +namespace sh +{ +namespace +{ +// Traverser that simplifies all the atomic function expressions into the ones that can be directly +// translated into HLSL. +// +// case 1 (only for atomicExchange and atomicCompSwap): +// original: +// atomicExchange(counter, newValue); +// new: +// tempValue = atomicExchange(counter, newValue); +// +// case 2 (atomic function, temporary variable required): +// original: +// value = atomicAdd(counter, 1) * otherValue; +// someArray[atomicAdd(counter, 1)] = someOtherValue; +// new: +// value = ((tempValue = atomicAdd(counter, 1)), tempValue) * otherValue; +// someArray[((tempValue = atomicAdd(counter, 1)), tempValue)] = someOtherValue; +// +// case 3 (atomic function used directly initialize a variable): +// original: +// int value = atomicAdd(counter, 1); +// new: +// tempValue = atomicAdd(counter, 1); +// int value = tempValue; +// +class RewriteAtomicFunctionExpressionsTraverser : public TIntermTraverser +{ + public: + RewriteAtomicFunctionExpressionsTraverser(TSymbolTable *symbolTable, int shaderVersion); + + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + + private: + static bool IsAtomicExchangeOrCompSwapNoReturnValue(TIntermAggregate *node, + TIntermNode *parentNode); + static bool IsAtomicFunctionInsideExpression(TIntermAggregate *node, TIntermNode *parentNode); + + void rewriteAtomicFunctionCallNode(TIntermAggregate *oldAtomicFunctionNode); + + const TVariable *getTempVariable(const TType *type); + + int mShaderVersion; + TIntermSequence mTempVariables; +}; + +RewriteAtomicFunctionExpressionsTraverser::RewriteAtomicFunctionExpressionsTraverser( + TSymbolTable *symbolTable, + int shaderVersion) + : TIntermTraverser(false, false, true, symbolTable), mShaderVersion(shaderVersion) +{} + +void RewriteAtomicFunctionExpressionsTraverser::rewriteAtomicFunctionCallNode( + TIntermAggregate *oldAtomicFunctionNode) +{ + ASSERT(oldAtomicFunctionNode); + + const TVariable *returnVariable = getTempVariable(&oldAtomicFunctionNode->getType()); + + TIntermBinary *rewrittenNode = new TIntermBinary( + TOperator::EOpAssign, CreateTempSymbolNode(returnVariable), oldAtomicFunctionNode); + + auto *parentNode = getParentNode(); + + auto *parentBinary = parentNode->getAsBinaryNode(); + if (parentBinary && parentBinary->getOp() == EOpInitialize) + { + insertStatementInParentBlock(rewrittenNode); + queueReplacement(CreateTempSymbolNode(returnVariable), OriginalNode::IS_DROPPED); + } + else + { + // As all atomic function assignment will be converted to the last argument of an + // interlocked function, if we need the return value, assignment needs to be wrapped with + // the comma operator and the temporary variables. + if (!parentNode->getAsBlock()) + { + rewrittenNode = TIntermBinary::CreateComma( + rewrittenNode, new TIntermSymbol(returnVariable), mShaderVersion); + } + + queueReplacement(rewrittenNode, OriginalNode::IS_DROPPED); + } +} + +const TVariable *RewriteAtomicFunctionExpressionsTraverser::getTempVariable(const TType *type) +{ + TIntermDeclaration *variableDeclaration; + TVariable *returnVariable = + DeclareTempVariable(mSymbolTable, type, EvqTemporary, &variableDeclaration); + mTempVariables.push_back(variableDeclaration); + return returnVariable; +} + +bool RewriteAtomicFunctionExpressionsTraverser::IsAtomicExchangeOrCompSwapNoReturnValue( + TIntermAggregate *node, + TIntermNode *parentNode) +{ + ASSERT(node); + return (node->getOp() == EOpAtomicExchange || node->getOp() == EOpAtomicCompSwap) && + parentNode && parentNode->getAsBlock(); +} + +bool RewriteAtomicFunctionExpressionsTraverser::IsAtomicFunctionInsideExpression( + TIntermAggregate *node, + TIntermNode *parentNode) +{ + ASSERT(node); + // We only need to handle atomic functions with a parent that it is not block nodes. If the + // parent node is block, it means that the atomic function is not inside an expression. + if (!IsAtomicFunction(node->getOp()) || parentNode->getAsBlock()) + { + return false; + } + + auto *parentAsBinary = parentNode->getAsBinaryNode(); + // Assignments are handled in OutputHLSL + return !parentAsBinary || parentAsBinary->getOp() != EOpAssign; +} + +bool RewriteAtomicFunctionExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + ASSERT(visit == PostVisit); + // Skip atomic memory functions for SSBO. They will be processed in the OutputHLSL traverser. + if (IsAtomicFunction(node->getOp()) && + IsInShaderStorageBlock((*node->getSequence())[0]->getAsTyped())) + { + return false; + } + + TIntermNode *parentNode = getParentNode(); + if (IsAtomicExchangeOrCompSwapNoReturnValue(node, parentNode) || + IsAtomicFunctionInsideExpression(node, parentNode)) + { + rewriteAtomicFunctionCallNode(node); + } + + return true; +} + +bool RewriteAtomicFunctionExpressionsTraverser::visitBlock(Visit visit, TIntermBlock *node) +{ + ASSERT(visit == PostVisit); + + if (!mTempVariables.empty() && getParentNode()->getAsFunctionDefinition()) + { + insertStatementsInBlockAtPosition(node, 0, mTempVariables, TIntermSequence()); + mTempVariables.clear(); + } + + return true; +} + +} // anonymous namespace + +void RewriteAtomicFunctionExpressions(TIntermNode *root, + TSymbolTable *symbolTable, + int shaderVersion) +{ + RewriteAtomicFunctionExpressionsTraverser traverser(symbolTable, shaderVersion); + traverser.traverse(root); + traverser.updateTree(); +} +} // namespace sh
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h new file mode 100644 index 0000000000..a54440536e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteAtomicFunctionExpressions.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 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. +// +// RewriteAtomicFunctionExpressions rewrites the expressions that contain +// atomic function calls and cannot be directly translated into HLSL into +// several simple ones that can be easily handled in the HLSL translator. +// +// We need to rewite these expressions because: +// 1. All GLSL atomic functions have return values, which all represent the +// original value of the shared or ssbo variable; while all HLSL atomic +// functions don't, and the original value can be stored in the last +// parameter of the function call. +// 2. For HLSL atomic functions, the last parameter that stores the original +// value is optional except for InterlockedExchange and +// InterlockedCompareExchange. Missing original_value in the call of +// InterlockedExchange or InterlockedCompareExchange results in a compile +// error from HLSL compiler. +// +// RewriteAtomicFunctionExpressions is a function that can modify the AST +// to ensure all the expressions that contain atomic function calls can be +// directly translated into HLSL expressions. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITE_ATOMIC_FUNCTION_EXPRESSIONS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITE_ATOMIC_FUNCTION_EXPRESSIONS_H_ + +namespace sh +{ +class TIntermNode; +class TSymbolTable; + +void RewriteAtomicFunctionExpressions(TIntermNode *root, + TSymbolTable *symbolTable, + int shaderVersion); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITE_ATOMIC_FUNCTION_EXPRESSIONS_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp new file mode 100644 index 0000000000..80606e7844 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp @@ -0,0 +1,89 @@ +// +// 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. +// +// Implementation of dFdy viewport transformation. +// See header for more info. + +#include "compiler/translator/tree_ops/RewriteDfdy.h" + +#include "common/angleutils.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root, + const TSymbolTable &symbolTable, + TIntermBinary *viewportYScale); + + private: + Traverser(TIntermBinary *viewportYScale, TSymbolTable *symbolTable); + bool visitUnary(Visit visit, TIntermUnary *node) override; + + TIntermBinary *mViewportYScale = nullptr; +}; + +Traverser::Traverser(TIntermBinary *viewportYScale, TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), mViewportYScale(viewportYScale) +{} + +// static +void Traverser::Apply(TIntermNode *root, + const TSymbolTable &symbolTable, + TIntermBinary *viewportYScale) +{ + TSymbolTable *pSymbolTable = const_cast<TSymbolTable *>(&symbolTable); + Traverser traverser(viewportYScale, pSymbolTable); + root->traverse(&traverser); + traverser.updateTree(); +} + +bool Traverser::visitUnary(Visit visit, TIntermUnary *node) +{ + // Decide if the node represents a call to dFdy() + if (node->getOp() != EOpDFdy) + { + return true; + } + + // Copy the dFdy node so we can replace it with the corrected value + TIntermUnary *newDfdy = node->deepCopy()->getAsUnaryNode(); + + size_t objectSize = node->getType().getObjectSize(); + TOperator multiplyOp = (objectSize == 1) ? EOpMul : EOpVectorTimesScalar; + + // Correct dFdy()'s value: + // (dFdy() * ANGLEUniforms.viewportYScale) + TIntermBinary *correctedDfdy = new TIntermBinary(multiplyOp, newDfdy, mViewportYScale); + + // Replace the old dFdy node with the new node that contains the corrected value + queueReplacement(correctedDfdy, OriginalNode::IS_DROPPED); + + return true; +} + +} // anonymous namespace + +void RewriteDfdy(TIntermNode *root, + const TSymbolTable &symbolTable, + int shaderVersion, + TIntermBinary *viewportYScale) +{ + // dFdy is only valid in GLSL 3.0 and later. + if (shaderVersion < 300) + return; + + Traverser::Apply(root, symbolTable, viewportYScale); +} + +} // namespace sh
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.h new file mode 100644 index 0000000000..299d3652f9 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.h @@ -0,0 +1,30 @@ +// +// 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. +// +// This mutating tree traversal flips the output of dFdy() to account for framebuffer flipping. +// +// From: dFdy(p) +// To: (dFdy(p) * viewportYScale) +// +// See http://anglebug.com/3487 + +#ifndef COMPILER_TRANSLATOR_TREEOPS_FLIP_DFDY_H_ +#define COMPILER_TRANSLATOR_TREEOPS_FLIP_DFDY_H_ + +class TIntermNode; +class TIntermBinary; +class TSymbolTable; + +namespace sh +{ + +void RewriteDfdy(TIntermNode *root, + const TSymbolTable &symbolTable, + int shaderVersion, + TIntermBinary *viewportYScale); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_FLIP_DFDY_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp new file mode 100644 index 0000000000..7956322a5a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2015 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. +// + +// RewriteDoWhile.cpp: rewrites do-while loops using another equivalent +// construct. + +#include "compiler/translator/tree_ops/RewriteDoWhile.h" + +#include "compiler/translator/StaticType.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// An AST traverser that rewrites loops of the form +// do { +// CODE; +// } while (CONDITION) +// +// to loops of the form +// bool temp = false; +// while (true) { +// if (temp) { +// if (!CONDITION) { +// break; +// } +// } +// temp = true; +// CODE; +// } +// +// The reason we don't use a simpler form, with for example just (temp && !CONDITION) in the +// while condition, is that short-circuit is often badly supported by driver shader compiler. +// The double if has the same effect, but forces shader compilers to behave. +// +// TODO(cwallez) when UnfoldShortCircuitIntoIf handles loops correctly, revisit this as we might +// be able to use while (temp || CONDITION) with temp initially set to true then run +// UnfoldShortCircuitIntoIf +class DoWhileRewriter : public TIntermTraverser +{ + public: + DoWhileRewriter(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable) + {} + + bool visitBlock(Visit, TIntermBlock *node) override + { + // A well-formed AST can only have do-while inside TIntermBlock. By doing a prefix traversal + // we are able to replace the do-while in the sequence directly as the content of the + // do-while will be traversed later. + + TIntermSequence *statements = node->getSequence(); + + // The statements vector will have new statements inserted when we encounter a do-while, + // which prevents us from using a range-based for loop. Using the usual i++ works, as + // the (two) new statements inserted replace the statement at the current position. + for (size_t i = 0; i < statements->size(); i++) + { + TIntermNode *statement = (*statements)[i]; + TIntermLoop *loop = statement->getAsLoopNode(); + + if (loop == nullptr || loop->getType() != ELoopDoWhile) + { + continue; + } + + // Found a loop to change. + const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>(); + TVariable *conditionVariable = CreateTempVariable(mSymbolTable, boolType); + + // bool temp = false; + TIntermDeclaration *tempDeclaration = + CreateTempInitDeclarationNode(conditionVariable, CreateBoolNode(false)); + + // temp = true; + TIntermBinary *assignTrue = + CreateTempAssignmentNode(conditionVariable, CreateBoolNode(true)); + + // if (temp) { + // if (!CONDITION) { + // break; + // } + // } + TIntermIfElse *breakIf = nullptr; + { + TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr); + + TIntermBlock *breakBlock = new TIntermBlock(); + breakBlock->getSequence()->push_back(breakStatement); + + TIntermUnary *negatedCondition = + new TIntermUnary(EOpLogicalNot, loop->getCondition(), nullptr); + + TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr); + + TIntermBlock *innerIfBlock = new TIntermBlock(); + innerIfBlock->getSequence()->push_back(innerIf); + + breakIf = new TIntermIfElse(CreateTempSymbolNode(conditionVariable), innerIfBlock, + nullptr); + } + + // Assemble the replacement loops, reusing the do-while loop's body and inserting our + // statements at the front. + TIntermLoop *newLoop = nullptr; + { + TIntermBlock *body = loop->getBody(); + if (body == nullptr) + { + body = new TIntermBlock(); + } + auto sequence = body->getSequence(); + sequence->insert(sequence->begin(), assignTrue); + sequence->insert(sequence->begin(), breakIf); + + newLoop = new TIntermLoop(ELoopWhile, nullptr, CreateBoolNode(true), nullptr, body); + } + + TIntermSequence replacement; + replacement.push_back(tempDeclaration); + replacement.push_back(newLoop); + + node->replaceChildNodeWithMultiple(loop, replacement); + } + return true; + } +}; + +} // anonymous namespace + +void RewriteDoWhile(TIntermNode *root, TSymbolTable *symbolTable) +{ + DoWhileRewriter rewriter(symbolTable); + + root->traverse(&rewriter); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h new file mode 100644 index 0000000000..c91d7deb06 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2015 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. +// + +// RewriteDoWhile.h: rewrite do-while loops as while loops to work around +// driver bugs + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEDOWHILE_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITEDOWHILE_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void RewriteDoWhile(TIntermNode *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEDOWHILE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp new file mode 100644 index 0000000000..701e29aa9d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp @@ -0,0 +1,120 @@ +// +// Copyright (c) 2014 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. +// +// RewriteElseBlocks.cpp: Implementation for tree transform to change +// all if-else blocks to if-if blocks. +// + +#include "compiler/translator/tree_ops/RewriteElseBlocks.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/NodeSearch.h" + +namespace sh +{ + +namespace +{ + +class ElseBlockRewriter : public TIntermTraverser +{ + public: + ElseBlockRewriter(TSymbolTable *symbolTable); + + protected: + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override; + bool visitBlock(Visit visit, TIntermBlock *block) override; + + private: + TIntermNode *rewriteIfElse(TIntermIfElse *ifElse); + + const TType *mFunctionType; +}; + +ElseBlockRewriter::ElseBlockRewriter(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mFunctionType(nullptr) +{} + +bool ElseBlockRewriter::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) +{ + // Store the current function context (see comment below) + mFunctionType = ((visit == PreVisit) ? &node->getFunctionPrototype()->getType() : nullptr); + return true; +} + +bool ElseBlockRewriter::visitBlock(Visit visit, TIntermBlock *node) +{ + if (visit == PostVisit) + { + for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); + statementIndex++) + { + TIntermNode *statement = (*node->getSequence())[statementIndex]; + TIntermIfElse *ifElse = statement->getAsIfElseNode(); + if (ifElse && ifElse->getFalseBlock() != nullptr) + { + (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse); + } + } + } + return true; +} + +TIntermNode *ElseBlockRewriter::rewriteIfElse(TIntermIfElse *ifElse) +{ + ASSERT(ifElse != nullptr); + + TIntermDeclaration *storeCondition = nullptr; + TVariable *conditionVariable = + DeclareTempVariable(mSymbolTable, ifElse->getCondition(), EvqTemporary, &storeCondition); + + TIntermBlock *falseBlock = nullptr; + + TType boolType(EbtBool, EbpUndefined, EvqTemporary); + + if (ifElse->getFalseBlock()) + { + TIntermBlock *negatedElse = nullptr; + // crbug.com/346463 + // D3D generates error messages claiming a function has no return value, when rewriting + // an if-else clause that returns something non-void in a function. By appending dummy + // returns (that are unreachable) we can silence this compile error. + if (mFunctionType && mFunctionType->getBasicType() != EbtVoid) + { + TIntermNode *returnNode = new TIntermBranch(EOpReturn, CreateZeroNode(*mFunctionType)); + negatedElse = new TIntermBlock(); + negatedElse->appendStatement(returnNode); + } + + TIntermSymbol *conditionSymbolElse = CreateTempSymbolNode(conditionVariable); + TIntermUnary *negatedCondition = + new TIntermUnary(EOpLogicalNot, conditionSymbolElse, nullptr); + TIntermIfElse *falseIfElse = + new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse); + falseBlock = EnsureBlock(falseIfElse); + } + + TIntermSymbol *conditionSymbolSel = CreateTempSymbolNode(conditionVariable); + TIntermIfElse *newIfElse = + new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock); + + TIntermBlock *block = new TIntermBlock(); + block->getSequence()->push_back(storeCondition); + block->getSequence()->push_back(newIfElse); + + return block; +} + +} // anonymous namespace + +void RewriteElseBlocks(TIntermNode *node, TSymbolTable *symbolTable) +{ + ElseBlockRewriter rewriter(symbolTable); + node->traverse(&rewriter); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h new file mode 100644 index 0000000000..3ae3b4a710 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2014 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. +// +// RewriteElseBlocks.h: Prototype for tree transform to change +// all if-else blocks to if-if blocks. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEELSEBLOCKS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITEELSEBLOCKS_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void RewriteElseBlocks(TIntermNode *node, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEELSEBLOCKS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp new file mode 100644 index 0000000000..9228f5b4ec --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.cpp @@ -0,0 +1,411 @@ +// +// 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. +// +// RewriteExpressionsWithShaderStorageBlock rewrites the expressions that contain shader storage +// block calls into several simple ones that can be easily handled in the HLSL translator. After the +// AST pass, all ssbo related blocks will be like below: +// ssbo_access_chain = ssbo_access_chain; +// ssbo_access_chain = expr_no_ssbo; +// lvalue_no_ssbo = ssbo_access_chain; +// + +#include "compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h" + +#include "compiler/translator/Symbol.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" +#include "compiler/translator/util.h" + +namespace sh +{ +namespace +{ + +bool IsIncrementOrDecrementOperator(TOperator op) +{ + switch (op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + return true; + default: + return false; + } +} + +bool IsCompoundAssignment(TOperator op) +{ + switch (op) + { + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + return true; + default: + return false; + } +} + +// EOpIndexDirect, EOpIndexIndirect, EOpIndexDirectStruct, EOpIndexDirectInterfaceBlock belong to +// operators in SSBO access chain. +bool IsReadonlyBinaryOperatorNotInSSBOAccessChain(TOperator op) +{ + switch (op) + { + case EOpComma: + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesMatrix: + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + return true; + default: + return false; + } +} + +bool HasSSBOAsFunctionArgument(TIntermSequence *arguments) +{ + for (TIntermNode *arg : *arguments) + { + TIntermTyped *typedArg = arg->getAsTyped(); + if (IsInShaderStorageBlock(typedArg)) + { + return true; + } + } + return false; +} + +class RewriteExpressionsWithShaderStorageBlockTraverser : public TIntermTraverser +{ + public: + RewriteExpressionsWithShaderStorageBlockTraverser(TSymbolTable *symbolTable); + void nextIteration(); + bool foundSSBO() const { return mFoundSSBO; } + + private: + bool visitBinary(Visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitUnary(Visit visit, TIntermUnary *node) override; + + TIntermSymbol *insertInitStatementAndReturnTempSymbol(TIntermTyped *node, + TIntermSequence *insertions); + + bool mFoundSSBO; +}; + +RewriteExpressionsWithShaderStorageBlockTraverser:: + RewriteExpressionsWithShaderStorageBlockTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, true, false, symbolTable), mFoundSSBO(false) +{} + +TIntermSymbol * +RewriteExpressionsWithShaderStorageBlockTraverser::insertInitStatementAndReturnTempSymbol( + TIntermTyped *node, + TIntermSequence *insertions) +{ + TIntermDeclaration *variableDeclaration; + TVariable *tempVariable = + DeclareTempVariable(mSymbolTable, node, EvqTemporary, &variableDeclaration); + + insertions->push_back(variableDeclaration); + return CreateTempSymbolNode(tempVariable); +} + +bool RewriteExpressionsWithShaderStorageBlockTraverser::visitBinary(Visit visit, + TIntermBinary *node) +{ + // Make sure that the expression is caculated from left to right. + if (visit != InVisit) + { + return true; + } + + if (mFoundSSBO) + { + return false; + } + + bool rightSSBO = IsInShaderStorageBlock(node->getRight()); + bool leftSSBO = IsInShaderStorageBlock(node->getLeft()); + if (!leftSSBO && !rightSSBO) + { + return true; + } + + // case 1: Compound assigment operator + // original: + // lssbo += expr; + // new: + // var rvalue = expr; + // var temp = lssbo; + // temp += rvalue; + // lssbo = temp; + // + // original: + // lvalue_no_ssbo += rssbo; + // new: + // var rvalue = rssbo; + // lvalue_no_ssbo += rvalue; + if (IsCompoundAssignment(node->getOp())) + { + mFoundSSBO = true; + TIntermSequence insertions; + TIntermTyped *rightNode = + insertInitStatementAndReturnTempSymbol(node->getRight(), &insertions); + if (leftSSBO) + { + TIntermSymbol *tempSymbol = + insertInitStatementAndReturnTempSymbol(node->getLeft()->deepCopy(), &insertions); + TIntermBinary *tempCompoundOperate = + new TIntermBinary(node->getOp(), tempSymbol->deepCopy(), rightNode->deepCopy()); + insertions.push_back(tempCompoundOperate); + insertStatementsInParentBlock(insertions); + + TIntermBinary *assignTempValueToSSBO = + new TIntermBinary(EOpAssign, node->getLeft(), tempSymbol->deepCopy()); + queueReplacement(assignTempValueToSSBO, OriginalNode::IS_DROPPED); + } + else + { + insertStatementsInParentBlock(insertions); + TIntermBinary *compoundAssignRValueToLValue = + new TIntermBinary(node->getOp(), node->getLeft(), rightNode->deepCopy()); + queueReplacement(compoundAssignRValueToLValue, OriginalNode::IS_DROPPED); + } + } + // case 2: Readonly binary operator + // original: + // ssbo0 + ssbo1 + ssbo2; + // new: + // var temp0 = ssbo0; + // var temp1 = ssbo1; + // var temp2 = ssbo2; + // temp0 + temp1 + temp2; + else if (IsReadonlyBinaryOperatorNotInSSBOAccessChain(node->getOp()) && (leftSSBO || rightSSBO)) + { + mFoundSSBO = true; + TIntermTyped *rightNode = node->getRight(); + TIntermTyped *leftNode = node->getLeft(); + TIntermSequence insertions; + if (rightSSBO) + { + rightNode = insertInitStatementAndReturnTempSymbol(node->getRight(), &insertions); + } + if (leftSSBO) + { + leftNode = insertInitStatementAndReturnTempSymbol(node->getLeft(), &insertions); + } + + insertStatementsInParentBlock(insertions); + TIntermBinary *newExpr = + new TIntermBinary(node->getOp(), leftNode->deepCopy(), rightNode->deepCopy()); + queueReplacement(newExpr, OriginalNode::IS_DROPPED); + } + return !mFoundSSBO; +} + +// case 3: ssbo as the argument of aggregate type +// original: +// foo(ssbo); +// new: +// var tempArg = ssbo; +// foo(tempArg); +// ssbo = tempArg; (Optional based on whether ssbo is an out|input argument) +// +// original: +// foo(ssbo) * expr; +// new: +// var tempArg = ssbo; +// var tempReturn = foo(tempArg); +// ssbo = tempArg; (Optional based on whether ssbo is an out|input argument) +// tempReturn * expr; +bool RewriteExpressionsWithShaderStorageBlockTraverser::visitAggregate(Visit visit, + TIntermAggregate *node) +{ + // Make sure that visitAggregate is only executed once for same node. + if (visit != PreVisit) + { + return true; + } + + if (mFoundSSBO) + { + return false; + } + + // We still need to process the ssbo as the non-first argument of atomic memory functions. + if (IsAtomicFunction(node->getOp()) && + IsInShaderStorageBlock((*node->getSequence())[0]->getAsTyped())) + { + return true; + } + + if (!HasSSBOAsFunctionArgument(node->getSequence())) + { + return true; + } + + mFoundSSBO = true; + TIntermSequence insertions; + TIntermSequence readBackToSSBOs; + TIntermSequence *originalArguments = node->getSequence(); + for (size_t i = 0; i < node->getChildCount(); ++i) + { + TIntermTyped *ssboArgument = (*originalArguments)[i]->getAsTyped(); + if (IsInShaderStorageBlock(ssboArgument)) + { + TIntermSymbol *argumentCopy = + insertInitStatementAndReturnTempSymbol(ssboArgument, &insertions); + if (node->getFunction() != nullptr) + { + TQualifier qual = node->getFunction()->getParam(i)->getType().getQualifier(); + if (qual == EvqInOut || qual == EvqOut) + { + TIntermBinary *readBackToSSBO = new TIntermBinary( + EOpAssign, ssboArgument->deepCopy(), argumentCopy->deepCopy()); + readBackToSSBOs.push_back(readBackToSSBO); + } + } + node->replaceChildNode(ssboArgument, argumentCopy); + } + } + + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + if (parentBlock) + { + // Aggregate node is as a single sentence. + insertions.push_back(node); + if (!readBackToSSBOs.empty()) + { + insertions.insert(insertions.end(), readBackToSSBOs.begin(), readBackToSSBOs.end()); + } + mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentBlock, node, insertions)); + } + else + { + // Aggregate node is inside an expression. + TIntermSymbol *tempSymbol = insertInitStatementAndReturnTempSymbol(node, &insertions); + if (!readBackToSSBOs.empty()) + { + insertions.insert(insertions.end(), readBackToSSBOs.begin(), readBackToSSBOs.end()); + } + insertStatementsInParentBlock(insertions); + queueReplacement(tempSymbol->deepCopy(), OriginalNode::IS_DROPPED); + } + + return false; +} + +bool RewriteExpressionsWithShaderStorageBlockTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFoundSSBO) + { + return false; + } + + if (!IsInShaderStorageBlock(node->getOperand())) + { + return true; + } + + // .length() is processed in OutputHLSL. + if (node->getOp() == EOpArrayLength) + { + return true; + } + + mFoundSSBO = true; + + // case 4: ssbo as the operand of ++/-- + // original: + // ++ssbo * expr; + // new: + // var temp1 = ssbo; + // var temp2 = ++temp1; + // ssbo = temp1; + // temp2 * expr; + if (IsIncrementOrDecrementOperator(node->getOp())) + { + TIntermSequence insertions; + TIntermSymbol *temp1 = + insertInitStatementAndReturnTempSymbol(node->getOperand(), &insertions); + TIntermUnary *newUnary = new TIntermUnary(node->getOp(), temp1->deepCopy(), nullptr); + TIntermSymbol *temp2 = insertInitStatementAndReturnTempSymbol(newUnary, &insertions); + TIntermBinary *readBackToSSBO = + new TIntermBinary(EOpAssign, node->getOperand()->deepCopy(), temp1->deepCopy()); + insertions.push_back(readBackToSSBO); + insertStatementsInParentBlock(insertions); + queueReplacement(temp2->deepCopy(), OriginalNode::IS_DROPPED); + } + // case 5: ssbo as the operand of readonly unary operator + // original: + // ~ssbo * expr; + // new: + // var temp = ssbo; + // ~temp * expr; + else + { + TIntermSequence insertions; + TIntermSymbol *temp = + insertInitStatementAndReturnTempSymbol(node->getOperand(), &insertions); + insertStatementsInParentBlock(insertions); + node->replaceChildNode(node->getOperand(), temp->deepCopy()); + } + return false; +} + +void RewriteExpressionsWithShaderStorageBlockTraverser::nextIteration() +{ + mFoundSSBO = false; +} + +} // anonymous namespace + +void RewriteExpressionsWithShaderStorageBlock(TIntermNode *root, TSymbolTable *symbolTable) +{ + RewriteExpressionsWithShaderStorageBlockTraverser traverser(symbolTable); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundSSBO()) + traverser.updateTree(); + } while (traverser.foundSSBO()); +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h new file mode 100644 index 0000000000..957552e6fd --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteExpressionsWithShaderStorageBlock.h @@ -0,0 +1,32 @@ +// +// 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. +// +// RewriteExpressionsWithShaderStorageBlock rewrites the expressions that contain shader storage +// block calls into several simple ones that can be easily handled in the HLSL translator. After the +// AST pass, all ssbo related blocks will be like below: +// ssbo_access_chain = ssbo_access_chain; +// ssbo_access_chain = expr_no_ssbo; +// lvalue_no_ssbo = ssbo_access_chain; +// +// Below situations are needed to be rewritten (Details can be found in .cpp file). +// SSBO as the operand of compound assignment operators. +// SSBO as the operand of ++/--. +// SSBO as the operand of repeated assignment. +// SSBO as the operand of readonly unary/binary/ternary operators. +// SSBO as the argument of aggregate type. +// SSBO as the condition of if/switch/while/do-while/for + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_ + +namespace sh +{ +class TIntermNode; +class TSymbolTable; + +void RewriteExpressionsWithShaderStorageBlock(TIntermNode *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITE_EXPRESSIONS_WITH_SHADER_STORAGE_BLOCK_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp new file mode 100644 index 0000000000..3cc670e688 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.cpp @@ -0,0 +1,92 @@ +// +// Copyright (c) 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/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: + static void rewrite(TIntermBlock *root); + + private: + RewriteAssignToSwizzledTraverser(); + + bool visitBinary(Visit, TIntermBinary *node) override; + + void nextIteration(); + + bool didRewrite() { return mDidRewrite; } + + bool mDidRewrite; +}; + +// static +void RewriteAssignToSwizzledTraverser::rewrite(TIntermBlock *root) +{ + RewriteAssignToSwizzledTraverser rewrite; + do + { + rewrite.nextIteration(); + root->traverse(&rewrite); + rewrite.updateTree(); + } while (rewrite.didRewrite()); +} + +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.push_back(NodeReplaceWithMultipleEntry(parentBlock, node, replacements)); + mDidRewrite = true; + return false; + } + return true; +} + +} // anonymous namespace + +void RewriteRepeatedAssignToSwizzled(TIntermBlock *root) +{ + RewriteAssignToSwizzledTraverser::rewrite(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h new file mode 100644 index 0000000000..2f2d3b9f80 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 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_REWRITEREPEATEDASSIGNTOSWIZZLED_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITEREPEATEDASSIGNTOSWIZZLED_H_ + +namespace sh +{ + +class TIntermBlock; + +void RewriteRepeatedAssignToSwizzled(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEREPEATEDASSIGNTOSWIZZLED_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp new file mode 100644 index 0000000000..8d5bdd0bae --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp @@ -0,0 +1,699 @@ +// +// 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. +// +// RewriteStructSamplers: Extract structs from samplers. +// + +#include "compiler/translator/tree_ops/RewriteStructSamplers.h" + +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ +namespace +{ +// Helper method to get the sampler extracted struct type of a parameter. +TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable ¶m) +{ + const TStructure *structure = param.getType().getStruct(); + const TSymbol *structSymbol = symbolTable->findUserDefined(structure->name()); + ASSERT(structSymbol && structSymbol->isStruct()); + const TStructure *structVar = static_cast<const TStructure *>(structSymbol); + TType *structType = new TType(structVar, false); + + if (param.getType().isArray()) + { + structType->makeArrays(*param.getType().getArraySizes()); + } + + ASSERT(!structType->isStructureContainingSamplers()); + + return structType; +} + +TIntermSymbol *ReplaceTypeOfSymbolNode(TIntermSymbol *symbolNode, TSymbolTable *symbolTable) +{ + const TVariable &oldVariable = symbolNode->variable(); + + TType *newType = GetStructSamplerParameterType(symbolTable, oldVariable); + + TVariable *newVariable = + new TVariable(oldVariable.uniqueId(), oldVariable.name(), oldVariable.symbolType(), + oldVariable.extension(), newType); + return new TIntermSymbol(newVariable); +} + +TIntermTyped *ReplaceTypeOfTypedStructNode(TIntermTyped *argument, TSymbolTable *symbolTable) +{ + TIntermSymbol *asSymbol = argument->getAsSymbolNode(); + if (asSymbol) + { + ASSERT(asSymbol->getType().getStruct()); + return ReplaceTypeOfSymbolNode(asSymbol, symbolTable); + } + + TIntermTyped *replacement = argument->deepCopy(); + TIntermBinary *binary = replacement->getAsBinaryNode(); + ASSERT(binary); + + while (binary) + { + ASSERT(binary->getOp() == EOpIndexDirectStruct || binary->getOp() == EOpIndexDirect); + + asSymbol = binary->getLeft()->getAsSymbolNode(); + + if (asSymbol) + { + ASSERT(asSymbol->getType().getStruct()); + TIntermSymbol *newSymbol = ReplaceTypeOfSymbolNode(asSymbol, symbolTable); + binary->replaceChildNode(binary->getLeft(), newSymbol); + return replacement; + } + + binary = binary->getLeft()->getAsBinaryNode(); + } + + UNREACHABLE(); + return nullptr; +} + +// Maximum string size of a hex unsigned int. +constexpr size_t kHexSize = ImmutableStringBuilder::GetHexCharCount<unsigned int>(); + +class Traverser final : public TIntermTraverser +{ + public: + explicit Traverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), mRemovedUniformsCount(0) + { + mSymbolTable->push(); + } + + ~Traverser() override { mSymbolTable->pop(); } + + int removedUniformsCount() const { return mRemovedUniformsCount; } + + // Each struct sampler declaration is stripped of its samplers. New uniforms are added for each + // stripped struct sampler. + bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override + { + if (visit != PreVisit) + return true; + + if (!mInGlobalScope) + { + return true; + } + + const TIntermSequence &sequence = *(decl->getSequence()); + TIntermTyped *declarator = sequence.front()->getAsTyped(); + const TType &type = declarator->getType(); + + if (type.isStructureContainingSamplers()) + { + TIntermSequence *newSequence = new TIntermSequence; + + if (type.isStructSpecifier()) + { + stripStructSpecifierSamplers(type.getStruct(), newSequence); + } + else + { + TIntermSymbol *asSymbol = declarator->getAsSymbolNode(); + ASSERT(asSymbol); + const TVariable &variable = asSymbol->variable(); + ASSERT(variable.symbolType() != SymbolType::Empty); + extractStructSamplerUniforms(decl, variable, type.getStruct(), newSequence); + } + + mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl, *newSequence); + } + + return true; + } + + // Each struct sampler reference is replaced with a reference to the new extracted sampler. + bool visitBinary(Visit visit, TIntermBinary *node) override + { + if (visit != PreVisit) + return true; + + if (node->getOp() == EOpIndexDirectStruct && node->getType().isSampler()) + { + ImmutableString newName = GetStructSamplerNameFromTypedNode(node); + const TVariable *samplerReplacement = + static_cast<const TVariable *>(mSymbolTable->findUserDefined(newName)); + ASSERT(samplerReplacement); + + TIntermSymbol *replacement = new TIntermSymbol(samplerReplacement); + + queueReplacement(replacement, OriginalNode::IS_DROPPED); + return true; + } + + return true; + } + + // In we are passing references to structs containing samplers we must new additional + // arguments. For each extracted struct sampler a new argument is added. This chains to nested + // structs. + void visitFunctionPrototype(TIntermFunctionPrototype *node) override + { + const TFunction *function = node->getFunction(); + + if (!function->hasSamplerInStructParams()) + { + return; + } + + const TSymbol *foundFunction = mSymbolTable->findUserDefined(function->name()); + if (foundFunction) + { + ASSERT(foundFunction->isFunction()); + function = static_cast<const TFunction *>(foundFunction); + } + else + { + TFunction *newFunction = createStructSamplerFunction(function); + mSymbolTable->declareUserDefinedFunction(newFunction, true); + function = newFunction; + } + + ASSERT(!function->hasSamplerInStructParams()); + TIntermFunctionPrototype *newProto = new TIntermFunctionPrototype(function); + queueReplacement(newProto, OriginalNode::IS_DROPPED); + } + + // We insert a new scope for each function definition so we can track the new parameters. + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override + { + if (visit == PreVisit) + { + mSymbolTable->push(); + } + else + { + ASSERT(visit == PostVisit); + mSymbolTable->pop(); + } + return true; + } + + // For function call nodes we pass references to the extracted struct samplers in that scope. + bool visitAggregate(Visit visit, TIntermAggregate *node) override + { + if (visit != PreVisit) + return true; + + if (!node->isFunctionCall()) + return true; + + const TFunction *function = node->getFunction(); + if (!function->hasSamplerInStructParams()) + return true; + + ASSERT(node->getOp() == EOpCallFunctionInAST); + TFunction *newFunction = mSymbolTable->findUserDefinedFunction(function->name()); + TIntermSequence *newArguments = getStructSamplerArguments(function, node->getSequence()); + + TIntermAggregate *newCall = + TIntermAggregate::CreateFunctionCall(*newFunction, newArguments); + queueReplacement(newCall, OriginalNode::IS_DROPPED); + return true; + } + + private: + // This returns the name of a struct sampler reference. References are always TIntermBinary. + static ImmutableString GetStructSamplerNameFromTypedNode(TIntermTyped *node) + { + std::string stringBuilder; + + TIntermTyped *currentNode = node; + while (currentNode->getAsBinaryNode()) + { + TIntermBinary *asBinary = currentNode->getAsBinaryNode(); + + switch (asBinary->getOp()) + { + case EOpIndexDirect: + { + const int index = asBinary->getRight()->getAsConstantUnion()->getIConst(0); + const std::string strInt = Str(index); + stringBuilder.insert(0, strInt); + stringBuilder.insert(0, "_"); + break; + } + case EOpIndexDirectStruct: + { + stringBuilder.insert(0, asBinary->getIndexStructFieldName().data()); + stringBuilder.insert(0, "_"); + break; + } + + default: + UNREACHABLE(); + break; + } + + currentNode = asBinary->getLeft(); + } + + const ImmutableString &variableName = currentNode->getAsSymbolNode()->variable().name(); + stringBuilder.insert(0, variableName.data()); + + return stringBuilder; + } + + // Removes all the struct samplers from a struct specifier. + void stripStructSpecifierSamplers(const TStructure *structure, TIntermSequence *newSequence) + { + TFieldList *newFieldList = new TFieldList; + ASSERT(structure->containsSamplers()); + + for (const TField *field : structure->fields()) + { + const TType &fieldType = *field->type(); + if (!fieldType.isSampler() && !isRemovedStructType(fieldType)) + { + TType *newType = nullptr; + + if (fieldType.isStructureContainingSamplers()) + { + const TSymbol *structSymbol = + mSymbolTable->findUserDefined(fieldType.getStruct()->name()); + ASSERT(structSymbol && structSymbol->isStruct()); + const TStructure *fieldStruct = static_cast<const TStructure *>(structSymbol); + newType = new TType(fieldStruct, true); + if (fieldType.isArray()) + { + newType->makeArrays(*fieldType.getArraySizes()); + } + } + else + { + newType = new TType(fieldType); + } + + TField *newField = + new TField(newType, field->name(), field->line(), field->symbolType()); + newFieldList->push_back(newField); + } + } + + // Prune empty structs. + if (newFieldList->empty()) + { + mRemovedStructs.insert(structure->name()); + return; + } + + TStructure *newStruct = + new TStructure(mSymbolTable, structure->name(), newFieldList, structure->symbolType()); + TType *newStructType = new TType(newStruct, true); + TVariable *newStructVar = + new TVariable(mSymbolTable, kEmptyImmutableString, newStructType, SymbolType::Empty); + TIntermSymbol *newStructRef = new TIntermSymbol(newStructVar); + + TIntermDeclaration *structDecl = new TIntermDeclaration; + structDecl->appendDeclarator(newStructRef); + + newSequence->push_back(structDecl); + + mSymbolTable->declare(newStruct); + } + + // Returns true if the type is a struct that was removed because we extracted all the members. + bool isRemovedStructType(const TType &type) const + { + const TStructure *structure = type.getStruct(); + return (structure && (mRemovedStructs.count(structure->name()) > 0)); + } + + // Removes samplers from struct uniforms. For each sampler removed also adds a new globally + // defined sampler uniform. + void extractStructSamplerUniforms(TIntermDeclaration *oldDeclaration, + const TVariable &variable, + const TStructure *structure, + TIntermSequence *newSequence) + { + ASSERT(structure->containsSamplers()); + + size_t nonSamplerCount = 0; + + for (const TField *field : structure->fields()) + { + nonSamplerCount += + extractFieldSamplers(variable.name(), field, variable.getType(), newSequence); + } + + if (nonSamplerCount > 0) + { + // Keep the old declaration around if it has other members. + newSequence->push_back(oldDeclaration); + } + else + { + mRemovedUniformsCount++; + } + } + + // Extracts samplers from a field of a struct. Works with nested structs and arrays. + size_t extractFieldSamplers(const ImmutableString &prefix, + const TField *field, + const TType &containingType, + TIntermSequence *newSequence) + { + if (containingType.isArray()) + { + size_t nonSamplerCount = 0; + + // Name the samplers internally as varName_<index>_fieldName + const TVector<unsigned int> &arraySizes = *containingType.getArraySizes(); + for (unsigned int arrayElement = 0; arrayElement < arraySizes[0]; ++arrayElement) + { + ImmutableStringBuilder stringBuilder(prefix.length() + kHexSize + 1); + stringBuilder << prefix << "_"; + stringBuilder.appendHex(arrayElement); + nonSamplerCount = extractFieldSamplersImpl(stringBuilder, field, newSequence); + } + + return nonSamplerCount; + } + + return extractFieldSamplersImpl(prefix, field, newSequence); + } + + // Extracts samplers from a field of a struct. Works with nested structs and arrays. + size_t extractFieldSamplersImpl(const ImmutableString &prefix, + const TField *field, + TIntermSequence *newSequence) + { + size_t nonSamplerCount = 0; + + const TType &fieldType = *field->type(); + if (fieldType.isSampler() || fieldType.isStructureContainingSamplers()) + { + ImmutableStringBuilder stringBuilder(prefix.length() + field->name().length() + 1); + stringBuilder << prefix << "_" << field->name(); + ImmutableString newPrefix(stringBuilder); + + if (fieldType.isSampler()) + { + extractSampler(newPrefix, fieldType, newSequence); + } + else + { + const TStructure *structure = fieldType.getStruct(); + for (const TField *nestedField : structure->fields()) + { + nonSamplerCount += + extractFieldSamplers(newPrefix, nestedField, fieldType, newSequence); + } + } + } + else + { + nonSamplerCount++; + } + + return nonSamplerCount; + } + + // Extracts a sampler from a struct. Declares the new extracted sampler. + void extractSampler(const ImmutableString &newName, + const TType &fieldType, + TIntermSequence *newSequence) const + { + TType *newType = new TType(fieldType); + newType->setQualifier(EvqUniform); + TVariable *newVariable = + new TVariable(mSymbolTable, newName, newType, SymbolType::AngleInternal); + TIntermSymbol *newRef = new TIntermSymbol(newVariable); + + TIntermDeclaration *samplerDecl = new TIntermDeclaration; + samplerDecl->appendDeclarator(newRef); + + newSequence->push_back(samplerDecl); + + mSymbolTable->declareInternal(newVariable); + } + + // Returns the chained name of a sampler uniform field. + static ImmutableString GetFieldName(const ImmutableString ¶mName, + const TField *field, + unsigned arrayIndex) + { + ImmutableStringBuilder nameBuilder(paramName.length() + kHexSize + 2 + + field->name().length()); + nameBuilder << paramName << "_"; + + if (arrayIndex < std::numeric_limits<unsigned>::max()) + { + nameBuilder.appendHex(arrayIndex); + nameBuilder << "_"; + } + nameBuilder << field->name(); + + return nameBuilder; + } + + // A pattern that visits every parameter of a function call. Uses different handlers for struct + // parameters, struct sampler parameters, and non-struct parameters. + class StructSamplerFunctionVisitor : angle::NonCopyable + { + public: + StructSamplerFunctionVisitor() = default; + virtual ~StructSamplerFunctionVisitor() = default; + + virtual void traverse(const TFunction *function) + { + size_t paramCount = function->getParamCount(); + + for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex) + { + const TVariable *param = function->getParam(paramIndex); + const TType ¶mType = param->getType(); + + if (paramType.isStructureContainingSamplers()) + { + const ImmutableString &baseName = getNameFromIndex(function, paramIndex); + if (traverseStructContainingSamplers(baseName, paramType)) + { + visitStructParam(function, paramIndex); + } + } + else + { + visitNonStructParam(function, paramIndex); + } + } + } + + virtual ImmutableString getNameFromIndex(const TFunction *function, size_t paramIndex) = 0; + virtual void visitSamplerInStructParam(const ImmutableString &name, + const TField *field) = 0; + virtual void visitStructParam(const TFunction *function, size_t paramIndex) = 0; + virtual void visitNonStructParam(const TFunction *function, size_t paramIndex) = 0; + + private: + bool traverseStructContainingSamplers(const ImmutableString &baseName, + const TType &structType) + { + bool hasNonSamplerFields = false; + const TStructure *structure = structType.getStruct(); + for (const TField *field : structure->fields()) + { + if (field->type()->isStructureContainingSamplers() || field->type()->isSampler()) + { + if (traverseSamplerInStruct(baseName, structType, field)) + { + hasNonSamplerFields = true; + } + } + else + { + hasNonSamplerFields = true; + } + } + return hasNonSamplerFields; + } + + bool traverseSamplerInStruct(const ImmutableString &baseName, + const TType &baseType, + const TField *field) + { + bool hasNonSamplerParams = false; + + if (baseType.isArray()) + { + const TVector<unsigned int> &arraySizes = *baseType.getArraySizes(); + ASSERT(arraySizes.size() == 1); + + for (unsigned int arrayIndex = 0; arrayIndex < arraySizes[0]; ++arrayIndex) + { + ImmutableString name = GetFieldName(baseName, field, arrayIndex); + + if (field->type()->isStructureContainingSamplers()) + { + if (traverseStructContainingSamplers(name, *field->type())) + { + hasNonSamplerParams = true; + } + } + else + { + ASSERT(field->type()->isSampler()); + visitSamplerInStructParam(name, field); + } + } + } + else if (field->type()->isStructureContainingSamplers()) + { + ImmutableString name = + GetFieldName(baseName, field, std::numeric_limits<unsigned>::max()); + hasNonSamplerParams = traverseStructContainingSamplers(name, *field->type()); + } + else + { + ASSERT(field->type()->isSampler()); + ImmutableString name = + GetFieldName(baseName, field, std::numeric_limits<unsigned>::max()); + visitSamplerInStructParam(name, field); + } + + return hasNonSamplerParams; + } + }; + + // A visitor that replaces functions with struct sampler references. The struct sampler + // references are expanded to include new fields for the structs. + class CreateStructSamplerFunctionVisitor final : public StructSamplerFunctionVisitor + { + public: + CreateStructSamplerFunctionVisitor(TSymbolTable *symbolTable) + : mSymbolTable(symbolTable), mNewFunction(nullptr) + {} + + ImmutableString getNameFromIndex(const TFunction *function, size_t paramIndex) override + { + const TVariable *param = function->getParam(paramIndex); + return param->name(); + } + + void traverse(const TFunction *function) override + { + mNewFunction = + new TFunction(mSymbolTable, function->name(), function->symbolType(), + &function->getReturnType(), function->isKnownToNotHaveSideEffects()); + + StructSamplerFunctionVisitor::traverse(function); + } + + void visitSamplerInStructParam(const ImmutableString &name, const TField *field) override + { + TVariable *fieldSampler = + new TVariable(mSymbolTable, name, field->type(), SymbolType::AngleInternal); + mNewFunction->addParameter(fieldSampler); + mSymbolTable->declareInternal(fieldSampler); + } + + void visitStructParam(const TFunction *function, size_t paramIndex) override + { + const TVariable *param = function->getParam(paramIndex); + TType *structType = GetStructSamplerParameterType(mSymbolTable, *param); + TVariable *newParam = + new TVariable(mSymbolTable, param->name(), structType, param->symbolType()); + mNewFunction->addParameter(newParam); + } + + void visitNonStructParam(const TFunction *function, size_t paramIndex) override + { + const TVariable *param = function->getParam(paramIndex); + mNewFunction->addParameter(param); + } + + TFunction *getNewFunction() const { return mNewFunction; } + + private: + TSymbolTable *mSymbolTable; + TFunction *mNewFunction; + }; + + TFunction *createStructSamplerFunction(const TFunction *function) const + { + CreateStructSamplerFunctionVisitor visitor(mSymbolTable); + visitor.traverse(function); + return visitor.getNewFunction(); + } + + // A visitor that replaces function calls with expanded struct sampler parameters. + class GetSamplerArgumentsVisitor final : public StructSamplerFunctionVisitor + { + public: + GetSamplerArgumentsVisitor(TSymbolTable *symbolTable, const TIntermSequence *arguments) + : mSymbolTable(symbolTable), mArguments(arguments), mNewArguments(new TIntermSequence) + {} + + ImmutableString getNameFromIndex(const TFunction *function, size_t paramIndex) override + { + TIntermTyped *argument = (*mArguments)[paramIndex]->getAsTyped(); + return GetStructSamplerNameFromTypedNode(argument); + } + + void visitSamplerInStructParam(const ImmutableString &name, const TField *field) override + { + TVariable *argSampler = + new TVariable(mSymbolTable, name, field->type(), SymbolType::AngleInternal); + TIntermSymbol *argSymbol = new TIntermSymbol(argSampler); + mNewArguments->push_back(argSymbol); + } + + void visitStructParam(const TFunction *function, size_t paramIndex) override + { + // The tree structure of the parameter is modified to point to the new type. This leaves + // the tree in a consistent state. + TIntermTyped *argument = (*mArguments)[paramIndex]->getAsTyped(); + TIntermTyped *replacement = ReplaceTypeOfTypedStructNode(argument, mSymbolTable); + mNewArguments->push_back(replacement); + } + + void visitNonStructParam(const TFunction *function, size_t paramIndex) override + { + TIntermTyped *argument = (*mArguments)[paramIndex]->getAsTyped(); + mNewArguments->push_back(argument); + } + + TIntermSequence *getNewArguments() const { return mNewArguments; } + + private: + TSymbolTable *mSymbolTable; + const TIntermSequence *mArguments; + TIntermSequence *mNewArguments; + }; + + TIntermSequence *getStructSamplerArguments(const TFunction *function, + const TIntermSequence *arguments) const + { + GetSamplerArgumentsVisitor visitor(mSymbolTable, arguments); + visitor.traverse(function); + return visitor.getNewArguments(); + } + + int mRemovedUniformsCount; + std::set<ImmutableString> mRemovedStructs; +}; +} // anonymous namespace + +int RewriteStructSamplers(TIntermBlock *root, TSymbolTable *symbolTable) +{ + Traverser rewriteStructSamplers(symbolTable); + root->traverse(&rewriteStructSamplers); + rewriteStructSamplers.updateTree(); + + return rewriteStructSamplers.removedUniformsCount(); +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.h new file mode 100644 index 0000000000..2b7aa6e1c4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteStructSamplers.h @@ -0,0 +1,31 @@ +// +// 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. +// +// RewriteStructSamplers: Extract structs from samplers. +// +// This traverser is designed to strip out samplers from structs. It moves them into +// separate uniform sampler declarations. This allows the struct to be stored in the +// default uniform block. It also requires that we rewrite any functions that take the +// struct as an argument. The struct is split into two arguments. +// +// For example: +// struct S { sampler2D samp; int i; }; +// uniform S uni; +// Is rewritten as: +// struct S { int i; }; +// uniform S uni; +// uniform sampler2D uni_i; + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITESTRUCTSAMPLERS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITESTRUCTSAMPLERS_H_ + +namespace sh +{ +class TIntermBlock; +class TSymbolTable; +int RewriteStructSamplers(TIntermBlock *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITESTRUCTSAMPLERS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp new file mode 100644 index 0000000000..3587fd6538 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp @@ -0,0 +1,154 @@ +// +// Copyright (c) 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. +// +// Implementation of texelFetchOffset translation issue workaround. +// See header for more info. + +#include "compiler/translator/tree_ops/RewriteTexelFetchOffset.h" + +#include "common/angleutils.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion); + + private: + Traverser(const TSymbolTable &symbolTable, int shaderVersion); + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + void nextIteration(); + + const TSymbolTable *symbolTable; + const int shaderVersion; + bool mFound = false; +}; + +Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion) + : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion) +{} + +// static +void Traverser::Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion) +{ + Traverser traverser(symbolTable, shaderVersion); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFound) + { + return false; + } + + // Decide if the node represents the call of texelFetchOffset. + if (node->getOp() != EOpCallBuiltInFunction) + { + return true; + } + + ASSERT(node->getFunction()->symbolType() == SymbolType::BuiltIn); + if (node->getFunction()->name() != "texelFetchOffset") + { + return true; + } + + // Potential problem case detected, apply workaround. + const TIntermSequence *sequence = node->getSequence(); + ASSERT(sequence->size() == 4u); + + // Decide if the sampler is a 2DArray sampler. In that case position is ivec3 and offset is + // ivec2. + bool is2DArray = sequence->at(1)->getAsTyped()->getNominalSize() == 3 && + sequence->at(3)->getAsTyped()->getNominalSize() == 2; + + // Create new node that represents the call of function texelFetch. + // Its argument list will be: texelFetch(sampler, Position+offset, lod). + + TIntermSequence *texelFetchArguments = new TIntermSequence(); + + // sampler + texelFetchArguments->push_back(sequence->at(0)); + + // Position + TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped(); + ASSERT(texCoordNode); + + // offset + TIntermTyped *offsetNode = nullptr; + ASSERT(sequence->at(3)->getAsTyped()); + if (is2DArray) + { + // For 2DArray samplers, Position is ivec3 and offset is ivec2; + // So offset must be converted into an ivec3 before being added to Position. + TIntermSequence *constructOffsetIvecArguments = new TIntermSequence(); + constructOffsetIvecArguments->push_back(sequence->at(3)->getAsTyped()); + + TIntermTyped *zeroNode = CreateZeroNode(TType(EbtInt)); + constructOffsetIvecArguments->push_back(zeroNode); + + offsetNode = TIntermAggregate::CreateConstructor(texCoordNode->getType(), + constructOffsetIvecArguments); + offsetNode->setLine(texCoordNode->getLine()); + } + else + { + offsetNode = sequence->at(3)->getAsTyped(); + } + + // Position+offset + TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode); + add->setLine(texCoordNode->getLine()); + texelFetchArguments->push_back(add); + + // lod + texelFetchArguments->push_back(sequence->at(2)); + + ASSERT(texelFetchArguments->size() == 3u); + + TIntermTyped *texelFetchNode = CreateBuiltInFunctionCallNode("texelFetch", texelFetchArguments, + *symbolTable, shaderVersion); + texelFetchNode->setLine(node->getLine()); + + // Replace the old node by this new node. + queueReplacement(texelFetchNode, OriginalNode::IS_DROPPED); + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteTexelFetchOffset(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion) +{ + // texelFetchOffset is only valid in GLSL 3.0 and later. + if (shaderVersion < 300) + return; + + Traverser::Apply(root, symbolTable, shaderVersion); +} + +} // namespace sh
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h new file mode 100644 index 0000000000..45e224dd62 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 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. +// +// This mutating tree traversal works around an issue on the translation +// from texelFetchOffset into HLSL function Load on INTEL drivers. It +// works by translating texelFetchOffset into texelFetch: +// +// - From: texelFetchOffset(sampler, Position, lod, offset) +// - To: texelFetch(sampler, Position+offset, lod) +// +// See http://anglebug.com/1469 + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITE_TEXELFETCHOFFSET_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITE_TEXELFETCHOFFSET_H_ + +class TIntermNode; +class TSymbolTable; + +namespace sh +{ + +void RewriteTexelFetchOffset(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITE_TEXELFETCHOFFSET_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp new file mode 100644 index 0000000000..e95dde2a76 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp @@ -0,0 +1,92 @@ +// +// Copyright (c) 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. +// + +#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h" + +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root); + + private: + Traverser(); + bool visitUnary(Visit visit, TIntermUnary *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root) +{ + Traverser traverser; + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser() : TIntermTraverser(true, false, false) {} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFound) + { + return false; + } + + // Detect if the current operator is unary minus operator. + if (node->getOp() != EOpNegative) + { + return true; + } + + // Detect if the current operand is a float variable. + TIntermTyped *fValue = node->getOperand(); + if (!fValue->getType().isScalarFloat()) + { + return true; + } + + // 0.0 - float + TIntermTyped *zero = CreateZeroNode(fValue->getType()); + zero->setLine(fValue->getLine()); + TIntermBinary *sub = new TIntermBinary(EOpSub, zero, fValue); + sub->setLine(fValue->getLine()); + + queueReplacement(sub, OriginalNode::IS_DROPPED); + + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteUnaryMinusOperatorFloat(TIntermNode *root) +{ + Traverser::Apply(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h new file mode 100644 index 0000000000..2df592a775 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h @@ -0,0 +1,19 @@ +// Copyright (c) 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. +// +// Rewrite "-float" to "0.0 - float" to work around unary minus operator on float issue on Intel Mac +// OSX 10.11. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORFLOAT_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORFLOAT_H_ + +class TIntermNode; +namespace sh +{ + +void RewriteUnaryMinusOperatorFloat(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORFLOAT_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp new file mode 100644 index 0000000000..5bfdb76e03 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp @@ -0,0 +1,110 @@ +// +// Copyright (c) 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. +// +// Implementation of evaluating unary integer variable bug workaround. +// See header for more info. + +#include "compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h" + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root); + + private: + Traverser(); + bool visitUnary(Visit visit, TIntermUnary *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root) +{ + Traverser traverser; + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser() : TIntermTraverser(true, false, false) {} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFound) + { + return false; + } + + // Decide if the current unary operator is unary minus. + if (node->getOp() != EOpNegative) + { + return true; + } + + // Decide if the current operand is an integer variable. + TIntermTyped *opr = node->getOperand(); + if (!opr->getType().isScalarInt()) + { + return true; + } + + // Potential problem case detected, apply workaround: -(int) -> ~(int) + 1. + // ~(int) + TIntermUnary *bitwiseNot = new TIntermUnary(EOpBitwiseNot, opr, nullptr); + bitwiseNot->setLine(opr->getLine()); + + // Constant 1 (or 1u) + TConstantUnion *one = new TConstantUnion(); + if (opr->getType().getBasicType() == EbtInt) + { + one->setIConst(1); + } + else + { + one->setUConst(1u); + } + TIntermConstantUnion *oneNode = + new TIntermConstantUnion(one, TType(opr->getBasicType(), opr->getPrecision(), EvqConst)); + oneNode->setLine(opr->getLine()); + + // ~(int) + 1 + TIntermBinary *add = new TIntermBinary(EOpAdd, bitwiseNot, oneNode); + add->setLine(opr->getLine()); + + queueReplacement(add, OriginalNode::IS_DROPPED); + + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteUnaryMinusOperatorInt(TIntermNode *root) +{ + Traverser::Apply(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h new file mode 100644 index 0000000000..66192179c4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h @@ -0,0 +1,20 @@ +// Copyright (c) 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. +// +// This mutating tree traversal works around a bug on evaluating unary +// integer variable on Intel D3D driver. It works by rewriting -(int) to +// ~(int) + 1 when evaluating unary integer variables. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORINT_H_ +#define COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORINT_H_ + +class TIntermNode; +namespace sh +{ + +void RewriteUnaryMinusOperatorInt(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_REWRITEUNARYMINUSOPERATORINT_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp new file mode 100644 index 0000000000..53d34ec5c1 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp @@ -0,0 +1,226 @@ +// +// Copyright (c) 2002-2014 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. +// +// Scalarize vector and matrix constructor args, so that vectors built from components don't have +// matrix arguments, and matrices built from components don't have vector arguments. This avoids +// driver bugs around vector and matrix constructors. +// + +#include "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h" +#include "common/debug.h" + +#include <algorithm> + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index) +{ + return new TIntermBinary(EOpIndexDirect, symbolNode, CreateIndexNode(index)); +} + +TIntermBinary *ConstructMatrixIndexBinaryNode(TIntermSymbol *symbolNode, int colIndex, int rowIndex) +{ + TIntermBinary *colVectorNode = ConstructVectorIndexBinaryNode(symbolNode, colIndex); + + return new TIntermBinary(EOpIndexDirect, colVectorNode, CreateIndexNode(rowIndex)); +} + +class ScalarizeArgsTraverser : public TIntermTraverser +{ + public: + ScalarizeArgsTraverser(sh::GLenum shaderType, + bool fragmentPrecisionHigh, + TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), + mShaderType(shaderType), + mFragmentPrecisionHigh(fragmentPrecisionHigh), + mNodesToScalarize(IntermNodePatternMatcher::kScalarizedVecOrMatConstructor) + {} + + protected: + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitBlock(Visit visit, TIntermBlock *node) override; + + private: + void scalarizeArgs(TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix); + + // If we have the following code: + // mat4 m(0); + // vec4 v(1, m); + // We will rewrite to: + // mat4 m(0); + // mat4 s0 = m; + // vec4 v(1, s0[0][0], s0[0][1], s0[0][2]); + // This function is to create nodes for "mat4 s0 = m;" and insert it to the code sequence. This + // way the possible side effects of the constructor argument will only be evaluated once. + TVariable *createTempVariable(TIntermTyped *original); + + std::vector<TIntermSequence> mBlockStack; + + sh::GLenum mShaderType; + bool mFragmentPrecisionHigh; + + IntermNodePatternMatcher mNodesToScalarize; +}; + +bool ScalarizeArgsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + ASSERT(visit == PreVisit); + if (mNodesToScalarize.match(node, getParentNode())) + { + if (node->getType().isVector()) + { + scalarizeArgs(node, false, true); + } + else + { + ASSERT(node->getType().isMatrix()); + scalarizeArgs(node, true, false); + } + } + return true; +} + +bool ScalarizeArgsTraverser::visitBlock(Visit visit, TIntermBlock *node) +{ + mBlockStack.push_back(TIntermSequence()); + { + for (TIntermNode *child : *node->getSequence()) + { + ASSERT(child != nullptr); + child->traverse(this); + mBlockStack.back().push_back(child); + } + } + if (mBlockStack.back().size() > node->getSequence()->size()) + { + node->getSequence()->clear(); + *(node->getSequence()) = mBlockStack.back(); + } + mBlockStack.pop_back(); + return false; +} + +void ScalarizeArgsTraverser::scalarizeArgs(TIntermAggregate *aggregate, + bool scalarizeVector, + bool scalarizeMatrix) +{ + ASSERT(aggregate); + ASSERT(!aggregate->isArray()); + int size = static_cast<int>(aggregate->getType().getObjectSize()); + TIntermSequence *sequence = aggregate->getSequence(); + TIntermSequence originalArgs(*sequence); + sequence->clear(); + for (TIntermNode *originalArgNode : originalArgs) + { + ASSERT(size > 0); + TIntermTyped *originalArg = originalArgNode->getAsTyped(); + ASSERT(originalArg); + TVariable *argVariable = createTempVariable(originalArg); + if (originalArg->isScalar()) + { + sequence->push_back(CreateTempSymbolNode(argVariable)); + size--; + } + else if (originalArg->isVector()) + { + if (scalarizeVector) + { + int repeat = std::min(size, originalArg->getNominalSize()); + size -= repeat; + for (int index = 0; index < repeat; ++index) + { + TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable); + TIntermBinary *newNode = ConstructVectorIndexBinaryNode(symbolNode, index); + sequence->push_back(newNode); + } + } + else + { + TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable); + sequence->push_back(symbolNode); + size -= originalArg->getNominalSize(); + } + } + else + { + ASSERT(originalArg->isMatrix()); + if (scalarizeMatrix) + { + int colIndex = 0, rowIndex = 0; + int repeat = std::min(size, originalArg->getCols() * originalArg->getRows()); + size -= repeat; + while (repeat > 0) + { + TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable); + TIntermBinary *newNode = + ConstructMatrixIndexBinaryNode(symbolNode, colIndex, rowIndex); + sequence->push_back(newNode); + rowIndex++; + if (rowIndex >= originalArg->getRows()) + { + rowIndex = 0; + colIndex++; + } + repeat--; + } + } + else + { + TIntermSymbol *symbolNode = CreateTempSymbolNode(argVariable); + sequence->push_back(symbolNode); + size -= originalArg->getCols() * originalArg->getRows(); + } + } + } +} + +TVariable *ScalarizeArgsTraverser::createTempVariable(TIntermTyped *original) +{ + ASSERT(original); + + TType *type = new TType(original->getType()); + type->setQualifier(EvqTemporary); + if (mShaderType == GL_FRAGMENT_SHADER && type->getBasicType() == EbtFloat && + type->getPrecision() == EbpUndefined) + { + // We use the highest available precision for the temporary variable + // to avoid computing the actual precision using the rules defined + // in GLSL ES 1.0 Section 4.5.2. + type->setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium); + } + + TVariable *variable = CreateTempVariable(mSymbolTable, type); + + ASSERT(mBlockStack.size() > 0); + TIntermSequence &sequence = mBlockStack.back(); + TIntermDeclaration *declaration = CreateTempInitDeclarationNode(variable, original); + sequence.push_back(declaration); + + return variable; +} + +} // namespace + +void ScalarizeVecAndMatConstructorArgs(TIntermBlock *root, + sh::GLenum shaderType, + bool fragmentPrecisionHigh, + TSymbolTable *symbolTable) +{ + ScalarizeArgsTraverser scalarizer(shaderType, fragmentPrecisionHigh, symbolTable); + root->traverse(&scalarizer); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h new file mode 100644 index 0000000000..e66908de1d --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 2002-2014 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. +// +// Scalarize vector and matrix constructor args, so that vectors built from components don't have +// matrix arguments, and matrices built from components don't have vector arguments. This avoids +// driver bugs around vector and matrix constructors. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ + +#include "GLSLANG/ShaderLang.h" + +namespace sh +{ +class TIntermBlock; +class TSymbolTable; + +void ScalarizeVecAndMatConstructorArgs(TIntermBlock *root, + sh::GLenum shaderType, + bool fragmentPrecisionHigh, + TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp new file mode 100644 index 0000000000..5b4672bf24 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp @@ -0,0 +1,84 @@ +// +// Copyright (c) 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. +// +// SeparateArrayConstructorStatements splits statements that are array constructors and drops all of +// their constant arguments. For example, a statement like: +// int[2](0, i++); +// Will be changed to: +// i++; + +#include "compiler/translator/tree_ops/SeparateArrayConstructorStatements.h" + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +void SplitConstructorArgs(const TIntermSequence &originalArgs, TIntermSequence *argsOut) +{ + for (TIntermNode *arg : originalArgs) + { + TIntermTyped *argTyped = arg->getAsTyped(); + if (argTyped->hasSideEffects()) + { + TIntermAggregate *argAggregate = argTyped->getAsAggregate(); + if (argTyped->isArray() && argAggregate && argAggregate->isConstructor()) + { + SplitConstructorArgs(*argAggregate->getSequence(), argsOut); + } + else + { + argsOut->push_back(argTyped); + } + } + } +} + +class SeparateArrayConstructorStatementsTraverser : public TIntermTraverser +{ + public: + SeparateArrayConstructorStatementsTraverser(); + + bool visitAggregate(Visit visit, TIntermAggregate *node) override; +}; + +SeparateArrayConstructorStatementsTraverser::SeparateArrayConstructorStatementsTraverser() + : TIntermTraverser(true, false, false) +{} + +bool SeparateArrayConstructorStatementsTraverser::visitAggregate(Visit visit, + TIntermAggregate *node) +{ + TIntermBlock *parentAsBlock = getParentNode()->getAsBlock(); + if (!parentAsBlock) + { + return false; + } + if (!node->isArray() || !node->isConstructor()) + { + return false; + } + + TIntermSequence constructorArgs; + SplitConstructorArgs(*node->getSequence(), &constructorArgs); + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentAsBlock, node, constructorArgs)); + + return false; +} + +} // namespace + +void SeparateArrayConstructorStatements(TIntermBlock *root) +{ + SeparateArrayConstructorStatementsTraverser traverser; + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h new file mode 100644 index 0000000000..740ba95aca --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 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. +// +// SeparateArrayConstructorStatements splits statements that are array constructors and drops all of +// their constant arguments. For example, a statement like: +// int[2](0, i++); +// Will be changed to: +// i++; + +#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYCONSTRUCTORSTATEMENTS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYCONSTRUCTORSTATEMENTS_H_ + +namespace sh +{ +class TIntermBlock; + +void SeparateArrayConstructorStatements(TIntermBlock *root); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYCONSTRUCTORSTATEMENTS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp new file mode 100644 index 0000000000..435ba9d6c4 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp @@ -0,0 +1,90 @@ +// +// Copyright (c) 2002-2015 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. +// +// The SeparateArrayInitialization function splits each array initialization into a declaration and +// an assignment. +// Example: +// type[n] a = initializer; +// will effectively become +// type[n] a; +// a = initializer; +// +// Note that if the array is declared as const, the initialization may still be split, making the +// AST technically invalid. Because of that this transformation should only be used when subsequent +// stages don't care about const qualifiers. However, the initialization will not be split if the +// initializer can be written as a HLSL literal. + +#include "compiler/translator/tree_ops/SeparateArrayInitialization.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/OutputHLSL.h" + +namespace sh +{ + +namespace +{ + +class SeparateArrayInitTraverser : private TIntermTraverser +{ + public: + static void apply(TIntermNode *root); + + private: + SeparateArrayInitTraverser(); + bool visitDeclaration(Visit, TIntermDeclaration *node) override; +}; + +void SeparateArrayInitTraverser::apply(TIntermNode *root) +{ + SeparateArrayInitTraverser separateInit; + root->traverse(&separateInit); + separateInit.updateTree(); +} + +SeparateArrayInitTraverser::SeparateArrayInitTraverser() : TIntermTraverser(true, false, false) {} + +bool SeparateArrayInitTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + TIntermSequence *sequence = node->getSequence(); + TIntermBinary *initNode = sequence->back()->getAsBinaryNode(); + if (initNode != nullptr && initNode->getOp() == EOpInitialize) + { + TIntermTyped *initializer = initNode->getRight(); + if (initializer->isArray() && !initializer->hasConstantValue()) + { + // We rely on that array declarations have been isolated to single declarations. + ASSERT(sequence->size() == 1); + TIntermTyped *symbol = initNode->getLeft(); + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + ASSERT(parentBlock != nullptr); + + TIntermSequence replacements; + + TIntermDeclaration *replacementDeclaration = new TIntermDeclaration(); + replacementDeclaration->appendDeclarator(symbol); + replacementDeclaration->setLine(symbol->getLine()); + replacements.push_back(replacementDeclaration); + + TIntermBinary *replacementAssignment = + new TIntermBinary(EOpAssign, symbol, initializer); + replacementAssignment->setLine(symbol->getLine()); + replacements.push_back(replacementAssignment); + + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentBlock, node, replacements)); + } + } + return false; +} + +} // namespace + +void SeparateArrayInitialization(TIntermNode *root) +{ + SeparateArrayInitTraverser::apply(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h new file mode 100644 index 0000000000..a197ff5a86 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 2002-2015 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. +// +// The SeparateArrayInitialization function splits each array initialization into a declaration and +// an assignment. +// Example: +// type[n] a = initializer; +// will effectively become +// type[n] a; +// a = initializer; +// +// Note that if the array is declared as const, the initialization may still be split, making the +// AST technically invalid. Because of that this transformation should only be used when subsequent +// stages don't care about const qualifiers. However, the initialization will not be split if the +// initializer can be written as a HLSL literal. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYINITIALIZATION_H_ +#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYINITIALIZATION_H_ + +namespace sh +{ +class TIntermNode; + +void SeparateArrayInitialization(TIntermNode *root); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEARRAYINITIALIZATION_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp new file mode 100644 index 0000000000..82011acd8a --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2002-2015 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. +// +// The SeparateDeclarations function processes declarations, so that in the end each declaration +// contains only one declarator. +// This is useful as an intermediate step when initialization needs to be separated from +// declaration, or when things need to be unfolded out of the initializer. +// Example: +// int a[1] = int[1](1), b[1] = int[1](2); +// gets transformed when run through this class into the AST equivalent of: +// int a[1] = int[1](1); +// int b[1] = int[1](2); + +#include "compiler/translator/tree_ops/SeparateDeclarations.h" + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class SeparateDeclarationsTraverser : private TIntermTraverser +{ + public: + static void apply(TIntermNode *root); + + private: + SeparateDeclarationsTraverser(); + bool visitDeclaration(Visit, TIntermDeclaration *node) override; +}; + +void SeparateDeclarationsTraverser::apply(TIntermNode *root) +{ + SeparateDeclarationsTraverser separateDecl; + root->traverse(&separateDecl); + separateDecl.updateTree(); +} + +SeparateDeclarationsTraverser::SeparateDeclarationsTraverser() + : TIntermTraverser(true, false, false) +{} + +bool SeparateDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node) +{ + TIntermSequence *sequence = node->getSequence(); + if (sequence->size() > 1) + { + TIntermBlock *parentBlock = getParentNode()->getAsBlock(); + ASSERT(parentBlock != nullptr); + + TIntermSequence replacementDeclarations; + for (size_t ii = 0; ii < sequence->size(); ++ii) + { + TIntermDeclaration *replacementDeclaration = new TIntermDeclaration(); + + replacementDeclaration->appendDeclarator(sequence->at(ii)->getAsTyped()); + replacementDeclaration->setLine(sequence->at(ii)->getLine()); + replacementDeclarations.push_back(replacementDeclaration); + } + + mMultiReplacements.push_back( + NodeReplaceWithMultipleEntry(parentBlock, node, replacementDeclarations)); + } + return false; +} + +} // namespace + +void SeparateDeclarations(TIntermNode *root) +{ + SeparateDeclarationsTraverser::apply(root); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h new file mode 100644 index 0000000000..1e7f967be9 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2002-2015 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. +// +// The SeparateDeclarations function processes declarations, so that in the end each declaration +// contains only one declarator. +// This is useful as an intermediate step when initialization needs to be separated from +// declaration, or when things need to be unfolded out of the initializer. +// Example: +// int a[1] = int[1](1), b[1] = int[1](2); +// gets transformed when run through this class into the AST equivalent of: +// int a[1] = int[1](1); +// int b[1] = int[1](2); + +#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEDECLARATIONS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEDECLARATIONS_H_ + +namespace sh +{ +class TIntermNode; + +void SeparateDeclarations(TIntermNode *root); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEDECLARATIONS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp new file mode 100644 index 0000000000..127e97ebcf --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp @@ -0,0 +1,129 @@ +// +// Copyright (c) 2002-2015 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. +// +// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names +// from more complex expressions, assigning them to a temporary variable a#. +// Examples where a, b and c are all arrays: +// (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2; +// type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i]; + +#include "compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h" + +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// Traverser that separates one array expression into a statement at a time. +class SeparateExpressionsTraverser : public TIntermTraverser +{ + public: + SeparateExpressionsTraverser(TSymbolTable *symbolTable); + + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + void nextIteration(); + bool foundArrayExpression() const { return mFoundArrayExpression; } + + protected: + // Marked to true once an operation that needs to be hoisted out of the expression has been + // found. After that, no more AST updates are performed on that traversal. + bool mFoundArrayExpression; + + IntermNodePatternMatcher mPatternToSeparateMatcher; +}; + +SeparateExpressionsTraverser::SeparateExpressionsTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), + mFoundArrayExpression(false), + mPatternToSeparateMatcher(IntermNodePatternMatcher::kExpressionReturningArray) +{} + +// Performs a shallow copy of an assignment node. +// These shallow copies are useful when a node gets inserted into an aggregate node +// and also needs to be replaced in its original location by a different node. +TIntermBinary *CopyAssignmentNode(TIntermBinary *node) +{ + return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight()); +} + +bool SeparateExpressionsTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (mFoundArrayExpression) + return false; + + // Return if the expression is not an array or if we're not inside a complex expression. + if (!mPatternToSeparateMatcher.match(node, getParentNode())) + return true; + + ASSERT(node->getOp() == EOpAssign); + + mFoundArrayExpression = true; + + TIntermSequence insertions; + insertions.push_back(CopyAssignmentNode(node)); + // TODO(oetuaho): In some cases it would be more optimal to not add the temporary node, but just + // use the original target of the assignment. Care must be taken so that this doesn't happen + // when the same array symbol is a target of assignment more than once in one expression. + TIntermDeclaration *arrayVariableDeclaration; + TVariable *arrayVariable = + DeclareTempVariable(mSymbolTable, node->getLeft(), EvqTemporary, &arrayVariableDeclaration); + insertions.push_back(arrayVariableDeclaration); + insertStatementsInParentBlock(insertions); + + queueReplacement(CreateTempSymbolNode(arrayVariable), OriginalNode::IS_DROPPED); + + return false; +} + +bool SeparateExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFoundArrayExpression) + return false; // No need to traverse further + + if (!mPatternToSeparateMatcher.match(node, getParentNode())) + return true; + + ASSERT(node->isConstructor() || node->getOp() == EOpCallFunctionInAST); + + mFoundArrayExpression = true; + + TIntermDeclaration *arrayVariableDeclaration; + TVariable *arrayVariable = DeclareTempVariable(mSymbolTable, node->shallowCopy(), EvqTemporary, + &arrayVariableDeclaration); + insertStatementInParentBlock(arrayVariableDeclaration); + + queueReplacement(CreateTempSymbolNode(arrayVariable), OriginalNode::IS_DROPPED); + + return false; +} + +void SeparateExpressionsTraverser::nextIteration() +{ + mFoundArrayExpression = false; +} + +} // namespace + +void SeparateExpressionsReturningArrays(TIntermNode *root, TSymbolTable *symbolTable) +{ + SeparateExpressionsTraverser traverser(symbolTable); + // Separate one expression at a time, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundArrayExpression()) + traverser.updateTree(); + } while (traverser.foundArrayExpression()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h new file mode 100644 index 0000000000..9b09f7c61e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2002-2015 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. +// +// SeparateExpressionsReturningArrays splits array-returning expressions that are not array names +// from more complex expressions, assigning them to a temporary variable a#. +// Examples where a, b and c are all arrays: +// (a = b) == (a = c) is split into a = b; type[n] a1 = a; a = c; type[n] a2 = a; a1 == a2; +// type d = type[n](...)[i]; is split into type[n] a1 = type[n](...); type d = a1[i]; + +#ifndef COMPILER_TRANSLATOR_TREEOPS_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_ + +namespace sh +{ +class TIntermNode; +class TSymbolTable; + +void SeparateExpressionsReturningArrays(TIntermNode *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_SEPARATEEXPRESSIONSRETURNINGARRAYS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp new file mode 100644 index 0000000000..35d3c33f34 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp @@ -0,0 +1,299 @@ +// +// Copyright (c) 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. +// +// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions +// to regular statements inside the loop. This way further transformations that generate statements +// from loop conditions and loop expressions work correctly. +// + +#include "compiler/translator/tree_ops/SimplifyLoopConditions.h" + +#include "compiler/translator/StaticType.h" +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser +{ + public: + SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask, + TSymbolTable *symbolTable); + + void traverseLoop(TIntermLoop *node) override; + + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; + + bool foundLoopToChange() const { return mFoundLoopToChange; } + + protected: + // Marked to true once an operation that needs to be hoisted out of a loop expression has been + // found. + bool mFoundLoopToChange; + bool mInsideLoopInitConditionOrExpression; + IntermNodePatternMatcher mConditionsToSimplify; +}; + +SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser( + unsigned int conditionsToSimplifyMask, + TSymbolTable *symbolTable) + : TLValueTrackingTraverser(true, false, false, symbolTable), + mFoundLoopToChange(false), + mInsideLoopInitConditionOrExpression(false), + mConditionsToSimplify(conditionsToSimplifyMask) +{} + +// If we're inside a loop initialization, condition, or expression, we check for expressions that +// should be moved out of the loop condition or expression. If one is found, the loop is +// transformed. +// If we're not inside loop initialization, condition, or expression, we only need to traverse nodes +// that may contain loops. + +bool SimplifyLoopConditionsTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere()); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode()); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node) +{ + if (!mInsideLoopInitConditionOrExpression) + return false; + + if (mFoundLoopToChange) + return false; // Already decided to change this loop. + + mFoundLoopToChange = mConditionsToSimplify.match(node); + return !mFoundLoopToChange; +} + +void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node) +{ + // Mark that we're inside a loop condition or expression, and determine if the loop needs to be + // transformed. + + ScopedNodeInTraversalPath addToPath(this, node); + + mInsideLoopInitConditionOrExpression = true; + mFoundLoopToChange = false; + + if (!mFoundLoopToChange && node->getInit()) + { + node->getInit()->traverse(this); + } + + if (!mFoundLoopToChange && node->getCondition()) + { + node->getCondition()->traverse(this); + } + + if (!mFoundLoopToChange && node->getExpression()) + { + node->getExpression()->traverse(this); + } + + mInsideLoopInitConditionOrExpression = false; + + if (mFoundLoopToChange) + { + const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>(); + TVariable *conditionVariable = CreateTempVariable(mSymbolTable, boolType); + + // Replace the loop condition with a boolean variable that's updated on each iteration. + TLoopType loopType = node->getType(); + if (loopType == ELoopWhile) + { + // Transform: + // while (expr) { body; } + // into + // bool s0 = expr; + // while (s0) { { body; } s0 = expr; } + TIntermDeclaration *tempInitDeclaration = + CreateTempInitDeclarationNode(conditionVariable, node->getCondition()->deepCopy()); + insertStatementInParentBlock(tempInitDeclaration); + + TIntermBlock *newBody = new TIntermBlock(); + if (node->getBody()) + { + newBody->getSequence()->push_back(node->getBody()); + } + newBody->getSequence()->push_back( + CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy())); + + // Can't use queueReplacement to replace old body, since it may have been nullptr. + // It's safe to do the replacements in place here - the new body will still be + // traversed, but that won't create any problems. + node->setBody(newBody); + node->setCondition(CreateTempSymbolNode(conditionVariable)); + } + else if (loopType == ELoopDoWhile) + { + // Transform: + // do { + // body; + // } while (expr); + // into + // bool s0 = true; + // do { + // { body; } + // s0 = expr; + // } while (s0); + TIntermDeclaration *tempInitDeclaration = + CreateTempInitDeclarationNode(conditionVariable, CreateBoolNode(true)); + insertStatementInParentBlock(tempInitDeclaration); + + TIntermBlock *newBody = new TIntermBlock(); + if (node->getBody()) + { + newBody->getSequence()->push_back(node->getBody()); + } + newBody->getSequence()->push_back( + CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy())); + + // Can't use queueReplacement to replace old body, since it may have been nullptr. + // It's safe to do the replacements in place here - the new body will still be + // traversed, but that won't create any problems. + node->setBody(newBody); + node->setCondition(CreateTempSymbolNode(conditionVariable)); + } + else if (loopType == ELoopFor) + { + // Move the loop condition inside the loop. + // Transform: + // for (init; expr; exprB) { body; } + // into + // { + // init; + // bool s0 = expr; + // while (s0) { + // { body; } + // exprB; + // s0 = expr; + // } + // } + TIntermBlock *loopScope = new TIntermBlock(); + TIntermSequence *loopScopeSequence = loopScope->getSequence(); + + // Insert "init;" + if (node->getInit()) + { + loopScopeSequence->push_back(node->getInit()); + } + + // Insert "bool s0 = expr;" if applicable, "bool s0 = true;" otherwise + TIntermTyped *conditionInitializer = nullptr; + if (node->getCondition()) + { + conditionInitializer = node->getCondition()->deepCopy(); + } + else + { + conditionInitializer = CreateBoolNode(true); + } + loopScopeSequence->push_back( + CreateTempInitDeclarationNode(conditionVariable, conditionInitializer)); + + // Insert "{ body; }" in the while loop + TIntermBlock *whileLoopBody = new TIntermBlock(); + if (node->getBody()) + { + whileLoopBody->getSequence()->push_back(node->getBody()); + } + // Insert "exprB;" in the while loop + if (node->getExpression()) + { + whileLoopBody->getSequence()->push_back(node->getExpression()); + } + // Insert "s0 = expr;" in the while loop + if (node->getCondition()) + { + whileLoopBody->getSequence()->push_back( + CreateTempAssignmentNode(conditionVariable, node->getCondition()->deepCopy())); + } + + // Create "while(s0) { whileLoopBody }" + TIntermLoop *whileLoop = + new TIntermLoop(ELoopWhile, nullptr, CreateTempSymbolNode(conditionVariable), + nullptr, whileLoopBody); + loopScope->getSequence()->push_back(whileLoop); + queueReplacement(loopScope, OriginalNode::IS_DROPPED); + + // After this the old body node will be traversed and loops inside it may be + // transformed. This is fine, since the old body node will still be in the AST after the + // transformation that's queued here, and transforming loops inside it doesn't need to + // know the exact post-transform path to it. + } + } + + mFoundLoopToChange = false; + + // We traverse the body of the loop even if the loop is transformed. + if (node->getBody()) + node->getBody()->traverse(this); +} + +} // namespace + +void SimplifyLoopConditions(TIntermNode *root, + unsigned int conditionsToSimplifyMask, + TSymbolTable *symbolTable) +{ + SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable); + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h new file mode 100644 index 0000000000..15265bb577 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 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. +// +// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions +// to regular statements inside the loop. This way further transformations that generate statements +// from loop conditions and loop expressions work correctly. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_SIMPLIFYLOOPCONDITIONS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_SIMPLIFYLOOPCONDITIONS_H_ + +namespace sh +{ +class TIntermNode; +class TSymbolTable; + +void SimplifyLoopConditions(TIntermNode *root, + unsigned int conditionsToSimplify, + TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_SIMPLIFYLOOPCONDITIONS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp new file mode 100644 index 0000000000..72804946fa --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp @@ -0,0 +1,163 @@ +// +// Copyright (c) 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. +// +// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that +// go through further AST transformations that generate statements, and splits them so that +// possible side effects of earlier parts of the sequence operator expression are guaranteed to be +// evaluated before the latter parts of the sequence operator expression are evaluated. +// + +#include "compiler/translator/tree_ops/SplitSequenceOperator.h" + +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser +{ + public: + SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, TSymbolTable *symbolTable); + + bool visitUnary(Visit visit, TIntermUnary *node) override; + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + + void nextIteration(); + bool foundExpressionToSplit() const { return mFoundExpressionToSplit; } + + protected: + // Marked to true once an operation that needs to be hoisted out of the expression has been + // found. After that, no more AST updates are performed on that traversal. + bool mFoundExpressionToSplit; + int mInsideSequenceOperator; + + IntermNodePatternMatcher mPatternToSplitMatcher; +}; + +SplitSequenceOperatorTraverser::SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, + TSymbolTable *symbolTable) + : TLValueTrackingTraverser(true, false, true, symbolTable), + mFoundExpressionToSplit(false), + mInsideSequenceOperator(0), + mPatternToSplitMatcher(patternsToSplitMask) +{} + +void SplitSequenceOperatorTraverser::nextIteration() +{ + mFoundExpressionToSplit = false; + mInsideSequenceOperator = 0; +} + +bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node, getParentNode()); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (node->getOp() == EOpComma) + { + if (visit == PreVisit) + { + if (mFoundExpressionToSplit) + { + return false; + } + mInsideSequenceOperator++; + } + else if (visit == PostVisit) + { + // Split sequence operators starting from the outermost one to preserve correct + // execution order. + if (mFoundExpressionToSplit && mInsideSequenceOperator == 1) + { + // Move the left side operand into a separate statement in the parent block. + TIntermSequence insertions; + insertions.push_back(node->getLeft()); + insertStatementsInParentBlock(insertions); + // Replace the comma node with its right side operand. + queueReplacement(node->getRight(), OriginalNode::IS_DROPPED); + } + mInsideSequenceOperator--; + } + return true; + } + + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = + mPatternToSplitMatcher.match(node, getParentNode(), isLValueRequiredHere()); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); + return !mFoundExpressionToSplit; + } + + return true; +} + +} // namespace + +void SplitSequenceOperator(TIntermNode *root, int patternsToSplitMask, TSymbolTable *symbolTable) +{ + SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable); + // Separate one expression at a time, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundExpressionToSplit()) + traverser.updateTree(); + } while (traverser.foundExpressionToSplit()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h new file mode 100644 index 0000000000..fc341c968e --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 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. +// +// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that +// go through further AST transformations that generate statements, and splits them so that +// possible side effects of earlier parts of the sequence operator expression are guaranteed to be +// evaluated before the latter parts of the sequence operator expression are evaluated. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_SPLITSEQUENCEOPERATOR_H_ +#define COMPILER_TRANSLATOR_TREEOPS_SPLITSEQUENCEOPERATOR_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void SplitSequenceOperator(TIntermNode *root, int patternsToSplitMask, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_SPLITSEQUENCEOPERATOR_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp new file mode 100644 index 0000000000..e408714fde --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2002-2013 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/UnfoldShortCircuitAST.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// "x || y" is equivalent to "x ? true : y". +TIntermTernary *UnfoldOR(TIntermTyped *x, TIntermTyped *y) +{ + return new TIntermTernary(x, CreateBoolNode(true), y); +} + +// "x && y" is equivalent to "x ? y : false". +TIntermTernary *UnfoldAND(TIntermTyped *x, TIntermTyped *y) +{ + return new TIntermTernary(x, y, CreateBoolNode(false)); +} + +// This traverser identifies all the short circuit binary nodes that need to +// be replaced, and creates the corresponding replacement nodes. However, +// the actual replacements happen after the traverse through updateTree(). + +class UnfoldShortCircuitASTTraverser : public TIntermTraverser +{ + public: + UnfoldShortCircuitASTTraverser() : TIntermTraverser(true, false, false) {} + + bool visitBinary(Visit visit, TIntermBinary *) override; +}; + +bool UnfoldShortCircuitASTTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + TIntermTernary *replacement = nullptr; + + switch (node->getOp()) + { + case EOpLogicalOr: + replacement = UnfoldOR(node->getLeft(), node->getRight()); + break; + case EOpLogicalAnd: + replacement = UnfoldAND(node->getLeft(), node->getRight()); + break; + default: + break; + } + if (replacement) + { + queueReplacement(replacement, OriginalNode::IS_DROPPED); + } + return true; +} + +} // anonymous namespace + +void UnfoldShortCircuitAST(TIntermBlock *root) +{ + UnfoldShortCircuitASTTraverser traverser; + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h new file mode 100644 index 0000000000..7f492a9ca0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2002-2013 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. +// +// UnfoldShortCircuitAST is an AST traverser to replace short-circuiting +// operations with ternary operations. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUITAST_H_ +#define COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUITAST_H_ + +namespace sh +{ + +class TIntermBlock; + +void UnfoldShortCircuitAST(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUITAST_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp new file mode 100644 index 0000000000..4a86c04766 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp @@ -0,0 +1,193 @@ +// +// Copyright (c) 2002-2013 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. +// +// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else +// statements. +// The results are assigned to s# temporaries, which are used by the main translator instead of +// the original expression. +// + +#include "compiler/translator/tree_ops/UnfoldShortCircuitToIf.h" + +#include "compiler/translator/StaticType.h" +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +// Traverser that unfolds one short-circuiting operation at a time. +class UnfoldShortCircuitTraverser : public TIntermTraverser +{ + public: + UnfoldShortCircuitTraverser(TSymbolTable *symbolTable); + + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + + void nextIteration(); + bool foundShortCircuit() const { return mFoundShortCircuit; } + + protected: + // Marked to true once an operation that needs to be unfolded has been found. + // After that, no more unfolding is performed on that traversal. + bool mFoundShortCircuit; + + IntermNodePatternMatcher mPatternToUnfoldMatcher; +}; + +UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, true, symbolTable), + mFoundShortCircuit(false), + mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression) +{} + +bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (mFoundShortCircuit) + return false; + + if (visit != PreVisit) + return true; + + if (!mPatternToUnfoldMatcher.match(node, getParentNode())) + return true; + + // If our right node doesn't have side effects, we know we don't need to unfold this + // expression: there will be no short-circuiting side effects to avoid + // (note: unfolding doesn't depend on the left node -- it will always be evaluated) + ASSERT(node->getRight()->hasSideEffects()); + + mFoundShortCircuit = true; + + switch (node->getOp()) + { + case EOpLogicalOr: + { + // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; + // else s = y;", + // and then further simplifies down to "bool s = x; if(!s) s = y;". + + TIntermSequence insertions; + const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>(); + TVariable *resultVariable = CreateTempVariable(mSymbolTable, boolType); + + ASSERT(node->getLeft()->getType() == *boolType); + insertions.push_back(CreateTempInitDeclarationNode(resultVariable, node->getLeft())); + + TIntermBlock *assignRightBlock = new TIntermBlock(); + ASSERT(node->getRight()->getType() == *boolType); + assignRightBlock->getSequence()->push_back( + CreateTempAssignmentNode(resultVariable, node->getRight())); + + TIntermUnary *notTempSymbol = + new TIntermUnary(EOpLogicalNot, CreateTempSymbolNode(resultVariable), nullptr); + TIntermIfElse *ifNode = new TIntermIfElse(notTempSymbol, assignRightBlock, nullptr); + insertions.push_back(ifNode); + + insertStatementsInParentBlock(insertions); + + queueReplacement(CreateTempSymbolNode(resultVariable), OriginalNode::IS_DROPPED); + return false; + } + case EOpLogicalAnd: + { + // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; + // else s = false;", + // and then further simplifies down to "bool s = x; if(s) s = y;". + TIntermSequence insertions; + const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>(); + TVariable *resultVariable = CreateTempVariable(mSymbolTable, boolType); + + ASSERT(node->getLeft()->getType() == *boolType); + insertions.push_back(CreateTempInitDeclarationNode(resultVariable, node->getLeft())); + + TIntermBlock *assignRightBlock = new TIntermBlock(); + ASSERT(node->getRight()->getType() == *boolType); + assignRightBlock->getSequence()->push_back( + CreateTempAssignmentNode(resultVariable, node->getRight())); + + TIntermIfElse *ifNode = + new TIntermIfElse(CreateTempSymbolNode(resultVariable), assignRightBlock, nullptr); + insertions.push_back(ifNode); + + insertStatementsInParentBlock(insertions); + + queueReplacement(CreateTempSymbolNode(resultVariable), OriginalNode::IS_DROPPED); + return false; + } + default: + UNREACHABLE(); + return true; + } +} + +bool UnfoldShortCircuitTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + if (mFoundShortCircuit) + return false; + + if (visit != PreVisit) + return true; + + if (!mPatternToUnfoldMatcher.match(node)) + return true; + + mFoundShortCircuit = true; + + // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" + TIntermSequence insertions; + TIntermDeclaration *tempDeclaration = nullptr; + TVariable *resultVariable = DeclareTempVariable(mSymbolTable, new TType(node->getType()), + EvqTemporary, &tempDeclaration); + insertions.push_back(tempDeclaration); + + TIntermBlock *trueBlock = new TIntermBlock(); + TIntermBinary *trueAssignment = + CreateTempAssignmentNode(resultVariable, node->getTrueExpression()); + trueBlock->getSequence()->push_back(trueAssignment); + + TIntermBlock *falseBlock = new TIntermBlock(); + TIntermBinary *falseAssignment = + CreateTempAssignmentNode(resultVariable, node->getFalseExpression()); + falseBlock->getSequence()->push_back(falseAssignment); + + TIntermIfElse *ifNode = + new TIntermIfElse(node->getCondition()->getAsTyped(), trueBlock, falseBlock); + insertions.push_back(ifNode); + + insertStatementsInParentBlock(insertions); + + TIntermSymbol *ternaryResult = CreateTempSymbolNode(resultVariable); + queueReplacement(ternaryResult, OriginalNode::IS_DROPPED); + + return false; +} + +void UnfoldShortCircuitTraverser::nextIteration() +{ + mFoundShortCircuit = false; +} + +} // namespace + +void UnfoldShortCircuitToIf(TIntermNode *root, TSymbolTable *symbolTable) +{ + UnfoldShortCircuitTraverser traverser(symbolTable); + // Unfold one operator at a time, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundShortCircuit()) + traverser.updateTree(); + } while (traverser.foundShortCircuit()); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h new file mode 100644 index 0000000000..3458cd27f0 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2002-2012 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. +// +// UnfoldShortCircuitToIf is an AST traverser to convert short-circuiting operators to if-else +// statements. +// The results are assigned to s# temporaries, which are used by the main translator instead of +// the original expression. +// + +#ifndef COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUIT_H_ +#define COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUIT_H_ + +namespace sh +{ + +class TIntermNode; +class TSymbolTable; + +void UnfoldShortCircuitToIf(TIntermNode *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_UNFOLDSHORTCIRCUIT_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp new file mode 100644 index 0000000000..83a133ca1f --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp @@ -0,0 +1,104 @@ +// +// 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/UseInterfaceBlockFields.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 + +void UseInterfaceBlockFields(TIntermBlock *root, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable) +{ + TIntermBlock *mainBody = FindMainBody(root); + InsertUseCode(mainBody->getSequence(), blocks, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h new file mode 100644 index 0000000000..37f0ba0220 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h @@ -0,0 +1,30 @@ +// +// 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_USEINTERFACEBLOCKFIELDS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_USEINTERFACEBLOCKFIELDS_H_ + +#include <GLSLANG/ShaderLang.h> + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +using InterfaceBlockList = std::vector<sh::InterfaceBlock>; + +void UseInterfaceBlockFields(TIntermBlock *root, + const InterfaceBlockList &blocks, + const TSymbolTable &symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_USEINTERFACEBLOCKFIELDS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp new file mode 100644 index 0000000000..221a73592b --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp @@ -0,0 +1,287 @@ +// Copyright (c) 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. +// +// VectorizeVectorScalarArithmetic.cpp: Turn some arithmetic operations that operate on a float +// vector-scalar pair into vector-vector operations. This is done recursively. Some scalar binary +// operations inside vector constructors are also turned into vector operations. +// +// This is targeted to work around a bug in NVIDIA OpenGL drivers that was reproducible on NVIDIA +// driver version 387.92. It works around the most common occurrences of the bug. + +#include "compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h" + +#include <set> + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class VectorizeVectorScalarArithmeticTraverser : public TIntermTraverser +{ + public: + VectorizeVectorScalarArithmeticTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, false, false, symbolTable), mReplaced(false) + {} + + bool didReplaceScalarsWithVectors() { return mReplaced; } + void nextIteration() + { + mReplaced = false; + mModifiedBlocks.clear(); + } + + protected: + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + private: + // These helpers should only be called from visitAggregate when visiting a constructor. + // argBinary is the only argument of the constructor. + void replaceMathInsideConstructor(TIntermAggregate *node, TIntermBinary *argBinary); + void replaceAssignInsideConstructor(const TIntermAggregate *node, + const TIntermBinary *argBinary); + + static TIntermTyped *Vectorize(TIntermTyped *node, + TType vectorType, + TIntermTraverser::OriginalNode *originalNodeFate); + + bool mReplaced; + std::set<const TIntermBlock *> mModifiedBlocks; +}; + +TIntermTyped *VectorizeVectorScalarArithmeticTraverser::Vectorize( + TIntermTyped *node, + TType vectorType, + TIntermTraverser::OriginalNode *originalNodeFate) +{ + ASSERT(node->isScalar()); + vectorType.setQualifier(EvqTemporary); + TIntermSequence vectorConstructorArgs; + vectorConstructorArgs.push_back(node); + TIntermAggregate *vectorized = + TIntermAggregate::CreateConstructor(vectorType, &vectorConstructorArgs); + TIntermTyped *vectorizedFolded = vectorized->fold(nullptr); + if (originalNodeFate != nullptr) + { + if (vectorizedFolded != vectorized) + { + *originalNodeFate = OriginalNode::IS_DROPPED; + } + else + { + *originalNodeFate = OriginalNode::BECOMES_CHILD; + } + } + return vectorizedFolded; +} + +bool VectorizeVectorScalarArithmeticTraverser::visitBinary(Visit /*visit*/, TIntermBinary *node) +{ + TIntermTyped *left = node->getLeft(); + TIntermTyped *right = node->getRight(); + ASSERT(left); + ASSERT(right); + switch (node->getOp()) + { + case EOpAdd: + case EOpAddAssign: + // Only these specific ops are necessary to turn into vector ops. + break; + default: + return true; + } + if (node->getBasicType() != EbtFloat) + { + // Only float ops have reproduced the bug. + return true; + } + if (left->isScalar() && right->isVector()) + { + ASSERT(!node->isAssignment()); + ASSERT(!right->isArray()); + OriginalNode originalNodeFate; + TIntermTyped *leftVectorized = Vectorize(left, right->getType(), &originalNodeFate); + queueReplacementWithParent(node, left, leftVectorized, originalNodeFate); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. However, nodes elsewhere + // in the tree may still be replaced. + return false; + } + else if (left->isVector() && right->isScalar()) + { + OriginalNode originalNodeFate; + TIntermTyped *rightVectorized = Vectorize(right, left->getType(), &originalNodeFate); + queueReplacementWithParent(node, right, rightVectorized, originalNodeFate); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. However, nodes elsewhere + // in the tree may still be replaced. + return false; + } + return true; +} + +void VectorizeVectorScalarArithmeticTraverser::replaceMathInsideConstructor( + TIntermAggregate *node, + TIntermBinary *argBinary) +{ + // Turn: + // a * b + // into: + // gvec(a) * gvec(b) + + TIntermTyped *left = argBinary->getLeft(); + TIntermTyped *right = argBinary->getRight(); + ASSERT(left->isScalar() && right->isScalar()); + + TType leftVectorizedType = left->getType(); + leftVectorizedType.setPrimarySize(static_cast<unsigned char>(node->getType().getNominalSize())); + TIntermTyped *leftVectorized = Vectorize(left, leftVectorizedType, nullptr); + TType rightVectorizedType = right->getType(); + rightVectorizedType.setPrimarySize( + static_cast<unsigned char>(node->getType().getNominalSize())); + TIntermTyped *rightVectorized = Vectorize(right, rightVectorizedType, nullptr); + + TIntermBinary *newArg = new TIntermBinary(argBinary->getOp(), leftVectorized, rightVectorized); + queueReplacementWithParent(node, argBinary, newArg, OriginalNode::IS_DROPPED); +} + +void VectorizeVectorScalarArithmeticTraverser::replaceAssignInsideConstructor( + const TIntermAggregate *node, + const TIntermBinary *argBinary) +{ + // Turn: + // gvec(a *= b); + // into: + // // This is inserted into the parent block: + // gvec s0 = gvec(a); + // + // // This goes where the gvec constructor used to be: + // ((s0 *= b, a = s0.x), s0); + + TIntermTyped *left = argBinary->getLeft(); + TIntermTyped *right = argBinary->getRight(); + ASSERT(left->isScalar() && right->isScalar()); + ASSERT(!left->hasSideEffects()); + + TType vecType = node->getType(); + vecType.setQualifier(EvqTemporary); + + // gvec s0 = gvec(a); + // s0 is called "tempAssignmentTarget" below. + TIntermTyped *tempAssignmentTargetInitializer = Vectorize(left->deepCopy(), vecType, nullptr); + TIntermDeclaration *tempAssignmentTargetDeclaration = nullptr; + TVariable *tempAssignmentTarget = + DeclareTempVariable(mSymbolTable, tempAssignmentTargetInitializer, EvqTemporary, + &tempAssignmentTargetDeclaration); + + // s0 *= b + TOperator compoundAssignmentOp = argBinary->getOp(); + if (compoundAssignmentOp == EOpMulAssign) + { + compoundAssignmentOp = EOpVectorTimesScalarAssign; + } + TIntermBinary *replacementCompoundAssignment = new TIntermBinary( + compoundAssignmentOp, CreateTempSymbolNode(tempAssignmentTarget), right->deepCopy()); + + // s0.x + TVector<int> swizzleXOffset; + swizzleXOffset.push_back(0); + TIntermSwizzle *tempAssignmentTargetX = + new TIntermSwizzle(CreateTempSymbolNode(tempAssignmentTarget), swizzleXOffset); + // a = s0.x + TIntermBinary *replacementAssignBackToTarget = + new TIntermBinary(EOpAssign, left->deepCopy(), tempAssignmentTargetX); + + // s0 *= b, a = s0.x + TIntermBinary *replacementSequenceLeft = + new TIntermBinary(EOpComma, replacementCompoundAssignment, replacementAssignBackToTarget); + // (s0 *= b, a = s0.x), s0 + // Note that the created comma node is not const qualified in any case, so we can always pass + // shader version 300 here. + TIntermBinary *replacementSequence = TIntermBinary::CreateComma( + replacementSequenceLeft, CreateTempSymbolNode(tempAssignmentTarget), 300); + + insertStatementInParentBlock(tempAssignmentTargetDeclaration); + queueReplacement(replacementSequence, OriginalNode::IS_DROPPED); +} + +bool VectorizeVectorScalarArithmeticTraverser::visitAggregate(Visit /*visit*/, + TIntermAggregate *node) +{ + // Transform scalar binary expressions inside vector constructors. + if (!node->isConstructor() || !node->isVector() || node->getSequence()->size() != 1) + { + return true; + } + TIntermTyped *argument = node->getSequence()->back()->getAsTyped(); + ASSERT(argument); + if (!argument->isScalar() || argument->getBasicType() != EbtFloat) + { + return true; + } + TIntermBinary *argBinary = argument->getAsBinaryNode(); + if (!argBinary) + { + return true; + } + + // Only specific ops are necessary to change. + switch (argBinary->getOp()) + { + case EOpMul: + case EOpDiv: + { + replaceMathInsideConstructor(node, argBinary); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. However, nodes + // elsewhere in the tree may still be replaced. + return false; + } + case EOpMulAssign: + case EOpDivAssign: + { + // The case where the left side has side effects is too complicated to deal with, so we + // leave that be. + if (!argBinary->getLeft()->hasSideEffects()) + { + const TIntermBlock *parentBlock = getParentBlock(); + // We can't do more than one insertion to the same block on the same traversal. + if (mModifiedBlocks.find(parentBlock) == mModifiedBlocks.end()) + { + replaceAssignInsideConstructor(node, argBinary); + mModifiedBlocks.insert(parentBlock); + mReplaced = true; + // Don't replace more nodes in the same subtree on this traversal. + // However, nodes elsewhere in the tree may still be replaced. + return false; + } + } + break; + } + default: + return true; + } + return true; +} + +} // anonymous namespace + +void VectorizeVectorScalarArithmetic(TIntermBlock *root, TSymbolTable *symbolTable) +{ + VectorizeVectorScalarArithmeticTraverser traverser(symbolTable); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + traverser.updateTree(); + } while (traverser.didReplaceScalarsWithVectors()); +} + +} // namespace sh
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h new file mode 100644 index 0000000000..e6480646f8 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h @@ -0,0 +1,25 @@ +// Copyright (c) 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. +// +// VectorizeVectorScalarArithmetic.h: Turn some arithmetic operations that operate on a float +// vector-scalar pair into vector-vector operations. This is done recursively. Some scalar binary +// operations inside vector constructors are also turned into vector operations. +// +// This is targeted to work around a bug in NVIDIA OpenGL drivers that was reproducible on NVIDIA +// driver version 387.92. It works around the most common occurrences of the bug. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_VECTORIZEVECTORSCALARARITHMETIC_H_ +#define COMPILER_TRANSLATOR_TREEOPS_VECTORIZEVECTORSCALARARITHMETIC_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void VectorizeVectorScalarArithmetic(TIntermBlock *root, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_VECTORIZEVECTORSCALARARITHMETIC_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp new file mode 100644 index 0000000000..5a4dd30853 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp @@ -0,0 +1,126 @@ +// +// Copyright (c) 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. +// +// WrapSwitchStatementsInBlocks.cpp: Wrap switch statements in blocks and declare all switch-scoped +// variables there to make the AST compatible with HLSL output. +// +// switch (init) +// { +// case 0: +// float f; +// default: +// f = 1.0; +// } +// +// becomes +// +// { +// float f; +// switch (init) +// { +// case 0: +// default: +// f = 1.0; +// } +// } + +#include "compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class WrapSwitchStatementsInBlocksTraverser : public TIntermTraverser +{ + public: + WrapSwitchStatementsInBlocksTraverser() : TIntermTraverser(true, false, false) {} + + bool visitSwitch(Visit visit, TIntermSwitch *node) override; +}; + +bool WrapSwitchStatementsInBlocksTraverser::visitSwitch(Visit, TIntermSwitch *node) +{ + std::vector<TIntermDeclaration *> declarations; + TIntermSequence *statementList = node->getStatementList()->getSequence(); + for (TIntermNode *statement : *statementList) + { + TIntermDeclaration *asDeclaration = statement->getAsDeclarationNode(); + if (asDeclaration) + { + declarations.push_back(asDeclaration); + } + } + if (declarations.empty()) + { + // We don't need to wrap the switch if it doesn't contain declarations as its direct + // descendants. + return true; + } + + TIntermBlock *wrapperBlock = new TIntermBlock(); + for (TIntermDeclaration *declaration : declarations) + { + // SeparateDeclarations should have already been run. + ASSERT(declaration->getSequence()->size() == 1); + + TIntermDeclaration *declarationInBlock = new TIntermDeclaration(); + TIntermSymbol *declaratorAsSymbol = declaration->getSequence()->at(0)->getAsSymbolNode(); + if (declaratorAsSymbol) + { + // This is a simple declaration like: "float f;" + // Remove the declaration from inside the switch and put it in the wrapping block. + TIntermSequence emptyReplacement; + mMultiReplacements.push_back(NodeReplaceWithMultipleEntry( + node->getStatementList(), declaration, emptyReplacement)); + + declarationInBlock->appendDeclarator(declaratorAsSymbol->deepCopy()); + // The declaration can't be the last statement inside the switch since unused variables + // should already have been pruned. + ASSERT(declaration != statementList->back()); + } + else + { + // This is an init declaration like: "float f = 0.0;" + // Change the init declaration inside the switch into an assignment and put a plain + // declaration in the wrapping block. + TIntermBinary *declaratorAsBinary = + declaration->getSequence()->at(0)->getAsBinaryNode(); + ASSERT(declaratorAsBinary); + + TIntermBinary *initAssignment = new TIntermBinary( + EOpAssign, declaratorAsBinary->getLeft(), declaratorAsBinary->getRight()); + + queueReplacementWithParent(node->getStatementList(), declaration, initAssignment, + OriginalNode::IS_DROPPED); + + declarationInBlock->appendDeclarator(declaratorAsBinary->getLeft()->deepCopy()); + } + wrapperBlock->appendStatement(declarationInBlock); + } + + wrapperBlock->appendStatement(node); + queueReplacement(wrapperBlock, OriginalNode::BECOMES_CHILD); + + // Should be fine to process multiple switch statements, even nesting ones in the same + // traversal. + return true; +} + +} // anonymous namespace + +// Wrap switch statements in the AST into blocks when needed. +void WrapSwitchStatementsInBlocks(TIntermBlock *root) +{ + WrapSwitchStatementsInBlocksTraverser traverser; + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h new file mode 100644 index 0000000000..d04893cb52 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 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. +// +// WrapSwitchStatementsInBlocks.h: Wrap switch statements in blocks and declare all switch-scoped +// variables there to make the AST compatible with HLSL output. + +#ifndef COMPILER_TRANSLATOR_TREEOPS_WRAPSWITCHSTATEMENTSINBLOCKS_H_ +#define COMPILER_TRANSLATOR_TREEOPS_WRAPSWITCHSTATEMENTSINBLOCKS_H_ + +namespace sh +{ + +class TIntermBlock; + +// Wrap switch statements in the AST into blocks when needed. Returns true if the AST was changed. +void WrapSwitchStatementsInBlocks(TIntermBlock *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEOPS_WRAPSWITCHSTATEMENTSINBLOCKS_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h b/gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h new file mode 100644 index 0000000000..6c84834550 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h @@ -0,0 +1,1373 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by gen_builtin_symbols.py using data from builtin_variables.json and +// builtin_function_declarations.txt. +// +// 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. +// +// BuiltIn_autogen.h: +// Compile-time initialized built-ins. + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ + +#include "compiler/translator/SymbolUniqueId.h" + +namespace sh +{ + +class TVariable; + +class BuiltInId +{ + public: + static constexpr const TSymbolUniqueId radians_Float1 = TSymbolUniqueId(0); + static constexpr const TSymbolUniqueId pt0B = TSymbolUniqueId(1); + static constexpr const TSymbolUniqueId radians_Float2 = TSymbolUniqueId(2); + static constexpr const TSymbolUniqueId pt1B = TSymbolUniqueId(3); + static constexpr const TSymbolUniqueId radians_Float3 = TSymbolUniqueId(4); + static constexpr const TSymbolUniqueId pt2B = TSymbolUniqueId(5); + static constexpr const TSymbolUniqueId radians_Float4 = TSymbolUniqueId(6); + static constexpr const TSymbolUniqueId pt3B = TSymbolUniqueId(7); + static constexpr const TSymbolUniqueId degrees_Float1 = TSymbolUniqueId(8); + static constexpr const TSymbolUniqueId degrees_Float2 = TSymbolUniqueId(9); + static constexpr const TSymbolUniqueId degrees_Float3 = TSymbolUniqueId(10); + static constexpr const TSymbolUniqueId degrees_Float4 = TSymbolUniqueId(11); + static constexpr const TSymbolUniqueId sin_Float1 = TSymbolUniqueId(12); + static constexpr const TSymbolUniqueId sin_Float2 = TSymbolUniqueId(13); + static constexpr const TSymbolUniqueId sin_Float3 = TSymbolUniqueId(14); + static constexpr const TSymbolUniqueId sin_Float4 = TSymbolUniqueId(15); + static constexpr const TSymbolUniqueId cos_Float1 = TSymbolUniqueId(16); + static constexpr const TSymbolUniqueId cos_Float2 = TSymbolUniqueId(17); + static constexpr const TSymbolUniqueId cos_Float3 = TSymbolUniqueId(18); + static constexpr const TSymbolUniqueId cos_Float4 = TSymbolUniqueId(19); + static constexpr const TSymbolUniqueId tan_Float1 = TSymbolUniqueId(20); + static constexpr const TSymbolUniqueId tan_Float2 = TSymbolUniqueId(21); + static constexpr const TSymbolUniqueId tan_Float3 = TSymbolUniqueId(22); + static constexpr const TSymbolUniqueId tan_Float4 = TSymbolUniqueId(23); + static constexpr const TSymbolUniqueId asin_Float1 = TSymbolUniqueId(24); + static constexpr const TSymbolUniqueId asin_Float2 = TSymbolUniqueId(25); + static constexpr const TSymbolUniqueId asin_Float3 = TSymbolUniqueId(26); + static constexpr const TSymbolUniqueId asin_Float4 = TSymbolUniqueId(27); + static constexpr const TSymbolUniqueId acos_Float1 = TSymbolUniqueId(28); + static constexpr const TSymbolUniqueId acos_Float2 = TSymbolUniqueId(29); + static constexpr const TSymbolUniqueId acos_Float3 = TSymbolUniqueId(30); + static constexpr const TSymbolUniqueId acos_Float4 = TSymbolUniqueId(31); + static constexpr const TSymbolUniqueId atan_Float1_Float1 = TSymbolUniqueId(32); + static constexpr const TSymbolUniqueId atan_Float2_Float2 = TSymbolUniqueId(33); + static constexpr const TSymbolUniqueId atan_Float3_Float3 = TSymbolUniqueId(34); + static constexpr const TSymbolUniqueId atan_Float4_Float4 = TSymbolUniqueId(35); + static constexpr const TSymbolUniqueId atan_Float1 = TSymbolUniqueId(36); + static constexpr const TSymbolUniqueId atan_Float2 = TSymbolUniqueId(37); + static constexpr const TSymbolUniqueId atan_Float3 = TSymbolUniqueId(38); + static constexpr const TSymbolUniqueId atan_Float4 = TSymbolUniqueId(39); + static constexpr const TSymbolUniqueId sinh_Float1 = TSymbolUniqueId(40); + static constexpr const TSymbolUniqueId sinh_Float2 = TSymbolUniqueId(41); + static constexpr const TSymbolUniqueId sinh_Float3 = TSymbolUniqueId(42); + static constexpr const TSymbolUniqueId sinh_Float4 = TSymbolUniqueId(43); + static constexpr const TSymbolUniqueId cosh_Float1 = TSymbolUniqueId(44); + static constexpr const TSymbolUniqueId cosh_Float2 = TSymbolUniqueId(45); + static constexpr const TSymbolUniqueId cosh_Float3 = TSymbolUniqueId(46); + static constexpr const TSymbolUniqueId cosh_Float4 = TSymbolUniqueId(47); + static constexpr const TSymbolUniqueId tanh_Float1 = TSymbolUniqueId(48); + static constexpr const TSymbolUniqueId tanh_Float2 = TSymbolUniqueId(49); + static constexpr const TSymbolUniqueId tanh_Float3 = TSymbolUniqueId(50); + static constexpr const TSymbolUniqueId tanh_Float4 = TSymbolUniqueId(51); + static constexpr const TSymbolUniqueId asinh_Float1 = TSymbolUniqueId(52); + static constexpr const TSymbolUniqueId asinh_Float2 = TSymbolUniqueId(53); + static constexpr const TSymbolUniqueId asinh_Float3 = TSymbolUniqueId(54); + static constexpr const TSymbolUniqueId asinh_Float4 = TSymbolUniqueId(55); + static constexpr const TSymbolUniqueId acosh_Float1 = TSymbolUniqueId(56); + static constexpr const TSymbolUniqueId acosh_Float2 = TSymbolUniqueId(57); + static constexpr const TSymbolUniqueId acosh_Float3 = TSymbolUniqueId(58); + static constexpr const TSymbolUniqueId acosh_Float4 = TSymbolUniqueId(59); + static constexpr const TSymbolUniqueId atanh_Float1 = TSymbolUniqueId(60); + static constexpr const TSymbolUniqueId atanh_Float2 = TSymbolUniqueId(61); + static constexpr const TSymbolUniqueId atanh_Float3 = TSymbolUniqueId(62); + static constexpr const TSymbolUniqueId atanh_Float4 = TSymbolUniqueId(63); + static constexpr const TSymbolUniqueId pow_Float1_Float1 = TSymbolUniqueId(64); + static constexpr const TSymbolUniqueId pow_Float2_Float2 = TSymbolUniqueId(65); + static constexpr const TSymbolUniqueId pow_Float3_Float3 = TSymbolUniqueId(66); + static constexpr const TSymbolUniqueId pow_Float4_Float4 = TSymbolUniqueId(67); + static constexpr const TSymbolUniqueId exp_Float1 = TSymbolUniqueId(68); + static constexpr const TSymbolUniqueId exp_Float2 = TSymbolUniqueId(69); + static constexpr const TSymbolUniqueId exp_Float3 = TSymbolUniqueId(70); + static constexpr const TSymbolUniqueId exp_Float4 = TSymbolUniqueId(71); + static constexpr const TSymbolUniqueId log_Float1 = TSymbolUniqueId(72); + static constexpr const TSymbolUniqueId log_Float2 = TSymbolUniqueId(73); + static constexpr const TSymbolUniqueId log_Float3 = TSymbolUniqueId(74); + static constexpr const TSymbolUniqueId log_Float4 = TSymbolUniqueId(75); + static constexpr const TSymbolUniqueId exp2_Float1 = TSymbolUniqueId(76); + static constexpr const TSymbolUniqueId exp2_Float2 = TSymbolUniqueId(77); + static constexpr const TSymbolUniqueId exp2_Float3 = TSymbolUniqueId(78); + static constexpr const TSymbolUniqueId exp2_Float4 = TSymbolUniqueId(79); + static constexpr const TSymbolUniqueId log2_Float1 = TSymbolUniqueId(80); + static constexpr const TSymbolUniqueId log2_Float2 = TSymbolUniqueId(81); + static constexpr const TSymbolUniqueId log2_Float3 = TSymbolUniqueId(82); + static constexpr const TSymbolUniqueId log2_Float4 = TSymbolUniqueId(83); + static constexpr const TSymbolUniqueId sqrt_Float1 = TSymbolUniqueId(84); + static constexpr const TSymbolUniqueId sqrt_Float2 = TSymbolUniqueId(85); + static constexpr const TSymbolUniqueId sqrt_Float3 = TSymbolUniqueId(86); + static constexpr const TSymbolUniqueId sqrt_Float4 = TSymbolUniqueId(87); + static constexpr const TSymbolUniqueId inversesqrt_Float1 = TSymbolUniqueId(88); + static constexpr const TSymbolUniqueId inversesqrt_Float2 = TSymbolUniqueId(89); + static constexpr const TSymbolUniqueId inversesqrt_Float3 = TSymbolUniqueId(90); + static constexpr const TSymbolUniqueId inversesqrt_Float4 = TSymbolUniqueId(91); + static constexpr const TSymbolUniqueId abs_Float1 = TSymbolUniqueId(92); + static constexpr const TSymbolUniqueId abs_Float2 = TSymbolUniqueId(93); + static constexpr const TSymbolUniqueId abs_Float3 = TSymbolUniqueId(94); + static constexpr const TSymbolUniqueId abs_Float4 = TSymbolUniqueId(95); + static constexpr const TSymbolUniqueId abs_Int1 = TSymbolUniqueId(96); + static constexpr const TSymbolUniqueId pt0C = TSymbolUniqueId(97); + static constexpr const TSymbolUniqueId abs_Int2 = TSymbolUniqueId(98); + static constexpr const TSymbolUniqueId pt1C = TSymbolUniqueId(99); + static constexpr const TSymbolUniqueId abs_Int3 = TSymbolUniqueId(100); + static constexpr const TSymbolUniqueId pt2C = TSymbolUniqueId(101); + static constexpr const TSymbolUniqueId abs_Int4 = TSymbolUniqueId(102); + static constexpr const TSymbolUniqueId pt3C = TSymbolUniqueId(103); + static constexpr const TSymbolUniqueId sign_Float1 = TSymbolUniqueId(104); + static constexpr const TSymbolUniqueId sign_Float2 = TSymbolUniqueId(105); + static constexpr const TSymbolUniqueId sign_Float3 = TSymbolUniqueId(106); + static constexpr const TSymbolUniqueId sign_Float4 = TSymbolUniqueId(107); + static constexpr const TSymbolUniqueId sign_Int1 = TSymbolUniqueId(108); + static constexpr const TSymbolUniqueId sign_Int2 = TSymbolUniqueId(109); + static constexpr const TSymbolUniqueId sign_Int3 = TSymbolUniqueId(110); + static constexpr const TSymbolUniqueId sign_Int4 = TSymbolUniqueId(111); + static constexpr const TSymbolUniqueId floor_Float1 = TSymbolUniqueId(112); + static constexpr const TSymbolUniqueId floor_Float2 = TSymbolUniqueId(113); + static constexpr const TSymbolUniqueId floor_Float3 = TSymbolUniqueId(114); + static constexpr const TSymbolUniqueId floor_Float4 = TSymbolUniqueId(115); + static constexpr const TSymbolUniqueId trunc_Float1 = TSymbolUniqueId(116); + static constexpr const TSymbolUniqueId trunc_Float2 = TSymbolUniqueId(117); + static constexpr const TSymbolUniqueId trunc_Float3 = TSymbolUniqueId(118); + static constexpr const TSymbolUniqueId trunc_Float4 = TSymbolUniqueId(119); + static constexpr const TSymbolUniqueId round_Float1 = TSymbolUniqueId(120); + static constexpr const TSymbolUniqueId round_Float2 = TSymbolUniqueId(121); + static constexpr const TSymbolUniqueId round_Float3 = TSymbolUniqueId(122); + static constexpr const TSymbolUniqueId round_Float4 = TSymbolUniqueId(123); + static constexpr const TSymbolUniqueId roundEven_Float1 = TSymbolUniqueId(124); + static constexpr const TSymbolUniqueId roundEven_Float2 = TSymbolUniqueId(125); + static constexpr const TSymbolUniqueId roundEven_Float3 = TSymbolUniqueId(126); + static constexpr const TSymbolUniqueId roundEven_Float4 = TSymbolUniqueId(127); + static constexpr const TSymbolUniqueId ceil_Float1 = TSymbolUniqueId(128); + static constexpr const TSymbolUniqueId ceil_Float2 = TSymbolUniqueId(129); + static constexpr const TSymbolUniqueId ceil_Float3 = TSymbolUniqueId(130); + static constexpr const TSymbolUniqueId ceil_Float4 = TSymbolUniqueId(131); + static constexpr const TSymbolUniqueId fract_Float1 = TSymbolUniqueId(132); + static constexpr const TSymbolUniqueId fract_Float2 = TSymbolUniqueId(133); + static constexpr const TSymbolUniqueId fract_Float3 = TSymbolUniqueId(134); + static constexpr const TSymbolUniqueId fract_Float4 = TSymbolUniqueId(135); + static constexpr const TSymbolUniqueId mod_Float1_Float1 = TSymbolUniqueId(136); + static constexpr const TSymbolUniqueId mod_Float2_Float1 = TSymbolUniqueId(137); + static constexpr const TSymbolUniqueId mod_Float3_Float1 = TSymbolUniqueId(138); + static constexpr const TSymbolUniqueId mod_Float4_Float1 = TSymbolUniqueId(139); + static constexpr const TSymbolUniqueId mod_Float2_Float2 = TSymbolUniqueId(140); + static constexpr const TSymbolUniqueId mod_Float3_Float3 = TSymbolUniqueId(141); + static constexpr const TSymbolUniqueId mod_Float4_Float4 = TSymbolUniqueId(142); + static constexpr const TSymbolUniqueId min_Float1_Float1 = TSymbolUniqueId(143); + static constexpr const TSymbolUniqueId min_Float2_Float1 = TSymbolUniqueId(144); + static constexpr const TSymbolUniqueId min_Float3_Float1 = TSymbolUniqueId(145); + static constexpr const TSymbolUniqueId min_Float4_Float1 = TSymbolUniqueId(146); + static constexpr const TSymbolUniqueId min_Float2_Float2 = TSymbolUniqueId(147); + static constexpr const TSymbolUniqueId min_Float3_Float3 = TSymbolUniqueId(148); + static constexpr const TSymbolUniqueId min_Float4_Float4 = TSymbolUniqueId(149); + static constexpr const TSymbolUniqueId min_Int1_Int1 = TSymbolUniqueId(150); + static constexpr const TSymbolUniqueId min_Int2_Int2 = TSymbolUniqueId(151); + static constexpr const TSymbolUniqueId min_Int3_Int3 = TSymbolUniqueId(152); + static constexpr const TSymbolUniqueId min_Int4_Int4 = TSymbolUniqueId(153); + static constexpr const TSymbolUniqueId min_Int2_Int1 = TSymbolUniqueId(154); + static constexpr const TSymbolUniqueId min_Int3_Int1 = TSymbolUniqueId(155); + static constexpr const TSymbolUniqueId min_Int4_Int1 = TSymbolUniqueId(156); + static constexpr const TSymbolUniqueId min_UInt1_UInt1 = TSymbolUniqueId(157); + static constexpr const TSymbolUniqueId pt0D = TSymbolUniqueId(158); + static constexpr const TSymbolUniqueId min_UInt2_UInt2 = TSymbolUniqueId(159); + static constexpr const TSymbolUniqueId pt1D = TSymbolUniqueId(160); + static constexpr const TSymbolUniqueId min_UInt3_UInt3 = TSymbolUniqueId(161); + static constexpr const TSymbolUniqueId pt2D = TSymbolUniqueId(162); + static constexpr const TSymbolUniqueId min_UInt4_UInt4 = TSymbolUniqueId(163); + static constexpr const TSymbolUniqueId pt3D = TSymbolUniqueId(164); + static constexpr const TSymbolUniqueId min_UInt2_UInt1 = TSymbolUniqueId(165); + static constexpr const TSymbolUniqueId min_UInt3_UInt1 = TSymbolUniqueId(166); + static constexpr const TSymbolUniqueId min_UInt4_UInt1 = TSymbolUniqueId(167); + static constexpr const TSymbolUniqueId max_Float1_Float1 = TSymbolUniqueId(168); + static constexpr const TSymbolUniqueId max_Float2_Float1 = TSymbolUniqueId(169); + static constexpr const TSymbolUniqueId max_Float3_Float1 = TSymbolUniqueId(170); + static constexpr const TSymbolUniqueId max_Float4_Float1 = TSymbolUniqueId(171); + static constexpr const TSymbolUniqueId max_Float2_Float2 = TSymbolUniqueId(172); + static constexpr const TSymbolUniqueId max_Float3_Float3 = TSymbolUniqueId(173); + static constexpr const TSymbolUniqueId max_Float4_Float4 = TSymbolUniqueId(174); + static constexpr const TSymbolUniqueId max_Int1_Int1 = TSymbolUniqueId(175); + static constexpr const TSymbolUniqueId max_Int2_Int2 = TSymbolUniqueId(176); + static constexpr const TSymbolUniqueId max_Int3_Int3 = TSymbolUniqueId(177); + static constexpr const TSymbolUniqueId max_Int4_Int4 = TSymbolUniqueId(178); + static constexpr const TSymbolUniqueId max_Int2_Int1 = TSymbolUniqueId(179); + static constexpr const TSymbolUniqueId max_Int3_Int1 = TSymbolUniqueId(180); + static constexpr const TSymbolUniqueId max_Int4_Int1 = TSymbolUniqueId(181); + static constexpr const TSymbolUniqueId max_UInt1_UInt1 = TSymbolUniqueId(182); + static constexpr const TSymbolUniqueId max_UInt2_UInt2 = TSymbolUniqueId(183); + static constexpr const TSymbolUniqueId max_UInt3_UInt3 = TSymbolUniqueId(184); + static constexpr const TSymbolUniqueId max_UInt4_UInt4 = TSymbolUniqueId(185); + static constexpr const TSymbolUniqueId max_UInt2_UInt1 = TSymbolUniqueId(186); + static constexpr const TSymbolUniqueId max_UInt3_UInt1 = TSymbolUniqueId(187); + static constexpr const TSymbolUniqueId max_UInt4_UInt1 = TSymbolUniqueId(188); + static constexpr const TSymbolUniqueId clamp_Float1_Float1_Float1 = TSymbolUniqueId(189); + static constexpr const TSymbolUniqueId clamp_Float2_Float1_Float1 = TSymbolUniqueId(190); + static constexpr const TSymbolUniqueId clamp_Float3_Float1_Float1 = TSymbolUniqueId(191); + static constexpr const TSymbolUniqueId clamp_Float4_Float1_Float1 = TSymbolUniqueId(192); + static constexpr const TSymbolUniqueId clamp_Float2_Float2_Float2 = TSymbolUniqueId(193); + static constexpr const TSymbolUniqueId clamp_Float3_Float3_Float3 = TSymbolUniqueId(194); + static constexpr const TSymbolUniqueId clamp_Float4_Float4_Float4 = TSymbolUniqueId(195); + static constexpr const TSymbolUniqueId clamp_Int1_Int1_Int1 = TSymbolUniqueId(196); + static constexpr const TSymbolUniqueId clamp_Int2_Int1_Int1 = TSymbolUniqueId(197); + static constexpr const TSymbolUniqueId clamp_Int3_Int1_Int1 = TSymbolUniqueId(198); + static constexpr const TSymbolUniqueId clamp_Int4_Int1_Int1 = TSymbolUniqueId(199); + static constexpr const TSymbolUniqueId clamp_Int2_Int2_Int2 = TSymbolUniqueId(200); + static constexpr const TSymbolUniqueId clamp_Int3_Int3_Int3 = TSymbolUniqueId(201); + static constexpr const TSymbolUniqueId clamp_Int4_Int4_Int4 = TSymbolUniqueId(202); + static constexpr const TSymbolUniqueId clamp_UInt1_UInt1_UInt1 = TSymbolUniqueId(203); + static constexpr const TSymbolUniqueId clamp_UInt2_UInt1_UInt1 = TSymbolUniqueId(204); + static constexpr const TSymbolUniqueId clamp_UInt3_UInt1_UInt1 = TSymbolUniqueId(205); + static constexpr const TSymbolUniqueId clamp_UInt4_UInt1_UInt1 = TSymbolUniqueId(206); + static constexpr const TSymbolUniqueId clamp_UInt2_UInt2_UInt2 = TSymbolUniqueId(207); + static constexpr const TSymbolUniqueId clamp_UInt3_UInt3_UInt3 = TSymbolUniqueId(208); + static constexpr const TSymbolUniqueId clamp_UInt4_UInt4_UInt4 = TSymbolUniqueId(209); + static constexpr const TSymbolUniqueId mix_Float1_Float1_Float1 = TSymbolUniqueId(210); + static constexpr const TSymbolUniqueId mix_Float2_Float2_Float1 = TSymbolUniqueId(211); + static constexpr const TSymbolUniqueId mix_Float3_Float3_Float1 = TSymbolUniqueId(212); + static constexpr const TSymbolUniqueId mix_Float4_Float4_Float1 = TSymbolUniqueId(213); + static constexpr const TSymbolUniqueId mix_Float2_Float2_Float2 = TSymbolUniqueId(214); + static constexpr const TSymbolUniqueId mix_Float3_Float3_Float3 = TSymbolUniqueId(215); + static constexpr const TSymbolUniqueId mix_Float4_Float4_Float4 = TSymbolUniqueId(216); + static constexpr const TSymbolUniqueId mix_Float1_Float1_Bool1 = TSymbolUniqueId(217); + static constexpr const TSymbolUniqueId pt0E = TSymbolUniqueId(218); + static constexpr const TSymbolUniqueId mix_Float2_Float2_Bool2 = TSymbolUniqueId(219); + static constexpr const TSymbolUniqueId pt1E = TSymbolUniqueId(220); + static constexpr const TSymbolUniqueId mix_Float3_Float3_Bool3 = TSymbolUniqueId(221); + static constexpr const TSymbolUniqueId pt2E = TSymbolUniqueId(222); + static constexpr const TSymbolUniqueId mix_Float4_Float4_Bool4 = TSymbolUniqueId(223); + static constexpr const TSymbolUniqueId pt3E = TSymbolUniqueId(224); + static constexpr const TSymbolUniqueId step_Float1_Float1 = TSymbolUniqueId(225); + static constexpr const TSymbolUniqueId step_Float2_Float2 = TSymbolUniqueId(226); + static constexpr const TSymbolUniqueId step_Float3_Float3 = TSymbolUniqueId(227); + static constexpr const TSymbolUniqueId step_Float4_Float4 = TSymbolUniqueId(228); + static constexpr const TSymbolUniqueId step_Float1_Float2 = TSymbolUniqueId(229); + static constexpr const TSymbolUniqueId step_Float1_Float3 = TSymbolUniqueId(230); + static constexpr const TSymbolUniqueId step_Float1_Float4 = TSymbolUniqueId(231); + static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float1 = TSymbolUniqueId(232); + static constexpr const TSymbolUniqueId smoothstep_Float2_Float2_Float2 = TSymbolUniqueId(233); + static constexpr const TSymbolUniqueId smoothstep_Float3_Float3_Float3 = TSymbolUniqueId(234); + static constexpr const TSymbolUniqueId smoothstep_Float4_Float4_Float4 = TSymbolUniqueId(235); + static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float2 = TSymbolUniqueId(236); + static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float3 = TSymbolUniqueId(237); + static constexpr const TSymbolUniqueId smoothstep_Float1_Float1_Float4 = TSymbolUniqueId(238); + static constexpr const TSymbolUniqueId modf_Float1_Float1 = TSymbolUniqueId(239); + static constexpr const TSymbolUniqueId pt_o_0B = TSymbolUniqueId(240); + static constexpr const TSymbolUniqueId modf_Float2_Float2 = TSymbolUniqueId(241); + static constexpr const TSymbolUniqueId pt_o_1B = TSymbolUniqueId(242); + static constexpr const TSymbolUniqueId modf_Float3_Float3 = TSymbolUniqueId(243); + static constexpr const TSymbolUniqueId pt_o_2B = TSymbolUniqueId(244); + static constexpr const TSymbolUniqueId modf_Float4_Float4 = TSymbolUniqueId(245); + static constexpr const TSymbolUniqueId pt_o_3B = TSymbolUniqueId(246); + static constexpr const TSymbolUniqueId isnan_Float1 = TSymbolUniqueId(247); + static constexpr const TSymbolUniqueId isnan_Float2 = TSymbolUniqueId(248); + static constexpr const TSymbolUniqueId isnan_Float3 = TSymbolUniqueId(249); + static constexpr const TSymbolUniqueId isnan_Float4 = TSymbolUniqueId(250); + static constexpr const TSymbolUniqueId isinf_Float1 = TSymbolUniqueId(251); + static constexpr const TSymbolUniqueId isinf_Float2 = TSymbolUniqueId(252); + static constexpr const TSymbolUniqueId isinf_Float3 = TSymbolUniqueId(253); + static constexpr const TSymbolUniqueId isinf_Float4 = TSymbolUniqueId(254); + static constexpr const TSymbolUniqueId floatBitsToInt_Float1 = TSymbolUniqueId(255); + static constexpr const TSymbolUniqueId floatBitsToInt_Float2 = TSymbolUniqueId(256); + static constexpr const TSymbolUniqueId floatBitsToInt_Float3 = TSymbolUniqueId(257); + static constexpr const TSymbolUniqueId floatBitsToInt_Float4 = TSymbolUniqueId(258); + static constexpr const TSymbolUniqueId floatBitsToUint_Float1 = TSymbolUniqueId(259); + static constexpr const TSymbolUniqueId floatBitsToUint_Float2 = TSymbolUniqueId(260); + static constexpr const TSymbolUniqueId floatBitsToUint_Float3 = TSymbolUniqueId(261); + static constexpr const TSymbolUniqueId floatBitsToUint_Float4 = TSymbolUniqueId(262); + static constexpr const TSymbolUniqueId intBitsToFloat_Int1 = TSymbolUniqueId(263); + static constexpr const TSymbolUniqueId intBitsToFloat_Int2 = TSymbolUniqueId(264); + static constexpr const TSymbolUniqueId intBitsToFloat_Int3 = TSymbolUniqueId(265); + static constexpr const TSymbolUniqueId intBitsToFloat_Int4 = TSymbolUniqueId(266); + static constexpr const TSymbolUniqueId uintBitsToFloat_UInt1 = TSymbolUniqueId(267); + static constexpr const TSymbolUniqueId uintBitsToFloat_UInt2 = TSymbolUniqueId(268); + static constexpr const TSymbolUniqueId uintBitsToFloat_UInt3 = TSymbolUniqueId(269); + static constexpr const TSymbolUniqueId uintBitsToFloat_UInt4 = TSymbolUniqueId(270); + static constexpr const TSymbolUniqueId frexp_Float1_Int1 = TSymbolUniqueId(271); + static constexpr const TSymbolUniqueId pt_o_0C = TSymbolUniqueId(272); + static constexpr const TSymbolUniqueId frexp_Float2_Int2 = TSymbolUniqueId(273); + static constexpr const TSymbolUniqueId pt_o_1C = TSymbolUniqueId(274); + static constexpr const TSymbolUniqueId frexp_Float3_Int3 = TSymbolUniqueId(275); + static constexpr const TSymbolUniqueId pt_o_2C = TSymbolUniqueId(276); + static constexpr const TSymbolUniqueId frexp_Float4_Int4 = TSymbolUniqueId(277); + static constexpr const TSymbolUniqueId pt_o_3C = TSymbolUniqueId(278); + static constexpr const TSymbolUniqueId ldexp_Float1_Int1 = TSymbolUniqueId(279); + static constexpr const TSymbolUniqueId ldexp_Float2_Int2 = TSymbolUniqueId(280); + static constexpr const TSymbolUniqueId ldexp_Float3_Int3 = TSymbolUniqueId(281); + static constexpr const TSymbolUniqueId ldexp_Float4_Int4 = TSymbolUniqueId(282); + static constexpr const TSymbolUniqueId packSnorm2x16_Float2 = TSymbolUniqueId(283); + static constexpr const TSymbolUniqueId packUnorm2x16_Float2 = TSymbolUniqueId(284); + static constexpr const TSymbolUniqueId packHalf2x16_Float2 = TSymbolUniqueId(285); + static constexpr const TSymbolUniqueId unpackSnorm2x16_UInt1 = TSymbolUniqueId(286); + static constexpr const TSymbolUniqueId unpackUnorm2x16_UInt1 = TSymbolUniqueId(287); + static constexpr const TSymbolUniqueId unpackHalf2x16_UInt1 = TSymbolUniqueId(288); + static constexpr const TSymbolUniqueId packUnorm4x8_Float4 = TSymbolUniqueId(289); + static constexpr const TSymbolUniqueId packSnorm4x8_Float4 = TSymbolUniqueId(290); + static constexpr const TSymbolUniqueId unpackUnorm4x8_UInt1 = TSymbolUniqueId(291); + static constexpr const TSymbolUniqueId unpackSnorm4x8_UInt1 = TSymbolUniqueId(292); + static constexpr const TSymbolUniqueId length_Float1 = TSymbolUniqueId(293); + static constexpr const TSymbolUniqueId length_Float2 = TSymbolUniqueId(294); + static constexpr const TSymbolUniqueId length_Float3 = TSymbolUniqueId(295); + static constexpr const TSymbolUniqueId length_Float4 = TSymbolUniqueId(296); + static constexpr const TSymbolUniqueId distance_Float1_Float1 = TSymbolUniqueId(297); + static constexpr const TSymbolUniqueId distance_Float2_Float2 = TSymbolUniqueId(298); + static constexpr const TSymbolUniqueId distance_Float3_Float3 = TSymbolUniqueId(299); + static constexpr const TSymbolUniqueId distance_Float4_Float4 = TSymbolUniqueId(300); + static constexpr const TSymbolUniqueId dot_Float1_Float1 = TSymbolUniqueId(301); + static constexpr const TSymbolUniqueId dot_Float2_Float2 = TSymbolUniqueId(302); + static constexpr const TSymbolUniqueId dot_Float3_Float3 = TSymbolUniqueId(303); + static constexpr const TSymbolUniqueId dot_Float4_Float4 = TSymbolUniqueId(304); + static constexpr const TSymbolUniqueId cross_Float3_Float3 = TSymbolUniqueId(305); + static constexpr const TSymbolUniqueId normalize_Float1 = TSymbolUniqueId(306); + static constexpr const TSymbolUniqueId normalize_Float2 = TSymbolUniqueId(307); + static constexpr const TSymbolUniqueId normalize_Float3 = TSymbolUniqueId(308); + static constexpr const TSymbolUniqueId normalize_Float4 = TSymbolUniqueId(309); + static constexpr const TSymbolUniqueId faceforward_Float1_Float1_Float1 = TSymbolUniqueId(310); + static constexpr const TSymbolUniqueId faceforward_Float2_Float2_Float2 = TSymbolUniqueId(311); + static constexpr const TSymbolUniqueId faceforward_Float3_Float3_Float3 = TSymbolUniqueId(312); + static constexpr const TSymbolUniqueId faceforward_Float4_Float4_Float4 = TSymbolUniqueId(313); + static constexpr const TSymbolUniqueId reflect_Float1_Float1 = TSymbolUniqueId(314); + static constexpr const TSymbolUniqueId reflect_Float2_Float2 = TSymbolUniqueId(315); + static constexpr const TSymbolUniqueId reflect_Float3_Float3 = TSymbolUniqueId(316); + static constexpr const TSymbolUniqueId reflect_Float4_Float4 = TSymbolUniqueId(317); + static constexpr const TSymbolUniqueId refract_Float1_Float1_Float1 = TSymbolUniqueId(318); + static constexpr const TSymbolUniqueId refract_Float2_Float2_Float1 = TSymbolUniqueId(319); + static constexpr const TSymbolUniqueId refract_Float3_Float3_Float1 = TSymbolUniqueId(320); + static constexpr const TSymbolUniqueId refract_Float4_Float4_Float1 = TSymbolUniqueId(321); + static constexpr const TSymbolUniqueId matrixCompMult_Float2x2_Float2x2 = TSymbolUniqueId(322); + static constexpr const TSymbolUniqueId pt5B = TSymbolUniqueId(323); + static constexpr const TSymbolUniqueId matrixCompMult_Float3x3_Float3x3 = TSymbolUniqueId(324); + static constexpr const TSymbolUniqueId ptAB = TSymbolUniqueId(325); + static constexpr const TSymbolUniqueId matrixCompMult_Float4x4_Float4x4 = TSymbolUniqueId(326); + static constexpr const TSymbolUniqueId ptFB = TSymbolUniqueId(327); + static constexpr const TSymbolUniqueId matrixCompMult_Float2x3_Float2x3 = TSymbolUniqueId(328); + static constexpr const TSymbolUniqueId pt9B = TSymbolUniqueId(329); + static constexpr const TSymbolUniqueId matrixCompMult_Float3x2_Float3x2 = TSymbolUniqueId(330); + static constexpr const TSymbolUniqueId pt6B = TSymbolUniqueId(331); + static constexpr const TSymbolUniqueId matrixCompMult_Float2x4_Float2x4 = TSymbolUniqueId(332); + static constexpr const TSymbolUniqueId ptDB = TSymbolUniqueId(333); + static constexpr const TSymbolUniqueId matrixCompMult_Float4x2_Float4x2 = TSymbolUniqueId(334); + static constexpr const TSymbolUniqueId pt7B = TSymbolUniqueId(335); + static constexpr const TSymbolUniqueId matrixCompMult_Float3x4_Float3x4 = TSymbolUniqueId(336); + static constexpr const TSymbolUniqueId ptEB = TSymbolUniqueId(337); + static constexpr const TSymbolUniqueId matrixCompMult_Float4x3_Float4x3 = TSymbolUniqueId(338); + static constexpr const TSymbolUniqueId ptBB = TSymbolUniqueId(339); + static constexpr const TSymbolUniqueId outerProduct_Float2_Float2 = TSymbolUniqueId(340); + static constexpr const TSymbolUniqueId outerProduct_Float3_Float3 = TSymbolUniqueId(341); + static constexpr const TSymbolUniqueId outerProduct_Float4_Float4 = TSymbolUniqueId(342); + static constexpr const TSymbolUniqueId outerProduct_Float3_Float2 = TSymbolUniqueId(343); + static constexpr const TSymbolUniqueId outerProduct_Float2_Float3 = TSymbolUniqueId(344); + static constexpr const TSymbolUniqueId outerProduct_Float4_Float2 = TSymbolUniqueId(345); + static constexpr const TSymbolUniqueId outerProduct_Float2_Float4 = TSymbolUniqueId(346); + static constexpr const TSymbolUniqueId outerProduct_Float4_Float3 = TSymbolUniqueId(347); + static constexpr const TSymbolUniqueId outerProduct_Float3_Float4 = TSymbolUniqueId(348); + static constexpr const TSymbolUniqueId transpose_Float2x2 = TSymbolUniqueId(349); + static constexpr const TSymbolUniqueId transpose_Float3x3 = TSymbolUniqueId(350); + static constexpr const TSymbolUniqueId transpose_Float4x4 = TSymbolUniqueId(351); + static constexpr const TSymbolUniqueId transpose_Float3x2 = TSymbolUniqueId(352); + static constexpr const TSymbolUniqueId transpose_Float2x3 = TSymbolUniqueId(353); + static constexpr const TSymbolUniqueId transpose_Float4x2 = TSymbolUniqueId(354); + static constexpr const TSymbolUniqueId transpose_Float2x4 = TSymbolUniqueId(355); + static constexpr const TSymbolUniqueId transpose_Float4x3 = TSymbolUniqueId(356); + static constexpr const TSymbolUniqueId transpose_Float3x4 = TSymbolUniqueId(357); + static constexpr const TSymbolUniqueId determinant_Float2x2 = TSymbolUniqueId(358); + static constexpr const TSymbolUniqueId determinant_Float3x3 = TSymbolUniqueId(359); + static constexpr const TSymbolUniqueId determinant_Float4x4 = TSymbolUniqueId(360); + static constexpr const TSymbolUniqueId inverse_Float2x2 = TSymbolUniqueId(361); + static constexpr const TSymbolUniqueId inverse_Float3x3 = TSymbolUniqueId(362); + static constexpr const TSymbolUniqueId inverse_Float4x4 = TSymbolUniqueId(363); + static constexpr const TSymbolUniqueId lessThan_Float2_Float2 = TSymbolUniqueId(364); + static constexpr const TSymbolUniqueId lessThan_Float3_Float3 = TSymbolUniqueId(365); + static constexpr const TSymbolUniqueId lessThan_Float4_Float4 = TSymbolUniqueId(366); + static constexpr const TSymbolUniqueId lessThan_Int2_Int2 = TSymbolUniqueId(367); + static constexpr const TSymbolUniqueId lessThan_Int3_Int3 = TSymbolUniqueId(368); + static constexpr const TSymbolUniqueId lessThan_Int4_Int4 = TSymbolUniqueId(369); + static constexpr const TSymbolUniqueId lessThan_UInt2_UInt2 = TSymbolUniqueId(370); + static constexpr const TSymbolUniqueId lessThan_UInt3_UInt3 = TSymbolUniqueId(371); + static constexpr const TSymbolUniqueId lessThan_UInt4_UInt4 = TSymbolUniqueId(372); + static constexpr const TSymbolUniqueId lessThanEqual_Float2_Float2 = TSymbolUniqueId(373); + static constexpr const TSymbolUniqueId lessThanEqual_Float3_Float3 = TSymbolUniqueId(374); + static constexpr const TSymbolUniqueId lessThanEqual_Float4_Float4 = TSymbolUniqueId(375); + static constexpr const TSymbolUniqueId lessThanEqual_Int2_Int2 = TSymbolUniqueId(376); + static constexpr const TSymbolUniqueId lessThanEqual_Int3_Int3 = TSymbolUniqueId(377); + static constexpr const TSymbolUniqueId lessThanEqual_Int4_Int4 = TSymbolUniqueId(378); + static constexpr const TSymbolUniqueId lessThanEqual_UInt2_UInt2 = TSymbolUniqueId(379); + static constexpr const TSymbolUniqueId lessThanEqual_UInt3_UInt3 = TSymbolUniqueId(380); + static constexpr const TSymbolUniqueId lessThanEqual_UInt4_UInt4 = TSymbolUniqueId(381); + static constexpr const TSymbolUniqueId greaterThan_Float2_Float2 = TSymbolUniqueId(382); + static constexpr const TSymbolUniqueId greaterThan_Float3_Float3 = TSymbolUniqueId(383); + static constexpr const TSymbolUniqueId greaterThan_Float4_Float4 = TSymbolUniqueId(384); + static constexpr const TSymbolUniqueId greaterThan_Int2_Int2 = TSymbolUniqueId(385); + static constexpr const TSymbolUniqueId greaterThan_Int3_Int3 = TSymbolUniqueId(386); + static constexpr const TSymbolUniqueId greaterThan_Int4_Int4 = TSymbolUniqueId(387); + static constexpr const TSymbolUniqueId greaterThan_UInt2_UInt2 = TSymbolUniqueId(388); + static constexpr const TSymbolUniqueId greaterThan_UInt3_UInt3 = TSymbolUniqueId(389); + static constexpr const TSymbolUniqueId greaterThan_UInt4_UInt4 = TSymbolUniqueId(390); + static constexpr const TSymbolUniqueId greaterThanEqual_Float2_Float2 = TSymbolUniqueId(391); + static constexpr const TSymbolUniqueId greaterThanEqual_Float3_Float3 = TSymbolUniqueId(392); + static constexpr const TSymbolUniqueId greaterThanEqual_Float4_Float4 = TSymbolUniqueId(393); + static constexpr const TSymbolUniqueId greaterThanEqual_Int2_Int2 = TSymbolUniqueId(394); + static constexpr const TSymbolUniqueId greaterThanEqual_Int3_Int3 = TSymbolUniqueId(395); + static constexpr const TSymbolUniqueId greaterThanEqual_Int4_Int4 = TSymbolUniqueId(396); + static constexpr const TSymbolUniqueId greaterThanEqual_UInt2_UInt2 = TSymbolUniqueId(397); + static constexpr const TSymbolUniqueId greaterThanEqual_UInt3_UInt3 = TSymbolUniqueId(398); + static constexpr const TSymbolUniqueId greaterThanEqual_UInt4_UInt4 = TSymbolUniqueId(399); + static constexpr const TSymbolUniqueId equal_Float2_Float2 = TSymbolUniqueId(400); + static constexpr const TSymbolUniqueId equal_Float3_Float3 = TSymbolUniqueId(401); + static constexpr const TSymbolUniqueId equal_Float4_Float4 = TSymbolUniqueId(402); + static constexpr const TSymbolUniqueId equal_Int2_Int2 = TSymbolUniqueId(403); + static constexpr const TSymbolUniqueId equal_Int3_Int3 = TSymbolUniqueId(404); + static constexpr const TSymbolUniqueId equal_Int4_Int4 = TSymbolUniqueId(405); + static constexpr const TSymbolUniqueId equal_UInt2_UInt2 = TSymbolUniqueId(406); + static constexpr const TSymbolUniqueId equal_UInt3_UInt3 = TSymbolUniqueId(407); + static constexpr const TSymbolUniqueId equal_UInt4_UInt4 = TSymbolUniqueId(408); + static constexpr const TSymbolUniqueId equal_Bool2_Bool2 = TSymbolUniqueId(409); + static constexpr const TSymbolUniqueId equal_Bool3_Bool3 = TSymbolUniqueId(410); + static constexpr const TSymbolUniqueId equal_Bool4_Bool4 = TSymbolUniqueId(411); + static constexpr const TSymbolUniqueId notEqual_Float2_Float2 = TSymbolUniqueId(412); + static constexpr const TSymbolUniqueId notEqual_Float3_Float3 = TSymbolUniqueId(413); + static constexpr const TSymbolUniqueId notEqual_Float4_Float4 = TSymbolUniqueId(414); + static constexpr const TSymbolUniqueId notEqual_Int2_Int2 = TSymbolUniqueId(415); + static constexpr const TSymbolUniqueId notEqual_Int3_Int3 = TSymbolUniqueId(416); + static constexpr const TSymbolUniqueId notEqual_Int4_Int4 = TSymbolUniqueId(417); + static constexpr const TSymbolUniqueId notEqual_UInt2_UInt2 = TSymbolUniqueId(418); + static constexpr const TSymbolUniqueId notEqual_UInt3_UInt3 = TSymbolUniqueId(419); + static constexpr const TSymbolUniqueId notEqual_UInt4_UInt4 = TSymbolUniqueId(420); + static constexpr const TSymbolUniqueId notEqual_Bool2_Bool2 = TSymbolUniqueId(421); + static constexpr const TSymbolUniqueId notEqual_Bool3_Bool3 = TSymbolUniqueId(422); + static constexpr const TSymbolUniqueId notEqual_Bool4_Bool4 = TSymbolUniqueId(423); + static constexpr const TSymbolUniqueId any_Bool2 = TSymbolUniqueId(424); + static constexpr const TSymbolUniqueId any_Bool3 = TSymbolUniqueId(425); + static constexpr const TSymbolUniqueId any_Bool4 = TSymbolUniqueId(426); + static constexpr const TSymbolUniqueId all_Bool2 = TSymbolUniqueId(427); + static constexpr const TSymbolUniqueId all_Bool3 = TSymbolUniqueId(428); + static constexpr const TSymbolUniqueId all_Bool4 = TSymbolUniqueId(429); + static constexpr const TSymbolUniqueId notFunc_Bool2 = TSymbolUniqueId(430); + static constexpr const TSymbolUniqueId notFunc_Bool3 = TSymbolUniqueId(431); + static constexpr const TSymbolUniqueId notFunc_Bool4 = TSymbolUniqueId(432); + static constexpr const TSymbolUniqueId bitfieldExtract_Int1_Int1_Int1 = TSymbolUniqueId(433); + static constexpr const TSymbolUniqueId bitfieldExtract_Int2_Int1_Int1 = TSymbolUniqueId(434); + static constexpr const TSymbolUniqueId bitfieldExtract_Int3_Int1_Int1 = TSymbolUniqueId(435); + static constexpr const TSymbolUniqueId bitfieldExtract_Int4_Int1_Int1 = TSymbolUniqueId(436); + static constexpr const TSymbolUniqueId bitfieldExtract_UInt1_Int1_Int1 = TSymbolUniqueId(437); + static constexpr const TSymbolUniqueId bitfieldExtract_UInt2_Int1_Int1 = TSymbolUniqueId(438); + static constexpr const TSymbolUniqueId bitfieldExtract_UInt3_Int1_Int1 = TSymbolUniqueId(439); + static constexpr const TSymbolUniqueId bitfieldExtract_UInt4_Int1_Int1 = TSymbolUniqueId(440); + static constexpr const TSymbolUniqueId bitfieldInsert_Int1_Int1_Int1_Int1 = + TSymbolUniqueId(441); + static constexpr const TSymbolUniqueId bitfieldInsert_Int2_Int2_Int1_Int1 = + TSymbolUniqueId(442); + static constexpr const TSymbolUniqueId bitfieldInsert_Int3_Int3_Int1_Int1 = + TSymbolUniqueId(443); + static constexpr const TSymbolUniqueId bitfieldInsert_Int4_Int4_Int1_Int1 = + TSymbolUniqueId(444); + static constexpr const TSymbolUniqueId bitfieldInsert_UInt1_UInt1_Int1_Int1 = + TSymbolUniqueId(445); + static constexpr const TSymbolUniqueId bitfieldInsert_UInt2_UInt2_Int1_Int1 = + TSymbolUniqueId(446); + static constexpr const TSymbolUniqueId bitfieldInsert_UInt3_UInt3_Int1_Int1 = + TSymbolUniqueId(447); + static constexpr const TSymbolUniqueId bitfieldInsert_UInt4_UInt4_Int1_Int1 = + TSymbolUniqueId(448); + static constexpr const TSymbolUniqueId bitfieldReverse_Int1 = TSymbolUniqueId(449); + static constexpr const TSymbolUniqueId bitfieldReverse_Int2 = TSymbolUniqueId(450); + static constexpr const TSymbolUniqueId bitfieldReverse_Int3 = TSymbolUniqueId(451); + static constexpr const TSymbolUniqueId bitfieldReverse_Int4 = TSymbolUniqueId(452); + static constexpr const TSymbolUniqueId bitfieldReverse_UInt1 = TSymbolUniqueId(453); + static constexpr const TSymbolUniqueId bitfieldReverse_UInt2 = TSymbolUniqueId(454); + static constexpr const TSymbolUniqueId bitfieldReverse_UInt3 = TSymbolUniqueId(455); + static constexpr const TSymbolUniqueId bitfieldReverse_UInt4 = TSymbolUniqueId(456); + static constexpr const TSymbolUniqueId bitCount_Int1 = TSymbolUniqueId(457); + static constexpr const TSymbolUniqueId bitCount_Int2 = TSymbolUniqueId(458); + static constexpr const TSymbolUniqueId bitCount_Int3 = TSymbolUniqueId(459); + static constexpr const TSymbolUniqueId bitCount_Int4 = TSymbolUniqueId(460); + static constexpr const TSymbolUniqueId bitCount_UInt1 = TSymbolUniqueId(461); + static constexpr const TSymbolUniqueId bitCount_UInt2 = TSymbolUniqueId(462); + static constexpr const TSymbolUniqueId bitCount_UInt3 = TSymbolUniqueId(463); + static constexpr const TSymbolUniqueId bitCount_UInt4 = TSymbolUniqueId(464); + static constexpr const TSymbolUniqueId findLSB_Int1 = TSymbolUniqueId(465); + static constexpr const TSymbolUniqueId findLSB_Int2 = TSymbolUniqueId(466); + static constexpr const TSymbolUniqueId findLSB_Int3 = TSymbolUniqueId(467); + static constexpr const TSymbolUniqueId findLSB_Int4 = TSymbolUniqueId(468); + static constexpr const TSymbolUniqueId findLSB_UInt1 = TSymbolUniqueId(469); + static constexpr const TSymbolUniqueId findLSB_UInt2 = TSymbolUniqueId(470); + static constexpr const TSymbolUniqueId findLSB_UInt3 = TSymbolUniqueId(471); + static constexpr const TSymbolUniqueId findLSB_UInt4 = TSymbolUniqueId(472); + static constexpr const TSymbolUniqueId findMSB_Int1 = TSymbolUniqueId(473); + static constexpr const TSymbolUniqueId findMSB_Int2 = TSymbolUniqueId(474); + static constexpr const TSymbolUniqueId findMSB_Int3 = TSymbolUniqueId(475); + static constexpr const TSymbolUniqueId findMSB_Int4 = TSymbolUniqueId(476); + static constexpr const TSymbolUniqueId findMSB_UInt1 = TSymbolUniqueId(477); + static constexpr const TSymbolUniqueId findMSB_UInt2 = TSymbolUniqueId(478); + static constexpr const TSymbolUniqueId findMSB_UInt3 = TSymbolUniqueId(479); + static constexpr const TSymbolUniqueId findMSB_UInt4 = TSymbolUniqueId(480); + static constexpr const TSymbolUniqueId uaddCarry_UInt1_UInt1_UInt1 = TSymbolUniqueId(481); + static constexpr const TSymbolUniqueId pt_o_0D = TSymbolUniqueId(482); + static constexpr const TSymbolUniqueId uaddCarry_UInt2_UInt2_UInt2 = TSymbolUniqueId(483); + static constexpr const TSymbolUniqueId pt_o_1D = TSymbolUniqueId(484); + static constexpr const TSymbolUniqueId uaddCarry_UInt3_UInt3_UInt3 = TSymbolUniqueId(485); + static constexpr const TSymbolUniqueId pt_o_2D = TSymbolUniqueId(486); + static constexpr const TSymbolUniqueId uaddCarry_UInt4_UInt4_UInt4 = TSymbolUniqueId(487); + static constexpr const TSymbolUniqueId pt_o_3D = TSymbolUniqueId(488); + static constexpr const TSymbolUniqueId usubBorrow_UInt1_UInt1_UInt1 = TSymbolUniqueId(489); + static constexpr const TSymbolUniqueId usubBorrow_UInt2_UInt2_UInt2 = TSymbolUniqueId(490); + static constexpr const TSymbolUniqueId usubBorrow_UInt3_UInt3_UInt3 = TSymbolUniqueId(491); + static constexpr const TSymbolUniqueId usubBorrow_UInt4_UInt4_UInt4 = TSymbolUniqueId(492); + static constexpr const TSymbolUniqueId umulExtended_UInt1_UInt1_UInt1_UInt1 = + TSymbolUniqueId(493); + static constexpr const TSymbolUniqueId umulExtended_UInt2_UInt2_UInt2_UInt2 = + TSymbolUniqueId(494); + static constexpr const TSymbolUniqueId umulExtended_UInt3_UInt3_UInt3_UInt3 = + TSymbolUniqueId(495); + static constexpr const TSymbolUniqueId umulExtended_UInt4_UInt4_UInt4_UInt4 = + TSymbolUniqueId(496); + static constexpr const TSymbolUniqueId imulExtended_Int1_Int1_Int1_Int1 = TSymbolUniqueId(497); + static constexpr const TSymbolUniqueId imulExtended_Int2_Int2_Int2_Int2 = TSymbolUniqueId(498); + static constexpr const TSymbolUniqueId imulExtended_Int3_Int3_Int3_Int3 = TSymbolUniqueId(499); + static constexpr const TSymbolUniqueId imulExtended_Int4_Int4_Int4_Int4 = TSymbolUniqueId(500); + static constexpr const TSymbolUniqueId texture2D_Sampler2D1_Float2 = TSymbolUniqueId(501); + static constexpr const TSymbolUniqueId pt0H = TSymbolUniqueId(502); + static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float3 = TSymbolUniqueId(503); + static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float4 = TSymbolUniqueId(504); + static constexpr const TSymbolUniqueId textureCube_SamplerCube1_Float3 = TSymbolUniqueId(505); + static constexpr const TSymbolUniqueId pt0J = TSymbolUniqueId(506); + static constexpr const TSymbolUniqueId texture2D_SamplerExternalOES1_Float2 = + TSymbolUniqueId(507); + static constexpr const TSymbolUniqueId pt0L = TSymbolUniqueId(508); + static constexpr const TSymbolUniqueId texture2DProj_SamplerExternalOES1_Float3 = + TSymbolUniqueId(509); + static constexpr const TSymbolUniqueId texture2DProj_SamplerExternalOES1_Float4 = + TSymbolUniqueId(510); + static constexpr const TSymbolUniqueId texture2DRect_Sampler2DRect1_Float2 = + TSymbolUniqueId(511); + static constexpr const TSymbolUniqueId pt0N = TSymbolUniqueId(512); + static constexpr const TSymbolUniqueId texture2DRectProj_Sampler2DRect1_Float3 = + TSymbolUniqueId(513); + static constexpr const TSymbolUniqueId texture2DRectProj_Sampler2DRect1_Float4 = + TSymbolUniqueId(514); + static constexpr const TSymbolUniqueId texture_Sampler2DRect1_Float2 = TSymbolUniqueId(515); + static constexpr const TSymbolUniqueId textureProj_Sampler2DRect1_Float3 = TSymbolUniqueId(516); + static constexpr const TSymbolUniqueId textureProj_Sampler2DRect1_Float4 = TSymbolUniqueId(517); + static constexpr const TSymbolUniqueId texture2DGradEXT_Sampler2D1_Float2_Float2_Float2 = + TSymbolUniqueId(518); + static constexpr const TSymbolUniqueId texture2DProjGradEXT_Sampler2D1_Float3_Float2_Float2 = + TSymbolUniqueId(519); + static constexpr const TSymbolUniqueId texture2DProjGradEXT_Sampler2D1_Float4_Float2_Float2 = + TSymbolUniqueId(520); + static constexpr const TSymbolUniqueId textureCubeGradEXT_SamplerCube1_Float3_Float3_Float3 = + TSymbolUniqueId(521); + static constexpr const TSymbolUniqueId texture2D_Sampler2D1_Float2_Float1 = + TSymbolUniqueId(522); + static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float3_Float1 = + TSymbolUniqueId(523); + static constexpr const TSymbolUniqueId texture2DProj_Sampler2D1_Float4_Float1 = + TSymbolUniqueId(524); + static constexpr const TSymbolUniqueId textureCube_SamplerCube1_Float3_Float1 = + TSymbolUniqueId(525); + static constexpr const TSymbolUniqueId dFdxExt_Float1 = TSymbolUniqueId(526); + static constexpr const TSymbolUniqueId dFdxExt_Float2 = TSymbolUniqueId(527); + static constexpr const TSymbolUniqueId dFdxExt_Float3 = TSymbolUniqueId(528); + static constexpr const TSymbolUniqueId dFdxExt_Float4 = TSymbolUniqueId(529); + static constexpr const TSymbolUniqueId dFdyExt_Float1 = TSymbolUniqueId(530); + static constexpr const TSymbolUniqueId dFdyExt_Float2 = TSymbolUniqueId(531); + static constexpr const TSymbolUniqueId dFdyExt_Float3 = TSymbolUniqueId(532); + static constexpr const TSymbolUniqueId dFdyExt_Float4 = TSymbolUniqueId(533); + static constexpr const TSymbolUniqueId fwidthExt_Float1 = TSymbolUniqueId(534); + static constexpr const TSymbolUniqueId fwidthExt_Float2 = TSymbolUniqueId(535); + static constexpr const TSymbolUniqueId fwidthExt_Float3 = TSymbolUniqueId(536); + static constexpr const TSymbolUniqueId fwidthExt_Float4 = TSymbolUniqueId(537); + static constexpr const TSymbolUniqueId texture2DLodEXT_Sampler2D1_Float2_Float1 = + TSymbolUniqueId(538); + static constexpr const TSymbolUniqueId texture2DProjLodEXT_Sampler2D1_Float3_Float1 = + TSymbolUniqueId(539); + static constexpr const TSymbolUniqueId texture2DProjLodEXT_Sampler2D1_Float4_Float1 = + TSymbolUniqueId(540); + static constexpr const TSymbolUniqueId textureCubeLodEXT_SamplerCube1_Float3_Float1 = + TSymbolUniqueId(541); + static constexpr const TSymbolUniqueId texture3D_Sampler3D1_Float3 = TSymbolUniqueId(542); + static constexpr const TSymbolUniqueId pt0I = TSymbolUniqueId(543); + static constexpr const TSymbolUniqueId texture3D_Sampler3D1_Float3_Float1 = + TSymbolUniqueId(544); + static constexpr const TSymbolUniqueId texture3DProj_Sampler3D1_Float4 = TSymbolUniqueId(545); + static constexpr const TSymbolUniqueId texture3DProj_Sampler3D1_Float4_Float1 = + TSymbolUniqueId(546); + static constexpr const TSymbolUniqueId texture3DLod_Sampler3D1_Float3_Float1 = + TSymbolUniqueId(547); + static constexpr const TSymbolUniqueId texture3DProjLod_Sampler3D1_Float4_Float1 = + TSymbolUniqueId(548); + static constexpr const TSymbolUniqueId texture2DLod_Sampler2D1_Float2_Float1 = + TSymbolUniqueId(549); + static constexpr const TSymbolUniqueId texture2DProjLod_Sampler2D1_Float3_Float1 = + TSymbolUniqueId(550); + static constexpr const TSymbolUniqueId texture2DProjLod_Sampler2D1_Float4_Float1 = + TSymbolUniqueId(551); + static constexpr const TSymbolUniqueId textureCubeLod_SamplerCube1_Float3_Float1 = + TSymbolUniqueId(552); + static constexpr const TSymbolUniqueId texture_Sampler2D1_Float2 = TSymbolUniqueId(553); + static constexpr const TSymbolUniqueId texture_ISampler2D1_Float2 = TSymbolUniqueId(554); + static constexpr const TSymbolUniqueId pt0Q = TSymbolUniqueId(555); + static constexpr const TSymbolUniqueId texture_USampler2D1_Float2 = TSymbolUniqueId(556); + static constexpr const TSymbolUniqueId pt0W = TSymbolUniqueId(557); + static constexpr const TSymbolUniqueId texture_Sampler3D1_Float3 = TSymbolUniqueId(558); + static constexpr const TSymbolUniqueId texture_ISampler3D1_Float3 = TSymbolUniqueId(559); + static constexpr const TSymbolUniqueId pt0R = TSymbolUniqueId(560); + static constexpr const TSymbolUniqueId texture_USampler3D1_Float3 = TSymbolUniqueId(561); + static constexpr const TSymbolUniqueId pt0X = TSymbolUniqueId(562); + static constexpr const TSymbolUniqueId texture_SamplerCube1_Float3 = TSymbolUniqueId(563); + static constexpr const TSymbolUniqueId texture_ISamplerCube1_Float3 = TSymbolUniqueId(564); + static constexpr const TSymbolUniqueId pt0S = TSymbolUniqueId(565); + static constexpr const TSymbolUniqueId texture_USamplerCube1_Float3 = TSymbolUniqueId(566); + static constexpr const TSymbolUniqueId pt0Y = TSymbolUniqueId(567); + static constexpr const TSymbolUniqueId texture_Sampler2DArray1_Float3 = TSymbolUniqueId(568); + static constexpr const TSymbolUniqueId pt0K = TSymbolUniqueId(569); + static constexpr const TSymbolUniqueId texture_ISampler2DArray1_Float3 = TSymbolUniqueId(570); + static constexpr const TSymbolUniqueId pt0T = TSymbolUniqueId(571); + static constexpr const TSymbolUniqueId texture_USampler2DArray1_Float3 = TSymbolUniqueId(572); + static constexpr const TSymbolUniqueId pt0Z = TSymbolUniqueId(573); + static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float3 = TSymbolUniqueId(574); + static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float3 = TSymbolUniqueId(575); + static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float3 = TSymbolUniqueId(576); + static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float4 = TSymbolUniqueId(577); + static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float4 = TSymbolUniqueId(578); + static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float4 = TSymbolUniqueId(579); + static constexpr const TSymbolUniqueId textureProj_Sampler3D1_Float4 = TSymbolUniqueId(580); + static constexpr const TSymbolUniqueId textureProj_ISampler3D1_Float4 = TSymbolUniqueId(581); + static constexpr const TSymbolUniqueId textureProj_USampler3D1_Float4 = TSymbolUniqueId(582); + static constexpr const TSymbolUniqueId textureLod_Sampler2D1_Float2_Float1 = + TSymbolUniqueId(583); + static constexpr const TSymbolUniqueId textureLod_ISampler2D1_Float2_Float1 = + TSymbolUniqueId(584); + static constexpr const TSymbolUniqueId textureLod_USampler2D1_Float2_Float1 = + TSymbolUniqueId(585); + static constexpr const TSymbolUniqueId textureLod_Sampler3D1_Float3_Float1 = + TSymbolUniqueId(586); + static constexpr const TSymbolUniqueId textureLod_ISampler3D1_Float3_Float1 = + TSymbolUniqueId(587); + static constexpr const TSymbolUniqueId textureLod_USampler3D1_Float3_Float1 = + TSymbolUniqueId(588); + static constexpr const TSymbolUniqueId textureLod_SamplerCube1_Float3_Float1 = + TSymbolUniqueId(589); + static constexpr const TSymbolUniqueId textureLod_ISamplerCube1_Float3_Float1 = + TSymbolUniqueId(590); + static constexpr const TSymbolUniqueId textureLod_USamplerCube1_Float3_Float1 = + TSymbolUniqueId(591); + static constexpr const TSymbolUniqueId textureLod_Sampler2DArray1_Float3_Float1 = + TSymbolUniqueId(592); + static constexpr const TSymbolUniqueId textureLod_ISampler2DArray1_Float3_Float1 = + TSymbolUniqueId(593); + static constexpr const TSymbolUniqueId textureLod_USampler2DArray1_Float3_Float1 = + TSymbolUniqueId(594); + static constexpr const TSymbolUniqueId texture_Sampler2DShadow1_Float3 = TSymbolUniqueId(595); + static constexpr const TSymbolUniqueId pt0c = TSymbolUniqueId(596); + static constexpr const TSymbolUniqueId texture_SamplerCubeShadow1_Float4 = TSymbolUniqueId(597); + static constexpr const TSymbolUniqueId pt0d = TSymbolUniqueId(598); + static constexpr const TSymbolUniqueId texture_Sampler2DArrayShadow1_Float4 = + TSymbolUniqueId(599); + static constexpr const TSymbolUniqueId pt0e = TSymbolUniqueId(600); + static constexpr const TSymbolUniqueId textureProj_Sampler2DShadow1_Float4 = + TSymbolUniqueId(601); + static constexpr const TSymbolUniqueId textureLod_Sampler2DShadow1_Float3_Float1 = + TSymbolUniqueId(602); + static constexpr const TSymbolUniqueId textureSize_Sampler2D1_Int1 = TSymbolUniqueId(603); + static constexpr const TSymbolUniqueId textureSize_ISampler2D1_Int1 = TSymbolUniqueId(604); + static constexpr const TSymbolUniqueId textureSize_USampler2D1_Int1 = TSymbolUniqueId(605); + static constexpr const TSymbolUniqueId textureSize_Sampler3D1_Int1 = TSymbolUniqueId(606); + static constexpr const TSymbolUniqueId textureSize_ISampler3D1_Int1 = TSymbolUniqueId(607); + static constexpr const TSymbolUniqueId textureSize_USampler3D1_Int1 = TSymbolUniqueId(608); + static constexpr const TSymbolUniqueId textureSize_SamplerCube1_Int1 = TSymbolUniqueId(609); + static constexpr const TSymbolUniqueId textureSize_ISamplerCube1_Int1 = TSymbolUniqueId(610); + static constexpr const TSymbolUniqueId textureSize_USamplerCube1_Int1 = TSymbolUniqueId(611); + static constexpr const TSymbolUniqueId textureSize_Sampler2DArray1_Int1 = TSymbolUniqueId(612); + static constexpr const TSymbolUniqueId textureSize_ISampler2DArray1_Int1 = TSymbolUniqueId(613); + static constexpr const TSymbolUniqueId textureSize_USampler2DArray1_Int1 = TSymbolUniqueId(614); + static constexpr const TSymbolUniqueId textureSize_Sampler2DShadow1_Int1 = TSymbolUniqueId(615); + static constexpr const TSymbolUniqueId textureSize_SamplerCubeShadow1_Int1 = + TSymbolUniqueId(616); + static constexpr const TSymbolUniqueId textureSize_Sampler2DArrayShadow1_Int1 = + TSymbolUniqueId(617); + static constexpr const TSymbolUniqueId textureProjLod_Sampler2D1_Float3_Float1 = + TSymbolUniqueId(618); + static constexpr const TSymbolUniqueId textureProjLod_ISampler2D1_Float3_Float1 = + TSymbolUniqueId(619); + static constexpr const TSymbolUniqueId textureProjLod_USampler2D1_Float3_Float1 = + TSymbolUniqueId(620); + static constexpr const TSymbolUniqueId textureProjLod_Sampler2D1_Float4_Float1 = + TSymbolUniqueId(621); + static constexpr const TSymbolUniqueId textureProjLod_ISampler2D1_Float4_Float1 = + TSymbolUniqueId(622); + static constexpr const TSymbolUniqueId textureProjLod_USampler2D1_Float4_Float1 = + TSymbolUniqueId(623); + static constexpr const TSymbolUniqueId textureProjLod_Sampler3D1_Float4_Float1 = + TSymbolUniqueId(624); + static constexpr const TSymbolUniqueId textureProjLod_ISampler3D1_Float4_Float1 = + TSymbolUniqueId(625); + static constexpr const TSymbolUniqueId textureProjLod_USampler3D1_Float4_Float1 = + TSymbolUniqueId(626); + static constexpr const TSymbolUniqueId textureProjLod_Sampler2DShadow1_Float4_Float1 = + TSymbolUniqueId(627); + static constexpr const TSymbolUniqueId texelFetch_Sampler2D1_Int2_Int1 = TSymbolUniqueId(628); + static constexpr const TSymbolUniqueId texelFetch_ISampler2D1_Int2_Int1 = TSymbolUniqueId(629); + static constexpr const TSymbolUniqueId texelFetch_USampler2D1_Int2_Int1 = TSymbolUniqueId(630); + static constexpr const TSymbolUniqueId texelFetch_Sampler3D1_Int3_Int1 = TSymbolUniqueId(631); + static constexpr const TSymbolUniqueId texelFetch_ISampler3D1_Int3_Int1 = TSymbolUniqueId(632); + static constexpr const TSymbolUniqueId texelFetch_USampler3D1_Int3_Int1 = TSymbolUniqueId(633); + static constexpr const TSymbolUniqueId texelFetch_Sampler2DArray1_Int3_Int1 = + TSymbolUniqueId(634); + static constexpr const TSymbolUniqueId texelFetch_ISampler2DArray1_Int3_Int1 = + TSymbolUniqueId(635); + static constexpr const TSymbolUniqueId texelFetch_USampler2DArray1_Int3_Int1 = + TSymbolUniqueId(636); + static constexpr const TSymbolUniqueId textureGrad_Sampler2D1_Float2_Float2_Float2 = + TSymbolUniqueId(637); + static constexpr const TSymbolUniqueId textureGrad_ISampler2D1_Float2_Float2_Float2 = + TSymbolUniqueId(638); + static constexpr const TSymbolUniqueId textureGrad_USampler2D1_Float2_Float2_Float2 = + TSymbolUniqueId(639); + static constexpr const TSymbolUniqueId textureGrad_Sampler3D1_Float3_Float3_Float3 = + TSymbolUniqueId(640); + static constexpr const TSymbolUniqueId textureGrad_ISampler3D1_Float3_Float3_Float3 = + TSymbolUniqueId(641); + static constexpr const TSymbolUniqueId textureGrad_USampler3D1_Float3_Float3_Float3 = + TSymbolUniqueId(642); + static constexpr const TSymbolUniqueId textureGrad_SamplerCube1_Float3_Float3_Float3 = + TSymbolUniqueId(643); + static constexpr const TSymbolUniqueId textureGrad_ISamplerCube1_Float3_Float3_Float3 = + TSymbolUniqueId(644); + static constexpr const TSymbolUniqueId textureGrad_USamplerCube1_Float3_Float3_Float3 = + TSymbolUniqueId(645); + static constexpr const TSymbolUniqueId textureGrad_Sampler2DShadow1_Float3_Float2_Float2 = + TSymbolUniqueId(646); + static constexpr const TSymbolUniqueId textureGrad_SamplerCubeShadow1_Float4_Float3_Float3 = + TSymbolUniqueId(647); + static constexpr const TSymbolUniqueId textureGrad_Sampler2DArray1_Float3_Float2_Float2 = + TSymbolUniqueId(648); + static constexpr const TSymbolUniqueId textureGrad_ISampler2DArray1_Float3_Float2_Float2 = + TSymbolUniqueId(649); + static constexpr const TSymbolUniqueId textureGrad_USampler2DArray1_Float3_Float2_Float2 = + TSymbolUniqueId(650); + static constexpr const TSymbolUniqueId textureGrad_Sampler2DArrayShadow1_Float4_Float2_Float2 = + TSymbolUniqueId(651); + static constexpr const TSymbolUniqueId textureProjGrad_Sampler2D1_Float3_Float2_Float2 = + TSymbolUniqueId(652); + static constexpr const TSymbolUniqueId textureProjGrad_ISampler2D1_Float3_Float2_Float2 = + TSymbolUniqueId(653); + static constexpr const TSymbolUniqueId textureProjGrad_USampler2D1_Float3_Float2_Float2 = + TSymbolUniqueId(654); + static constexpr const TSymbolUniqueId textureProjGrad_Sampler2D1_Float4_Float2_Float2 = + TSymbolUniqueId(655); + static constexpr const TSymbolUniqueId textureProjGrad_ISampler2D1_Float4_Float2_Float2 = + TSymbolUniqueId(656); + static constexpr const TSymbolUniqueId textureProjGrad_USampler2D1_Float4_Float2_Float2 = + TSymbolUniqueId(657); + static constexpr const TSymbolUniqueId textureProjGrad_Sampler3D1_Float4_Float3_Float3 = + TSymbolUniqueId(658); + static constexpr const TSymbolUniqueId textureProjGrad_ISampler3D1_Float4_Float3_Float3 = + TSymbolUniqueId(659); + static constexpr const TSymbolUniqueId textureProjGrad_USampler3D1_Float4_Float3_Float3 = + TSymbolUniqueId(660); + static constexpr const TSymbolUniqueId textureProjGrad_Sampler2DShadow1_Float4_Float2_Float2 = + TSymbolUniqueId(661); + static constexpr const TSymbolUniqueId textureSize_Sampler2DMS1 = TSymbolUniqueId(662); + static constexpr const TSymbolUniqueId pt0O = TSymbolUniqueId(663); + static constexpr const TSymbolUniqueId textureSize_ISampler2DMS1 = TSymbolUniqueId(664); + static constexpr const TSymbolUniqueId pt0U = TSymbolUniqueId(665); + static constexpr const TSymbolUniqueId textureSize_USampler2DMS1 = TSymbolUniqueId(666); + static constexpr const TSymbolUniqueId pt0a = TSymbolUniqueId(667); + static constexpr const TSymbolUniqueId textureSizeExt_Sampler2DMS1 = TSymbolUniqueId(668); + static constexpr const TSymbolUniqueId textureSizeExt_ISampler2DMS1 = TSymbolUniqueId(669); + static constexpr const TSymbolUniqueId textureSizeExt_USampler2DMS1 = TSymbolUniqueId(670); + static constexpr const TSymbolUniqueId textureSize_Sampler2DMSArray1 = TSymbolUniqueId(671); + static constexpr const TSymbolUniqueId pt0P = TSymbolUniqueId(672); + static constexpr const TSymbolUniqueId textureSize_ISampler2DMSArray1 = TSymbolUniqueId(673); + static constexpr const TSymbolUniqueId pt0V = TSymbolUniqueId(674); + static constexpr const TSymbolUniqueId textureSize_USampler2DMSArray1 = TSymbolUniqueId(675); + static constexpr const TSymbolUniqueId pt0b = TSymbolUniqueId(676); + static constexpr const TSymbolUniqueId textureOffset_Sampler2D1_Float2_Int2 = + TSymbolUniqueId(677); + static constexpr const TSymbolUniqueId textureOffset_ISampler2D1_Float2_Int2 = + TSymbolUniqueId(678); + static constexpr const TSymbolUniqueId textureOffset_USampler2D1_Float2_Int2 = + TSymbolUniqueId(679); + static constexpr const TSymbolUniqueId textureOffset_Sampler3D1_Float3_Int3 = + TSymbolUniqueId(680); + static constexpr const TSymbolUniqueId textureOffset_ISampler3D1_Float3_Int3 = + TSymbolUniqueId(681); + static constexpr const TSymbolUniqueId textureOffset_USampler3D1_Float3_Int3 = + TSymbolUniqueId(682); + static constexpr const TSymbolUniqueId textureOffset_Sampler2DShadow1_Float3_Int2 = + TSymbolUniqueId(683); + static constexpr const TSymbolUniqueId textureOffset_Sampler2DArray1_Float3_Int2 = + TSymbolUniqueId(684); + static constexpr const TSymbolUniqueId textureOffset_ISampler2DArray1_Float3_Int2 = + TSymbolUniqueId(685); + static constexpr const TSymbolUniqueId textureOffset_USampler2DArray1_Float3_Int2 = + TSymbolUniqueId(686); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float3_Int2 = + TSymbolUniqueId(687); + static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float3_Int2 = + TSymbolUniqueId(688); + static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float3_Int2 = + TSymbolUniqueId(689); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float4_Int2 = + TSymbolUniqueId(690); + static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float4_Int2 = + TSymbolUniqueId(691); + static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float4_Int2 = + TSymbolUniqueId(692); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler3D1_Float4_Int3 = + TSymbolUniqueId(693); + static constexpr const TSymbolUniqueId textureProjOffset_ISampler3D1_Float4_Int3 = + TSymbolUniqueId(694); + static constexpr const TSymbolUniqueId textureProjOffset_USampler3D1_Float4_Int3 = + TSymbolUniqueId(695); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler2DShadow1_Float4_Int2 = + TSymbolUniqueId(696); + static constexpr const TSymbolUniqueId textureLodOffset_Sampler2D1_Float2_Float1_Int2 = + TSymbolUniqueId(697); + static constexpr const TSymbolUniqueId textureLodOffset_ISampler2D1_Float2_Float1_Int2 = + TSymbolUniqueId(698); + static constexpr const TSymbolUniqueId textureLodOffset_USampler2D1_Float2_Float1_Int2 = + TSymbolUniqueId(699); + static constexpr const TSymbolUniqueId textureLodOffset_Sampler3D1_Float3_Float1_Int3 = + TSymbolUniqueId(700); + static constexpr const TSymbolUniqueId textureLodOffset_ISampler3D1_Float3_Float1_Int3 = + TSymbolUniqueId(701); + static constexpr const TSymbolUniqueId textureLodOffset_USampler3D1_Float3_Float1_Int3 = + TSymbolUniqueId(702); + static constexpr const TSymbolUniqueId textureLodOffset_Sampler2DShadow1_Float3_Float1_Int2 = + TSymbolUniqueId(703); + static constexpr const TSymbolUniqueId textureLodOffset_Sampler2DArray1_Float3_Float1_Int2 = + TSymbolUniqueId(704); + static constexpr const TSymbolUniqueId textureLodOffset_ISampler2DArray1_Float3_Float1_Int2 = + TSymbolUniqueId(705); + static constexpr const TSymbolUniqueId textureLodOffset_USampler2DArray1_Float3_Float1_Int2 = + TSymbolUniqueId(706); + static constexpr const TSymbolUniqueId textureProjLodOffset_Sampler2D1_Float3_Float1_Int2 = + TSymbolUniqueId(707); + static constexpr const TSymbolUniqueId textureProjLodOffset_ISampler2D1_Float3_Float1_Int2 = + TSymbolUniqueId(708); + static constexpr const TSymbolUniqueId textureProjLodOffset_USampler2D1_Float3_Float1_Int2 = + TSymbolUniqueId(709); + static constexpr const TSymbolUniqueId textureProjLodOffset_Sampler2D1_Float4_Float1_Int2 = + TSymbolUniqueId(710); + static constexpr const TSymbolUniqueId textureProjLodOffset_ISampler2D1_Float4_Float1_Int2 = + TSymbolUniqueId(711); + static constexpr const TSymbolUniqueId textureProjLodOffset_USampler2D1_Float4_Float1_Int2 = + TSymbolUniqueId(712); + static constexpr const TSymbolUniqueId textureProjLodOffset_Sampler3D1_Float4_Float1_Int3 = + TSymbolUniqueId(713); + static constexpr const TSymbolUniqueId textureProjLodOffset_ISampler3D1_Float4_Float1_Int3 = + TSymbolUniqueId(714); + static constexpr const TSymbolUniqueId textureProjLodOffset_USampler3D1_Float4_Float1_Int3 = + TSymbolUniqueId(715); + static constexpr const TSymbolUniqueId + textureProjLodOffset_Sampler2DShadow1_Float4_Float1_Int2 = TSymbolUniqueId(716); + static constexpr const TSymbolUniqueId texelFetchOffset_Sampler2D1_Int2_Int1_Int2 = + TSymbolUniqueId(717); + static constexpr const TSymbolUniqueId texelFetchOffset_ISampler2D1_Int2_Int1_Int2 = + TSymbolUniqueId(718); + static constexpr const TSymbolUniqueId texelFetchOffset_USampler2D1_Int2_Int1_Int2 = + TSymbolUniqueId(719); + static constexpr const TSymbolUniqueId texelFetchOffset_Sampler3D1_Int3_Int1_Int3 = + TSymbolUniqueId(720); + static constexpr const TSymbolUniqueId texelFetchOffset_ISampler3D1_Int3_Int1_Int3 = + TSymbolUniqueId(721); + static constexpr const TSymbolUniqueId texelFetchOffset_USampler3D1_Int3_Int1_Int3 = + TSymbolUniqueId(722); + static constexpr const TSymbolUniqueId texelFetchOffset_Sampler2DArray1_Int3_Int1_Int2 = + TSymbolUniqueId(723); + static constexpr const TSymbolUniqueId texelFetchOffset_ISampler2DArray1_Int3_Int1_Int2 = + TSymbolUniqueId(724); + static constexpr const TSymbolUniqueId texelFetchOffset_USampler2DArray1_Int3_Int1_Int2 = + TSymbolUniqueId(725); + static constexpr const TSymbolUniqueId textureGradOffset_Sampler2D1_Float2_Float2_Float2_Int2 = + TSymbolUniqueId(726); + static constexpr const TSymbolUniqueId textureGradOffset_ISampler2D1_Float2_Float2_Float2_Int2 = + TSymbolUniqueId(727); + static constexpr const TSymbolUniqueId textureGradOffset_USampler2D1_Float2_Float2_Float2_Int2 = + TSymbolUniqueId(728); + static constexpr const TSymbolUniqueId textureGradOffset_Sampler3D1_Float3_Float3_Float3_Int3 = + TSymbolUniqueId(729); + static constexpr const TSymbolUniqueId textureGradOffset_ISampler3D1_Float3_Float3_Float3_Int3 = + TSymbolUniqueId(730); + static constexpr const TSymbolUniqueId textureGradOffset_USampler3D1_Float3_Float3_Float3_Int3 = + TSymbolUniqueId(731); + static constexpr const TSymbolUniqueId + textureGradOffset_Sampler2DShadow1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(732); + static constexpr const TSymbolUniqueId + textureGradOffset_Sampler2DArray1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(733); + static constexpr const TSymbolUniqueId + textureGradOffset_ISampler2DArray1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(734); + static constexpr const TSymbolUniqueId + textureGradOffset_USampler2DArray1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(735); + static constexpr const TSymbolUniqueId + textureGradOffset_Sampler2DArrayShadow1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(736); + static constexpr const TSymbolUniqueId + textureProjGradOffset_Sampler2D1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(737); + static constexpr const TSymbolUniqueId + textureProjGradOffset_ISampler2D1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(738); + static constexpr const TSymbolUniqueId + textureProjGradOffset_USampler2D1_Float3_Float2_Float2_Int2 = TSymbolUniqueId(739); + static constexpr const TSymbolUniqueId + textureProjGradOffset_Sampler2D1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(740); + static constexpr const TSymbolUniqueId + textureProjGradOffset_ISampler2D1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(741); + static constexpr const TSymbolUniqueId + textureProjGradOffset_USampler2D1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(742); + static constexpr const TSymbolUniqueId + textureProjGradOffset_Sampler3D1_Float4_Float3_Float3_Int3 = TSymbolUniqueId(743); + static constexpr const TSymbolUniqueId + textureProjGradOffset_ISampler3D1_Float4_Float3_Float3_Int3 = TSymbolUniqueId(744); + static constexpr const TSymbolUniqueId + textureProjGradOffset_USampler3D1_Float4_Float3_Float3_Int3 = TSymbolUniqueId(745); + static constexpr const TSymbolUniqueId + textureProjGradOffset_Sampler2DShadow1_Float4_Float2_Float2_Int2 = TSymbolUniqueId(746); + static constexpr const TSymbolUniqueId textureOffset_Sampler2D1_Float2_Int2_Float1 = + TSymbolUniqueId(747); + static constexpr const TSymbolUniqueId textureOffset_ISampler2D1_Float2_Int2_Float1 = + TSymbolUniqueId(748); + static constexpr const TSymbolUniqueId textureOffset_USampler2D1_Float2_Int2_Float1 = + TSymbolUniqueId(749); + static constexpr const TSymbolUniqueId textureOffset_Sampler3D1_Float3_Int3_Float1 = + TSymbolUniqueId(750); + static constexpr const TSymbolUniqueId textureOffset_ISampler3D1_Float3_Int3_Float1 = + TSymbolUniqueId(751); + static constexpr const TSymbolUniqueId textureOffset_USampler3D1_Float3_Int3_Float1 = + TSymbolUniqueId(752); + static constexpr const TSymbolUniqueId textureOffset_Sampler2DShadow1_Float3_Int2_Float1 = + TSymbolUniqueId(753); + static constexpr const TSymbolUniqueId textureOffset_Sampler2DArray1_Float3_Int2_Float1 = + TSymbolUniqueId(754); + static constexpr const TSymbolUniqueId textureOffset_ISampler2DArray1_Float3_Int2_Float1 = + TSymbolUniqueId(755); + static constexpr const TSymbolUniqueId textureOffset_USampler2DArray1_Float3_Int2_Float1 = + TSymbolUniqueId(756); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float3_Int2_Float1 = + TSymbolUniqueId(757); + static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float3_Int2_Float1 = + TSymbolUniqueId(758); + static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float3_Int2_Float1 = + TSymbolUniqueId(759); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler2D1_Float4_Int2_Float1 = + TSymbolUniqueId(760); + static constexpr const TSymbolUniqueId textureProjOffset_ISampler2D1_Float4_Int2_Float1 = + TSymbolUniqueId(761); + static constexpr const TSymbolUniqueId textureProjOffset_USampler2D1_Float4_Int2_Float1 = + TSymbolUniqueId(762); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler3D1_Float4_Int3_Float1 = + TSymbolUniqueId(763); + static constexpr const TSymbolUniqueId textureProjOffset_ISampler3D1_Float4_Int3_Float1 = + TSymbolUniqueId(764); + static constexpr const TSymbolUniqueId textureProjOffset_USampler3D1_Float4_Int3_Float1 = + TSymbolUniqueId(765); + static constexpr const TSymbolUniqueId textureProjOffset_Sampler2DShadow1_Float4_Int2_Float1 = + TSymbolUniqueId(766); + static constexpr const TSymbolUniqueId texture_SamplerExternalOES1_Float2 = + TSymbolUniqueId(767); + static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float3 = + TSymbolUniqueId(768); + static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float4 = + TSymbolUniqueId(769); + static constexpr const TSymbolUniqueId textureSize_SamplerExternalOES1_Int1 = + TSymbolUniqueId(770); + static constexpr const TSymbolUniqueId texelFetch_SamplerExternalOES1_Int2_Int1 = + TSymbolUniqueId(771); + static constexpr const TSymbolUniqueId texture_SamplerExternal2DY2YEXT1_Float2 = + TSymbolUniqueId(772); + static constexpr const TSymbolUniqueId pt0M = TSymbolUniqueId(773); + static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float3 = + TSymbolUniqueId(774); + static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float4 = + TSymbolUniqueId(775); + static constexpr const TSymbolUniqueId rgb_2_yuv_Float3_YuvCscStandardEXT1 = + TSymbolUniqueId(776); + static constexpr const TSymbolUniqueId pt0G = TSymbolUniqueId(777); + static constexpr const TSymbolUniqueId yuv_2_rgb_Float3_YuvCscStandardEXT1 = + TSymbolUniqueId(778); + static constexpr const TSymbolUniqueId textureSize_SamplerExternal2DY2YEXT1_Int1 = + TSymbolUniqueId(779); + static constexpr const TSymbolUniqueId texelFetch_SamplerExternal2DY2YEXT1_Int2_Int1 = + TSymbolUniqueId(780); + static constexpr const TSymbolUniqueId texture_Sampler2D1_Float2_Float1 = TSymbolUniqueId(781); + static constexpr const TSymbolUniqueId texture_ISampler2D1_Float2_Float1 = TSymbolUniqueId(782); + static constexpr const TSymbolUniqueId texture_USampler2D1_Float2_Float1 = TSymbolUniqueId(783); + static constexpr const TSymbolUniqueId texture_Sampler3D1_Float3_Float1 = TSymbolUniqueId(784); + static constexpr const TSymbolUniqueId texture_ISampler3D1_Float3_Float1 = TSymbolUniqueId(785); + static constexpr const TSymbolUniqueId texture_USampler3D1_Float3_Float1 = TSymbolUniqueId(786); + static constexpr const TSymbolUniqueId texture_SamplerCube1_Float3_Float1 = + TSymbolUniqueId(787); + static constexpr const TSymbolUniqueId texture_ISamplerCube1_Float3_Float1 = + TSymbolUniqueId(788); + static constexpr const TSymbolUniqueId texture_USamplerCube1_Float3_Float1 = + TSymbolUniqueId(789); + static constexpr const TSymbolUniqueId texture_Sampler2DArray1_Float3_Float1 = + TSymbolUniqueId(790); + static constexpr const TSymbolUniqueId texture_ISampler2DArray1_Float3_Float1 = + TSymbolUniqueId(791); + static constexpr const TSymbolUniqueId texture_USampler2DArray1_Float3_Float1 = + TSymbolUniqueId(792); + static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float3_Float1 = + TSymbolUniqueId(793); + static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float3_Float1 = + TSymbolUniqueId(794); + static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float3_Float1 = + TSymbolUniqueId(795); + static constexpr const TSymbolUniqueId textureProj_Sampler2D1_Float4_Float1 = + TSymbolUniqueId(796); + static constexpr const TSymbolUniqueId textureProj_ISampler2D1_Float4_Float1 = + TSymbolUniqueId(797); + static constexpr const TSymbolUniqueId textureProj_USampler2D1_Float4_Float1 = + TSymbolUniqueId(798); + static constexpr const TSymbolUniqueId textureProj_Sampler3D1_Float4_Float1 = + TSymbolUniqueId(799); + static constexpr const TSymbolUniqueId textureProj_ISampler3D1_Float4_Float1 = + TSymbolUniqueId(800); + static constexpr const TSymbolUniqueId textureProj_USampler3D1_Float4_Float1 = + TSymbolUniqueId(801); + static constexpr const TSymbolUniqueId texture_Sampler2DShadow1_Float3_Float1 = + TSymbolUniqueId(802); + static constexpr const TSymbolUniqueId texture_SamplerCubeShadow1_Float4_Float1 = + TSymbolUniqueId(803); + static constexpr const TSymbolUniqueId textureProj_Sampler2DShadow1_Float4_Float1 = + TSymbolUniqueId(804); + static constexpr const TSymbolUniqueId texture_SamplerExternalOES1_Float2_Float1 = + TSymbolUniqueId(805); + static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float3_Float1 = + TSymbolUniqueId(806); + static constexpr const TSymbolUniqueId textureProj_SamplerExternalOES1_Float4_Float1 = + TSymbolUniqueId(807); + static constexpr const TSymbolUniqueId texture_SamplerExternal2DY2YEXT1_Float2_Float1 = + TSymbolUniqueId(808); + static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float3_Float1 = + TSymbolUniqueId(809); + static constexpr const TSymbolUniqueId textureProj_SamplerExternal2DY2YEXT1_Float4_Float1 = + TSymbolUniqueId(810); + static constexpr const TSymbolUniqueId texelFetch_Sampler2DMS1_Int2_Int1 = TSymbolUniqueId(811); + static constexpr const TSymbolUniqueId texelFetch_ISampler2DMS1_Int2_Int1 = + TSymbolUniqueId(812); + static constexpr const TSymbolUniqueId texelFetch_USampler2DMS1_Int2_Int1 = + TSymbolUniqueId(813); + static constexpr const TSymbolUniqueId texelFetchExt_Sampler2DMS1_Int2_Int1 = + TSymbolUniqueId(814); + static constexpr const TSymbolUniqueId texelFetchExt_ISampler2DMS1_Int2_Int1 = + TSymbolUniqueId(815); + static constexpr const TSymbolUniqueId texelFetchExt_USampler2DMS1_Int2_Int1 = + TSymbolUniqueId(816); + static constexpr const TSymbolUniqueId texelFetch_Sampler2DMSArray1_Int3_Int1 = + TSymbolUniqueId(817); + static constexpr const TSymbolUniqueId texelFetch_ISampler2DMSArray1_Int3_Int1 = + TSymbolUniqueId(818); + static constexpr const TSymbolUniqueId texelFetch_USampler2DMSArray1_Int3_Int1 = + TSymbolUniqueId(819); + static constexpr const TSymbolUniqueId textureGather_Sampler2D1_Float2 = TSymbolUniqueId(820); + static constexpr const TSymbolUniqueId textureGather_ISampler2D1_Float2 = TSymbolUniqueId(821); + static constexpr const TSymbolUniqueId textureGather_USampler2D1_Float2 = TSymbolUniqueId(822); + static constexpr const TSymbolUniqueId textureGather_Sampler2D1_Float2_Int1 = + TSymbolUniqueId(823); + static constexpr const TSymbolUniqueId textureGather_ISampler2D1_Float2_Int1 = + TSymbolUniqueId(824); + static constexpr const TSymbolUniqueId textureGather_USampler2D1_Float2_Int1 = + TSymbolUniqueId(825); + static constexpr const TSymbolUniqueId textureGather_Sampler2DArray1_Float3 = + TSymbolUniqueId(826); + static constexpr const TSymbolUniqueId textureGather_ISampler2DArray1_Float3 = + TSymbolUniqueId(827); + static constexpr const TSymbolUniqueId textureGather_USampler2DArray1_Float3 = + TSymbolUniqueId(828); + static constexpr const TSymbolUniqueId textureGather_Sampler2DArray1_Float3_Int1 = + TSymbolUniqueId(829); + static constexpr const TSymbolUniqueId textureGather_ISampler2DArray1_Float3_Int1 = + TSymbolUniqueId(830); + static constexpr const TSymbolUniqueId textureGather_USampler2DArray1_Float3_Int1 = + TSymbolUniqueId(831); + static constexpr const TSymbolUniqueId textureGather_SamplerCube1_Float3 = TSymbolUniqueId(832); + static constexpr const TSymbolUniqueId textureGather_ISamplerCube1_Float3 = + TSymbolUniqueId(833); + static constexpr const TSymbolUniqueId textureGather_USamplerCube1_Float3 = + TSymbolUniqueId(834); + static constexpr const TSymbolUniqueId textureGather_SamplerCube1_Float3_Int1 = + TSymbolUniqueId(835); + static constexpr const TSymbolUniqueId textureGather_ISamplerCube1_Float3_Int1 = + TSymbolUniqueId(836); + static constexpr const TSymbolUniqueId textureGather_USamplerCube1_Float3_Int1 = + TSymbolUniqueId(837); + static constexpr const TSymbolUniqueId textureGather_Sampler2DShadow1_Float2 = + TSymbolUniqueId(838); + static constexpr const TSymbolUniqueId textureGather_Sampler2DShadow1_Float2_Float1 = + TSymbolUniqueId(839); + static constexpr const TSymbolUniqueId textureGather_Sampler2DArrayShadow1_Float3 = + TSymbolUniqueId(840); + static constexpr const TSymbolUniqueId textureGather_Sampler2DArrayShadow1_Float3_Float1 = + TSymbolUniqueId(841); + static constexpr const TSymbolUniqueId textureGather_SamplerCubeShadow1_Float3 = + TSymbolUniqueId(842); + static constexpr const TSymbolUniqueId textureGather_SamplerCubeShadow1_Float3_Float1 = + TSymbolUniqueId(843); + static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2D1_Float2_Int2 = + TSymbolUniqueId(844); + static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2D1_Float2_Int2 = + TSymbolUniqueId(845); + static constexpr const TSymbolUniqueId textureGatherOffset_USampler2D1_Float2_Int2 = + TSymbolUniqueId(846); + static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2D1_Float2_Int2_Int1 = + TSymbolUniqueId(847); + static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2D1_Float2_Int2_Int1 = + TSymbolUniqueId(848); + static constexpr const TSymbolUniqueId textureGatherOffset_USampler2D1_Float2_Int2_Int1 = + TSymbolUniqueId(849); + static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2DArray1_Float3_Int2 = + TSymbolUniqueId(850); + static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2DArray1_Float3_Int2 = + TSymbolUniqueId(851); + static constexpr const TSymbolUniqueId textureGatherOffset_USampler2DArray1_Float3_Int2 = + TSymbolUniqueId(852); + static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2DArray1_Float3_Int2_Int1 = + TSymbolUniqueId(853); + static constexpr const TSymbolUniqueId textureGatherOffset_ISampler2DArray1_Float3_Int2_Int1 = + TSymbolUniqueId(854); + static constexpr const TSymbolUniqueId textureGatherOffset_USampler2DArray1_Float3_Int2_Int1 = + TSymbolUniqueId(855); + static constexpr const TSymbolUniqueId textureGatherOffset_Sampler2DShadow1_Float2_Float1_Int2 = + TSymbolUniqueId(856); + static constexpr const TSymbolUniqueId + textureGatherOffset_Sampler2DArrayShadow1_Float3_Float1_Int2 = TSymbolUniqueId(857); + static constexpr const TSymbolUniqueId dFdx_Float1 = TSymbolUniqueId(858); + static constexpr const TSymbolUniqueId dFdx_Float2 = TSymbolUniqueId(859); + static constexpr const TSymbolUniqueId dFdx_Float3 = TSymbolUniqueId(860); + static constexpr const TSymbolUniqueId dFdx_Float4 = TSymbolUniqueId(861); + static constexpr const TSymbolUniqueId dFdy_Float1 = TSymbolUniqueId(862); + static constexpr const TSymbolUniqueId dFdy_Float2 = TSymbolUniqueId(863); + static constexpr const TSymbolUniqueId dFdy_Float3 = TSymbolUniqueId(864); + static constexpr const TSymbolUniqueId dFdy_Float4 = TSymbolUniqueId(865); + static constexpr const TSymbolUniqueId fwidth_Float1 = TSymbolUniqueId(866); + static constexpr const TSymbolUniqueId fwidth_Float2 = TSymbolUniqueId(867); + static constexpr const TSymbolUniqueId fwidth_Float3 = TSymbolUniqueId(868); + static constexpr const TSymbolUniqueId fwidth_Float4 = TSymbolUniqueId(869); + static constexpr const TSymbolUniqueId atomicCounter_AtomicCounter1 = TSymbolUniqueId(870); + static constexpr const TSymbolUniqueId pt0F = TSymbolUniqueId(871); + static constexpr const TSymbolUniqueId atomicCounterIncrement_AtomicCounter1 = + TSymbolUniqueId(872); + static constexpr const TSymbolUniqueId atomicCounterDecrement_AtomicCounter1 = + TSymbolUniqueId(873); + static constexpr const TSymbolUniqueId atomicAdd_UInt1_UInt1 = TSymbolUniqueId(874); + static constexpr const TSymbolUniqueId pt_io_0D = TSymbolUniqueId(875); + static constexpr const TSymbolUniqueId atomicAdd_Int1_Int1 = TSymbolUniqueId(876); + static constexpr const TSymbolUniqueId pt_io_0C = TSymbolUniqueId(877); + static constexpr const TSymbolUniqueId atomicMin_UInt1_UInt1 = TSymbolUniqueId(878); + static constexpr const TSymbolUniqueId atomicMin_Int1_Int1 = TSymbolUniqueId(879); + static constexpr const TSymbolUniqueId atomicMax_UInt1_UInt1 = TSymbolUniqueId(880); + static constexpr const TSymbolUniqueId atomicMax_Int1_Int1 = TSymbolUniqueId(881); + static constexpr const TSymbolUniqueId atomicAnd_UInt1_UInt1 = TSymbolUniqueId(882); + static constexpr const TSymbolUniqueId atomicAnd_Int1_Int1 = TSymbolUniqueId(883); + static constexpr const TSymbolUniqueId atomicOr_UInt1_UInt1 = TSymbolUniqueId(884); + static constexpr const TSymbolUniqueId atomicOr_Int1_Int1 = TSymbolUniqueId(885); + static constexpr const TSymbolUniqueId atomicXor_UInt1_UInt1 = TSymbolUniqueId(886); + static constexpr const TSymbolUniqueId atomicXor_Int1_Int1 = TSymbolUniqueId(887); + static constexpr const TSymbolUniqueId atomicExchange_UInt1_UInt1 = TSymbolUniqueId(888); + static constexpr const TSymbolUniqueId atomicExchange_Int1_Int1 = TSymbolUniqueId(889); + static constexpr const TSymbolUniqueId atomicCompSwap_UInt1_UInt1_UInt1 = TSymbolUniqueId(890); + static constexpr const TSymbolUniqueId atomicCompSwap_Int1_Int1_Int1 = TSymbolUniqueId(891); + static constexpr const TSymbolUniqueId imageSize_Image2D1 = TSymbolUniqueId(892); + static constexpr const TSymbolUniqueId pt0f = TSymbolUniqueId(893); + static constexpr const TSymbolUniqueId imageSize_IImage2D1 = TSymbolUniqueId(894); + static constexpr const TSymbolUniqueId pt0g = TSymbolUniqueId(895); + static constexpr const TSymbolUniqueId imageSize_UImage2D1 = TSymbolUniqueId(896); + static constexpr const TSymbolUniqueId pt0h = TSymbolUniqueId(897); + static constexpr const TSymbolUniqueId imageSize_Image3D1 = TSymbolUniqueId(898); + static constexpr const TSymbolUniqueId pt0i = TSymbolUniqueId(899); + static constexpr const TSymbolUniqueId imageSize_IImage3D1 = TSymbolUniqueId(900); + static constexpr const TSymbolUniqueId pt0j = TSymbolUniqueId(901); + static constexpr const TSymbolUniqueId imageSize_UImage3D1 = TSymbolUniqueId(902); + static constexpr const TSymbolUniqueId pt0k = TSymbolUniqueId(903); + static constexpr const TSymbolUniqueId imageSize_Image2DArray1 = TSymbolUniqueId(904); + static constexpr const TSymbolUniqueId pt0l = TSymbolUniqueId(905); + static constexpr const TSymbolUniqueId imageSize_IImage2DArray1 = TSymbolUniqueId(906); + static constexpr const TSymbolUniqueId pt0m = TSymbolUniqueId(907); + static constexpr const TSymbolUniqueId imageSize_UImage2DArray1 = TSymbolUniqueId(908); + static constexpr const TSymbolUniqueId pt0n = TSymbolUniqueId(909); + static constexpr const TSymbolUniqueId imageSize_ImageCube1 = TSymbolUniqueId(910); + static constexpr const TSymbolUniqueId pt0o = TSymbolUniqueId(911); + static constexpr const TSymbolUniqueId imageSize_IImageCube1 = TSymbolUniqueId(912); + static constexpr const TSymbolUniqueId pt0p = TSymbolUniqueId(913); + static constexpr const TSymbolUniqueId imageSize_UImageCube1 = TSymbolUniqueId(914); + static constexpr const TSymbolUniqueId pt0q = TSymbolUniqueId(915); + static constexpr const TSymbolUniqueId imageLoad_Image2D1_Int2 = TSymbolUniqueId(916); + static constexpr const TSymbolUniqueId imageLoad_IImage2D1_Int2 = TSymbolUniqueId(917); + static constexpr const TSymbolUniqueId imageLoad_UImage2D1_Int2 = TSymbolUniqueId(918); + static constexpr const TSymbolUniqueId imageLoad_Image3D1_Int3 = TSymbolUniqueId(919); + static constexpr const TSymbolUniqueId imageLoad_IImage3D1_Int3 = TSymbolUniqueId(920); + static constexpr const TSymbolUniqueId imageLoad_UImage3D1_Int3 = TSymbolUniqueId(921); + static constexpr const TSymbolUniqueId imageLoad_Image2DArray1_Int3 = TSymbolUniqueId(922); + static constexpr const TSymbolUniqueId imageLoad_IImage2DArray1_Int3 = TSymbolUniqueId(923); + static constexpr const TSymbolUniqueId imageLoad_UImage2DArray1_Int3 = TSymbolUniqueId(924); + static constexpr const TSymbolUniqueId imageLoad_ImageCube1_Int3 = TSymbolUniqueId(925); + static constexpr const TSymbolUniqueId imageLoad_IImageCube1_Int3 = TSymbolUniqueId(926); + static constexpr const TSymbolUniqueId imageLoad_UImageCube1_Int3 = TSymbolUniqueId(927); + static constexpr const TSymbolUniqueId imageStore_Image2D1_Int2_Float4 = TSymbolUniqueId(928); + static constexpr const TSymbolUniqueId imageStore_IImage2D1_Int2_Int4 = TSymbolUniqueId(929); + static constexpr const TSymbolUniqueId imageStore_UImage2D1_Int2_UInt4 = TSymbolUniqueId(930); + static constexpr const TSymbolUniqueId imageStore_Image3D1_Int3_Float4 = TSymbolUniqueId(931); + static constexpr const TSymbolUniqueId imageStore_IImage3D1_Int3_Int4 = TSymbolUniqueId(932); + static constexpr const TSymbolUniqueId imageStore_UImage3D1_Int3_UInt4 = TSymbolUniqueId(933); + static constexpr const TSymbolUniqueId imageStore_Image2DArray1_Int3_Float4 = + TSymbolUniqueId(934); + static constexpr const TSymbolUniqueId imageStore_IImage2DArray1_Int3_Int4 = + TSymbolUniqueId(935); + static constexpr const TSymbolUniqueId imageStore_UImage2DArray1_Int3_UInt4 = + TSymbolUniqueId(936); + static constexpr const TSymbolUniqueId imageStore_ImageCube1_Int3_Float4 = TSymbolUniqueId(937); + static constexpr const TSymbolUniqueId imageStore_IImageCube1_Int3_Int4 = TSymbolUniqueId(938); + static constexpr const TSymbolUniqueId imageStore_UImageCube1_Int3_UInt4 = TSymbolUniqueId(939); + static constexpr const TSymbolUniqueId memoryBarrier = TSymbolUniqueId(940); + static constexpr const TSymbolUniqueId memoryBarrierAtomicCounter = TSymbolUniqueId(941); + static constexpr const TSymbolUniqueId memoryBarrierBuffer = TSymbolUniqueId(942); + static constexpr const TSymbolUniqueId memoryBarrierImage = TSymbolUniqueId(943); + static constexpr const TSymbolUniqueId barrier = TSymbolUniqueId(944); + static constexpr const TSymbolUniqueId memoryBarrierShared = TSymbolUniqueId(945); + static constexpr const TSymbolUniqueId groupMemoryBarrier = TSymbolUniqueId(946); + static constexpr const TSymbolUniqueId EmitVertex = TSymbolUniqueId(947); + static constexpr const TSymbolUniqueId EndPrimitive = TSymbolUniqueId(948); + static constexpr const TSymbolUniqueId gl_DepthRangeParameters = TSymbolUniqueId(949); + static constexpr const TSymbolUniqueId gl_DepthRange = TSymbolUniqueId(950); + static constexpr const TSymbolUniqueId gl_MaxVertexAttribs = TSymbolUniqueId(951); + static constexpr const TSymbolUniqueId gl_MaxVertexUniformVectors = TSymbolUniqueId(952); + static constexpr const TSymbolUniqueId gl_MaxVertexTextureImageUnits = TSymbolUniqueId(953); + static constexpr const TSymbolUniqueId gl_MaxCombinedTextureImageUnits = TSymbolUniqueId(954); + static constexpr const TSymbolUniqueId gl_MaxTextureImageUnits = TSymbolUniqueId(955); + static constexpr const TSymbolUniqueId gl_MaxFragmentUniformVectors = TSymbolUniqueId(956); + static constexpr const TSymbolUniqueId gl_MaxVaryingVectors = TSymbolUniqueId(957); + static constexpr const TSymbolUniqueId gl_MaxDrawBuffers = TSymbolUniqueId(958); + static constexpr const TSymbolUniqueId gl_MaxDualSourceDrawBuffersEXT = TSymbolUniqueId(959); + static constexpr const TSymbolUniqueId gl_MaxVertexOutputVectors = TSymbolUniqueId(960); + static constexpr const TSymbolUniqueId gl_MaxFragmentInputVectors = TSymbolUniqueId(961); + static constexpr const TSymbolUniqueId gl_MinProgramTexelOffset = TSymbolUniqueId(962); + static constexpr const TSymbolUniqueId gl_MaxProgramTexelOffset = TSymbolUniqueId(963); + static constexpr const TSymbolUniqueId gl_MaxImageUnits = TSymbolUniqueId(964); + static constexpr const TSymbolUniqueId gl_MaxVertexImageUniforms = TSymbolUniqueId(965); + static constexpr const TSymbolUniqueId gl_MaxFragmentImageUniforms = TSymbolUniqueId(966); + static constexpr const TSymbolUniqueId gl_MaxComputeImageUniforms = TSymbolUniqueId(967); + static constexpr const TSymbolUniqueId gl_MaxCombinedImageUniforms = TSymbolUniqueId(968); + static constexpr const TSymbolUniqueId gl_MaxCombinedShaderOutputResources = + TSymbolUniqueId(969); + static constexpr const TSymbolUniqueId gl_MaxComputeWorkGroupCount = TSymbolUniqueId(970); + static constexpr const TSymbolUniqueId gl_MaxComputeWorkGroupSize = TSymbolUniqueId(971); + static constexpr const TSymbolUniqueId gl_MaxComputeUniformComponents = TSymbolUniqueId(972); + static constexpr const TSymbolUniqueId gl_MaxComputeTextureImageUnits = TSymbolUniqueId(973); + static constexpr const TSymbolUniqueId gl_MaxComputeAtomicCounters = TSymbolUniqueId(974); + static constexpr const TSymbolUniqueId gl_MaxComputeAtomicCounterBuffers = TSymbolUniqueId(975); + static constexpr const TSymbolUniqueId gl_MaxVertexAtomicCounters = TSymbolUniqueId(976); + static constexpr const TSymbolUniqueId gl_MaxFragmentAtomicCounters = TSymbolUniqueId(977); + static constexpr const TSymbolUniqueId gl_MaxCombinedAtomicCounters = TSymbolUniqueId(978); + static constexpr const TSymbolUniqueId gl_MaxAtomicCounterBindings = TSymbolUniqueId(979); + static constexpr const TSymbolUniqueId gl_MaxVertexAtomicCounterBuffers = TSymbolUniqueId(980); + static constexpr const TSymbolUniqueId gl_MaxFragmentAtomicCounterBuffers = + TSymbolUniqueId(981); + static constexpr const TSymbolUniqueId gl_MaxCombinedAtomicCounterBuffers = + TSymbolUniqueId(982); + static constexpr const TSymbolUniqueId gl_MaxAtomicCounterBufferSize = TSymbolUniqueId(983); + static constexpr const TSymbolUniqueId gl_MaxGeometryInputComponents = TSymbolUniqueId(984); + static constexpr const TSymbolUniqueId gl_MaxGeometryOutputComponents = TSymbolUniqueId(985); + static constexpr const TSymbolUniqueId gl_MaxGeometryImageUniforms = TSymbolUniqueId(986); + static constexpr const TSymbolUniqueId gl_MaxGeometryTextureImageUnits = TSymbolUniqueId(987); + static constexpr const TSymbolUniqueId gl_MaxGeometryOutputVertices = TSymbolUniqueId(988); + static constexpr const TSymbolUniqueId gl_MaxGeometryTotalOutputComponents = + TSymbolUniqueId(989); + static constexpr const TSymbolUniqueId gl_MaxGeometryUniformComponents = TSymbolUniqueId(990); + static constexpr const TSymbolUniqueId gl_MaxGeometryAtomicCounters = TSymbolUniqueId(991); + static constexpr const TSymbolUniqueId gl_MaxGeometryAtomicCounterBuffers = + TSymbolUniqueId(992); + static constexpr const TSymbolUniqueId gl_FragCoord = TSymbolUniqueId(993); + static constexpr const TSymbolUniqueId gl_FrontFacing = TSymbolUniqueId(994); + static constexpr const TSymbolUniqueId gl_PointCoord = TSymbolUniqueId(995); + static constexpr const TSymbolUniqueId gl_FragColor = TSymbolUniqueId(996); + static constexpr const TSymbolUniqueId gl_FragData = TSymbolUniqueId(997); + static constexpr const TSymbolUniqueId gl_FragDepth = TSymbolUniqueId(998); + static constexpr const TSymbolUniqueId gl_SecondaryFragColorEXT = TSymbolUniqueId(999); + static constexpr const TSymbolUniqueId gl_SecondaryFragDataEXT = TSymbolUniqueId(1000); + static constexpr const TSymbolUniqueId gl_FragDepthEXT = TSymbolUniqueId(1001); + static constexpr const TSymbolUniqueId gl_LastFragData = TSymbolUniqueId(1002); + static constexpr const TSymbolUniqueId gl_LastFragColor = TSymbolUniqueId(1003); + static constexpr const TSymbolUniqueId gl_LastFragDataNV = TSymbolUniqueId(1004); + static constexpr const TSymbolUniqueId gl_LastFragColorARM = TSymbolUniqueId(1005); + static constexpr const TSymbolUniqueId gl_PrimitiveID = TSymbolUniqueId(1006); + static constexpr const TSymbolUniqueId gl_Layer = TSymbolUniqueId(1007); + static constexpr const TSymbolUniqueId gl_Position = TSymbolUniqueId(1008); + static constexpr const TSymbolUniqueId gl_PointSize = TSymbolUniqueId(1009); + static constexpr const TSymbolUniqueId gl_InstanceID = TSymbolUniqueId(1010); + static constexpr const TSymbolUniqueId gl_VertexID = TSymbolUniqueId(1011); + static constexpr const TSymbolUniqueId gl_ViewportIndex = TSymbolUniqueId(1012); + static constexpr const TSymbolUniqueId gl_LayerVS = TSymbolUniqueId(1013); + static constexpr const TSymbolUniqueId gl_DrawID = TSymbolUniqueId(1014); + static constexpr const TSymbolUniqueId gl_DrawIDESSL1 = TSymbolUniqueId(1015); + static constexpr const TSymbolUniqueId gl_BaseVertex = TSymbolUniqueId(1016); + static constexpr const TSymbolUniqueId gl_BaseInstance = TSymbolUniqueId(1017); + static constexpr const TSymbolUniqueId gl_NumWorkGroups = TSymbolUniqueId(1018); + static constexpr const TSymbolUniqueId gl_WorkGroupSize = TSymbolUniqueId(1019); + static constexpr const TSymbolUniqueId gl_WorkGroupID = TSymbolUniqueId(1020); + static constexpr const TSymbolUniqueId gl_LocalInvocationID = TSymbolUniqueId(1021); + static constexpr const TSymbolUniqueId gl_GlobalInvocationID = TSymbolUniqueId(1022); + static constexpr const TSymbolUniqueId gl_LocalInvocationIndex = TSymbolUniqueId(1023); + static constexpr const TSymbolUniqueId gl_PrimitiveIDIn = TSymbolUniqueId(1024); + static constexpr const TSymbolUniqueId gl_InvocationID = TSymbolUniqueId(1025); + static constexpr const TSymbolUniqueId gl_PrimitiveIDGS = TSymbolUniqueId(1026); + static constexpr const TSymbolUniqueId gl_LayerGS = TSymbolUniqueId(1027); + static constexpr const TSymbolUniqueId gl_PerVertex = TSymbolUniqueId(1028); + static constexpr const TSymbolUniqueId gl_in = TSymbolUniqueId(1029); + static constexpr const TSymbolUniqueId gl_PerVertexOutBlock = TSymbolUniqueId(1030); + static constexpr const TSymbolUniqueId gl_PositionGS = TSymbolUniqueId(1031); + static constexpr const TSymbolUniqueId gl_ViewID_OVR = TSymbolUniqueId(1032); + static constexpr const TSymbolUniqueId gl_ViewID_OVRESSL1 = TSymbolUniqueId(1033); + +}; // class BuiltInId + +namespace BuiltInVariable +{ + +const TVariable *gl_BaseInstance(); +const TVariable *gl_BaseVertex(); +const TVariable *gl_DrawID(); +const TVariable *gl_DrawIDESSL1(); +const TVariable *gl_FragColor(); +const TVariable *gl_FragCoord(); +const TVariable *gl_FragDepth(); +const TVariable *gl_FrontFacing(); +const TVariable *gl_GlobalInvocationID(); +const TVariable *gl_InstanceID(); +const TVariable *gl_InvocationID(); +const TVariable *gl_LastFragColor(); +const TVariable *gl_LastFragColorARM(); +const TVariable *gl_Layer(); +const TVariable *gl_LayerGS(); +const TVariable *gl_LayerVS(); +const TVariable *gl_LocalInvocationID(); +const TVariable *gl_LocalInvocationIndex(); +const TVariable *gl_NumWorkGroups(); +const TVariable *gl_PointCoord(); +const TVariable *gl_PointSize(); +const TVariable *gl_Position(); +const TVariable *gl_PrimitiveID(); +const TVariable *gl_PrimitiveIDGS(); +const TVariable *gl_PrimitiveIDIn(); +const TVariable *gl_SecondaryFragColorEXT(); +const TVariable *gl_VertexID(); +const TVariable *gl_ViewID_OVR(); +const TVariable *gl_ViewID_OVRESSL1(); +const TVariable *gl_ViewportIndex(); +const TVariable *gl_WorkGroupID(); +const TVariable *gl_WorkGroupSize(); + +} // namespace BuiltInVariable + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.cpp new file mode 100644 index 0000000000..198040df14 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.cpp @@ -0,0 +1,32 @@ +// +// 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. +// + +// FindFunction.cpp: Find functions. + +#include "compiler/translator/tree_util/FindFunction.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Symbol.h" + +namespace sh +{ + +size_t FindFirstFunctionDefinitionIndex(TIntermBlock *root) +{ + const TIntermSequence &sequence = *root->getSequence(); + for (size_t index = 0; index < sequence.size(); ++index) + { + TIntermNode *node = sequence[index]; + TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition(); + if (nodeFunction != nullptr) + { + return index; + } + } + return std::numeric_limits<size_t>::max(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.h b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.h new file mode 100644 index 0000000000..946a135037 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindFunction.h @@ -0,0 +1,21 @@ +// +// 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. +// + +// FindFunction.h: Adds functions to find functions + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_FINDFUNCTION_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_FINDFUNCTION_H_ + +#include <cstddef> + +namespace sh +{ +class TIntermBlock; + +size_t FindFirstFunctionDefinitionIndex(TIntermBlock *root); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_FINDFUNCTION_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp new file mode 100644 index 0000000000..0e3023b2bf --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp @@ -0,0 +1,54 @@ +// +// Copyright (c) 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. +// + +// FindMain.cpp: Find the main() function definition in a given AST. + +#include "compiler/translator/tree_util/FindMain.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Symbol.h" + +namespace sh +{ + +size_t FindMainIndex(TIntermBlock *root) +{ + const TIntermSequence &sequence = *root->getSequence(); + for (size_t index = 0; index < sequence.size(); ++index) + { + TIntermNode *node = sequence[index]; + TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition(); + if (nodeFunction != nullptr && nodeFunction->getFunction()->isMain()) + { + return index; + } + } + return std::numeric_limits<size_t>::max(); +} + +TIntermFunctionDefinition *FindMain(TIntermBlock *root) +{ + for (TIntermNode *node : *root->getSequence()) + { + TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition(); + if (nodeFunction != nullptr && nodeFunction->getFunction()->isMain()) + { + return nodeFunction; + } + } + return nullptr; +} + +TIntermBlock *FindMainBody(TIntermBlock *root) +{ + TIntermFunctionDefinition *main = FindMain(root); + ASSERT(main != nullptr); + TIntermBlock *mainBody = main->getBody(); + ASSERT(mainBody != nullptr); + return mainBody; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h new file mode 100644 index 0000000000..a313315d76 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 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. +// + +// FindMain.h: Adds functions to get the main function definition and its body. + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_FINDMAIN_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_FINDMAIN_H_ + +#include <cstddef> + +namespace sh +{ +class TIntermBlock; +class TIntermFunctionDefinition; + +size_t FindMainIndex(TIntermBlock *root); +TIntermFunctionDefinition *FindMain(TIntermBlock *root); +TIntermBlock *FindMainBody(TIntermBlock *root); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_FINDMAIN_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp new file mode 100644 index 0000000000..3eeb9cfd05 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2015 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. +// +// FindSymbol.cpp: +// Utility for finding a symbol node inside an AST tree. + +#include "compiler/translator/tree_util/FindSymbolNode.h" + +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/Symbol.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class SymbolFinder : public TIntermTraverser +{ + public: + SymbolFinder(const ImmutableString &symbolName) + : TIntermTraverser(true, false, false), mSymbolName(symbolName), mNodeFound(nullptr) + {} + + void visitSymbol(TIntermSymbol *node) + { + if (node->variable().symbolType() != SymbolType::Empty && node->getName() == mSymbolName) + { + mNodeFound = node; + } + } + + bool isFound() const { return mNodeFound != nullptr; } + const TIntermSymbol *getNode() const { return mNodeFound; } + + private: + ImmutableString mSymbolName; + TIntermSymbol *mNodeFound; +}; + +} // anonymous namespace + +const TIntermSymbol *FindSymbolNode(TIntermNode *root, const ImmutableString &symbolName) +{ + SymbolFinder finder(symbolName); + root->traverse(&finder); + return finder.getNode(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h new file mode 100644 index 0000000000..f285479277 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2015 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. +// +// FindSymbolNode.h: +// Utility for finding a symbol node inside an AST tree. + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_FINDSYMBOLNODE_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_FINDSYMBOLNODE_H_ + +namespace sh +{ + +class ImmutableString; +class TIntermNode; +class TIntermSymbol; + +const TIntermSymbol *FindSymbolNode(TIntermNode *root, const ImmutableString &symbolName); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_FINDSYMBOLNODE_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp new file mode 100644 index 0000000000..0f3c3a42a3 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp @@ -0,0 +1,204 @@ +// +// Copyright (c) 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. +// +// IntermNodePatternMatcher is a helper class for matching node trees to given patterns. +// It can be used whenever the same checks for certain node structures are common to multiple AST +// traversers. +// + +#include "compiler/translator/tree_util/IntermNodePatternMatcher.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +bool ContainsMatrixNode(const TIntermSequence &sequence) +{ + for (size_t ii = 0; ii < sequence.size(); ++ii) + { + TIntermTyped *node = sequence[ii]->getAsTyped(); + if (node && node->isMatrix()) + return true; + } + return false; +} + +bool ContainsVectorNode(const TIntermSequence &sequence) +{ + for (size_t ii = 0; ii < sequence.size(); ++ii) + { + TIntermTyped *node = sequence[ii]->getAsTyped(); + if (node && node->isVector()) + return true; + } + return false; +} + +} // anonymous namespace + +IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask) {} + +// static +bool IntermNodePatternMatcher::IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node) +{ + return IsDynamicIndexingOfVectorOrMatrix(node) && !IsInShaderStorageBlock(node->getLeft()); +} + +// static +bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node) +{ + return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() && + node->getLeft()->getBasicType() != EbtStruct; +} + +bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode) +{ + if ((mMask & kExpressionReturningArray) != 0) + { + if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr && + !parentNode->getAsBlock()) + { + return true; + } + } + + if ((mMask & kUnfoldedShortCircuitExpression) != 0) + { + if (node->getRight()->hasSideEffects() && + (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd)) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermUnary *node) +{ + if ((mMask & kArrayLengthMethod) != 0) + { + if (node->getOp() == EOpArrayLength) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode) +{ + // L-value tracking information is needed to check for dynamic indexing in L-value. + // Traversers that don't track l-values can still use this class and match binary nodes with + // this variation of this method if they don't need to check for dynamic indexing in l-values. + ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0); + return matchInternal(node, parentNode); +} + +bool IntermNodePatternMatcher::match(TIntermBinary *node, + TIntermNode *parentNode, + bool isLValueRequiredHere) +{ + if (matchInternal(node, parentNode)) + { + return true; + } + if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0) + { + if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node)) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode) +{ + if ((mMask & kExpressionReturningArray) != 0) + { + if (parentNode != nullptr) + { + TIntermBinary *parentBinary = parentNode->getAsBinaryNode(); + bool parentIsAssignment = + (parentBinary != nullptr && + (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize)); + + if (node->getType().isArray() && !parentIsAssignment && + (node->isConstructor() || node->isFunctionCall()) && !parentNode->getAsBlock()) + { + return true; + } + } + } + if ((mMask & kScalarizedVecOrMatConstructor) != 0) + { + if (node->getOp() == EOpConstruct) + { + if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence()))) + { + return true; + } + else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence()))) + { + return true; + } + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermTernary *node) +{ + if ((mMask & kUnfoldedShortCircuitExpression) != 0) + { + return true; + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermDeclaration *node) +{ + if ((mMask & kMultiDeclaration) != 0) + { + if (node->getSequence()->size() > 1) + { + return true; + } + } + if ((mMask & kArrayDeclaration) != 0) + { + if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays()) + { + return true; + } + // Need to check from all declarators whether they are arrays since that may vary between + // declarators. + for (TIntermNode *declarator : *node->getSequence()) + { + if (declarator->getAsTyped()->isArray()) + { + return true; + } + } + } + if ((mMask & kNamelessStructDeclaration) != 0) + { + TIntermTyped *declarator = node->getSequence()->front()->getAsTyped(); + if (declarator->getBasicType() == EbtStruct && + declarator->getType().getStruct()->symbolType() == SymbolType::Empty) + { + return true; + } + } + return false; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h new file mode 100644 index 0000000000..25a46ff4f6 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 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. +// +// IntermNodePatternMatcher is a helper class for matching node trees to given patterns. +// It can be used whenever the same checks for certain node structures are common to multiple AST +// traversers. +// + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMNODEPATTERNMATCHER_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_INTERMNODEPATTERNMATCHER_H_ + +namespace sh +{ + +class TIntermAggregate; +class TIntermBinary; +class TIntermDeclaration; +class TIntermNode; +class TIntermTernary; +class TIntermUnary; + +class IntermNodePatternMatcher +{ + public: + static bool IsDynamicIndexingOfNonSSBOVectorOrMatrix(TIntermBinary *node); + static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node); + + enum PatternType + { + // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf + kUnfoldedShortCircuitExpression = 0x0001, + + // Matches expressions that return arrays with the exception of simple statements where a + // constructor or function call result is assigned. + kExpressionReturningArray = 0x0001 << 1, + + // Matches dynamic indexing of vectors or matrices in l-values. + kDynamicIndexingOfVectorOrMatrixInLValue = 0x0001 << 2, + + // Matches declarations with more than one declared variables. + kMultiDeclaration = 0x0001 << 3, + + // Matches declarations of arrays. + kArrayDeclaration = 0x0001 << 4, + + // Matches declarations of structs where the struct type does not have a name. + kNamelessStructDeclaration = 0x0001 << 5, + + // Matches array length() method. + kArrayLengthMethod = 0x0001 << 6, + + // Matches a vector or matrix constructor whose arguments are scalarized by the + // SH_SCALARIZE_VEC_OR_MAT_CONSTRUCTOR_ARGUMENTS workaround. + kScalarizedVecOrMatConstructor = 0x0001 << 7 + }; + IntermNodePatternMatcher(const unsigned int mask); + + bool match(TIntermUnary *node); + + bool match(TIntermBinary *node, TIntermNode *parentNode); + + // Use this version for checking binary node matches in case you're using flag + // kDynamicIndexingOfVectorOrMatrixInLValue. + bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere); + + bool match(TIntermAggregate *node, TIntermNode *parentNode); + bool match(TIntermTernary *node); + bool match(TIntermDeclaration *node); + + private: + const unsigned int mMask; + + bool matchInternal(TIntermBinary *node, TIntermNode *parentNode); +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_INTERMNODEPATTERNMATCHER_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp new file mode 100644 index 0000000000..224535bd8c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp @@ -0,0 +1,291 @@ +// +// Copyright (c) 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. +// +// IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly +// meant to be used in AST transforms. + +#include "compiler/translator/tree_util/IntermNode_util.h" + +#include "compiler/translator/FunctionLookup.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +const TFunction *LookUpBuiltInFunction(const char *name, + const TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const ImmutableString &mangledName = TFunctionLookup::GetMangledName(name, *arguments); + const TSymbol *symbol = symbolTable.findBuiltIn(mangledName, shaderVersion); + if (symbol) + { + ASSERT(symbol->isFunction()); + return static_cast<const TFunction *>(symbol); + } + return nullptr; +} + +} // anonymous namespace + +TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func) +{ + return new TIntermFunctionPrototype(&func); +} + +TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func, + TIntermBlock *functionBody) +{ + return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody); +} + +TIntermTyped *CreateZeroNode(const TType &type) +{ + TType constType(type); + constType.setQualifier(EvqConst); + + if (!type.isArray() && type.getBasicType() != EbtStruct) + { + size_t size = constType.getObjectSize(); + TConstantUnion *u = new TConstantUnion[size]; + for (size_t i = 0; i < size; ++i) + { + switch (type.getBasicType()) + { + case EbtFloat: + u[i].setFConst(0.0f); + break; + case EbtInt: + u[i].setIConst(0); + break; + case EbtUInt: + u[i].setUConst(0u); + break; + case EbtBool: + u[i].setBConst(false); + break; + default: + // CreateZeroNode is called by ParseContext that keeps parsing even when an + // error occurs, so it is possible for CreateZeroNode to be called with + // non-basic types. This happens only on error condition but CreateZeroNode + // needs to return a value with the correct type to continue the typecheck. + // That's why we handle non-basic type by setting whatever value, we just need + // the type to be right. + u[i].setIConst(42); + break; + } + } + + TIntermConstantUnion *node = new TIntermConstantUnion(u, constType); + return node; + } + + TIntermSequence *arguments = new TIntermSequence(); + + if (type.isArray()) + { + TType elementType(type); + elementType.toArrayElementType(); + + size_t arraySize = type.getOutermostArraySize(); + for (size_t i = 0; i < arraySize; ++i) + { + arguments->push_back(CreateZeroNode(elementType)); + } + } + else + { + ASSERT(type.getBasicType() == EbtStruct); + + const TStructure *structure = type.getStruct(); + for (const auto &field : structure->fields()) + { + arguments->push_back(CreateZeroNode(*field->type())); + } + } + + return TIntermAggregate::CreateConstructor(constType, arguments); +} + +TIntermConstantUnion *CreateIndexNode(int index) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setIConst(index); + + TType type(EbtInt, EbpUndefined, EvqConst, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + +TIntermConstantUnion *CreateBoolNode(bool value) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setBConst(value); + + TType type(EbtBool, EbpUndefined, EvqConst, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + +TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type) +{ + ASSERT(symbolTable != nullptr); + // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created + // variable. This might need to be done in other places as well. + return new TVariable(symbolTable, kEmptyImmutableString, type, SymbolType::AngleInternal); +} + +TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier) +{ + ASSERT(symbolTable != nullptr); + if (type->getQualifier() == qualifier) + { + return CreateTempVariable(symbolTable, type); + } + TType *typeWithQualifier = new TType(*type); + typeWithQualifier->setQualifier(qualifier); + return CreateTempVariable(symbolTable, typeWithQualifier); +} + +TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable) +{ + ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal); + ASSERT(tempVariable->getType().getQualifier() == EvqTemporary || + tempVariable->getType().getQualifier() == EvqConst || + tempVariable->getType().getQualifier() == EvqGlobal); + return new TIntermSymbol(tempVariable); +} + +TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable) +{ + TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); + tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable)); + return tempDeclaration; +} + +TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable, + TIntermTyped *initializer) +{ + ASSERT(initializer != nullptr); + TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable); + TIntermDeclaration *tempDeclaration = new TIntermDeclaration(); + TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer); + tempDeclaration->appendDeclarator(tempInit); + return tempDeclaration; +} + +TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode) +{ + ASSERT(rightNode != nullptr); + TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable); + return new TIntermBinary(EOpAssign, tempSymbol, rightNode); +} + +TVariable *DeclareTempVariable(TSymbolTable *symbolTable, + const TType *type, + TQualifier qualifier, + TIntermDeclaration **declarationOut) +{ + TVariable *variable = CreateTempVariable(symbolTable, type, qualifier); + *declarationOut = CreateTempDeclarationNode(variable); + return variable; +} + +TVariable *DeclareTempVariable(TSymbolTable *symbolTable, + TIntermTyped *initializer, + TQualifier qualifier, + TIntermDeclaration **declarationOut) +{ + TVariable *variable = + CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier); + *declarationOut = CreateTempInitDeclarationNode(variable, initializer); + return variable; +} + +const TVariable *DeclareInterfaceBlock(TIntermBlock *root, + TSymbolTable *symbolTable, + TFieldList *fieldList, + TQualifier qualifier, + const TMemoryQualifier &memoryQualifier, + const char *blockTypeName, + const char *blockVariableName) +{ + // Define an interface block. + TLayoutQualifier layoutQualifier = TLayoutQualifier::Create(); + TInterfaceBlock *interfaceBlock = + new TInterfaceBlock(symbolTable, ImmutableString(blockTypeName), fieldList, layoutQualifier, + SymbolType::AngleInternal); + + // Turn the inteface block into a declaration. + TType *interfaceBlockType = new TType(interfaceBlock, qualifier, layoutQualifier); + interfaceBlockType->setMemoryQualifier(memoryQualifier); + + TIntermDeclaration *interfaceBlockDecl = new TIntermDeclaration; + TVariable *interfaceBlockVar = new TVariable(symbolTable, ImmutableString(blockVariableName), + interfaceBlockType, SymbolType::AngleInternal); + TIntermSymbol *interfaceBlockDeclarator = new TIntermSymbol(interfaceBlockVar); + interfaceBlockDecl->appendDeclarator(interfaceBlockDeclarator); + + // Insert the declarations before the first function. + TIntermSequence *insertSequence = new TIntermSequence; + insertSequence->push_back(interfaceBlockDecl); + + size_t firstFunctionIndex = FindFirstFunctionDefinitionIndex(root); + root->insertChildNodes(firstFunctionIndex, *insertSequence); + + return interfaceBlockVar; +} + +TIntermBlock *EnsureBlock(TIntermNode *node) +{ + if (node == nullptr) + return nullptr; + TIntermBlock *blockNode = node->getAsBlock(); + if (blockNode != nullptr) + return blockNode; + + blockNode = new TIntermBlock(); + blockNode->setLine(node->getLine()); + blockNode->appendStatement(node); + return blockNode; +} + +TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable) +{ + const TVariable *var = static_cast<const TVariable *>(symbolTable.findGlobal(name)); + ASSERT(var); + return new TIntermSymbol(var); +} + +TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const TVariable *var = + static_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion)); + ASSERT(var); + return new TIntermSymbol(var); +} + +TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, + TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion); + ASSERT(fn); + TOperator op = fn->getBuiltInOp(); + if (op != EOpCallBuiltInFunction && arguments->size() == 1) + { + return new TIntermUnary(op, arguments->at(0)->getAsTyped(), fn); + } + return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h new file mode 100644 index 0000000000..3a82ec07a7 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h @@ -0,0 +1,76 @@ +// +// Copyright (c) 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. +// +// IntermNode_util.h: High-level utilities for creating AST nodes and node hierarchies. Mostly meant +// to be used in AST transforms. + +#ifndef COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ +#define COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/FindFunction.h" + +namespace sh +{ + +class TSymbolTable; +class TVariable; + +TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func); +TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func, + TIntermBlock *functionBody); + +TIntermTyped *CreateZeroNode(const TType &type); +TIntermConstantUnion *CreateIndexNode(int index); +TIntermConstantUnion *CreateBoolNode(bool value); + +TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type); +TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier); + +TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable); +TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable); +TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable, + TIntermTyped *initializer); +TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode); + +TVariable *DeclareTempVariable(TSymbolTable *symbolTable, + const TType *type, + TQualifier qualifier, + TIntermDeclaration **declarationOut); +TVariable *DeclareTempVariable(TSymbolTable *symbolTable, + TIntermTyped *initializer, + TQualifier qualifier, + TIntermDeclaration **declarationOut); +const TVariable *DeclareInterfaceBlock(TIntermBlock *root, + TSymbolTable *symbolTable, + TFieldList *fieldList, + TQualifier qualifier, + const TMemoryQualifier &memoryQualifier, + const char *blockTypeName, + const char *blockVariableName); + +// If the input node is nullptr, return nullptr. +// If the input node is a block node, return it. +// If the input node is not a block node, put it inside a block node and return that. +TIntermBlock *EnsureBlock(TIntermNode *node); + +// Should be called from inside Compiler::compileTreeImpl() where the global level is in scope. +TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, + const TSymbolTable &symbolTable); + +// Note: this can't access desktop GLSL built-ins. Those can only be accessed directly through +// BuiltIn_autogen.h. +TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name, + const TSymbolTable &symbolTable, + int shaderVersion); + +TIntermTyped *CreateBuiltInFunctionCallNode(const char *name, + TIntermSequence *arguments, + const TSymbolTable &symbolTable, + int shaderVersion); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_INTERMNODEUTIL_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp new file mode 100644 index 0000000000..c38baa12bf --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp @@ -0,0 +1,638 @@ +// +// Copyright (c) 2002-2010 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_util/IntermTraverse.h" + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" + +namespace sh +{ + +// Traverse the intermediate representation tree, and call a node type specific visit function for +// each node. Traversal is done recursively through the node member function traverse(). Nodes with +// children can have their whole subtree skipped if preVisit is turned on and the type specific +// function returns false. +template <typename T> +void TIntermTraverser::traverse(T *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + if (!addToPath.isWithinDepthLimit()) + return; + + bool visit = true; + + // Visit the node before children if pre-visiting. + if (preVisit) + visit = node->visit(PreVisit, this); + + if (visit) + { + size_t childIndex = 0; + size_t childCount = node->getChildCount(); + + while (childIndex < childCount && visit) + { + node->getChildNode(childIndex)->traverse(this); + if (inVisit && childIndex != childCount - 1) + { + visit = node->visit(InVisit, this); + } + ++childIndex; + } + + if (visit && postVisit) + node->visit(PostVisit, this); + } +} + +void TIntermNode::traverse(TIntermTraverser *it) +{ + it->traverse(this); +} + +void TIntermSymbol::traverse(TIntermTraverser *it) +{ + TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); + it->visitSymbol(this); +} + +void TIntermConstantUnion::traverse(TIntermTraverser *it) +{ + TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); + it->visitConstantUnion(this); +} + +void TIntermFunctionPrototype::traverse(TIntermTraverser *it) +{ + TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); + it->visitFunctionPrototype(this); +} + +void TIntermBinary::traverse(TIntermTraverser *it) +{ + it->traverseBinary(this); +} + +void TIntermUnary::traverse(TIntermTraverser *it) +{ + it->traverseUnary(this); +} + +void TIntermFunctionDefinition::traverse(TIntermTraverser *it) +{ + it->traverseFunctionDefinition(this); +} + +void TIntermBlock::traverse(TIntermTraverser *it) +{ + it->traverseBlock(this); +} + +void TIntermAggregate::traverse(TIntermTraverser *it) +{ + it->traverseAggregate(this); +} + +void TIntermLoop::traverse(TIntermTraverser *it) +{ + it->traverseLoop(this); +} + +void TIntermPreprocessorDirective::traverse(TIntermTraverser *it) +{ + it->visitPreprocessorDirective(this); +} + +bool TIntermSymbol::visit(Visit visit, TIntermTraverser *it) +{ + it->visitSymbol(this); + return false; +} + +bool TIntermConstantUnion::visit(Visit visit, TIntermTraverser *it) +{ + it->visitConstantUnion(this); + return false; +} + +bool TIntermFunctionPrototype::visit(Visit visit, TIntermTraverser *it) +{ + it->visitFunctionPrototype(this); + return false; +} + +bool TIntermFunctionDefinition::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitFunctionDefinition(visit, this); +} + +bool TIntermUnary::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitUnary(visit, this); +} + +bool TIntermSwizzle::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitSwizzle(visit, this); +} + +bool TIntermBinary::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitBinary(visit, this); +} + +bool TIntermTernary::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitTernary(visit, this); +} + +bool TIntermAggregate::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitAggregate(visit, this); +} + +bool TIntermDeclaration::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitDeclaration(visit, this); +} + +bool TIntermInvariantDeclaration::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitInvariantDeclaration(visit, this); +} + +bool TIntermBlock::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitBlock(visit, this); +} + +bool TIntermIfElse::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitIfElse(visit, this); +} + +bool TIntermLoop::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitLoop(visit, this); +} + +bool TIntermBranch::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitBranch(visit, this); +} + +bool TIntermSwitch::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitSwitch(visit, this); +} + +bool TIntermCase::visit(Visit visit, TIntermTraverser *it) +{ + return it->visitCase(visit, this); +} + +bool TIntermPreprocessorDirective::visit(Visit visit, TIntermTraverser *it) +{ + it->visitPreprocessorDirective(this); + return false; +} + +TIntermTraverser::TIntermTraverser(bool preVisit, + bool inVisit, + bool postVisit, + TSymbolTable *symbolTable) + : preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + mMaxDepth(0), + mMaxAllowedDepth(std::numeric_limits<int>::max()), + mInGlobalScope(true), + mSymbolTable(symbolTable) +{ + // Only enabling inVisit is not supported. + ASSERT(!(inVisit && !preVisit && !postVisit)); +} + +TIntermTraverser::~TIntermTraverser() {} + +void TIntermTraverser::setMaxAllowedDepth(int depth) +{ + mMaxAllowedDepth = depth; +} + +const TIntermBlock *TIntermTraverser::getParentBlock() const +{ + if (!mParentBlockStack.empty()) + { + return mParentBlockStack.back().node; + } + return nullptr; +} + +void TIntermTraverser::pushParentBlock(TIntermBlock *node) +{ + mParentBlockStack.push_back(ParentBlock(node, 0)); +} + +void TIntermTraverser::incrementParentBlockPos() +{ + ++mParentBlockStack.back().pos; +} + +void TIntermTraverser::popParentBlock() +{ + ASSERT(!mParentBlockStack.empty()); + mParentBlockStack.pop_back(); +} + +void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions) +{ + TIntermSequence emptyInsertionsAfter; + insertStatementsInParentBlock(insertions, emptyInsertionsAfter); +} + +void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore, + const TIntermSequence &insertionsAfter) +{ + ASSERT(!mParentBlockStack.empty()); + ParentBlock &parentBlock = mParentBlockStack.back(); + if (mPath.back() == parentBlock.node) + { + ASSERT(mParentBlockStack.size() >= 2u); + // The current node is a block node, so the parent block is not the topmost one in the block + // stack, but the one below that. + parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u); + } + NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore, + insertionsAfter); + mInsertions.push_back(insert); +} + +void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement) +{ + TIntermSequence insertions; + insertions.push_back(statement); + insertStatementsInParentBlock(insertions); +} + +void TIntermTraverser::insertStatementsInBlockAtPosition(TIntermBlock *parent, + size_t position, + const TIntermSequence &insertionsBefore, + const TIntermSequence &insertionsAfter) +{ + ASSERT(parent); + ASSERT(position >= 0); + ASSERT(position < parent->getChildCount()); + + mInsertions.emplace_back(parent, position, insertionsBefore, insertionsAfter); +} + +void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter) +{ + mInFunctionCallOutParameter = inOutParameter; +} + +bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const +{ + return mInFunctionCallOutParameter; +} + +void TIntermTraverser::traverseBinary(TIntermBinary *node) +{ + traverse(node); +} + +void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + if (!addToPath.isWithinDepthLimit()) + return; + + bool visit = true; + + // visit the node before children if pre-visiting. + if (preVisit) + visit = node->visit(PreVisit, this); + + // Visit the children, in the right order. + if (visit) + { + if (node->isAssignment()) + { + ASSERT(!isLValueRequiredHere()); + setOperatorRequiresLValue(true); + } + + node->getLeft()->traverse(this); + + if (node->isAssignment()) + setOperatorRequiresLValue(false); + + if (inVisit) + visit = node->visit(InVisit, this); + + if (visit) + { + // Some binary operations like indexing can be inside an expression which must be an + // l-value. + bool parentOperatorRequiresLValue = operatorRequiresLValue(); + bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter(); + + // Index is not required to be an l-value even when the surrounding expression is + // required to be an l-value. + TOperator op = node->getOp(); + if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock || + op == EOpIndexDirectStruct || op == EOpIndexIndirect) + { + setOperatorRequiresLValue(false); + setInFunctionCallOutParameter(false); + } + + node->getRight()->traverse(this); + + setOperatorRequiresLValue(parentOperatorRequiresLValue); + setInFunctionCallOutParameter(parentInFunctionCallOutParameter); + + // Visit the node after the children, if requested and the traversal + // hasn't been cancelled yet. + if (postVisit) + visit = node->visit(PostVisit, this); + } + } +} + +void TIntermTraverser::traverseUnary(TIntermUnary *node) +{ + traverse(node); +} + +void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + if (!addToPath.isWithinDepthLimit()) + return; + + bool visit = true; + + if (preVisit) + visit = node->visit(PreVisit, this); + + if (visit) + { + ASSERT(!operatorRequiresLValue()); + switch (node->getOp()) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + setOperatorRequiresLValue(true); + break; + default: + break; + } + + node->getOperand()->traverse(this); + + setOperatorRequiresLValue(false); + + if (postVisit) + visit = node->visit(PostVisit, this); + } +} + +// Traverse a function definition node. This keeps track of global scope. +void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + if (!addToPath.isWithinDepthLimit()) + return; + + bool visit = true; + + if (preVisit) + visit = node->visit(PreVisit, this); + + if (visit) + { + node->getFunctionPrototype()->traverse(this); + if (inVisit) + visit = node->visit(InVisit, this); + if (visit) + { + mInGlobalScope = false; + node->getBody()->traverse(this); + mInGlobalScope = true; + if (postVisit) + visit = node->visit(PostVisit, this); + } + } +} + +// Traverse a block node. This keeps track of the position of traversed child nodes within the block +// so that nodes may be inserted before or after them. +void TIntermTraverser::traverseBlock(TIntermBlock *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + if (!addToPath.isWithinDepthLimit()) + return; + + pushParentBlock(node); + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + + if (preVisit) + visit = node->visit(PreVisit, this); + + if (visit) + { + for (auto *child : *sequence) + { + if (visit) + { + child->traverse(this); + if (inVisit) + { + if (child != sequence->back()) + visit = node->visit(InVisit, this); + } + + incrementParentBlockPos(); + } + } + + if (visit && postVisit) + visit = node->visit(PostVisit, this); + } + + popParentBlock(); +} + +void TIntermTraverser::traverseAggregate(TIntermAggregate *node) +{ + traverse(node); +} + +bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a, + const NodeInsertMultipleEntry &b) +{ + if (a.parent != b.parent) + { + return a.parent > b.parent; + } + return a.position > b.position; +} + +void TIntermTraverser::updateTree() +{ + // Sort the insertions so that insertion position is decreasing. This way multiple insertions to + // the same parent node are handled correctly. + std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion); + for (size_t ii = 0; ii < mInsertions.size(); ++ii) + { + // We can't know here what the intended ordering of two insertions to the same position is, + // so it is not supported. + ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position || + mInsertions[ii].parent != mInsertions[ii - 1].parent); + const NodeInsertMultipleEntry &insertion = mInsertions[ii]; + ASSERT(insertion.parent); + if (!insertion.insertionsAfter.empty()) + { + bool inserted = insertion.parent->insertChildNodes(insertion.position + 1, + insertion.insertionsAfter); + ASSERT(inserted); + } + if (!insertion.insertionsBefore.empty()) + { + bool inserted = + insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore); + ASSERT(inserted); + } + } + for (size_t ii = 0; ii < mReplacements.size(); ++ii) + { + const NodeUpdateEntry &replacement = mReplacements[ii]; + ASSERT(replacement.parent); + bool replaced = + replacement.parent->replaceChildNode(replacement.original, replacement.replacement); + ASSERT(replaced); + + if (!replacement.originalBecomesChildOfReplacement) + { + // In AST traversing, a parent is visited before its children. + // After we replace a node, if its immediate child is to + // be replaced, we need to make sure we don't update the replaced + // node; instead, we update the replacement node. + for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj) + { + NodeUpdateEntry &replacement2 = mReplacements[jj]; + if (replacement2.parent == replacement.original) + replacement2.parent = replacement.replacement; + } + } + } + for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii) + { + const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii]; + ASSERT(replacement.parent); + bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original, + replacement.replacements); + ASSERT(replaced); + } + + clearReplacementQueue(); +} + +void TIntermTraverser::clearReplacementQueue() +{ + mReplacements.clear(); + mMultiReplacements.clear(); + mInsertions.clear(); +} + +void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus) +{ + queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus); +} + +void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent, + TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus) +{ + bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD); + mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild)); +} + +TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit, + bool inVisit, + bool postVisit, + TSymbolTable *symbolTable) + : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable), + mOperatorRequiresLValue(false), + mInFunctionCallOutParameter(false) +{ + ASSERT(symbolTable); +} + +void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) +{ + ScopedNodeInTraversalPath addToPath(this, node); + if (!addToPath.isWithinDepthLimit()) + return; + + bool visit = true; + + TIntermSequence *sequence = node->getSequence(); + + if (preVisit) + visit = node->visit(PreVisit, this); + + if (visit) + { + size_t paramIndex = 0u; + for (auto *child : *sequence) + { + if (visit) + { + if (node->getFunction()) + { + // Both built-ins and user defined functions should have the function symbol + // set. + ASSERT(paramIndex < node->getFunction()->getParamCount()); + TQualifier qualifier = + node->getFunction()->getParam(paramIndex)->getType().getQualifier(); + setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut); + ++paramIndex; + } + else + { + ASSERT(node->isConstructor()); + } + child->traverse(this); + if (inVisit) + { + if (child != sequence->back()) + visit = node->visit(InVisit, this); + } + } + } + setInFunctionCallOutParameter(false); + + if (visit && postVisit) + visit = node->visit(PostVisit, this); + } +} + +void TIntermTraverser::traverseLoop(TIntermLoop *node) +{ + traverse(node); +} +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h new file mode 100644 index 0000000000..30687a4869 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h @@ -0,0 +1,322 @@ +// +// Copyright (c) 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. +// +// IntermTraverse.h : base classes for AST traversers that walk the AST and +// also have the ability to transform it by replacing nodes. + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_INTERMTRAVERSE_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_INTERMTRAVERSE_H_ + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/Visit.h" + +namespace sh +{ + +class TSymbolTable; +class TSymbolUniqueId; + +// For traversing the tree. User should derive from this class overriding the visit functions, +// and then pass an object of the subclass to a traverse method of a node. +// +// The traverse*() functions may also be overridden to do other bookkeeping on the tree to provide +// contextual information to the visit functions, such as whether the node is the target of an +// assignment. This is complex to maintain and so should only be done in special cases. +// +// When using this, just fill in the methods for nodes you want visited. +// Return false from a pre-visit to skip visiting that node's subtree. +// +// See also how to write AST transformations documentation: +// https://github.com/google/angle/blob/master/doc/WritingShaderASTTransformations.md +class TIntermTraverser : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE + TIntermTraverser(bool preVisit, + bool inVisit, + bool postVisit, + TSymbolTable *symbolTable = nullptr); + virtual ~TIntermTraverser(); + + virtual void visitSymbol(TIntermSymbol *node) {} + virtual void visitConstantUnion(TIntermConstantUnion *node) {} + virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; } + virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; } + virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; } + virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; } + virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; } + virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; } + virtual bool visitCase(Visit visit, TIntermCase *node) { return true; } + virtual void visitFunctionPrototype(TIntermFunctionPrototype *node) {} + virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) + { + return true; + } + virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; } + virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; } + virtual bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) + { + return true; + } + virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; } + virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; } + virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; } + virtual void visitPreprocessorDirective(TIntermPreprocessorDirective *node) {} + + // The traverse functions contain logic for iterating over the children of the node + // and calling the visit functions in the appropriate places. They also track some + // context that may be used by the visit functions. + + // The generic traverse() function is used for nodes that don't need special handling. + // It's templated in order to avoid virtual function calls, this gains around 2% compiler + // performance. + template <typename T> + void traverse(T *node); + + // Specialized traverse functions are implemented for node types where traversal logic may need + // to be overridden or where some special bookkeeping needs to be done. + virtual void traverseBinary(TIntermBinary *node); + virtual void traverseUnary(TIntermUnary *node); + virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node); + virtual void traverseAggregate(TIntermAggregate *node); + virtual void traverseBlock(TIntermBlock *node); + virtual void traverseLoop(TIntermLoop *node); + + int getMaxDepth() const { return mMaxDepth; } + + // If traversers need to replace nodes, they can add the replacements in + // mReplacements/mMultiReplacements during traversal and the user of the traverser should call + // this function after traversal to perform them. + void updateTree(); + + protected: + void setMaxAllowedDepth(int depth); + + // Should only be called from traverse*() functions + bool incrementDepth(TIntermNode *current) + { + mMaxDepth = std::max(mMaxDepth, static_cast<int>(mPath.size())); + mPath.push_back(current); + return mMaxDepth < mMaxAllowedDepth; + } + + // Should only be called from traverse*() functions + void decrementDepth() { mPath.pop_back(); } + + int getCurrentTraversalDepth() const { return static_cast<int>(mPath.size()) - 1; } + + // RAII helper for incrementDepth/decrementDepth + class ScopedNodeInTraversalPath + { + public: + ScopedNodeInTraversalPath(TIntermTraverser *traverser, TIntermNode *current) + : mTraverser(traverser) + { + mWithinDepthLimit = mTraverser->incrementDepth(current); + } + ~ScopedNodeInTraversalPath() { mTraverser->decrementDepth(); } + + bool isWithinDepthLimit() { return mWithinDepthLimit; } + + private: + TIntermTraverser *mTraverser; + bool mWithinDepthLimit; + }; + // Optimized traversal functions for leaf nodes directly access ScopedNodeInTraversalPath. + friend void TIntermSymbol::traverse(TIntermTraverser *); + friend void TIntermConstantUnion::traverse(TIntermTraverser *); + friend void TIntermFunctionPrototype::traverse(TIntermTraverser *); + + TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; } + + // Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode() + TIntermNode *getAncestorNode(unsigned int n) + { + if (mPath.size() > n + 1u) + { + return mPath[mPath.size() - n - 2u]; + } + return nullptr; + } + + const TIntermBlock *getParentBlock() const; + + void pushParentBlock(TIntermBlock *node); + void incrementParentBlockPos(); + void popParentBlock(); + + // To replace a single node with multiple nodes in the parent aggregate. May be used with blocks + // but also with other nodes like declarations. + struct NodeReplaceWithMultipleEntry + { + NodeReplaceWithMultipleEntry(TIntermAggregateBase *parentIn, + TIntermNode *originalIn, + TIntermSequence replacementsIn) + : parent(parentIn), original(originalIn), replacements(std::move(replacementsIn)) + {} + + TIntermAggregateBase *parent; + TIntermNode *original; + TIntermSequence replacements; + }; + + // Helper to insert statements in the parent block of the node currently being traversed. + // The statements will be inserted before the node being traversed once updateTree is called. + // Should only be called during PreVisit or PostVisit if called from block nodes. + // Note that two insertions to the same position in the same block are not supported. + void insertStatementsInParentBlock(const TIntermSequence &insertions); + + // Same as above, but supports simultaneous insertion of statements before and after the node + // currently being traversed. + void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore, + const TIntermSequence &insertionsAfter); + + // Helper to insert a single statement. + void insertStatementInParentBlock(TIntermNode *statement); + + // Explicitly specify where to insert statements. The statements are inserted before and after + // the specified position. The statements will be inserted once updateTree is called. Note that + // two insertions to the same position in the same block are not supported. + void insertStatementsInBlockAtPosition(TIntermBlock *parent, + size_t position, + const TIntermSequence &insertionsBefore, + const TIntermSequence &insertionsAfter); + + enum class OriginalNode + { + BECOMES_CHILD, + IS_DROPPED + }; + + void clearReplacementQueue(); + + // Replace the node currently being visited with replacement. + void queueReplacement(TIntermNode *replacement, OriginalNode originalStatus); + // Explicitly specify a node to replace with replacement. + void queueReplacementWithParent(TIntermNode *parent, + TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus); + + const bool preVisit; + const bool inVisit; + const bool postVisit; + + int mMaxDepth; + int mMaxAllowedDepth; + + bool mInGlobalScope; + + // During traversing, save all the changes that need to happen into + // mReplacements/mMultiReplacements, then do them by calling updateTree(). + // Multi replacements are processed after single replacements. + std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements; + + TSymbolTable *mSymbolTable; + + private: + // To insert multiple nodes into the parent block. + struct NodeInsertMultipleEntry + { + NodeInsertMultipleEntry(TIntermBlock *_parent, + TIntermSequence::size_type _position, + TIntermSequence _insertionsBefore, + TIntermSequence _insertionsAfter) + : parent(_parent), + position(_position), + insertionsBefore(_insertionsBefore), + insertionsAfter(_insertionsAfter) + {} + + TIntermBlock *parent; + TIntermSequence::size_type position; + TIntermSequence insertionsBefore; + TIntermSequence insertionsAfter; + }; + + static bool CompareInsertion(const NodeInsertMultipleEntry &a, + const NodeInsertMultipleEntry &b); + + // To replace a single node with another on the parent node + struct NodeUpdateEntry + { + NodeUpdateEntry(TIntermNode *_parent, + TIntermNode *_original, + TIntermNode *_replacement, + bool _originalBecomesChildOfReplacement) + : parent(_parent), + original(_original), + replacement(_replacement), + originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) + {} + + TIntermNode *parent; + TIntermNode *original; + TIntermNode *replacement; + bool originalBecomesChildOfReplacement; + }; + + struct ParentBlock + { + ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn) + : node(nodeIn), pos(posIn) + {} + + TIntermBlock *node; + TIntermSequence::size_type pos; + }; + + std::vector<NodeInsertMultipleEntry> mInsertions; + std::vector<NodeUpdateEntry> mReplacements; + + // All the nodes from root to the current node during traversing. + TVector<TIntermNode *> mPath; + + // All the code blocks from the root to the current node's parent during traversal. + std::vector<ParentBlock> mParentBlockStack; +}; + +// Traverser parent class that tracks where a node is a destination of a write operation and so is +// required to be an l-value. +class TLValueTrackingTraverser : public TIntermTraverser +{ + public: + TLValueTrackingTraverser(bool preVisit, + bool inVisit, + bool postVisit, + TSymbolTable *symbolTable); + virtual ~TLValueTrackingTraverser() {} + + void traverseBinary(TIntermBinary *node) final; + void traverseUnary(TIntermUnary *node) final; + void traverseAggregate(TIntermAggregate *node) final; + + protected: + bool isLValueRequiredHere() const + { + return mOperatorRequiresLValue || mInFunctionCallOutParameter; + } + + private: + // Track whether an l-value is required in the node that is currently being traversed by the + // surrounding operator. + // Use isLValueRequiredHere to check all conditions which require an l-value. + void setOperatorRequiresLValue(bool lValueRequired) + { + mOperatorRequiresLValue = lValueRequired; + } + bool operatorRequiresLValue() const { return mOperatorRequiresLValue; } + + // Track whether an l-value is required inside a function call. + void setInFunctionCallOutParameter(bool inOutParameter); + bool isInFunctionCallOutParameter() const; + + bool mOperatorRequiresLValue; + bool mInFunctionCallOutParameter; +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_INTERMTRAVERSE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h b/gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h new file mode 100644 index 0000000000..c083531578 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2013 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. +// +// NodeSearch.h: Utilities for searching translator node graphs +// + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_NODESEARCH_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_NODESEARCH_H_ + +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +template <class Parent> +class NodeSearchTraverser : public TIntermTraverser +{ + public: + NodeSearchTraverser() : TIntermTraverser(true, false, false), mFound(false) {} + + bool found() const { return mFound; } + + static bool search(TIntermNode *node) + { + Parent searchTraverser; + node->traverse(&searchTraverser); + return searchTraverser.found(); + } + + protected: + bool mFound; +}; + +class FindDiscard : public NodeSearchTraverser<FindDiscard> +{ + public: + virtual bool visitBranch(Visit visit, TIntermBranch *node) + { + switch (node->getFlowOp()) + { + case EOpKill: + mFound = true; + break; + + default: + break; + } + + return !mFound; + } +}; +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_NODESEARCH_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp new file mode 100644 index 0000000000..14f6f7db98 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp @@ -0,0 +1,136 @@ +// +// 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. +// +// ReplaceShadowingVariables.cpp: Replace all references to any variable in the AST that is +// a redefinition of a variable in a nested scope. This is a useful for ESSL 1.00 shaders +// where the spec section "4.2.3. Redeclaring Variables" states "However, a nested scope can +// override an outer scope's declaration of a particular variable name." This is changed in +// later spec versions, such as ESSL 3.20 spec which states "If [a variable] is declared as +// a parameter in a function definition, it is scoped until the end of that function +// definition. A function's parameter declarations and body together form a single scope." +// +// So this class is useful when translating from ESSL 1.00 shaders, where function body var +// redefinition is allowed, to later shader versions where it's not allowed. +// + +#include "compiler/translator/tree_util/ReplaceShadowingVariables.h" +#include "compiler/translator/tree_util/ReplaceVariable.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Symbol.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +#include <unordered_set> + +namespace sh +{ + +namespace +{ + +// Custom struct to queue up any replacements until after AST traversal +struct DeferredReplacementBlock +{ + const TVariable *originalVariable; // variable to be replaced + TVariable *replacementVariable; // variable to replace originalVar with + TIntermBlock *functionBody; // function body where replacement occurs +}; + +class ReplaceShadowingVariablesTraverser : public TIntermTraverser +{ + public: + ReplaceShadowingVariablesTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, true, true), + mSymbolTable(symbolTable), + mParameterNames{}, + mFunctionBody(nullptr) + {} + + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override + { + // In pre-visit of function, record params + if (visit == PreVisit) + { + ASSERT(mParameterNames.size() == 0); + const TFunction *func = node->getFunctionPrototype()->getFunction(); + // Grab all of the parameter names from the function prototype + uint32_t paramCount = func->getParamCount(); + for (uint32_t i = 0; i < paramCount; ++i) + { + mParameterNames.emplace(std::string(func->getParam(i)->name().data())); + } + if (mParameterNames.size() > 0) + mFunctionBody = node->getBody(); + } + else if (visit == PostVisit) + { + // Clear data saved from function definition + mParameterNames.clear(); + mFunctionBody = nullptr; + } + return true; + } + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override + { + if (visit == PreVisit && mParameterNames.size() != 0) + { + TIntermSequence *decls = node->getSequence(); + for (auto &declVector : *decls) + { + // no init case + TIntermSymbol *symNode = declVector->getAsSymbolNode(); + if (symNode == nullptr) + { + // init case + TIntermBinary *binaryNode = declVector->getAsBinaryNode(); + ASSERT(binaryNode->getOp() == EOpInitialize); + symNode = binaryNode->getLeft()->getAsSymbolNode(); + } + ASSERT(symNode != nullptr); + std::string varName = std::string(symNode->variable().name().data()); + if (mParameterNames.count(varName) > 0) + { + // We found a redefined var so queue replacement + mReplacements.emplace_back(DeferredReplacementBlock{ + &symNode->variable(), + CreateTempVariable(mSymbolTable, &symNode->variable().getType()), + mFunctionBody}); + } + } + } + return true; + } + // Perform replacement of vars for any deferred replacements that were identified + void executeReplacements() + { + for (DeferredReplacementBlock &replace : mReplacements) + { + ReplaceVariable(replace.functionBody, replace.originalVariable, + replace.replacementVariable); + } + mReplacements.clear(); + } + + private: + TSymbolTable *mSymbolTable; + std::unordered_set<std::string> mParameterNames; + TIntermBlock *mFunctionBody; + std::vector<DeferredReplacementBlock> mReplacements; +}; + +} // anonymous namespace + +// Replaces every occurrence of a variable with another variable. +void ReplaceShadowingVariables(TIntermBlock *root, TSymbolTable *symbolTable) +{ + ReplaceShadowingVariablesTraverser traverser(symbolTable); + root->traverse(&traverser); + traverser.executeReplacements(); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.h b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.h new file mode 100644 index 0000000000..79e2694d53 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.h @@ -0,0 +1,21 @@ +// +// 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. +// +// ReplaceShadowingVariables.h: Find any variables that are redefined within a nested +// scope and replace them with a newly named variable. + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_REPLACESHADOWINGVARIABLES_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_REPLACESHADOWINGVARIABLES_H_ + +namespace sh +{ + +class TIntermBlock; +class TSymbolTable; + +void ReplaceShadowingVariables(TIntermBlock *root, TSymbolTable *symbolTable); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_REPLACESHADOWINGVARIABLES_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp new file mode 100644 index 0000000000..7120cea20b --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 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. +// +// ReplaceVariable.cpp: Replace all references to a specific variable in the AST with references to +// another variable. + +#include "compiler/translator/tree_util/ReplaceVariable.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +class ReplaceVariableTraverser : public TIntermTraverser +{ + public: + ReplaceVariableTraverser(const TVariable *toBeReplaced, const TIntermTyped *replacement) + : TIntermTraverser(true, false, false), + mToBeReplaced(toBeReplaced), + mReplacement(replacement) + {} + + void visitSymbol(TIntermSymbol *node) override + { + if (&node->variable() == mToBeReplaced) + { + queueReplacement(mReplacement->deepCopy(), OriginalNode::IS_DROPPED); + } + } + + private: + const TVariable *const mToBeReplaced; + const TIntermTyped *const mReplacement; +}; + +} // anonymous namespace + +// Replaces every occurrence of a variable with another variable. +void ReplaceVariable(TIntermBlock *root, + const TVariable *toBeReplaced, + const TVariable *replacement) +{ + ReplaceVariableTraverser traverser(toBeReplaced, new TIntermSymbol(replacement)); + root->traverse(&traverser); + traverser.updateTree(); +} + +// Replaces every occurrence of a variable with a TIntermNode. +void ReplaceVariableWithTyped(TIntermBlock *root, + const TVariable *toBeReplaced, + const TIntermTyped *replacement) +{ + ReplaceVariableTraverser traverser(toBeReplaced, replacement); + root->traverse(&traverser); + traverser.updateTree(); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h new file mode 100644 index 0000000000..3a9e34ee34 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 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. +// +// ReplaceVariable.h: Replace all references to a specific variable in the AST with references to +// another variable. + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_ + +namespace sh +{ + +class TIntermBlock; +class TVariable; +class TIntermTyped; + +void ReplaceVariable(TIntermBlock *root, + const TVariable *toBeReplaced, + const TVariable *replacement); +void ReplaceVariableWithTyped(TIntermBlock *root, + const TVariable *toBeReplaced, + const TIntermTyped *replacement); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_REPLACEVARIABLE_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp new file mode 100644 index 0000000000..bd00b8a0d9 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp @@ -0,0 +1,116 @@ +// +// Copyright (c) 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. +// +// RunAtTheEndOfShader.cpp: Add code to be run at the end of the shader. In case main() contains a +// return statement, this is done by replacing the main() function with another function that calls +// the old main, like this: +// +// void main() { body } +// => +// void main0() { body } +// void main() +// { +// main0(); +// codeToRun +// } +// +// This way the code will get run even if the return statement inside main is executed. +// + +#include "compiler/translator/tree_util/RunAtTheEndOfShader.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/StaticType.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/FindMain.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +namespace sh +{ + +namespace +{ + +constexpr const ImmutableString kMainString("main"); + +class ContainsReturnTraverser : public TIntermTraverser +{ + public: + ContainsReturnTraverser() : TIntermTraverser(true, false, false), mContainsReturn(false) {} + + bool visitBranch(Visit visit, TIntermBranch *node) override + { + if (node->getFlowOp() == EOpReturn) + { + mContainsReturn = true; + } + return false; + } + + bool containsReturn() { return mContainsReturn; } + + private: + bool mContainsReturn; +}; + +bool ContainsReturn(TIntermNode *node) +{ + ContainsReturnTraverser traverser; + node->traverse(&traverser); + return traverser.containsReturn(); +} + +void WrapMainAndAppend(TIntermBlock *root, + TIntermFunctionDefinition *main, + TIntermNode *codeToRun, + TSymbolTable *symbolTable) +{ + // Replace main() with main0() with the same body. + TFunction *oldMain = + new TFunction(symbolTable, kEmptyImmutableString, SymbolType::AngleInternal, + StaticType::GetBasic<EbtVoid>(), false); + TIntermFunctionDefinition *oldMainDefinition = + CreateInternalFunctionDefinitionNode(*oldMain, main->getBody()); + + bool replaced = root->replaceChildNode(main, oldMainDefinition); + ASSERT(replaced); + + // void main() + TFunction *newMain = new TFunction(symbolTable, kMainString, SymbolType::UserDefined, + StaticType::GetBasic<EbtVoid>(), false); + TIntermFunctionPrototype *newMainProto = new TIntermFunctionPrototype(newMain); + + // { + // main0(); + // codeToRun + // } + TIntermBlock *newMainBody = new TIntermBlock(); + TIntermAggregate *oldMainCall = + TIntermAggregate::CreateFunctionCall(*oldMain, new TIntermSequence()); + newMainBody->appendStatement(oldMainCall); + newMainBody->appendStatement(codeToRun); + + // Add the new main() to the root node. + TIntermFunctionDefinition *newMainDefinition = + new TIntermFunctionDefinition(newMainProto, newMainBody); + root->appendStatement(newMainDefinition); +} + +} // anonymous namespace + +void RunAtTheEndOfShader(TIntermBlock *root, TIntermNode *codeToRun, TSymbolTable *symbolTable) +{ + TIntermFunctionDefinition *main = FindMain(root); + if (!ContainsReturn(main)) + { + main->getBody()->appendStatement(codeToRun); + return; + } + + WrapMainAndAppend(root, main, codeToRun, symbolTable); +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h new file mode 100644 index 0000000000..ed5a0bb64f --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 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. +// +// RunAtTheEndOfShader.h: Add code to be run at the end of the shader. +// + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEENDOFSHADER_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEENDOFSHADER_H_ + +namespace sh +{ + +class TIntermBlock; +class TIntermNode; +class TSymbolTable; + +void RunAtTheEndOfShader(TIntermBlock *root, TIntermNode *codeToRun, TSymbolTable *symbolTable); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_RUNATTHEENDOFSHADER_H_
\ No newline at end of file diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/Visit.h b/gfx/angle/checkout/src/compiler/translator/tree_util/Visit.h new file mode 100644 index 0000000000..2b22fbdf86 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/Visit.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 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. +// + +#ifndef COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_ +#define COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_ + +namespace sh +{ + +enum Visit +{ + PreVisit, + InVisit, + PostVisit +}; + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_TREEUTIL_VISIT_H_ diff --git a/gfx/angle/checkout/src/compiler/translator/util.cpp b/gfx/angle/checkout/src/compiler/translator/util.cpp new file mode 100644 index 0000000000..7781c1bc7c --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/util.cpp @@ -0,0 +1,936 @@ +// +// Copyright (c) 2010 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/util.h" + +#include <limits> + +#include "common/utilities.h" +#include "compiler/preprocessor/numeric_lex.h" +#include "compiler/translator/ImmutableStringBuilder.h" +#include "compiler/translator/SymbolTable.h" + +bool atoi_clamp(const char *str, unsigned int *value) +{ + bool success = angle::pp::numeric_lex_int(str, value); + if (!success) + *value = std::numeric_limits<unsigned int>::max(); + return success; +} + +namespace sh +{ + +namespace +{ + +bool IsInterpolationIn(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqSmoothIn: + case EvqFlatIn: + case EvqCentroidIn: + return true; + default: + return false; + } +} + +} // anonymous namespace + +float NumericLexFloat32OutOfRangeToInfinity(const std::string &str) +{ + // Parses a decimal string using scientific notation into a floating point number. + // Out-of-range values are converted to infinity. Values that are too small to be + // represented are converted to zero. + + // The mantissa in decimal scientific notation. The magnitude of the mantissa integer does not + // matter. + unsigned int decimalMantissa = 0; + size_t i = 0; + bool decimalPointSeen = false; + bool nonZeroSeenInMantissa = false; + + // The exponent offset reflects the position of the decimal point. + int exponentOffset = -1; + + // This is just a counter for how many decimal digits are written to decimalMantissa. + int mantissaDecimalDigits = 0; + + while (i < str.length()) + { + const char c = str[i]; + if (c == 'e' || c == 'E') + { + break; + } + if (c == '.') + { + decimalPointSeen = true; + ++i; + continue; + } + + unsigned int digit = static_cast<unsigned int>(c - '0'); + ASSERT(digit < 10u); + if (digit != 0u) + { + nonZeroSeenInMantissa = true; + } + if (nonZeroSeenInMantissa) + { + // Add bits to the mantissa until space runs out in 32-bit int. This should be + // enough precision to make the resulting binary mantissa accurate to 1 ULP. + if (decimalMantissa <= (std::numeric_limits<unsigned int>::max() - 9u) / 10u) + { + decimalMantissa = decimalMantissa * 10u + digit; + ++mantissaDecimalDigits; + } + if (!decimalPointSeen) + { + ++exponentOffset; + } + } + else if (decimalPointSeen) + { + --exponentOffset; + } + ++i; + } + if (decimalMantissa == 0) + { + return 0.0f; + } + int exponent = 0; + if (i < str.length()) + { + ASSERT(str[i] == 'e' || str[i] == 'E'); + ++i; + bool exponentOutOfRange = false; + bool negativeExponent = false; + if (str[i] == '-') + { + negativeExponent = true; + ++i; + } + else if (str[i] == '+') + { + ++i; + } + while (i < str.length()) + { + const char c = str[i]; + unsigned int digit = static_cast<unsigned int>(c - '0'); + ASSERT(digit < 10u); + if (exponent <= (std::numeric_limits<int>::max() - 9) / 10) + { + exponent = exponent * 10 + digit; + } + else + { + exponentOutOfRange = true; + } + ++i; + } + if (negativeExponent) + { + exponent = -exponent; + } + if (exponentOutOfRange) + { + if (negativeExponent) + { + return 0.0f; + } + else + { + return std::numeric_limits<float>::infinity(); + } + } + } + // Do the calculation in 64-bit to avoid overflow. + long long exponentLong = + static_cast<long long>(exponent) + static_cast<long long>(exponentOffset); + if (exponentLong > std::numeric_limits<float>::max_exponent10) + { + return std::numeric_limits<float>::infinity(); + } + else if (exponentLong < std::numeric_limits<float>::min_exponent10) + { + return 0.0f; + } + // The exponent is in range, so we need to actually evaluate the float. + exponent = static_cast<int>(exponentLong); + double value = decimalMantissa; + + // Calculate the exponent offset to normalize the mantissa. + int normalizationExponentOffset = 1 - mantissaDecimalDigits; + // Apply the exponent. + value *= std::pow(10.0, static_cast<double>(exponent + normalizationExponentOffset)); + if (value > static_cast<double>(std::numeric_limits<float>::max())) + { + return std::numeric_limits<float>::infinity(); + } + if (value < static_cast<double>(std::numeric_limits<float>::min())) + { + return 0.0f; + } + return static_cast<float>(value); +} + +bool strtof_clamp(const std::string &str, float *value) +{ + // Custom float parsing that can handle the following corner cases: + // 1. The decimal mantissa is very small but the exponent is very large, putting the resulting + // number inside the float range. + // 2. The decimal mantissa is very large but the exponent is very small, putting the resulting + // number inside the float range. + // 3. The value is out-of-range and should be evaluated as infinity. + // 4. The value is too small and should be evaluated as zero. + // See ESSL 3.00.6 section 4.1.4 for the relevant specification. + *value = NumericLexFloat32OutOfRangeToInfinity(str); + return !gl::isInf(*value); +} + +GLenum GLVariableType(const TType &type) +{ + if (type.getBasicType() == EbtFloat) + { + if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: + return GL_FLOAT_VEC2; + case 3: + return GL_FLOAT_VEC3; + case 4: + return GL_FLOAT_VEC4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + } + else if (type.isMatrix()) + { + switch (type.getCols()) + { + case 2: + switch (type.getRows()) + { + case 2: + return GL_FLOAT_MAT2; + case 3: + return GL_FLOAT_MAT2x3; + case 4: + return GL_FLOAT_MAT2x4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + + case 3: + switch (type.getRows()) + { + case 2: + return GL_FLOAT_MAT3x2; + case 3: + return GL_FLOAT_MAT3; + case 4: + return GL_FLOAT_MAT3x4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + + case 4: + switch (type.getRows()) + { + case 2: + return GL_FLOAT_MAT4x2; + case 3: + return GL_FLOAT_MAT4x3; + case 4: + return GL_FLOAT_MAT4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + } + else + { + return GL_FLOAT; + } + } + else if (type.getBasicType() == EbtInt) + { + if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: + return GL_INT_VEC2; + case 3: + return GL_INT_VEC3; + case 4: + return GL_INT_VEC4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + } + else + { + ASSERT(!type.isMatrix()); + return GL_INT; + } + } + else if (type.getBasicType() == EbtUInt) + { + if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: + return GL_UNSIGNED_INT_VEC2; + case 3: + return GL_UNSIGNED_INT_VEC3; + case 4: + return GL_UNSIGNED_INT_VEC4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + } + else + { + ASSERT(!type.isMatrix()); + return GL_UNSIGNED_INT; + } + } + else if (type.getBasicType() == EbtBool) + { + if (type.isVector()) + { + switch (type.getNominalSize()) + { + case 2: + return GL_BOOL_VEC2; + case 3: + return GL_BOOL_VEC3; + case 4: + return GL_BOOL_VEC4; + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return GL_NONE; +#endif + } + } + else + { + ASSERT(!type.isMatrix()); + return GL_BOOL; + } + } + + switch (type.getBasicType()) + { + case EbtSampler2D: + return GL_SAMPLER_2D; + case EbtSampler3D: + return GL_SAMPLER_3D; + case EbtSamplerCube: + return GL_SAMPLER_CUBE; + case EbtSamplerExternalOES: + return GL_SAMPLER_EXTERNAL_OES; + case EbtSamplerExternal2DY2YEXT: + return GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT; + case EbtSampler2DRect: + return GL_SAMPLER_2D_RECT_ANGLE; + case EbtSampler2DArray: + return GL_SAMPLER_2D_ARRAY; + case EbtSampler2DMS: + return GL_SAMPLER_2D_MULTISAMPLE; + case EbtSampler2DMSArray: + return GL_SAMPLER_2D_MULTISAMPLE_ARRAY; + case EbtISampler2D: + return GL_INT_SAMPLER_2D; + case EbtISampler3D: + return GL_INT_SAMPLER_3D; + case EbtISamplerCube: + return GL_INT_SAMPLER_CUBE; + case EbtISampler2DArray: + return GL_INT_SAMPLER_2D_ARRAY; + case EbtISampler2DMS: + return GL_INT_SAMPLER_2D_MULTISAMPLE; + case EbtISampler2DMSArray: + return GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY; + case EbtUSampler2D: + return GL_UNSIGNED_INT_SAMPLER_2D; + case EbtUSampler3D: + return GL_UNSIGNED_INT_SAMPLER_3D; + case EbtUSamplerCube: + return GL_UNSIGNED_INT_SAMPLER_CUBE; + case EbtUSampler2DArray: + return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY; + case EbtUSampler2DMS: + return GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE; + case EbtUSampler2DMSArray: + return GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY; + case EbtSampler2DShadow: + return GL_SAMPLER_2D_SHADOW; + case EbtSamplerCubeShadow: + return GL_SAMPLER_CUBE_SHADOW; + case EbtSampler2DArrayShadow: + return GL_SAMPLER_2D_ARRAY_SHADOW; + case EbtImage2D: + return GL_IMAGE_2D; + case EbtIImage2D: + return GL_INT_IMAGE_2D; + case EbtUImage2D: + return GL_UNSIGNED_INT_IMAGE_2D; + case EbtImage2DArray: + return GL_IMAGE_2D_ARRAY; + case EbtIImage2DArray: + return GL_INT_IMAGE_2D_ARRAY; + case EbtUImage2DArray: + return GL_UNSIGNED_INT_IMAGE_2D_ARRAY; + case EbtImage3D: + return GL_IMAGE_3D; + case EbtIImage3D: + return GL_INT_IMAGE_3D; + case EbtUImage3D: + return GL_UNSIGNED_INT_IMAGE_3D; + case EbtImageCube: + return GL_IMAGE_CUBE; + case EbtIImageCube: + return GL_INT_IMAGE_CUBE; + case EbtUImageCube: + return GL_UNSIGNED_INT_IMAGE_CUBE; + case EbtAtomicCounter: + return GL_UNSIGNED_INT_ATOMIC_COUNTER; + default: + UNREACHABLE(); + } + + return GL_NONE; +} + +GLenum GLVariablePrecision(const TType &type) +{ + if (type.getBasicType() == EbtFloat) + { + switch (type.getPrecision()) + { + case EbpHigh: + return GL_HIGH_FLOAT; + case EbpMedium: + return GL_MEDIUM_FLOAT; + case EbpLow: + return GL_LOW_FLOAT; + case EbpUndefined: + // Desktop specs do not use precision + return GL_NONE; + default: + UNREACHABLE(); + } + } + else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt) + { + switch (type.getPrecision()) + { + case EbpHigh: + return GL_HIGH_INT; + case EbpMedium: + return GL_MEDIUM_INT; + case EbpLow: + return GL_LOW_INT; + case EbpUndefined: + // Desktop specs do not use precision + return GL_NONE; + default: + UNREACHABLE(); + } + } + + // Other types (boolean, sampler) don't have a precision + return GL_NONE; +} + +ImmutableString ArrayString(const TType &type) +{ + if (!type.isArray()) + return ImmutableString(""); + + const TVector<unsigned int> &arraySizes = *type.getArraySizes(); + constexpr const size_t kMaxDecimalDigitsPerSize = 10u; + ImmutableStringBuilder arrayString(arraySizes.size() * (kMaxDecimalDigitsPerSize + 2u)); + for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend(); + ++arraySizeIter) + { + arrayString << "["; + if (*arraySizeIter > 0) + { + arrayString.appendDecimal(*arraySizeIter); + } + arrayString << "]"; + } + return arrayString; +} + +ImmutableString GetTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap) +{ + if (type.getBasicType() == EbtStruct) + return HashName(type.getStruct(), hashFunction, nameMap); + else + return ImmutableString(type.getBuiltInTypeNameString()); +} + +bool IsVaryingOut(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqVaryingOut: + case EvqSmoothOut: + case EvqFlatOut: + case EvqCentroidOut: + case EvqVertexOut: + case EvqGeometryOut: + return true; + + default: + break; + } + + return false; +} + +bool IsVaryingIn(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqVaryingIn: + case EvqSmoothIn: + case EvqFlatIn: + case EvqCentroidIn: + case EvqFragmentIn: + case EvqGeometryIn: + return true; + + default: + break; + } + + return false; +} + +bool IsVarying(TQualifier qualifier) +{ + return IsVaryingIn(qualifier) || IsVaryingOut(qualifier); +} + +bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier) +{ + return (qualifier == EvqGeometryIn) || + ((shaderType == GL_GEOMETRY_SHADER_EXT) && IsInterpolationIn(qualifier)); +} + +InterpolationType GetInterpolationType(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqFlatIn: + case EvqFlatOut: + return INTERPOLATION_FLAT; + + case EvqSmoothIn: + case EvqSmoothOut: + case EvqVertexOut: + case EvqFragmentIn: + case EvqVaryingIn: + case EvqVaryingOut: + case EvqGeometryIn: + case EvqGeometryOut: + return INTERPOLATION_SMOOTH; + + case EvqCentroidIn: + case EvqCentroidOut: + return INTERPOLATION_CENTROID; + + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return INTERPOLATION_SMOOTH; +#endif + } +} + +TType GetShaderVariableBasicType(const sh::ShaderVariable &var) +{ + switch (var.type) + { + case GL_BOOL: + return TType(EbtBool); + case GL_BOOL_VEC2: + return TType(EbtBool, 2); + case GL_BOOL_VEC3: + return TType(EbtBool, 3); + case GL_BOOL_VEC4: + return TType(EbtBool, 4); + case GL_FLOAT: + return TType(EbtFloat); + case GL_FLOAT_VEC2: + return TType(EbtFloat, 2); + case GL_FLOAT_VEC3: + return TType(EbtFloat, 3); + case GL_FLOAT_VEC4: + return TType(EbtFloat, 4); + case GL_FLOAT_MAT2: + return TType(EbtFloat, 2, 2); + case GL_FLOAT_MAT3: + return TType(EbtFloat, 3, 3); + case GL_FLOAT_MAT4: + return TType(EbtFloat, 4, 4); + case GL_FLOAT_MAT2x3: + return TType(EbtFloat, 2, 3); + case GL_FLOAT_MAT2x4: + return TType(EbtFloat, 2, 4); + case GL_FLOAT_MAT3x2: + return TType(EbtFloat, 3, 2); + case GL_FLOAT_MAT3x4: + return TType(EbtFloat, 3, 4); + case GL_FLOAT_MAT4x2: + return TType(EbtFloat, 4, 2); + case GL_FLOAT_MAT4x3: + return TType(EbtFloat, 4, 3); + case GL_INT: + return TType(EbtInt); + case GL_INT_VEC2: + return TType(EbtInt, 2); + case GL_INT_VEC3: + return TType(EbtInt, 3); + case GL_INT_VEC4: + return TType(EbtInt, 4); + case GL_UNSIGNED_INT: + return TType(EbtUInt); + case GL_UNSIGNED_INT_VEC2: + return TType(EbtUInt, 2); + case GL_UNSIGNED_INT_VEC3: + return TType(EbtUInt, 3); + case GL_UNSIGNED_INT_VEC4: + return TType(EbtUInt, 4); + default: + UNREACHABLE(); +#if !UNREACHABLE_IS_NORETURN + return TType(); +#endif + } +} + +void DeclareGlobalVariable(TIntermBlock *root, const TVariable *variable) +{ + TIntermDeclaration *declaration = new TIntermDeclaration(); + declaration->appendDeclarator(new TIntermSymbol(variable)); + + TIntermSequence *globalSequence = root->getSequence(); + globalSequence->insert(globalSequence->begin(), declaration); +} + +// GLSL ES 1.0.17 4.6.1 The Invariant Qualifier +bool CanBeInvariantESSL1(TQualifier qualifier) +{ + return IsVaryingIn(qualifier) || IsVaryingOut(qualifier) || + IsBuiltinOutputVariable(qualifier) || + (IsBuiltinFragmentInputVariable(qualifier) && qualifier != EvqFrontFacing); +} + +// GLSL ES 3.00 Revision 6, 4.6.1 The Invariant Qualifier +// GLSL ES 3.10 Revision 4, 4.8.1 The Invariant Qualifier +bool CanBeInvariantESSL3OrGreater(TQualifier qualifier) +{ + return IsVaryingOut(qualifier) || qualifier == EvqFragmentOut || + IsBuiltinOutputVariable(qualifier); +} + +bool IsBuiltinOutputVariable(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqPosition: + case EvqPointSize: + case EvqFragDepth: + case EvqFragDepthEXT: + case EvqFragColor: + case EvqSecondaryFragColorEXT: + case EvqFragData: + case EvqSecondaryFragDataEXT: + return true; + default: + break; + } + return false; +} + +bool IsBuiltinFragmentInputVariable(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqFragCoord: + case EvqPointCoord: + case EvqFrontFacing: + return true; + default: + break; + } + return false; +} + +bool IsShaderOutput(TQualifier qualifier) +{ + return IsVaryingOut(qualifier) || IsBuiltinOutputVariable(qualifier); +} + +bool IsOutputESSL(ShShaderOutput output) +{ + return output == SH_ESSL_OUTPUT; +} + +bool IsOutputGLSL(ShShaderOutput output) +{ + switch (output) + { + case SH_GLSL_130_OUTPUT: + case SH_GLSL_140_OUTPUT: + case SH_GLSL_150_CORE_OUTPUT: + case SH_GLSL_330_CORE_OUTPUT: + case SH_GLSL_400_CORE_OUTPUT: + case SH_GLSL_410_CORE_OUTPUT: + case SH_GLSL_420_CORE_OUTPUT: + case SH_GLSL_430_CORE_OUTPUT: + case SH_GLSL_440_CORE_OUTPUT: + case SH_GLSL_450_CORE_OUTPUT: + case SH_GLSL_COMPATIBILITY_OUTPUT: + return true; + default: + break; + } + return false; +} +bool IsOutputHLSL(ShShaderOutput output) +{ + switch (output) + { + case SH_HLSL_3_0_OUTPUT: + case SH_HLSL_4_1_OUTPUT: + case SH_HLSL_4_0_FL9_3_OUTPUT: + return true; + default: + break; + } + return false; +} +bool IsOutputVulkan(ShShaderOutput output) +{ + return output == SH_GLSL_VULKAN_OUTPUT; +} + +bool IsInShaderStorageBlock(TIntermTyped *node) +{ + TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); + if (swizzleNode) + { + return IsInShaderStorageBlock(swizzleNode->getOperand()); + } + + TIntermBinary *binaryNode = node->getAsBinaryNode(); + if (binaryNode) + { + switch (binaryNode->getOp()) + { + case EOpIndexDirectInterfaceBlock: + case EOpIndexIndirect: + case EOpIndexDirect: + case EOpIndexDirectStruct: + return IsInShaderStorageBlock(binaryNode->getLeft()); + default: + return false; + } + } + + const TType &type = node->getType(); + return type.getQualifier() == EvqBuffer; +} + +GLenum GetImageInternalFormatType(TLayoutImageInternalFormat iifq) +{ + switch (iifq) + { + case EiifRGBA32F: + return GL_RGBA32F; + case EiifRGBA16F: + return GL_RGBA16F; + case EiifR32F: + return GL_R32F; + case EiifRGBA32UI: + return GL_RGBA32UI; + case EiifRGBA16UI: + return GL_RGBA16UI; + case EiifRGBA8UI: + return GL_RGBA8UI; + case EiifR32UI: + return GL_R32UI; + case EiifRGBA32I: + return GL_RGBA32I; + case EiifRGBA16I: + return GL_RGBA16I; + case EiifRGBA8I: + return GL_RGBA8I; + case EiifR32I: + return GL_R32I; + case EiifRGBA8: + return GL_RGBA8; + case EiifRGBA8_SNORM: + return GL_RGBA8_SNORM; + default: + return GL_NONE; + } +} + +bool IsSpecWithFunctionBodyNewScope(ShShaderSpec shaderSpec, int shaderVersion) +{ + return (shaderVersion == 100 && !sh::IsWebGLBasedSpec(shaderSpec)); +} + +ImplicitTypeConversion GetConversion(TBasicType t1, TBasicType t2) +{ + if (t1 == t2) + return ImplicitTypeConversion::Same; + + switch (t1) + { + case EbtInt: + switch (t2) + { + case EbtInt: + UNREACHABLE(); + break; + case EbtUInt: + return ImplicitTypeConversion::Invalid; + case EbtFloat: + return ImplicitTypeConversion::Left; + default: + return ImplicitTypeConversion::Invalid; + } + break; + case EbtUInt: + switch (t2) + { + case EbtInt: + return ImplicitTypeConversion::Invalid; + case EbtUInt: + UNREACHABLE(); + break; + case EbtFloat: + return ImplicitTypeConversion::Left; + default: + return ImplicitTypeConversion::Invalid; + } + break; + case EbtFloat: + switch (t2) + { + case EbtInt: + case EbtUInt: + return ImplicitTypeConversion::Right; + case EbtFloat: + UNREACHABLE(); + break; + default: + return ImplicitTypeConversion::Invalid; + } + break; + default: + return ImplicitTypeConversion::Invalid; + } + return ImplicitTypeConversion::Invalid; +} + +bool IsValidImplicitConversion(sh::ImplicitTypeConversion conversion, TOperator op) +{ + switch (conversion) + { + case sh::ImplicitTypeConversion::Same: + return true; + case sh::ImplicitTypeConversion::Left: + switch (op) + { + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + return true; + default: + break; + } + break; + case sh::ImplicitTypeConversion::Right: + switch (op) + { + case EOpAssign: + case EOpInitialize: + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpDivAssign: + return true; + default: + break; + } + break; + case sh::ImplicitTypeConversion::Invalid: + break; + } + return false; +} + +} // namespace sh diff --git a/gfx/angle/checkout/src/compiler/translator/util.h b/gfx/angle/checkout/src/compiler/translator/util.h new file mode 100644 index 0000000000..609c72af67 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/util.h @@ -0,0 +1,92 @@ +// +// Copyright (c) 2002-2010 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_UTIL_H_ +#define COMPILER_TRANSLATOR_UTIL_H_ + +#include <stack> + +#include <GLSLANG/ShaderLang.h> +#include "angle_gl.h" + +#include "compiler/translator/HashNames.h" +#include "compiler/translator/ImmutableString.h" +#include "compiler/translator/Operator.h" +#include "compiler/translator/Types.h" + +// If overflow happens, clamp the value to UINT_MIN or UINT_MAX. +// Return false if overflow happens. +bool atoi_clamp(const char *str, unsigned int *value); + +namespace sh +{ + +// Keeps track of whether an implicit conversion from int/uint to float is possible. +// These conversions are supported in desktop GLSL shaders only. +// Also keeps track of which side of operation should be converted. +enum class ImplicitTypeConversion +{ + Same, + Left, + Right, + Invalid, +}; + +class TIntermBlock; +class TSymbolTable; +class TIntermTyped; + +float NumericLexFloat32OutOfRangeToInfinity(const std::string &str); + +// strtof_clamp is like strtof but +// 1. it forces C locale, i.e. forcing '.' as decimal point. +// 2. it sets the value to infinity if overflow happens. +// 3. str should be guaranteed to be in the valid format for a floating point number as defined +// by the grammar in the ESSL 3.00.6 spec section 4.1.4. +// Return false if overflow happens. +bool strtof_clamp(const std::string &str, float *value); + +GLenum GLVariableType(const TType &type); +GLenum GLVariablePrecision(const TType &type); +bool IsVaryingIn(TQualifier qualifier); +bool IsVaryingOut(TQualifier qualifier); +bool IsVarying(TQualifier qualifier); +bool IsGeometryShaderInput(GLenum shaderType, TQualifier qualifier); +InterpolationType GetInterpolationType(TQualifier qualifier); + +// Returns array brackets including size with outermost array size first, as specified in GLSL ES +// 3.10 section 4.1.9. +ImmutableString ArrayString(const TType &type); + +ImmutableString GetTypeName(const TType &type, ShHashFunction64 hashFunction, NameMap *nameMap); + +TType GetShaderVariableBasicType(const sh::ShaderVariable &var); + +void DeclareGlobalVariable(TIntermBlock *root, const TVariable *variable); + +bool IsBuiltinOutputVariable(TQualifier qualifier); +bool IsBuiltinFragmentInputVariable(TQualifier qualifier); +bool CanBeInvariantESSL1(TQualifier qualifier); +bool CanBeInvariantESSL3OrGreater(TQualifier qualifier); +bool IsShaderOutput(TQualifier qualifier); +bool IsOutputESSL(ShShaderOutput output); +bool IsOutputGLSL(ShShaderOutput output); +bool IsOutputHLSL(ShShaderOutput output); +bool IsOutputVulkan(ShShaderOutput output); + +bool IsInShaderStorageBlock(TIntermTyped *node); + +GLenum GetImageInternalFormatType(TLayoutImageInternalFormat iifq); +// ESSL 1.00 shaders nest function body scope within function parameter scope +bool IsSpecWithFunctionBodyNewScope(ShShaderSpec shaderSpec, int shaderVersion); + +// Helper functions for implicit conversions +ImplicitTypeConversion GetConversion(TBasicType t1, TBasicType t2); + +bool IsValidImplicitConversion(ImplicitTypeConversion conversion, TOperator op); +} // namespace sh + +#endif // COMPILER_TRANSLATOR_UTIL_H_ |