| // |
| // 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 |