Commit 9aef3670 by Jamie Madill Committed by Commit Bot

Vulkan: Implement masked color clears.

This implements masked color clear using clear shaders. The shaders themselves were introduced in a prior patch. In order to get the right setup for the draw call to trigger the shaders, we create an internal pipeline from the pipeline cache. We also use a special pipeline layout with only uniform buffers. The masked out color channels are disabled via settings on the pipeline. This fixes the dEQP masked color clear tests. It doesn't handle masked color clears combined with the depth clear bit. It's likely we don't have test coverage for this case. Bug: angleproject:2455 Change-Id: I513248cc0f7e58f490fc16ac9afb40119d730ccc Reviewed-on: https://chromium-review.googlesource.com/1031373 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 78feddc2
......@@ -45,6 +45,9 @@ constexpr gl::Rectangle kMaxSizedScissor(0,
std::numeric_limits<int>::max(),
std::numeric_limits<int>::max());
constexpr VkColorComponentFlags kAllColorChannelsMask =
(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT);
} // anonymous namespace
ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
......@@ -53,7 +56,8 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
mCurrentDrawMode(GL_NONE),
mDynamicDescriptorPool(),
mTexturesDirty(false),
mVertexArrayBindingHasChanged(false)
mVertexArrayBindingHasChanged(false),
mClearColorMask(kAllColorChannelsMask)
{
memset(&mClearColorValue, 0, sizeof(mClearColorValue));
memset(&mClearDepthStencilValue, 0, sizeof(mClearDepthStencilValue));
......@@ -117,7 +121,7 @@ gl::Error ContextVk::initPipeline()
mPipelineDesc->updateRenderPassDesc(framebufferVk->getRenderPassDesc());
// TODO(jmadill): Validate with ASSERT against physical device limits/caps?
ANGLE_TRY(mRenderer->getPipeline(programVk, *mPipelineDesc, activeAttribLocationsMask,
ANGLE_TRY(mRenderer->getAppPipeline(programVk, *mPipelineDesc, activeAttribLocationsMask,
&mCurrentPipeline));
return gl::NoError();
......@@ -404,8 +408,14 @@ void ContextVk::syncState(const gl::Context *context, const gl::State::DirtyBits
mPipelineDesc->updateBlendEquations(glState.getBlendState());
break;
case gl::State::DIRTY_BIT_COLOR_MASK:
mPipelineDesc->updateColorWriteMask(glState.getBlendState());
{
const gl::BlendState &blendState = glState.getBlendState();
mClearColorMask = gl_vk::GetColorComponentFlags(
blendState.colorMaskRed, blendState.colorMaskGreen, blendState.colorMaskBlue,
blendState.colorMaskAlpha);
mPipelineDesc->updateColorWriteMask(mClearColorMask);
break;
}
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
WARN() << "DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED unimplemented";
break;
......@@ -750,4 +760,8 @@ const VkClearValue &ContextVk::getClearDepthStencilValue() const
return mClearDepthStencilValue;
}
VkColorComponentFlags ContextVk::getClearColorMask() const
{
return mClearColorMask;
}
} // namespace rx
......@@ -158,6 +158,7 @@ class ContextVk : public ContextImpl
const VkClearValue &getClearColorValue() const;
const VkClearValue &getClearDepthStencilValue() const;
VkColorComponentFlags getClearColorMask() const;
const VkRect2D &getScissor() const { return mPipelineDesc->getScissor(); }
private:
......@@ -184,9 +185,10 @@ class ContextVk : public ContextImpl
bool mTexturesDirty;
bool mVertexArrayBindingHasChanged;
// Cached clear value for color and depth/stencil.
// Cached clear value/mask for color and depth/stencil.
VkClearValue mClearColorValue;
VkClearValue mClearDepthStencilValue;
VkColorComponentFlags mClearColorMask;
};
} // namespace rx
......
......@@ -99,12 +99,24 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
bool clearColor,
bool clearDepth,
bool clearStencil);
gl::Error clearWithDraw(ContextVk *contextVk, VkColorComponentFlags colorMaskFlags);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a);
WindowSurfaceVk *mBackbuffer;
Optional<vk::RenderPassDesc> mRenderPassDesc;
vk::Framebuffer mFramebuffer;
RenderTargetCache<RenderTargetVk> mRenderTargetCache;
// These two variables are used to quickly compute if we need to do a masked clear. If a color
// 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];
// For use in masked clear.
vk::BufferAndMemory mMaskedClearUniformBuffer;
VkDescriptorSet mMaskedClearDescriptorSet;
};
} // namespace rx
......
......@@ -220,6 +220,7 @@ RendererVk::~RendererVk()
}
mGraphicsPipelineLayout.destroy(mDevice);
mInternalUniformPipelineLayout.destroy(mDevice);
mRenderPassCache.destroy(mDevice);
mPipelineCache.destroy(mDevice);
......@@ -874,7 +875,7 @@ vk::Error RendererVk::initGraphicsPipelineLayout()
uint32_t blockCount = 0;
{
auto &layoutBinding = uniformBindings[blockCount];
VkDescriptorSetLayoutBinding &layoutBinding = uniformBindings[blockCount];
layoutBinding.binding = blockCount;
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
......@@ -886,7 +887,7 @@ vk::Error RendererVk::initGraphicsPipelineLayout()
}
{
auto &layoutBinding = uniformBindings[blockCount];
VkDescriptorSetLayoutBinding &layoutBinding = uniformBindings[blockCount];
layoutBinding.binding = blockCount;
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
......@@ -951,12 +952,40 @@ vk::Error RendererVk::initGraphicsPipelineLayout()
return vk::NoError();
}
const vk::DescriptorSetLayout &RendererVk::getInternalUniformDescriptorSetLayout() const
{
return mGraphicsDescriptorSetLayouts[0];
}
vk::Error RendererVk::getInternalUniformPipelineLayout(const vk::PipelineLayout **pipelineLayoutOut)
{
*pipelineLayoutOut = &mInternalUniformPipelineLayout;
if (mInternalUniformPipelineLayout.valid())
{
return vk::NoError();
}
// Here we use the knowledge that the "graphics" descriptor set has uniform blocks at offset 0.
VkPipelineLayoutCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.setLayoutCount = 1;
createInfo.pSetLayouts = mGraphicsDescriptorSetLayouts[0].ptr();
createInfo.pushConstantRangeCount = 0;
createInfo.pPushConstantRanges = nullptr;
ANGLE_TRY(mInternalUniformPipelineLayout.init(mDevice, createInfo));
return vk::NoError();
}
Serial RendererVk::issueShaderSerial()
{
return mShaderSerialFactory.generate();
}
vk::Error RendererVk::getPipeline(const ProgramVk *programVk,
vk::Error RendererVk::getAppPipeline(const ProgramVk *programVk,
const vk::PipelineDesc &desc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut)
......@@ -975,6 +1004,27 @@ vk::Error RendererVk::getPipeline(const ProgramVk *programVk,
programVk->getLinkedFragmentModule(), desc, pipelineOut);
}
vk::Error RendererVk::getInternalPipeline(const vk::ShaderAndSerial &vertexShader,
const vk::ShaderAndSerial &fragmentShader,
const vk::PipelineLayout &pipelineLayout,
const vk::PipelineDesc &pipelineDesc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut)
{
ASSERT(vertexShader.queueSerial() ==
pipelineDesc.getShaderStageInfo()[vk::ShaderType::VertexShader].moduleSerial);
ASSERT(fragmentShader.queueSerial() ==
pipelineDesc.getShaderStageInfo()[vk::ShaderType::FragmentShader].moduleSerial);
// Pull in a compatible RenderPass.
vk::RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(getCompatibleRenderPass(pipelineDesc.getRenderPassDesc(), &compatibleRenderPass));
return mPipelineCache.getPipeline(mDevice, *compatibleRenderPass, pipelineLayout,
activeAttribLocationsMask, vertexShader.get(),
fragmentShader.get(), pipelineDesc, pipelineOut);
}
vk::ShaderLibrary *RendererVk::getShaderLibrary()
{
return &mShaderLibrary;
......
......@@ -113,11 +113,20 @@ class RendererVk : angle::NonCopyable
const vk::AttachmentOpsArray &ops,
vk::RenderPass **renderPassOut);
vk::Error getPipeline(const ProgramVk *programVk,
// For getting a vk::Pipeline for the an application's draw call. RenderPassDesc is automatic.
vk::Error getAppPipeline(const ProgramVk *programVk,
const vk::PipelineDesc &desc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut);
// For getting a vk::Pipeline for an internal draw call. Use an explicit RenderPass.
vk::Error getInternalPipeline(const vk::ShaderAndSerial &vertexShader,
const vk::ShaderAndSerial &fragmentShader,
const vk::PipelineLayout &pipelineLayout,
const vk::PipelineDesc &pipelineDesc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut);
// This should only be called from ResourceVk.
// TODO(jmadill): Keep in ContextVk to enable threaded rendering.
vk::CommandGraphNode *allocateCommandNode();
......@@ -125,6 +134,10 @@ class RendererVk : angle::NonCopyable
const vk::PipelineLayout &getGraphicsPipelineLayout() const;
const std::vector<vk::DescriptorSetLayout> &getGraphicsDescriptorSetLayouts() const;
// Used in internal shaders.
vk::Error getInternalUniformPipelineLayout(const vk::PipelineLayout **pipelineLayoutOut);
const vk::DescriptorSetLayout &getInternalUniformDescriptorSetLayout() const;
// Issues a new serial for linked shader modules. Used in the pipeline cache.
Serial issueShaderSerial();
......@@ -189,6 +202,9 @@ class RendererVk : angle::NonCopyable
vk::PipelineLayout mGraphicsPipelineLayout;
std::vector<vk::DescriptorSetLayout> mGraphicsDescriptorSetLayouts;
// Used for internal shaders.
vk::PipelineLayout mInternalUniformPipelineLayout;
// Internal shader library.
vk::ShaderLibrary mShaderLibrary;
};
......
......@@ -727,9 +727,9 @@ void PipelineDesc::updateBlendFuncs(const gl::BlendState &blendState)
}
}
void PipelineDesc::updateColorWriteMask(const gl::BlendState &blendState)
void PipelineDesc::updateColorWriteMask(VkColorComponentFlags colorComponentFlags)
{
uint8_t colorMask = static_cast<uint8_t>(gl_vk::GetColorComponentFlags(blendState));
uint8_t colorMask = static_cast<uint8_t>(colorComponentFlags);
for (PackedColorBlendAttachmentState &blendAttachmentState : mColorBlendStateInfo.attachments)
{
......
......@@ -300,7 +300,7 @@ class PipelineDesc final
void updateBlendColor(const gl::ColorF &color);
void updateBlendFuncs(const gl::BlendState &blend_state);
void updateBlendEquations(const gl::BlendState &blend_state);
void updateColorWriteMask(const gl::BlendState &blendState);
void updateColorWriteMask(VkColorComponentFlags colorComponentFlags);
// Depth/stencil states.
void updateDepthTestEnabled(const gl::DepthStencilState &depthStencilState);
......
......@@ -242,7 +242,6 @@ class ImageHelper final : angle::NonCopyable
// Cached properties.
uint32_t mLayerCount;
};
} // namespace vk
} // namespace rx
......
......@@ -555,6 +555,15 @@ void CommandBuffer::executeCommands(uint32_t commandBufferCount,
vkCmdExecuteCommands(mHandle, commandBufferCount, commandBuffers[0].ptr());
}
void CommandBuffer::updateBuffer(const vk::Buffer &buffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const void *data)
{
ASSERT(valid() && buffer.valid());
vkCmdUpdateBuffer(mHandle, buffer.getHandle(), dstOffset, dataSize, data);
}
// Image implementation.
Image::Image()
{
......@@ -1364,12 +1373,10 @@ VkImageViewType GetImageViewType(gl::TextureType textureType)
}
}
VkColorComponentFlags GetColorComponentFlags(const gl::BlendState &blendState)
VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha)
{
return (blendState.colorMaskRed ? VK_COLOR_COMPONENT_R_BIT : 0) |
(blendState.colorMaskGreen ? VK_COLOR_COMPONENT_G_BIT : 0) |
(blendState.colorMaskBlue ? VK_COLOR_COMPONENT_B_BIT : 0) |
(blendState.colorMaskAlpha ? VK_COLOR_COMPONENT_A_BIT : 0);
return (red ? VK_COLOR_COMPONENT_R_BIT : 0) | (green ? VK_COLOR_COMPONENT_G_BIT : 0) |
(blue ? VK_COLOR_COMPONENT_B_BIT : 0) | (alpha ? VK_COLOR_COMPONENT_A_BIT : 0);
}
} // namespace gl_vk
} // namespace rx
......
......@@ -397,6 +397,10 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
const uint32_t *dynamicOffsets);
void executeCommands(uint32_t commandBufferCount, const CommandBuffer *commandBuffers);
void updateBuffer(const vk::Buffer &buffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const void *data);
};
class Image final : public WrappedObject<Image, VkImage>
......@@ -682,7 +686,7 @@ void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset);
void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent);
VkImageType GetImageType(gl::TextureType textureType);
VkImageViewType GetImageViewType(gl::TextureType textureType);
VkColorComponentFlags GetColorComponentFlags(const gl::BlendState &blendState);
VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha);
} // namespace gl_vk
} // namespace rx
......
......@@ -188,10 +188,6 @@
1028 WIN LINUX MAC : dEQP-GLES2.functional.fbo.completeness.renderable.texture.depth.srgb8 = FAIL
// Vulkan failures
2455 VULKAN : dEQP-GLES2.functional.color_clear.masked_rg* = FAIL
2455 VULKAN : dEQP-GLES2.functional.color_clear.masked_scissor* = FAIL
2455 VULKAN : dEQP-GLES2.functional.color_clear.complex_* = FAIL
2455 VULKAN : dEQP-GLES2.functional.color_clear.long_masked_* = FAIL
2161 VULKAN : dEQP-GLES2.functional.prerequisite.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.implementation_limits.* = SKIP
2161 VULKAN : dEQP-GLES2.functional.buffer.* = 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