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