Commit 5c00d0db by Martin Radev Committed by Commit Bot

D3D11: Handle Clear* commands for side-by-side framebuffers

The patch modifies Clear11 to add support for clearing the color, depth and stencil attachments to a side-by-side framebuffer: - Color attachments are cleared through the command ClearView. - Depth and stencil attachments are cleared by drawing a quad on top of each view. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: I5753a72222216a48cd954eb1219bc58f968735fc Reviewed-on: https://chromium-review.googlesource.com/603853 Commit-Queue: Martin Radev <mradev@nvidia.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent eef80e40
......@@ -453,6 +453,36 @@ bool FramebufferState::hasStencil() const
return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
}
GLsizei FramebufferState::getNumViews() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return FramebufferAttachment::kDefaultNumViews;
}
return attachment->getNumViews();
}
const std::vector<Offset> *FramebufferState::getViewportOffsets() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return nullptr;
}
return &attachment->getMultiviewViewportOffsets();
}
GLenum FramebufferState::getMultiviewLayout() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return GL_NONE;
}
return attachment->getMultiviewLayout();
}
Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
: mState(caps),
mImpl(factory->createFramebuffer(mState)),
......@@ -1619,32 +1649,17 @@ int Framebuffer::getSamples(const ValidationContext *context)
GLsizei Framebuffer::getNumViews() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return FramebufferAttachment::kDefaultNumViews;
}
return attachment->getNumViews();
return mState.getNumViews();
}
const std::vector<Offset> *Framebuffer::getViewportOffsets() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return nullptr;
}
return &attachment->getMultiviewViewportOffsets();
return mState.getViewportOffsets();
}
GLenum Framebuffer::getMultiviewLayout() const
{
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
if (attachment == nullptr)
{
return GL_NONE;
}
return attachment->getMultiviewLayout();
return mState.getMultiviewLayout();
}
} // namespace gl
......@@ -92,6 +92,10 @@ class FramebufferState final : angle::NonCopyable
bool hasDepth() const;
bool hasStencil() const;
GLenum getMultiviewLayout() const;
GLsizei getNumViews() const;
const std::vector<Offset> *getViewportOffsets() const;
private:
friend class Framebuffer;
......
......@@ -79,6 +79,19 @@ bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache,
return cacheDirty;
}
bool AllOffsetsAreNonNegative(const std::vector<gl::Offset> &viewportOffsets)
{
for (size_t i = 0u; i < viewportOffsets.size(); ++i)
{
const auto &offset = viewportOffsets[i];
if (offset.x < 0 || offset.y < 0)
{
return false;
}
}
return true;
}
} // anonymous namespace
Clear11::ShaderManager::ShaderManager()
......@@ -364,24 +377,66 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
framebufferSize = colorAttachment->getSize();
}
const bool isSideBySideFBO =
(fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
bool needScissoredClear = false;
std::vector<D3D11_RECT> scissorRects;
if (clearParams.scissorEnabled)
{
const std::vector<gl::Offset> *viewportOffsets = fboData.getViewportOffsets();
ASSERT(viewportOffsets != nullptr);
ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets()));
if (clearParams.scissor.x >= framebufferSize.width ||
clearParams.scissor.y >= framebufferSize.height ||
clearParams.scissor.x + clearParams.scissor.width <= 0 ||
clearParams.scissor.y + clearParams.scissor.height <= 0 ||
clearParams.scissor.width == 0 || clearParams.scissor.height == 0)
clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 ||
clearParams.scissor.height == 0)
{
// Scissor rect is outside the renderbuffer or is an empty rect
// The check assumes that the viewport offsets are not negative as according to the
// ANGLE_multiview spec.
// Scissor rect is outside the renderbuffer or is an empty rect.
return gl::NoError();
}
needScissoredClear =
clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height;
if (isSideBySideFBO)
{
// We always have to do a scissor clear for side-by-side framebuffers.
needScissoredClear = true;
}
else
{
// Because the viewport offsets can generate scissor rectangles within the framebuffer's
// bounds, we can do this check only for non-side-by-side framebuffers.
if (clearParams.scissor.x + clearParams.scissor.width <= 0 ||
clearParams.scissor.y + clearParams.scissor.height <= 0)
{
// Scissor rect is outside the renderbuffer.
return gl::NoError();
}
needScissoredClear =
clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height;
}
if (needScissoredClear)
{
// Apply viewport offsets to compute the final scissor rectangles. This is valid also
// for non-side-by-side framebuffers, because the default viewport offset is {0,0}.
const size_t numViews = viewportOffsets->size();
scissorRects.reserve(numViews);
for (size_t i = 0u; i < numViews; ++i)
{
const gl::Offset &offset = (*viewportOffsets)[i];
D3D11_RECT rect;
int x = clearParams.scissor.x + offset.x;
int y = clearParams.scissor.y + offset.y;
rect.left = x;
rect.right = x + clearParams.scissor.width;
rect.top = y;
rect.bottom = y + clearParams.scissor.height;
scissorRects.emplace_back(rect);
}
}
}
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
......@@ -479,19 +534,17 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
{
// We shouldn't reach here if deviceContext1 is unavailable.
ASSERT(deviceContext1);
D3D11_RECT rect;
rect.left = clearParams.scissor.x;
rect.right = clearParams.scissor.x + clearParams.scissor.width;
rect.top = clearParams.scissor.y;
rect.bottom = clearParams.scissor.y + clearParams.scissor.height;
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &rect, 1);
// There must be at least one scissor rectangle.
ASSERT(!scissorRects.empty());
deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(),
static_cast<UINT>(scissorRects.size()));
if (mRenderer->getWorkarounds().callClearTwiceOnSmallTarget)
{
if (clearParams.scissor.width <= 16 || clearParams.scissor.height <= 16)
{
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &rect, 1);
deviceContext1->ClearView(framebufferRTV.get(), clearValues,
scissorRects.data(),
static_cast<UINT>(scissorRects.size()));
}
}
}
......@@ -649,7 +702,7 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
deviceContext->Unmap(mConstantBuffer.get(), 0);
}
// Set the viewport to be the same size as the framebuffer
// Set the viewport to be the same size as the framebuffer.
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
......@@ -667,9 +720,6 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
if (needScissoredClear)
{
const D3D11_RECT scissorRect = {clearParams.scissor.x, clearParams.scissor.y,
clearParams.scissor.x1(), clearParams.scissor.y1()};
deviceContext->RSSetScissorRects(1, &scissorRect);
deviceContext->RSSetState(mScissorEnabledRasterizerState.get());
}
else
......@@ -710,8 +760,19 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
// Apply render targets
stateManager->setOneTimeRenderTargets(context, &rtvs[0], numRtvs, dsv);
// Draw the fullscreen quad
deviceContext->Draw(6, 0);
// If scissors are necessary to be applied, then the number of clears is the number of scissor
// rects. If no scissors are necessary, then a single full-size clear is enough.
size_t necessaryNumClears = needScissoredClear ? scissorRects.size() : 1u;
for (size_t i = 0u; i < necessaryNumClears; ++i)
{
if (needScissoredClear)
{
ASSERT(i < scissorRects.size());
deviceContext->RSSetScissorRects(1, &scissorRects[i]);
}
// Draw the fullscreen quad.
deviceContext->Draw(6, 0);
}
// Clean up
mRenderer->markAllStateDirty(context);
......
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