| // | |
| // 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/BuiltinsWorkaroundGLSL.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.h" | |
| namespace sh | |
| { | |
| namespace | |
| { | |
| constexpr const ImmutableString kGlInstanceIDString("gl_InstanceID"); | |
| constexpr const ImmutableString kGlVertexIDString("gl_VertexID"); | |
| class TBuiltinsWorkaroundGLSL : public TIntermTraverser | |
| { | |
| public: | |
| TBuiltinsWorkaroundGLSL(TSymbolTable *symbolTable, ShCompileOptions options); | |
| void visitSymbol(TIntermSymbol *node) override; | |
| bool visitDeclaration(Visit, TIntermDeclaration *node) override; | |
| private: | |
| void ensureVersionIsAtLeast(int version); | |
| ShCompileOptions mCompileOptions; | |
| bool isBaseInstanceDeclared = false; | |
| bool isBaseVertexDeclared = false; | |
| }; | |
| TBuiltinsWorkaroundGLSL::TBuiltinsWorkaroundGLSL(TSymbolTable *symbolTable, | |
| ShCompileOptions options) | |
| : TIntermTraverser(true, false, false, symbolTable), mCompileOptions(options) | |
| {} | |
| void TBuiltinsWorkaroundGLSL::visitSymbol(TIntermSymbol *node) | |
| { | |
| if (node->variable().symbolType() == SymbolType::BuiltIn) | |
| { | |
| if (node->getName() == kGlInstanceIDString) | |
| { | |
| TIntermSymbol *instanceIndexRef = | |
| new TIntermSymbol(BuiltInVariable::gl_InstanceIndex()); | |
| if (isBaseInstanceDeclared) | |
| { | |
| TIntermSymbol *baseInstanceRef = | |
| new TIntermSymbol(BuiltInVariable::angle_BaseInstance()); | |
| TIntermBinary *subBaseInstance = | |
| new TIntermBinary(EOpSub, instanceIndexRef, baseInstanceRef); | |
| queueReplacement(subBaseInstance, OriginalNode::IS_DROPPED); | |
| } | |
| else | |
| { | |
| queueReplacement(instanceIndexRef, OriginalNode::IS_DROPPED); | |
| } | |
| } | |
| else if (node->getName() == kGlVertexIDString) | |
| { | |
| TIntermSymbol *vertexIndexRef = new TIntermSymbol(BuiltInVariable::gl_VertexIndex()); | |
| queueReplacement(vertexIndexRef, OriginalNode::IS_DROPPED); | |
| } | |
| } | |
| } | |
| bool TBuiltinsWorkaroundGLSL::visitDeclaration(Visit, TIntermDeclaration *node) | |
| { | |
| const TIntermSequence &sequence = *(node->getSequence()); | |
| ASSERT(!sequence.empty()); | |
| for (TIntermNode *variableNode : sequence) | |
| { | |
| TIntermSymbol *variable = variableNode->getAsSymbolNode(); | |
| if (variable && variable->variable().symbolType() == SymbolType::AngleInternal) | |
| { | |
| if (variable->getName() == "angle_BaseInstance") | |
| { | |
| isBaseInstanceDeclared = true; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| } // anonymous namespace | |
| ANGLE_NO_DISCARD bool ShaderBuiltinsWorkaround(TCompiler *compiler, | |
| TIntermBlock *root, | |
| TSymbolTable *symbolTable, | |
| ShCompileOptions compileOptions) | |
| { | |
| TBuiltinsWorkaroundGLSL builtins(symbolTable, compileOptions); | |
| root->traverse(&builtins); | |
| if (!builtins.updateTree(compiler, root)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| } // namespace sh |