Line data Source code
1 : //
2 : // Copyright (c) 2016 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 : // Implementation of texelFetchOffset translation issue workaround.
7 : // See header for more info.
8 :
9 : #include "compiler/translator/RewriteTexelFetchOffset.h"
10 :
11 : #include "common/angleutils.h"
12 : #include "compiler/translator/IntermNode.h"
13 : #include "compiler/translator/SymbolTable.h"
14 :
15 : namespace sh
16 : {
17 :
18 : namespace
19 : {
20 :
21 0 : class Traverser : public TIntermTraverser
22 : {
23 : public:
24 : static void Apply(TIntermNode *root,
25 : const TSymbolTable &symbolTable,
26 : int shaderVersion);
27 :
28 : private:
29 : Traverser(const TSymbolTable &symbolTable, int shaderVersion);
30 : bool visitAggregate(Visit visit, TIntermAggregate *node) override;
31 : void nextIteration();
32 :
33 : const TSymbolTable *symbolTable;
34 : const int shaderVersion;
35 : bool mFound = false;
36 : };
37 :
38 0 : Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion)
39 0 : : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion)
40 : {
41 0 : }
42 :
43 : // static
44 0 : void Traverser::Apply(TIntermNode *root,
45 : const TSymbolTable &symbolTable,
46 : int shaderVersion)
47 : {
48 0 : Traverser traverser(symbolTable, shaderVersion);
49 0 : do
50 : {
51 0 : traverser.nextIteration();
52 0 : root->traverse(&traverser);
53 0 : if (traverser.mFound)
54 : {
55 0 : traverser.updateTree();
56 : }
57 0 : } while (traverser.mFound);
58 0 : }
59 :
60 0 : void Traverser::nextIteration()
61 : {
62 0 : mFound = false;
63 0 : }
64 :
65 0 : bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
66 : {
67 0 : if (mFound)
68 : {
69 0 : return false;
70 : }
71 :
72 : // Decide if the node represents the call of texelFetchOffset.
73 0 : if (node->getOp() != EOpFunctionCall || node->isUserDefined())
74 : {
75 0 : return true;
76 : }
77 :
78 0 : if (node->getFunctionSymbolInfo()->getName().compare(0, 16, "texelFetchOffset") != 0)
79 : {
80 0 : return true;
81 : }
82 :
83 : // Potential problem case detected, apply workaround.
84 0 : const TIntermSequence *sequence = node->getSequence();
85 0 : ASSERT(sequence->size() == 4u);
86 :
87 : // Decide if there is a 2DArray sampler.
88 0 : bool is2DArray = node->getFunctionSymbolInfo()->getName().find("s2a1") != TString::npos;
89 :
90 : // Create new argument list from node->getName().
91 : // e.g. Get "(is2a1;vi3;i1;" from "texelFetchOffset(is2a1;vi3;i1;vi2;"
92 0 : TString newArgs = node->getFunctionSymbolInfo()->getName().substr(
93 0 : 16, node->getFunctionSymbolInfo()->getName().length() - 20);
94 0 : TString newName = "texelFetch" + newArgs;
95 0 : TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(newName, shaderVersion);
96 0 : ASSERT(texelFetchSymbol);
97 0 : int uniqueId = texelFetchSymbol->getUniqueId();
98 :
99 : // Create new node that represents the call of function texelFetch.
100 : // Its argument list will be: texelFetch(sampler, Position+offset, lod).
101 0 : TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpFunctionCall);
102 0 : texelFetchNode->getFunctionSymbolInfo()->setName(newName);
103 0 : texelFetchNode->getFunctionSymbolInfo()->setId(uniqueId);
104 0 : texelFetchNode->setType(node->getType());
105 0 : texelFetchNode->setLine(node->getLine());
106 :
107 : // sampler
108 0 : texelFetchNode->getSequence()->push_back(sequence->at(0));
109 :
110 : // Position
111 0 : TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
112 0 : ASSERT(texCoordNode);
113 :
114 : // offset
115 0 : TIntermTyped *offsetNode = nullptr;
116 0 : ASSERT(sequence->at(3)->getAsTyped());
117 0 : if (is2DArray)
118 : {
119 : // For 2DArray samplers, Position is ivec3 and offset is ivec2;
120 : // So offset must be converted into an ivec3 before being added to Position.
121 0 : TIntermAggregate *constructIVec3Node = new TIntermAggregate(EOpConstructIVec3);
122 0 : constructIVec3Node->setLine(texCoordNode->getLine());
123 0 : constructIVec3Node->setType(texCoordNode->getType());
124 :
125 0 : constructIVec3Node->getSequence()->push_back(sequence->at(3)->getAsTyped());
126 :
127 0 : TConstantUnion *zero = new TConstantUnion();
128 0 : zero->setIConst(0);
129 0 : TType *intType = new TType(EbtInt);
130 :
131 0 : TIntermConstantUnion *zeroNode = new TIntermConstantUnion(zero, *intType);
132 0 : constructIVec3Node->getSequence()->push_back(zeroNode);
133 :
134 0 : offsetNode = constructIVec3Node;
135 : }
136 : else
137 : {
138 0 : offsetNode = sequence->at(3)->getAsTyped();
139 : }
140 :
141 : // Position+offset
142 0 : TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
143 0 : add->setLine(texCoordNode->getLine());
144 0 : texelFetchNode->getSequence()->push_back(add);
145 :
146 : // lod
147 0 : texelFetchNode->getSequence()->push_back(sequence->at(2));
148 :
149 0 : ASSERT(texelFetchNode->getSequence()->size() == 3u);
150 :
151 : // Replace the old node by this new node.
152 0 : queueReplacement(node, texelFetchNode, OriginalNode::IS_DROPPED);
153 0 : mFound = true;
154 0 : return false;
155 : }
156 :
157 : } // anonymous namespace
158 :
159 0 : void RewriteTexelFetchOffset(TIntermNode *root,
160 : const TSymbolTable &symbolTable,
161 : int shaderVersion)
162 : {
163 : // texelFetchOffset is only valid in GLSL 3.0 and later.
164 0 : if (shaderVersion < 300)
165 0 : return;
166 :
167 0 : Traverser::Apply(root, symbolTable, shaderVersion);
168 : }
169 :
170 : } // namespace sh
|