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