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 ...@@ -453,6 +453,36 @@ bool FramebufferState::hasStencil() const
return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0); 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) Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
: mState(caps), : mState(caps),
mImpl(factory->createFramebuffer(mState)), mImpl(factory->createFramebuffer(mState)),
...@@ -1619,32 +1649,17 @@ int Framebuffer::getSamples(const ValidationContext *context) ...@@ -1619,32 +1649,17 @@ int Framebuffer::getSamples(const ValidationContext *context)
GLsizei Framebuffer::getNumViews() const GLsizei Framebuffer::getNumViews() const
{ {
const FramebufferAttachment *attachment = getFirstNonNullAttachment(); return mState.getNumViews();
if (attachment == nullptr)
{
return FramebufferAttachment::kDefaultNumViews;
}
return attachment->getNumViews();
} }
const std::vector<Offset> *Framebuffer::getViewportOffsets() const const std::vector<Offset> *Framebuffer::getViewportOffsets() const
{ {
const FramebufferAttachment *attachment = getFirstNonNullAttachment(); return mState.getViewportOffsets();
if (attachment == nullptr)
{
return nullptr;
}
return &attachment->getMultiviewViewportOffsets();
} }
GLenum Framebuffer::getMultiviewLayout() const GLenum Framebuffer::getMultiviewLayout() const
{ {
const FramebufferAttachment *attachment = getFirstNonNullAttachment(); return mState.getMultiviewLayout();
if (attachment == nullptr)
{
return GL_NONE;
}
return attachment->getMultiviewLayout();
} }
} // namespace gl } // namespace gl
...@@ -92,6 +92,10 @@ class FramebufferState final : angle::NonCopyable ...@@ -92,6 +92,10 @@ class FramebufferState final : angle::NonCopyable
bool hasDepth() const; bool hasDepth() const;
bool hasStencil() const; bool hasStencil() const;
GLenum getMultiviewLayout() const;
GLsizei getNumViews() const;
const std::vector<Offset> *getViewportOffsets() const;
private: private:
friend class Framebuffer; friend class Framebuffer;
......
...@@ -79,6 +79,19 @@ bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache, ...@@ -79,6 +79,19 @@ bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache,
return cacheDirty; 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 } // anonymous namespace
Clear11::ShaderManager::ShaderManager() Clear11::ShaderManager::ShaderManager()
...@@ -364,24 +377,66 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -364,24 +377,66 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
framebufferSize = colorAttachment->getSize(); framebufferSize = colorAttachment->getSize();
} }
const bool isSideBySideFBO =
(fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
bool needScissoredClear = false; bool needScissoredClear = false;
std::vector<D3D11_RECT> scissorRects;
if (clearParams.scissorEnabled) if (clearParams.scissorEnabled)
{ {
const std::vector<gl::Offset> *viewportOffsets = fboData.getViewportOffsets();
ASSERT(viewportOffsets != nullptr);
ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets()));
if (clearParams.scissor.x >= framebufferSize.width || if (clearParams.scissor.x >= framebufferSize.width ||
clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 ||
clearParams.scissor.x + clearParams.scissor.width <= 0 || clearParams.scissor.height == 0)
clearParams.scissor.y + clearParams.scissor.height <= 0 ||
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(); return gl::NoError();
} }
needScissoredClear = if (isSideBySideFBO)
clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || {
clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || // We always have to do a scissor clear for side-by-side framebuffers.
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height; 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(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
...@@ -479,19 +534,17 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -479,19 +534,17 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
{ {
// We shouldn't reach here if deviceContext1 is unavailable. // We shouldn't reach here if deviceContext1 is unavailable.
ASSERT(deviceContext1); ASSERT(deviceContext1);
// There must be at least one scissor rectangle.
D3D11_RECT rect; ASSERT(!scissorRects.empty());
rect.left = clearParams.scissor.x; deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(),
rect.right = clearParams.scissor.x + clearParams.scissor.width; static_cast<UINT>(scissorRects.size()));
rect.top = clearParams.scissor.y;
rect.bottom = clearParams.scissor.y + clearParams.scissor.height;
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &rect, 1);
if (mRenderer->getWorkarounds().callClearTwiceOnSmallTarget) if (mRenderer->getWorkarounds().callClearTwiceOnSmallTarget)
{ {
if (clearParams.scissor.width <= 16 || clearParams.scissor.height <= 16) 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, ...@@ -649,7 +702,7 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
deviceContext->Unmap(mConstantBuffer.get(), 0); 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; D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0; viewport.TopLeftX = 0;
viewport.TopLeftY = 0; viewport.TopLeftY = 0;
...@@ -667,9 +720,6 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -667,9 +720,6 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
if (needScissoredClear) 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()); deviceContext->RSSetState(mScissorEnabledRasterizerState.get());
} }
else else
...@@ -710,8 +760,19 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context, ...@@ -710,8 +760,19 @@ gl::Error Clear11::clearFramebuffer(const gl::Context *context,
// Apply render targets // Apply render targets
stateManager->setOneTimeRenderTargets(context, &rtvs[0], numRtvs, dsv); stateManager->setOneTimeRenderTargets(context, &rtvs[0], numRtvs, dsv);
// Draw the fullscreen quad // If scissors are necessary to be applied, then the number of clears is the number of scissor
deviceContext->Draw(6, 0); // 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 // Clean up
mRenderer->markAllStateDirty(context); 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