Commit 43163491 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Unresolve depth/stencil MSRTT attachments

Using the same shader that unresolves color, this change allows depth/stencil to be unresolved as well. In turn, this allows the depth and stencil loadOp/storeOp of the implicit multisampled image associated with a multisampled-render-to-texture renderbuffer to be set to DONT_CARE. Stencil unresolve depends on VK_EXT_shader_stencil_export. In the absence of this extension, the stencil aspect is not unresolved and must continue to use loadOp=LOAD and storeOp=STORE. This is not ideal, but the expected use-case of depth/stencil MSRTT renderbuffers is that they get invalidated, so that load and store wouldn't happen in practice. Bug: angleproject:4836 Change-Id: I9939d1e15e10fa8ed285acdd6fe6edb42c59054f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2427049Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 74ed9b65
......@@ -511,6 +511,9 @@ template <size_t N>
using BitSet8 = BitSetT<N, uint8_t>;
template <size_t N>
using BitSet16 = BitSetT<N, uint16_t>;
template <size_t N>
using BitSet32 = BitSetT<N, uint32_t>;
template <size_t N>
......
......@@ -2243,7 +2243,10 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Initialize RenderPass info.
vk::AttachmentOpsArray renderPassAttachmentOps;
vk::PackedClearValuesArray packedClearValues;
gl::DrawBufferMask previousUnresolveMask = mRenderPassDesc.getColorUnresolveAttachmentMask();
gl::DrawBufferMask previousUnresolveColorMask =
mRenderPassDesc.getColorUnresolveAttachmentMask();
bool previousUnresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
bool previousUnresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
// Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors();
......@@ -2318,6 +2321,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
if (depthStencilRenderTarget)
{
const bool canExportStencil =
contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled;
// depth stencil attachment always immediately follows color attachment
depthStencilAttachmentIndex = colorIndexVk;
......@@ -2337,14 +2343,16 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
// If depth/stencil image is transient, no need to store its data at the end of the render
// pass. If shader stencil export is not supported, stencil data cannot be unresolved on
// the next render pass, so it must be stored/loaded. If the image is entirely transient,
// there is no resolve/unresolve and the image data is never stored/loaded.
if (depthStencilRenderTarget->isImageTransient())
{
// TODO(syoussefi): currently, depth/stencil unresolve is not implemented. Until then,
// don't change storeOp to DONT_CARE, unless the attachment is entirely transient (i.e.
// depth textures from EXT_multisampled_render_to_texture2. http://anglebug.com/4836
if (depthStencilRenderTarget->isEntirelyTransient())
depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
if (canExportStencil || depthStencilRenderTarget->isEntirelyTransient())
{
depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
}
......@@ -2391,6 +2399,40 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
// Similar to color attachments, if there's a resolve attachment and the multisampled image
// is transient, depth/stencil data need to be unresolved in an initial subpass.
//
// Note that stencil unresolve is currently only possible if shader stencil export is
// supported.
if (depthStencilRenderTarget->hasResolveAttachment() &&
depthStencilRenderTarget->isImageTransient())
{
const bool unresolveDepth = depthLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD;
const bool unresolveStencil =
stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD && canExportStencil;
if (unresolveDepth)
{
depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
if (unresolveStencil)
{
stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
if (unresolveDepth || unresolveStencil)
{
mRenderPassDesc.packDepthStencilUnresolveAttachment(unresolveDepth,
unresolveStencil);
}
else
{
mRenderPassDesc.removeDepthStencilUnresolveAttachment();
}
}
renderPassAttachmentOps.setOps(depthStencilAttachmentIndex, depthLoadOp, depthStoreOp);
renderPassAttachmentOps.setStencilOps(depthStencilAttachmentIndex, stencilLoadOp,
stencilStoreOp);
......@@ -2418,13 +2460,28 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Note that render passes are compatible only if the differences are in loadOp/storeOp values,
// or the existence of resolve attachments in single subpass render passes. The modification
// here can add/remove a subpass, or modify its input attachments.
gl::DrawBufferMask unresolveMask = mRenderPassDesc.getColorUnresolveAttachmentMask();
if (previousUnresolveMask != unresolveMask)
gl::DrawBufferMask unresolveColorMask = mRenderPassDesc.getColorUnresolveAttachmentMask();
bool unresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
bool unresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
if (previousUnresolveColorMask != unresolveColorMask ||
previousUnresolveDepth != unresolveDepth || previousUnresolveStencil != unresolveStencil)
{
contextVk->onDrawFramebufferRenderPassDescChange(this);
// Make sure framebuffer is recreated.
mFramebuffer = nullptr;
mCurrentFramebufferDesc.updateColorUnresolveMask(unresolveMask);
vk::FramebufferNonResolveAttachmentMask unresolveMask(unresolveColorMask.bits());
if (unresolveDepth)
{
unresolveMask.set(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
}
if (unresolveStencil)
{
unresolveMask.set(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1);
}
mCurrentFramebufferDesc.updateUnresolveMask(unresolveMask);
}
vk::Framebuffer *framebuffer = nullptr;
......@@ -2450,11 +2507,13 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
depthStencilRenderTarget->onDepthStencilDraw(contextVk, mReadOnlyDepthStencilMode);
}
if (unresolveMask.any())
if (unresolveColorMask.any() || unresolveDepth || unresolveStencil)
{
// Unresolve attachments if any.
UtilsVk::UnresolveParameters params;
params.unresolveMask = unresolveMask;
params.unresolveColorMask = unresolveColorMask;
params.unresolveDepth = unresolveDepth;
params.unresolveStencil = unresolveStencil;
ANGLE_TRY(contextVk->getUtils().unresolve(contextVk, this, params));
......
......@@ -125,8 +125,8 @@ void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, bool isReadOnly)
mImage);
if (mResolveImage)
{
contextVk->onImageRenderPassWrite(aspectFlags, vk::ImageLayout::DepthStencilAttachment,
mResolveImage);
contextVk->onImageRenderPassWrite(
aspectFlags, vk::ImageLayout::DepthStencilResolveAttachment, mResolveImage);
}
}
......
......@@ -272,7 +272,7 @@ uint32_t GetGenerateMipmapFlags(ContextVk *contextVk, const vk::Format &format)
return flags;
}
enum UnresolveAttachmentType
enum UnresolveColorAttachmentType
{
kUnresolveTypeUnused = 0,
kUnresolveTypeFloat = 1,
......@@ -280,17 +280,19 @@ enum UnresolveAttachmentType
kUnresolveTypeUint = 3,
};
uint32_t GetUnresolveFlags(uint32_t attachmentCount,
const gl::DrawBuffersArray<vk::ImageHelper *> &src,
gl::DrawBuffersArray<UnresolveAttachmentType> *attachmentTypesOut)
uint32_t GetUnresolveFlags(uint32_t colorAttachmentCount,
const gl::DrawBuffersArray<vk::ImageHelper *> &colorSrc,
bool unresolveDepth,
bool unresolveStencil,
gl::DrawBuffersArray<UnresolveColorAttachmentType> *attachmentTypesOut)
{
uint32_t flags = 0;
for (uint32_t attachmentIndex = 0; attachmentIndex < attachmentCount; ++attachmentIndex)
for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
{
const angle::Format &format = src[attachmentIndex]->getFormat().intendedFormat();
const angle::Format &format = colorSrc[attachmentIndex]->getFormat().intendedFormat();
UnresolveAttachmentType type = kUnresolveTypeFloat;
UnresolveColorAttachmentType type = kUnresolveTypeFloat;
if (format.isSint())
{
type = kUnresolveTypeSint;
......@@ -302,11 +304,24 @@ uint32_t GetUnresolveFlags(uint32_t attachmentCount,
(*attachmentTypesOut)[attachmentIndex] = type;
// |flags| is comprised of |attachmentCount| values from |UnresolveAttachmentType|, each
// taking up 2 bits.
// |flags| is comprised of |colorAttachmentCount| values from
// |UnresolveColorAttachmentType|, each taking up 2 bits.
flags |= type << (2 * attachmentIndex);
}
// Additionally, two bits are used for depth and stencil unresolve.
constexpr uint32_t kDepthUnresolveFlagBit = 2 * gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
constexpr uint32_t kStencilUnresolveFlagBit = kDepthUnresolveFlagBit + 1;
if (unresolveDepth)
{
flags |= 1 << kDepthUnresolveFlagBit;
}
if (unresolveStencil)
{
flags |= 1 << kStencilUnresolveFlagBit;
}
return flags;
}
......@@ -348,10 +363,29 @@ void CalculateResolveOffset(const UtilsVk::BlitResolveParameters &params, int32_
offset[1] = params.destOffset[1] - params.srcOffset[1] * srcOffsetFactorY;
}
// Sets the appropriate settings in the pipeline for the shader to output stencil. Requires the
// shader stencil export extension.
void SetStencilForShaderExport(ContextVk *contextVk, vk::GraphicsPipelineDesc *desc)
{
ASSERT(contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled);
const uint8_t completeMask = 0xFF;
const uint8_t unusedReference = 0x00;
desc->setStencilTestEnabled(true);
desc->setStencilFrontFuncs(unusedReference, VK_COMPARE_OP_ALWAYS, completeMask);
desc->setStencilBackFuncs(unusedReference, VK_COMPARE_OP_ALWAYS, completeMask);
desc->setStencilFrontOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE);
desc->setStencilBackOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE);
desc->setStencilFrontWriteMask(completeMask);
desc->setStencilBackWriteMask(completeMask);
}
// Creates a shader that looks like the following, based on the number and types of unresolve
// attachments.
//
// #version 450 core
// #extension GL_ARB_shader_stencil_export : require
//
// layout(location = 0) out vec4 colorOut0;
// layout(location = 1) out ivec4 colorOut1;
......@@ -359,26 +393,37 @@ void CalculateResolveOffset(const UtilsVk::BlitResolveParameters &params, int32_
// layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput colorIn0;
// layout(input_attachment_index = 1, set = 0, binding = 1) uniform isubpassInput colorIn1;
// layout(input_attachment_index = 2, set = 0, binding = 2) uniform usubpassInput colorIn2;
// layout(input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput depthIn;
// layout(input_attachment_index = 3, set = 0, binding = 4) uniform usubpassInput stencilIn;
//
// void main()
// {
// colorOut0 = subpassLoad(colorIn0);
// colorOut1 = subpassLoad(colorIn1);
// colorOut2 = subpassLoad(colorIn2);
// gl_FragDepth = subpassLoad(depthIn).x;
// gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);
// }
angle::Result MakeUnresolveFragShader(
vk::Context *context,
uint32_t attachmentCount,
gl::DrawBuffersArray<UnresolveAttachmentType> &attachmentTypes,
uint32_t colorAttachmentCount,
gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
bool unresolveDepth,
bool unresolveStencil,
SpirvBlob *spirvBlobOut)
{
std::ostringstream source;
source << "#version 450 core\n";
for (uint32_t attachmentIndex = 0; attachmentIndex < attachmentCount; ++attachmentIndex)
if (unresolveStencil)
{
source << "#extension GL_ARB_shader_stencil_export : require\n";
}
for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
{
const UnresolveAttachmentType type = attachmentTypes[attachmentIndex];
const UnresolveColorAttachmentType type = colorAttachmentTypes[attachmentIndex];
ASSERT(type != kUnresolveTypeUnused);
const char *prefix =
......@@ -387,28 +432,58 @@ angle::Result MakeUnresolveFragShader(
source << "layout(location=" << attachmentIndex << ") out " << prefix << "vec4 colorOut"
<< attachmentIndex << ";\n";
source << "layout(input_attachment_index=" << attachmentIndex
<< ", set=0, binding=" << attachmentIndex << ") uniform " << prefix
<< "subpassInput colorIn" << attachmentIndex << ";\n";
<< ", set=" << DescriptorSetIndex::InternalShader << ", binding=" << attachmentIndex
<< ") uniform " << prefix << "subpassInput colorIn" << attachmentIndex << ";\n";
}
const uint32_t depthStencilInputIndex = colorAttachmentCount;
uint32_t depthStencilBindingIndex = colorAttachmentCount;
if (unresolveDepth)
{
source << "layout(input_attachment_index=" << depthStencilInputIndex
<< ", set=" << DescriptorSetIndex::InternalShader
<< ", binding=" << depthStencilBindingIndex << ") uniform subpassInput depthIn;\n";
++depthStencilBindingIndex;
}
if (unresolveStencil)
{
source << "layout(input_attachment_index=" << depthStencilInputIndex
<< ", set=" << DescriptorSetIndex::InternalShader
<< ", binding=" << depthStencilBindingIndex
<< ") uniform usubpassInput stencilIn;\n";
}
source << "void main(){\n";
for (uint32_t attachmentIndex = 0; attachmentIndex < attachmentCount; ++attachmentIndex)
for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
{
source << "colorOut" << attachmentIndex << " = subpassLoad(colorIn" << attachmentIndex
<< ");\n";
}
if (unresolveDepth)
{
source << "gl_FragDepth = subpassLoad(depthIn).x;\n";
}
if (unresolveStencil)
{
source << "gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);\n";
}
source << "}\n";
return GlslangWrapperVk::CompileShaderOneOff(context, gl::ShaderType::Fragment, source.str(),
spirvBlobOut);
}
angle::Result GetUnresolveFrag(vk::Context *context,
uint32_t attachmentCount,
gl::DrawBuffersArray<UnresolveAttachmentType> &attachmentTypes,
vk::RefCounted<vk::ShaderAndSerial> *shader)
angle::Result GetUnresolveFrag(
vk::Context *context,
uint32_t colorAttachmentCount,
gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
bool unresolveDepth,
bool unresolveStencil,
vk::RefCounted<vk::ShaderAndSerial> *shader)
{
if (shader->get().valid())
{
......@@ -416,7 +491,8 @@ angle::Result GetUnresolveFrag(vk::Context *context,
}
SpirvBlob shaderCode;
ANGLE_TRY(MakeUnresolveFragShader(context, attachmentCount, attachmentTypes, &shaderCode));
ANGLE_TRY(MakeUnresolveFragShader(context, colorAttachmentCount, colorAttachmentTypes,
unresolveDepth, unresolveStencil, &shaderCode));
// Create shader lazily. Access will need to be locked for multi-threading.
return vk::InitShaderAndSerial(context, &shader->get(), shaderCode.data(),
......@@ -813,7 +889,7 @@ angle::Result UtilsVk::ensureUnresolveResourcesInitialized(ContextVk *contextVk,
return angle::Result::Continue;
}
gl::DrawBuffersArray<VkDescriptorPoolSize> setSizes;
vk::FramebufferAttachmentArray<VkDescriptorPoolSize> setSizes;
std::fill(setSizes.begin(), setSizes.end(),
VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1});
......@@ -1577,20 +1653,7 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk,
if (blitStencil)
{
ASSERT(contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled);
const uint8_t completeMask = 0xFF;
const uint8_t unusedReference = 0x00;
pipelineDesc.setStencilTestEnabled(true);
pipelineDesc.setStencilFrontFuncs(unusedReference, VK_COMPARE_OP_ALWAYS, completeMask);
pipelineDesc.setStencilBackFuncs(unusedReference, VK_COMPARE_OP_ALWAYS, completeMask);
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(completeMask);
pipelineDesc.setStencilBackWriteMask(completeMask);
SetStencilForShaderExport(contextVk, &pipelineDesc);
}
VkViewport viewport;
......@@ -2144,41 +2207,92 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk,
const UnresolveParameters &params)
{
// Get attachment count and pointers to resolve images and views.
gl::DrawBuffersArray<vk::ImageHelper *> src;
gl::DrawBuffersArray<const vk::ImageView *> srcView;
gl::DrawBuffersArray<vk::ImageHelper *> colorSrc = {};
gl::DrawBuffersArray<const vk::ImageView *> colorSrcView = {};
vk::DeviceScoped<vk::ImageView> depthView(contextVk->getDevice());
vk::DeviceScoped<vk::ImageView> stencilView(contextVk->getDevice());
ASSERT(params.unresolveMask.any());
const vk::ImageView *depthSrcView = nullptr;
const vk::ImageView *stencilSrcView = nullptr;
// The subpass that initializes the multisampled-render-to-texture attachments packs the
// attachments that need to be unresolved, so the attachment indices of this subpass are not the
// same. See InitializeUnresolveSubpass for details.
vk::PackedAttachmentIndex colorIndexVk(0);
for (size_t colorIndexGL : params.unresolveMask)
for (size_t colorIndexGL : params.unresolveColorMask)
{
RenderTargetVk *colorRenderTarget = framebuffer->getColorDrawRenderTarget(colorIndexGL);
ASSERT(colorRenderTarget->hasResolveAttachment());
ASSERT(colorRenderTarget->isImageTransient());
src[colorIndexVk.get()] = &colorRenderTarget->getResolveImageForRenderPass();
ANGLE_TRY(colorRenderTarget->getResolveImageView(contextVk, &srcView[colorIndexVk.get()]));
colorSrc[colorIndexVk.get()] = &colorRenderTarget->getResolveImageForRenderPass();
ANGLE_TRY(
colorRenderTarget->getResolveImageView(contextVk, &colorSrcView[colorIndexVk.get()]));
++colorIndexVk;
}
const uint32_t attachmentCount = colorIndexVk.get();
const Function function = static_cast<Function>(
static_cast<uint32_t>(Function::Unresolve1Attachment) + attachmentCount - 1);
ANGLE_TRY(ensureUnresolveResourcesInitialized(contextVk, function, attachmentCount));
if (params.unresolveDepth || params.unresolveStencil)
{
RenderTargetVk *depthStencilRenderTarget = framebuffer->getDepthStencilRenderTarget();
ASSERT(depthStencilRenderTarget->hasResolveAttachment());
ASSERT(depthStencilRenderTarget->isImageTransient());
vk::ImageHelper *depthStencilSrc =
&depthStencilRenderTarget->getResolveImageForRenderPass();
// The resolved depth/stencil image is necessarily single-sampled.
ASSERT(depthStencilSrc->getSamples() == 1);
gl::TextureType textureType = vk::Get2DTextureType(depthStencilSrc->getLayerCount(), 1);
const vk::LevelIndex levelIndex = gl_vk::GetLevelIndex(
depthStencilRenderTarget->getLevelIndex(), depthStencilSrc->getBaseLevel());
const uint32_t layerIndex = depthStencilRenderTarget->getLayerIndex();
if (params.unresolveDepth)
{
ANGLE_TRY(depthStencilSrc->initLayerImageView(
contextVk, textureType, VK_IMAGE_ASPECT_DEPTH_BIT, gl::SwizzleState(),
&depthView.get(), levelIndex, 1, layerIndex, 1));
depthSrcView = &depthView.get();
}
if (params.unresolveStencil)
{
ANGLE_TRY(depthStencilSrc->initLayerImageView(
contextVk, textureType, VK_IMAGE_ASPECT_STENCIL_BIT, gl::SwizzleState(),
&stencilView.get(), levelIndex, 1, layerIndex, 1));
stencilSrcView = &stencilView.get();
}
}
const uint32_t colorAttachmentCount = colorIndexVk.get();
const uint32_t depthStencilBindingCount =
(params.unresolveDepth ? 1 : 0) + (params.unresolveStencil ? 1 : 0);
const uint32_t totalBindingCount = colorAttachmentCount + depthStencilBindingCount;
ASSERT(totalBindingCount > 0);
const Function function = static_cast<Function>(
static_cast<uint32_t>(Function::Unresolve1Attachment) + totalBindingCount - 1);
ANGLE_TRY(ensureUnresolveResourcesInitialized(contextVk, function, totalBindingCount));
vk::GraphicsPipelineDesc pipelineDesc;
pipelineDesc.initDefaults();
pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
pipelineDesc.setRasterizationSamples(framebuffer->getSamples());
pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
// Note: depth test is disabled by default so this should be unnecessary, but works around an
// Intel bug on windows. http://anglebug.com/3348
pipelineDesc.setDepthWriteEnabled(false);
pipelineDesc.setDepthTestEnabled(params.unresolveDepth);
pipelineDesc.setDepthWriteEnabled(params.unresolveDepth);
pipelineDesc.setDepthFunc(VK_COMPARE_OP_ALWAYS);
if (params.unresolveStencil)
{
SetStencilForShaderExport(contextVk, &pipelineDesc);
}
VkViewport viewport;
gl::Rectangle completeRenderArea = framebuffer->getRotatedCompleteRenderArea(contextVk);
......@@ -2193,31 +2307,48 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk,
vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
ANGLE_TRY(allocateDescriptorSet(contextVk, function, &descriptorPoolBinding, &descriptorSet));
gl::DrawBuffersArray<VkDescriptorImageInfo> inputImageInfo = {};
for (uint32_t attachmentIndex = 0; attachmentIndex < attachmentCount; ++attachmentIndex)
vk::FramebufferAttachmentArray<VkDescriptorImageInfo> inputImageInfo = {};
for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
{
inputImageInfo[attachmentIndex].imageView = srcView[attachmentIndex]->getHandle();
inputImageInfo[attachmentIndex].imageView = colorSrcView[attachmentIndex]->getHandle();
inputImageInfo[attachmentIndex].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
uint32_t depthStencilBindingIndex = colorAttachmentCount;
if (params.unresolveDepth)
{
inputImageInfo[depthStencilBindingIndex].imageView = depthSrcView->getHandle();
inputImageInfo[depthStencilBindingIndex].imageLayout =
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
++depthStencilBindingIndex;
}
if (params.unresolveStencil)
{
inputImageInfo[depthStencilBindingIndex].imageView = stencilSrcView->getHandle();
inputImageInfo[depthStencilBindingIndex].imageLayout =
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
VkWriteDescriptorSet writeInfo = {};
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.dstSet = descriptorSet;
writeInfo.dstBinding = 0;
writeInfo.descriptorCount = attachmentCount;
writeInfo.descriptorCount = totalBindingCount;
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
writeInfo.pImageInfo = inputImageInfo.data();
vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
gl::DrawBuffersArray<UnresolveAttachmentType> attachmentTypes;
uint32_t flags = GetUnresolveFlags(attachmentCount, src, &attachmentTypes);
gl::DrawBuffersArray<UnresolveColorAttachmentType> colorAttachmentTypes;
uint32_t flags = GetUnresolveFlags(colorAttachmentCount, colorSrc, params.unresolveDepth,
params.unresolveStencil, &colorAttachmentTypes);
vk::ShaderLibrary &shaderLibrary = contextVk->getShaderLibrary();
vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr;
vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = &mUnresolveFragShaders[flags];
ANGLE_TRY(shaderLibrary.getFullScreenQuad_vert(contextVk, 0, &vertexShader));
ANGLE_TRY(GetUnresolveFrag(contextVk, attachmentCount, attachmentTypes, fragmentShader));
ANGLE_TRY(GetUnresolveFrag(contextVk, colorAttachmentCount, colorAttachmentTypes,
params.unresolveDepth, params.unresolveStencil, fragmentShader));
vk::CommandBuffer *commandBuffer =
&contextVk->getStartedRenderPassCommands().getCommandBuffer();
......@@ -2225,10 +2356,17 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk,
ANGLE_TRY(setupProgram(contextVk, function, fragmentShader, vertexShader,
&mUnresolvePrograms[flags], &pipelineDesc, descriptorSet, nullptr, 0,
commandBuffer));
// This draw call is made before ContextVk gets a chance to start the occlusion query. As such,
// occlusion queries are not enabled.
commandBuffer->draw(3, 0);
// Release temporary views
vk::ImageView depthViewObject = depthView.release();
vk::ImageView stencilViewObject = stencilView.release();
contextVk->addGarbage(&depthViewObject);
contextVk->addGarbage(&stencilViewObject);
return angle::Result::Continue;
}
......
......@@ -166,7 +166,9 @@ class UtilsVk : angle::NonCopyable
struct UnresolveParameters
{
gl::DrawBufferMask unresolveMask;
gl::DrawBufferMask unresolveColorMask;
bool unresolveDepth;
bool unresolveStencil;
};
// Based on the maximum number of levels in GenerateMipmap.comp.
......@@ -406,30 +408,33 @@ class UtilsVk : angle::NonCopyable
ImageClear = 0,
ImageCopy = 1,
BlitResolve = 2,
// Note: unresolve is special as it has a different layout per attachment
Unresolve1Attachment = 3,
Unresolve2Attachments = 4,
Unresolve3Attachments = 5,
Unresolve4Attachments = 6,
Unresolve5Attachments = 7,
Unresolve6Attachments = 8,
Unresolve7Attachments = 9,
Unresolve8Attachments = 10,
// Note: unresolve is special as it has a different layout per attachment count. Depth and
// stencil each require a binding, so are counted separately.
Unresolve1Attachment = 3,
Unresolve2Attachments = 4,
Unresolve3Attachments = 5,
Unresolve4Attachments = 6,
Unresolve5Attachments = 7,
Unresolve6Attachments = 8,
Unresolve7Attachments = 9,
Unresolve8Attachments = 10,
Unresolve9Attachments = 11,
Unresolve10Attachments = 12,
// Functions implemented in compute
ComputeStartIndex = 11, // Special value to separate draw and dispatch functions.
ConvertIndexBuffer = 11,
ConvertVertexBuffer = 12,
BlitResolveStencilNoExport = 13,
OverlayCull = 14,
OverlayDraw = 15,
ConvertIndexIndirectBuffer = 16,
ConvertIndexIndirectLineLoopBuffer = 17,
ConvertIndirectLineLoopBuffer = 18,
GenerateMipmap = 19,
InvalidEnum = 20,
EnumCount = 20,
ComputeStartIndex = 13, // Special value to separate draw and dispatch functions.
ConvertIndexBuffer = 13,
ConvertVertexBuffer = 14,
BlitResolveStencilNoExport = 15,
OverlayCull = 16,
OverlayDraw = 17,
ConvertIndexIndirectBuffer = 18,
ConvertIndexIndirectLineLoopBuffer = 19,
ConvertIndirectLineLoopBuffer = 20,
GenerateMipmap = 21,
InvalidEnum = 22,
EnumCount = 22,
};
// Common function that creates the pipeline for the specified function, binds it and prepares
......
......@@ -178,12 +178,14 @@ void UnpackColorResolveAttachmentDesc(VkAttachmentDescription *desc,
const angle::Format &angleFormat = format.actualImageFormat();
ASSERT(angleFormat.depthBits == 0 && angleFormat.stencilBits == 0);
// Resolve attachments always have a sample count of 1. For simplicity, unlikely cases where
// the resolve framebuffer is immediately invalidated or cleared are ignored. Therefore, loadOp
// and storeOp can be fixed to DONT_CARE and STORE respectively.
// Resolve attachments always have a sample count of 1.
//
// That said, if the corresponding color attachment needs to take its initial value from the
// resolve attachment (i.e. needs to be unresolved), loadOp needs to be set to LOAD.
// If the corresponding color attachment needs to take its initial value from the resolve
// attachment (i.e. needs to be unresolved), loadOp needs to be set to LOAD, otherwise it should
// be DONT_CARE as it gets overwritten during resolve.
//
// storeOp should be STORE. If the attachment is invalidated, it would get set to DONT_CARE.
// TODO(syoussefi): currently invalidate doesn't affect storeOp of resolve attachment.
desc->samples = VK_SAMPLE_COUNT_1_BIT;
desc->loadOp =
usedAsInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
......@@ -195,7 +197,9 @@ void UnpackColorResolveAttachmentDesc(VkAttachmentDescription *desc,
}
void UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription *desc,
const vk::Format &format)
const vk::Format &format,
bool usedAsDepthInputAttachment,
bool usedAsStencilInputAttachment)
{
// There cannot be simultaneous usages of the depth/stencil resolve image, as depth/stencil
// resolve currently only comes from depth/stencil renderbuffers.
......@@ -206,14 +210,15 @@ void UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription *desc,
const angle::Format &angleFormat = format.intendedFormat();
ASSERT(angleFormat.depthBits != 0 || angleFormat.stencilBits != 0);
// Resolve attachments always have a sample count of 1. Currently, invalidate of
// multisampled-render-to-texture depth/stencil renderbuffer is not implemented. Therefore,
// loadOp and storeOp can be fixed to DONT_CARE and STORE respectively.
// Similarly to color resolve attachments, sample count is 1, loadOp is LOAD or DONT_CARE based
// on whether unresolve is required, and storeOp is STORE (if aspect exists).
desc->samples = VK_SAMPLE_COUNT_1_BIT;
desc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc->loadOp =
usedAsDepthInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc->storeOp =
angleFormat.depthBits > 0 ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc->stencilLoadOp =
usedAsStencilInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc->stencilStoreOp = angleFormat.stencilBits > 0 ? VK_ATTACHMENT_STORE_OP_STORE
: VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
......@@ -258,10 +263,10 @@ void SetPipelineShaderStageInfo(const VkStructureType type,
shaderStage->pSpecializationInfo = &specializationInfo;
}
// Defines a subpass that uses the resolve attachments as input attachments to initialize color
// attachments that need to be "unresolved" at the start of the render pass. The subpass will
// only contain color attachments that need to be unresolved to simplify the shader that performs
// the operations.
// Defines a subpass that uses the resolve attachments as input attachments to initialize color and
// depth/stencil attachments that need to be "unresolved" at the start of the render pass. The
// subpass will only contain the attachments that need to be unresolved to simplify the shader that
// performs the operations.
void InitializeUnresolveSubpass(
const RenderPassDesc &desc,
const gl::DrawBuffersVector<VkAttachmentReference> &drawSubpassColorAttachmentRefs,
......@@ -269,7 +274,8 @@ void InitializeUnresolveSubpass(
const VkAttachmentReference &depthStencilAttachmentRef,
const VkAttachmentReference2KHR &depthStencilResolveAttachmentRef,
gl::DrawBuffersVector<VkAttachmentReference> *unresolveColorAttachmentRefs,
gl::DrawBuffersVector<VkAttachmentReference> *unresolveInputAttachmentRefs,
VkAttachmentReference *unresolveDepthStencilAttachmentRef,
FramebufferAttachmentsVector<VkAttachmentReference> *unresolveInputAttachmentRefs,
FramebufferAttachmentsVector<uint32_t> *unresolvePreserveAttachmentRefs,
VkSubpassDescription *subpassDesc)
{
......@@ -300,6 +306,11 @@ void InitializeUnresolveSubpass(
// RP Attachment[7] <- corresponding to resolve attachment of GL Color 4
// RP Attachment[8] <- corresponding to resolve attachment of GL Color 6
//
// If the depth/stencil attachment is to be resolved, the following attachment would also be
// present:
//
// RP Attachment[9] <- corresponding to resolve attachment of GL Depth/Stencil
//
// The subpass that takes the application draw calls has the following attachments, creating
// the mapping from the Vulkan attachment indices (i.e. RP attachment indices) to GL indices
// as indicated by the GL shaders:
......@@ -322,6 +333,10 @@ void InitializeUnresolveSubpass(
// Subpass[1] Resolve[6] -> RP Attachment[8]
// Subpass[1] Resolve[7] -> VK_ATTACHMENT_UNUSED
//
// With depth/stencil resolve attachment:
//
// Subpass[1] Depth/Stencil Resolve -> RP Attachment[9]
//
// The initial subpass that's created here is (remember that in the above example Color 4
// and 6 need to be unresolved):
//
......@@ -333,18 +348,26 @@ void InitializeUnresolveSubpass(
// The trick here therefore is to use the color attachment refs already created for the
// application draw subpass indexed with colorIndexGL.
//
// If depth/stencil needs to be unresolved:
//
// Subpass[0] Input[2] -> RP Attachment[9] = Subpass[1] Depth/Stencil Resolve
// Subpass[0] Color[2] -> RP Attachment[5] = Subpass[1] Depth/Stencil
//
// As an additional note, the attachments that are not used in the unresolve subpass must be
// preserved. That is color attachments and the depth/stencil attachment if any. Resolve
// attachments are rewritten by the next subpass, so they don't need to be preserved. Note
// that there's no need to preserve a color attachment whose loadOp is DONT_CARE. For
// simplicity, we preserve those as well. The driver would ideally avoid preserving
// attachments with loadOp=DONT_CARE.
// that there's no need to preserve attachments whose loadOp is DONT_CARE. For simplicity,
// we preserve those as well. The driver would ideally avoid preserving attachments with
// loadOp=DONT_CARE.
//
// With the above example:
//
// Subpass[0] Preserve[0] -> RP Attachment[0] = Subpass[1] Color[0]
// Subpass[0] Preserve[1] -> RP Attachment[1] = Subpass[1] Color[3]
// Subpass[0] Preserve[2] -> RP Attachment[4] = Subpass[1] Color[7]
//
// If depth/stencil is not unresolved:
//
// Subpass[0] Preserve[3] -> RP Attachment[5] = Subpass[1] Depth/Stencil
//
// Again, the color attachment refs already created for the application draw subpass can be
......@@ -373,27 +396,41 @@ void InitializeUnresolveSubpass(
unresolveInputAttachmentRefs->back().layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
// Preserve depth/stencil attachments.
if (depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED)
if (desc.hasDepthStencilUnresolveAttachment())
{
// There's no need to preserve the depth attachment if loadOp=DONT_CARE, but we do for
// simplicity.
unresolvePreserveAttachmentRefs->push_back(depthStencilAttachmentRef.attachment);
}
ASSERT(desc.hasDepthStencilAttachment());
ASSERT(desc.hasDepthStencilResolveAttachment());
*unresolveDepthStencilAttachmentRef = depthStencilAttachmentRef;
ASSERT(!unresolveColorAttachmentRefs->empty());
ASSERT(unresolveColorAttachmentRefs->size() == unresolveInputAttachmentRefs->size());
VkAttachmentReference unresolveDepthStencilInputAttachmentRef = {};
unresolveDepthStencilInputAttachmentRef.attachment =
depthStencilResolveAttachmentRef.attachment;
unresolveDepthStencilInputAttachmentRef.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
const uint32_t attachmentCount = static_cast<uint32_t>(unresolveColorAttachmentRefs->size());
unresolveInputAttachmentRefs->push_back(unresolveDepthStencilInputAttachmentRef);
}
else if (desc.hasDepthStencilAttachment())
{
// Preserve the depth/stencil attachment if not unresolved. Again, there's no need to
// preserve this attachment if loadOp=DONT_CARE, but we do for simplicity.
unresolvePreserveAttachmentRefs->push_back(depthStencilAttachmentRef.attachment);
}
subpassDesc->flags = 0;
subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc->inputAttachmentCount = attachmentCount;
subpassDesc->pInputAttachments = unresolveInputAttachmentRefs->data();
subpassDesc->colorAttachmentCount = attachmentCount;
subpassDesc->pColorAttachments = unresolveColorAttachmentRefs->data();
subpassDesc->pResolveAttachments = nullptr;
subpassDesc->pDepthStencilAttachment = nullptr;
ASSERT(!unresolveColorAttachmentRefs->empty() ||
unresolveDepthStencilAttachmentRef->attachment != VK_ATTACHMENT_UNUSED);
ASSERT(unresolveColorAttachmentRefs->size() +
(desc.hasDepthStencilUnresolveAttachment() ? 1 : 0) ==
unresolveInputAttachmentRefs->size());
subpassDesc->flags = 0;
subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc->inputAttachmentCount = static_cast<uint32_t>(unresolveInputAttachmentRefs->size());
subpassDesc->pInputAttachments = unresolveInputAttachmentRefs->data();
subpassDesc->colorAttachmentCount = static_cast<uint32_t>(unresolveColorAttachmentRefs->size());
subpassDesc->pColorAttachments = unresolveColorAttachmentRefs->data();
subpassDesc->pResolveAttachments = nullptr;
subpassDesc->pDepthStencilAttachment = unresolveDepthStencilAttachmentRef;
subpassDesc->preserveAttachmentCount =
static_cast<uint32_t>(unresolvePreserveAttachmentRefs->size());
subpassDesc->pPreserveAttachments = unresolvePreserveAttachmentRefs->data();
......@@ -405,9 +442,12 @@ template <typename T>
using SubpassVector = angle::FastVector<T, kSubpassFastVectorSize>;
void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription> &subpassDesc,
bool unresolveColor,
bool unresolveDepthStencil,
std::vector<VkSubpassDependency> *subpassDependencies)
{
ASSERT(subpassDesc.size() >= 2);
ASSERT(unresolveColor || unresolveDepthStencil);
// The unresolve subpass is the first subpass. The application draw subpass is the next one.
constexpr uint32_t kUnresolveSubpassIndex = 0;
......@@ -416,9 +456,9 @@ void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescrip
// A subpass dependency is needed between the unresolve and draw subpasses. There are two
// hazards here:
//
// - Subpass 0 writes to color attachments, subpass 1 writes to the same color attachments.
// This is a WaW hazard (color write -> color write) similar to when two subsequent render
// passes write to the same images.
// - Subpass 0 writes to color/depth/stencil attachments, subpass 1 writes to the same
// attachments. This is a WaW hazard (color/depth/stencil write -> color/depth/stencil write)
// similar to when two subsequent render passes write to the same images.
// - Subpass 0 reads from resolve attachments, subpass 1 writes to the same resolve attachments.
// This is a WaR hazard (fragment shader read -> color write) which only requires an execution
// barrier.
......@@ -438,32 +478,78 @@ void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescrip
// > can access any sample in the input attachment's pixel even if it only uses
// > framebuffer-local dependencies.
//
// The dependency for the first hazard above (color write -> color write) is on same-sample
// attachments, so it will not allow the use of input attachments as required by the unresolve
// subpass. As a result, even though the second hazard seems to be subsumed by the first (its
// src stage is earlier and its dst stage is the same), a separate dependency is created for it
// just to obtain a pixel granularity dependency.
// The dependency for the first hazard above (attachment write -> attachment write) is on
// same-sample attachments, so it will not allow the use of input attachments as required by the
// unresolve subpass. As a result, even though the second hazard seems to be subsumed by the
// first (its src stage is earlier and its dst stage is the same), a separate dependency is
// created for it just to obtain a pixel granularity dependency.
//
// Note: depth/stencil resolve is considered to be done in the color write stage:
//
// > Moving to the next subpass automatically performs any multisample resolve operations in the
// > subpass being ended. End-of-subpass multisample resolves are treated as color attachment
// > writes for the purposes of synchronization. This applies to resolve operations for both
// > color and depth/stencil attachments. That is, they are considered to execute in the
// > VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT pipeline stage and their writes are
// > synchronized with VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.
subpassDependencies->emplace_back();
VkSubpassDependency *dependency = &subpassDependencies->back();
constexpr VkPipelineStageFlags kColorWriteStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
constexpr VkPipelineStageFlags kColorReadWriteStage =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
constexpr VkAccessFlags kColorWriteFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
constexpr VkAccessFlags kColorReadWriteFlags =
kColorWriteFlags | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
constexpr VkPipelineStageFlags kDepthStencilWriteStage =
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
constexpr VkPipelineStageFlags kDepthStencilReadWriteStage =
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
constexpr VkAccessFlags kDepthStencilWriteFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
constexpr VkAccessFlags kDepthStencilReadWriteFlags =
kDepthStencilWriteFlags | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
VkPipelineStageFlags attachmentWriteStages = 0;
VkPipelineStageFlags attachmentReadWriteStages = 0;
VkAccessFlags attachmentWriteFlags = 0;
VkAccessFlags attachmentReadWriteFlags = 0;
if (unresolveColor)
{
attachmentWriteStages |= kColorWriteStage;
attachmentReadWriteStages |= kColorReadWriteStage;
attachmentWriteFlags |= kColorWriteFlags;
attachmentReadWriteFlags |= kColorReadWriteFlags;
}
if (unresolveDepthStencil)
{
attachmentWriteStages |= kDepthStencilWriteStage;
attachmentReadWriteStages |= kDepthStencilReadWriteStage;
attachmentWriteFlags |= kDepthStencilWriteFlags;
attachmentReadWriteFlags |= kDepthStencilReadWriteFlags;
}
dependency->srcSubpass = kUnresolveSubpassIndex;
dependency->dstSubpass = kDrawSubpassIndex;
dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency->dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency->srcStageMask = attachmentWriteStages;
dependency->dstStageMask = attachmentReadWriteStages;
dependency->srcAccessMask = attachmentWriteFlags;
dependency->dstAccessMask = attachmentReadWriteFlags;
dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
subpassDependencies->emplace_back();
dependency = &subpassDependencies->back();
// Note again that depth/stencil resolve is considered to be done in the color output stage.
dependency->srcSubpass = kUnresolveSubpassIndex;
dependency->dstSubpass = kDrawSubpassIndex;
dependency->srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency->dstStageMask = kColorWriteStage;
dependency->srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
dependency->dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency->dstAccessMask = kColorWriteFlags;
dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
}
......@@ -495,7 +581,7 @@ void ToAttachmentReference2(const VkAttachmentReference &ref,
}
void ToSubpassDescription2(const VkSubpassDescription &desc,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &inputRefs,
const FramebufferAttachmentsVector<VkAttachmentReference2KHR> &inputRefs,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &resolveRefs,
const VkAttachmentReference2KHR &depthStencilRef,
......@@ -531,6 +617,8 @@ void ToSubpassDependency2(const VkSubpassDependency &dep, VkSubpassDependency2KH
angle::Result CreateRenderPass2(Context *context,
const VkRenderPassCreateInfo &createInfo,
const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
bool unresolveDepth,
bool unresolveStencil,
RenderPass *renderPass)
{
// Convert the attachments to VkAttachmentDescription2.
......@@ -542,8 +630,8 @@ angle::Result CreateRenderPass2(Context *context,
// Convert subpass attachments to VkAttachmentReference2 and the subpass description to
// VkSubpassDescription2.
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassInputAttachmentRefs(
createInfo.subpassCount);
SubpassVector<FramebufferAttachmentsVector<VkAttachmentReference2KHR>>
subpassInputAttachmentRefs(createInfo.subpassCount);
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassColorAttachmentRefs(
createInfo.subpassCount);
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassResolveAttachmentRefs(
......@@ -554,7 +642,7 @@ angle::Result CreateRenderPass2(Context *context,
for (uint32_t subpass = 0; subpass < createInfo.subpassCount; ++subpass)
{
const VkSubpassDescription &desc = createInfo.pSubpasses[subpass];
gl::DrawBuffersVector<VkAttachmentReference2KHR> &inputRefs =
FramebufferAttachmentsVector<VkAttachmentReference2KHR> &inputRefs =
subpassInputAttachmentRefs[subpass];
gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs =
subpassColorAttachmentRefs[subpass];
......@@ -568,10 +656,27 @@ angle::Result CreateRenderPass2(Context *context,
// Convert subpass attachment references.
for (uint32_t index = 0; index < desc.inputAttachmentCount; ++index)
{
// TODO(syoussefi): support depth/stencil unresolve. http://anglebug.com/4836
ToAttachmentReference2(desc.pInputAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT,
&inputRefs[index]);
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
if (index >= desc.colorAttachmentCount)
{
// Set the aspect of the depth/stencil input attachment (of which there can be only
// one).
ASSERT(index + 1 == desc.inputAttachmentCount);
aspectMask = 0;
if (unresolveDepth)
{
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (unresolveStencil)
{
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
ASSERT(aspectMask != 0);
}
ToAttachmentReference2(desc.pInputAttachments[index], aspectMask, &inputRefs[index]);
}
for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
{
ToAttachmentReference2(desc.pColorAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT,
......@@ -751,7 +856,9 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
depthStencilResolveAttachmentRef.aspectMask =
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
UnpackDepthStencilResolveAttachmentDesc(&attachmentDescs[attachmentCount.get()], format);
UnpackDepthStencilResolveAttachmentDesc(&attachmentDescs[attachmentCount.get()], format,
desc.hasDepthUnresolveAttachment(),
desc.hasStencilUnresolveAttachment());
++attachmentCount;
}
......@@ -763,15 +870,17 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
// which is in turn used in VkRenderPassCreateInfo below. That is why they are declared in the
// same scope.
gl::DrawBuffersVector<VkAttachmentReference> unresolveColorAttachmentRefs;
gl::DrawBuffersVector<VkAttachmentReference> unresolveInputAttachmentRefs;
VkAttachmentReference unresolveDepthStencilAttachmentRef = kUnusedAttachment;
FramebufferAttachmentsVector<VkAttachmentReference> unresolveInputAttachmentRefs;
FramebufferAttachmentsVector<uint32_t> unresolvePreserveAttachmentRefs;
if (desc.getColorUnresolveAttachmentMask().any())
if (desc.getColorUnresolveAttachmentMask().any() || desc.hasDepthStencilUnresolveAttachment())
{
subpassDesc.push_back({});
InitializeUnresolveSubpass(desc, colorAttachmentRefs, colorResolveAttachmentRefs,
depthStencilAttachmentRef, depthStencilResolveAttachmentRef,
&unresolveColorAttachmentRefs, &unresolveInputAttachmentRefs,
&unresolvePreserveAttachmentRefs, &subpassDesc.back());
InitializeUnresolveSubpass(
desc, colorAttachmentRefs, colorResolveAttachmentRefs, depthStencilAttachmentRef,
depthStencilResolveAttachmentRef, &unresolveColorAttachmentRefs,
&unresolveDepthStencilAttachmentRef, &unresolveInputAttachmentRefs,
&unresolvePreserveAttachmentRefs, &subpassDesc.back());
}
subpassDesc.push_back({});
......@@ -810,9 +919,11 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
}
std::vector<VkSubpassDependency> subpassDependencies;
if (desc.getColorUnresolveAttachmentMask().any())
if (desc.getColorUnresolveAttachmentMask().any() || desc.hasDepthStencilUnresolveAttachment())
{
InitializeUnresolveSubpassDependencies(subpassDesc, &subpassDependencies);
InitializeUnresolveSubpassDependencies(
subpassDesc, desc.getColorUnresolveAttachmentMask().any(),
desc.hasDepthStencilUnresolveAttachment(), &subpassDependencies);
}
VkRenderPassCreateInfo createInfo = {};
......@@ -835,7 +946,9 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
// vkCreateRenderPass2KHR.
if (desc.hasDepthStencilResolveAttachment())
{
ANGLE_TRY(CreateRenderPass2(context, createInfo, depthStencilResolve, renderPass));
ANGLE_TRY(CreateRenderPass2(context, createInfo, depthStencilResolve,
desc.hasDepthUnresolveAttachment(),
desc.hasStencilUnresolveAttachment(), renderPass));
}
else
{
......@@ -1082,6 +1195,29 @@ void RenderPassDesc::packDepthStencilResolveAttachment(bool resolveDepth, bool r
}
}
void RenderPassDesc::packDepthStencilUnresolveAttachment(bool unresolveDepth, bool unresolveStencil)
{
ASSERT(hasDepthStencilAttachment());
static_assert(
(kDepthStencilFormatStorageMask & (kUnresolveDepthFlag | kUnresolveStencilFlag)) == 0,
"Collision in depth/stencil format and flag bits");
if (unresolveDepth)
{
mAttachmentFormats.back() |= kUnresolveDepthFlag;
}
if (unresolveStencil)
{
mAttachmentFormats.back() |= kUnresolveStencilFlag;
}
}
void RenderPassDesc::removeDepthStencilUnresolveAttachment()
{
mAttachmentFormats.back() &= ~(kUnresolveDepthFlag | kUnresolveStencilFlag);
}
RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
......@@ -1537,7 +1673,8 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
// If this graphics pipeline is for the unresolve operation, correct the color attachment count
// for that subpass.
if (mRenderPassDesc.getColorUnresolveAttachmentMask().any() &&
if ((mRenderPassDesc.getColorUnresolveAttachmentMask().any() ||
mRenderPassDesc.hasDepthStencilUnresolveAttachment()) &&
mRasterizationAndMultisampleStateInfo.bits.subpass == 0)
{
blendState.attachmentCount =
......@@ -2431,6 +2568,8 @@ FramebufferDesc &FramebufferDesc::operator=(const FramebufferDesc &other) = defa
void FramebufferDesc::update(uint32_t index, ImageViewSubresourceSerial serial)
{
static_assert(kMaxFramebufferAttachments + 1 < std::numeric_limits<uint8_t>::max(),
"mMaxIndex size is too small");
ASSERT(index < kMaxFramebufferAttachments);
mSerials[index] = serial;
if (serial.imageViewSerial.valid())
......@@ -2449,9 +2588,9 @@ void FramebufferDesc::updateColorResolve(uint32_t index, ImageViewSubresourceSer
update(kFramebufferDescColorResolveIndexOffset + index, serial);
}
void FramebufferDesc::updateColorUnresolveMask(gl::DrawBufferMask colorUnresolveMask)
void FramebufferDesc::updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask)
{
mColorUnresolveAttachmentMask = colorUnresolveMask;
mUnresolveAttachmentMask = unresolveMask;
}
void FramebufferDesc::updateDepthStencil(ImageViewSubresourceSerial serial)
......@@ -2467,21 +2606,19 @@ void FramebufferDesc::updateDepthStencilResolve(ImageViewSubresourceSerial seria
size_t FramebufferDesc::hash() const
{
return angle::ComputeGenericHash(&mSerials, sizeof(mSerials[0]) * mMaxIndex) ^
mColorUnresolveAttachmentMask.bits();
mUnresolveAttachmentMask.bits();
}
void FramebufferDesc::reset()
{
mMaxIndex = 0;
mPadding = 0;
mColorUnresolveAttachmentMask.reset();
mUnresolveAttachmentMask.reset();
memset(&mSerials, 0, sizeof(mSerials));
}
bool FramebufferDesc::operator==(const FramebufferDesc &other) const
{
if (mMaxIndex != other.mMaxIndex ||
mColorUnresolveAttachmentMask != other.mColorUnresolveAttachmentMask)
if (mMaxIndex != other.mMaxIndex || mUnresolveAttachmentMask != other.mUnresolveAttachmentMask)
{
return false;
}
......
......@@ -118,6 +118,7 @@ using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttach
constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
template <typename T>
using FramebufferNonResolveAttachmentArray = std::array<T, kMaxFramebufferNonResolveAttachments>;
using FramebufferNonResolveAttachmentMask = angle::BitSet16<kMaxFramebufferNonResolveAttachments>;
class alignas(4) RenderPassDesc final
{
......@@ -145,6 +146,10 @@ class alignas(4) RenderPassDesc final
void removeColorUnresolveAttachment(size_t colorIndexGL);
// Indicate that a depth/stencil attachment should have a corresponding resolve attachment.
void packDepthStencilResolveAttachment(bool resolveDepth, bool resolveStencil);
// Indicate that a depth/stencil attachment should take its data from the resolve attachment
// initially.
void packDepthStencilUnresolveAttachment(bool unresolveDepth, bool unresolveStencil);
void removeDepthStencilUnresolveAttachment();
size_t hash() const;
......@@ -182,6 +187,18 @@ class alignas(4) RenderPassDesc final
{
return (mAttachmentFormats.back() & kResolveStencilFlag) != 0;
}
bool hasDepthStencilUnresolveAttachment() const
{
return (mAttachmentFormats.back() & (kUnresolveDepthFlag | kUnresolveStencilFlag)) != 0;
}
bool hasDepthUnresolveAttachment() const
{
return (mAttachmentFormats.back() & kUnresolveDepthFlag) != 0;
}
bool hasStencilUnresolveAttachment() const
{
return (mAttachmentFormats.back() & kUnresolveStencilFlag) != 0;
}
// Get the number of attachments in the Vulkan render pass, i.e. after removing disabled
// color attachments.
......@@ -260,8 +277,10 @@ class alignas(4) RenderPassDesc final
static constexpr uint8_t kDepthStencilFormatStorageMask = 0x7;
// Flags stored in the upper 5 bits of mAttachmentFormats.back().
static constexpr uint8_t kResolveDepthFlag = 0x80;
static constexpr uint8_t kResolveStencilFlag = 0x40;
static constexpr uint8_t kResolveDepthFlag = 0x80;
static constexpr uint8_t kResolveStencilFlag = 0x40;
static constexpr uint8_t kUnresolveDepthFlag = 0x20;
static constexpr uint8_t kUnresolveStencilFlag = 0x10;
};
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
......@@ -1061,7 +1080,7 @@ class FramebufferDesc
void updateColor(uint32_t index, ImageViewSubresourceSerial serial);
void updateColorResolve(uint32_t index, ImageViewSubresourceSerial serial);
void updateColorUnresolveMask(gl::DrawBufferMask colorUnresolveMask);
void updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask);
void updateDepthStencil(ImageViewSubresourceSerial serial);
void updateDepthStencilResolve(ImageViewSubresourceSerial serial);
size_t hash() const;
......@@ -1082,12 +1101,11 @@ class FramebufferDesc
// Note: this is an exclusive index. If there is one index it will be "1".
uint16_t mMaxIndex;
uint8_t mPadding;
// If the render pass contains an initial subpass to unresolve a number of attachments, the
// subpass description is derived from the following mask, specifying which attachments need
// to be unresolved.
gl::DrawBufferMask mColorUnresolveAttachmentMask;
// to be unresolved. Includes both color and depth/stencil attachments.
FramebufferNonResolveAttachmentMask mUnresolveAttachmentMask;
FramebufferAttachmentArray<ImageViewSubresourceSerial> mSerials;
};
......
......@@ -384,6 +384,22 @@ constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemory
},
},
{
ImageLayout::DepthStencilResolveAttachment,
ImageMemoryBarrierData{
"DepthStencilResolveAttachment",
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
// Note: depth/stencil resolve uses color output stage and mask!
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// Transition to: all reads and writes must happen after barrier.
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
// Transition from: all writes must finish before barrier.
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
ResourceAccess::Write,
PipelineStage::ColorAttachmentOutput,
},
},
{
ImageLayout::Present,
ImageMemoryBarrierData{
"Present",
......@@ -5743,8 +5759,8 @@ angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk,
}
// Lazily allocate the image view itself.
// Note that these views are specifically made to be used as color attachments, and therefore
// don't have swizzle.
// Note that these views are specifically made to be used as framebuffer attachments, and
// therefore don't have swizzle.
gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(),
imageView, levelVk, 1, layer, 1);
......
......@@ -1204,6 +1204,7 @@ enum class ImageLayout
ColorAttachment,
DepthStencilReadOnly,
DepthStencilAttachment,
DepthStencilResolveAttachment,
Present,
InvalidEnum,
......
......@@ -98,6 +98,9 @@ class MultisampledRenderToTextureTest : public ANGLETest
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(mCopyTextureUniformLocation, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
drawQuad(mCopyTextureProgram, essl1_shaders::PositionAttrib(), 0.5f);
// Expect that the rendered quad has the same color as the source texture
......@@ -121,7 +124,7 @@ class MultisampledRenderToTextureTest : public ANGLETest
struct GLType
{
GLint internalFormat;
GLenum internalFormat;
GLenum format;
GLenum type;
};
......@@ -156,6 +159,7 @@ class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTes
void colorAttachment1Common(bool useRenderbuffer);
void colorAttachments0And3Common(bool useRenderbuffer);
void blitFramebufferMixedColorAndDepthCommon(bool useRenderbuffer);
void renderbufferUnresolveColorAndDepthStencilThenTwoColors(bool withDepth, bool withStencil);
};
class MultisampledRenderToTextureES31Test : public MultisampledRenderToTextureTest
......@@ -1264,6 +1268,9 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
// http://anglebug.com/5096
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
......@@ -1271,7 +1278,7 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create framebuffer to draw into, with both color and depth attachments.
// Create framebuffer to draw into, with both color and depth/stencil attachments.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
......@@ -1342,6 +1349,506 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize);
}
// Draw, copy, then clear&blend. This tests uses a depth/stencil buffer and makes sure the second
// draw (in the second render pass) succeeds (i.e. depth/stencil data is not lost). The difference
// with RenderbufferDepthStencilClearDrawCopyThenBlend is that color is cleared in the second render
// pass, so only depth/stencil data is unresolved. This test doesn't apply to depth/stencil
// textures as they are explicitly autoinvalidated between render passes.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilDrawCopyClearThenBlend)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
// http://anglebug.com/5096
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create framebuffer to draw into, with both color and depth/stencil attachments.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color,
0, 4);
GLRenderbuffer depthStencil;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Set viewport and clear depth/stencil through draw
glViewport(0, 0, kSize, kSize);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilMask(0xFF);
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1.0f);
ASSERT_GL_NO_ERROR();
// Create a texture and copy into it.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Clear color to blue
glClearColor(0.0, 0.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not cleared to 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Draw again into the framebuffer, this time blending. This tests that depth/stencil data are
// preserved after the resolve incurred by the copy above and color is cleared correctly.
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 0.5f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Copy into the texture again.
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now cyan
const GLColor kExpected(0, 127, 127, 191);
EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is also cyan.
const GLColor expectedCopyResult(0, 127, 127, 191);
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize);
}
// Clear, then blit depth/stencil with renderbuffers. This test makes sure depth/stencil blit uses
// the correct image. Note that this test doesn't apply to depth/stencil textures as they are
// explicitly autoinvalidated between render passes.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferClearThenBlitDepthStencil)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
// D3D backend doesn't implement multisampled render to texture renderbuffers correctly.
// http://anglebug.com/3107
ANGLE_SKIP_TEST_IF(IsD3D());
// The following trybot configurations don't support VK_KHR_depth_stencil_resolve. ANGLE is not
// conformant without this extension, but it's allowed as users commonly invalidate
// depth/stencil.
//
// - SwifthShader
// - Android
ANGLE_SKIP_TEST_IF(IsVulkan() && (isSwiftshader() || IsAndroid() || IsAMD()));
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
// Create framebuffer to draw into, with both color and depth/stencil attachments.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color,
0, 4);
GLRenderbuffer depthStencilMS;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencilMS);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Clear depth/stencil
glClearDepthf(1);
glClearStencil(0x55);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Create framebuffer as blit target.
GLFramebuffer fbo;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
GLRenderbuffer depthStencil;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
// Blit depth/stencil
glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize,
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
// Draw into the framebuffer that was the destination of blit, verifying that depth and stencil
// values are correct.
// If depth is not 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now red
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red);
// Clear depth/stencil to a different value, and blit again but this time flipped.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboMS);
glClearDepthf(0);
glClearStencil(0x3E);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Blit
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glBlitFramebuffer(0, 0, kSize, kSize, kSize, kSize, 0, 0,
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
// Draw green
glDepthFunc(GL_GREATER);
glStencilFunc(GL_EQUAL, 0x3E, 0xFF);
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now green
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green);
}
// Draw, then blit depth/stencil with renderbuffers. This test makes sure depth/stencil resolve is
// correctly implemented. Note that this test doesn't apply to depth/stencil textures as they are
// explicitly autoinvalidated between render passes.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDrawThenBlitDepthStencil)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
// Skip on configurations that don't support VK_KHR_depth_stencil_resolve. See comment
// in RenderbufferClearThenBlitDepthStencil.
ANGLE_SKIP_TEST_IF(IsVulkan() && (isSwiftshader() || IsAndroid() || IsAMD()));
// http://anglebug.com/5096
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
constexpr GLsizei kSize = 64;
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
// Create framebuffer to draw into, with both color and depth/stencil attachments.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color,
0, 4);
GLRenderbuffer depthStencilMS;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencilMS);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Output depth/stencil through draw
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilMask(0xFF);
// Draw blue
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1.0f);
ASSERT_GL_NO_ERROR();
// Create framebuffer as blit target.
GLFramebuffer fbo;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
GLRenderbuffer depthStencil;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
// Blit depth/stencil
glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize,
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
// Draw into the framebuffer that was the destination of blit, verifying that depth and stencil
// values are correct.
// If depth is not 1, rendering would fail.
glDepthFunc(GL_LESS);
// If stencil is not 0x55, rendering would fail.
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now red
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red);
}
// Draw, then blit depth/stencil with renderbuffers, without a color attachment. Note that this test
// doesn't apply to depth/stencil textures as they are explicitly autoinvalidated between render
// passes.
//
// This test first uses a draw call to fill in the depth/stencil buffer, then blits it to force a
// resolve. Then it uses a no-op draw call to start a "fullscreen" render pass followed by a
// scissored draw to modify parts of the depth buffer:
//
// +--------------------+
// | D=1, S=0x55 |
// | |
// | +--------+ |
// | | D=0 | |
// | | S=0xAA | |
// | +--------+ |
// | |
// | |
// +--------------------+
//
// Blit is used again to copy the depth/stencil attachment data, and the result is verified.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDrawThenBlitDepthStencilOnly)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
// Skip on configurations that don't support VK_KHR_depth_stencil_resolve. See comment
// in RenderbufferClearThenBlitDepthStencil.
ANGLE_SKIP_TEST_IF(IsVulkan() && (isSwiftshader() || IsAndroid() || IsAMD()));
// http://anglebug.com/5096
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
// http://anglebug.com/5110
ANGLE_SKIP_TEST_IF(IsD3D());
constexpr GLsizei kSize = 64;
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
// Create framebuffer to draw into, with depth/stencil attachment only.
GLRenderbuffer depthStencilMS;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencilMS);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
// Output depth/stencil through draw
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilMask(0xFF);
// Draw. Depth/stencil is now:
//
// +--------------------+
// | D=1, S=0x55 |
// | |
// | |
// | |
// | |
// | |
// | |
// | |
// +--------------------+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1.0f);
ASSERT_GL_NO_ERROR();
// Create framebuffer as blit target.
GLFramebuffer fbo;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
GLRenderbuffer depthStencil;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
// Blit depth/stencil
glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize,
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
// Disable depth/stencil and draw again. Depth/stencil is not modified.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboMS);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Enable depth/stencil and do a scissored draw. Depth/stencil is now:
//
// +--------------------+
// | D=1, S=0x55 |
// | |
// | +--------+ |
// | | D=0 | |
// | | S=0xAA | |
// | +--------+ |
// | |
// | |
// +--------------------+
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0xAA, 0xFF);
glEnable(GL_SCISSOR_TEST);
glScissor(kSize / 4, kSize / 4, kSize / 2, kSize / 2);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), -1.0f);
glDisable(GL_SCISSOR_TEST);
ASSERT_GL_NO_ERROR();
// Blit depth/stencil again.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize,
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Draw into the framebuffer that was the destination of blit, verifying that depth and stencil
// values are correct.
GLTexture color;
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
// First, verify the outside border, where D=1 and S=0x55
glDepthFunc(GL_LESS);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
ASSERT_GL_NO_ERROR();
// Draw green
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
// Then, verify the center, where D=0 and S=0xAA
glDepthFunc(GL_GREATER);
glStencilFunc(GL_EQUAL, 0xAA, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Draw blue
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), -0.95f);
ASSERT_GL_NO_ERROR();
// Verify that the border is now green
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::green);
// Verify that the center is now blue
EXPECT_PIXEL_COLOR_EQ(kSize / 4, kSize / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, kSize / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize / 4, 3 * kSize / 4 - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(3 * kSize / 4 - 1, 3 * kSize / 4 - 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::blue);
}
// Test the depth read/write mode change within the renderpass while there is color unresolve
// attachment
TEST_P(MultisampledRenderToTextureTest, DepthReadWriteToggleWithStartedRenderPass)
......@@ -2139,10 +2646,6 @@ void MultisampledRenderToTextureES31Test::drawCopyThenBlendAllAttachmentsMixed(b
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture2"));
// The Vulkan backend doesn't appropriately disable blend for integer attachments. This causes
// an assertion failure within swiftshader. http://anglebug.com/4583
ANGLE_SKIP_TEST_IF(isSwiftshader());
GLint maxDrawBuffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
......@@ -2309,6 +2812,204 @@ TEST_P(MultisampledRenderToTextureES31Test, RenderbufferDrawCopyThenBlendAllAtta
drawCopyThenBlendAllAttachmentsMixed(true);
}
void MultisampledRenderToTextureES3Test::renderbufferUnresolveColorAndDepthStencilThenTwoColors(
bool withDepth,
bool withStencil)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture2"));
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
// http://anglebug.com/5096
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
constexpr GLsizei kSize = 64;
setupCopyTexProgram();
GLFramebuffer fboColorAndDepthStencil;
glBindFramebuffer(GL_FRAMEBUFFER, fboColorAndDepthStencil);
// Create framebuffer to draw into, with both color and depth/stencil attachments.
GLTexture color1;
glBindTexture(GL_TEXTURE_2D, color1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
color1, 0, 4);
GLenum depthStencilFormat = GL_DEPTH24_STENCIL8;
GLenum depthStencilTarget = GL_DEPTH_STENCIL_ATTACHMENT;
ASSERT_TRUE(withDepth || withStencil);
if (withDepth && !withStencil)
{
depthStencilFormat = GL_DEPTH_COMPONENT24;
depthStencilTarget = GL_DEPTH_ATTACHMENT;
}
if (!withDepth && withStencil)
{
depthStencilFormat = GL_STENCIL_INDEX8;
depthStencilTarget = GL_STENCIL_ATTACHMENT;
}
GLRenderbuffer depthStencil;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, depthStencilFormat, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, depthStencilTarget, GL_RENDERBUFFER, depthStencil);
ASSERT_GL_NO_ERROR();
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Set viewport and clear depth/stencil
glViewport(0, 0, kSize, kSize);
glClearDepthf(1);
glClearStencil(0x55);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// If depth is not cleared to 1, rendering would fail.
if (withDepth)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
// If stencil is not cleared to 0x55, rendering would fail.
if (withStencil)
{
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
}
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.25f);
ASSERT_GL_NO_ERROR();
// Create a texture and copy into it.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Draw again into the framebuffer, this time blending. This tests that both the color and
// depth/stencil data are preserved after the resolve incurred by the copy above.
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 0.5f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now yellow
const GLColor kExpected(127, 127, 0, 191);
EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
// For completeness, verify that the texture used as copy target is red.
const GLColor expectedCopyResult(255, 0, 0, 255);
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize);
// Now create a framebuffer with two color attachments and do something similar. This makes
// sure that the fact that both these framebuffers have 2 attachments does not cause confusion,
// for example by having the unresolve shader generated for the first framebuffer used for the
// second framebuffer.
GLFramebuffer fboTwoColors;
glBindFramebuffer(GL_FRAMEBUFFER, fboTwoColors);
GLTexture color2;
glBindTexture(GL_TEXTURE_2D, color2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
color2, 0, 4);
GLTexture color3;
glBindTexture(GL_TEXTURE_2D, color3);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
color3, 0, 4);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
constexpr GLenum kDrawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, kDrawBuffers);
glReadBuffer(GL_COLOR_ATTACHMENT1);
// Setup program
constexpr bool kBuffersEnabled[8] = {true, true};
GLuint drawColorMRT;
setupUniformColorProgramMultiRenderTarget(kBuffersEnabled, &drawColorMRT);
glUseProgram(drawColorMRT);
GLint colorUniformLocationMRT =
glGetUniformLocation(drawColorMRT, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocationMRT, -1);
// Draw blue
glUniform4f(colorUniformLocationMRT, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(drawColorMRT, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Copy into texture
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
// Blend.
glUniform4f(colorUniformLocationMRT, 0.0f, 1.0f, 0.0f, 0.5f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawQuad(drawColorMRT, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Verify that the texture is now cyan
const GLColor kExpected2(0, 127, 127, 191);
EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected2, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected2, 1);
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected2, 1);
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected2, 1);
// For completeness, verify that the texture used as copy target is blue.
const GLColor expectedCopyResult2(0, 0, 255, 255);
verifyResults(texture, expectedCopyResult2, kSize, 0, 0, kSize, kSize);
}
// Draw, copy, then blend once on a framebuffer with color and depth attachments, and once with two
// color attachments. Tests that unresolve is done correctly on two framebuffers with the same
// number of attachments, but differing in depth being there. Note that this test doesn't apply to
// depth/stencil textures as they are explicitly autoinvalidated between render passes.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferUnresolveColorAndDepthThenTwoColors)
{
renderbufferUnresolveColorAndDepthStencilThenTwoColors(true, false);
}
// Similar to RenderbufferUnresolveColorAndDepthThenTwoColors, but with stencil.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferUnresolveColorAndStencilThenTwoColors)
{
renderbufferUnresolveColorAndDepthStencilThenTwoColors(false, true);
}
// Similar to RenderbufferUnresolveColorAndDepthThenTwoColors, but with depth and stencil.
TEST_P(MultisampledRenderToTextureES3Test, RenderbufferUnresolveColorAndDepthStencilThenTwoColors)
{
renderbufferUnresolveColorAndDepthStencilThenTwoColors(true, true);
}
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(MultisampledRenderToTextureTest);
ANGLE_INSTANTIATE_TEST_ES3(MultisampledRenderToTextureES3Test);
ANGLE_INSTANTIATE_TEST_ES31(MultisampledRenderToTextureES31Test);
......
......@@ -1638,6 +1638,126 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilTextureShouldNot
EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, kSize / 2 - 1, GLColor::red);
}
// Tests that multisampled-render-to-texture depth/stencil renderbuffers don't ever load depth data.
// Stencil data may still be loaded if VK_EXT_shader_stencil_export is not supported.
TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShouldNotLoad)
{
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
const rx::vk::PerfCounters &counters = hackANGLE();
uint32_t expectedDepthClearCount = counters.depthClears + 1;
uint32_t expectedDepthLoadCount = counters.depthLoads;
uint32_t expectedStencilClearCount = counters.stencilClears + 1;
uint32_t expectedStencilLoadCountMin = counters.stencilLoads;
uint32_t expectedStencilLoadCountMax = counters.stencilLoads + 4;
GLFramebuffer FBO;
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
constexpr GLsizei kSize = 6;
// Create multisampled framebuffer to draw into, with both color and depth attachments.
GLTexture colorMS;
glBindTexture(GL_TEXTURE_2D, colorMS);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLRenderbuffer depthStencilMS;
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilMS);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
GLFramebuffer fboMS;
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
colorMS, 0, 4);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencilMS);
ASSERT_GL_NO_ERROR();
// Set up texture for copy operation that breaks the render pass
GLTexture copyTex;
glBindTexture(GL_TEXTURE_2D, copyTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// Set viewport and clear depth
glViewport(0, 0, kSize, kSize);
glClearDepthf(1);
glClearStencil(0x55);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not clear to 0x55, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Set up program
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(drawColor);
GLint colorUniformLocation =
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
ASSERT_NE(colorUniformLocation, -1);
// Draw red
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.75f);
ASSERT_GL_NO_ERROR();
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Draw green
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, 0, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Draw blue
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.25f);
ASSERT_GL_NO_ERROR();
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, kSize / 2, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Draw yellow
glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f);
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Break the render pass
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, kSize / 2, 0, 0, kSize / 2, kSize / 2);
ASSERT_GL_NO_ERROR();
// Verify the counters
EXPECT_EQ(counters.depthClears, expectedDepthClearCount);
EXPECT_EQ(counters.depthLoads, expectedDepthLoadCount);
EXPECT_EQ(counters.stencilClears, expectedStencilClearCount);
EXPECT_GE(counters.stencilLoads, expectedStencilLoadCountMin);
EXPECT_LE(counters.stencilLoads, expectedStencilLoadCountMax);
// Verify that copies were done correctly.
GLFramebuffer verifyFBO;
glBindFramebuffer(GL_FRAMEBUFFER, verifyFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copyTex, 0);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(0, kSize / 2, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::yellow);
}
// Ensures we use read-only depth layout when there is no write
TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
{
......
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