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