Handle viewport and scissor state changes for side-by-side framebuffers
Side-by-side framebuffers have viewport offsets as part of their state
which have to be applied to the viewport and scissor rectangles to
generate the final viewport and scissor rectangles of each view.
Whenever there is a transition to or from a side-by-side framebuffer,
viewport and scissor state has to be synced. Also, because rendering is
done on the same 2D texture the scissor test has to be always enabled to
guarantee that no fragments leak to a neighboring view.
The patch addresses this by extending the viewport and scissor state
in StateManagerGL to be a vector of rectangles instead of a single
rectangle. Two new dirty bits are added to cover changes in the viewport
offsets and whether the framebuffer has a side-by-side layout.
BUG=angleproject:2062
TEST=angle_end2end_tests
Change-Id: I8107d7ba97d06b20cf24358f19963fa494844592
Reviewed-on: https://chromium-review.googlesource.com/585012
Commit-Queue: Martin Radev <mradev@nvidia.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp
index 805f923..a53aa7d 100644
--- a/src/libANGLE/renderer/gl/FramebufferGL.cpp
+++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp
@@ -33,53 +33,12 @@
namespace rx
{
-FramebufferGL::FramebufferGL(const FramebufferState &state,
- const FunctionsGL *functions,
- StateManagerGL *stateManager,
- const WorkaroundsGL &workarounds,
- BlitGL *blitter,
- bool isDefault)
- : FramebufferImpl(state),
- mFunctions(functions),
- mStateManager(stateManager),
- mWorkarounds(workarounds),
- mBlitter(blitter),
- mFramebufferID(0),
- mIsDefault(isDefault),
- mAppliedEnabledDrawBuffers(1)
+namespace
{
- if (!mIsDefault)
- {
- mFunctions->genFramebuffers(1, &mFramebufferID);
- }
-}
-FramebufferGL::FramebufferGL(GLuint id,
- const FramebufferState &state,
- const FunctionsGL *functions,
- const WorkaroundsGL &workarounds,
- BlitGL *blitter,
- StateManagerGL *stateManager)
- : FramebufferImpl(state),
- mFunctions(functions),
- mStateManager(stateManager),
- mWorkarounds(workarounds),
- mBlitter(blitter),
- mFramebufferID(id),
- mIsDefault(true),
- mAppliedEnabledDrawBuffers(1)
-{
-}
-
-FramebufferGL::~FramebufferGL()
-{
- mStateManager->deleteFramebuffer(mFramebufferID);
- mFramebufferID = 0;
-}
-
-static void BindFramebufferAttachment(const FunctionsGL *functions,
- GLenum attachmentPoint,
- const FramebufferAttachment *attachment)
+void BindFramebufferAttachment(const FunctionsGL *functions,
+ GLenum attachmentPoint,
+ const FramebufferAttachment *attachment)
{
if (attachment)
{
@@ -133,6 +92,63 @@
}
}
+void RetrieveMultiviewFieldsFromAttachment(const gl::FramebufferAttachment *attachment,
+ const std::vector<gl::Offset> **viewportOffsets,
+ GLenum *multiviewLayout)
+{
+ if (attachment)
+ {
+ *viewportOffsets = &attachment->getMultiviewViewportOffsets();
+ *multiviewLayout = attachment->getMultiviewLayout();
+ }
+}
+
+} // namespace
+
+FramebufferGL::FramebufferGL(const FramebufferState &state,
+ const FunctionsGL *functions,
+ StateManagerGL *stateManager,
+ const WorkaroundsGL &workarounds,
+ BlitGL *blitter,
+ bool isDefault)
+ : FramebufferImpl(state),
+ mFunctions(functions),
+ mStateManager(stateManager),
+ mWorkarounds(workarounds),
+ mBlitter(blitter),
+ mFramebufferID(0),
+ mIsDefault(isDefault),
+ mAppliedEnabledDrawBuffers(1)
+{
+ if (!mIsDefault)
+ {
+ mFunctions->genFramebuffers(1, &mFramebufferID);
+ }
+}
+
+FramebufferGL::FramebufferGL(GLuint id,
+ const FramebufferState &state,
+ const FunctionsGL *functions,
+ const WorkaroundsGL &workarounds,
+ BlitGL *blitter,
+ StateManagerGL *stateManager)
+ : FramebufferImpl(state),
+ mFunctions(functions),
+ mStateManager(stateManager),
+ mWorkarounds(workarounds),
+ mBlitter(blitter),
+ mFramebufferID(id),
+ mIsDefault(true),
+ mAppliedEnabledDrawBuffers(1)
+{
+}
+
+FramebufferGL::~FramebufferGL()
+{
+ mStateManager->deleteFramebuffer(mFramebufferID);
+ mFramebufferID = 0;
+}
+
Error FramebufferGL::discard(const gl::Context *context, size_t count, const GLenum *attachments)
{
// glInvalidateFramebuffer accepts the same enums as glDiscardFramebufferEXT
@@ -467,6 +483,10 @@
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
+ const std::vector<gl::Offset> *attachmentViewportOffsets = nullptr;
+ GLenum multiviewLayout = GL_NONE;
+ bool isAttachmentModified = false;
+
for (auto dirtyBit : dirtyBits)
{
switch (dirtyBit)
@@ -474,10 +494,16 @@
case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
BindFramebufferAttachment(mFunctions, GL_DEPTH_ATTACHMENT,
mState.getDepthAttachment());
+ RetrieveMultiviewFieldsFromAttachment(mState.getDepthAttachment(),
+ &attachmentViewportOffsets, &multiviewLayout);
+ isAttachmentModified = true;
break;
case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
BindFramebufferAttachment(mFunctions, GL_STENCIL_ATTACHMENT,
mState.getStencilAttachment());
+ RetrieveMultiviewFieldsFromAttachment(mState.getStencilAttachment(),
+ &attachmentViewportOffsets, &multiviewLayout);
+ isAttachmentModified = true;
break;
case Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
{
@@ -516,10 +542,30 @@
BindFramebufferAttachment(mFunctions,
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index),
mState.getColorAttachment(index));
+ RetrieveMultiviewFieldsFromAttachment(mState.getColorAttachment(index),
+ &attachmentViewportOffsets, &multiviewLayout);
+ isAttachmentModified = true;
break;
}
}
}
+
+ if (isAttachmentModified)
+ {
+ 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);
+ }
+ else
+ {
+ mStateManager->setViewportOffsets(
+ FramebufferAttachment::GetDefaultViewportOffsetVector());
+ }
+ }
}
GLuint FramebufferGL::getFramebufferID() const