RewriteTexelFetchOffset.cpp (5098B)
1 // 2 // Copyright 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/tree_ops/RewriteTexelFetchOffset.h" 10 11 #include "common/angleutils.h" 12 #include "compiler/translator/SymbolTable.h" 13 #include "compiler/translator/tree_util/IntermNode_util.h" 14 #include "compiler/translator/tree_util/IntermTraverse.h" 15 16 namespace sh 17 { 18 19 namespace 20 { 21 22 class Traverser : public TIntermTraverser 23 { 24 public: 25 [[nodiscard]] static bool Apply(TCompiler *compiler, 26 TIntermNode *root, 27 const TSymbolTable &symbolTable, 28 int shaderVersion); 29 30 private: 31 Traverser(const TSymbolTable &symbolTable, int shaderVersion); 32 bool visitAggregate(Visit visit, TIntermAggregate *node) override; 33 void nextIteration(); 34 35 const TSymbolTable *symbolTable; 36 const int shaderVersion; 37 bool mFound = false; 38 }; 39 40 Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion) 41 : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion) 42 {} 43 44 // static 45 bool Traverser::Apply(TCompiler *compiler, 46 TIntermNode *root, 47 const TSymbolTable &symbolTable, 48 int shaderVersion) 49 { 50 Traverser traverser(symbolTable, shaderVersion); 51 do 52 { 53 traverser.nextIteration(); 54 root->traverse(&traverser); 55 if (traverser.mFound) 56 { 57 if (!traverser.updateTree(compiler, root)) 58 { 59 return false; 60 } 61 } 62 } while (traverser.mFound); 63 64 return true; 65 } 66 67 void Traverser::nextIteration() 68 { 69 mFound = false; 70 } 71 72 bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) 73 { 74 if (mFound) 75 { 76 return false; 77 } 78 79 // Decide if the node represents the call of texelFetchOffset. 80 if (!BuiltInGroup::IsBuiltIn(node->getOp())) 81 { 82 return true; 83 } 84 85 ASSERT(node->getFunction()->symbolType() == SymbolType::BuiltIn); 86 if (node->getFunction()->name() != "texelFetchOffset") 87 { 88 return true; 89 } 90 91 // Potential problem case detected, apply workaround. 92 const TIntermSequence *sequence = node->getSequence(); 93 ASSERT(sequence->size() == 4u); 94 95 // Decide if the sampler is a 2DArray sampler. In that case position is ivec3 and offset is 96 // ivec2. 97 bool is2DArray = sequence->at(1)->getAsTyped()->getNominalSize() == 3 && 98 sequence->at(3)->getAsTyped()->getNominalSize() == 2; 99 100 // Create new node that represents the call of function texelFetch. 101 // Its argument list will be: texelFetch(sampler, Position+offset, lod). 102 103 TIntermSequence texelFetchArguments; 104 105 // sampler 106 texelFetchArguments.push_back(sequence->at(0)); 107 108 // Position 109 TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped(); 110 ASSERT(texCoordNode); 111 112 // offset 113 TIntermTyped *offsetNode = nullptr; 114 ASSERT(sequence->at(3)->getAsTyped()); 115 if (is2DArray) 116 { 117 // For 2DArray samplers, Position is ivec3 and offset is ivec2; 118 // So offset must be converted into an ivec3 before being added to Position. 119 TIntermSequence constructOffsetIvecArguments; 120 constructOffsetIvecArguments.push_back(sequence->at(3)->getAsTyped()); 121 122 TIntermTyped *zeroNode = CreateZeroNode(TType(EbtInt)); 123 constructOffsetIvecArguments.push_back(zeroNode); 124 125 offsetNode = TIntermAggregate::CreateConstructor(texCoordNode->getType(), 126 &constructOffsetIvecArguments); 127 offsetNode->setLine(texCoordNode->getLine()); 128 } 129 else 130 { 131 offsetNode = sequence->at(3)->getAsTyped(); 132 } 133 134 // Position+offset 135 TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode); 136 add->setLine(texCoordNode->getLine()); 137 texelFetchArguments.push_back(add); 138 139 // lod 140 texelFetchArguments.push_back(sequence->at(2)); 141 142 ASSERT(texelFetchArguments.size() == 3u); 143 144 TIntermTyped *texelFetchNode = CreateBuiltInFunctionCallNode("texelFetch", &texelFetchArguments, 145 *symbolTable, shaderVersion); 146 texelFetchNode->setLine(node->getLine()); 147 148 // Replace the old node by this new node. 149 queueReplacement(texelFetchNode, OriginalNode::IS_DROPPED); 150 mFound = true; 151 return false; 152 } 153 154 } // anonymous namespace 155 156 bool RewriteTexelFetchOffset(TCompiler *compiler, 157 TIntermNode *root, 158 const TSymbolTable &symbolTable, 159 int shaderVersion) 160 { 161 // texelFetchOffset is only valid in GLSL 3.0 and later. 162 if (shaderVersion < 300) 163 return true; 164 165 return Traverser::Apply(compiler, root, symbolTable, shaderVersion); 166 } 167 168 } // namespace sh