// // 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/spirv/BuiltinsWorkaround.h" #include "angle_gl.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 TBuiltinsWorkaround : public TIntermTraverser { public: TBuiltinsWorkaround(TSymbolTable *symbolTable, const ShCompileOptions &options, const TVariable *emulatedBaseInstance) : TIntermTraverser(true, false, false, symbolTable), mCompileOptions(options), mEmulatedBaseInstance(emulatedBaseInstance) {} void visitSymbol(TIntermSymbol *node) override; private: void ensureVersionIsAtLeast(int version); const ShCompileOptions &mCompileOptions; const TVariable *mEmulatedBaseInstance; }; void TBuiltinsWorkaround::visitSymbol(TIntermSymbol *node) { if (node->variable().symbolType() == SymbolType::BuiltIn && node->getName() == kGlInstanceIDString) { TIntermSymbol *instanceIndexRef = new TIntermSymbol(BuiltInVariable::gl_InstanceIndex()); if (mEmulatedBaseInstance != nullptr) { TIntermSymbol *baseInstanceRef = new TIntermSymbol(mEmulatedBaseInstance); 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); } } const TVariable *FindEmulatedBaseInstance(TIntermBlock *root) { for (TIntermNode *node : *root->getSequence()) { TIntermDeclaration *decl = node->getAsDeclarationNode(); if (decl == nullptr) { continue; } const TIntermSequence &sequence = *(decl->getSequence()); ASSERT(!sequence.empty()); TIntermSymbol *symbol = sequence[0]->getAsSymbolNode(); if (symbol == nullptr) { continue; } if (symbol->variable().symbolType() == SymbolType::AngleInternal && symbol->variable().name() == "angle_BaseInstance") { return &symbol->variable(); } } return nullptr; } } // anonymous namespace [[nodiscard]] bool ShaderBuiltinsWorkaround(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable, const ShCompileOptions &compileOptions) { TBuiltinsWorkaround builtins(symbolTable, compileOptions, FindEmulatedBaseInstance(root)); root->traverse(&builtins); if (!builtins.updateTree(compiler, root)) { return false; } return true; } } // namespace sh