Commit e4e2a016 by Charlie Lao Committed by Commit Bot

Vulkan: Use color mask to handle draw buffer disabled case

When draw buffers set to GL_NONE, instead of remove the attachment from renderpass which breaks renderpass, we force vulkan's per buffer color mask to false while keep the disabled draw buffer attached. This CL also always create FrameBuffer with all color attachments regardless it is enabled or not. Bug: b/167301719 Change-Id: Ice9fca9aacf774a47d13b749f822b222cc050174 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2389007Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Charlie Lao <cclao@google.com>
parent 821aabb3
...@@ -2624,10 +2624,10 @@ void ContextVk::updateColorMask(const gl::BlendState &blendState) ...@@ -2624,10 +2624,10 @@ void ContextVk::updateColorMask(const gl::BlendState &blendState)
mClearColorMask = mClearColorMask =
gl_vk::GetColorComponentFlags(blendState.colorMaskRed, blendState.colorMaskGreen, gl_vk::GetColorComponentFlags(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha); blendState.colorMaskBlue, blendState.colorMaskAlpha);
FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer()); FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
mGraphicsPipelineDesc->updateColorWriteMask(&mGraphicsPipelineTransition, mClearColorMask, mGraphicsPipelineDesc->updateColorWriteMask(&mGraphicsPipelineTransition, mClearColorMask,
framebufferVk->getEmulatedAlphaAttachmentMask()); framebufferVk->getEmulatedAlphaAttachmentMask(),
framebufferVk->getState().getEnabledDrawBuffers());
} }
void ContextVk::updateSampleMask(const gl::State &glState) void ContextVk::updateSampleMask(const gl::State &glState)
......
...@@ -1477,9 +1477,10 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk, ...@@ -1477,9 +1477,10 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
{ {
// Set the appropriate storeOp for attachments. // Set the appropriate storeOp for attachments.
size_t attachmentIndexVk = 0; size_t attachmentIndexVk = 0;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
if (invalidateColorBuffers.test(colorIndexGL)) if (mState.getEnabledDrawBuffers()[colorIndexGL] &&
invalidateColorBuffers.test(colorIndexGL))
{ {
contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment( contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment(
attachmentIndexVk); attachmentIndexVk);
...@@ -1576,16 +1577,19 @@ angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context, ...@@ -1576,16 +1577,19 @@ angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context,
updateActiveColorMasks(colorIndexGL, false, false, false, false); updateActiveColorMasks(colorIndexGL, false, false, false, false);
} }
const bool enabledColor = renderTarget && mState.getEnabledDrawBuffers()[colorIndexGL]; const bool enabledColor =
renderTarget && mState.getColorAttachments()[colorIndexGL].isAttached();
const bool enabledResolve = enabledColor && renderTarget->hasResolveAttachment(); const bool enabledResolve = enabledColor && renderTarget->hasResolveAttachment();
if (enabledColor) if (enabledColor)
{ {
mCurrentFramebufferDesc.updateColor(colorIndexGL, renderTarget->getDrawSubresourceSerial()); mCurrentFramebufferDesc.updateColor(colorIndexGL, renderTarget->getDrawSubresourceSerial());
mAttachedColorBufferMask.set(colorIndexGL);
} }
else else
{ {
mCurrentFramebufferDesc.updateColor(colorIndexGL, vk::kInvalidImageViewSubresourceSerial); mCurrentFramebufferDesc.updateColor(colorIndexGL, vk::kInvalidImageViewSubresourceSerial);
mAttachedColorBufferMask.reset(colorIndexGL);
} }
if (enabledResolve) if (enabledResolve)
...@@ -1662,6 +1666,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -1662,6 +1666,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
// If we are notified that any attachment is dirty, but we have deferred clears for them, a // If we are notified that any attachment is dirty, but we have deferred clears for them, a
// flushDeferredClears() call is missing somewhere. ASSERT this to catch these bugs. // flushDeferredClears() call is missing somewhere. ASSERT this to catch these bugs.
vk::ClearValuesArray previousDeferredClears = mDeferredClears; vk::ClearValuesArray previousDeferredClears = mDeferredClears;
bool shouldUpdateColorMask = false;
// For any updated attachments we'll update their Serials below // For any updated attachments we'll update their Serials below
ASSERT(dirtyBits.any()); ASSERT(dirtyBits.any());
...@@ -1681,22 +1686,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -1681,22 +1686,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits)); ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
break; break;
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS: case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
// Force update of serial for enabled draw buffers shouldUpdateColorMask = true;
mCurrentFramebufferDesc.reset();
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
{
uint32_t colorIndex32 = static_cast<uint32_t>(colorIndexGL);
RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL];
mCurrentFramebufferDesc.updateColor(colorIndex32,
renderTarget->getDrawSubresourceSerial());
if (renderTarget->hasResolveAttachment())
{
mCurrentFramebufferDesc.updateColorResolve(
colorIndex32, renderTarget->getResolveSubresourceSerial());
}
}
updateDepthStencilAttachmentSerial(contextVk);
break; break;
case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH: case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT: case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
...@@ -1724,13 +1714,18 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -1724,13 +1714,18 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
} }
ASSERT(!previousDeferredClears.test(colorIndexGL)); ASSERT(!previousDeferredClears.test(colorIndexGL));
ANGLE_TRY(updateColorAttachment(context, deferClears, colorIndexGL)); ANGLE_TRY(updateColorAttachment(context, deferClears, colorIndexGL));
shouldUpdateColorMask = true;
break; break;
} }
} }
} }
if (shouldUpdateColorMask)
{
contextVk->updateColorMask(context->getState().getBlendState());
}
// In some cases we'll need to force a flush of deferred clears. When we're syncing the read // In some cases we'll need to force a flush of deferred clears. When we're syncing the read
// framebuffer we might not get a RenderPass. Also when there are masked out cleared color // framebuffer we might not get a RenderPass. Also when there are masked out cleared color
// channels. // channels.
...@@ -1802,11 +1797,10 @@ void FramebufferVk::updateRenderPassDesc() ...@@ -1802,11 +1797,10 @@ void FramebufferVk::updateRenderPassDesc()
mRenderPassDesc.setSamples(getSamples()); mRenderPassDesc.setSamples(getSamples());
// Color attachments. // Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors(); const auto &colorRenderTargets = mRenderTargetCache.getColors();
const gl::DrawBufferMask enabledDrawBuffers = mState.getEnabledDrawBuffers(); for (size_t colorIndexGL = 0; colorIndexGL < mAttachedColorBufferMask.size(); ++colorIndexGL)
for (size_t colorIndexGL = 0; colorIndexGL < enabledDrawBuffers.size(); ++colorIndexGL)
{ {
if (enabledDrawBuffers[colorIndexGL]) if (mAttachedColorBufferMask[colorIndexGL])
{ {
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
...@@ -1880,7 +1874,7 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, ...@@ -1880,7 +1874,7 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
// Color attachments. // Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors(); const auto &colorRenderTargets = mRenderTargetCache.getColors();
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
...@@ -1920,7 +1914,7 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, ...@@ -1920,7 +1914,7 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
else else
{ {
// This Framebuffer owns all of the ImageViews, including its own resolve ImageViews. // This Framebuffer owns all of the ImageViews, including its own resolve ImageViews.
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
...@@ -2124,18 +2118,16 @@ void FramebufferVk::clearWithLoadOp(ContextVk *contextVk, ...@@ -2124,18 +2118,16 @@ void FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
ASSERT(commands.getCommandBuffer().empty()); ASSERT(commands.getCommandBuffer().empty());
// The clear colors are packed with no gaps. The draw buffers mask is unpacked uint32_t colorIndexVk = 0;
// and can have gaps. Thus we need to count the packed index explicitly in this loop. for (size_t colorIndexGL : mAttachedColorBufferMask)
size_t colorCount = 0;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
{ {
if (clearColorBuffers[colorIndexGL]) if (mState.getEnabledDrawBuffers()[colorIndexGL] && clearColorBuffers[colorIndexGL])
{ {
VkClearValue clearValue = VkClearValue clearValue =
getCorrectedColorClearValue(colorIndexGL, clearColorValue); getCorrectedColorClearValue(colorIndexGL, clearColorValue);
commands.updateRenderPassColorClear(colorCount, clearValue); commands.updateRenderPassColorClear(colorIndexVk, clearValue);
} }
colorCount++; ++colorIndexVk;
} }
if (dsAspectFlags) if (dsAspectFlags)
...@@ -2242,7 +2234,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2242,7 +2234,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Color attachments. // Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors(); const auto &colorRenderTargets = mRenderTargetCache.getColors();
uint32_t colorAttachmentCount = 0; uint32_t colorAttachmentCount = 0;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
...@@ -2386,7 +2378,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2386,7 +2378,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Transition the images to the correct layout (through onColorDraw) after the // Transition the images to the correct layout (through onColorDraw) after the
// resolve-to-multisampled copies are done. // resolve-to-multisampled copies are done.
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
colorRenderTarget->onColorDraw(contextVk); colorRenderTarget->onColorDraw(contextVk);
......
...@@ -124,13 +124,6 @@ class FramebufferVk : public FramebufferImpl ...@@ -124,13 +124,6 @@ class FramebufferVk : public FramebufferImpl
const vk::RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; } const vk::RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; }
// We only support depth/stencil packed format and depthstencil attachment always follow all
// color attachments
size_t getDepthStencilAttachmentIndexVk() const
{
return getState().getEnabledDrawBuffers().count();
}
angle::Result getFramebuffer(ContextVk *contextVk, angle::Result getFramebuffer(ContextVk *contextVk,
vk::Framebuffer **framebufferOut, vk::Framebuffer **framebufferOut,
const vk::ImageView *resolveImageViewIn); const vk::ImageView *resolveImageViewIn);
...@@ -257,6 +250,8 @@ class FramebufferVk : public FramebufferImpl ...@@ -257,6 +250,8 @@ class FramebufferVk : public FramebufferImpl
vk::FramebufferDesc mCurrentFramebufferDesc; vk::FramebufferDesc mCurrentFramebufferDesc;
std::unordered_map<vk::FramebufferDesc, vk::FramebufferHelper> mFramebufferCache; std::unordered_map<vk::FramebufferDesc, vk::FramebufferHelper> mFramebufferCache;
// Tracks all the color buffers attached to this FramebufferDesc
gl::DrawBufferMask mAttachedColorBufferMask;
vk::ClearValuesArray mDeferredClears; vk::ClearValuesArray mDeferredClears;
}; };
......
...@@ -1162,7 +1162,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk, ...@@ -1162,7 +1162,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
vk::GraphicsPipelineDesc pipelineDesc; vk::GraphicsPipelineDesc pipelineDesc;
pipelineDesc.initDefaults(); pipelineDesc.initDefaults();
pipelineDesc.setCullMode(VK_CULL_MODE_NONE); pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask()); pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask(), gl::DrawBufferMask());
pipelineDesc.setSingleColorWriteMask(params.colorAttachmentIndexGL, params.colorMaskFlags); pipelineDesc.setSingleColorWriteMask(params.colorAttachmentIndexGL, params.colorMaskFlags);
pipelineDesc.setRasterizationSamples(framebuffer->getSamples()); pipelineDesc.setRasterizationSamples(framebuffer->getSamples());
pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc()); pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
...@@ -1374,11 +1374,12 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk, ...@@ -1374,11 +1374,12 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk,
if (blitColor) if (blitColor)
{ {
pipelineDesc.setColorWriteMask(kAllColorComponents, pipelineDesc.setColorWriteMask(kAllColorComponents,
framebuffer->getEmulatedAlphaAttachmentMask()); framebuffer->getEmulatedAlphaAttachmentMask(),
~gl::DrawBufferMask());
} }
else else
{ {
pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask()); pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask(), gl::DrawBufferMask());
} }
pipelineDesc.setCullMode(VK_CULL_MODE_NONE); pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc()); pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
......
...@@ -1246,7 +1246,8 @@ void GraphicsPipelineDesc::updateBlendFuncs(GraphicsPipelineTransitionBits *tran ...@@ -1246,7 +1246,8 @@ void GraphicsPipelineDesc::updateBlendFuncs(GraphicsPipelineTransitionBits *tran
} }
void GraphicsPipelineDesc::setColorWriteMask(VkColorComponentFlags colorComponentFlags, void GraphicsPipelineDesc::setColorWriteMask(VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask) const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers)
{ {
PackedInputAssemblyAndColorBlendStateInfo &inputAndBlend = mInputAssemblyAndColorBlendStateInfo; PackedInputAssemblyAndColorBlendStateInfo &inputAndBlend = mInputAssemblyAndColorBlendStateInfo;
uint8_t colorMask = static_cast<uint8_t>(colorComponentFlags); uint8_t colorMask = static_cast<uint8_t>(colorComponentFlags);
...@@ -1254,8 +1255,11 @@ void GraphicsPipelineDesc::setColorWriteMask(VkColorComponentFlags colorComponen ...@@ -1254,8 +1255,11 @@ void GraphicsPipelineDesc::setColorWriteMask(VkColorComponentFlags colorComponen
for (uint32_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; for (uint32_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
colorIndexGL++) colorIndexGL++)
{ {
uint8_t mask = uint8_t mask = 0;
alphaMask[colorIndexGL] ? (colorMask & ~VK_COLOR_COMPONENT_A_BIT) : colorMask; if (enabledDrawBuffers.test(colorIndexGL))
{
mask = alphaMask[colorIndexGL] ? (colorMask & ~VK_COLOR_COMPONENT_A_BIT) : colorMask;
}
Int4Array_Set(inputAndBlend.colorWriteMaskBits, colorIndexGL, mask); Int4Array_Set(inputAndBlend.colorWriteMaskBits, colorIndexGL, mask);
} }
} }
...@@ -1270,9 +1274,10 @@ void GraphicsPipelineDesc::setSingleColorWriteMask(uint32_t colorIndexGL, ...@@ -1270,9 +1274,10 @@ void GraphicsPipelineDesc::setSingleColorWriteMask(uint32_t colorIndexGL,
void GraphicsPipelineDesc::updateColorWriteMask(GraphicsPipelineTransitionBits *transition, void GraphicsPipelineDesc::updateColorWriteMask(GraphicsPipelineTransitionBits *transition,
VkColorComponentFlags colorComponentFlags, VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask) const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers)
{ {
setColorWriteMask(colorComponentFlags, alphaMask); setColorWriteMask(colorComponentFlags, alphaMask, enabledDrawBuffers);
for (size_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; for (size_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
colorIndexGL++) colorIndexGL++)
......
...@@ -523,11 +523,13 @@ class GraphicsPipelineDesc final ...@@ -523,11 +523,13 @@ class GraphicsPipelineDesc final
void updateBlendEquations(GraphicsPipelineTransitionBits *transition, void updateBlendEquations(GraphicsPipelineTransitionBits *transition,
const gl::BlendState &blendState); const gl::BlendState &blendState);
void setColorWriteMask(VkColorComponentFlags colorComponentFlags, void setColorWriteMask(VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask); const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers);
void setSingleColorWriteMask(uint32_t colorIndexGL, VkColorComponentFlags colorComponentFlags); void setSingleColorWriteMask(uint32_t colorIndexGL, VkColorComponentFlags colorComponentFlags);
void updateColorWriteMask(GraphicsPipelineTransitionBits *transition, void updateColorWriteMask(GraphicsPipelineTransitionBits *transition,
VkColorComponentFlags colorComponentFlags, VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask); const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers);
// Depth/stencil states. // Depth/stencil states.
void setDepthTestEnabled(bool enabled); void setDepthTestEnabled(bool enabled);
......
...@@ -526,6 +526,50 @@ TEST_P(DrawBuffersWebGL2Test, TwoProgramsWithDifferentOutputsAndClear) ...@@ -526,6 +526,50 @@ TEST_P(DrawBuffersWebGL2Test, TwoProgramsWithDifferentOutputsAndClear)
glDeleteProgram(program); glDeleteProgram(program);
} }
// Test clear with gaps in draw buffers, originally show up as
// webgl_conformance_vulkan_passthrough_tests conformance/extensions/webgl-draw-buffers.html
// failure. This is added for ease of debugging.
TEST_P(DrawBuffersWebGL2Test, Clear)
{
ANGLE_SKIP_TEST_IF(!setupTest());
constexpr GLint kMaxBuffers = 4;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
ASSERT_GE(mMaxDrawBuffers, kMaxBuffers);
GLenum drawBufs[kMaxBuffers] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
// Enable all draw buffers.
for (GLuint texIndex = 0; texIndex < kMaxBuffers; texIndex++)
{
glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
mTextures[texIndex], 0);
}
// Clear with all draw buffers.
setDrawBuffers(kMaxBuffers, drawBufs);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Clear with first half none draw buffers.
drawBufs[0] = GL_NONE;
drawBufs[1] = GL_NONE;
setDrawBuffers(kMaxBuffers, drawBufs);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Verify first is drawn red, second is untouched, and last two are cleared green.
verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::red);
verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);
verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);
}
TEST_P(DrawBuffersTest, UnwrittenOutputVariablesShouldNotCrash) TEST_P(DrawBuffersTest, UnwrittenOutputVariablesShouldNotCrash)
{ {
ANGLE_SKIP_TEST_IF(!setupTest()); ANGLE_SKIP_TEST_IF(!setupTest());
...@@ -736,6 +780,188 @@ TEST_P(DrawBuffersTestES3, 2DArrayTextures) ...@@ -736,6 +780,188 @@ TEST_P(DrawBuffersTestES3, 2DArrayTextures)
glDeleteProgram(program); glDeleteProgram(program);
} }
// Vulkan backend is setting per buffer color mask to false for draw buffers that set to GL_NONE.
// These set of tests are to test draw buffer change followed by draw/clear/blit and followed by
// draw buffer change are behaving correctly.
class ColorMaskForDrawBuffersTest : public DrawBuffersTest
{
protected:
void setupColorMaskForDrawBuffersTest()
{
glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
0);
glBindTexture(GL_TEXTURE_2D, mTextures[1]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1],
0);
glBindTexture(GL_TEXTURE_2D, mTextures[2]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mTextures[2],
0);
constexpr char kFS_ESSL3[] =
"#version 300 es\n"
"precision highp float;\n"
"uniform mediump vec4 u_color0;\n"
"uniform mediump vec4 u_color1;\n"
"uniform mediump vec4 u_color2;\n"
"layout(location = 0) out vec4 out_color0;\n"
"layout(location = 1) out vec4 out_color1;\n"
"layout(location = 2) out vec4 out_color2;\n"
"void main()\n"
"{\n"
" out_color0 = u_color0;\n"
" out_color1 = u_color1;\n"
" out_color2 = u_color2;\n"
"}\n";
program = CompileProgram(essl3_shaders::vs::Simple(), kFS_ESSL3);
glUseProgram(program);
positionLocation = glGetAttribLocation(program, positionAttrib());
ASSERT_NE(-1, positionLocation);
color0UniformLocation = glGetUniformLocation(program, "u_color0");
ASSERT_NE(color0UniformLocation, -1);
color1UniformLocation = glGetUniformLocation(program, "u_color1");
ASSERT_NE(color1UniformLocation, -1);
color2UniformLocation = glGetUniformLocation(program, "u_color2");
ASSERT_NE(color2UniformLocation, -1);
glUniform4fv(color0UniformLocation, 1, GLColor::red.toNormalizedVector().data());
glUniform4fv(color1UniformLocation, 1, GLColor::green.toNormalizedVector().data());
glUniform4fv(color2UniformLocation, 1, GLColor::yellow.toNormalizedVector().data());
// First draw into both buffers so that buffer0 is red and buffer1 is green
resetDrawBuffers();
drawQuad(program, positionAttrib(), 0.5);
EXPECT_GL_NO_ERROR();
for (int i = 0; i < 4; i++)
{
drawBuffers[i] = GL_NONE;
}
}
void resetDrawBuffers()
{
drawBuffers[0] = GL_COLOR_ATTACHMENT0;
drawBuffers[1] = GL_COLOR_ATTACHMENT1;
drawBuffers[2] = GL_COLOR_ATTACHMENT2;
drawBuffers[3] = GL_NONE;
setDrawBuffers(4, drawBuffers);
}
GLenum drawBuffers[4];
GLuint program;
GLint positionLocation;
GLint color0UniformLocation;
GLint color1UniformLocation;
GLint color2UniformLocation;
};
// Test draw buffer state change followed draw call
TEST_P(ColorMaskForDrawBuffersTest, DrawQuad)
{
ANGLE_SKIP_TEST_IF(!setupTest());
setupColorMaskForDrawBuffersTest();
// Draw blue into attachment0. Buffer0 should be blue and buffer1 should remain green
drawBuffers[0] = GL_COLOR_ATTACHMENT0;
setDrawBuffers(4, drawBuffers);
glUniform4fv(color0UniformLocation, 1, GLColor::blue.toNormalizedVector().data());
glUniform4fv(color1UniformLocation, 1, GLColor::cyan.toNormalizedVector().data());
glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
drawQuad(program, positionAttrib(), 0.5);
resetDrawBuffers();
glUniform4fv(color0UniformLocation, 1, GLColor::magenta.toNormalizedVector().data());
glUniform4fv(color1UniformLocation, 1, GLColor::white.toNormalizedVector().data());
glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);
drawQuad(program, positionAttrib(), 0.5);
EXPECT_GL_NO_ERROR();
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
0);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],
0);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::white);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);
EXPECT_GL_NO_ERROR();
}
// Test draw buffer state change followed clear
TEST_P(ColorMaskForDrawBuffersTest, Clear)
{
ANGLE_SKIP_TEST_IF(!setupTest());
setupColorMaskForDrawBuffersTest();
// Clear attachment1. Buffer0 should retain red and buffer1 should be blue
drawBuffers[1] = GL_COLOR_ATTACHMENT1;
setDrawBuffers(4, drawBuffers);
GLfloat *clearColor = GLColor::blue.toNormalizedVector().data();
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glClear(GL_COLOR_BUFFER_BIT);
verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::blue);
EXPECT_GL_NO_ERROR();
}
// Test draw buffer state change followed scissored clear
TEST_P(ColorMaskForDrawBuffersTest, ScissoredClear)
{
ANGLE_SKIP_TEST_IF(!setupTest());
setupColorMaskForDrawBuffersTest();
// Clear attachment1. Buffer0 should retain red and buffer1 should be blue
drawBuffers[1] = GL_COLOR_ATTACHMENT1;
setDrawBuffers(4, drawBuffers);
GLfloat *clearColor = GLColor::blue.toNormalizedVector().data();
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glScissor(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
resetDrawBuffers();
clearColor = GLColor::magenta.toNormalizedVector().data();
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glScissor(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
0);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],
0);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);
EXPECT_GL_NO_ERROR();
}
// Test draw buffer state change followed FBO blit
TEST_P(ColorMaskForDrawBuffersTest, Blit)
{
ANGLE_SKIP_TEST_IF(!setupTest());
setupColorMaskForDrawBuffersTest();
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[2],
0);
// BLIT mTexture[2] to attachment0. Buffer0 should remain red and buffer1 should be yellow
drawBuffers[0] = GL_COLOR_ATTACHMENT0;
setDrawBuffers(4, drawBuffers);
glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(),
getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::green);
EXPECT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(DrawBuffersTest, ANGLE_INSTANTIATE_TEST(DrawBuffersTest,
...@@ -745,3 +971,5 @@ ANGLE_INSTANTIATE_TEST(DrawBuffersTest, ...@@ -745,3 +971,5 @@ ANGLE_INSTANTIATE_TEST(DrawBuffersTest,
ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersWebGL2Test); ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersWebGL2Test);
ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersTestES3); ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersTestES3);
ANGLE_INSTANTIATE_TEST_ES3(ColorMaskForDrawBuffersTest);
...@@ -1183,6 +1183,65 @@ TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass) ...@@ -1183,6 +1183,65 @@ TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass)
EXPECT_PIXEL_NEAR(0, 0, 63, 127, 255, 191, 1); EXPECT_PIXEL_NEAR(0, 0, 63, 127, 255, 191, 1);
} }
// Tests that draw buffer change with all color channel mask off should not break renderpass
TEST_P(VulkanPerformanceCounterTest, DrawbufferChangeWithAllColorMaskDisabled)
{
const rx::vk::PerfCounters &counters = hackANGLE();
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor());
glUseProgram(program);
GLint colorUniformLocation =
glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
ASSERT_NE(-1, colorUniformLocation);
ASSERT_GL_NO_ERROR();
GLTexture textureRGBA;
glBindTexture(GL_TEXTURE_2D, textureRGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLTexture textureDepth;
glBindTexture(GL_TEXTURE_2D, textureDepth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 64, 64, 0, GL_DEPTH_COMPONENT,
GL_UNSIGNED_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureRGBA, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureDepth, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
uint32_t expectedRenderPassCount = counters.renderPasses + 1;
// Draw into FBO
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f); // clear to green
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, 256, 256);
glUniform4fv(colorUniformLocation, 1, GLColor::blue.toNormalizedVector().data());
GLenum glDrawBuffers_bufs_1[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, glDrawBuffers_bufs_1);
glEnable(GL_DEPTH_TEST);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
// Change draw buffer state and color mask
GLenum glDrawBuffers_bufs_0[] = {GL_NONE};
glDrawBuffers(1, glDrawBuffers_bufs_0);
glColorMask(false, false, false, false);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.6f);
// Change back draw buffer state and color mask
glDrawBuffers(1, glDrawBuffers_bufs_1);
glColorMask(true, true, true, true);
glUniform4fv(colorUniformLocation, 1, GLColor::red.toNormalizedVector().data());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.7f);
uint32_t actualRenderPassCount = counters.renderPasses;
EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount);
}
ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest, ES3_VULKAN()); ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest, ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest_ES31, ES31_VULKAN()); ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest_ES31, ES31_VULKAN());
......
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