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 ...@@ -257,6 +257,11 @@ Rectangle Rectangle::removeReversal() const
return unreversed; 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) bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection)
{ {
int minSourceX, maxSourceX, minSourceY, maxSourceY; int minSourceX, maxSourceX, minSourceY, maxSourceY;
......
...@@ -48,6 +48,8 @@ struct Rectangle ...@@ -48,6 +48,8 @@ struct Rectangle
// Returns a rectangle with the same area but with height and width guaranteed to be positive. // Returns a rectangle with the same area but with height and width guaranteed to be positive.
Rectangle removeReversal() const; Rectangle removeReversal() const;
bool encloses(const gl::Rectangle &inside) const;
int x; int x;
int y; int y;
int width; int width;
......
...@@ -608,4 +608,32 @@ angle::Result GetVertexRangeInfo(const gl::Context *context, ...@@ -608,4 +608,32 @@ angle::Result GetVertexRangeInfo(const gl::Context *context,
} }
return angle::Result::Continue; 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 } // namespace rx
...@@ -28,6 +28,7 @@ namespace gl ...@@ -28,6 +28,7 @@ namespace gl
{ {
struct FormatType; struct FormatType;
struct InternalFormat; struct InternalFormat;
class State;
} // namespace gl } // namespace gl
namespace egl namespace egl
...@@ -286,6 +287,8 @@ angle::Result GetVertexRangeInfo(const gl::Context *context, ...@@ -286,6 +287,8 @@ angle::Result GetVertexRangeInfo(const gl::Context *context,
GLint baseVertex, GLint baseVertex,
GLint *startVertexOut, GLint *startVertexOut,
size_t *vertexCountOut); size_t *vertexCountOut);
gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY);
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_ #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
...@@ -208,12 +208,6 @@ angle::Result CommandGraphResource::recordCommands(Context *context, ...@@ -208,12 +208,6 @@ angle::Result CommandGraphResource::recordCommands(Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
{
ASSERT(hasStartedRenderPass());
return mCurrentWritingNode->getRenderPassRenderArea();
}
angle::Result CommandGraphResource::beginRenderPass( angle::Result CommandGraphResource::beginRenderPass(
ContextVk *contextVk, ContextVk *contextVk,
const Framebuffer &framebuffer, const Framebuffer &framebuffer,
...@@ -654,11 +648,6 @@ std::string CommandGraphNode::dumpCommandsForDiagnostics(const char *separator) ...@@ -654,11 +648,6 @@ std::string CommandGraphNode::dumpCommandsForDiagnostics(const char *separator)
return result; return result;
} }
const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
{
return mRenderPassRenderArea;
}
// CommandGraph implementation. // CommandGraph implementation.
CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator) CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator)
: mEnableGraphDiagnostics(enableGraphDiagnostics), : mEnableGraphDiagnostics(enableGraphDiagnostics),
......
...@@ -157,7 +157,7 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -157,7 +157,7 @@ class CommandGraphNode final : angle::NonCopyable
uintptr_t getResourceIDForDiagnostics() const { return mResourceID; } uintptr_t getResourceIDForDiagnostics() const { return mResourceID; }
std::string dumpCommandsForDiagnostics(const char *separator) const; std::string dumpCommandsForDiagnostics(const char *separator) const;
const gl::Rectangle &getRenderPassRenderArea() const; const gl::Rectangle &getRenderPassRenderArea() const { return mRenderPassRenderArea; }
CommandGraphNodeFunction getFunction() const { return mFunction; } CommandGraphNodeFunction getFunction() const { return mFunction; }
...@@ -292,21 +292,30 @@ class CommandGraphResource : angle::NonCopyable ...@@ -292,21 +292,30 @@ class CommandGraphResource : angle::NonCopyable
const std::vector<VkClearValue> &clearValues, const std::vector<VkClearValue> &clearValues,
CommandBuffer **commandBufferOut); CommandBuffer **commandBufferOut);
// Checks if we're in a RenderPass, returning true if so. Updates serial internally. // Checks if we're in a RenderPass without children.
// Returns the started command buffer in commandBufferOut. 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, ANGLE_INLINE bool appendToStartedRenderPass(Serial currentQueueSerial,
const gl::Rectangle &renderArea,
CommandBuffer **commandBufferOut) CommandBuffer **commandBufferOut)
{ {
updateQueueSerial(currentQueueSerial); updateQueueSerial(currentQueueSerial);
if (hasStartedRenderPass()) if (hasStartedRenderPass())
{ {
*commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands(); if (mCurrentWritingNode->getRenderPassRenderArea().encloses(renderArea))
return true; {
} *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
else return true;
{ }
return false;
} }
return false;
} }
// Returns true if the render pass is started, but there are no commands yet recorded in it. // 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 ...@@ -336,7 +345,11 @@ class CommandGraphResource : angle::NonCopyable
} }
// Accessor for RenderPass RenderArea. // 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. // Called when 'this' object changes, but we'd like to start a new command buffer later.
void finishCurrentCommands(RendererVk *renderer); void finishCurrentCommands(RendererVk *renderer);
...@@ -365,13 +378,6 @@ class CommandGraphResource : angle::NonCopyable ...@@ -365,13 +378,6 @@ class CommandGraphResource : angle::NonCopyable
return (mCurrentWritingNode != nullptr && !mCurrentWritingNode->hasChildren()); 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 startNewCommands(RendererVk *renderer);
void onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial); void onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial);
......
...@@ -260,10 +260,13 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, ...@@ -260,10 +260,13 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
if (!mCommandBuffer) if (!mCommandBuffer)
{ {
mDirtyBits |= mNewCommandBufferDirtyBits; mDirtyBits |= mNewCommandBufferDirtyBits;
gl::Rectangle scissoredRenderArea = mDrawFramebuffer->getScissoredRenderArea(this);
if (!mDrawFramebuffer->appendToStartedRenderPass(mRenderer->getCurrentQueueSerial(), 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) ...@@ -686,12 +689,11 @@ void ContextVk::updateDepthRange(float nearPlane, float farPlane)
void ContextVk::updateScissor(const gl::State &glState) void ContextVk::updateScissor(const gl::State &glState)
{ {
FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer()); FramebufferVk *framebufferVk = vk::GetImpl(glState.getDrawFramebuffer());
gl::Box dimensions = framebufferVk->getState().getDimensions(); gl::Rectangle scissoredRenderArea = framebufferVk->getScissoredRenderArea(this);
gl::Rectangle renderArea(0, 0, dimensions.width, dimensions.height); VkRect2D scissor = gl_vk::GetRect(scissoredRenderArea);
VkRect2D scissor;
gl_vk::GetScissor(glState, isViewportFlipEnabledForDrawFBO(), renderArea, &scissor);
mGraphicsPipelineDesc->updateScissor(&mGraphicsPipelineTransition, scissor); mGraphicsPipelineDesc->updateScissor(&mGraphicsPipelineTransition, scissor);
framebufferVk->onScissorChange(this);
} }
angle::Result ContextVk::syncState(const gl::Context *context, angle::Result ContextVk::syncState(const gl::Context *context,
......
...@@ -101,19 +101,28 @@ class FramebufferVk : public FramebufferImpl ...@@ -101,19 +101,28 @@ class FramebufferVk : public FramebufferImpl
void *pixels); void *pixels);
gl::Extents getReadImageExtents() const; gl::Extents getReadImageExtents() const;
gl::Rectangle getCompleteRenderArea() const;
gl::Rectangle getScissoredRenderArea(ContextVk *contextVk) const;
void onScissorChange(ContextVk *contextVk);
const gl::DrawBufferMask &getEmulatedAlphaAttachmentMask() const; const gl::DrawBufferMask &getEmulatedAlphaAttachmentMask() const;
RenderTargetVk *getColorReadRenderTarget() const; RenderTargetVk *getColorReadRenderTarget() const;
// This will clear the current write operation if it is complete. // 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; } 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; RenderTargetVk *getFirstRenderTarget() const;
GLint getSamples() const; GLint getSamples() const;
...@@ -125,11 +134,6 @@ class FramebufferVk : public FramebufferImpl ...@@ -125,11 +134,6 @@ class FramebufferVk : public FramebufferImpl
const gl::FramebufferState &state, const gl::FramebufferState &state,
WindowSurfaceVk *backbuffer); 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'. // The 'in' rectangles must be clipped to the scissor and FBO. The clipping is done in 'blit'.
angle::Result blitWithCommand(ContextVk *contextVk, angle::Result blitWithCommand(ContextVk *contextVk,
const gl::Rectangle &readRectIn, const gl::Rectangle &readRectIn,
...@@ -166,18 +170,14 @@ class FramebufferVk : public FramebufferImpl ...@@ -166,18 +170,14 @@ class FramebufferVk : public FramebufferImpl
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithRenderPassOp(ContextVk *contextVk, angle::Result clearWithRenderPassOp(ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
bool clearStencil, bool clearStencil,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); 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, angle::Result clearWithDraw(ContextVk *contextVk,
const gl::Rectangle &clearArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
bool clearStencil, bool clearStencil,
......
...@@ -668,10 +668,13 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -668,10 +668,13 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk)); ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk));
const gl::Rectangle &scissoredRenderArea = params.clearArea;
vk::CommandBuffer *commandBuffer; 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; FullScreenQuadParams vsParams;
...@@ -716,17 +719,14 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -716,17 +719,14 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
pipelineDesc.setStencilBackWriteMask(params.stencilMask); pipelineDesc.setStencilBackWriteMask(params.stencilMask);
} }
const gl::Rectangle &renderArea = framebuffer->getFramebuffer()->getRenderPassRenderArea();
bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
VkViewport viewport; 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); pipelineDesc.setViewport(viewport);
VkRect2D scissor; pipelineDesc.setScissor(gl_vk::GetRect(params.clearArea));
const gl::State &glState = contextVk->getState();
gl_vk::GetScissor(glState, invertViewport, renderArea, &scissor);
pipelineDesc.setScissor(scissor);
vk::ShaderLibrary &shaderLibrary = renderer->getShaderLibrary(); vk::ShaderLibrary &shaderLibrary = renderer->getShaderLibrary();
vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr; vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr;
...@@ -875,4 +875,18 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, ...@@ -875,4 +875,18 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
return angle::Result::Continue; 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 } // namespace rx
...@@ -61,8 +61,13 @@ class UtilsVk : angle::NonCopyable ...@@ -61,8 +61,13 @@ class UtilsVk : angle::NonCopyable
struct ClearFramebufferParameters struct ClearFramebufferParameters
{ {
// Satisfy chromium-style with a constructor that does what = {} was already doing in a
// safer way.
ClearFramebufferParameters();
const vk::RenderPassDesc *renderPassDesc; const vk::RenderPassDesc *renderPassDesc;
GLint renderAreaHeight; GLint renderAreaHeight;
gl::Rectangle clearArea;
bool clearColor; bool clearColor;
bool clearDepth; bool clearDepth;
......
...@@ -33,11 +33,6 @@ VkImageUsageFlags GetStagingBufferUsageFlags(rx::vk::StagingUsage usage) ...@@ -33,11 +33,6 @@ VkImageUsageFlags GetStagingBufferUsageFlags(rx::vk::StagingUsage usage)
return 0; return 0;
} }
} }
constexpr gl::Rectangle kMaxSizedScissor(0,
0,
std::numeric_limits<int>::max(),
std::numeric_limits<int>::max());
} // anonymous namespace } // anonymous namespace
namespace angle namespace angle
...@@ -826,36 +821,5 @@ void GetViewport(const gl::Rectangle &viewport, ...@@ -826,36 +821,5 @@ void GetViewport(const gl::Rectangle &viewport,
viewportOut->height = -viewportOut->height; 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 gl_vk
} // namespace rx } // namespace rx
...@@ -529,10 +529,6 @@ void GetViewport(const gl::Rectangle &viewport, ...@@ -529,10 +529,6 @@ void GetViewport(const gl::Rectangle &viewport,
bool invertViewport, bool invertViewport,
GLint renderAreaHeight, GLint renderAreaHeight,
VkViewport *viewportOut); VkViewport *viewportOut);
void GetScissor(const gl::State &glState,
bool invertViewport,
const gl::Rectangle &renderArea,
VkRect2D *scissorOut);
} // namespace gl_vk } // namespace gl_vk
} // namespace rx } // namespace rx
......
...@@ -825,7 +825,7 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments) ...@@ -825,7 +825,7 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments)
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glEnable(GL_SCISSOR_TEST); 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); glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -840,8 +840,11 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments) ...@@ -840,8 +840,11 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments)
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked); EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked); EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, 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 // Scissored clear
...@@ -863,8 +866,11 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments) ...@@ -863,8 +866,11 @@ TEST_P(ClearTestES3, MaskedScissoredClearMultipleAttachments)
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked); EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked); EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, clearColorMasked);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, 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( ...@@ -1239,8 +1245,8 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
const int w = getWindowWidth(); const int w = getWindowWidth();
const int h = getWindowHeight(); const int h = getWindowHeight();
const int whalf = w >> 1; const int wthird = w / 3;
const int hhalf = h >> 1; const int hthird = h / 3;
constexpr float kPreClearDepth = 0.9f; constexpr float kPreClearDepth = 0.9f;
constexpr float kClearDepth = 0.5f; constexpr float kClearDepth = 0.5f;
...@@ -1283,7 +1289,7 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear( ...@@ -1283,7 +1289,7 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
if (scissor) if (scissor)
{ {
glEnable(GL_SCISSOR_TEST); 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. // Use color and stencil masks to clear to a second color, 0.5 depth and 0x59 stencil.
...@@ -1325,12 +1331,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear( ...@@ -1325,12 +1331,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
GLColor expectedCornerColorRGB = scissor ? color1RGB : expectedCenterColorRGB; GLColor expectedCornerColorRGB = scissor ? color1RGB : expectedCenterColorRGB;
// Verify second clear color mask worked as expected. // 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(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 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(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 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, // If there is depth, but depth is not asked to be cleared, the depth buffer contains garbage,
// so no particular behavior can be expected. // so no particular behavior can be expected.
...@@ -1356,12 +1365,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear( ...@@ -1356,12 +1365,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
expectedCornerColorRGB = expectedCornerColorRGB =
mHasDepth && scissor && !maskDepth ? expectedCornerColorRGB : GLColor::blue; 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(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 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(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 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. // If there is stencil, but it's not asked to be cleared, there is similarly no expectation.
...@@ -1387,12 +1399,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear( ...@@ -1387,12 +1399,15 @@ void MaskedScissoredClearTestBase::MaskedScissoredColorDepthStencilClear(
// If there is no stencil, stencil test always passes so the whole image must be green. // If there is no stencil, stencil test always passes so the whole image must be green.
expectedCornerColorRGB = mHasStencil && scissor ? expectedCornerColorRGB : GLColor::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(0, 0, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 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(0, h - 1, expectedCornerColorRGB, 1);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 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