Commit fb19e084 by Jamie Madill Committed by Commit Bot

Vulkan: Correct gl_FragCoord with default FBO.

The viewport flipping we use would give incorrect values. Correct them using the same logic we do for gl_PointCoord. Also corrects the viewport scale driver uniform. It was not being updated after the draw framebuffer setting was adjusted. Also corrects the naming of the replaced builtin variables so it can't possibly conflict with a user variable. This was affecting the OpenGL line raster emulation. Bug: angleproject:2598 Change-Id: I843b5ac7b02160a5ec81a6f8ed2d937b0937198b Reviewed-on: https://chromium-review.googlesource.com/1208515Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 55b03d0e
...@@ -150,81 +150,84 @@ class DeclareDefaultUniformsTraverser : public TIntermTraverser ...@@ -150,81 +150,84 @@ class DeclareDefaultUniformsTraverser : public TIntermTraverser
}; };
constexpr ImmutableString kFlippedPointCoordName = ImmutableString("flippedPointCoord"); constexpr ImmutableString kFlippedPointCoordName = ImmutableString("flippedPointCoord");
constexpr ImmutableString kFlippedFragCoordName = ImmutableString("flippedFragCoord");
constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams"); constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
// Declares a new variable to replace gl_PointCoord with a version that is flipping the Y TIntermConstantUnion *CreateConstantFloat(float value)
// coordinate. {
void FlipGLPointCoord(TIntermBlock *root, const TType *constantType = StaticType::GetBasic<TBasicType::EbtFloat>();
const TVariable *driverUniforms, TConstantUnion *constantValue = new TConstantUnion();
TSymbolTable *symbolTable) constantValue->setFConst(value);
return new TIntermConstantUnion(constantValue, *constantType);
}
TIntermBinary *CreateDriverUniformRef(const TVariable *driverUniforms, int fieldIndex)
{ {
// Create a symbol reference to "gl_PointCoord" TIntermSymbol *angleUniformsRef = new TIntermSymbol(driverUniforms);
const TVariable *pointCoord = BuiltInVariable::gl_PointCoord(); TConstantUnion *uniformIndex = new TConstantUnion;
TIntermSymbol *pointCoordRef = new TIntermSymbol(pointCoord); uniformIndex->setIConst(fieldIndex);
TIntermConstantUnion *indexRef =
new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt>());
return new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, indexRef);
}
// Create a swizzle to "gl_PointCoord.x" // Replaces a builtin variable with a version that corrects the Y coordinate.
TVector<int> swizzleOffsetX; void FlipBuiltinVariable(TIntermBlock *root,
swizzleOffsetX.push_back(0); const TVariable *driverUniforms,
TIntermSwizzle *pointCoordX = new TIntermSwizzle(pointCoordRef, swizzleOffsetX); int driverUniformSwizzleIndex,
TSymbolTable *symbolTable,
const TVariable *builtin,
const ImmutableString &flippedVariableName,
TIntermTyped *pivot)
{
// Create a symbol reference to 'builtin'.
TIntermSymbol *builtinRef = new TIntermSymbol(builtin);
// Create a swizzle to "gl_PointCoord.y" // Create a swizzle to "builtin.y"
TVector<int> swizzleOffsetY; TVector<int> swizzleOffsetY;
swizzleOffsetY.push_back(1); swizzleOffsetY.push_back(1);
TIntermSwizzle *pointCoordY = new TIntermSwizzle(pointCoordRef, swizzleOffsetY); TIntermSwizzle *builtinY = new TIntermSwizzle(builtinRef, swizzleOffsetY);
// Create a symbol reference to our new variable that will hold the modified gl_PointCoord. // 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 = TVariable *replacementVar =
new TVariable(symbolTable, kFlippedPointCoordName, new TVariable(symbolTable, flippedVariableName, type, SymbolType::AngleInternal);
StaticType::Helpers::GetForVecMatHelper<EbtFloat, EbpMedium, EvqGlobal, 1>(2),
SymbolType::UserDefined);
DeclareGlobalVariable(root, replacementVar); DeclareGlobalVariable(root, replacementVar);
TIntermSymbol *flippedPointCoordsRef = new TIntermSymbol(replacementVar); TIntermSymbol *flippedBuiltinRef = new TIntermSymbol(replacementVar);
const TType *constantType = StaticType::GetBasic<EbtFloat>(); // Use this new variable instead of 'builtin' everywhere.
ReplaceVariable(root, builtin, replacementVar);
// Create a constant "0.5"
TConstantUnion *constantValuePointFive = new TConstantUnion();
constantValuePointFive->setFConst(0.5f);
TIntermConstantUnion *pointFive =
new TIntermConstantUnion(constantValuePointFive, *constantType);
// ANGLEUniforms.viewportScaleFactor // ANGLEUniforms.viewportScaleFactor
TIntermSymbol *angleUniformsRef = new TIntermSymbol(driverUniforms); TIntermBinary *viewportScaleFactorRef = CreateDriverUniformRef(driverUniforms, 1);
TConstantUnion *viewportScaleFactorConstant = new TConstantUnion;
viewportScaleFactorConstant->setIConst(1); // Creates a swizzle to ANGLEUniforms.viewportScaleFactor[index]
TIntermConstantUnion *viewportScaleFactorIndex =
new TIntermConstantUnion(viewportScaleFactorConstant, *StaticType::GetBasic<EbtInt>());
TIntermBinary *viewportScaleFactorRef =
new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, viewportScaleFactorIndex);
// Creates a swizzle to ANGLEUniforms.viewportScaleFactor.y
TVector<int> viewportScaleSwizzleOffsetY; TVector<int> viewportScaleSwizzleOffsetY;
viewportScaleSwizzleOffsetY.push_back(1); viewportScaleSwizzleOffsetY.push_back(driverUniformSwizzleIndex);
TIntermSwizzle *viewportScaleY = TIntermSwizzle *viewportScaleY =
new TIntermSwizzle(viewportScaleFactorRef->deepCopy(), viewportScaleSwizzleOffsetY); new TIntermSwizzle(viewportScaleFactorRef->deepCopy(), viewportScaleSwizzleOffsetY);
// Create the expression "(gl_PointCoord.y - 0.5) * ANGLEUniforms.viewportScaleFactor.y + // Create the expression "(builtin.y - pivot) * ANGLEUniforms.viewportScaleFactor[index] +
// 0.5 // pivot
TIntermBinary *removePointFive = new TIntermBinary(EOpSub, pointCoordY, pointFive); TIntermBinary *removePivot = new TIntermBinary(EOpSub, builtinY, pivot);
TIntermBinary *inverseY = new TIntermBinary(EOpMul, removePointFive, viewportScaleY); TIntermBinary *inverseY = new TIntermBinary(EOpMul, removePivot, viewportScaleY);
TIntermBinary *plusPointFive = new TIntermBinary(EOpAdd, inverseY, pointFive->deepCopy()); TIntermBinary *plusPivot = new TIntermBinary(EOpAdd, inverseY, pivot->deepCopy());
// Create the new vec2 using the modified Y // Create the corrected variable and copy the value of the original builtin.
TIntermSequence *sequence = new TIntermSequence(); TIntermSequence *sequence = new TIntermSequence();
sequence->push_back(pointCoordX); sequence->push_back(builtinRef);
sequence->push_back(plusPointFive); TIntermAggregate *aggregate = TIntermAggregate::CreateConstructor(builtin->getType(), sequence);
TIntermAggregate *aggregate = TIntermBinary *assignment = new TIntermBinary(EOpInitialize, flippedBuiltinRef, aggregate);
TIntermAggregate::CreateConstructor(BuiltInVariable::gl_PointCoord()->getType(), sequence);
// Use this new variable instead of gl_PointCoord everywhere. // Create an assignment to the replaced variable's y.
ReplaceVariable(root, pointCoord, replacementVar); TIntermSwizzle *correctedY = new TIntermSwizzle(flippedBuiltinRef, swizzleOffsetY);
TIntermBinary *assignToY = new TIntermBinary(EOpAssign, correctedY, plusPivot);
// Assign this new value to flippedPointCoord
TIntermBinary *assignment = new TIntermBinary(EOpInitialize, flippedPointCoordsRef, aggregate);
// Add this assigment at the beginning of the main function // Add this assigment at the beginning of the main function
TIntermFunctionDefinition *main = FindMain(root); TIntermFunctionDefinition *main = FindMain(root);
TIntermSequence *mainSequence = main->getBody()->getSequence(); TIntermSequence *mainSequence = main->getBody()->getSequence();
mainSequence->insert(mainSequence->begin(), assignToY);
mainSequence->insert(mainSequence->begin(), assignment); mainSequence->insert(mainSequence->begin(), assignment);
} }
...@@ -238,13 +241,7 @@ void ReplaceGLDepthRangeWithDriverUniform(TIntermBlock *root, ...@@ -238,13 +241,7 @@ void ReplaceGLDepthRangeWithDriverUniform(TIntermBlock *root,
symbolTable->findBuiltIn(ImmutableString("gl_DepthRange"), 0)); symbolTable->findBuiltIn(ImmutableString("gl_DepthRange"), 0));
// ANGLEUniforms.depthRange // ANGLEUniforms.depthRange
TIntermSymbol *angleUniformsRef = new TIntermSymbol(driverUniforms); TIntermBinary *angleEmulatedDepthRangeRef = CreateDriverUniformRef(driverUniforms, 2);
TConstantUnion *depthRangeConstant = new TConstantUnion;
depthRangeConstant->setIConst(2);
TIntermConstantUnion *depthRangeIndex =
new TIntermConstantUnion(depthRangeConstant, *StaticType::GetBasic<EbtInt>());
TIntermBinary *angleEmulatedDepthRangeRef =
new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, depthRangeIndex);
// Use this variable instead of gl_DepthRange everywhere. // Use this variable instead of gl_DepthRange everywhere.
ReplaceVariableWithTyped(root, depthRangeVar, angleEmulatedDepthRangeRef); ReplaceVariableWithTyped(root, depthRangeVar, angleEmulatedDepthRangeRef);
...@@ -271,10 +268,7 @@ void AppendVertexShaderDepthCorrectionToMain(TIntermBlock *root, TSymbolTable *s ...@@ -271,10 +268,7 @@ void AppendVertexShaderDepthCorrectionToMain(TIntermBlock *root, TSymbolTable *s
TIntermSwizzle *positionZ = new TIntermSwizzle(positionRef, swizzleOffsetZ); TIntermSwizzle *positionZ = new TIntermSwizzle(positionRef, swizzleOffsetZ);
// Create a constant "0.5" // Create a constant "0.5"
const TType *constantType = StaticType::GetBasic<TBasicType::EbtFloat>(); TIntermConstantUnion *oneHalf = CreateConstantFloat(0.5f);
TConstantUnion *constantValue = new TConstantUnion();
constantValue->setFConst(0.5f);
TIntermConstantUnion *oneHalf = new TIntermConstantUnion(constantValue, *constantType);
// Create a swizzle to "gl_Position.w" // Create a swizzle to "gl_Position.w"
TVector<int> swizzleOffsetW; TVector<int> swizzleOffsetW;
...@@ -424,9 +418,9 @@ void TranslatorVulkan::translate(TIntermBlock *root, ...@@ -424,9 +418,9 @@ void TranslatorVulkan::translate(TIntermBlock *root,
sink << "};\n"; sink << "};\n";
} }
const TVariable *driverUniformsVariable = AddDriverUniformsToShader(root, &getSymbolTable()); const TVariable *driverUniforms = AddDriverUniformsToShader(root, &getSymbolTable());
ReplaceGLDepthRangeWithDriverUniform(root, driverUniformsVariable, &getSymbolTable()); ReplaceGLDepthRangeWithDriverUniform(root, driverUniforms, &getSymbolTable());
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
// if it's core profile shaders and they are used. // if it's core profile shaders and they are used.
...@@ -470,7 +464,25 @@ void TranslatorVulkan::translate(TIntermBlock *root, ...@@ -470,7 +464,25 @@ void TranslatorVulkan::translate(TIntermBlock *root,
if (inputVarying.name == "gl_PointCoord") if (inputVarying.name == "gl_PointCoord")
{ {
FlipGLPointCoord(root, driverUniformsVariable, &getSymbolTable()); TIntermConstantUnion *pivot = CreateConstantFloat(0.5f);
FlipBuiltinVariable(root, driverUniforms, 1, &getSymbolTable(),
BuiltInVariable::gl_PointCoord(), kFlippedPointCoordName,
pivot);
break;
}
if (inputVarying.name == "gl_FragCoord")
{
// Create a reference to ANGLEDriverUniforms.viewport.w * 0.5
TIntermBinary *viewportRef = CreateDriverUniformRef(driverUniforms, 0);
TVector<int> swizzleOffset;
swizzleOffset.push_back(3);
TIntermSwizzle *viewportSwizzle = new TIntermSwizzle(viewportRef, swizzleOffset);
TIntermTyped *oneHalf = CreateConstantFloat(0.5f);
TIntermBinary *pivot = new TIntermBinary(EOpMul, viewportSwizzle, oneHalf);
FlipBuiltinVariable(root, driverUniforms, 3, &getSymbolTable(),
BuiltInVariable::gl_FragCoord(), kFlippedFragCoordName, pivot);
break; break;
} }
} }
......
...@@ -789,7 +789,6 @@ gl::Error ContextVk::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -789,7 +789,6 @@ gl::Error ContextVk::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING: case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
{ {
mDrawFramebuffer = vk::GetImpl(glState.getDrawFramebuffer()); mDrawFramebuffer = vk::GetImpl(glState.getDrawFramebuffer());
ANGLE_TRY(updateDriverUniforms(glState));
updateFlipViewportDrawFramebuffer(glState); updateFlipViewportDrawFramebuffer(glState);
mPipelineDesc->updateViewport(mDrawFramebuffer, glState.getViewport(), mPipelineDesc->updateViewport(mDrawFramebuffer, glState.getViewport(),
glState.getNearPlane(), glState.getFarPlane(), glState.getNearPlane(), glState.getFarPlane(),
...@@ -807,6 +806,7 @@ gl::Error ContextVk::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -807,6 +806,7 @@ gl::Error ContextVk::syncState(const gl::Context *context, const gl::State::Dirt
glState.getDrawFramebuffer()); glState.getDrawFramebuffer());
mPipelineDesc->updateStencilBackWriteMask(glState.getDepthStencilState(), mPipelineDesc->updateStencilBackWriteMask(glState.getDepthStencilState(),
glState.getDrawFramebuffer()); glState.getDrawFramebuffer());
ANGLE_TRY(updateDriverUniforms(glState));
break; break;
} }
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING: case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
...@@ -1096,7 +1096,7 @@ angle::Result ContextVk::updateDriverUniforms(const gl::State &glState) ...@@ -1096,7 +1096,7 @@ angle::Result ContextVk::updateDriverUniforms(const gl::State &glState)
bool newBufferAllocated = false; bool newBufferAllocated = false;
ANGLE_TRY(mDriverUniformsBuffer.allocate(this, sizeof(DriverUniforms), &ptr, &buffer, &offset, ANGLE_TRY(mDriverUniformsBuffer.allocate(this, sizeof(DriverUniforms), &ptr, &buffer, &offset,
&newBufferAllocated)); &newBufferAllocated));
float scaleY = isViewportFlipEnabledForDrawFBO() ? 1.0f : -1.0f; float scaleY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
float depthRangeNear = glState.getNearPlane(); float depthRangeNear = glState.getNearPlane();
float depthRangeFar = glState.getFarPlane(); float depthRangeFar = glState.getFarPlane();
...@@ -1107,7 +1107,7 @@ angle::Result ContextVk::updateDriverUniforms(const gl::State &glState) ...@@ -1107,7 +1107,7 @@ angle::Result ContextVk::updateDriverUniforms(const gl::State &glState)
*driverUniforms = { *driverUniforms = {
{static_cast<float>(glViewport.x), static_cast<float>(glViewport.y), {static_cast<float>(glViewport.x), static_cast<float>(glViewport.y),
static_cast<float>(glViewport.width), static_cast<float>(glViewport.height)}, static_cast<float>(glViewport.width), static_cast<float>(glViewport.height)},
{1.0f, scaleY, 1.0f, 1.0f}, {1.0f, -scaleY, 1.0f, scaleY},
{depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}}; {depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}};
ANGLE_TRY(mDriverUniformsBuffer.flush(this)); ANGLE_TRY(mDriverUniformsBuffer.flush(this));
......
...@@ -4774,6 +4774,116 @@ TEST_P(GLSLTest, IfElseIfAndReturn) ...@@ -4774,6 +4774,116 @@ TEST_P(GLSLTest, IfElseIfAndReturn)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Tests that PointCoord behaves the same betweeen a user FBO and the back buffer.
TEST_P(GLSLTest, PointCoordConsistency)
{
// On Intel Windows OpenGL drivers PointCoord appears to be flipped when drawing to the
// default framebuffer. http://anglebug.com/2805
ANGLE_SKIP_TEST_IF(IsIntel() && IsWindows() && IsOpenGL());
// AMD's OpenGL drivers may have the same issue. http://anglebug.com/1643
ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
constexpr char kPointCoordVS[] = R"(attribute vec2 position;
uniform vec2 viewportSize;
void main()
{
gl_Position = vec4(position, 0, 1);
gl_PointSize = viewportSize.x;
})";
constexpr char kPointCoordFS[] = R"(void main()
{
gl_FragColor = vec4(gl_PointCoord.xy, 0, 1);
})";
ANGLE_GL_PROGRAM(program, kPointCoordVS, kPointCoordFS);
glUseProgram(program);
GLint uniLoc = glGetUniformLocation(program, "viewportSize");
ASSERT_NE(-1, uniLoc);
glUniform2f(uniLoc, getWindowWidth(), getWindowHeight());
// Draw to backbuffer.
glDrawArrays(GL_POINTS, 0, 1);
ASSERT_GL_NO_ERROR();
std::vector<GLColor> backbufferData(getWindowWidth() * getWindowHeight());
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
backbufferData.data());
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Draw to user FBO.
glDrawArrays(GL_POINTS, 0, 1);
ASSERT_GL_NO_ERROR();
std::vector<GLColor> userFBOData(getWindowWidth() * getWindowHeight());
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
userFBOData.data());
ASSERT_GL_NO_ERROR();
ASSERT_EQ(userFBOData.size(), backbufferData.size());
EXPECT_EQ(userFBOData, backbufferData);
}
// Tests that FragCoord behaves the same betweeen a user FBO and the back buffer.
TEST_P(GLSLTest, FragCoordConsistency)
{
constexpr char kFragCoordShader[] = R"(uniform mediump vec2 viewportSize;
void main()
{
gl_FragColor = vec4(gl_FragCoord.xy / viewportSize, 0, 1);
})";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFragCoordShader);
glUseProgram(program);
GLint uniLoc = glGetUniformLocation(program, "viewportSize");
ASSERT_NE(-1, uniLoc);
glUniform2f(uniLoc, getWindowWidth(), getWindowHeight());
// Draw to backbuffer.
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
ASSERT_GL_NO_ERROR();
std::vector<GLColor> backbufferData(getWindowWidth() * getWindowHeight());
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
backbufferData.data());
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Draw to user FBO.
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
ASSERT_GL_NO_ERROR();
std::vector<GLColor> userFBOData(getWindowWidth() * getWindowHeight());
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
userFBOData.data());
ASSERT_GL_NO_ERROR();
ASSERT_EQ(userFBOData.size(), backbufferData.size());
EXPECT_EQ(userFBOData, backbufferData);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest, ANGLE_INSTANTIATE_TEST(GLSLTest,
......
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