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> ...@@ -511,6 +511,9 @@ template <size_t N>
using BitSet8 = BitSetT<N, uint8_t>; using BitSet8 = BitSetT<N, uint8_t>;
template <size_t N> template <size_t N>
using BitSet16 = BitSetT<N, uint16_t>;
template <size_t N>
using BitSet32 = BitSetT<N, uint32_t>; using BitSet32 = BitSetT<N, uint32_t>;
template <size_t N> template <size_t N>
......
...@@ -2243,7 +2243,10 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2243,7 +2243,10 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Initialize RenderPass info. // Initialize RenderPass info.
vk::AttachmentOpsArray renderPassAttachmentOps; vk::AttachmentOpsArray renderPassAttachmentOps;
vk::PackedClearValuesArray packedClearValues; vk::PackedClearValuesArray packedClearValues;
gl::DrawBufferMask previousUnresolveMask = mRenderPassDesc.getColorUnresolveAttachmentMask(); gl::DrawBufferMask previousUnresolveColorMask =
mRenderPassDesc.getColorUnresolveAttachmentMask();
bool previousUnresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
bool previousUnresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
// Color attachments. // Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors(); const auto &colorRenderTargets = mRenderTargetCache.getColors();
...@@ -2318,6 +2321,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2318,6 +2321,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget(); RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
const bool canExportStencil =
contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled;
// depth stencil attachment always immediately follows color attachment // depth stencil attachment always immediately follows color attachment
depthStencilAttachmentIndex = colorIndexVk; depthStencilAttachmentIndex = colorIndexVk;
...@@ -2337,14 +2343,16 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2337,14 +2343,16 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 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()) if (depthStencilRenderTarget->isImageTransient())
{ {
// TODO(syoussefi): currently, depth/stencil unresolve is not implemented. Until then, depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
// 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 (canExportStencil || depthStencilRenderTarget->isEntirelyTransient())
if (depthStencilRenderTarget->isEntirelyTransient())
{ {
depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
} }
} }
...@@ -2391,6 +2399,40 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2391,6 +2399,40 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthStoreOp = VK_ATTACHMENT_STORE_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.setOps(depthStencilAttachmentIndex, depthLoadOp, depthStoreOp);
renderPassAttachmentOps.setStencilOps(depthStencilAttachmentIndex, stencilLoadOp, renderPassAttachmentOps.setStencilOps(depthStencilAttachmentIndex, stencilLoadOp,
stencilStoreOp); stencilStoreOp);
...@@ -2418,13 +2460,28 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -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, // 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 // or the existence of resolve attachments in single subpass render passes. The modification
// here can add/remove a subpass, or modify its input attachments. // here can add/remove a subpass, or modify its input attachments.
gl::DrawBufferMask unresolveMask = mRenderPassDesc.getColorUnresolveAttachmentMask(); gl::DrawBufferMask unresolveColorMask = mRenderPassDesc.getColorUnresolveAttachmentMask();
if (previousUnresolveMask != unresolveMask) bool unresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
bool unresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
if (previousUnresolveColorMask != unresolveColorMask ||
previousUnresolveDepth != unresolveDepth || previousUnresolveStencil != unresolveStencil)
{ {
contextVk->onDrawFramebufferRenderPassDescChange(this); contextVk->onDrawFramebufferRenderPassDescChange(this);
// Make sure framebuffer is recreated. // Make sure framebuffer is recreated.
mFramebuffer = nullptr; 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; vk::Framebuffer *framebuffer = nullptr;
...@@ -2450,11 +2507,13 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2450,11 +2507,13 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
depthStencilRenderTarget->onDepthStencilDraw(contextVk, mReadOnlyDepthStencilMode); depthStencilRenderTarget->onDepthStencilDraw(contextVk, mReadOnlyDepthStencilMode);
} }
if (unresolveMask.any()) if (unresolveColorMask.any() || unresolveDepth || unresolveStencil)
{ {
// Unresolve attachments if any. // Unresolve attachments if any.
UtilsVk::UnresolveParameters params; UtilsVk::UnresolveParameters params;
params.unresolveMask = unresolveMask; params.unresolveColorMask = unresolveColorMask;
params.unresolveDepth = unresolveDepth;
params.unresolveStencil = unresolveStencil;
ANGLE_TRY(contextVk->getUtils().unresolve(contextVk, this, params)); ANGLE_TRY(contextVk->getUtils().unresolve(contextVk, this, params));
......
...@@ -125,8 +125,8 @@ void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, bool isReadOnly) ...@@ -125,8 +125,8 @@ void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, bool isReadOnly)
mImage); mImage);
if (mResolveImage) if (mResolveImage)
{ {
contextVk->onImageRenderPassWrite(aspectFlags, vk::ImageLayout::DepthStencilAttachment, contextVk->onImageRenderPassWrite(
mResolveImage); aspectFlags, vk::ImageLayout::DepthStencilResolveAttachment, mResolveImage);
} }
} }
......
...@@ -272,7 +272,7 @@ uint32_t GetGenerateMipmapFlags(ContextVk *contextVk, const vk::Format &format) ...@@ -272,7 +272,7 @@ uint32_t GetGenerateMipmapFlags(ContextVk *contextVk, const vk::Format &format)
return flags; return flags;
} }
enum UnresolveAttachmentType enum UnresolveColorAttachmentType
{ {
kUnresolveTypeUnused = 0, kUnresolveTypeUnused = 0,
kUnresolveTypeFloat = 1, kUnresolveTypeFloat = 1,
...@@ -280,17 +280,19 @@ enum UnresolveAttachmentType ...@@ -280,17 +280,19 @@ enum UnresolveAttachmentType
kUnresolveTypeUint = 3, kUnresolveTypeUint = 3,
}; };
uint32_t GetUnresolveFlags(uint32_t attachmentCount, uint32_t GetUnresolveFlags(uint32_t colorAttachmentCount,
const gl::DrawBuffersArray<vk::ImageHelper *> &src, const gl::DrawBuffersArray<vk::ImageHelper *> &colorSrc,
gl::DrawBuffersArray<UnresolveAttachmentType> *attachmentTypesOut) bool unresolveDepth,
bool unresolveStencil,
gl::DrawBuffersArray<UnresolveColorAttachmentType> *attachmentTypesOut)
{ {
uint32_t flags = 0; 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()) if (format.isSint())
{ {
type = kUnresolveTypeSint; type = kUnresolveTypeSint;
...@@ -302,11 +304,24 @@ uint32_t GetUnresolveFlags(uint32_t attachmentCount, ...@@ -302,11 +304,24 @@ uint32_t GetUnresolveFlags(uint32_t attachmentCount,
(*attachmentTypesOut)[attachmentIndex] = type; (*attachmentTypesOut)[attachmentIndex] = type;
// |flags| is comprised of |attachmentCount| values from |UnresolveAttachmentType|, each // |flags| is comprised of |colorAttachmentCount| values from
// taking up 2 bits. // |UnresolveColorAttachmentType|, each taking up 2 bits.
flags |= type << (2 * attachmentIndex); 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; return flags;
} }
...@@ -348,10 +363,29 @@ void CalculateResolveOffset(const UtilsVk::BlitResolveParameters &params, int32_ ...@@ -348,10 +363,29 @@ void CalculateResolveOffset(const UtilsVk::BlitResolveParameters &params, int32_
offset[1] = params.destOffset[1] - params.srcOffset[1] * srcOffsetFactorY; 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 // Creates a shader that looks like the following, based on the number and types of unresolve
// attachments. // attachments.
// //
// #version 450 core // #version 450 core
// #extension GL_ARB_shader_stencil_export : require
// //
// layout(location = 0) out vec4 colorOut0; // layout(location = 0) out vec4 colorOut0;
// layout(location = 1) out ivec4 colorOut1; // layout(location = 1) out ivec4 colorOut1;
...@@ -359,26 +393,37 @@ void CalculateResolveOffset(const UtilsVk::BlitResolveParameters &params, int32_ ...@@ -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 = 0, set = 0, binding = 0) uniform subpassInput colorIn0;
// layout(input_attachment_index = 1, set = 0, binding = 1) uniform isubpassInput colorIn1; // 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 = 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() // void main()
// { // {
// colorOut0 = subpassLoad(colorIn0); // colorOut0 = subpassLoad(colorIn0);
// colorOut1 = subpassLoad(colorIn1); // colorOut1 = subpassLoad(colorIn1);
// colorOut2 = subpassLoad(colorIn2); // colorOut2 = subpassLoad(colorIn2);
// gl_FragDepth = subpassLoad(depthIn).x;
// gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);
// } // }
angle::Result MakeUnresolveFragShader( angle::Result MakeUnresolveFragShader(
vk::Context *context, vk::Context *context,
uint32_t attachmentCount, uint32_t colorAttachmentCount,
gl::DrawBuffersArray<UnresolveAttachmentType> &attachmentTypes, gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
bool unresolveDepth,
bool unresolveStencil,
SpirvBlob *spirvBlobOut) SpirvBlob *spirvBlobOut)
{ {
std::ostringstream source; std::ostringstream source;
source << "#version 450 core\n"; 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); ASSERT(type != kUnresolveTypeUnused);
const char *prefix = const char *prefix =
...@@ -387,28 +432,58 @@ angle::Result MakeUnresolveFragShader( ...@@ -387,28 +432,58 @@ angle::Result MakeUnresolveFragShader(
source << "layout(location=" << attachmentIndex << ") out " << prefix << "vec4 colorOut" source << "layout(location=" << attachmentIndex << ") out " << prefix << "vec4 colorOut"
<< attachmentIndex << ";\n"; << attachmentIndex << ";\n";
source << "layout(input_attachment_index=" << attachmentIndex source << "layout(input_attachment_index=" << attachmentIndex
<< ", set=0, binding=" << attachmentIndex << ") uniform " << prefix << ", set=" << DescriptorSetIndex::InternalShader << ", binding=" << attachmentIndex
<< "subpassInput colorIn" << attachmentIndex << ";\n"; << ") 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"; 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 source << "colorOut" << attachmentIndex << " = subpassLoad(colorIn" << attachmentIndex
<< ");\n"; << ");\n";
} }
if (unresolveDepth)
{
source << "gl_FragDepth = subpassLoad(depthIn).x;\n";
}
if (unresolveStencil)
{
source << "gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);\n";
}
source << "}\n"; source << "}\n";
return GlslangWrapperVk::CompileShaderOneOff(context, gl::ShaderType::Fragment, source.str(), return GlslangWrapperVk::CompileShaderOneOff(context, gl::ShaderType::Fragment, source.str(),
spirvBlobOut); spirvBlobOut);
} }
angle::Result GetUnresolveFrag(vk::Context *context, angle::Result GetUnresolveFrag(
uint32_t attachmentCount, vk::Context *context,
gl::DrawBuffersArray<UnresolveAttachmentType> &attachmentTypes, uint32_t colorAttachmentCount,
vk::RefCounted<vk::ShaderAndSerial> *shader) gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
bool unresolveDepth,
bool unresolveStencil,
vk::RefCounted<vk::ShaderAndSerial> *shader)
{ {
if (shader->get().valid()) if (shader->get().valid())
{ {
...@@ -416,7 +491,8 @@ angle::Result GetUnresolveFrag(vk::Context *context, ...@@ -416,7 +491,8 @@ angle::Result GetUnresolveFrag(vk::Context *context,
} }
SpirvBlob shaderCode; 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. // Create shader lazily. Access will need to be locked for multi-threading.
return vk::InitShaderAndSerial(context, &shader->get(), shaderCode.data(), return vk::InitShaderAndSerial(context, &shader->get(), shaderCode.data(),
...@@ -813,7 +889,7 @@ angle::Result UtilsVk::ensureUnresolveResourcesInitialized(ContextVk *contextVk, ...@@ -813,7 +889,7 @@ angle::Result UtilsVk::ensureUnresolveResourcesInitialized(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
gl::DrawBuffersArray<VkDescriptorPoolSize> setSizes; vk::FramebufferAttachmentArray<VkDescriptorPoolSize> setSizes;
std::fill(setSizes.begin(), setSizes.end(), std::fill(setSizes.begin(), setSizes.end(),
VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1}); VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1});
...@@ -1577,20 +1653,7 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk, ...@@ -1577,20 +1653,7 @@ angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk,
if (blitStencil) if (blitStencil)
{ {
ASSERT(contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled); SetStencilForShaderExport(contextVk, &pipelineDesc);
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);
} }
VkViewport viewport; VkViewport viewport;
...@@ -2144,41 +2207,92 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk, ...@@ -2144,41 +2207,92 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk,
const UnresolveParameters &params) const UnresolveParameters &params)
{ {
// Get attachment count and pointers to resolve images and views. // Get attachment count and pointers to resolve images and views.
gl::DrawBuffersArray<vk::ImageHelper *> src; gl::DrawBuffersArray<vk::ImageHelper *> colorSrc = {};
gl::DrawBuffersArray<const vk::ImageView *> srcView; 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 // 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 // attachments that need to be unresolved, so the attachment indices of this subpass are not the
// same. See InitializeUnresolveSubpass for details. // same. See InitializeUnresolveSubpass for details.
vk::PackedAttachmentIndex colorIndexVk(0); vk::PackedAttachmentIndex colorIndexVk(0);
for (size_t colorIndexGL : params.unresolveMask) for (size_t colorIndexGL : params.unresolveColorMask)
{ {
RenderTargetVk *colorRenderTarget = framebuffer->getColorDrawRenderTarget(colorIndexGL); RenderTargetVk *colorRenderTarget = framebuffer->getColorDrawRenderTarget(colorIndexGL);
ASSERT(colorRenderTarget->hasResolveAttachment()); ASSERT(colorRenderTarget->hasResolveAttachment());
ASSERT(colorRenderTarget->isImageTransient()); ASSERT(colorRenderTarget->isImageTransient());
src[colorIndexVk.get()] = &colorRenderTarget->getResolveImageForRenderPass(); colorSrc[colorIndexVk.get()] = &colorRenderTarget->getResolveImageForRenderPass();
ANGLE_TRY(colorRenderTarget->getResolveImageView(contextVk, &srcView[colorIndexVk.get()])); ANGLE_TRY(
colorRenderTarget->getResolveImageView(contextVk, &colorSrcView[colorIndexVk.get()]));
++colorIndexVk; ++colorIndexVk;
} }
const uint32_t attachmentCount = colorIndexVk.get(); if (params.unresolveDepth || params.unresolveStencil)
const Function function = static_cast<Function>( {
static_cast<uint32_t>(Function::Unresolve1Attachment) + attachmentCount - 1); RenderTargetVk *depthStencilRenderTarget = framebuffer->getDepthStencilRenderTarget();
ANGLE_TRY(ensureUnresolveResourcesInitialized(contextVk, function, attachmentCount));
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; vk::GraphicsPipelineDesc pipelineDesc;
pipelineDesc.initDefaults(); pipelineDesc.initDefaults();
pipelineDesc.setCullMode(VK_CULL_MODE_NONE); pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
pipelineDesc.setRasterizationSamples(framebuffer->getSamples()); pipelineDesc.setRasterizationSamples(framebuffer->getSamples());
pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc()); pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
// Note: depth test is disabled by default so this should be unnecessary, but works around an pipelineDesc.setDepthTestEnabled(params.unresolveDepth);
// Intel bug on windows. http://anglebug.com/3348 pipelineDesc.setDepthWriteEnabled(params.unresolveDepth);
pipelineDesc.setDepthWriteEnabled(false); pipelineDesc.setDepthFunc(VK_COMPARE_OP_ALWAYS);
if (params.unresolveStencil)
{
SetStencilForShaderExport(contextVk, &pipelineDesc);
}
VkViewport viewport; VkViewport viewport;
gl::Rectangle completeRenderArea = framebuffer->getRotatedCompleteRenderArea(contextVk); gl::Rectangle completeRenderArea = framebuffer->getRotatedCompleteRenderArea(contextVk);
...@@ -2193,31 +2307,48 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk, ...@@ -2193,31 +2307,48 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk,
vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
ANGLE_TRY(allocateDescriptorSet(contextVk, function, &descriptorPoolBinding, &descriptorSet)); ANGLE_TRY(allocateDescriptorSet(contextVk, function, &descriptorPoolBinding, &descriptorSet));
gl::DrawBuffersArray<VkDescriptorImageInfo> inputImageInfo = {}; vk::FramebufferAttachmentArray<VkDescriptorImageInfo> inputImageInfo = {};
for (uint32_t attachmentIndex = 0; attachmentIndex < attachmentCount; ++attachmentIndex) 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; 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 = {}; VkWriteDescriptorSet writeInfo = {};
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.dstSet = descriptorSet; writeInfo.dstSet = descriptorSet;
writeInfo.dstBinding = 0; writeInfo.dstBinding = 0;
writeInfo.descriptorCount = attachmentCount; writeInfo.descriptorCount = totalBindingCount;
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
writeInfo.pImageInfo = inputImageInfo.data(); writeInfo.pImageInfo = inputImageInfo.data();
vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr); vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
gl::DrawBuffersArray<UnresolveAttachmentType> attachmentTypes; gl::DrawBuffersArray<UnresolveColorAttachmentType> colorAttachmentTypes;
uint32_t flags = GetUnresolveFlags(attachmentCount, src, &attachmentTypes); uint32_t flags = GetUnresolveFlags(colorAttachmentCount, colorSrc, params.unresolveDepth,
params.unresolveStencil, &colorAttachmentTypes);
vk::ShaderLibrary &shaderLibrary = contextVk->getShaderLibrary(); vk::ShaderLibrary &shaderLibrary = contextVk->getShaderLibrary();
vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr; vk::RefCounted<vk::ShaderAndSerial> *vertexShader = nullptr;
vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = &mUnresolveFragShaders[flags]; vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = &mUnresolveFragShaders[flags];
ANGLE_TRY(shaderLibrary.getFullScreenQuad_vert(contextVk, 0, &vertexShader)); 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 = vk::CommandBuffer *commandBuffer =
&contextVk->getStartedRenderPassCommands().getCommandBuffer(); &contextVk->getStartedRenderPassCommands().getCommandBuffer();
...@@ -2225,10 +2356,17 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk, ...@@ -2225,10 +2356,17 @@ angle::Result UtilsVk::unresolve(ContextVk *contextVk,
ANGLE_TRY(setupProgram(contextVk, function, fragmentShader, vertexShader, ANGLE_TRY(setupProgram(contextVk, function, fragmentShader, vertexShader,
&mUnresolvePrograms[flags], &pipelineDesc, descriptorSet, nullptr, 0, &mUnresolvePrograms[flags], &pipelineDesc, descriptorSet, nullptr, 0,
commandBuffer)); commandBuffer));
// This draw call is made before ContextVk gets a chance to start the occlusion query. As such, // This draw call is made before ContextVk gets a chance to start the occlusion query. As such,
// occlusion queries are not enabled. // occlusion queries are not enabled.
commandBuffer->draw(3, 0); 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; return angle::Result::Continue;
} }
......
...@@ -166,7 +166,9 @@ class UtilsVk : angle::NonCopyable ...@@ -166,7 +166,9 @@ class UtilsVk : angle::NonCopyable
struct UnresolveParameters struct UnresolveParameters
{ {
gl::DrawBufferMask unresolveMask; gl::DrawBufferMask unresolveColorMask;
bool unresolveDepth;
bool unresolveStencil;
}; };
// Based on the maximum number of levels in GenerateMipmap.comp. // Based on the maximum number of levels in GenerateMipmap.comp.
...@@ -406,30 +408,33 @@ class UtilsVk : angle::NonCopyable ...@@ -406,30 +408,33 @@ class UtilsVk : angle::NonCopyable
ImageClear = 0, ImageClear = 0,
ImageCopy = 1, ImageCopy = 1,
BlitResolve = 2, BlitResolve = 2,
// Note: unresolve is special as it has a different layout per attachment // Note: unresolve is special as it has a different layout per attachment count. Depth and
Unresolve1Attachment = 3, // stencil each require a binding, so are counted separately.
Unresolve2Attachments = 4, Unresolve1Attachment = 3,
Unresolve3Attachments = 5, Unresolve2Attachments = 4,
Unresolve4Attachments = 6, Unresolve3Attachments = 5,
Unresolve5Attachments = 7, Unresolve4Attachments = 6,
Unresolve6Attachments = 8, Unresolve5Attachments = 7,
Unresolve7Attachments = 9, Unresolve6Attachments = 8,
Unresolve8Attachments = 10, Unresolve7Attachments = 9,
Unresolve8Attachments = 10,
Unresolve9Attachments = 11,
Unresolve10Attachments = 12,
// Functions implemented in compute // Functions implemented in compute
ComputeStartIndex = 11, // Special value to separate draw and dispatch functions. ComputeStartIndex = 13, // Special value to separate draw and dispatch functions.
ConvertIndexBuffer = 11, ConvertIndexBuffer = 13,
ConvertVertexBuffer = 12, ConvertVertexBuffer = 14,
BlitResolveStencilNoExport = 13, BlitResolveStencilNoExport = 15,
OverlayCull = 14, OverlayCull = 16,
OverlayDraw = 15, OverlayDraw = 17,
ConvertIndexIndirectBuffer = 16, ConvertIndexIndirectBuffer = 18,
ConvertIndexIndirectLineLoopBuffer = 17, ConvertIndexIndirectLineLoopBuffer = 19,
ConvertIndirectLineLoopBuffer = 18, ConvertIndirectLineLoopBuffer = 20,
GenerateMipmap = 19, GenerateMipmap = 21,
InvalidEnum = 20, InvalidEnum = 22,
EnumCount = 20, EnumCount = 22,
}; };
// Common function that creates the pipeline for the specified function, binds it and prepares // Common function that creates the pipeline for the specified function, binds it and prepares
......
...@@ -178,12 +178,14 @@ void UnpackColorResolveAttachmentDesc(VkAttachmentDescription *desc, ...@@ -178,12 +178,14 @@ void UnpackColorResolveAttachmentDesc(VkAttachmentDescription *desc,
const angle::Format &angleFormat = format.actualImageFormat(); const angle::Format &angleFormat = format.actualImageFormat();
ASSERT(angleFormat.depthBits == 0 && angleFormat.stencilBits == 0); ASSERT(angleFormat.depthBits == 0 && angleFormat.stencilBits == 0);
// Resolve attachments always have a sample count of 1. For simplicity, unlikely cases where // Resolve attachments always have a sample count of 1.
// the resolve framebuffer is immediately invalidated or cleared are ignored. Therefore, loadOp
// and storeOp can be fixed to DONT_CARE and STORE respectively.
// //
// That said, if the corresponding color attachment needs to take its initial value from the // If the corresponding color attachment needs to take its initial value from the resolve
// resolve attachment (i.e. needs to be unresolved), loadOp needs to be set to LOAD. // 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->samples = VK_SAMPLE_COUNT_1_BIT;
desc->loadOp = desc->loadOp =
usedAsInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE; usedAsInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
...@@ -195,7 +197,9 @@ void UnpackColorResolveAttachmentDesc(VkAttachmentDescription *desc, ...@@ -195,7 +197,9 @@ void UnpackColorResolveAttachmentDesc(VkAttachmentDescription *desc,
} }
void UnpackDepthStencilResolveAttachmentDesc(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 // There cannot be simultaneous usages of the depth/stencil resolve image, as depth/stencil
// resolve currently only comes from depth/stencil renderbuffers. // resolve currently only comes from depth/stencil renderbuffers.
...@@ -206,14 +210,15 @@ void UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription *desc, ...@@ -206,14 +210,15 @@ void UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription *desc,
const angle::Format &angleFormat = format.intendedFormat(); const angle::Format &angleFormat = format.intendedFormat();
ASSERT(angleFormat.depthBits != 0 || angleFormat.stencilBits != 0); ASSERT(angleFormat.depthBits != 0 || angleFormat.stencilBits != 0);
// Resolve attachments always have a sample count of 1. Currently, invalidate of // Similarly to color resolve attachments, sample count is 1, loadOp is LOAD or DONT_CARE based
// multisampled-render-to-texture depth/stencil renderbuffer is not implemented. Therefore, // on whether unresolve is required, and storeOp is STORE (if aspect exists).
// loadOp and storeOp can be fixed to DONT_CARE and STORE respectively.
desc->samples = VK_SAMPLE_COUNT_1_BIT; 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 = desc->storeOp =
angleFormat.depthBits > 0 ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE; 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 desc->stencilStoreOp = angleFormat.stencilBits > 0 ? VK_ATTACHMENT_STORE_OP_STORE
: VK_ATTACHMENT_STORE_OP_DONT_CARE; : VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; desc->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
...@@ -258,10 +263,10 @@ void SetPipelineShaderStageInfo(const VkStructureType type, ...@@ -258,10 +263,10 @@ void SetPipelineShaderStageInfo(const VkStructureType type,
shaderStage->pSpecializationInfo = &specializationInfo; shaderStage->pSpecializationInfo = &specializationInfo;
} }
// Defines a subpass that uses the resolve attachments as input attachments to initialize color // Defines a subpass that uses the resolve attachments as input attachments to initialize color and
// attachments that need to be "unresolved" at the start of the render pass. The subpass will // depth/stencil attachments that need to be "unresolved" at the start of the render pass. The
// only contain color attachments that need to be unresolved to simplify the shader that performs // subpass will only contain the attachments that need to be unresolved to simplify the shader that
// the operations. // performs the operations.
void InitializeUnresolveSubpass( void InitializeUnresolveSubpass(
const RenderPassDesc &desc, const RenderPassDesc &desc,
const gl::DrawBuffersVector<VkAttachmentReference> &drawSubpassColorAttachmentRefs, const gl::DrawBuffersVector<VkAttachmentReference> &drawSubpassColorAttachmentRefs,
...@@ -269,7 +274,8 @@ void InitializeUnresolveSubpass( ...@@ -269,7 +274,8 @@ void InitializeUnresolveSubpass(
const VkAttachmentReference &depthStencilAttachmentRef, const VkAttachmentReference &depthStencilAttachmentRef,
const VkAttachmentReference2KHR &depthStencilResolveAttachmentRef, const VkAttachmentReference2KHR &depthStencilResolveAttachmentRef,
gl::DrawBuffersVector<VkAttachmentReference> *unresolveColorAttachmentRefs, gl::DrawBuffersVector<VkAttachmentReference> *unresolveColorAttachmentRefs,
gl::DrawBuffersVector<VkAttachmentReference> *unresolveInputAttachmentRefs, VkAttachmentReference *unresolveDepthStencilAttachmentRef,
FramebufferAttachmentsVector<VkAttachmentReference> *unresolveInputAttachmentRefs,
FramebufferAttachmentsVector<uint32_t> *unresolvePreserveAttachmentRefs, FramebufferAttachmentsVector<uint32_t> *unresolvePreserveAttachmentRefs,
VkSubpassDescription *subpassDesc) VkSubpassDescription *subpassDesc)
{ {
...@@ -300,6 +306,11 @@ void InitializeUnresolveSubpass( ...@@ -300,6 +306,11 @@ void InitializeUnresolveSubpass(
// RP Attachment[7] <- corresponding to resolve attachment of GL Color 4 // RP Attachment[7] <- corresponding to resolve attachment of GL Color 4
// RP Attachment[8] <- corresponding to resolve attachment of GL Color 6 // 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 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 // the mapping from the Vulkan attachment indices (i.e. RP attachment indices) to GL indices
// as indicated by the GL shaders: // as indicated by the GL shaders:
...@@ -322,6 +333,10 @@ void InitializeUnresolveSubpass( ...@@ -322,6 +333,10 @@ void InitializeUnresolveSubpass(
// Subpass[1] Resolve[6] -> RP Attachment[8] // Subpass[1] Resolve[6] -> RP Attachment[8]
// Subpass[1] Resolve[7] -> VK_ATTACHMENT_UNUSED // 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 // The initial subpass that's created here is (remember that in the above example Color 4
// and 6 need to be unresolved): // and 6 need to be unresolved):
// //
...@@ -333,18 +348,26 @@ void InitializeUnresolveSubpass( ...@@ -333,18 +348,26 @@ void InitializeUnresolveSubpass(
// The trick here therefore is to use the color attachment refs already created for the // The trick here therefore is to use the color attachment refs already created for the
// application draw subpass indexed with colorIndexGL. // 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 // 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 // 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 // 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 // that there's no need to preserve attachments whose loadOp is DONT_CARE. For simplicity,
// simplicity, we preserve those as well. The driver would ideally avoid preserving // we preserve those as well. The driver would ideally avoid preserving attachments with
// attachments with loadOp=DONT_CARE. // loadOp=DONT_CARE.
// //
// With the above example: // With the above example:
// //
// Subpass[0] Preserve[0] -> RP Attachment[0] = Subpass[1] Color[0] // 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[1] -> RP Attachment[1] = Subpass[1] Color[3]
// Subpass[0] Preserve[2] -> RP Attachment[4] = Subpass[1] Color[7] // 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 // 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 // Again, the color attachment refs already created for the application draw subpass can be
...@@ -373,27 +396,41 @@ void InitializeUnresolveSubpass( ...@@ -373,27 +396,41 @@ void InitializeUnresolveSubpass(
unresolveInputAttachmentRefs->back().layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; unresolveInputAttachmentRefs->back().layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
} }
// Preserve depth/stencil attachments. if (desc.hasDepthStencilUnresolveAttachment())
if (depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED)
{ {
// There's no need to preserve the depth attachment if loadOp=DONT_CARE, but we do for ASSERT(desc.hasDepthStencilAttachment());
// simplicity. ASSERT(desc.hasDepthStencilResolveAttachment());
unresolvePreserveAttachmentRefs->push_back(depthStencilAttachmentRef.attachment);
} *unresolveDepthStencilAttachmentRef = depthStencilAttachmentRef;
ASSERT(!unresolveColorAttachmentRefs->empty()); VkAttachmentReference unresolveDepthStencilInputAttachmentRef = {};
ASSERT(unresolveColorAttachmentRefs->size() == unresolveInputAttachmentRefs->size()); 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; ASSERT(!unresolveColorAttachmentRefs->empty() ||
subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; unresolveDepthStencilAttachmentRef->attachment != VK_ATTACHMENT_UNUSED);
subpassDesc->inputAttachmentCount = attachmentCount; ASSERT(unresolveColorAttachmentRefs->size() +
subpassDesc->pInputAttachments = unresolveInputAttachmentRefs->data(); (desc.hasDepthStencilUnresolveAttachment() ? 1 : 0) ==
subpassDesc->colorAttachmentCount = attachmentCount; unresolveInputAttachmentRefs->size());
subpassDesc->pColorAttachments = unresolveColorAttachmentRefs->data();
subpassDesc->pResolveAttachments = nullptr; subpassDesc->flags = 0;
subpassDesc->pDepthStencilAttachment = nullptr; 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 = subpassDesc->preserveAttachmentCount =
static_cast<uint32_t>(unresolvePreserveAttachmentRefs->size()); static_cast<uint32_t>(unresolvePreserveAttachmentRefs->size());
subpassDesc->pPreserveAttachments = unresolvePreserveAttachmentRefs->data(); subpassDesc->pPreserveAttachments = unresolvePreserveAttachmentRefs->data();
...@@ -405,9 +442,12 @@ template <typename T> ...@@ -405,9 +442,12 @@ template <typename T>
using SubpassVector = angle::FastVector<T, kSubpassFastVectorSize>; using SubpassVector = angle::FastVector<T, kSubpassFastVectorSize>;
void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription> &subpassDesc, void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription> &subpassDesc,
bool unresolveColor,
bool unresolveDepthStencil,
std::vector<VkSubpassDependency> *subpassDependencies) std::vector<VkSubpassDependency> *subpassDependencies)
{ {
ASSERT(subpassDesc.size() >= 2); ASSERT(subpassDesc.size() >= 2);
ASSERT(unresolveColor || unresolveDepthStencil);
// The unresolve subpass is the first subpass. The application draw subpass is the next one. // The unresolve subpass is the first subpass. The application draw subpass is the next one.
constexpr uint32_t kUnresolveSubpassIndex = 0; constexpr uint32_t kUnresolveSubpassIndex = 0;
...@@ -416,9 +456,9 @@ void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescrip ...@@ -416,9 +456,9 @@ void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescrip
// A subpass dependency is needed between the unresolve and draw subpasses. There are two // A subpass dependency is needed between the unresolve and draw subpasses. There are two
// hazards here: // hazards here:
// //
// - Subpass 0 writes to color attachments, subpass 1 writes to the same color attachments. // - Subpass 0 writes to color/depth/stencil attachments, subpass 1 writes to the same
// This is a WaW hazard (color write -> color write) similar to when two subsequent render // attachments. This is a WaW hazard (color/depth/stencil write -> color/depth/stencil write)
// passes write to the same images. // 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. // - 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 // This is a WaR hazard (fragment shader read -> color write) which only requires an execution
// barrier. // barrier.
...@@ -438,32 +478,78 @@ void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescrip ...@@ -438,32 +478,78 @@ void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescrip
// > can access any sample in the input attachment's pixel even if it only uses // > can access any sample in the input attachment's pixel even if it only uses
// > framebuffer-local dependencies. // > framebuffer-local dependencies.
// //
// The dependency for the first hazard above (color write -> color write) is on same-sample // The dependency for the first hazard above (attachment write -> attachment write) is on
// attachments, so it will not allow the use of input attachments as required by the unresolve // same-sample attachments, so it will not allow the use of input attachments as required by the
// subpass. As a result, even though the second hazard seems to be subsumed by the first (its // unresolve subpass. As a result, even though the second hazard seems to be subsumed by the
// src stage is earlier and its dst stage is the same), a separate dependency is created for it // first (its src stage is earlier and its dst stage is the same), a separate dependency is
// just to obtain a pixel granularity dependency. // 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(); subpassDependencies->emplace_back();
VkSubpassDependency *dependency = &subpassDependencies->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->srcSubpass = kUnresolveSubpassIndex;
dependency->dstSubpass = kDrawSubpassIndex; dependency->dstSubpass = kDrawSubpassIndex;
dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency->srcStageMask = attachmentWriteStages;
dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency->dstStageMask = attachmentReadWriteStages;
dependency->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dependency->srcAccessMask = attachmentWriteFlags;
dependency->dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dependency->dstAccessMask = attachmentReadWriteFlags;
dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
subpassDependencies->emplace_back(); subpassDependencies->emplace_back();
dependency = &subpassDependencies->back(); dependency = &subpassDependencies->back();
// Note again that depth/stencil resolve is considered to be done in the color output stage.
dependency->srcSubpass = kUnresolveSubpassIndex; dependency->srcSubpass = kUnresolveSubpassIndex;
dependency->dstSubpass = kDrawSubpassIndex; dependency->dstSubpass = kDrawSubpassIndex;
dependency->srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 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->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; dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
} }
...@@ -495,7 +581,7 @@ void ToAttachmentReference2(const VkAttachmentReference &ref, ...@@ -495,7 +581,7 @@ void ToAttachmentReference2(const VkAttachmentReference &ref,
} }
void ToSubpassDescription2(const VkSubpassDescription &desc, void ToSubpassDescription2(const VkSubpassDescription &desc,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &inputRefs, const FramebufferAttachmentsVector<VkAttachmentReference2KHR> &inputRefs,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs, const gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs,
const gl::DrawBuffersVector<VkAttachmentReference2KHR> &resolveRefs, const gl::DrawBuffersVector<VkAttachmentReference2KHR> &resolveRefs,
const VkAttachmentReference2KHR &depthStencilRef, const VkAttachmentReference2KHR &depthStencilRef,
...@@ -531,6 +617,8 @@ void ToSubpassDependency2(const VkSubpassDependency &dep, VkSubpassDependency2KH ...@@ -531,6 +617,8 @@ void ToSubpassDependency2(const VkSubpassDependency &dep, VkSubpassDependency2KH
angle::Result CreateRenderPass2(Context *context, angle::Result CreateRenderPass2(Context *context,
const VkRenderPassCreateInfo &createInfo, const VkRenderPassCreateInfo &createInfo,
const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve, const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
bool unresolveDepth,
bool unresolveStencil,
RenderPass *renderPass) RenderPass *renderPass)
{ {
// Convert the attachments to VkAttachmentDescription2. // Convert the attachments to VkAttachmentDescription2.
...@@ -542,8 +630,8 @@ angle::Result CreateRenderPass2(Context *context, ...@@ -542,8 +630,8 @@ angle::Result CreateRenderPass2(Context *context,
// Convert subpass attachments to VkAttachmentReference2 and the subpass description to // Convert subpass attachments to VkAttachmentReference2 and the subpass description to
// VkSubpassDescription2. // VkSubpassDescription2.
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassInputAttachmentRefs( SubpassVector<FramebufferAttachmentsVector<VkAttachmentReference2KHR>>
createInfo.subpassCount); subpassInputAttachmentRefs(createInfo.subpassCount);
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassColorAttachmentRefs( SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassColorAttachmentRefs(
createInfo.subpassCount); createInfo.subpassCount);
SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassResolveAttachmentRefs( SubpassVector<gl::DrawBuffersVector<VkAttachmentReference2KHR>> subpassResolveAttachmentRefs(
...@@ -554,7 +642,7 @@ angle::Result CreateRenderPass2(Context *context, ...@@ -554,7 +642,7 @@ angle::Result CreateRenderPass2(Context *context,
for (uint32_t subpass = 0; subpass < createInfo.subpassCount; ++subpass) for (uint32_t subpass = 0; subpass < createInfo.subpassCount; ++subpass)
{ {
const VkSubpassDescription &desc = createInfo.pSubpasses[subpass]; const VkSubpassDescription &desc = createInfo.pSubpasses[subpass];
gl::DrawBuffersVector<VkAttachmentReference2KHR> &inputRefs = FramebufferAttachmentsVector<VkAttachmentReference2KHR> &inputRefs =
subpassInputAttachmentRefs[subpass]; subpassInputAttachmentRefs[subpass];
gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs = gl::DrawBuffersVector<VkAttachmentReference2KHR> &colorRefs =
subpassColorAttachmentRefs[subpass]; subpassColorAttachmentRefs[subpass];
...@@ -568,10 +656,27 @@ angle::Result CreateRenderPass2(Context *context, ...@@ -568,10 +656,27 @@ angle::Result CreateRenderPass2(Context *context,
// Convert subpass attachment references. // Convert subpass attachment references.
for (uint32_t index = 0; index < desc.inputAttachmentCount; ++index) for (uint32_t index = 0; index < desc.inputAttachmentCount; ++index)
{ {
// TODO(syoussefi): support depth/stencil unresolve. http://anglebug.com/4836 VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ToAttachmentReference2(desc.pInputAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT, if (index >= desc.colorAttachmentCount)
&inputRefs[index]); {
// 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) for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
{ {
ToAttachmentReference2(desc.pColorAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT, ToAttachmentReference2(desc.pColorAttachments[index], VK_IMAGE_ASPECT_COLOR_BIT,
...@@ -751,7 +856,9 @@ angle::Result InitializeRenderPassFromDesc(Context *context, ...@@ -751,7 +856,9 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
depthStencilResolveAttachmentRef.aspectMask = depthStencilResolveAttachmentRef.aspectMask =
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; 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; ++attachmentCount;
} }
...@@ -763,15 +870,17 @@ angle::Result InitializeRenderPassFromDesc(Context *context, ...@@ -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 // which is in turn used in VkRenderPassCreateInfo below. That is why they are declared in the
// same scope. // same scope.
gl::DrawBuffersVector<VkAttachmentReference> unresolveColorAttachmentRefs; gl::DrawBuffersVector<VkAttachmentReference> unresolveColorAttachmentRefs;
gl::DrawBuffersVector<VkAttachmentReference> unresolveInputAttachmentRefs; VkAttachmentReference unresolveDepthStencilAttachmentRef = kUnusedAttachment;
FramebufferAttachmentsVector<VkAttachmentReference> unresolveInputAttachmentRefs;
FramebufferAttachmentsVector<uint32_t> unresolvePreserveAttachmentRefs; FramebufferAttachmentsVector<uint32_t> unresolvePreserveAttachmentRefs;
if (desc.getColorUnresolveAttachmentMask().any()) if (desc.getColorUnresolveAttachmentMask().any() || desc.hasDepthStencilUnresolveAttachment())
{ {
subpassDesc.push_back({}); subpassDesc.push_back({});
InitializeUnresolveSubpass(desc, colorAttachmentRefs, colorResolveAttachmentRefs, InitializeUnresolveSubpass(
depthStencilAttachmentRef, depthStencilResolveAttachmentRef, desc, colorAttachmentRefs, colorResolveAttachmentRefs, depthStencilAttachmentRef,
&unresolveColorAttachmentRefs, &unresolveInputAttachmentRefs, depthStencilResolveAttachmentRef, &unresolveColorAttachmentRefs,
&unresolvePreserveAttachmentRefs, &subpassDesc.back()); &unresolveDepthStencilAttachmentRef, &unresolveInputAttachmentRefs,
&unresolvePreserveAttachmentRefs, &subpassDesc.back());
} }
subpassDesc.push_back({}); subpassDesc.push_back({});
...@@ -810,9 +919,11 @@ angle::Result InitializeRenderPassFromDesc(Context *context, ...@@ -810,9 +919,11 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
} }
std::vector<VkSubpassDependency> subpassDependencies; 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 = {}; VkRenderPassCreateInfo createInfo = {};
...@@ -835,7 +946,9 @@ angle::Result InitializeRenderPassFromDesc(Context *context, ...@@ -835,7 +946,9 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
// vkCreateRenderPass2KHR. // vkCreateRenderPass2KHR.
if (desc.hasDepthStencilResolveAttachment()) if (desc.hasDepthStencilResolveAttachment())
{ {
ANGLE_TRY(CreateRenderPass2(context, createInfo, depthStencilResolve, renderPass)); ANGLE_TRY(CreateRenderPass2(context, createInfo, depthStencilResolve,
desc.hasDepthUnresolveAttachment(),
desc.hasStencilUnresolveAttachment(), renderPass));
} }
else else
{ {
...@@ -1082,6 +1195,29 @@ void RenderPassDesc::packDepthStencilResolveAttachment(bool resolveDepth, bool r ...@@ -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) RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
{ {
memcpy(this, &other, sizeof(RenderPassDesc)); memcpy(this, &other, sizeof(RenderPassDesc));
...@@ -1537,7 +1673,8 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -1537,7 +1673,8 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
// If this graphics pipeline is for the unresolve operation, correct the color attachment count // If this graphics pipeline is for the unresolve operation, correct the color attachment count
// for that subpass. // for that subpass.
if (mRenderPassDesc.getColorUnresolveAttachmentMask().any() && if ((mRenderPassDesc.getColorUnresolveAttachmentMask().any() ||
mRenderPassDesc.hasDepthStencilUnresolveAttachment()) &&
mRasterizationAndMultisampleStateInfo.bits.subpass == 0) mRasterizationAndMultisampleStateInfo.bits.subpass == 0)
{ {
blendState.attachmentCount = blendState.attachmentCount =
...@@ -2431,6 +2568,8 @@ FramebufferDesc &FramebufferDesc::operator=(const FramebufferDesc &other) = defa ...@@ -2431,6 +2568,8 @@ FramebufferDesc &FramebufferDesc::operator=(const FramebufferDesc &other) = defa
void FramebufferDesc::update(uint32_t index, ImageViewSubresourceSerial serial) 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); ASSERT(index < kMaxFramebufferAttachments);
mSerials[index] = serial; mSerials[index] = serial;
if (serial.imageViewSerial.valid()) if (serial.imageViewSerial.valid())
...@@ -2449,9 +2588,9 @@ void FramebufferDesc::updateColorResolve(uint32_t index, ImageViewSubresourceSer ...@@ -2449,9 +2588,9 @@ void FramebufferDesc::updateColorResolve(uint32_t index, ImageViewSubresourceSer
update(kFramebufferDescColorResolveIndexOffset + index, serial); update(kFramebufferDescColorResolveIndexOffset + index, serial);
} }
void FramebufferDesc::updateColorUnresolveMask(gl::DrawBufferMask colorUnresolveMask) void FramebufferDesc::updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask)
{ {
mColorUnresolveAttachmentMask = colorUnresolveMask; mUnresolveAttachmentMask = unresolveMask;
} }
void FramebufferDesc::updateDepthStencil(ImageViewSubresourceSerial serial) void FramebufferDesc::updateDepthStencil(ImageViewSubresourceSerial serial)
...@@ -2467,21 +2606,19 @@ void FramebufferDesc::updateDepthStencilResolve(ImageViewSubresourceSerial seria ...@@ -2467,21 +2606,19 @@ void FramebufferDesc::updateDepthStencilResolve(ImageViewSubresourceSerial seria
size_t FramebufferDesc::hash() const size_t FramebufferDesc::hash() const
{ {
return angle::ComputeGenericHash(&mSerials, sizeof(mSerials[0]) * mMaxIndex) ^ return angle::ComputeGenericHash(&mSerials, sizeof(mSerials[0]) * mMaxIndex) ^
mColorUnresolveAttachmentMask.bits(); mUnresolveAttachmentMask.bits();
} }
void FramebufferDesc::reset() void FramebufferDesc::reset()
{ {
mMaxIndex = 0; mMaxIndex = 0;
mPadding = 0; mUnresolveAttachmentMask.reset();
mColorUnresolveAttachmentMask.reset();
memset(&mSerials, 0, sizeof(mSerials)); memset(&mSerials, 0, sizeof(mSerials));
} }
bool FramebufferDesc::operator==(const FramebufferDesc &other) const bool FramebufferDesc::operator==(const FramebufferDesc &other) const
{ {
if (mMaxIndex != other.mMaxIndex || if (mMaxIndex != other.mMaxIndex || mUnresolveAttachmentMask != other.mUnresolveAttachmentMask)
mColorUnresolveAttachmentMask != other.mColorUnresolveAttachmentMask)
{ {
return false; return false;
} }
......
...@@ -118,6 +118,7 @@ using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttach ...@@ -118,6 +118,7 @@ using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttach
constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1; constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
template <typename T> template <typename T>
using FramebufferNonResolveAttachmentArray = std::array<T, kMaxFramebufferNonResolveAttachments>; using FramebufferNonResolveAttachmentArray = std::array<T, kMaxFramebufferNonResolveAttachments>;
using FramebufferNonResolveAttachmentMask = angle::BitSet16<kMaxFramebufferNonResolveAttachments>;
class alignas(4) RenderPassDesc final class alignas(4) RenderPassDesc final
{ {
...@@ -145,6 +146,10 @@ class alignas(4) RenderPassDesc final ...@@ -145,6 +146,10 @@ class alignas(4) RenderPassDesc final
void removeColorUnresolveAttachment(size_t colorIndexGL); void removeColorUnresolveAttachment(size_t colorIndexGL);
// Indicate that a depth/stencil attachment should have a corresponding resolve attachment. // Indicate that a depth/stencil attachment should have a corresponding resolve attachment.
void packDepthStencilResolveAttachment(bool resolveDepth, bool resolveStencil); 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; size_t hash() const;
...@@ -182,6 +187,18 @@ class alignas(4) RenderPassDesc final ...@@ -182,6 +187,18 @@ class alignas(4) RenderPassDesc final
{ {
return (mAttachmentFormats.back() & kResolveStencilFlag) != 0; 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 // Get the number of attachments in the Vulkan render pass, i.e. after removing disabled
// color attachments. // color attachments.
...@@ -260,8 +277,10 @@ class alignas(4) RenderPassDesc final ...@@ -260,8 +277,10 @@ class alignas(4) RenderPassDesc final
static constexpr uint8_t kDepthStencilFormatStorageMask = 0x7; static constexpr uint8_t kDepthStencilFormatStorageMask = 0x7;
// Flags stored in the upper 5 bits of mAttachmentFormats.back(). // Flags stored in the upper 5 bits of mAttachmentFormats.back().
static constexpr uint8_t kResolveDepthFlag = 0x80; static constexpr uint8_t kResolveDepthFlag = 0x80;
static constexpr uint8_t kResolveStencilFlag = 0x40; 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); bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
...@@ -1061,7 +1080,7 @@ class FramebufferDesc ...@@ -1061,7 +1080,7 @@ class FramebufferDesc
void updateColor(uint32_t index, ImageViewSubresourceSerial serial); void updateColor(uint32_t index, ImageViewSubresourceSerial serial);
void updateColorResolve(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 updateDepthStencil(ImageViewSubresourceSerial serial);
void updateDepthStencilResolve(ImageViewSubresourceSerial serial); void updateDepthStencilResolve(ImageViewSubresourceSerial serial);
size_t hash() const; size_t hash() const;
...@@ -1082,12 +1101,11 @@ class FramebufferDesc ...@@ -1082,12 +1101,11 @@ class FramebufferDesc
// Note: this is an exclusive index. If there is one index it will be "1". // Note: this is an exclusive index. If there is one index it will be "1".
uint16_t mMaxIndex; uint16_t mMaxIndex;
uint8_t mPadding;
// If the render pass contains an initial subpass to unresolve a number of attachments, the // 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 // subpass description is derived from the following mask, specifying which attachments need
// to be unresolved. // to be unresolved. Includes both color and depth/stencil attachments.
gl::DrawBufferMask mColorUnresolveAttachmentMask; FramebufferNonResolveAttachmentMask mUnresolveAttachmentMask;
FramebufferAttachmentArray<ImageViewSubresourceSerial> mSerials; FramebufferAttachmentArray<ImageViewSubresourceSerial> mSerials;
}; };
......
...@@ -384,6 +384,22 @@ constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemory ...@@ -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, ImageLayout::Present,
ImageMemoryBarrierData{ ImageMemoryBarrierData{
"Present", "Present",
...@@ -5743,8 +5759,8 @@ angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk, ...@@ -5743,8 +5759,8 @@ angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk,
} }
// Lazily allocate the image view itself. // Lazily allocate the image view itself.
// Note that these views are specifically made to be used as color attachments, and therefore // Note that these views are specifically made to be used as framebuffer attachments, and
// don't have swizzle. // therefore don't have swizzle.
gl::TextureType viewType = Get2DTextureType(1, image.getSamples()); gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(), return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(),
imageView, levelVk, 1, layer, 1); imageView, levelVk, 1, layer, 1);
......
...@@ -1204,6 +1204,7 @@ enum class ImageLayout ...@@ -1204,6 +1204,7 @@ enum class ImageLayout
ColorAttachment, ColorAttachment,
DepthStencilReadOnly, DepthStencilReadOnly,
DepthStencilAttachment, DepthStencilAttachment,
DepthStencilResolveAttachment,
Present, Present,
InvalidEnum, InvalidEnum,
......
...@@ -98,6 +98,9 @@ class MultisampledRenderToTextureTest : public ANGLETest ...@@ -98,6 +98,9 @@ class MultisampledRenderToTextureTest : public ANGLETest
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(mCopyTextureUniformLocation, 0); glUniform1i(mCopyTextureUniformLocation, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
drawQuad(mCopyTextureProgram, essl1_shaders::PositionAttrib(), 0.5f); drawQuad(mCopyTextureProgram, essl1_shaders::PositionAttrib(), 0.5f);
// Expect that the rendered quad has the same color as the source texture // Expect that the rendered quad has the same color as the source texture
...@@ -121,7 +124,7 @@ class MultisampledRenderToTextureTest : public ANGLETest ...@@ -121,7 +124,7 @@ class MultisampledRenderToTextureTest : public ANGLETest
struct GLType struct GLType
{ {
GLint internalFormat; GLenum internalFormat;
GLenum format; GLenum format;
GLenum type; GLenum type;
}; };
...@@ -156,6 +159,7 @@ class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTes ...@@ -156,6 +159,7 @@ class MultisampledRenderToTextureES3Test : public MultisampledRenderToTextureTes
void colorAttachment1Common(bool useRenderbuffer); void colorAttachment1Common(bool useRenderbuffer);
void colorAttachments0And3Common(bool useRenderbuffer); void colorAttachments0And3Common(bool useRenderbuffer);
void blitFramebufferMixedColorAndDepthCommon(bool useRenderbuffer); void blitFramebufferMixedColorAndDepthCommon(bool useRenderbuffer);
void renderbufferUnresolveColorAndDepthStencilThenTwoColors(bool withDepth, bool withStencil);
}; };
class MultisampledRenderToTextureES31Test : public MultisampledRenderToTextureTest class MultisampledRenderToTextureES31Test : public MultisampledRenderToTextureTest
...@@ -1264,6 +1268,9 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy ...@@ -1264,6 +1268,9 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy
// http://anglebug.com/5083 // http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan()); ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
// http://anglebug.com/5096
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
constexpr GLsizei kSize = 64; constexpr GLsizei kSize = 64;
setupCopyTexProgram(); setupCopyTexProgram();
...@@ -1271,7 +1278,7 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy ...@@ -1271,7 +1278,7 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, 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; GLTexture color;
glBindTexture(GL_TEXTURE_2D, color); glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
...@@ -1342,6 +1349,506 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy ...@@ -1342,6 +1349,506 @@ TEST_P(MultisampledRenderToTextureES3Test, RenderbufferDepthStencilClearDrawCopy
verifyResults(texture, expectedCopyResult, kSize, 0, 0, kSize, kSize); 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 // Test the depth read/write mode change within the renderpass while there is color unresolve
// attachment // attachment
TEST_P(MultisampledRenderToTextureTest, DepthReadWriteToggleWithStartedRenderPass) TEST_P(MultisampledRenderToTextureTest, DepthReadWriteToggleWithStartedRenderPass)
...@@ -2139,10 +2646,6 @@ void MultisampledRenderToTextureES31Test::drawCopyThenBlendAllAttachmentsMixed(b ...@@ -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_texture"));
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture2")); 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; GLint maxDrawBuffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
...@@ -2309,6 +2812,204 @@ TEST_P(MultisampledRenderToTextureES31Test, RenderbufferDrawCopyThenBlendAllAtta ...@@ -2309,6 +2812,204 @@ TEST_P(MultisampledRenderToTextureES31Test, RenderbufferDrawCopyThenBlendAllAtta
drawCopyThenBlendAllAttachmentsMixed(true); 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_ES2_AND_ES3_AND_ES31(MultisampledRenderToTextureTest);
ANGLE_INSTANTIATE_TEST_ES3(MultisampledRenderToTextureES3Test); ANGLE_INSTANTIATE_TEST_ES3(MultisampledRenderToTextureES3Test);
ANGLE_INSTANTIATE_TEST_ES31(MultisampledRenderToTextureES31Test); ANGLE_INSTANTIATE_TEST_ES31(MultisampledRenderToTextureES31Test);
......
...@@ -1638,6 +1638,126 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilTextureShouldNot ...@@ -1638,6 +1638,126 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilTextureShouldNot
EXPECT_PIXEL_COLOR_EQ(kSize / 2 - 1, kSize / 2 - 1, GLColor::red); 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 // Ensures we use read-only depth layout when there is no write
TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout) 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