Commit f6c937f8 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: fix masked stencil clear

Previously, masked stencil clear was done by clearing every stencil bit to the ClearValue & Mask. The correct behavior as implemented in this change is to clear only the bits that are set in Mask. This can only be done through a draw call, with ClearValue as the stencil reference, and Mask as the stencil write mask. Note: this change relies on the depthClamp Vulkan feature which is not available on ARM. Bug: angleproject:3241 Change-Id: I0a181c32f881ee813f144e7bdd6f42c8ea6f1966 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1548442 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTobin Ehlis <tobine@google.com>
parent 194a9674
...@@ -1349,7 +1349,31 @@ angle::Result Framebuffer::clear(const Context *context, GLbitfield mask) ...@@ -1349,7 +1349,31 @@ angle::Result Framebuffer::clear(const Context *context, GLbitfield mask)
return angle::Result::Continue; return angle::Result::Continue;
} }
ANGLE_TRY(mImpl->clear(context, mask)); // Remove clear bits that are ineffective. An effective clear changes at least one fragment. If
// color/depth/stencil masks make the clear ineffective we skip it altogether.
// If all color channels are masked, don't attempt to clear color.
if (context->getState().getBlendState().allChannelsMasked())
{
mask &= ~GL_COLOR_BUFFER_BIT;
}
// If depth write is disabled, don't attempt to clear depth.
if (!context->getState().getDepthStencilState().depthMask)
{
mask &= ~GL_DEPTH_BUFFER_BIT;
}
// If all stencil bits are masked, don't attempt to clear stencil.
if (context->getState().getDepthStencilState().stencilWritemask == 0)
{
mask &= ~GL_STENCIL_BUFFER_BIT;
}
if (mask != 0)
{
ANGLE_TRY(mImpl->clear(context, mask));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1364,6 +1388,23 @@ angle::Result Framebuffer::clearBufferfv(const Context *context, ...@@ -1364,6 +1388,23 @@ angle::Result Framebuffer::clearBufferfv(const Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
if (buffer == GL_DEPTH)
{
// If depth write is disabled, don't attempt to clear depth.
if (!context->getState().getDepthStencilState().depthMask)
{
return angle::Result::Continue;
}
}
else
{
// If all color channels are masked, don't attempt to clear color.
if (context->getState().getBlendState().allChannelsMasked())
{
return angle::Result::Continue;
}
}
ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values)); ANGLE_TRY(mImpl->clearBufferfv(context, buffer, drawbuffer, values));
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1379,6 +1420,12 @@ angle::Result Framebuffer::clearBufferuiv(const Context *context, ...@@ -1379,6 +1420,12 @@ angle::Result Framebuffer::clearBufferuiv(const Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
// If all color channels are masked, don't attempt to clear color.
if (context->getState().getBlendState().allChannelsMasked())
{
return angle::Result::Continue;
}
ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values)); ANGLE_TRY(mImpl->clearBufferuiv(context, buffer, drawbuffer, values));
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1394,6 +1441,23 @@ angle::Result Framebuffer::clearBufferiv(const Context *context, ...@@ -1394,6 +1441,23 @@ angle::Result Framebuffer::clearBufferiv(const Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
if (buffer == GL_STENCIL)
{
// If all stencil bits are masked, don't attempt to clear stencil.
if (context->getState().getDepthStencilState().stencilWritemask == 0)
{
return angle::Result::Continue;
}
}
else
{
// If all color channels are masked, don't attempt to clear color.
if (context->getState().getBlendState().allChannelsMasked())
{
return angle::Result::Continue;
}
}
ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values)); ANGLE_TRY(mImpl->clearBufferiv(context, buffer, drawbuffer, values));
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1410,7 +1474,22 @@ angle::Result Framebuffer::clearBufferfi(const Context *context, ...@@ -1410,7 +1474,22 @@ angle::Result Framebuffer::clearBufferfi(const Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
ANGLE_TRY(mImpl->clearBufferfi(context, buffer, drawbuffer, depth, stencil)); bool clearDepth = context->getState().getDepthStencilState().depthMask;
bool clearStencil = context->getState().getDepthStencilState().stencilWritemask != 0;
if (clearDepth && clearStencil)
{
ASSERT(buffer == GL_DEPTH_STENCIL);
ANGLE_TRY(mImpl->clearBufferfi(context, GL_DEPTH_STENCIL, drawbuffer, depth, stencil));
}
else if (clearDepth && !clearStencil)
{
ANGLE_TRY(mImpl->clearBufferfv(context, GL_DEPTH, drawbuffer, &depth));
}
else if (!clearDepth && clearStencil)
{
ANGLE_TRY(mImpl->clearBufferiv(context, GL_STENCIL, drawbuffer, &stencil));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -59,6 +59,11 @@ BlendState::BlendState(const BlendState &other) ...@@ -59,6 +59,11 @@ BlendState::BlendState(const BlendState &other)
memcpy(this, &other, sizeof(BlendState)); memcpy(this, &other, sizeof(BlendState));
} }
bool BlendState::allChannelsMasked() const
{
return !colorMaskRed && !colorMaskGreen && !colorMaskBlue && !colorMaskAlpha;
}
bool operator==(const BlendState &a, const BlendState &b) bool operator==(const BlendState &a, const BlendState &b)
{ {
return memcmp(&a, &b, sizeof(BlendState)) == 0; return memcmp(&a, &b, sizeof(BlendState)) == 0;
......
...@@ -146,6 +146,8 @@ struct BlendState final ...@@ -146,6 +146,8 @@ struct BlendState final
BlendState(); BlendState();
BlendState(const BlendState &other); BlendState(const BlendState &other);
bool allChannelsMasked() const;
bool blend; bool blend;
GLenum sourceBlendRGB; GLenum sourceBlendRGB;
GLenum destBlendRGB; GLenum destBlendRGB;
......
...@@ -234,20 +234,37 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -234,20 +234,37 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
// This function assumes that only enabled attachments are asked to be cleared. // This function assumes that only enabled attachments are asked to be cleared.
ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers); ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
bool clearColor = clearColorBuffers.any();
// Adjust clear behavior based on whether:
//
// - the respective attachments are present: if asked to clear a non-existent attachment, don't
// attempt to clear it.
// - extra clear is necessary: if depth- or stencil-only attachments are emulated with a format
// that has both aspects, clear the emulated aspect.
VkColorComponentFlags colorMaskFlags = contextVk->getClearColorMask();
bool clearColor = clearColorBuffers.any();
const gl::FramebufferAttachment *depthAttachment = mState.getDepthAttachment(); const gl::FramebufferAttachment *depthAttachment = mState.getDepthAttachment();
clearDepth = clearDepth && depthAttachment; clearDepth = clearDepth && depthAttachment;
ASSERT(!clearDepth || depthAttachment->isAttached()); ASSERT(!clearDepth || depthAttachment->isAttached());
// If depth write is disabled, pretend that depth clear is not requested altogether.
clearDepth = clearDepth && contextVk->getState().getDepthStencilState().depthMask;
const gl::FramebufferAttachment *stencilAttachment = mState.getStencilAttachment(); const gl::FramebufferAttachment *stencilAttachment = mState.getStencilAttachment();
clearStencil = clearStencil && stencilAttachment; clearStencil = clearStencil && stencilAttachment;
ASSERT(!clearStencil || stencilAttachment->isAttached()); ASSERT(!clearStencil || stencilAttachment->isAttached());
// If the only thing to be cleared was depth and it's masked, there's nothing to do. uint8_t stencilMask =
static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask);
// The front-end should ensure we don't attempt to clear color if all channels are masked.
ASSERT(!clearColor || colorMaskFlags != 0);
// The front-end should ensure we don't attempt to clear depth if depth write is disabled.
ASSERT(!clearDepth || contextVk->getState().getDepthStencilState().depthMask);
// The front-end should ensure we don't attempt to clear stencil if all bits are masked.
ASSERT(!clearStencil || stencilMask != 0);
// If there is nothing to clear, return right away (for example, if asked to clear depth, but
// there is no depth attachment).
if (!clearColor && !clearDepth && !clearStencil) if (!clearColor && !clearDepth && !clearStencil)
{ {
return angle::Result::Continue; return angle::Result::Continue;
...@@ -255,11 +272,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -255,11 +272,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
VkClearDepthStencilValue modifiedDepthStencilValue = clearDepthStencilValue; VkClearDepthStencilValue modifiedDepthStencilValue = clearDepthStencilValue;
// Apply the stencil mask to the clear value.
// TODO(syoussefi): this logic is flawed. See http://anglebug.com/3241#c9.
modifiedDepthStencilValue.stencil &=
contextVk->getState().getDepthStencilState().stencilWritemask;
// If the depth or stencil is being cleared, and the image was originally requested to have a // If the depth or stencil is being cleared, and the image was originally requested to have a
// single aspect, but it's emulated with a depth/stencil format, clear both aspects, setting the // single aspect, but it's emulated with a depth/stencil format, clear both aspects, setting the
// other aspect to 0. // other aspect to 0.
...@@ -287,19 +299,19 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -287,19 +299,19 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
bool isScissorTestEffectivelyEnabled = bool isScissorTestEffectivelyEnabled =
glState.isScissorTestEnabled() && scissorRenderAreaIntersection != renderArea; glState.isScissorTestEnabled() && scissorRenderAreaIntersection != renderArea;
// We can use render pass load ops if clearing depth/stencil or unmasked color. If there's a // We can use render pass load ops if clearing depth, unmasked color or unmasked stencil. If
// depth mask, depth clearing is disabled. If there's a stencil mask, the clear value is // there's a depth mask, depth clearing is already disabled.
// already masked. There is no depth/stencil condition prohibiting the use of render pass
// loadOp.
VkColorComponentFlags colorMaskFlags = contextVk->getClearColorMask();
bool maskedClearColor = bool maskedClearColor =
clearColor && (mActiveColorComponents & colorMaskFlags) != mActiveColorComponents; clearColor && (mActiveColorComponents & colorMaskFlags) != mActiveColorComponents;
bool clearColorWithRenderPassLoadOp = clearColor && !maskedClearColor; bool maskedClearStencil = stencilMask != 0xFF;
bool clearColorWithRenderPassLoadOp = clearColor && !maskedClearColor;
bool clearStencilWithRenderPassLoadOp = clearStencil && !maskedClearStencil;
// At least one of color, depth or stencil should be clearable with render pass loadOp for us // At least one of color, depth or stencil should be clearable with render pass loadOp for us
// to use this clear path. // to use this clear path.
bool clearAnyWithRenderPassLoadOp = bool clearAnyWithRenderPassLoadOp =
clearColorWithRenderPassLoadOp || clearDepth || clearStencil; clearColorWithRenderPassLoadOp || clearDepth || clearStencilWithRenderPassLoadOp;
if (clearAnyWithRenderPassLoadOp && !isScissorTestEffectivelyEnabled) if (clearAnyWithRenderPassLoadOp && !isScissorTestEffectivelyEnabled)
{ {
...@@ -313,7 +325,8 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -313,7 +325,8 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
} }
// If there's a color mask, only clear depth/stencil with render pass loadOp. // If there's a color mask, only clear depth/stencil with render pass loadOp.
ANGLE_TRY(clearWithRenderPassOp(contextVk, clearBuffersWithRenderPassLoadOp, clearDepth, ANGLE_TRY(clearWithRenderPassOp(contextVk, clearBuffersWithRenderPassLoadOp, clearDepth,
clearStencil, clearColorValue, modifiedDepthStencilValue)); clearStencilWithRenderPassLoadOp, clearColorValue,
modifiedDepthStencilValue));
// On some hardware, having inline commands at this point results in corrupted output. In // On some hardware, having inline commands at this point results in corrupted output. In
// that case, end the render pass immediately. http://anglebug.com/2361 // that case, end the render pass immediately. http://anglebug.com/2361
...@@ -323,39 +336,34 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -323,39 +336,34 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
} }
// Fallback to other methods for whatever isn't cleared here. // Fallback to other methods for whatever isn't cleared here.
clearDepth = false; clearDepth = false;
clearStencil = false;
if (clearColorWithRenderPassLoadOp) if (clearColorWithRenderPassLoadOp)
{ {
clearColorBuffers.reset();
clearColor = false; clearColor = false;
} }
if (clearStencilWithRenderPassLoadOp)
{
clearStencil = false;
}
if (!clearColor) // If nothing left to clear, early out.
if (!clearColor && !clearStencil)
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
} }
// The most costly clear mode is when we need to mask out specific color channels. This can // The most costly clear mode is when we need to mask out specific color channels or stencil
// only be done with a draw call. The scissor region however can easily be integrated with // bits. This can only be done with a draw call. The scissor region however can easily be
// this method. Similarly for depth/stencil clear. // integrated with this method.
if (maskedClearColor) //
// Since we have to have a draw call for the sake of masked color or stencil, we can make sure
// everything else is cleared with the draw call at the same time as well.
if (maskedClearColor || maskedClearStencil)
{ {
ANGLE_TRY(clearWithDraw(contextVk, clearColorBuffers, clearColorValue, colorMaskFlags)); return clearWithDraw(contextVk, clearColorBuffers, clearDepth, clearStencil, colorMaskFlags,
stencilMask, clearColorValue, modifiedDepthStencilValue);
// Stencil clears must be handled separately. The only way to write out a stencil value from
// a fragment shader in Vulkan is with VK_EXT_shader_stencil_export. Support for this
// extension is sparse. Hence, we call into the RenderPass clear path. We similarly clear
// depth to keep the code simple, but depth clears could be combined with the masked color
// clears as an optimization.
if (clearDepth || clearStencil)
{
ANGLE_TRY(clearWithClearAttachments(contextVk, gl::DrawBufferMask(), clearDepth,
clearStencil, clearColorValue,
modifiedDepthStencilValue));
}
return angle::Result::Continue;
} }
ASSERT(isScissorTestEffectivelyEnabled); ASSERT(isScissorTestEffectivelyEnabled);
...@@ -1173,15 +1181,25 @@ angle::Result FramebufferVk::clearWithClearAttachments( ...@@ -1173,15 +1181,25 @@ angle::Result FramebufferVk::clearWithClearAttachments(
angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk, angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
VkColorComponentFlags colorMaskFlags,
uint8_t stencilMask,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
VkColorComponentFlags colorMaskFlags) const VkClearDepthStencilValue &clearDepthStencilValue)
{ {
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
UtilsVk::ClearImageParameters params = {}; UtilsVk::ClearFramebufferParameters params = {};
params.renderAreaHeight = mState.getDimensions().height; params.renderPassDesc = &getRenderPassDesc();
params.clearValue = clearColorValue; params.renderAreaHeight = mState.getDimensions().height;
params.renderPassDesc = &getRenderPassDesc(); params.colorClearValue = clearColorValue;
params.depthStencilClearValue = clearDepthStencilValue;
params.stencilMask = stencilMask;
params.clearColor = true;
params.clearDepth = clearDepth;
params.clearStencil = clearStencil;
const auto &colorRenderTargets = mRenderTargetCache.getColors(); const auto &colorRenderTargets = mRenderTargetCache.getColors();
for (size_t colorIndex : clearColorBuffers) for (size_t colorIndex : clearColorBuffers)
...@@ -1189,15 +1207,26 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk, ...@@ -1189,15 +1207,26 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
const RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex]; const RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndex];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
params.format = &colorRenderTarget->getImage().getFormat().textureFormat(); params.colorFormat = &colorRenderTarget->getImage().getFormat().textureFormat();
params.attachmentIndex = colorIndex; params.colorAttachmentIndex = colorIndex;
params.colorMaskFlags = colorMaskFlags; params.colorMaskFlags = colorMaskFlags;
if (mEmulatedAlphaAttachmentMask[colorIndex]) if (mEmulatedAlphaAttachmentMask[colorIndex])
{ {
params.colorMaskFlags &= ~VK_COLOR_COMPONENT_A_BIT; params.colorMaskFlags &= ~VK_COLOR_COMPONENT_A_BIT;
} }
ANGLE_TRY(renderer->getUtils().clearImage(contextVk, this, params)); ANGLE_TRY(renderer->getUtils().clearFramebuffer(contextVk, this, params));
// Clear depth/stencil only once!
params.clearDepth = false;
params.clearStencil = false;
}
// If there was no color clear, clear depth/stencil alone.
if (params.clearDepth || params.clearStencil)
{
params.clearColor = false;
ANGLE_TRY(renderer->getUtils().clearFramebuffer(contextVk, this, params));
} }
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -179,8 +179,12 @@ class FramebufferVk : public FramebufferImpl ...@@ -179,8 +179,12 @@ class FramebufferVk : public FramebufferImpl
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
angle::Result clearWithDraw(ContextVk *contextVk, angle::Result clearWithDraw(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
VkColorComponentFlags colorMaskFlags,
uint8_t stencilMask,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
VkColorComponentFlags colorMaskFlags); const VkClearDepthStencilValue &clearDepthStencilValue);
void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a); void updateActiveColorMasks(size_t colorIndex, bool r, bool g, bool b, bool a);
void updateRenderPassDesc(); void updateRenderPassDesc();
......
...@@ -979,6 +979,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -979,6 +979,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend; enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend;
enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess; enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess;
enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy; enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy;
enabledFeatures.features.depthClamp = mPhysicalDeviceFeatures.depthClamp;
if (!vk::CommandBuffer::ExecutesInline()) if (!vk::CommandBuffer::ExecutesInline())
{ {
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries; enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
......
...@@ -200,6 +200,7 @@ void UtilsVk::destroy(VkDevice device) ...@@ -200,6 +200,7 @@ void UtilsVk::destroy(VkDevice device)
{ {
program.destroy(device); program.destroy(device);
} }
mImageClearProgramVSOnly.destroy(device);
for (vk::ShaderProgramHelper &program : mImageClearProgram) for (vk::ShaderProgramHelper &program : mImageClearProgram)
{ {
program.destroy(device); program.destroy(device);
...@@ -365,7 +366,10 @@ angle::Result UtilsVk::setupProgram(vk::Context *context, ...@@ -365,7 +366,10 @@ angle::Result UtilsVk::setupProgram(vk::Context *context,
else else
{ {
program->setShader(gl::ShaderType::Vertex, vsShader); program->setShader(gl::ShaderType::Vertex, vsShader);
program->setShader(gl::ShaderType::Fragment, fsCsShader); if (fsCsShader)
{
program->setShader(gl::ShaderType::Fragment, fsCsShader);
}
// This value is not used but is passed to getGraphicsPipeline to avoid a nullptr check. // This value is not used but is passed to getGraphicsPipeline to avoid a nullptr check.
const vk::GraphicsPipelineDesc *descPtr; const vk::GraphicsPipelineDesc *descPtr;
...@@ -637,9 +641,9 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk, ...@@ -637,9 +641,9 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result UtilsVk::clearImage(ContextVk *contextVk, angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
FramebufferVk *framebuffer, FramebufferVk *framebuffer,
const ClearImageParameters &params) const ClearFramebufferParameters &params)
{ {
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
...@@ -652,24 +656,54 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk, ...@@ -652,24 +656,54 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk,
} }
ImageClearShaderParams shaderParams; ImageClearShaderParams shaderParams;
shaderParams.clearValue = params.clearValue; shaderParams.clearValue = params.colorClearValue;
uint32_t flags = GetImageClearFlags(*params.format, params.attachmentIndex);
vk::GraphicsPipelineDesc pipelineDesc; vk::GraphicsPipelineDesc pipelineDesc;
pipelineDesc.initDefaults(); pipelineDesc.initDefaults();
pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask()); pipelineDesc.setColorWriteMask(0, gl::DrawBufferMask());
pipelineDesc.setSingleColorWriteMask(params.attachmentIndex, params.colorMaskFlags); pipelineDesc.setSingleColorWriteMask(params.colorAttachmentIndex, params.colorMaskFlags);
pipelineDesc.setRenderPassDesc(*params.renderPassDesc); pipelineDesc.setRenderPassDesc(*params.renderPassDesc);
// Note: depth test is disabled by default so this should be unnecessary, but works around an // Note: depth test is disabled by default so this should be unnecessary, but works around an
// Intel bug on windows. http://anglebug.com/3348 // Intel bug on windows. http://anglebug.com/3348
pipelineDesc.setDepthWriteEnabled(false); pipelineDesc.setDepthWriteEnabled(false);
// Clear depth by enabling depth clamping and setting the viewport depth range to the clear
// value.
if (params.clearDepth)
{
pipelineDesc.setDepthTestEnabled(true);
pipelineDesc.setDepthWriteEnabled(true);
pipelineDesc.setDepthFunc(VK_COMPARE_OP_ALWAYS);
pipelineDesc.setDepthClampEnabled(true);
}
// Clear stencil by enabling stencil write with the right mask.
if (params.clearStencil)
{
const uint8_t compareMask = 0xFF;
const uint8_t clearStencilValue =
static_cast<uint8_t>(params.depthStencilClearValue.stencil);
pipelineDesc.setStencilTestEnabled(true);
pipelineDesc.setStencilFrontFuncs(clearStencilValue, VK_COMPARE_OP_ALWAYS, compareMask);
pipelineDesc.setStencilBackFuncs(clearStencilValue, VK_COMPARE_OP_ALWAYS, compareMask);
pipelineDesc.setStencilFrontOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE,
VK_STENCIL_OP_REPLACE);
pipelineDesc.setStencilBackOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE,
VK_STENCIL_OP_REPLACE);
pipelineDesc.setStencilFrontWriteMask(params.stencilMask);
pipelineDesc.setStencilBackWriteMask(params.stencilMask);
}
const gl::Rectangle &renderArea = framebuffer->getFramebuffer()->getRenderPassRenderArea(); const gl::Rectangle &renderArea = framebuffer->getFramebuffer()->getRenderPassRenderArea();
bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO(); bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
VkViewport viewport; VkViewport viewport;
gl_vk::GetViewport(renderArea, 0.0f, 1.0f, invertViewport, params.renderAreaHeight, &viewport); // Set depth range to clear value. If clearing depth, the vertex shader depth output is clamped
// to this value, thus clearing the depth buffer to the desired clear value.
const float clearDepthValue = params.depthStencilClearValue.depth;
gl_vk::GetViewport(renderArea, clearDepthValue, clearDepthValue, invertViewport,
params.renderAreaHeight, &viewport);
pipelineDesc.setViewport(viewport); pipelineDesc.setViewport(viewport);
VkRect2D scissor; VkRect2D scissor;
...@@ -680,11 +714,18 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk, ...@@ -680,11 +714,18 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk,
vk::ShaderLibrary &shaderLibrary = renderer->getShaderLibrary(); vk::ShaderLibrary &shaderLibrary = renderer->getShaderLibrary();
vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr; vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr;
vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = nullptr; vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = nullptr;
vk::ShaderProgramHelper *imageClearProgram = &mImageClearProgramVSOnly;
ANGLE_TRY(shaderLibrary.getFullScreenQuad_vert(contextVk, 0, &vertexShader)); ANGLE_TRY(shaderLibrary.getFullScreenQuad_vert(contextVk, 0, &vertexShader));
ANGLE_TRY(shaderLibrary.getImageClear_frag(contextVk, flags, &fragmentShader)); if (params.clearColor)
{
uint32_t flags = GetImageClearFlags(*params.colorFormat, params.colorAttachmentIndex);
ANGLE_TRY(shaderLibrary.getImageClear_frag(contextVk, flags, &fragmentShader));
imageClearProgram = &mImageClearProgram[flags];
}
ANGLE_TRY(setupProgram(contextVk, Function::ImageClear, fragmentShader, vertexShader, ANGLE_TRY(setupProgram(contextVk, Function::ImageClear, fragmentShader, vertexShader,
&mImageClearProgram[flags], &pipelineDesc, VK_NULL_HANDLE, &shaderParams, imageClearProgram, &pipelineDesc, VK_NULL_HANDLE, &shaderParams,
sizeof(shaderParams), commandBuffer)); sizeof(shaderParams), commandBuffer));
commandBuffer->draw(6, 0); commandBuffer->draw(6, 0);
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -59,14 +59,22 @@ class UtilsVk : angle::NonCopyable ...@@ -59,14 +59,22 @@ class UtilsVk : angle::NonCopyable
size_t destOffset; size_t destOffset;
}; };
struct ClearImageParameters struct ClearFramebufferParameters
{ {
VkClearColorValue clearValue;
VkColorComponentFlags colorMaskFlags;
GLint renderAreaHeight;
const vk::RenderPassDesc *renderPassDesc; const vk::RenderPassDesc *renderPassDesc;
const angle::Format *format; GLint renderAreaHeight;
uint32_t attachmentIndex;
bool clearColor;
bool clearDepth;
bool clearStencil;
uint8_t stencilMask;
VkColorComponentFlags colorMaskFlags;
uint32_t colorAttachmentIndex;
const angle::Format *colorFormat;
VkClearColorValue colorClearValue;
VkClearDepthStencilValue depthStencilClearValue;
}; };
struct CopyImageParameters struct CopyImageParameters
...@@ -95,12 +103,9 @@ class UtilsVk : angle::NonCopyable ...@@ -95,12 +103,9 @@ class UtilsVk : angle::NonCopyable
vk::BufferHelper *src, vk::BufferHelper *src,
const ConvertVertexParameters &params); const ConvertVertexParameters &params);
// Note: this function takes a FramebufferVk instead of ImageHelper, as that's the only user, angle::Result clearFramebuffer(ContextVk *contextVk,
// which avoids recreating a framebuffer. An overload taking ImageHelper can be added when FramebufferVk *framebuffer,
// necessary. const ClearFramebufferParameters &params);
angle::Result clearImage(ContextVk *contextVk,
FramebufferVk *framebuffer,
const ClearImageParameters &params);
angle::Result copyImage(ContextVk *contextVk, angle::Result copyImage(ContextVk *contextVk,
vk::ImageHelper *dest, vk::ImageHelper *dest,
...@@ -232,6 +237,7 @@ class UtilsVk : angle::NonCopyable ...@@ -232,6 +237,7 @@ class UtilsVk : angle::NonCopyable
vk::ShaderProgramHelper vk::ShaderProgramHelper
mConvertVertexPrograms[vk::InternalShader::ConvertVertex_comp::kFlagsMask | mConvertVertexPrograms[vk::InternalShader::ConvertVertex_comp::kFlagsMask |
vk::InternalShader::ConvertVertex_comp::kConversionMask]; vk::InternalShader::ConvertVertex_comp::kConversionMask];
vk::ShaderProgramHelper mImageClearProgramVSOnly;
vk::ShaderProgramHelper vk::ShaderProgramHelper
mImageClearProgram[vk::InternalShader::ImageClear_frag::kAttachmentIndexMask | mImageClearProgram[vk::InternalShader::ImageClear_frag::kAttachmentIndexMask |
vk::InternalShader::ImageClear_frag::kFormatMask]; vk::InternalShader::ImageClear_frag::kFormatMask];
......
...@@ -85,7 +85,7 @@ uint8_t PackGLBlendFactor(GLenum blendFactor) ...@@ -85,7 +85,7 @@ uint8_t PackGLBlendFactor(GLenum blendFactor)
} }
} }
uint8_t PackGLStencilOp(GLenum compareOp) VkStencilOp PackGLStencilOp(GLenum compareOp)
{ {
switch (compareOp) switch (compareOp)
{ {
...@@ -107,11 +107,11 @@ uint8_t PackGLStencilOp(GLenum compareOp) ...@@ -107,11 +107,11 @@ uint8_t PackGLStencilOp(GLenum compareOp)
return VK_STENCIL_OP_INVERT; return VK_STENCIL_OP_INVERT;
default: default:
UNREACHABLE(); UNREACHABLE();
return 0; return VK_STENCIL_OP_KEEP;
} }
} }
uint8_t PackGLCompareFunc(GLenum compareFunc) VkCompareOp PackGLCompareFunc(GLenum compareFunc)
{ {
switch (compareFunc) switch (compareFunc)
{ {
...@@ -133,7 +133,7 @@ uint8_t PackGLCompareFunc(GLenum compareFunc) ...@@ -133,7 +133,7 @@ uint8_t PackGLCompareFunc(GLenum compareFunc)
return VK_COMPARE_OP_NOT_EQUAL; return VK_COMPARE_OP_NOT_EQUAL;
default: default:
UNREACHABLE(); UNREACHABLE();
return 0; return VK_COMPARE_OP_NEVER;
} }
} }
...@@ -879,26 +879,91 @@ void GraphicsPipelineDesc::updateColorWriteMask(GraphicsPipelineTransitionBits * ...@@ -879,26 +879,91 @@ void GraphicsPipelineDesc::updateColorWriteMask(GraphicsPipelineTransitionBits *
} }
} }
void GraphicsPipelineDesc::setDepthTestEnabled(bool enabled)
{
mDepthStencilStateInfo.enable.depthTest = enabled;
}
void GraphicsPipelineDesc::setDepthWriteEnabled(bool enabled) void GraphicsPipelineDesc::setDepthWriteEnabled(bool enabled)
{ {
mDepthStencilStateInfo.enable.depthWrite = enabled; mDepthStencilStateInfo.enable.depthWrite = enabled;
} }
void GraphicsPipelineDesc::setDepthFunc(VkCompareOp op)
{
SetBitField(mDepthStencilStateInfo.depthCompareOp, op);
}
void GraphicsPipelineDesc::setDepthClampEnabled(bool enabled)
{
mRasterizationAndMultisampleStateInfo.bits.depthClampEnable = enabled;
}
void GraphicsPipelineDesc::setStencilTestEnabled(bool enabled)
{
mDepthStencilStateInfo.enable.stencilTest = enabled;
}
void GraphicsPipelineDesc::setStencilFrontFuncs(uint8_t reference,
VkCompareOp compareOp,
uint8_t compareMask)
{
mDepthStencilStateInfo.frontStencilReference = reference;
mDepthStencilStateInfo.front.compareMask = compareMask;
SetBitField(mDepthStencilStateInfo.front.ops.compare, compareOp);
}
void GraphicsPipelineDesc::setStencilBackFuncs(uint8_t reference,
VkCompareOp compareOp,
uint8_t compareMask)
{
mDepthStencilStateInfo.backStencilReference = reference;
mDepthStencilStateInfo.back.compareMask = compareMask;
SetBitField(mDepthStencilStateInfo.back.ops.compare, compareOp);
}
void GraphicsPipelineDesc::setStencilFrontOps(VkStencilOp failOp,
VkStencilOp passOp,
VkStencilOp depthFailOp)
{
SetBitField(mDepthStencilStateInfo.front.ops.fail, failOp);
SetBitField(mDepthStencilStateInfo.front.ops.pass, passOp);
SetBitField(mDepthStencilStateInfo.front.ops.depthFail, depthFailOp);
}
void GraphicsPipelineDesc::setStencilBackOps(VkStencilOp failOp,
VkStencilOp passOp,
VkStencilOp depthFailOp)
{
SetBitField(mDepthStencilStateInfo.back.ops.fail, failOp);
SetBitField(mDepthStencilStateInfo.back.ops.pass, passOp);
SetBitField(mDepthStencilStateInfo.back.ops.depthFail, depthFailOp);
}
void GraphicsPipelineDesc::setStencilFrontWriteMask(uint8_t mask)
{
mDepthStencilStateInfo.front.writeMask = mask;
}
void GraphicsPipelineDesc::setStencilBackWriteMask(uint8_t mask)
{
mDepthStencilStateInfo.back.writeMask = mask;
}
void GraphicsPipelineDesc::updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition, void GraphicsPipelineDesc::updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState, const gl::DepthStencilState &depthStencilState,
const gl::Framebuffer *drawFramebuffer) const gl::Framebuffer *drawFramebuffer)
{ {
// Only enable the depth test if the draw framebuffer has a depth buffer. It's possible that // Only enable the depth test if the draw framebuffer has a depth buffer. It's possible that
// we're emulating a stencil-only buffer with a depth-stencil buffer // we're emulating a stencil-only buffer with a depth-stencil buffer
mDepthStencilStateInfo.enable.depthTest = setDepthTestEnabled(depthStencilState.depthTest && drawFramebuffer->hasDepth());
static_cast<uint8_t>(depthStencilState.depthTest && drawFramebuffer->hasDepth());
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, enable)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, enable));
} }
void GraphicsPipelineDesc::updateDepthFunc(GraphicsPipelineTransitionBits *transition, void GraphicsPipelineDesc::updateDepthFunc(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState) const gl::DepthStencilState &depthStencilState)
{ {
mDepthStencilStateInfo.depthCompareOp = PackGLCompareFunc(depthStencilState.depthFunc); setDepthFunc(PackGLCompareFunc(depthStencilState.depthFunc));
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, depthCompareOp)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, depthCompareOp));
} }
...@@ -907,8 +972,7 @@ void GraphicsPipelineDesc::updateDepthWriteEnabled(GraphicsPipelineTransitionBit ...@@ -907,8 +972,7 @@ void GraphicsPipelineDesc::updateDepthWriteEnabled(GraphicsPipelineTransitionBit
const gl::Framebuffer *drawFramebuffer) const gl::Framebuffer *drawFramebuffer)
{ {
// Don't write to depth buffers that should not exist // Don't write to depth buffers that should not exist
mDepthStencilStateInfo.enable.depthWrite = setDepthWriteEnabled(drawFramebuffer->hasDepth() ? depthStencilState.depthMask : false);
static_cast<uint8_t>(drawFramebuffer->hasDepth() ? depthStencilState.depthMask : 0);
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, enable)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, enable));
} }
...@@ -918,8 +982,7 @@ void GraphicsPipelineDesc::updateStencilTestEnabled(GraphicsPipelineTransitionBi ...@@ -918,8 +982,7 @@ void GraphicsPipelineDesc::updateStencilTestEnabled(GraphicsPipelineTransitionBi
{ {
// Only enable the stencil test if the draw framebuffer has a stencil buffer. It's possible // Only enable the stencil test if the draw framebuffer has a stencil buffer. It's possible
// that we're emulating a depth-only buffer with a depth-stencil buffer // that we're emulating a depth-only buffer with a depth-stencil buffer
mDepthStencilStateInfo.enable.stencilTest = setStencilTestEnabled(depthStencilState.stencilTest && drawFramebuffer->hasStencil());
static_cast<uint8_t>(depthStencilState.stencilTest && drawFramebuffer->hasStencil());
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, enable)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, enable));
} }
...@@ -927,9 +990,9 @@ void GraphicsPipelineDesc::updateStencilFrontFuncs(GraphicsPipelineTransitionBit ...@@ -927,9 +990,9 @@ void GraphicsPipelineDesc::updateStencilFrontFuncs(GraphicsPipelineTransitionBit
GLint ref, GLint ref,
const gl::DepthStencilState &depthStencilState) const gl::DepthStencilState &depthStencilState)
{ {
mDepthStencilStateInfo.frontStencilReference = static_cast<uint8_t>(ref); setStencilFrontFuncs(static_cast<uint8_t>(ref),
mDepthStencilStateInfo.front.ops.compare = PackGLCompareFunc(depthStencilState.stencilFunc); PackGLCompareFunc(depthStencilState.stencilFunc),
mDepthStencilStateInfo.front.compareMask = static_cast<uint8_t>(depthStencilState.stencilMask); static_cast<uint8_t>(depthStencilState.stencilMask));
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, front)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, front));
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, frontStencilReference)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, frontStencilReference));
} }
...@@ -938,10 +1001,9 @@ void GraphicsPipelineDesc::updateStencilBackFuncs(GraphicsPipelineTransitionBits ...@@ -938,10 +1001,9 @@ void GraphicsPipelineDesc::updateStencilBackFuncs(GraphicsPipelineTransitionBits
GLint ref, GLint ref,
const gl::DepthStencilState &depthStencilState) const gl::DepthStencilState &depthStencilState)
{ {
mDepthStencilStateInfo.backStencilReference = static_cast<uint8_t>(ref); setStencilBackFuncs(static_cast<uint8_t>(ref),
mDepthStencilStateInfo.back.ops.compare = PackGLCompareFunc(depthStencilState.stencilBackFunc); PackGLCompareFunc(depthStencilState.stencilBackFunc),
mDepthStencilStateInfo.back.compareMask = static_cast<uint8_t>(depthStencilState.stencilBackMask));
static_cast<uint8_t>(depthStencilState.stencilBackMask);
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, back)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, back));
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, backStencilReference)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, backStencilReference));
} }
...@@ -949,21 +1011,18 @@ void GraphicsPipelineDesc::updateStencilBackFuncs(GraphicsPipelineTransitionBits ...@@ -949,21 +1011,18 @@ void GraphicsPipelineDesc::updateStencilBackFuncs(GraphicsPipelineTransitionBits
void GraphicsPipelineDesc::updateStencilFrontOps(GraphicsPipelineTransitionBits *transition, void GraphicsPipelineDesc::updateStencilFrontOps(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState) const gl::DepthStencilState &depthStencilState)
{ {
mDepthStencilStateInfo.front.ops.pass = PackGLStencilOp(depthStencilState.stencilPassDepthPass); setStencilFrontOps(PackGLStencilOp(depthStencilState.stencilFail),
mDepthStencilStateInfo.front.ops.fail = PackGLStencilOp(depthStencilState.stencilFail); PackGLStencilOp(depthStencilState.stencilPassDepthPass),
mDepthStencilStateInfo.front.ops.depthFail = PackGLStencilOp(depthStencilState.stencilPassDepthFail));
PackGLStencilOp(depthStencilState.stencilPassDepthFail);
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, front)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, front));
} }
void GraphicsPipelineDesc::updateStencilBackOps(GraphicsPipelineTransitionBits *transition, void GraphicsPipelineDesc::updateStencilBackOps(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState) const gl::DepthStencilState &depthStencilState)
{ {
mDepthStencilStateInfo.back.ops.pass = setStencilBackOps(PackGLStencilOp(depthStencilState.stencilBackFail),
PackGLStencilOp(depthStencilState.stencilBackPassDepthPass); PackGLStencilOp(depthStencilState.stencilBackPassDepthPass),
mDepthStencilStateInfo.back.ops.fail = PackGLStencilOp(depthStencilState.stencilBackFail); PackGLStencilOp(depthStencilState.stencilBackPassDepthFail));
mDepthStencilStateInfo.back.ops.depthFail =
PackGLStencilOp(depthStencilState.stencilBackPassDepthFail);
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, back)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, back));
} }
...@@ -973,8 +1032,8 @@ void GraphicsPipelineDesc::updateStencilFrontWriteMask( ...@@ -973,8 +1032,8 @@ void GraphicsPipelineDesc::updateStencilFrontWriteMask(
const gl::Framebuffer *drawFramebuffer) const gl::Framebuffer *drawFramebuffer)
{ {
// Don't write to stencil buffers that should not exist // Don't write to stencil buffers that should not exist
mDepthStencilStateInfo.front.writeMask = static_cast<uint8_t>( setStencilFrontWriteMask(static_cast<uint8_t>(
drawFramebuffer->hasStencil() ? depthStencilState.stencilWritemask : 0); drawFramebuffer->hasStencil() ? depthStencilState.stencilWritemask : 0));
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, front)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, front));
} }
...@@ -984,8 +1043,8 @@ void GraphicsPipelineDesc::updateStencilBackWriteMask( ...@@ -984,8 +1043,8 @@ void GraphicsPipelineDesc::updateStencilBackWriteMask(
const gl::Framebuffer *drawFramebuffer) const gl::Framebuffer *drawFramebuffer)
{ {
// Don't write to stencil buffers that should not exist // Don't write to stencil buffers that should not exist
mDepthStencilStateInfo.back.writeMask = static_cast<uint8_t>( setStencilBackWriteMask(static_cast<uint8_t>(
drawFramebuffer->hasStencil() ? depthStencilState.stencilBackWritemask : 0); drawFramebuffer->hasStencil() ? depthStencilState.stencilBackWritemask : 0));
transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, back)); transition->set(ANGLE_GET_TRANSITION_BIT(mDepthStencilStateInfo, back));
} }
......
...@@ -373,7 +373,17 @@ class GraphicsPipelineDesc final ...@@ -373,7 +373,17 @@ class GraphicsPipelineDesc final
const gl::DrawBufferMask &alphaMask); const gl::DrawBufferMask &alphaMask);
// Depth/stencil states. // Depth/stencil states.
void setDepthTestEnabled(bool enabled);
void setDepthWriteEnabled(bool enabled); void setDepthWriteEnabled(bool enabled);
void setDepthFunc(VkCompareOp op);
void setDepthClampEnabled(bool enabled);
void setStencilTestEnabled(bool enabled);
void setStencilFrontFuncs(uint8_t reference, VkCompareOp compareOp, uint8_t compareMask);
void setStencilBackFuncs(uint8_t reference, VkCompareOp compareOp, uint8_t compareMask);
void setStencilFrontOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
void setStencilBackOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
void setStencilFrontWriteMask(uint8_t mask);
void setStencilBackWriteMask(uint8_t mask);
void updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition, void updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState, const gl::DepthStencilState &depthStencilState,
const gl::Framebuffer *drawFramebuffer); const gl::Framebuffer *drawFramebuffer);
......
...@@ -266,12 +266,6 @@ ...@@ -266,12 +266,6 @@
// General Vulkan failures // General Vulkan failures
3300 VULKAN : dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod = FAIL 3300 VULKAN : dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod = FAIL
// Depth/stencil clear
3241 VULKAN : dEQP-GLES2.functional.depth_stencil_clear.stencil_masked = FAIL
3241 VULKAN : dEQP-GLES2.functional.depth_stencil_clear.stencil_scissored_masked = FAIL
3241 VULKAN : dEQP-GLES2.functional.depth_stencil_clear.depth_stencil_masked = FAIL
3241 VULKAN : dEQP-GLES2.functional.depth_stencil_clear.depth_stencil_scissored_masked = FAIL
// Only seen failing on Android // Only seen failing on Android
3241 VULKAN ANDROID : dEQP-GLES2.functional.depth_stencil_clear.depth_scissored_masked = FAIL 3241 VULKAN ANDROID : dEQP-GLES2.functional.depth_stencil_clear.depth_scissored_masked = FAIL
...@@ -378,4 +372,4 @@ ...@@ -378,4 +372,4 @@
2976 VULKAN NVIDIA : dEQP-GLES2.functional.shaders.invariance.* = FAIL 2976 VULKAN NVIDIA : dEQP-GLES2.functional.shaders.invariance.* = FAIL
// Tests were being hidden by flakiness (anglebug.com/3271) // Tests were being hidden by flakiness (anglebug.com/3271)
3328 VULKAN WIN NVIDIA : dEQP-GLES2.functional.shaders.swizzles.vector_swizzles.mediump_vec4_qqqt_vertex = SKIP 3328 VULKAN WIN NVIDIA : dEQP-GLES2.functional.shaders.swizzles.vector_swizzles.mediump_vec4_qqqt_vertex = SKIP
\ No newline at end of file
...@@ -84,6 +84,7 @@ class ClearTest : public ClearTestBase ...@@ -84,6 +84,7 @@ class ClearTest : public ClearTestBase
protected: protected:
void MaskedScissoredColorDepthStencilClear(bool mask, void MaskedScissoredColorDepthStencilClear(bool mask,
bool scissor, bool scissor,
bool clearColor,
bool clearDepth, bool clearDepth,
bool clearStencil); bool clearStencil);
...@@ -1131,6 +1132,7 @@ TEST_P(ClearTestES3, RepeatedClear) ...@@ -1131,6 +1132,7 @@ TEST_P(ClearTestES3, RepeatedClear)
void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
bool scissor, bool scissor,
bool clearColor,
bool clearDepth, bool clearDepth,
bool clearStencil) bool clearStencil)
{ {
...@@ -1143,14 +1145,31 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -1143,14 +1145,31 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
const int whalf = w >> 1; const int whalf = w >> 1;
const int hhalf = h >> 1; const int hhalf = h >> 1;
constexpr float kPreClearDepth = 0.9f;
constexpr float kClearDepth = 0.5f;
constexpr uint8_t kPreClearStencil = 0xFF;
constexpr uint8_t kClearStencil = 0x16;
constexpr uint8_t kStencilMask = 0x59;
constexpr uint8_t kMaskedClearStencil =
(kPreClearStencil & ~kStencilMask) | (kClearStencil & kStencilMask);
// Clear to a random color, 0.9 depth and 0x00 stencil // Clear to a random color, 0.9 depth and 0x00 stencil
Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f); Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f);
GLColor color1RGB(color1); GLColor color1RGB(color1);
glClearColor(color1[0], color1[1], color1[2], color1[3]); glClearColor(color1[0], color1[1], color1[2], color1[3]);
glClearDepthf(0.9f); glClearDepthf(kPreClearDepth);
glClearStencil(0x00); glClearStencil(kPreClearStencil);
glClear(GL_COLOR_BUFFER_BIT | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) |
if (!clearColor)
{
// If not asked to clear color, clear it anyway, but individually. The clear value is
// still used to verify that the depth/stencil clear happened correctly. This allows
// testing for depth/stencil-only clear implementations.
glClear(GL_COLOR_BUFFER_BIT);
}
glClear((clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) |
(clearStencil ? GL_STENCIL_BUFFER_BIT : 0)); (clearStencil ? GL_STENCIL_BUFFER_BIT : 0));
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -1167,15 +1186,15 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -1167,15 +1186,15 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
Vector4 color2(0.2f, 0.4f, 0.6f, 0.8f); Vector4 color2(0.2f, 0.4f, 0.6f, 0.8f);
GLColor color2RGB(color2); GLColor color2RGB(color2);
glClearColor(color2[0], color2[1], color2[2], color2[3]); glClearColor(color2[0], color2[1], color2[2], color2[3]);
glClearDepthf(0.5f); glClearDepthf(kClearDepth);
glClearStencil(0xFF); glClearStencil(kClearStencil);
if (mask) if (mask)
{ {
glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE); glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
glStencilMask(0x59); glStencilMask(kStencilMask);
} }
glClear(GL_COLOR_BUFFER_BIT | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) | glClear((clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) |
(clearStencil ? GL_STENCIL_BUFFER_BIT : 0)); (clearStencil ? GL_STENCIL_BUFFER_BIT : 0));
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
...@@ -1188,7 +1207,10 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -1188,7 +1207,10 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
// Verify second clear mask worked as expected. // Verify second clear mask worked as expected.
GLColor color2MaskedRGB(color2RGB[0], color1RGB[1], color2RGB[2], color1RGB[3]); GLColor color2MaskedRGB(color2RGB[0], color1RGB[1], color2RGB[2], color1RGB[3]);
GLColor expectedCenterColorRGB = mask ? color2MaskedRGB : color2RGB; // If not clearing color, the original color should be left both in the center and corners. If
// using a scissor, the corners should be left to the original color, while the center is
// possibly changed. If using a mask, the center (and corers if not scissored), h
GLColor expectedCenterColorRGB = !clearColor ? color1RGB : mask ? color2MaskedRGB : color2RGB;
GLColor expectedCornerColorRGB = scissor ? color1RGB : expectedCenterColorRGB; GLColor expectedCornerColorRGB = scissor ? color1RGB : expectedCenterColorRGB;
EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1); EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, expectedCenterColorRGB, 1);
...@@ -1207,8 +1229,8 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -1207,8 +1229,8 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
essl1_shaders::fs::Blue()); essl1_shaders::fs::Blue());
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(mask ? GL_GREATER : GL_EQUAL); glDepthFunc(mask ? GL_GREATER : GL_EQUAL);
// - If depth is cleared, but it's masked, 0.9 should be in the depth buffer. // - If depth is cleared, but it's masked, kPreClearDepth should be in the depth buffer.
// - If depth is cleared, but it's not masked, 0.5 should be in the depth buffer. // - If depth is cleared, but it's not masked, kClearDepth should be in the depth buffer.
// - If depth is not cleared, the if above ensures there is no depth buffer at all, // - If depth is not cleared, the if above ensures there is no depth buffer at all,
// which means depth test will always pass. // which means depth test will always pass.
drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), mask ? 1.0f : 0.0f); drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), mask ? 1.0f : 0.0f);
...@@ -1237,11 +1259,13 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -1237,11 +1259,13 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(), ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Green()); essl1_shaders::fs::Green());
glEnable(GL_STENCIL_TEST); glEnable(GL_STENCIL_TEST);
// - If stencil is cleared, but it's masked, 0x59 should be in the stencil buffer. // - If stencil is cleared, but it's masked, kMaskedClearStencil should be in the stencil
// - If stencil is cleared, but it's not masked, 0xFF should be in the stencil buffer. // buffer.
// - If stencil is cleared, but it's not masked, kClearStencil should be in the stencil
// buffer.
// - If stencil is not cleared, the if above ensures there is no stencil buffer at all, // - If stencil is not cleared, the if above ensures there is no stencil buffer at all,
// which means stencil test will always pass. // which means stencil test will always pass.
glStencilFunc(GL_EQUAL, mask ? 0x59 : 0xFF, 0xFF); glStencilFunc(GL_EQUAL, mask ? kMaskedClearStencil : kClearStencil, 0xFF);
drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f); drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f);
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -1263,61 +1287,106 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask, ...@@ -1263,61 +1287,106 @@ void ClearTest::MaskedScissoredColorDepthStencilClear(bool mask,
// Tests combined color+depth+stencil clears. // Tests combined color+depth+stencil clears.
TEST_P(ClearTest, MaskedColorAndDepthClear) TEST_P(ClearTest, MaskedColorAndDepthClear)
{ {
MaskedScissoredColorDepthStencilClear(true, false, true, false); MaskedScissoredColorDepthStencilClear(true, false, true, true, false);
} }
TEST_P(ClearTest, MaskedColorAndStencilClear) TEST_P(ClearTest, MaskedColorAndStencilClear)
{ {
MaskedScissoredColorDepthStencilClear(true, false, false, true); MaskedScissoredColorDepthStencilClear(true, false, true, false, true);
} }
TEST_P(ClearTest, MaskedColorAndDepthAndStencilClear) TEST_P(ClearTest, MaskedColorAndDepthAndStencilClear)
{ {
MaskedScissoredColorDepthStencilClear(true, false, true, true); MaskedScissoredColorDepthStencilClear(true, false, true, true, true);
}
TEST_P(ClearTest, MaskedDepthClear)
{
MaskedScissoredColorDepthStencilClear(true, false, false, true, false);
}
TEST_P(ClearTest, MaskedStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, false, false, false, true);
}
TEST_P(ClearTest, MaskedDepthAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, false, false, true, true);
} }
// Simple scissored clear. // Simple scissored clear.
TEST_P(ScissoredClearTest, BasicScissoredColorClear) TEST_P(ScissoredClearTest, BasicScissoredColorClear)
{ {
MaskedScissoredColorDepthStencilClear(false, true, false, false); MaskedScissoredColorDepthStencilClear(false, true, true, false, false);
} }
// Simple scissored masked clear. // Simple scissored masked clear.
TEST_P(ScissoredClearTest, MaskedScissoredColorClear) TEST_P(ScissoredClearTest, MaskedScissoredColorClear)
{ {
MaskedScissoredColorDepthStencilClear(true, true, false, false); MaskedScissoredColorDepthStencilClear(true, true, true, false, false);
} }
// Tests combined color+depth+stencil scissored clears. // Tests combined color+depth+stencil scissored clears.
TEST_P(ScissoredClearTest, ScissoredColorAndDepthClear) TEST_P(ScissoredClearTest, ScissoredColorAndDepthClear)
{ {
MaskedScissoredColorDepthStencilClear(false, true, true, false); MaskedScissoredColorDepthStencilClear(false, true, true, true, false);
} }
TEST_P(ScissoredClearTest, ScissoredColorAndStencilClear) TEST_P(ScissoredClearTest, ScissoredColorAndStencilClear)
{ {
MaskedScissoredColorDepthStencilClear(false, true, false, true); MaskedScissoredColorDepthStencilClear(false, true, true, false, true);
} }
TEST_P(ScissoredClearTest, ScissoredColorAndDepthAndStencilClear) TEST_P(ScissoredClearTest, ScissoredColorAndDepthAndStencilClear)
{ {
MaskedScissoredColorDepthStencilClear(false, true, true, true); MaskedScissoredColorDepthStencilClear(false, true, true, true, true);
}
TEST_P(ScissoredClearTest, ScissoredDepthClear)
{
MaskedScissoredColorDepthStencilClear(false, true, false, true, false);
}
TEST_P(ScissoredClearTest, ScissoredStencilClear)
{
MaskedScissoredColorDepthStencilClear(false, true, false, false, true);
}
TEST_P(ScissoredClearTest, ScissoredDepthAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(false, true, false, true, true);
} }
// Tests combined color+depth+stencil scissored masked clears. // Tests combined color+depth+stencil scissored masked clears.
TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthClear) TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthClear)
{ {
MaskedScissoredColorDepthStencilClear(true, true, true, false); MaskedScissoredColorDepthStencilClear(true, true, true, true, false);
} }
TEST_P(ScissoredClearTest, MaskedScissoredColorAndStencilClear) TEST_P(ScissoredClearTest, MaskedScissoredColorAndStencilClear)
{ {
MaskedScissoredColorDepthStencilClear(true, true, false, true); MaskedScissoredColorDepthStencilClear(true, true, true, false, true);
} }
TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear) TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear)
{ {
MaskedScissoredColorDepthStencilClear(true, true, true, true); MaskedScissoredColorDepthStencilClear(true, true, true, true, true);
}
TEST_P(ScissoredClearTest, MaskedScissoredgDepthClear)
{
MaskedScissoredColorDepthStencilClear(true, true, false, true, false);
}
TEST_P(ScissoredClearTest, MaskedScissoredgStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, true, false, false, true);
}
TEST_P(ScissoredClearTest, MaskedScissoredgDepthAndStencilClear)
{
MaskedScissoredColorDepthStencilClear(true, true, false, true, true);
} }
// Tests combined color+stencil scissored masked clears for a depth-stencil-emulated // Tests combined color+stencil scissored masked clears for a depth-stencil-emulated
...@@ -1325,25 +1394,49 @@ TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear) ...@@ -1325,25 +1394,49 @@ TEST_P(ScissoredClearTest, MaskedScissoredColorAndDepthAndStencilClear)
TEST_P(VulkanClearTest, ColorAndStencilClear) TEST_P(VulkanClearTest, ColorAndStencilClear)
{ {
bindColorStencilFBO(); bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(false, false, false, true); MaskedScissoredColorDepthStencilClear(false, false, true, false, true);
} }
TEST_P(VulkanClearTest, MaskedColorAndStencilClear) TEST_P(VulkanClearTest, MaskedColorAndStencilClear)
{ {
bindColorStencilFBO(); bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(true, false, false, true); MaskedScissoredColorDepthStencilClear(true, false, true, false, true);
} }
TEST_P(VulkanClearTest, ScissoredColorAndStencilClear) TEST_P(VulkanClearTest, ScissoredColorAndStencilClear)
{ {
bindColorStencilFBO(); bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(false, true, false, true); MaskedScissoredColorDepthStencilClear(false, true, true, false, true);
} }
TEST_P(VulkanClearTest, MaskedScissoredColorAndStencilClear) TEST_P(VulkanClearTest, MaskedScissoredColorAndStencilClear)
{ {
bindColorStencilFBO(); bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(true, true, false, true); MaskedScissoredColorDepthStencilClear(true, true, true, false, true);
}
TEST_P(VulkanClearTest, StencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(false, false, false, false, true);
}
TEST_P(VulkanClearTest, MaskedStencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(true, false, false, false, true);
}
TEST_P(VulkanClearTest, ScissoredStencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(false, true, false, false, true);
}
TEST_P(VulkanClearTest, MaskedScissoredStencilClear)
{
bindColorStencilFBO();
MaskedScissoredColorDepthStencilClear(true, true, false, false, true);
} }
// Tests combined color+depth scissored masked clears for a depth-stencil-emulated // Tests combined color+depth scissored masked clears for a depth-stencil-emulated
...@@ -1352,28 +1445,56 @@ TEST_P(VulkanClearTest, ColorAndDepthClear) ...@@ -1352,28 +1445,56 @@ TEST_P(VulkanClearTest, ColorAndDepthClear)
{ {
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO(); bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(false, false, true, false); MaskedScissoredColorDepthStencilClear(false, false, true, true, false);
} }
TEST_P(VulkanClearTest, MaskedColorAndDepthClear) TEST_P(VulkanClearTest, MaskedColorAndDepthClear)
{ {
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO(); bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(true, false, true, false); MaskedScissoredColorDepthStencilClear(true, false, true, true, false);
} }
TEST_P(VulkanClearTest, ScissoredColorAndDepthClear) TEST_P(VulkanClearTest, ScissoredColorAndDepthClear)
{ {
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO(); bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(false, true, true, false); MaskedScissoredColorDepthStencilClear(false, true, true, true, false);
} }
TEST_P(VulkanClearTest, MaskedScissoredColorAndDepthClear) TEST_P(VulkanClearTest, MaskedScissoredColorAndDepthClear)
{ {
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO(); bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(true, true, true, false); MaskedScissoredColorDepthStencilClear(true, true, true, true, false);
}
TEST_P(VulkanClearTest, DepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(false, false, false, true, false);
}
TEST_P(VulkanClearTest, MaskedDepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(true, false, false, true, false);
}
TEST_P(VulkanClearTest, ScissoredDepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(false, true, false, true, false);
}
TEST_P(VulkanClearTest, MaskedScissoredDepthClear)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
bindColorDepthFBO();
MaskedScissoredColorDepthStencilClear(true, true, false, true, false);
} }
// Test that just clearing a nonexistent drawbuffer of the default framebuffer doesn't cause an // Test that just clearing a nonexistent drawbuffer of the default framebuffer doesn't cause an
......
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