blob: b1ccf0caa2b42a2202a8c7037bf25705fbd432bb [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:
Jamie Madilld7b1ab52016-12-12 14:42:19 -050024 static void Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion);
Shao11e43ec2016-08-11 09:54:08 +080025
26 private:
27 Traverser(const TSymbolTable &symbolTable, int shaderVersion);
28 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
29 void nextIteration();
30
31 const TSymbolTable *symbolTable;
32 const int shaderVersion;
33 bool mFound = false;
34};
35
36Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion)
37 : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion)
38{
39}
40
41// static
Jamie Madilld7b1ab52016-12-12 14:42:19 -050042void Traverser::Apply(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion)
Shao11e43ec2016-08-11 09:54:08 +080043{
44 Traverser traverser(symbolTable, shaderVersion);
Shao11e43ec2016-08-11 09:54:08 +080045 do
46 {
47 traverser.nextIteration();
48 root->traverse(&traverser);
49 if (traverser.mFound)
50 {
51 traverser.updateTree();
52 }
53 } while (traverser.mFound);
54}
55
56void Traverser::nextIteration()
57{
58 mFound = false;
Shao11e43ec2016-08-11 09:54:08 +080059}
60
61bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
62{
63 if (mFound)
64 {
65 return false;
66 }
67
68 // Decide if the node represents the call of texelFetchOffset.
Olli Etuaho1ecd14b2017-01-26 13:54:15 -080069 if (node->getOp() != EOpCallBuiltInFunction)
Shao11e43ec2016-08-11 09:54:08 +080070 {
71 return true;
72 }
73
Olli Etuahobd674552016-10-06 13:28:42 +010074 if (node->getFunctionSymbolInfo()->getName().compare(0, 16, "texelFetchOffset") != 0)
Shao11e43ec2016-08-11 09:54:08 +080075 {
76 return true;
77 }
78
79 // Potential problem case detected, apply workaround.
80 const TIntermSequence *sequence = node->getSequence();
81 ASSERT(sequence->size() == 4u);
Shao11e43ec2016-08-11 09:54:08 +080082
83 // Decide if there is a 2DArray sampler.
Olli Etuahobd674552016-10-06 13:28:42 +010084 bool is2DArray = node->getFunctionSymbolInfo()->getName().find("s2a1") != TString::npos;
Shao11e43ec2016-08-11 09:54:08 +080085
86 // Create new argument list from node->getName().
87 // e.g. Get "(is2a1;vi3;i1;" from "texelFetchOffset(is2a1;vi3;i1;vi2;"
Olli Etuahobd674552016-10-06 13:28:42 +010088 TString newArgs = node->getFunctionSymbolInfo()->getName().substr(
89 16, node->getFunctionSymbolInfo()->getName().length() - 20);
Shao11e43ec2016-08-11 09:54:08 +080090 TString newName = "texelFetch" + newArgs;
91 TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(newName, shaderVersion);
92 ASSERT(texelFetchSymbol);
93 int uniqueId = texelFetchSymbol->getUniqueId();
94
95 // Create new node that represents the call of function texelFetch.
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010096 // Its argument list will be: texelFetch(sampler, Position+offset, lod).
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -080097
98 TIntermSequence *texelFetchArguments = new TIntermSequence();
Shao11e43ec2016-08-11 09:54:08 +080099
Shao11e43ec2016-08-11 09:54:08 +0800100 // sampler
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800101 texelFetchArguments->push_back(sequence->at(0));
Shao11e43ec2016-08-11 09:54:08 +0800102
Shao11e43ec2016-08-11 09:54:08 +0800103 // Position
104 TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
105 ASSERT(texCoordNode);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100106
Shao11e43ec2016-08-11 09:54:08 +0800107 // offset
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300108 TIntermTyped *offsetNode = nullptr;
Shao11e43ec2016-08-11 09:54:08 +0800109 ASSERT(sequence->at(3)->getAsTyped());
110 if (is2DArray)
111 {
112 // For 2DArray samplers, Position is ivec3 and offset is ivec2;
113 // So offset must be converted into an ivec3 before being added to Position.
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800114 TIntermSequence *constructOffsetIvecArguments = new TIntermSequence();
115 constructOffsetIvecArguments->push_back(sequence->at(3)->getAsTyped());
Shao11e43ec2016-08-11 09:54:08 +0800116
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800117 TIntermTyped *zeroNode = TIntermTyped::CreateZero(TType(EbtInt));
118 constructOffsetIvecArguments->push_back(zeroNode);
Shao11e43ec2016-08-11 09:54:08 +0800119
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800120 offsetNode = new TIntermAggregate(texCoordNode->getType(), EOpConstructIVec3,
121 constructOffsetIvecArguments);
122 offsetNode->setLine(texCoordNode->getLine());
Shao11e43ec2016-08-11 09:54:08 +0800123 }
124 else
125 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300126 offsetNode = sequence->at(3)->getAsTyped();
Shao11e43ec2016-08-11 09:54:08 +0800127 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300128
129 // Position+offset
130 TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
131 add->setLine(texCoordNode->getLine());
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800132 texelFetchArguments->push_back(add);
Shao11e43ec2016-08-11 09:54:08 +0800133
134 // lod
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800135 texelFetchArguments->push_back(sequence->at(2));
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100136
Olli Etuahoaf6fc1b2017-01-26 17:45:35 -0800137 ASSERT(texelFetchArguments->size() == 3u);
138
139 TIntermAggregate *texelFetchNode =
140 new TIntermAggregate(node->getType(), EOpCallBuiltInFunction, texelFetchArguments);
141 texelFetchNode->getFunctionSymbolInfo()->setName(newName);
142 texelFetchNode->getFunctionSymbolInfo()->setId(uniqueId);
143 texelFetchNode->setLine(node->getLine());
Shao11e43ec2016-08-11 09:54:08 +0800144
145 // Replace the old node by this new node.
146 queueReplacement(node, texelFetchNode, OriginalNode::IS_DROPPED);
147 mFound = true;
148 return false;
149}
150
151} // anonymous namespace
152
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500153void RewriteTexelFetchOffset(TIntermNode *root, const TSymbolTable &symbolTable, int shaderVersion)
Shao11e43ec2016-08-11 09:54:08 +0800154{
155 // texelFetchOffset is only valid in GLSL 3.0 and later.
156 if (shaderVersion < 300)
157 return;
158
Jiawei-Shaof9795242016-09-21 15:19:00 +0800159 Traverser::Apply(root, symbolTable, shaderVersion);
Shao11e43ec2016-08-11 09:54:08 +0800160}
161
162} // namespace sh