Hash :
cbd5bee8
Author :
Date :
2020-07-13T20:31:29
Disable shader's pre-rotation code on Metal & non-Android. Pre-rotation code were added to transform gl_Position, gl_FragCoords, gl_PointCoords, dFdX, dFdY in shader. However, it is only useful for android's surface pre-rotation and completely un-needed in Metal back-end. This CL disables these pre-rotation code if the platform is not android. Bug: angleproject:4678 Change-Id: I89c42fcf24b49896f4ed9c2f9465da521beaf25f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2295000 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Ian Elliott <ianelliott@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
//
// 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/StaticType.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
class Traverser : public TIntermTraverser
{
public:
ANGLE_NO_DISCARD static bool Apply(TCompiler *compiler,
TIntermNode *root,
const TSymbolTable &symbolTable,
TIntermBinary *flipXY,
TIntermTyped *fragRotation);
private:
Traverser(TIntermBinary *flipXY, TIntermTyped *fragRotation, TSymbolTable *symbolTable);
bool visitUnary(Visit visit, TIntermUnary *node) override;
bool visitUnaryWithRotation(Visit visit, TIntermUnary *node);
bool visitUnaryWithoutRotation(Visit visit, TIntermUnary *node);
TIntermBinary *mFlipXY = nullptr;
TIntermTyped *mFragRotation = nullptr;
};
Traverser::Traverser(TIntermBinary *flipXY, TIntermTyped *fragRotation, TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable),
mFlipXY(flipXY),
mFragRotation(fragRotation)
{}
// static
bool Traverser::Apply(TCompiler *compiler,
TIntermNode *root,
const TSymbolTable &symbolTable,
TIntermBinary *flipXY,
TIntermTyped *fragRotation)
{
TSymbolTable *pSymbolTable = const_cast<TSymbolTable *>(&symbolTable);
Traverser traverser(flipXY, fragRotation, pSymbolTable);
root->traverse(&traverser);
return traverser.updateTree(compiler, root);
}
bool Traverser::visitUnary(Visit visit, TIntermUnary *node)
{
if (mFragRotation)
{
return visitUnaryWithRotation(visit, node);
}
return visitUnaryWithoutRotation(visit, node);
}
bool Traverser::visitUnaryWithRotation(Visit visit, TIntermUnary *node)
{
// Decide if the node represents a call to dFdx() or dFdy()
if ((node->getOp() != EOpDFdx) && (node->getOp() != EOpDFdy))
{
return true;
}
// Prior to supporting Android pre-rotation, dFdy() needed to be multiplied by mFlipXY.y:
//
// correctedDfdy(operand) = dFdy(operand) * mFlipXY.y
//
// For Android pre-rotation, both dFdx() and dFdy() need to be "rotated" and multiplied by
// mFlipXY. "Rotation" means to swap them for 90 and 270 degrees, or to not swap them for 0
// and 180 degrees. This rotation is accomplished with mFragRotation, which is a 2x2 matrix
// used for fragment shader rotation. The 1st half (a vec2 that is either (1,0) or (0,1)) is
// used for rewriting dFdx() and the 2nd half (either (0,1) or (1,0)) is used for rewriting
// dFdy(). Otherwise, the formula for the rewrite is the same:
//
// result = ((dFdx(operand) * (mFragRotation[half] * mFlipXY).x) +
// (dFdy(operand) * (mFragRotation[half] * mFlipXY).y))
//
// For dFdx(), half is 0 (the 1st half). For dFdy(), half is 1 (the 2nd half). Depending on
// the rotation, mFragRotation[half] will cause either dFdx(operand) or dFdy(operand) to be
// zeroed-out. That effectively means that the above code results in the following for 0 and
// 180 degrees:
//
// correctedDfdx(operand) = dFdx(operand) * mFlipXY.x
// correctedDfdy(operand) = dFdy(operand) * mFlipXY.y
//
// and the following for 90 and 270 degrees:
//
// correctedDfdx(operand) = dFdy(operand) * mFlipXY.y
// correctedDfdy(operand) = dFdx(operand) * mFlipXY.x
//
// TODO(ianelliott): Look at the performance of this approach and potentially optimize it
// http://anglebug.com/4678
// Get a vec2 with the correct half of ANGLEUniforms.fragRotation
TIntermBinary *halfRotationMat = nullptr;
if (node->getOp() == EOpDFdx)
{
halfRotationMat =
new TIntermBinary(EOpIndexDirect, mFragRotation->deepCopy(), CreateIndexNode(0));
}
else
{
halfRotationMat =
new TIntermBinary(EOpIndexDirect, mFragRotation->deepCopy(), CreateIndexNode(1));
}
// Multiply halfRotationMat by ANGLEUniforms.flipXY and store in a temporary variable
TIntermBinary *rotatedFlipXY = new TIntermBinary(EOpMul, mFlipXY->deepCopy(), halfRotationMat);
const TType *vec2Type = StaticType::GetBasic<EbtFloat, 2>();
TIntermSymbol *tmpRotFlipXY = new TIntermSymbol(CreateTempVariable(mSymbolTable, vec2Type));
TIntermSequence *tmpDecl = new TIntermSequence;
tmpDecl->push_back(CreateTempInitDeclarationNode(&tmpRotFlipXY->variable(), rotatedFlipXY));
insertStatementsInParentBlock(*tmpDecl);
// Get the .x and .y swizzles to use as multipliers
TVector<int> swizzleOffsetX = {0};
TVector<int> swizzleOffsetY = {1};
TIntermSwizzle *multiplierX = new TIntermSwizzle(tmpRotFlipXY, swizzleOffsetX);
TIntermSwizzle *multiplierY = new TIntermSwizzle(tmpRotFlipXY->deepCopy(), swizzleOffsetY);
// Get the results of dFdx(operand) and dFdy(operand), and multiply them by the swizzles
TIntermTyped *operand = node->getOperand();
TIntermUnary *dFdx = new TIntermUnary(EOpDFdx, operand->deepCopy(), node->getFunction());
TIntermUnary *dFdy = new TIntermUnary(EOpDFdy, operand->deepCopy(), node->getFunction());
size_t objectSize = node->getType().getObjectSize();
TOperator multiplyOp = (objectSize == 1) ? EOpMul : EOpVectorTimesScalar;
TIntermBinary *rotatedFlippedDfdx = new TIntermBinary(multiplyOp, dFdx, multiplierX);
TIntermBinary *rotatedFlippedDfdy = new TIntermBinary(multiplyOp, dFdy, multiplierY);
// Sum them together into the result:
TIntermBinary *correctedResult =
new TIntermBinary(EOpAdd, rotatedFlippedDfdx, rotatedFlippedDfdy);
// Replace the old dFdx() or dFdy() node with the new node that contains the corrected value
queueReplacement(correctedResult, OriginalNode::IS_DROPPED);
return true;
}
bool Traverser::visitUnaryWithoutRotation(Visit visit, TIntermUnary *node)
{
// Decide if the node represents a call to dFdy()
if (node->getOp() != EOpDFdy)
{
return true;
}
// Copy the dFdy node so we can replace it with the corrected value
TIntermUnary *newDfdy = node->deepCopy()->getAsUnaryNode();
size_t objectSize = node->getType().getObjectSize();
TOperator multiplyOp = (objectSize == 1) ? EOpMul : EOpVectorTimesScalar;
TIntermBinary *flipY =
new TIntermBinary(EOpIndexDirect, mFlipXY->deepCopy(), CreateIndexNode(1));
// Correct dFdy()'s value:
// (dFdy() * mFlipXY.y)
TIntermBinary *correctedDfdy = new TIntermBinary(multiplyOp, newDfdy, flipY);
// Replace the old dFdy node with the new node that contains the corrected value
queueReplacement(correctedDfdy, OriginalNode::IS_DROPPED);
return true;
}
} // anonymous namespace
bool RewriteDfdy(TCompiler *compiler,
TIntermNode *root,
const TSymbolTable &symbolTable,
int shaderVersion,
TIntermBinary *flipXY,
TIntermTyped *fragRotation)
{
// dFdy is only valid in GLSL 3.0 and later.
if (shaderVersion < 300)
return true;
return Traverser::Apply(compiler, root, symbolTable, flipXY, fragRotation);
}
} // namespace sh