1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "compiler/translator/BuiltinsWorkaroundGLSL.h"
8
9 #include "angle_gl.h"
10 #include "compiler/translator/Symbol.h"
11 #include "compiler/translator/SymbolTable.h"
12 #include "compiler/translator/tree_util/BuiltIn.h"
13
14 namespace sh
15 {
16
17 namespace
18 {
19 constexpr const ImmutableString kGlInstanceIDString("gl_InstanceID");
20 constexpr const ImmutableString kGlVertexIDString("gl_VertexID");
21
22 class TBuiltinsWorkaroundGLSL : public TIntermTraverser
23 {
24 public:
25 TBuiltinsWorkaroundGLSL(TSymbolTable *symbolTable, ShCompileOptions options);
26
27 void visitSymbol(TIntermSymbol *node) override;
28 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
29
30 private:
31 void ensureVersionIsAtLeast(int version);
32
33 ShCompileOptions mCompileOptions;
34
35 bool isBaseInstanceDeclared = false;
36 };
37
TBuiltinsWorkaroundGLSL(TSymbolTable * symbolTable,ShCompileOptions options)38 TBuiltinsWorkaroundGLSL::TBuiltinsWorkaroundGLSL(TSymbolTable *symbolTable,
39 ShCompileOptions options)
40 : TIntermTraverser(true, false, false, symbolTable), mCompileOptions(options)
41 {}
42
visitSymbol(TIntermSymbol * node)43 void TBuiltinsWorkaroundGLSL::visitSymbol(TIntermSymbol *node)
44 {
45 if (node->variable().symbolType() == SymbolType::BuiltIn)
46 {
47 if (node->getName() == kGlInstanceIDString)
48 {
49 TIntermSymbol *instanceIndexRef =
50 new TIntermSymbol(BuiltInVariable::gl_InstanceIndex());
51
52 if (isBaseInstanceDeclared)
53 {
54 TIntermSymbol *baseInstanceRef =
55 new TIntermSymbol(BuiltInVariable::angle_BaseInstance());
56
57 TIntermBinary *subBaseInstance =
58 new TIntermBinary(EOpSub, instanceIndexRef, baseInstanceRef);
59 queueReplacement(subBaseInstance, OriginalNode::IS_DROPPED);
60 }
61 else
62 {
63 queueReplacement(instanceIndexRef, OriginalNode::IS_DROPPED);
64 }
65 }
66 else if (node->getName() == kGlVertexIDString)
67 {
68 TIntermSymbol *vertexIndexRef = new TIntermSymbol(BuiltInVariable::gl_VertexIndex());
69 queueReplacement(vertexIndexRef, OriginalNode::IS_DROPPED);
70 }
71 }
72 }
73
visitDeclaration(Visit,TIntermDeclaration * node)74 bool TBuiltinsWorkaroundGLSL::visitDeclaration(Visit, TIntermDeclaration *node)
75 {
76 const TIntermSequence &sequence = *(node->getSequence());
77 ASSERT(!sequence.empty());
78
79 for (TIntermNode *variableNode : sequence)
80 {
81 TIntermSymbol *variable = variableNode->getAsSymbolNode();
82 if (variable && variable->variable().symbolType() == SymbolType::BuiltIn)
83 {
84 if (variable->getName() == "angle_BaseInstance")
85 {
86 isBaseInstanceDeclared = true;
87 }
88 }
89 }
90 return true;
91 }
92
93 } // anonymous namespace
94
ShaderBuiltinsWorkaround(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,ShCompileOptions compileOptions)95 ANGLE_NO_DISCARD bool ShaderBuiltinsWorkaround(TCompiler *compiler,
96 TIntermBlock *root,
97 TSymbolTable *symbolTable,
98 ShCompileOptions compileOptions)
99 {
100 TBuiltinsWorkaroundGLSL builtins(symbolTable, compileOptions);
101 root->traverse(&builtins);
102 if (!builtins.updateTree(compiler, root))
103 {
104 return false;
105 }
106 return true;
107 }
108
109 } // namespace sh
110