diff options
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.cpp | 141 |
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 |