Commit 11d7b952 by Ian Elliott Committed by Commit Bot

Vulkan: Pre-rotate dFdx() & dFdy() for Android

Test: angle_deqp_gles3_tests --gtest_filter=dEQP.GLES3/functional_shaders_derivate Test: angle_end2end_tests --gtest_filter=*EGLPreRotationSurfaceTest.OrientedWindow Bug: b/157476241 Change-Id: I7b60b7a33313ba91731755d289792bd0968515c6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2222825 Commit-Queue: Ian Elliott <ianelliott@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent ebc6d0a4
...@@ -996,9 +996,9 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -996,9 +996,9 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
{ {
TIntermBinary *flipXY = CreateDriverUniformRef(driverUniforms, kFlipXY); TIntermBinary *flipXY = CreateDriverUniformRef(driverUniforms, kFlipXY);
TVector<int> swizzleOffsetY = {1}; TIntermBinary *fragRotation = CreateDriverUniformRef(driverUniforms, kFragRotation);
TIntermSwizzle *flipY = new TIntermSwizzle(flipXY, swizzleOffsetY); if (!RewriteDfdy(this, root, getSymbolTable(), getShaderVersion(), flipXY,
if (!RewriteDfdy(this, root, getSymbolTable(), getShaderVersion(), flipY)) fragRotation))
{ {
return false; return false;
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "compiler/translator/tree_ops/RewriteDfdy.h" #include "compiler/translator/tree_ops/RewriteDfdy.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermNode_util.h" #include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h" #include "compiler/translator/tree_util/IntermTraverse.h"
...@@ -25,52 +26,116 @@ class Traverser : public TIntermTraverser ...@@ -25,52 +26,116 @@ class Traverser : public TIntermTraverser
ANGLE_NO_DISCARD static bool Apply(TCompiler *compiler, ANGLE_NO_DISCARD static bool Apply(TCompiler *compiler,
TIntermNode *root, TIntermNode *root,
const TSymbolTable &symbolTable, const TSymbolTable &symbolTable,
TIntermSwizzle *viewportYScale); TIntermBinary *flipXY,
TIntermTyped *fragRotation);
private: private:
Traverser(TIntermSwizzle *viewportYScale, TSymbolTable *symbolTable); Traverser(TIntermBinary *flipXY, TIntermTyped *fragRotation, TSymbolTable *symbolTable);
bool visitUnary(Visit visit, TIntermUnary *node) override; bool visitUnary(Visit visit, TIntermUnary *node) override;
TIntermSwizzle *mViewportYScale = nullptr; TIntermBinary *mFlipXY = nullptr;
TIntermTyped *mFragRotation = nullptr;
}; };
Traverser::Traverser(TIntermSwizzle *viewportYScale, TSymbolTable *symbolTable) Traverser::Traverser(TIntermBinary *flipXY, TIntermTyped *fragRotation, TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable), mViewportYScale(viewportYScale) : TIntermTraverser(true, false, false, symbolTable),
mFlipXY(flipXY),
mFragRotation(fragRotation)
{} {}
// static // static
bool Traverser::Apply(TCompiler *compiler, bool Traverser::Apply(TCompiler *compiler,
TIntermNode *root, TIntermNode *root,
const TSymbolTable &symbolTable, const TSymbolTable &symbolTable,
TIntermSwizzle *viewportYScale) TIntermBinary *flipXY,
TIntermTyped *fragRotation)
{ {
TSymbolTable *pSymbolTable = const_cast<TSymbolTable *>(&symbolTable); TSymbolTable *pSymbolTable = const_cast<TSymbolTable *>(&symbolTable);
Traverser traverser(viewportYScale, pSymbolTable); Traverser traverser(flipXY, fragRotation, pSymbolTable);
root->traverse(&traverser); root->traverse(&traverser);
return traverser.updateTree(compiler, root); return traverser.updateTree(compiler, root);
} }
bool Traverser::visitUnary(Visit visit, TIntermUnary *node) bool Traverser::visitUnary(Visit visit, TIntermUnary *node)
{ {
// Decide if the node represents a call to dFdy() // Decide if the node represents a call to dFdx() or dFdy()
if (node->getOp() != EOpDFdy) if ((node->getOp() != EOpDFdx) && (node->getOp() != EOpDFdy))
{ {
return true; return true;
} }
// Copy the dFdy node so we can replace it with the corrected value // Prior to supporting Android pre-rotation, dFdy() needed to be multiplied by mFlipXY.y:
TIntermUnary *newDfdy = node->deepCopy()->getAsUnaryNode(); //
// correctedDfdy(operand) = dFdy(operand) * mFlipXY.y
size_t objectSize = node->getType().getObjectSize(); //
TOperator multiplyOp = (objectSize == 1) ? EOpMul : EOpVectorTimesScalar; // 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
// Correct dFdy()'s value: // and 180 degrees. This rotation is accomplished with mFragRotation, which is a 2x2 matrix
// (dFdy() * ANGLEUniforms.viewportYScale) // used for fragment shader rotation. The 1st half (a vec2 that is either (1,0) or (0,1)) is
TIntermBinary *correctedDfdy = // used for rewriting dFdx() and the 2nd half (either (0,1) or (1,0)) is used for rewriting
new TIntermBinary(multiplyOp, newDfdy, mViewportYScale->deepCopy()); // 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));
}
// Replace the old dFdy node with the new node that contains the corrected value // Multiply halfRotationMat by ANGLEUniforms.flipXY and store in a temporary variable
queueReplacement(correctedDfdy, OriginalNode::IS_DROPPED); 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; return true;
} }
...@@ -81,13 +146,14 @@ bool RewriteDfdy(TCompiler *compiler, ...@@ -81,13 +146,14 @@ bool RewriteDfdy(TCompiler *compiler,
TIntermNode *root, TIntermNode *root,
const TSymbolTable &symbolTable, const TSymbolTable &symbolTable,
int shaderVersion, int shaderVersion,
TIntermSwizzle *viewportYScale) TIntermBinary *flipXY,
TIntermTyped *fragRotation)
{ {
// dFdy is only valid in GLSL 3.0 and later. // dFdy is only valid in GLSL 3.0 and later.
if (shaderVersion < 300) if (shaderVersion < 300)
return true; return true;
return Traverser::Apply(compiler, root, symbolTable, viewportYScale); return Traverser::Apply(compiler, root, symbolTable, flipXY, fragRotation);
} }
} // namespace sh } // namespace sh
...@@ -20,14 +20,16 @@ namespace sh ...@@ -20,14 +20,16 @@ namespace sh
class TCompiler; class TCompiler;
class TIntermNode; class TIntermNode;
class TIntermSwizzle; class TIntermBinary;
class TIntermTyped;
class TSymbolTable; class TSymbolTable;
ANGLE_NO_DISCARD bool RewriteDfdy(TCompiler *compiler, ANGLE_NO_DISCARD bool RewriteDfdy(TCompiler *compiler,
TIntermNode *root, TIntermNode *root,
const TSymbolTable &symbolTable, const TSymbolTable &symbolTable,
int shaderVersion, int shaderVersion,
TIntermSwizzle *viewportYScale); TIntermBinary *flipXY,
TIntermTyped *fragRotation);
} // namespace sh } // namespace sh
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment