Commit eef80e40 by Martin Radev Committed by Commit Bot

Do not implicitly enable the scissor test for side-by-side FBOs

The patch modifies the ANGLE_multiview specification so that issuing a Draw* command has undefined results for side-by-side FBOs if the scissor test is disabled. Also, clearing a side-by-side framebuffer will result in clearing the whole content of the specified buffers if the scissor test is disabled. StateManagerGL and FramebufferGL are modified to address this change in the spec. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: I39a87d297944f12769dee2ead17b508ac22053db Reviewed-on: https://chromium-review.googlesource.com/612283 Commit-Queue: Martin Radev <mradev@nvidia.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 599555b5
......@@ -101,6 +101,10 @@ Additions to Chapter 2 of the OpenGL ES 3.0 Specification (OpenGL ES Operation)
uses the multi-view extension, the number of views specified in the
program must match the number of views in the draw framebuffer. If
there is a mismatch, an INVALID_OPERATION error is generated.
If the active draw framebuffer has a side-by-side multi-view layout
and the scissor test is not enabled, the result of any draw command
is undefined, but is not followed by program termination.
"
Modify section 2.15.2 Transform Feedback Primitive Capture, p. 91
......@@ -154,6 +158,10 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification
Clearing commands are applied to each view in the current multi-view
framebuffer object and have the same constraints as described
in section 4.2.3 Clearing the Buffers.
If the active draw framebuffer has a side-by-side multi-view layout
and the scissor test is not enabled, the clearing command clears
the whole content of the specified buffers.
"
Modify section 4.3.2 (Reading pixels), p. 193
......
......@@ -104,10 +104,11 @@ void RetrieveMultiviewFieldsFromAttachment(const gl::FramebufferAttachment *atta
}
}
bool RequiresMultipleClears(const FramebufferAttachment *attachment)
bool RequiresMultipleClears(const FramebufferAttachment *attachment, bool scissorTestEnabled)
{
return attachment != nullptr &&
attachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
attachment->getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE &&
scissorTestEnabled;
}
} // namespace
......@@ -221,7 +222,8 @@ Error FramebufferGL::clear(const gl::Context *context, GLbitfield mask)
syncClearState(context, mask);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment()))
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::Clear, mask, GL_NONE, 0, nullptr, 0.0f,
0);
......@@ -242,7 +244,8 @@ Error FramebufferGL::clearBufferfv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment()))
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferfv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
......@@ -264,7 +267,8 @@ Error FramebufferGL::clearBufferuiv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment()))
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferuiv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
......@@ -286,7 +290,8 @@ Error FramebufferGL::clearBufferiv(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment()))
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferiv,
static_cast<GLbitfield>(0u), buffer, drawbuffer,
......@@ -309,7 +314,8 @@ Error FramebufferGL::clearBufferfi(const gl::Context *context,
syncClearBufferState(context, buffer, drawbuffer);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
if (RequiresMultipleClears(mState.getFirstNonNullAttachment()))
if (RequiresMultipleClears(mState.getFirstNonNullAttachment(),
context->getGLState().isScissorTestEnabled()))
{
genericSideBySideClear(context, ClearCommandType::ClearBufferfi,
static_cast<GLbitfield>(0u), buffer, drawbuffer, nullptr, depth,
......@@ -659,8 +665,6 @@ void FramebufferGL::syncState(const gl::Context *context, const Framebuffer::Dir
{
const bool isSideBySide = multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
mStateManager->setSideBySide(isSideBySide);
mStateManager->setScissorTestEnabled(isSideBySide ||
context->getGLState().isScissorTestEnabled());
if (attachmentViewportOffsets != nullptr)
{
mStateManager->setViewportOffsets(*attachmentViewportOffsets);
......
......@@ -1665,9 +1665,7 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt
switch (dirtyBit)
{
case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
// If the active draw framebuffer has a side-by-side layout, then the scissor test
// is always enabled.
setScissorTestEnabled(state.isScissorTestEnabled() || mIsSideBySideDrawFramebuffer);
setScissorTestEnabled(state.isScissorTestEnabled());
break;
case gl::State::DIRTY_BIT_SCISSOR:
{
......
......@@ -471,7 +471,7 @@ TEST_P(FramebufferMultiviewTest, InvalidReadPixels)
EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
}
// Test that glClear clears only the contents of each view.
// Test that glClear clears only the contents of each view if the scissor test is enabled.
TEST_P(FramebufferMultiviewTest, SideBySideClear)
{
if (!requestMultiviewExtension())
......@@ -496,34 +496,35 @@ TEST_P(FramebufferMultiviewTest, SideBySideClear)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
// Clear the contents of the texture.
glClearColor(0, 0, 0, 0);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
// Bind and specify viewport/scissor dimensions for each view.
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO);
glViewport(0, 0, 1, 2);
glScissor(0, 0, 1, 2);
glEnable(GL_SCISSOR_TEST);
glClearColor(1, 0, 0, 0);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, normalFBO);
// column 0
EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
EXPECT_PIXEL_EQ(0, 1, 0, 0, 0, 0);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::black);
// column 1
EXPECT_PIXEL_EQ(1, 0, 255, 0, 0, 0);
EXPECT_PIXEL_EQ(1, 1, 255, 0, 0, 0);
EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
// column 2
EXPECT_PIXEL_EQ(2, 0, 0, 0, 0, 0);
EXPECT_PIXEL_EQ(2, 1, 0, 0, 0, 0);
EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
EXPECT_PIXEL_COLOR_EQ(2, 1, GLColor::black);
// column 3
EXPECT_PIXEL_EQ(3, 0, 255, 0, 0, 0);
EXPECT_PIXEL_EQ(3, 1, 255, 0, 0, 0);
EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(3, 1, GLColor::red);
}
// Test that glFramebufferTextureMultiviewLayeredANGLE modifies the internal multiview state.
......@@ -631,4 +632,51 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
// Test that glClear clears all of the contents if the scissor test is disabled.
TEST_P(FramebufferMultiviewTest, SideBySideClearWithDisabledScissorTest)
{
if (!requestMultiviewExtension())
{
return;
}
GLFramebuffer multiviewFBO;
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO);
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
const GLint kViewportOffsets[2] = {1, 0};
glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 1,
&kViewportOffsets[0]);
// Create and bind a normal framebuffer to access the 2D texture.
GLFramebuffer normalFBO;
glBindFramebuffer(GL_FRAMEBUFFER, normalFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
// Clear the contents of the texture.
glClearColor(0, 1, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
// Bind and specify viewport/scissor dimensions for each view.
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO);
glViewport(0, 0, 1, 2);
glScissor(0, 0, 1, 2);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, normalFBO);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 2; ++j)
{
EXPECT_PIXEL_COLOR_EQ(i, j, GLColor::red);
}
}
}
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL());
\ No newline at end of file
......@@ -134,8 +134,9 @@ class MultiviewSideBySideRenderTest : public MultiviewDrawTest
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
// Clear the buffers.
glViewport(0, 0, width, height);
glScissor(0, 0, width, height);
glViewport(0, 0, widthPerView, height);
glScissor(0, 0, widthPerView, height);
glEnable(GL_SCISSOR_TEST);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
......@@ -814,6 +815,7 @@ TEST_P(MultiviewSideBySideRenderTest, DivisorOrderOfOperation)
glViewport(0, 0, 1, 1);
glScissor(0, 0, 1, 1);
glEnable(GL_SCISSOR_TEST);
glClearColor(0, 0, 0, 0);
// Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
......
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