mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-04 22:09:59 +03:00
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:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user