Commit 901045cc by Ian Elliott Committed by Commit Bot

Vulkan: Rotate gl_FragCoord for Android pre-rotation

This extends the current y-flip that's done for gl_FragCoord. Now, gl_FragCoord is rotated and then flips both the x and y-axis. Bug: angleproject:4643 Bug: b/156395519 Change-Id: Iada8680eda8322f7382ff242e4a9422a66114f05 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2210936Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Ian Elliott <ianelliott@google.com>
parent 218a6835
......@@ -35,7 +35,7 @@ namespace
ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable,
TIntermBinary *negViewportYScale)
TIntermBinary *negFlipY)
{
// Create a symbol reference to "gl_Position"
const TVariable *position = BuiltInVariable::gl_Position();
......@@ -46,8 +46,8 @@ ANGLE_NO_DISCARD bool AppendVertexShaderPositionYCorrectionToMain(TCompiler *com
swizzleOffsetY.push_back(1);
TIntermSwizzle *positionY = new TIntermSwizzle(positionRef, swizzleOffsetY);
// Create the expression "gl_Position.y * negViewportScaleY"
TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), negViewportYScale);
// Create the expression "gl_Position.y * negFlipY"
TIntermBinary *inverseY = new TIntermBinary(EOpMul, positionY->deepCopy(), negFlipY);
// Create the assignment "gl_Position.y = gl_Position.y * negViewportScaleY
TIntermTyped *positionYLHS = positionY->deepCopy();
......@@ -81,11 +81,10 @@ bool TranslatorMetal::translate(TIntermBlock *root,
if (getShaderType() == GL_VERTEX_SHADER)
{
auto negViewportYScale = getDriverUniformNegViewportYScaleRef(driverUniforms);
auto negFlipY = getDriverUniformNegFlipYRef(driverUniforms);
// Append gl_Position.y correction to main
if (!AppendVertexShaderPositionYCorrectionToMain(this, root, &getSymbolTable(),
negViewportYScale))
if (!AppendVertexShaderPositionYCorrectionToMain(this, root, &getSymbolTable(), negFlipY))
{
return false;
}
......
......@@ -174,9 +174,10 @@ constexpr ImmutableString kLineRasterEmulationSpecConstVarName =
ImmutableString("ANGLELineRasterEmulation");
constexpr const char kViewport[] = "viewport";
constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight";
constexpr const char kHalfRenderArea[] = "halfRenderArea";
constexpr const char kFlipXY[] = "flipXY";
constexpr const char kViewportYScale[] = "viewportYScale";
constexpr const char kNegViewportYScale[] = "negViewportYScale";
constexpr const char kNegFlipY[] = "negFlipY";
constexpr const char kClipDistancesEnabled[] = "clipDistancesEnabled";
constexpr const char kXfbActiveUnpaused[] = "xfbActiveUnpaused";
constexpr const char kXfbVerticesPerDraw[] = "xfbVerticesPerDraw";
......@@ -184,12 +185,13 @@ constexpr const char kXfbBufferOffsets[] = "xfbBufferOffsets";
constexpr const char kAcbBufferOffsets[] = "acbBufferOffsets";
constexpr const char kDepthRange[] = "depthRange";
constexpr const char kPreRotation[] = "preRotation";
constexpr const char kFragRotation[] = "fragRotation";
constexpr size_t kNumGraphicsDriverUniforms = 11;
constexpr size_t kNumGraphicsDriverUniforms = 13;
constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {
{kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, kClipDistancesEnabled,
{kViewport, kHalfRenderArea, kFlipXY, kViewportYScale, kNegFlipY, kClipDistancesEnabled,
kXfbActiveUnpaused, kXfbVerticesPerDraw, kXfbBufferOffsets, kAcbBufferOffsets, kDepthRange,
kPreRotation}};
kPreRotation, kFragRotation}};
constexpr size_t kNumComputeDriverUniforms = 1;
constexpr std::array<const char *, kNumComputeDriverUniforms> kComputeDriverUniformNames = {
......@@ -274,6 +276,65 @@ ANGLE_NO_DISCARD bool FlipBuiltinVariable(TCompiler *compiler,
return compiler->validateAST(root);
}
// Replaces a builtin variable with a version that is rotated and corrects the X and Y coordinates.
ANGLE_NO_DISCARD bool RotateAndFlipBuiltinVariable(TCompiler *compiler,
TIntermBlock *root,
TIntermSequence *insertSequence,
TIntermTyped *flipXY,
TSymbolTable *symbolTable,
const TVariable *builtin,
const ImmutableString &flippedVariableName,
TIntermTyped *pivot,
TIntermTyped *fragRotation)
{
// Create a symbol reference to 'builtin'.
TIntermSymbol *builtinRef = new TIntermSymbol(builtin);
// Create a swizzle to "builtin.xy"
TVector<int> swizzleOffsetXY = {0, 1};
TIntermSwizzle *builtinXY = new TIntermSwizzle(builtinRef, swizzleOffsetXY);
// Create a symbol reference to our new variable that will hold the modified builtin.
const TType *type = StaticType::GetForVec<EbtFloat>(
EvqGlobal, static_cast<unsigned char>(builtin->getType().getNominalSize()));
TVariable *replacementVar =
new TVariable(symbolTable, flippedVariableName, type, SymbolType::AngleInternal);
DeclareGlobalVariable(root, replacementVar);
TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
// Use this new variable instead of 'builtin' everywhere.
if (!ReplaceVariable(compiler, root, builtin, replacementVar))
{
return false;
}
// Create the expression "(builtin.xy * fragRotation)"
TIntermBinary *rotatedXY =
new TIntermBinary(EOpMatrixTimesVector, fragRotation->deepCopy(), builtinXY->deepCopy());
// Create the expression "(builtin.xy - pivot) * flipXY + pivot
TIntermBinary *removePivot = new TIntermBinary(EOpSub, rotatedXY, pivot);
TIntermBinary *inverseXY = new TIntermBinary(EOpMul, removePivot, flipXY);
TIntermBinary *plusPivot = new TIntermBinary(EOpAdd, inverseXY, pivot->deepCopy());
// Create the corrected variable and copy the value of the original builtin.
TIntermSequence *sequence = new TIntermSequence();
sequence->push_back(builtinRef->deepCopy());
TIntermAggregate *aggregate = TIntermAggregate::CreateConstructor(builtin->getType(), sequence);
TIntermBinary *assignment = new TIntermBinary(EOpInitialize, flippedBuiltinRef, aggregate);
// Create an assignment to the replaced variable's .xy.
TIntermSwizzle *correctedXY =
new TIntermSwizzle(flippedBuiltinRef->deepCopy(), swizzleOffsetXY);
TIntermBinary *assignToY = new TIntermBinary(EOpAssign, correctedXY, plusPivot);
// Add this assigment at the beginning of the main function
insertSequence->insert(insertSequence->begin(), assignToY);
insertSequence->insert(insertSequence->begin(), assignment);
return compiler->validateAST(root);
}
TIntermSequence *GetMainSequence(TIntermBlock *root)
{
TIntermFunctionDefinition *main = FindMain(root);
......@@ -415,7 +476,8 @@ const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTa
const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
new TType(EbtFloat, 4),
new TType(EbtFloat),
new TType(EbtFloat, 2),
new TType(EbtFloat, 2),
new TType(EbtFloat),
new TType(EbtFloat),
new TType(EbtUInt), // uint clipDistancesEnabled; // 32 bits for 32 clip distances max
......@@ -426,6 +488,7 @@ const TVariable *AddGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTa
new TType(EbtUInt, 4),
emulatedDepthRangeType,
new TType(EbtFloat, 2, 2),
new TType(EbtFloat, 2, 2),
}};
for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
......@@ -575,10 +638,12 @@ ANGLE_NO_DISCARD bool InsertFragCoordCorrection(TCompiler *compiler,
TSymbolTable *symbolTable,
const TVariable *driverUniforms)
{
TIntermBinary *viewportYScale = CreateDriverUniformRef(driverUniforms, kViewportYScale);
TIntermBinary *pivot = CreateDriverUniformRef(driverUniforms, kHalfRenderAreaHeight);
return FlipBuiltinVariable(compiler, root, insertSequence, viewportYScale, symbolTable,
BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName, pivot);
TIntermBinary *flipXY = CreateDriverUniformRef(driverUniforms, kFlipXY);
TIntermBinary *pivot = CreateDriverUniformRef(driverUniforms, kHalfRenderArea);
TIntermBinary *fragRotation = CreateDriverUniformRef(driverUniforms, kFragRotation);
return RotateAndFlipBuiltinVariable(compiler, root, insertSequence, flipXY, symbolTable,
BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName,
pivot, fragRotation);
}
// This block adds OpenGL line segment rasterization emulation behind a specialization constant
......@@ -964,9 +1029,8 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
if (usesPointCoord)
{
TIntermBinary *viewportYScale =
CreateDriverUniformRef(driverUniforms, kNegViewportYScale);
TIntermConstantUnion *pivot = CreateFloatNode(0.5f);
TIntermBinary *viewportYScale = CreateDriverUniformRef(driverUniforms, kNegFlipY);
TIntermConstantUnion *pivot = CreateFloatNode(0.5f);
if (!FlipBuiltinVariable(this, root, GetMainSequence(root), viewportYScale,
&getSymbolTable(), BuiltInVariable::gl_PointCoord(),
kFlippedPointCoordName, pivot))
......@@ -1104,10 +1168,9 @@ bool TranslatorVulkan::shouldFlattenPragmaStdglInvariantAll()
return false;
}
TIntermBinary *TranslatorVulkan::getDriverUniformNegViewportYScaleRef(
const TVariable *driverUniforms) const
TIntermBinary *TranslatorVulkan::getDriverUniformNegFlipYRef(const TVariable *driverUniforms) const
{
return CreateDriverUniformRef(driverUniforms, kNegViewportYScale);
return CreateDriverUniformRef(driverUniforms, kNegFlipY);
}
TIntermBinary *TranslatorVulkan::getDriverUniformDepthRangeReservedFieldRef(
......
......@@ -30,7 +30,7 @@ class TranslatorVulkan : public TCompiler
PerformanceDiagnostics *perfDiagnostics) override;
bool shouldFlattenPragmaStdglInvariantAll() override;
TIntermBinary *getDriverUniformNegViewportYScaleRef(const TVariable *driverUniforms) const;
TIntermBinary *getDriverUniformNegFlipYRef(const TVariable *driverUniforms) const;
TIntermBinary *getDriverUniformDepthRangeReservedFieldRef(
const TVariable *driverUniforms) const;
// Subclass can call this method to transform the AST before writing the final output.
......
......@@ -377,7 +377,8 @@ class ContextMtl : public ContextImpl, public mtl::Context
{
float viewport[4];
float halfRenderAreaHeight;
float halfRenderArea[2];
float flipXY[2];
float viewportYScale;
float negViewportYScale;
......@@ -388,7 +389,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
uint32_t xfbActiveUnpaused;
uint32_t xfbVerticesPerDraw;
// NOTE: Explicit padding. Fill in with useful data when needed in the future.
int32_t padding[2];
int32_t padding[3];
int32_t xfbBufferOffsets[4];
uint32_t acbBufferOffsets[4];
......@@ -399,6 +400,10 @@ class ContextMtl : public ContextImpl, public mtl::Context
// Used to pre-rotate gl_Position for Vulkan swapchain images on Android (a mat2, which is
// padded to the size of two vec4's).
float preRotation[8];
// Used to pre-rotate gl_FragCoord for Vulkan swapchain images on Android (a mat2, which is
// padded to the size of two vec4's).
float fragRotation[8];
};
struct DefaultAttribute
......
......@@ -1594,8 +1594,12 @@ angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context)
mDriverUniforms.viewport[2] = glViewport.width;
mDriverUniforms.viewport[3] = glViewport.height;
mDriverUniforms.halfRenderAreaHeight =
mDriverUniforms.halfRenderArea[0] =
static_cast<float>(mDrawFramebuffer->getState().getDimensions().width) * 0.5f;
mDriverUniforms.halfRenderArea[1] =
static_cast<float>(mDrawFramebuffer->getState().getDimensions().height) * 0.5f;
mDriverUniforms.flipXY[0] = 1.0f;
mDriverUniforms.flipXY[1] = mDrawFramebuffer->flipY() ? -1.0f : 1.0f;
mDriverUniforms.viewportYScale = mDrawFramebuffer->flipY() ? -1.0f : 1.0f;
mDriverUniforms.negViewportYScale = -mDriverUniforms.viewportYScale;
......@@ -1616,6 +1620,16 @@ angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context)
mDriverUniforms.preRotation[6] = 0.0f;
mDriverUniforms.preRotation[7] = 0.0f;
// Fill in a mat2 identity matrix, plus padding
mDriverUniforms.fragRotation[0] = 1.0f;
mDriverUniforms.fragRotation[1] = 0.0f;
mDriverUniforms.fragRotation[2] = 0.0f;
mDriverUniforms.fragRotation[3] = 0.0f;
mDriverUniforms.fragRotation[4] = 0.0f;
mDriverUniforms.fragRotation[5] = 1.0f;
mDriverUniforms.fragRotation[6] = 0.0f;
mDriverUniforms.fragRotation[7] = 0.0f;
ASSERT(mRenderEncoder.valid());
mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex);
......
......@@ -52,17 +52,25 @@ struct GraphicsDriverUniforms
{
std::array<float, 4> viewport;
float halfRenderAreaHeight;
// Used to flip gl_FragCoord (both .xy for Android pre-rotation; only .y for desktop)
std::array<float, 2> halfRenderArea;
std::array<float, 2> flipXY;
// TODO(ianelliott): Remove the following while doing pre-rotation for gl_PointCoord & dFdy()
// https://issuetracker.google.com/issues/157476696
// https://issuetracker.google.com/issues/157476241
float viewportYScale;
float negViewportYScale;
float negFlipY;
// 32 bits for 32 clip planes
uint32_t enabledClipPlanes;
uint32_t xfbActiveUnpaused;
uint32_t xfbVerticesPerDraw;
// TODO(ianelliott): Remove the following while doing pre-rotation for gl_PointCoord
// https://issuetracker.google.com/issues/157476696
// https://issuetracker.google.com/issues/157476241
// NOTE: Explicit padding. Fill in with useful data when needed in the future.
std::array<int32_t, 2> padding;
std::array<int32_t, 3> padding;
std::array<int32_t, 4> xfbBufferOffsets;
......@@ -79,6 +87,9 @@ struct GraphicsDriverUniforms
// Used to pre-rotate gl_Position for swapchain images on Android (a mat2, which is padded to
// the size of two vec4's).
std::array<float, 8> preRotation;
// Used to pre-rotate gl_FragCoord for swapchain images on Android (a mat2, which is padded to
// the size of two vec4's).
std::array<float, 8> fragRotation;
};
struct ComputeDriverUniforms
......@@ -189,7 +200,8 @@ void ApplySampleCoverage(const gl::State &glState,
}
// When an Android surface is rotated differently than the device's native orientation, ANGLE must
// rotate gl_Position in the vertex shader. The following are the rotation matrices used.
// rotate gl_Position in the vertex shader and gl_FragCoord in the fragment shader. The following
// are the rotation matrices used.
//
// Note: these are mat2's that are appropriately padded (4 floats per row).
using PreRotationMatrixValues = std::array<float, 8>;
......@@ -213,6 +225,25 @@ constexpr angle::PackedEnumMap<rx::SurfaceRotation,
{rx::SurfaceRotation::FlippedRotated270Degrees,
{{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}}}};
constexpr angle::PackedEnumMap<rx::SurfaceRotation,
PreRotationMatrixValues,
angle::EnumSize<rx::SurfaceRotation>()>
kFragRotationMatrices = {
{{rx::SurfaceRotation::Identity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::Rotated90Degrees,
{{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::Rotated180Degrees,
{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::Rotated270Degrees,
{{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedIdentity, {{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedRotated90Degrees,
{{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedRotated180Degrees,
{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}}},
{rx::SurfaceRotation::FlippedRotated270Degrees,
{{0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}}}}};
bool IsRotatedAspectRatio(SurfaceRotation rotation)
{
return ((rotation == SurfaceRotation::Rotated90Degrees) ||
......@@ -3368,17 +3399,50 @@ angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(const gl::Context *co
&newBuffer));
gl::Rectangle glViewport = mState.getViewport();
float halfRenderAreaWidth =
static_cast<float>(mDrawFramebuffer->getState().getDimensions().width) * 0.5f;
float halfRenderAreaHeight =
static_cast<float>(mDrawFramebuffer->getState().getDimensions().height) * 0.5f;
if (isRotatedAspectRatioForDrawFBO())
{
// The surface is rotated 90/270 degrees. This changes the aspect ratio of the surface.
// TODO(ianelliott): handle small viewport/scissor cases. http://anglebug.com/4431
std::swap(glViewport.x, glViewport.y);
std::swap(glViewport.width, glViewport.height);
halfRenderAreaHeight =
static_cast<float>(mDrawFramebuffer->getState().getDimensions().width) * 0.5f;
}
float scaleY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
float flipX = 1.0f;
float flipY = -1.0f;
// Y-axis flipping only comes into play with the default framebuffer (i.e. a swapchain image).
// For 0-degree rotation, an FBO or pbuffer could be the draw framebuffer, and so we must check
// whether flipY should be positive or negative. All other rotations, will be to the default
// framebuffer, and so the value of isViewportFlipEnabledForDrawFBO() is assumed true; the
// appropriate flipY value is chosen such that gl_FragCoord is positioned at the lower-left
// corner of the window.
switch (mCurrentRotationDrawFramebuffer)
{
case SurfaceRotation::Identity:
flipX = 1.0f;
flipY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
break;
case SurfaceRotation::Rotated90Degrees:
ASSERT(isViewportFlipEnabledForDrawFBO());
flipX = 1.0f;
flipY = 1.0f;
std::swap(halfRenderAreaWidth, halfRenderAreaHeight);
break;
case SurfaceRotation::Rotated180Degrees:
ASSERT(isViewportFlipEnabledForDrawFBO());
flipX = -1.0f;
flipY = 1.0f;
break;
case SurfaceRotation::Rotated270Degrees:
ASSERT(isViewportFlipEnabledForDrawFBO());
flipX = -1.0f;
flipY = -1.0f;
break;
default:
UNREACHABLE();
break;
}
uint32_t xfbActiveUnpaused = mState.isTransformFeedbackActiveUnpaused();
......@@ -3391,9 +3455,10 @@ angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(const gl::Context *co
*driverUniforms = {
{static_cast<float>(glViewport.x), static_cast<float>(glViewport.y),
static_cast<float>(glViewport.width), static_cast<float>(glViewport.height)},
halfRenderAreaHeight,
scaleY,
-scaleY,
{halfRenderAreaWidth, halfRenderAreaHeight},
{flipX, flipY},
flipY,
-flipY,
mState.getEnabledClipDistances().bits(),
xfbActiveUnpaused,
mXfbVertexCountPerInstance,
......@@ -3401,9 +3466,12 @@ angle::Result ContextVk::handleDirtyGraphicsDriverUniforms(const gl::Context *co
{},
{},
{depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f},
{},
{}};
memcpy(&driverUniforms->preRotation, &kPreRotationMatrices[mCurrentRotationDrawFramebuffer],
sizeof(PreRotationMatrixValues));
memcpy(&driverUniforms->fragRotation, &kFragRotationMatrices[mCurrentRotationDrawFramebuffer],
sizeof(PreRotationMatrixValues));
if (xfbActiveUnpaused)
{
......
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