Commit 5fd3693e by Luc Ferron Committed by Commit Bot

Vulkan: Mask the alpha channel for draw when needed

When the angleFormat we have has no alpha channel, but the actual texture underneath has one, we shouldn't be drawing over the alpha channel, so we apply a mask on it when we're in this situation. Bug: angleproject:2597 Change-Id: Ia7110709e6ee32bb61988d08f5049e4e80e7e24e Reviewed-on: https://chromium-review.googlesource.com/1106759 Commit-Queue: Luc Ferron <lucferron@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 1a3bbaa8
......@@ -362,6 +362,17 @@ void ContextVk::popDebugGroup()
UNIMPLEMENTED();
}
void ContextVk::updateClearColorMask(const gl::BlendState &blendState)
{
mClearColorMask =
gl_vk::GetColorComponentFlags(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha);
FramebufferVk *framebufferVk = vk::GetImpl(mState.getState().getDrawFramebuffer());
mPipelineDesc->updateColorWriteMask(mClearColorMask,
framebufferVk->getEmulatedAlphaAttachmentMask());
}
void ContextVk::updateScissor(const gl::State &glState)
{
if (glState.isScissorTestEnabled())
......@@ -417,14 +428,8 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
mPipelineDesc->updateBlendEquations(glState.getBlendState());
break;
case gl::State::DIRTY_BIT_COLOR_MASK:
{
const gl::BlendState &blendState = glState.getBlendState();
mClearColorMask = gl_vk::GetColorComponentFlags(
blendState.colorMaskRed, blendState.colorMaskGreen, blendState.colorMaskBlue,
blendState.colorMaskAlpha);
mPipelineDesc->updateColorWriteMask(mClearColorMask);
updateClearColorMask(glState.getBlendState());
break;
}
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
WARN() << "DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED unimplemented";
break;
......@@ -534,7 +539,7 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
WARN() << "DIRTY_BIT_READ_FRAMEBUFFER_BINDING unimplemented";
break;
case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
WARN() << "DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING unimplemented";
updateClearColorMask(glState.getBlendState());
break;
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
WARN() << "DIRTY_BIT_RENDERBUFFER_BINDING unimplemented";
......
......@@ -171,6 +171,7 @@ class ContextVk : public ContextImpl
vk::CommandBuffer **commandBufferOut,
bool *shouldApplyVertexArrayOut);
void updateClearColorMask(const gl::BlendState &blendState);
void updateScissor(const gl::State &glState);
RendererVk *mRenderer;
......
......@@ -203,11 +203,21 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
const VkClearColorValue &clearColorValue = contextVk->getClearColorValue().color;
for (size_t colorIndex : mState.getEnabledDrawBuffers())
{
VkClearColorValue modifiedClearColorValue = clearColorValue;
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex];
// Its possible we're clearing a render target that has no alpha channel but we represent it
// with a texture that has one. We must not affect its alpha channel no matter what the
// clear value is in that case.
if (mEmulatedAlphaAttachmentMask[colorIndex])
{
modifiedClearColorValue.float32[3] = 1.0;
}
ASSERT(colorRenderTarget);
vk::ImageHelper *image = colorRenderTarget->getImageForWrite(currentSerial, this);
GLint mipLevelToClear = (attachment->type() == GL_TEXTURE) ? attachment->mipLevel() : 0;
image->clearColor(clearColorValue, mipLevelToClear, 1, commandBuffer);
image->clearColor(modifiedClearColorValue, mipLevelToClear, 1, commandBuffer);
}
return gl::NoError();
......@@ -369,9 +379,19 @@ gl::Error FramebufferVk::syncState(const gl::Context *context,
RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndex];
if (renderTarget)
{
const angle::Format &format = renderTarget->getImageFormat().textureFormat();
updateActiveColorMasks(colorIndex, format.redBits > 0, format.greenBits > 0,
format.blueBits > 0, format.alphaBits > 0);
const angle::Format &emulatedFormat =
renderTarget->getImageFormat().textureFormat();
updateActiveColorMasks(
colorIndex, emulatedFormat.redBits > 0, emulatedFormat.greenBits > 0,
emulatedFormat.blueBits > 0, emulatedFormat.alphaBits > 0);
// TODO(lucferron): Add a test to trigger edge case where the framebuffer
// attachment would change but not the binding.
// http://anglebug.com/2597
const angle::Format &sourceFormat =
renderTarget->getImageFormat().angleFormat();
mEmulatedAlphaAttachmentMask.set(
colorIndex, sourceFormat.alphaBits == 0 && emulatedFormat.alphaBits > 0);
}
else
{
......@@ -383,8 +403,8 @@ gl::Error FramebufferVk::syncState(const gl::Context *context,
}
mActiveColorComponents = gl_vk::GetColorComponentFlags(
mActiveColorComponentMasks[0].any(), mActiveColorComponentMasks[1].any(),
mActiveColorComponentMasks[2].any(), mActiveColorComponentMasks[3].any());
mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(),
mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any());
mRenderPassDesc.reset();
renderer->releaseObject(getStoredQueueSerial(), &mFramebuffer);
......@@ -626,7 +646,7 @@ gl::Error FramebufferVk::clearWithDraw(const gl::Context *context,
// This pipeline desc could be cached.
vk::PipelineDesc pipelineDesc;
pipelineDesc.initDefaults();
pipelineDesc.updateColorWriteMask(colorMaskFlags);
pipelineDesc.updateColorWriteMask(colorMaskFlags, getEmulatedAlphaAttachmentMask());
pipelineDesc.updateRenderPassDesc(getRenderPassDesc());
pipelineDesc.updateShaders(fullScreenQuad->queueSerial(), pushConstantColor->queueSerial());
pipelineDesc.updateViewport(renderArea, 0.0f, 1.0f);
......@@ -740,10 +760,15 @@ gl::Error FramebufferVk::getCommandBufferForDraw(ContextVk *contextVk,
void FramebufferVk::updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a)
{
mActiveColorComponentMasks[0].set(colorIndex, r);
mActiveColorComponentMasks[1].set(colorIndex, g);
mActiveColorComponentMasks[2].set(colorIndex, b);
mActiveColorComponentMasks[3].set(colorIndex, a);
mActiveColorComponentMasksForClear[0].set(colorIndex, r);
mActiveColorComponentMasksForClear[1].set(colorIndex, g);
mActiveColorComponentMasksForClear[2].set(colorIndex, b);
mActiveColorComponentMasksForClear[3].set(colorIndex, a);
}
gl::DrawBufferMask FramebufferVk::getEmulatedAlphaAttachmentMask()
{
return mEmulatedAlphaAttachmentMask;
}
gl::Error FramebufferVk::readPixelsImpl(const gl::Context *context,
......
......@@ -100,6 +100,8 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
const gl::Extents &getReadImageExtents() const;
gl::DrawBufferMask getEmulatedAlphaAttachmentMask();
private:
FramebufferVk(const gl::FramebufferState &state);
FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer);
......@@ -124,9 +126,13 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
// channel is masked out, we check against the Framebuffer Attachments (RenderTargets) to see
// if the masked out channel is present in any of the attachments.
VkColorComponentFlags mActiveColorComponents;
gl::DrawBufferMask mActiveColorComponentMasks[4];
gl::DrawBufferMask mActiveColorComponentMasksForClear[4];
vk::DynamicBuffer mReadPixelsBuffer;
// When we draw to the framebuffer, and the real format has an alpha channel but the format of
// the framebuffer does not, we need to mask out the alpha channel. This DrawBufferMask will
// contain the mask to apply to the alpha channel when drawing.
gl::DrawBufferMask mEmulatedAlphaAttachmentMask;
};
} // namespace rx
......
......@@ -723,13 +723,15 @@ void PipelineDesc::updateBlendFuncs(const gl::BlendState &blendState)
}
}
void PipelineDesc::updateColorWriteMask(VkColorComponentFlags colorComponentFlags)
void PipelineDesc::updateColorWriteMask(VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask)
{
uint8_t colorMask = static_cast<uint8_t>(colorComponentFlags);
for (PackedColorBlendAttachmentState &blendAttachmentState : mColorBlendStateInfo.attachments)
for (size_t colorIndex = 0; colorIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorIndex++)
{
blendAttachmentState.colorWriteMask = colorMask;
mColorBlendStateInfo.attachments[colorIndex].colorWriteMask =
alphaMask[colorIndex] ? (colorMask & ~VK_COLOR_COMPONENT_A_BIT) : colorMask;
}
}
......
......@@ -382,7 +382,8 @@ class PipelineDesc final
void updateBlendColor(const gl::ColorF &color);
void updateBlendFuncs(const gl::BlendState &blendState);
void updateBlendEquations(const gl::BlendState &blendState);
void updateColorWriteMask(VkColorComponentFlags colorComponentFlags);
void updateColorWriteMask(VkColorComponentFlags colorComponentFlags,
const gl::DrawBufferMask &alphaMask);
// Depth/stencil states.
void updateDepthTestEnabled(const gl::DepthStencilState &depthStencilState);
......
......@@ -231,7 +231,6 @@
2592 VULKAN : dEQP-GLES2.functional.shaders.builtin_variable.depth_range* = SKIP
2595 VULKAN : dEQP-GLES2.functional.shaders.random.all_features.fragment* = SKIP
2597 VULKAN : dEQP-GLES2.functional.fbo.render.recreate_stencilbuffer.no_rebind_rbo_rgb* = SKIP
2597 VULKAN : dEQP-GLES2.functional.fbo.render.stencil_clear.tex2d_rgb_stencil_index8 = SKIP
2161 VULKAN : dEQP-GLES2.functional.vertex_arrays.* = SKIP
2598 VULKAN : dEQP-GLES2.functional.rasterization.primitives.line* = SKIP
2599 VULKAN : dEQP-GLES2.functional.rasterization.limits.points = SKIP
......
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