1 //
2 // Copyright 2020 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 InterpolateAtOffset viewport transformation.
7 // See header for more info.
8
9 #include "compiler/translator/tree_ops/vulkan/RewriteInterpolateAtOffset.h"
10
11 #include "common/angleutils.h"
12 #include "compiler/translator/SymbolTable.h"
13 #include "compiler/translator/TranslatorVulkan.h"
14 #include "compiler/translator/tree_util/DriverUniform.h"
15 #include "compiler/translator/tree_util/IntermNode_util.h"
16 #include "compiler/translator/tree_util/IntermTraverse.h"
17 #include "compiler/translator/tree_util/SpecializationConstant.h"
18
19 namespace sh
20 {
21
22 namespace
23 {
24
25 class Traverser : public TIntermTraverser
26 {
27 public:
28 ANGLE_NO_DISCARD static bool Apply(TCompiler *compiler,
29 ShCompileOptions compileOptions,
30 TIntermNode *root,
31 const TSymbolTable &symbolTable,
32 int ShaderVersion,
33 SpecConst *specConst,
34 const DriverUniform *driverUniforms);
35
36 private:
37 Traverser(TSymbolTable *symbolTable,
38 ShCompileOptions compileOptions,
39 int shaderVersion,
40 SpecConst *specConst,
41 const DriverUniform *driverUniforms);
42 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
43
44 const TSymbolTable *symbolTable = nullptr;
45 const int shaderVersion;
46 SpecConst *mRotationSpecConst = nullptr;
47 const DriverUniform *mDriverUniforms = nullptr;
48 bool mUsePreRotation = false;
49 };
50
Traverser(TSymbolTable * symbolTable,ShCompileOptions compileOptions,int shaderVersion,SpecConst * specConst,const DriverUniform * driverUniforms)51 Traverser::Traverser(TSymbolTable *symbolTable,
52 ShCompileOptions compileOptions,
53 int shaderVersion,
54 SpecConst *specConst,
55 const DriverUniform *driverUniforms)
56 : TIntermTraverser(true, false, false, symbolTable),
57 symbolTable(symbolTable),
58 shaderVersion(shaderVersion),
59 mRotationSpecConst(specConst),
60 mDriverUniforms(driverUniforms),
61 mUsePreRotation((compileOptions & SH_ADD_PRE_ROTATION) != 0)
62 {}
63
64 // static
Apply(TCompiler * compiler,ShCompileOptions compileOptions,TIntermNode * root,const TSymbolTable & symbolTable,int shaderVersion,SpecConst * specConst,const DriverUniform * driverUniforms)65 bool Traverser::Apply(TCompiler *compiler,
66 ShCompileOptions compileOptions,
67 TIntermNode *root,
68 const TSymbolTable &symbolTable,
69 int shaderVersion,
70 SpecConst *specConst,
71 const DriverUniform *driverUniforms)
72 {
73 TSymbolTable *pSymbolTable = const_cast<TSymbolTable *>(&symbolTable);
74 Traverser traverser(pSymbolTable, compileOptions, shaderVersion, specConst, driverUniforms);
75 root->traverse(&traverser);
76 return traverser.updateTree(compiler, root);
77 }
78
visitAggregate(Visit visit,TIntermAggregate * node)79 bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
80 {
81 // Decide if the node represents the call of texelFetchOffset.
82 if (!BuiltInGroup::IsBuiltIn(node->getOp()))
83 {
84 return true;
85 }
86
87 ASSERT(node->getFunction()->symbolType() == SymbolType::BuiltIn);
88 if (node->getFunction()->name() != "interpolateAtOffset")
89 {
90 return true;
91 }
92
93 const TIntermSequence *sequence = node->getSequence();
94 ASSERT(sequence->size() == 2u);
95
96 TIntermSequence interpolateAtOffsetArguments;
97 // interpolant node
98 interpolateAtOffsetArguments.push_back(sequence->at(0));
99 // offset
100 TIntermTyped *offsetNode = sequence->at(1)->getAsTyped();
101 ASSERT(offsetNode->getType().getBasicType() == EbtFloat &&
102 offsetNode->getType().getNominalSize() == 2);
103
104 // If pre-rotation is enabled apply the transformation else just flip the Y-coordinate
105 TIntermTyped *rotatedXY;
106 TOperator mulOp = EOpMul;
107 if (mUsePreRotation)
108 {
109 rotatedXY = mRotationSpecConst->getFragRotationMultiplyFlipXY();
110 mulOp = EOpVectorTimesMatrix;
111 if (!rotatedXY)
112 {
113 TIntermTyped *fragRotation = mDriverUniforms->getFragRotationMatrixRef();
114 offsetNode = new TIntermBinary(EOpVectorTimesMatrix, offsetNode, fragRotation);
115
116 rotatedXY = mDriverUniforms->getFlipXYRef();
117 mulOp = EOpMul;
118 }
119 }
120 else
121 {
122 rotatedXY = mRotationSpecConst->getFlipXY();
123 if (!rotatedXY)
124 {
125 rotatedXY = mDriverUniforms->getFlipXYRef();
126 }
127 }
128
129 TIntermBinary *correctedOffset = new TIntermBinary(mulOp, offsetNode, rotatedXY);
130 correctedOffset->setLine(offsetNode->getLine());
131 interpolateAtOffsetArguments.push_back(correctedOffset);
132
133 TIntermTyped *interpolateAtOffsetNode = CreateBuiltInFunctionCallNode(
134 "interpolateAtOffset", &interpolateAtOffsetArguments, *symbolTable, shaderVersion);
135 interpolateAtOffsetNode->setLine(node->getLine());
136
137 // Replace the old node by this new node.
138 queueReplacement(interpolateAtOffsetNode, OriginalNode::IS_DROPPED);
139
140 return true;
141 }
142
143 } // anonymous namespace
144
RewriteInterpolateAtOffset(TCompiler * compiler,ShCompileOptions compileOptions,TIntermNode * root,const TSymbolTable & symbolTable,int shaderVersion,SpecConst * specConst,const DriverUniform * driverUniforms)145 bool RewriteInterpolateAtOffset(TCompiler *compiler,
146 ShCompileOptions compileOptions,
147 TIntermNode *root,
148 const TSymbolTable &symbolTable,
149 int shaderVersion,
150 SpecConst *specConst,
151 const DriverUniform *driverUniforms)
152 {
153 // interpolateAtOffset is only valid in GLSL 3.0 and later.
154 if (shaderVersion < 300)
155 {
156 return true;
157 }
158
159 return Traverser::Apply(compiler, compileOptions, root, symbolTable, shaderVersion, specConst,
160 driverUniforms);
161 }
162
163 } // namespace sh
164