Implement VK_KHR_depth_stencil_resolve

This extension allows users to pass depthstencil attachments that vkCmdResolveImage will resolve to in addition to its other resolve operations. Only the mandatory resolve modes "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT" and "VK_RESOLVE_MODE_NONE" are supported. It's trivial to support both independent resolve modes since we must resolve depth and stencil attachments separately due to how depth and stencil attachments are stored internally. Change-Id: I0f8ff7cddca5f5acbac1d991b11f0a4447956784 Bug: b/167558951 Test: dEQP-VK.renderpass2.depth_stencil_resolve.* Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/48808Tested-by: 's avatarSean Risser <srisser@google.com> Commit-Queue: Sean Risser <srisser@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com>
parent 8642467d
......@@ -22,6 +22,7 @@
#include "System/Memory.hpp"
#include "Vulkan/VkBuffer.hpp"
#include "Vulkan/VkImage.hpp"
#include "Vulkan/VkImageView.hpp"
#include <utility>
......@@ -1880,6 +1881,88 @@ void Blitter::blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkF
dst->contentsChanged(dstSubresRange);
}
static void resolveDepth(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc)
{
if(dsrDesc.depthResolveMode == VK_RESOLVE_MODE_NONE)
{
return;
}
vk::Format format = src->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT);
VkExtent2D extent = src->getMipLevelExtent(0, VK_IMAGE_ASPECT_DEPTH_BIT);
int width = extent.width;
int height = extent.height;
int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
// To support other resolve modes, get the slice bytes and get a pointer to each sample plane.
// Then modify the loop below to include logic for handling each new mode.
uint8_t *source = (uint8_t *)src->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
uint8_t *dest = (uint8_t *)dst->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
size_t formatSize = format.bytes();
// TODO(b/167558951) support other resolve modes.
ASSERT(dsrDesc.depthResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT);
for(int y = 0; y < height; y++)
{
memcpy(dest, source, formatSize * width);
source += pitch;
dest += pitch;
}
dst->contentsChanged();
}
static void resolveStencil(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc)
{
if(dsrDesc.stencilResolveMode == VK_RESOLVE_MODE_NONE)
{
return;
}
VkExtent2D extent = src->getMipLevelExtent(0, VK_IMAGE_ASPECT_STENCIL_BIT);
int width = extent.width;
int height = extent.height;
int pitch = src->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
// To support other resolve modes, use src->slicePitchBytes() and get a pointer to each sample's slice.
// Then modify the loop below to include logic for handling each new mode.
uint8_t *source = reinterpret_cast<uint8_t *>(src->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0));
uint8_t *dest = reinterpret_cast<uint8_t *>(dst->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0));
// TODO(b/167558951) support other resolve modes.
ASSERT(dsrDesc.stencilResolveMode == VK_RESOLVE_MODE_SAMPLE_ZERO_BIT);
for(int y = 0; y < height; y++)
{
// Stencil is always 8 bits, so the width of the resource we're resolving is
// the number of bytes in each row we need to copy during for SAMPLE_ZERO
memcpy(dest, source, width);
source += pitch;
dest += pitch;
}
dst->contentsChanged();
}
void Blitter::resolveDepthStencil(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc)
{
VkImageSubresourceRange srcRange = src->getSubresourceRange();
VkImageSubresourceRange dstRange = src->getSubresourceRange();
ASSERT(src->getFormat() == dst->getFormat());
ASSERT(srcRange.layerCount == 1 && dstRange.layerCount == 1);
ASSERT(srcRange.aspectMask == dstRange.aspectMask);
if(srcRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
{
resolveDepth(src, dst, dsrDesc);
}
if(srcRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
{
resolveStencil(src, dst, dsrDesc);
}
}
void Blitter::resolve(const vk::Image *src, vk::Image *dst, VkImageResolve region)
{
// "The aspectMask member of srcSubresource and dstSubresource must only contain VK_IMAGE_ASPECT_COLOR_BIT"
......
......@@ -28,6 +28,7 @@
namespace vk {
class Image;
class ImageView;
class Buffer;
} // namespace vk
......@@ -145,6 +146,7 @@ public:
void blit(const vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter);
void resolve(const vk::Image *src, vk::Image *dst, VkImageResolve region);
void resolveDepthStencil(const vk::ImageView *src, vk::ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsrDesc);
void copy(const vk::Image *src, uint8_t *dst, unsigned int dstPitch);
void updateBorders(vk::Image *image, const VkImageSubresource &subresource);
......
......@@ -183,6 +183,17 @@ void Framebuffer::resolve(const RenderPass *renderPass, uint32_t subpassIndex)
}
}
}
if(renderPass->hasDepthStencilResolve() && subpass.pDepthStencilAttachment != nullptr)
{
VkSubpassDescriptionDepthStencilResolve dsResolve = renderPass->getSubpassDepthStencilResolve(subpassIndex);
uint32_t depthStencilAttachment = subpass.pDepthStencilAttachment->attachment;
if(depthStencilAttachment != VK_ATTACHMENT_UNUSED)
{
ImageView *imageView = attachments[depthStencilAttachment];
imageView->resolveDepthStencil(attachments[dsResolve.pDepthStencilResolveAttachment->attachment], dsResolve);
}
}
}
size_t Framebuffer::ComputeRequiredAllocationSize(const VkFramebufferCreateInfo *pCreateInfo)
......
......@@ -17,6 +17,7 @@
#include "VkBuffer.hpp"
#include "VkDevice.hpp"
#include "VkDeviceMemory.hpp"
#include "VkImageView.hpp"
#include "VkStringify.hpp"
#include "Device/ASTC_Decoder.hpp"
#include "Device/BC_Decoder.hpp"
......@@ -992,6 +993,11 @@ void Image::resolveTo(Image *dstImage, const VkImageResolve &region) const
device->getBlitter()->resolve(this, dstImage, region);
}
void Image::resolveDepthStencilTo(const ImageView *src, ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &dsResolve) const
{
device->getBlitter()->resolveDepthStencil(src, dst, dsResolve);
}
VkFormat Image::getClearFormat() const
{
// Set the proper format for the clear value, as described here:
......
......@@ -31,6 +31,7 @@ namespace vk {
class Buffer;
class Device;
class DeviceMemory;
class ImageView;
#ifdef __ANDROID__
struct BackingMemory
......@@ -65,6 +66,7 @@ public:
void blitTo(Image *dstImage, const VkImageBlit &region, VkFilter filter) const;
void copyTo(uint8_t *dst, unsigned int dstPitch) const;
void resolveTo(Image *dstImage, const VkImageResolve &region) const;
void resolveDepthStencilTo(const ImageView *src, ImageView *dst, const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve) const;
void clear(const VkClearValue &clearValue, const vk::Format &viewFormat, const VkRect2D &renderArea, const VkImageSubresourceRange &subresourceRange);
void clear(const VkClearColorValue &color, const VkImageSubresourceRange &subresourceRange);
void clear(const VkClearDepthStencilValue &color, const VkImageSubresourceRange &subresourceRange);
......
......@@ -262,6 +262,17 @@ void ImageView::resolveWithLayerMask(ImageView *resolveAttachment, uint32_t laye
}
}
void ImageView::resolveDepthStencil(ImageView *resolveAttachment, const VkSubpassDescriptionDepthStencilResolve &dsResolve)
{
ASSERT(subresourceRange.levelCount == 1 && resolveAttachment->subresourceRange.levelCount == 1);
if((subresourceRange.layerCount != 1) || (resolveAttachment->subresourceRange.layerCount != 1))
{
UNIMPLEMENTED("b/148242443: layerCount != 1"); // FIXME(b/148242443)
}
image->resolveDepthStencilTo(this, resolveAttachment, dsResolve);
}
const Image *ImageView::getImage(Usage usage) const
{
switch(usage)
......@@ -310,6 +321,13 @@ VkExtent2D ImageView::getMipLevelExtent(uint32_t mipLevel) const
return { extent.width, extent.height };
}
VkExtent2D ImageView::getMipLevelExtent(uint32_t mipLevel, VkImageAspectFlagBits aspect) const
{
VkExtent3D extent = image->getMipLevelExtent(aspect, subresourceRange.baseMipLevel + mipLevel);
return { extent.width, extent.height };
}
int ImageView::getDepthOrLayerCount(uint32_t mipLevel) const
{
VkExtent3D extent = image->getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask),
......
......@@ -79,6 +79,7 @@ public:
void resolve(ImageView *resolveAttachment);
void resolve(ImageView *resolveAttachment, int layer);
void resolveWithLayerMask(ImageView *resolveAttachment, uint32_t layerMask);
void resolveDepthStencil(ImageView *resolveAttachment, const VkSubpassDescriptionDepthStencilResolve &dsResolve);
VkImageViewType getType() const { return viewType; }
Format getFormat(Usage usage = RAW) const;
......@@ -88,6 +89,7 @@ public:
int getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage = RAW) const;
int layerPitchBytes(VkImageAspectFlagBits aspect, Usage usage = RAW) const;
VkExtent2D getMipLevelExtent(uint32_t mipLevel) const;
VkExtent2D getMipLevelExtent(uint32_t mipLevel, VkImageAspectFlagBits aspect) const;
int getDepthOrLayerCount(uint32_t mipLevel) const;
int getSampleCount() const
......
......@@ -838,8 +838,8 @@ static void getDepthStencilResolveProperties(T *properties)
{
properties->supportedDepthResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT | VK_RESOLVE_MODE_NONE;
properties->supportedStencilResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT | VK_RESOLVE_MODE_NONE;
properties->independentResolveNone = VK_FALSE;
properties->independentResolve = VK_FALSE;
properties->independentResolveNone = VK_TRUE;
properties->independentResolve = VK_TRUE;
}
void PhysicalDevice::getProperties(VkPhysicalDeviceDepthStencilResolveProperties *properties) const
......
......@@ -129,7 +129,7 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo *pCreateInfo, void *mem)
, subpassCount(pCreateInfo->subpassCount)
, dependencyCount(pCreateInfo->dependencyCount)
{
init(pCreateInfo, mem);
init(pCreateInfo, &mem);
}
RenderPass::RenderPass(const VkRenderPassCreateInfo2KHR *pCreateInfo, void *mem)
......@@ -137,18 +137,76 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo2KHR *pCreateInfo, void *mem)
, subpassCount(pCreateInfo->subpassCount)
, dependencyCount(pCreateInfo->dependencyCount)
{
init(pCreateInfo, mem);
init(pCreateInfo, &mem);
// Note: the init function above ignores:
// - pCorrelatedViewMasks: This provides a potential performance optimization
// - VkAttachmentReference2::aspectMask : This specifies which aspects may be used
// - VkSubpassDependency2::viewOffset : This is the same as VkRenderPassMultiviewCreateInfo::pViewOffsets, which is currently ignored
// - Any pNext pointer in VkRenderPassCreateInfo2KHR's internal structures
char *hostMemory = reinterpret_cast<char *>(mem);
// Handle the extensions in each subpass
for(uint32_t i = 0; i < subpassCount; i++)
{
auto const &subpass = pCreateInfo->pSubpasses[i];
const VkBaseInStructure *extension = reinterpret_cast<const VkBaseInStructure *>(subpass.pNext);
while(extension)
{
switch(extension->sType)
{
case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE:
{
const auto *ext = reinterpret_cast<const VkSubpassDescriptionDepthStencilResolve *>(extension);
// If any subpass includes depthStencilResolve, allocate a DSR struct for each subpass
// This allows us to index into subpassDepthStencilResolves using the subpass index.
if(ext->pDepthStencilResolveAttachment != nullptr && ext->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED)
{
if(subpassDepthStencilResolves == nullptr)
{
subpassDepthStencilResolves = reinterpret_cast<VkSubpassDescriptionDepthStencilResolve *>(hostMemory);
hostMemory += subpassCount * sizeof(VkSubpassDescriptionDepthStencilResolve);
for(uint32_t subpass = 0; subpass < subpassCount; subpass++)
{
subpassDepthStencilResolves[subpass].sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
subpassDepthStencilResolves[subpass].pNext = nullptr;
subpassDepthStencilResolves[subpass].depthResolveMode = VK_RESOLVE_MODE_NONE;
subpassDepthStencilResolves[subpass].stencilResolveMode = VK_RESOLVE_MODE_NONE;
subpassDepthStencilResolves[subpass].pDepthStencilResolveAttachment = nullptr;
}
}
VkAttachmentReference2 *reference = reinterpret_cast<VkAttachmentReference2 *>(hostMemory);
hostMemory += sizeof(VkAttachmentReference2);
subpassDepthStencilResolves[i].depthResolveMode = ext->depthResolveMode;
subpassDepthStencilResolves[i].stencilResolveMode = ext->stencilResolveMode;
reference->pNext = nullptr;
reference->sType = ext->pDepthStencilResolveAttachment->sType;
reference->attachment = ext->pDepthStencilResolveAttachment->attachment;
reference->layout = ext->pDepthStencilResolveAttachment->layout;
reference->aspectMask = ext->pDepthStencilResolveAttachment->aspectMask;
subpassDepthStencilResolves[i].pDepthStencilResolveAttachment = reinterpret_cast<const VkAttachmentReference2 *>(reference);
MarkFirstUse(reference->attachment, i);
}
}
break;
default:
LOG_TRAP("VkRenderPassCreateInfo2KHR->subpass[%d]->pNext sType: %s",
i, vk::Stringify(extension->sType).c_str());
break;
}
extension = extension->pNext;
}
}
}
template<class T>
void RenderPass::init(const T *pCreateInfo, void *mem)
void RenderPass::init(const T *pCreateInfo, void **mem)
{
char *hostMemory = reinterpret_cast<char *>(mem);
char *hostMemory = reinterpret_cast<char *>(*mem);
// subpassCount must be greater than 0
ASSERT(pCreateInfo->subpassCount > 0);
......@@ -300,7 +358,9 @@ void RenderPass::init(const T *pCreateInfo, void *mem)
{
dependencies = reinterpret_cast<VkSubpassDependency *>(hostMemory);
CopySubpassDependencies(dependencies, pCreateInfo->pDependencies, pCreateInfo->dependencyCount);
hostMemory += dependencyCount * sizeof(VkSubpassDependency);
}
*mem = hostMemory;
}
void RenderPass::destroy(const VkAllocationCallbacks *pAllocator)
......@@ -315,7 +375,46 @@ size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo *p
size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo2KHR *pCreateInfo)
{
return ComputeRequiredAllocationSizeT(pCreateInfo);
size_t requiredMemory = ComputeRequiredAllocationSizeT(pCreateInfo);
// Calculate the memory required to handle depth stencil resolves
bool usesDSR = false;
for(uint32_t i = 0; i < pCreateInfo->subpassCount; i++)
{
auto const &subpass = pCreateInfo->pSubpasses[i];
const VkBaseInStructure *extension = reinterpret_cast<const VkBaseInStructure *>(subpass.pNext);
while(extension)
{
switch(extension->sType)
{
case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE:
{
const auto *ext = reinterpret_cast<const VkSubpassDescriptionDepthStencilResolve *>(extension);
if(ext->pDepthStencilResolveAttachment != nullptr && ext->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED)
{
if(!usesDSR)
{
// If any subpass uses DSR, then allocate a VkSubpassDescriptionDepthStencilResolve
// for all subpasses. This allows us to index into our DSR structs using the subpass index.
requiredMemory += sizeof(VkSubpassDescriptionDepthStencilResolve) * pCreateInfo->subpassCount;
usesDSR = true;
}
// For each subpass that actually uses DSR, allocate a VkAttachmentReference2.
requiredMemory += sizeof(VkAttachmentReference2);
}
}
break;
default:
LOG_TRAP("VkRenderPassCreateInfo2KHR->subpass[%d]->pNext sType: %s",
i, vk::Stringify(extension->sType).c_str());
break;
}
extension = extension->pNext;
}
}
return requiredMemory;
}
void RenderPass::getRenderAreaGranularity(VkExtent2D *pGranularity) const
......
......@@ -53,6 +53,16 @@ public:
return subpasses[subpassIndex];
}
bool hasDepthStencilResolve() const
{
return subpassDepthStencilResolves != nullptr;
}
VkSubpassDescriptionDepthStencilResolve getSubpassDepthStencilResolve(uint32_t subpassIndex) const
{
return subpassDepthStencilResolves[subpassIndex];
}
uint32_t getDependencyCount() const
{
return dependencyCount;
......@@ -88,6 +98,7 @@ private:
VkAttachmentDescription *attachments = nullptr;
uint32_t subpassCount = 0;
VkSubpassDescription *subpasses = nullptr;
VkSubpassDescriptionDepthStencilResolve *subpassDepthStencilResolves = nullptr;
uint32_t dependencyCount = 0;
VkSubpassDependency *dependencies = nullptr;
int *attachmentFirstUse = nullptr;
......@@ -96,7 +107,7 @@ private:
void MarkFirstUse(int attachment, int subpass);
template<class T>
void init(const T *pCreateInfo, void *mem);
void init(const T *pCreateInfo, void **mem);
};
static inline RenderPass *Cast(VkRenderPass object)
......@@ -106,4 +117,4 @@ static inline RenderPass *Cast(VkRenderPass object)
} // namespace vk
#endif // VK_RENDER_PASS_HPP_
\ No newline at end of file
#endif // VK_RENDER_PASS_HPP_
......@@ -408,6 +408,7 @@ static const VkExtensionProperties deviceExtensionProperties[] = {
{ VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, VK_EXT_HOST_QUERY_RESET_SPEC_VERSION },
{ VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION },
{ VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME, VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION },
{ VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION },
{ VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION },
{ VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME, VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION },
{ VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION },
......
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