blob: 90613d09566807417d97e1ad0887f4eec8ed07e3 [file] [log] [blame]
Shao11e43ec2016-08-11 09:54:08 +08001//
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
15namespace sh
16{
17
18namespace
19{
20
21class Traverser : public TIntermTraverser
22{
23 public:
24 static void Apply(TIntermNode *root,
25 unsigned int *tempIndex,
26 const TSymbolTable &symbolTable,
27 int shaderVersion);
28
29 private:
30 Traverser(const TSymbolTable &symbolTable, int shaderVersion);
31 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
32 void nextIteration();
33
34 const TSymbolTable *symbolTable;
35 const int shaderVersion;
36 bool mFound = false;
37};
38
39Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion)
40 : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion)
41{
42}
43
44// static
45void Traverser::Apply(TIntermNode *root,
46 unsigned int *tempIndex,
47 const TSymbolTable &symbolTable,
48 int shaderVersion)
49{
50 Traverser traverser(symbolTable, shaderVersion);
51 traverser.useTemporaryIndex(tempIndex);
52 do
53 {
54 traverser.nextIteration();
55 root->traverse(&traverser);
56 if (traverser.mFound)
57 {
58 traverser.updateTree();
59 }
60 } while (traverser.mFound);
61}
62
63void Traverser::nextIteration()
64{
65 mFound = false;
66 nextTemporaryIndex();
67}
68
69bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
70{
71 if (mFound)
72 {
73 return false;
74 }
75
76 // Decide if the node represents the call of texelFetchOffset.
77 if (node->getOp() != EOpFunctionCall || node->isUserDefined())
78 {
79 return true;
80 }
81
82 if (node->getName().compare(0, 16, "texelFetchOffset") != 0)
83 {
84 return true;
85 }
86
87 // Potential problem case detected, apply workaround.
88 const TIntermSequence *sequence = node->getSequence();
89 ASSERT(sequence->size() == 4u);
90 nextTemporaryIndex();
91
92 // Decide if there is a 2DArray sampler.
93 bool is2DArray = node->getName().find("s2a1") != TString::npos;
94
95 // Create new argument list from node->getName().
96 // e.g. Get "(is2a1;vi3;i1;" from "texelFetchOffset(is2a1;vi3;i1;vi2;"
97 TString newArgs = node->getName().substr(16, node->getName().length() - 20);
98 TString newName = "texelFetch" + newArgs;
99 TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(newName, shaderVersion);
100 ASSERT(texelFetchSymbol);
101 int uniqueId = texelFetchSymbol->getUniqueId();
102
103 // Create new node that represents the call of function texelFetch.
104 TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpFunctionCall);
105 texelFetchNode->setName(newName);
106 texelFetchNode->setFunctionId(uniqueId);
107 texelFetchNode->setType(node->getType());
108 texelFetchNode->setLine(node->getLine());
109
110 // Create argument List of texelFetch(sampler, Position+offset, lod).
111 TIntermSequence newsequence;
112
113 // sampler
114 newsequence.push_back(sequence->at(0));
115
Shao11e43ec2016-08-11 09:54:08 +0800116 // Position
117 TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
118 ASSERT(texCoordNode);
Shao11e43ec2016-08-11 09:54:08 +0800119 // offset
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300120 TIntermTyped *offsetNode = nullptr;
Shao11e43ec2016-08-11 09:54:08 +0800121 ASSERT(sequence->at(3)->getAsTyped());
122 if (is2DArray)
123 {
124 // For 2DArray samplers, Position is ivec3 and offset is ivec2;
125 // So offset must be converted into an ivec3 before being added to Position.
126 TIntermAggregate *constructIVec3Node = new TIntermAggregate(EOpConstructIVec3);
127 constructIVec3Node->setLine(texCoordNode->getLine());
128 constructIVec3Node->setType(texCoordNode->getType());
129
130 TIntermSequence ivec3Sequence;
131 ivec3Sequence.push_back(sequence->at(3)->getAsTyped());
132
133 TConstantUnion *zero = new TConstantUnion();
134 zero->setIConst(0);
135 TType *intType = new TType(EbtInt);
136
137 TIntermConstantUnion *zeroNode = new TIntermConstantUnion(zero, *intType);
138 ivec3Sequence.push_back(zeroNode);
139 constructIVec3Node->insertChildNodes(0, ivec3Sequence);
140
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300141 offsetNode = constructIVec3Node;
Shao11e43ec2016-08-11 09:54:08 +0800142 }
143 else
144 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300145 offsetNode = sequence->at(3)->getAsTyped();
Shao11e43ec2016-08-11 09:54:08 +0800146 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300147
148 // Position+offset
149 TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
150 add->setLine(texCoordNode->getLine());
Shao11e43ec2016-08-11 09:54:08 +0800151 newsequence.push_back(add);
152
153 // lod
154 newsequence.push_back(sequence->at(2));
155 texelFetchNode->insertChildNodes(0, newsequence);
156
157 // Replace the old node by this new node.
158 queueReplacement(node, texelFetchNode, OriginalNode::IS_DROPPED);
159 mFound = true;
160 return false;
161}
162
163} // anonymous namespace
164
165void RewriteTexelFetchOffset(TIntermNode *root,
166 unsigned int *tempIndex,
167 const TSymbolTable &symbolTable,
168 int shaderVersion)
169{
170 // texelFetchOffset is only valid in GLSL 3.0 and later.
171 if (shaderVersion < 300)
172 return;
173
174 Traverser::Apply(root, tempIndex, symbolTable, shaderVersion);
175}
176
177} // namespace sh