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