Commit 127990f9 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Use render pass loadOp for scissored clears

At this point, every clear is done through render pass loadOp, except masked color or stencil clears. The only fallback is clearWithDraw, that can clear both color and stencil at the same time. Bug: angleproject:2361 Change-Id: I805fc12475e832ad2f573f665cdfeb766e61a6d0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1553740 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTobin Ehlis <tobine@google.com>
parent d581f918
......@@ -257,6 +257,11 @@ Rectangle Rectangle::removeReversal() const
return unreversed;
}
bool Rectangle::encloses(const gl::Rectangle &inside) const
{
return x0() <= inside.x0() && y0() <= inside.y0() && x1() >= inside.x1() && y1() >= inside.y1();
}
bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection)
{
int minSourceX, maxSourceX, minSourceY, maxSourceY;
......
......@@ -48,6 +48,8 @@ struct Rectangle
// Returns a rectangle with the same area but with height and width guaranteed to be positive.
Rectangle removeReversal() const;
bool encloses(const gl::Rectangle &inside) const;
int x;
int y;
int width;
......
......@@ -608,4 +608,32 @@ angle::Result GetVertexRangeInfo(const gl::Context *context,
}
return angle::Result::Continue;
}
gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY)
{
if (glState.isScissorTestEnabled())
{
gl::Rectangle clippedRect;
if (!gl::ClipRectangle(glState.getScissor(), rect, &clippedRect))
{
return gl::Rectangle();
}
if (invertY)
{
clippedRect.y = rect.height - clippedRect.y - clippedRect.height;
}
return clippedRect;
}
// If the scissor test isn't enabled, assume it has infinite size. Its intersection with the
// rect would be the rect itself.
//
// Note that on Vulkan, returning this (as opposed to a fixed max-int-sized rect) could lead to
// unnecessary pipeline creations if two otherwise identical pipelines are used on framebuffers
// with different sizes. If such usage is observed in an application, we should investigate
// possible optimizations.
return rect;
}
} // namespace rx
......@@ -28,6 +28,7 @@ namespace gl
{
struct FormatType;
struct InternalFormat;
class State;
} // namespace gl
namespace egl
......@@ -286,6 +287,8 @@ angle::Result GetVertexRangeInfo(const gl::Context *context,
GLint baseVertex,
GLint *startVertexOut,
size_t *vertexCountOut);
gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY);
} // namespace rx
#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
......@@ -208,12 +208,6 @@ angle::Result CommandGraphResource::recordCommands(Context *context,
return angle::Result::Continue;
}
const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
{
ASSERT(hasStartedRenderPass());
return mCurrentWritingNode->getRenderPassRenderArea();
}
angle::Result CommandGraphResource::beginRenderPass(
ContextVk *contextVk,
const Framebuffer &framebuffer,
......@@ -654,11 +648,6 @@ std::string CommandGraphNode::dumpCommandsForDiagnostics(const char *separator)
return result;
}
const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
{
return mRenderPassRenderArea;
}
// CommandGraph implementation.
CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator)
: mEnableGraphDiagnostics(enableGraphDiagnostics),
......
......@@ -157,7 +157,7 @@ class CommandGraphNode final : angle::NonCopyable
uintptr_t getResourceIDForDiagnostics() const { return mResourceID; }
std::string dumpCommandsForDiagnostics(const char *separator) const;
const gl::Rectangle &getRenderPassRenderArea() const;
const gl::Rectangle &getRenderPassRenderArea() const { return mRenderPassRenderArea; }
CommandGraphNodeFunction getFunction() const { return mFunction; }
......@@ -292,21 +292,30 @@ class CommandGraphResource : angle::NonCopyable
const std::vector<VkClearValue> &clearValues,
CommandBuffer **commandBufferOut);
// Checks if we're in a RenderPass, returning true if so. Updates serial internally.
// Returns the started command buffer in commandBufferOut.
// Checks if we're in a RenderPass without children.
bool hasStartedRenderPass() const
{
return hasChildlessWritingNode() &&
mCurrentWritingNode->getInsideRenderPassCommands()->valid();
}
// Checks if we're in a RenderPass that encompasses renderArea, returning true if so. Updates
// serial internally. Returns the started command buffer in commandBufferOut.
ANGLE_INLINE bool appendToStartedRenderPass(Serial currentQueueSerial,
const gl::Rectangle &renderArea,
CommandBuffer **commandBufferOut)
{
updateQueueSerial(currentQueueSerial);
if (hasStartedRenderPass())
{
*commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
return true;
}
else
{
return false;
if (mCurrentWritingNode->getRenderPassRenderArea().encloses(renderArea))
{
*commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
return true;
}
}
return false;
}
// Returns true if the render pass is started, but there are no commands yet recorded in it.
......@@ -336,7 +345,11 @@ class CommandGraphResource : angle::NonCopyable
}
// Accessor for RenderPass RenderArea.
const gl::Rectangle &getRenderPassRenderArea() const;
const gl::Rectangle &getRenderPassRenderArea() const
{
ASSERT(hasStartedRenderPass());
return mCurrentWritingNode->getRenderPassRenderArea();
}
// Called when 'this' object changes, but we'd like to start a new command buffer later.
void finishCurrentCommands(RendererVk *renderer);
......@@ -365,13 +378,6 @@ class CommandGraphResource : angle::NonCopyable
return (mCurrentWritingNode != nullptr && !mCurrentWritingNode->hasChildren());
}
// Checks if we're in a RenderPass without children.
bool hasStartedRenderPass() const
{
return hasChildlessWritingNode() &&
mCurrentWritingNode->getInsideRenderPassCommands()->valid();
}
void startNewCommands(RendererVk *renderer);
void onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial);
......
......@@ -260,10 +260,13 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
if (!mCommandBuffer)
{
mDirtyBits |= mNewCommandBufferDirtyBits;
gl::Rectangle scissoredRenderArea = mDrawFramebuffer->getScissoredRenderArea(this);
if (!mDrawFramebuffer->appendToStartedRenderPass(mRenderer->getCurrentQueueSerial(),
&mCommandBuffer))
scissoredRenderArea, &mCommandBuffer))
{
ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, &mCommandBuffer));
ANGLE_TRY(
mDrawFramebuffer->startNewRenderPass(this, scissoredRenderArea, &mCommandBuffer));
}
}
......@@ -686,12 +689,11 @@ void ContextVk::updateDepthRange(float nearPlane, float farPlane)
void ContextVk::updateScissor(const gl::State &glState)
{
FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
gl::Box dimensions = framebufferVk->getState().getDimensions();
gl::Rectangle renderArea(0, 0, dimensions.width, dimensions.height);
VkRect2D scissor;
gl_vk::GetScissor(glState, isViewportFlipEnabledForDrawFBO(), renderArea, &scissor);
gl::Rectangle scissoredRenderArea = framebufferVk->getScissoredRenderArea(this);
VkRect2D scissor = gl_vk::GetRect(scissoredRenderArea);
mGraphicsPipelineDesc->updateScissor(&mGraphicsPipelineTransition, scissor);
framebufferVk->onScissorChange(this);
}
angle::Result ContextVk::syncState(const gl::Context *context,
......
......@@ -101,19 +101,28 @@ class FramebufferVk : public FramebufferImpl
void *pixels);
gl::Extents getReadImageExtents() const;
gl::Rectangle getCompleteRenderArea() const;
gl::Rectangle getScissoredRenderArea(ContextVk *contextVk) const;
void onScissorChange(ContextVk *contextVk);
const gl::DrawBufferMask &getEmulatedAlphaAttachmentMask() const;
RenderTargetVk *getColorReadRenderTarget() const;
// This will clear the current write operation if it is complete.
bool appendToStartedRenderPass(Serial currentQueueSerial, vk::CommandBuffer **commandBufferOut)
bool appendToStartedRenderPass(Serial currentQueueSerial,
const gl::Rectangle &renderArea,
vk::CommandBuffer **commandBufferOut)
{
return mFramebuffer.appendToStartedRenderPass(currentQueueSerial, commandBufferOut);
return mFramebuffer.appendToStartedRenderPass(currentQueueSerial, renderArea,
commandBufferOut);
}
vk::FramebufferHelper *getFramebuffer() { return &mFramebuffer; }
angle::Result startNewRenderPass(ContextVk *context, vk::CommandBuffer **commandBufferOut);
angle::Result startNewRenderPass(ContextVk *context,
const gl::Rectangle &renderArea,
vk::CommandBuffer **commandBufferOut);
RenderTargetVk *getFirstRenderTarget() const;
GLint getSamples() const;
......@@ -125,11 +134,6 @@ class FramebufferVk : public FramebufferImpl
const gl::FramebufferState &state,
WindowSurfaceVk *backbuffer);
// Helper for appendToStarted/else startNewRenderPass.
angle::Result getCommandBufferForDraw(ContextVk *contextVk,
vk::CommandBuffer **commandBufferOut,
vk::RecordingMode *modeOut);
// The 'in' rectangles must be clipped to the scissor and FBO. The clipping is done in 'blit'.
angle::Result blitWithCommand(ContextVk *contextVk,
const gl::Rectangle &readRectIn,
......@@ -166,18 +170,14 @@ class FramebufferVk : public FramebufferImpl
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithRenderPassOp(ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithClearAttachments(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
......
......@@ -668,10 +668,13 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk));
const gl::Rectangle &scissoredRenderArea = params.clearArea;
vk::CommandBuffer *commandBuffer;
if (!framebuffer->appendToStartedRenderPass(renderer->getCurrentQueueSerial(), &commandBuffer))
if (!framebuffer->appendToStartedRenderPass(renderer->getCurrentQueueSerial(),
scissoredRenderArea, &commandBuffer))
{
ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, &commandBuffer));
ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, scissoredRenderArea, &commandBuffer));
}
FullScreenQuadParams vsParams;
......@@ -716,17 +719,14 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
pipelineDesc.setStencilBackWriteMask(params.stencilMask);
}
const gl::Rectangle &renderArea = framebuffer->getFramebuffer()->getRenderPassRenderArea();
bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
VkViewport viewport;
gl_vk::GetViewport(renderArea, 0.0f, 1.0f, invertViewport, params.renderAreaHeight, &viewport);
gl::Rectangle completeRenderArea = framebuffer->getCompleteRenderArea();
bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
gl_vk::GetViewport(completeRenderArea, 0.0f, 1.0f, invertViewport, params.renderAreaHeight,
&viewport);
pipelineDesc.setViewport(viewport);
VkRect2D scissor;
const gl::State &glState = contextVk->getState();
gl_vk::GetScissor(glState, invertViewport, renderArea, &scissor);
pipelineDesc.setScissor(scissor);
pipelineDesc.setScissor(gl_vk::GetRect(params.clearArea));
vk::ShaderLibrary &shaderLibrary = renderer->getShaderLibrary();
vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr;
......@@ -875,4 +875,18 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
return angle::Result::Continue;
}
UtilsVk::ClearFramebufferParameters::ClearFramebufferParameters()
: renderPassDesc(nullptr),
renderAreaHeight(0),
clearColor(false),
clearDepth(false),
clearStencil(false),
stencilMask(0),
colorMaskFlags(0),
colorAttachmentIndex(0),
colorFormat(nullptr),
colorClearValue{},
depthStencilClearValue{}
{}
} // namespace rx
......@@ -61,8 +61,13 @@ class UtilsVk : angle::NonCopyable
struct ClearFramebufferParameters
{
// Satisfy chromium-style with a constructor that does what = {} was already doing in a
// safer way.
ClearFramebufferParameters();
const vk::RenderPassDesc *renderPassDesc;
GLint renderAreaHeight;
gl::Rectangle clearArea;
bool clearColor;
bool clearDepth;
......
......@@ -33,11 +33,6 @@ VkImageUsageFlags GetStagingBufferUsageFlags(rx::vk::StagingUsage usage)
return 0;
}
}
constexpr gl::Rectangle kMaxSizedScissor(0,
0,
std::numeric_limits<int>::max(),
std::numeric_limits<int>::max());
} // anonymous namespace
namespace angle
......@@ -826,36 +821,5 @@ void GetViewport(const gl::Rectangle &viewport,
viewportOut->height = -viewportOut->height;
}
}
void GetScissor(const gl::State &glState,
bool invertViewport,
const gl::Rectangle &renderArea,
VkRect2D *scissorOut)
{
if (glState.isScissorTestEnabled())
{
gl::Rectangle clippedRect;
if (!gl::ClipRectangle(glState.getScissor(), renderArea, &clippedRect))
{
memset(scissorOut, 0, sizeof(VkRect2D));
return;
}
*scissorOut = gl_vk::GetRect(clippedRect);
if (invertViewport)
{
scissorOut->offset.y =
renderArea.height - scissorOut->offset.y - scissorOut->extent.height;
}
}
else
{
// If the scissor test isn't enabled, we can simply use a really big scissor that's
// certainly larger than the current surface using the maximum size of a 2D texture
// for the width and height.
*scissorOut = gl_vk::GetRect(kMaxSizedScissor);
}
}
} // namespace gl_vk
} // namespace rx
......@@ -529,10 +529,6 @@ void GetViewport(const gl::Rectangle &viewport,
bool invertViewport,
GLint renderAreaHeight,
VkViewport *viewportOut);
void GetScissor(const gl::State &glState,
bool invertViewport,
const gl::Rectangle &renderArea,
VkRect2D *scissorOut);
} // namespace gl_vk
} // namespace rx
......
......@@ -825,7 +825,7 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments)
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glEnable(GL_SCISSOR_TEST);
glScissor(kSize / 4, kSize / 4, kSize / 2, kSize / 2);
glScissor(kSize / 6, kSize / 6, kSize / 3, kSize / 3);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
......@@ -840,8 +840,11 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments)
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, kSize / 3, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, 2 * kSize / 3, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, clearColorMaskedScissored);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, clearColorMaskedScissored);
}
// Scissored clear
......@@ -863,8 +866,11 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments)
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, 2 * kSize / 3, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, kSize / 3, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(2 * kSize / 3, 2 * kSize / 3, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, clearColorScissored);
EXPECT_PIXEL_COLOR_EQ(kSize / 3, kSize / 3, clearColorScissored);
}
}
......@@ -1239,8 +1245,8 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
const int w = getWindowWidth();
const int h = getWindowHeight();
const int whalf = w >> 1;
const int hhalf = h >> 1;
const int wthird = w / 3;
const int hthird = h / 3;
constexpr float kPreClearDepth = 0.9f;
constexpr float kClearDepth = 0.5f;
......@@ -1283,7 +1289,7 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
if (scissor)
{
glEnable(GL_SCISSOR_TEST);
glScissor(whalf / 2, hhalf / 2, whalf, hhalf);
glScissor(wthird / 2, hthird / 2, wthird, hthird);
}
// Use color and stencil masks to clear to a second color, 0.5 depth and 0x59 stencil.
......@@ -1325,12 +1331,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
GLColor expectedCornerColorRGB = scissor ? color1RGB : expectedCenterColorRGB;
// Verify second clear color mask worked as expected.
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(wthird, hthird, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(wthird, 2 * hthird, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(2 * wthird, hthird, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(2 * wthird, 2 * hthird, expectedCornerColorRGB, 1);
// If there is depth, but depth is not asked to be cleared, the depth buffer contains garbage,
// so no particular behavior can be expected.
......@@ -1356,12 +1365,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
expectedCornerColorRGB =
mHasDepth && scissor && !maskDepth ? expectedCornerColorRGB : GLColor::blue;
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(wthird, hthird, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(wthird, 2 * hthird, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(2 * wthird, hthird, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(2 * wthird, 2 * hthird, expectedCornerColorRGB, 1);
}
// If there is stencil, but it's not asked to be cleared, there is similarly no expectation.
......@@ -1387,12 +1399,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
// If there is no stencil, stencil test always passes so the whole image must be green.
expectedCornerColorRGB = mHasStencil && scissor ? expectedCornerColorRGB : GLColor::green;
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(wthird, hthird, expectedCenterColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(wthird, 2 * hthird, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(2 * wthird, hthird, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(2 * wthird, 2 * hthird, expectedCornerColorRGB, 1);
}
}
......
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