summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp141
1 files changed, 141 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp
new file mode 100644
index 0000000000..1a2aabf7dc
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDfdy.cpp
@@ -0,0 +1,141 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of dFdy viewport transformation.
+// See header for more info.
+
+#include "compiler/translator/tree_ops/RewriteDfdy.h"
+
+#include "common/angleutils.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/TranslatorVulkan.h"
+#include "compiler/translator/tree_util/DriverUniform.h"
+#include "compiler/translator/tree_util/IntermNode_util.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/tree_util/SpecializationConstant.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+ public:
+ Traverser(TSymbolTable *symbolTable, SpecConst *specConst, const DriverUniform *driverUniforms);
+
+ private:
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+
+ SpecConst *mSpecConst = nullptr;
+ const DriverUniform *mDriverUniforms = nullptr;
+};
+
+Traverser::Traverser(TSymbolTable *symbolTable,
+ SpecConst *specConst,
+ const DriverUniform *driverUniforms)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mSpecConst(specConst),
+ mDriverUniforms(driverUniforms)
+{}
+
+bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ // Decide if the node represents a call to dFdx() or dFdy()
+ if (node->getOp() != EOpDFdx && node->getOp() != EOpDFdy)
+ {
+ return true;
+ }
+
+ const bool isDFdx = node->getOp() == EOpDFdx;
+
+ // Two transformations are done on dFdx and dFdy:
+ //
+ // - If pre-rotation is applied, dFdx and dFdy may need to swap their axis based on the degree
+ // of rotation. dFdx becomes dFdy if rotation is 90 or 270 degrees. Similarly, dFdy becomes
+ // dFdx.
+ // - The result is potentially negated. This could be due to viewport y-flip or pre-rotation.
+ //
+ // Accordingly, there are two variables controlling the above transformations:
+ //
+ // - Rotation: A vec2 that is either (0, 1) or (1, 0). dFdx and dFdy are replaced with:
+ //
+ // dFdx * Rotation.x + dFdy * Rotation.y
+ //
+ // - Scale: A vec2 with -1 or 1 for either x or y components. The previous result is multiplied
+ // by this.
+ //
+ // Together, the above operations account for the combinations of 4 possible rotations and
+ // y-flip.
+
+ // Get the results of dFdx(operand) and dFdy(operand), and multiply them by the swizzles
+ TIntermTyped *operand = node->getChildNode(0)->getAsTyped();
+
+ TIntermTyped *dFdx = CreateBuiltInUnaryFunctionCallNode("dFdx", operand, *mSymbolTable, 300);
+ TIntermTyped *dFdy =
+ CreateBuiltInUnaryFunctionCallNode("dFdy", operand->deepCopy(), *mSymbolTable, 300);
+
+ // Get rotation multiplier
+ TIntermTyped *swapXY = mSpecConst->getSwapXY();
+ if (swapXY == nullptr)
+ {
+ swapXY = mDriverUniforms->getSwapXY();
+ }
+
+ TIntermTyped *swapXMultiplier = MakeSwapXMultiplier(swapXY);
+ TIntermTyped *swapYMultiplier = MakeSwapYMultiplier(swapXY->deepCopy());
+
+ // Get flip multiplier
+ TIntermTyped *flipXY = mDriverUniforms->getFlipXY(mSymbolTable, DriverUniformFlip::Fragment);
+
+ // Multiply the flip and rotation multipliers
+ TIntermTyped *xMultiplier =
+ new TIntermBinary(EOpMul, isDFdx ? swapXMultiplier : swapYMultiplier,
+ (new TIntermSwizzle(flipXY->deepCopy(), {0}))->fold(nullptr));
+ TIntermTyped *yMultiplier =
+ new TIntermBinary(EOpMul, isDFdx ? swapYMultiplier : swapXMultiplier,
+ (new TIntermSwizzle(flipXY->deepCopy(), {1}))->fold(nullptr));
+
+ const TOperator mulOp = dFdx->getType().isVector() ? EOpVectorTimesScalar : EOpMul;
+ TIntermTyped *rotatedFlippedDfdx = new TIntermBinary(mulOp, dFdx, xMultiplier);
+ TIntermTyped *rotatedFlippedDfdy = new TIntermBinary(mulOp, dFdy, yMultiplier);
+
+ // Sum them together into the result
+ TIntermBinary *rotatedFlippedResult =
+ new TIntermBinary(EOpAdd, rotatedFlippedDfdx, rotatedFlippedDfdy);
+
+ // Replace the old dFdx() or dFdy() node with the new node that contains the corrected value
+ //
+ // Note the following bugs (anglebug.com/7346):
+ //
+ // - Side effects of operand are duplicated with the above
+ // - If the direct child of this node is itself dFdx/y, its queueReplacement will not be
+ // effective as the parent is also replaced.
+ queueReplacement(rotatedFlippedResult, OriginalNode::IS_DROPPED);
+
+ return true;
+}
+} // anonymous namespace
+
+bool RewriteDfdy(TCompiler *compiler,
+ TIntermBlock *root,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ SpecConst *specConst,
+ const DriverUniform *driverUniforms)
+{
+ // dFdx/dFdy is only valid in GLSL 3.0 and later.
+ if (shaderVersion < 300)
+ {
+ return true;
+ }
+
+ Traverser traverser(symbolTable, specConst, driverUniforms);
+ root->traverse(&traverser);
+ return traverser.updateTree(compiler, root);
+}
+
+} // namespace sh