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 };
38
TBuiltinsWorkaroundGLSL(TSymbolTable * symbolTable,ShCompileOptions options)39 TBuiltinsWorkaroundGLSL::TBuiltinsWorkaroundGLSL(TSymbolTable *symbolTable,
40 ShCompileOptions options)
41 : TIntermTraverser(true, false, false, symbolTable), mCompileOptions(options)
42 {}
43
visitSymbol(TIntermSymbol * node)44 void TBuiltinsWorkaroundGLSL::visitSymbol(TIntermSymbol *node)
45 {
46 if (node->variable().symbolType() == SymbolType::BuiltIn)
47 {
48 if (node->getName() == kGlInstanceIDString)
49 {
50 TIntermSymbol *instanceIndexRef =
51 new TIntermSymbol(BuiltInVariable::gl_InstanceIndex());
52
53 if (isBaseInstanceDeclared)
54 {
55 TIntermSymbol *baseInstanceRef =
56 new TIntermSymbol(BuiltInVariable::angle_BaseInstance());
57
58 TIntermBinary *subBaseInstance =
59 new TIntermBinary(EOpSub, instanceIndexRef, baseInstanceRef);
60 queueReplacement(subBaseInstance, OriginalNode::IS_DROPPED);
61 }
62 else
63 {
64 queueReplacement(instanceIndexRef, OriginalNode::IS_DROPPED);
65 }
66 }
67 else if (node->getName() == kGlVertexIDString)
68 {
69 TIntermSymbol *vertexIndexRef = new TIntermSymbol(BuiltInVariable::gl_VertexIndex());
70 queueReplacement(vertexIndexRef, OriginalNode::IS_DROPPED);
71 }
72 }
73 }
74
visitDeclaration(Visit,TIntermDeclaration * node)75 bool TBuiltinsWorkaroundGLSL::visitDeclaration(Visit, TIntermDeclaration *node)
76 {
77 const TIntermSequence &sequence = *(node->getSequence());
78 ASSERT(!sequence.empty());
79
80 for (TIntermNode *variableNode : sequence)
81 {
82 TIntermSymbol *variable = variableNode->getAsSymbolNode();
83 if (variable && variable->variable().symbolType() == SymbolType::BuiltIn)
84 {
85 if (variable->getName() == "angle_BaseInstance")
86 {
87 isBaseInstanceDeclared = true;
88 }
89 }
90 }
91 return true;
92 }
93
94 } // anonymous namespace
95
ShaderBuiltinsWorkaround(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,ShCompileOptions compileOptions)96 ANGLE_NO_DISCARD bool ShaderBuiltinsWorkaround(TCompiler *compiler,
97 TIntermBlock *root,
98 TSymbolTable *symbolTable,
99 ShCompileOptions compileOptions)
100 {
101 TBuiltinsWorkaroundGLSL builtins(symbolTable, compileOptions);
102 root->traverse(&builtins);
103 if (!builtins.updateTree(compiler, root))
104 {
105 return false;
106 }
107 return true;
108 }
109
110 } // namespace sh
111