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/+/2389007
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Tim Van Patten <timvp@google.com>
Commit-Queue: Charlie Lao <cclao@google.com>
This commit is contained in:
Charlie Lao
2020-09-01 11:23:09 -07:00
committed by Commit Bot
parent 821aabb385
commit e4e2a016a7
8 changed files with 336 additions and 54 deletions

View File

@@ -2624,10 +2624,10 @@ void ContextVk::updateColorMask(const gl::BlendState &blendState)
mClearColorMask =
gl_vk::GetColorComponentFlags(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha);
FramebufferVk *framebufferVk = vk::GetImpl(mState.getDrawFramebuffer());
mGraphicsPipelineDesc->updateColorWriteMask(&mGraphicsPipelineTransition, mClearColorMask,
framebufferVk->getEmulatedAlphaAttachmentMask());
framebufferVk->getEmulatedAlphaAttachmentMask(),
framebufferVk->getState().getEnabledDrawBuffers());
}
void ContextVk::updateSampleMask(const gl::State &glState)

View File

@@ -1477,9 +1477,10 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
{
// Set the appropriate storeOp for attachments.
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(
attachmentIndexVk);
@@ -1576,16 +1577,19 @@ angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context,
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();
if (enabledColor)
{
mCurrentFramebufferDesc.updateColor(colorIndexGL, renderTarget->getDrawSubresourceSerial());
mAttachedColorBufferMask.set(colorIndexGL);
}
else
{
mCurrentFramebufferDesc.updateColor(colorIndexGL, vk::kInvalidImageViewSubresourceSerial);
mAttachedColorBufferMask.reset(colorIndexGL);
}
if (enabledResolve)
@@ -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
// flushDeferredClears() call is missing somewhere. ASSERT this to catch these bugs.
vk::ClearValuesArray previousDeferredClears = mDeferredClears;
bool shouldUpdateColorMask = false;
// For any updated attachments we'll update their Serials below
ASSERT(dirtyBits.any());
@@ -1681,22 +1686,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
break;
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
// Force update of serial for enabled draw buffers
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);
shouldUpdateColorMask = true;
break;
case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
@@ -1724,13 +1714,18 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
}
ASSERT(!previousDeferredClears.test(colorIndexGL));
ANGLE_TRY(updateColorAttachment(context, deferClears, colorIndexGL));
shouldUpdateColorMask = true;
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
// framebuffer we might not get a RenderPass. Also when there are masked out cleared color
// channels.
@@ -1802,11 +1797,10 @@ void FramebufferVk::updateRenderPassDesc()
mRenderPassDesc.setSamples(getSamples());
// Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors();
const gl::DrawBufferMask enabledDrawBuffers = mState.getEnabledDrawBuffers();
for (size_t colorIndexGL = 0; colorIndexGL < enabledDrawBuffers.size(); ++colorIndexGL)
const auto &colorRenderTargets = mRenderTargetCache.getColors();
for (size_t colorIndexGL = 0; colorIndexGL < mAttachedColorBufferMask.size(); ++colorIndexGL)
{
if (enabledDrawBuffers[colorIndexGL])
if (mAttachedColorBufferMask[colorIndexGL])
{
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget);
@@ -1880,7 +1874,7 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
// Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors();
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
for (size_t colorIndexGL : mAttachedColorBufferMask)
{
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget);
@@ -1920,7 +1914,7 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
else
{
// 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];
ASSERT(colorRenderTarget);
@@ -2124,18 +2118,16 @@ void FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
ASSERT(commands.getCommandBuffer().empty());
// The clear colors are packed with no gaps. The draw buffers mask is unpacked
// and can have gaps. Thus we need to count the packed index explicitly in this loop.
size_t colorCount = 0;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
uint32_t colorIndexVk = 0;
for (size_t colorIndexGL : mAttachedColorBufferMask)
{
if (clearColorBuffers[colorIndexGL])
if (mState.getEnabledDrawBuffers()[colorIndexGL] && clearColorBuffers[colorIndexGL])
{
VkClearValue clearValue =
getCorrectedColorClearValue(colorIndexGL, clearColorValue);
commands.updateRenderPassColorClear(colorCount, clearValue);
commands.updateRenderPassColorClear(colorIndexVk, clearValue);
}
colorCount++;
++colorIndexVk;
}
if (dsAspectFlags)
@@ -2242,7 +2234,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors();
uint32_t colorAttachmentCount = 0;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
for (size_t colorIndexGL : mAttachedColorBufferMask)
{
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget);
@@ -2386,7 +2378,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Transition the images to the correct layout (through onColorDraw) after the
// resolve-to-multisampled copies are done.
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
for (size_t colorIndexGL : mAttachedColorBufferMask)
{
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
colorRenderTarget->onColorDraw(contextVk);

View File

@@ -124,13 +124,6 @@ class FramebufferVk : public FramebufferImpl
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,
vk::Framebuffer **framebufferOut,
const vk::ImageView *resolveImageViewIn);
@@ -257,6 +250,8 @@ class FramebufferVk : public FramebufferImpl
vk::FramebufferDesc mCurrentFramebufferDesc;
std::unordered_map<vk::FramebufferDesc, vk::FramebufferHelper> mFramebufferCache;
// Tracks all the color buffers attached to this FramebufferDesc
gl::DrawBufferMask mAttachedColorBufferMask;
vk::ClearValuesArray mDeferredClears;
};

View File

@@ -1162,7 +1162,7 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
vk::GraphicsPipelineDesc pipelineDesc;
pipelineDesc.initDefaults();
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.setRasterizationSamples(framebuffer->getSamples());
pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
@@ -1374,11 +1374,12 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk,
if (blitColor)
{
pipelineDesc.setColorWriteMask(kAllColorComponents,
framebuffer->getEmulatedAlphaAttachmentMask());
framebuffer->getEmulatedAlphaAttachmentMask(),
~gl::DrawBufferMask());
}
else
{
pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask());
pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask(), gl::DrawBufferMask());
}
pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());

View File

@@ -1246,7 +1246,8 @@ void GraphicsPipelineDesc::updateBlendFuncs(GraphicsPipelineTransitionBits *tran
}
void GraphicsPipelineDesc::setColorWriteMask(VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask)
const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers)
{
PackedInputAssemblyAndColorBlendStateInfo &inputAndBlend = mInputAssemblyAndColorBlendStateInfo;
uint8_t colorMask = static_cast<uint8_t>(colorComponentFlags);
@@ -1254,8 +1255,11 @@ void GraphicsPipelineDesc::setColorWriteMask(VkColorComponentFlags colorComponen
for (uint32_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
colorIndexGL++)
{
uint8_t mask =
alphaMask[colorIndexGL] ? (colorMask & ~VK_COLOR_COMPONENT_A_BIT) : colorMask;
uint8_t mask = 0;
if (enabledDrawBuffers.test(colorIndexGL))
{
mask = alphaMask[colorIndexGL] ? (colorMask & ~VK_COLOR_COMPONENT_A_BIT) : colorMask;
}
Int4Array_Set(inputAndBlend.colorWriteMaskBits, colorIndexGL, mask);
}
}
@@ -1270,9 +1274,10 @@ void GraphicsPipelineDesc::setSingleColorWriteMask(uint32_t colorIndexGL,
void GraphicsPipelineDesc::updateColorWriteMask(GraphicsPipelineTransitionBits *transition,
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;
colorIndexGL++)

View File

@@ -523,11 +523,13 @@ class GraphicsPipelineDesc final
void updateBlendEquations(GraphicsPipelineTransitionBits *transition,
const gl::BlendState &blendState);
void setColorWriteMask(VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask);
const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers);
void setSingleColorWriteMask(uint32_t colorIndexGL, VkColorComponentFlags colorComponentFlags);
void updateColorWriteMask(GraphicsPipelineTransitionBits *transition,
VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask);
const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers);
// Depth/stencil states.
void setDepthTestEnabled(bool enabled);

View File

@@ -526,6 +526,50 @@ TEST_P(DrawBuffersWebGL2Test, TwoProgramsWithDifferentOutputsAndClear)
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)
{
ANGLE_SKIP_TEST_IF(!setupTest());
@@ -736,6 +780,188 @@ TEST_P(DrawBuffersTestES3, 2DArrayTextures)
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
// tests should be run against.
ANGLE_INSTANTIATE_TEST(DrawBuffersTest,
@@ -745,3 +971,5 @@ ANGLE_INSTANTIATE_TEST(DrawBuffersTest,
ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersWebGL2Test);
ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersTestES3);
ANGLE_INSTANTIATE_TEST_ES3(ColorMaskForDrawBuffersTest);

View File

@@ -1183,6 +1183,65 @@ TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass)
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_ES31, ES31_VULKAN());