Fix readback copying of depth-stencil images

This commit is contained in:
baldurk
2016-07-13 16:46:50 +02:00
parent d4e78f785c
commit bf707845d1
3 changed files with 158 additions and 29 deletions
+143 -29
View File
@@ -4566,7 +4566,9 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
bool isDepth =
(layouts.subresourceStates[0].subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
VkImageAspectFlags aspectMask = layouts.subresourceStates[0].subresourceRange.aspectMask;
bool isStencil =
(layouts.subresourceStates[0].subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
VkImageAspectFlags srcAspectMask = layouts.subresourceStates[0].subresourceRange.aspectMask;
VkImage srcImage = Unwrap(GetResourceManager()->GetCurrentHandle<VkImage>(tex));
VkImage tmpImage = VK_NULL_HANDLE;
@@ -4794,6 +4796,7 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
// no longer depth, if it was
isDepth = false;
isStencil = false;
}
else if(wasms && resolve)
{
@@ -4821,11 +4824,12 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
vkr = vt->BindImageMemory(Unwrap(dev), tmpImage, tmpMemory, 0);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
RDCASSERT(!isDepth && !isStencil);
VkImageResolve resolveRegion = {
{VkImageAspectFlags(isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT), mip,
arrayIdx, 1},
{VK_IMAGE_ASPECT_COLOR_BIT, mip, arrayIdx, 1},
{0, 0, 0},
{VkImageAspectFlags(isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT), 0, 0, 1},
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
{0, 0, 0},
imCreateInfo.extent,
};
@@ -4840,7 +4844,7 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
VK_QUEUE_FAMILY_IGNORED,
VK_QUEUE_FAMILY_IGNORED,
srcImage,
{aspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}};
{srcAspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}};
VkImageMemoryBarrier dstimBarrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
@@ -4852,7 +4856,7 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
0,
0, // MULTIDEVICE - need to actually pick the right queue family here maybe?
tmpImage,
{aspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}};
{srcAspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}};
// ensure all previous writes have completed
srcimBarrier.srcAccessMask = VK_ACCESS_ALL_WRITE_BITS;
@@ -4917,7 +4921,7 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
VK_QUEUE_FAMILY_IGNORED,
VK_QUEUE_FAMILY_IGNORED,
srcImage,
{aspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}};
{srcAspectMask, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}};
// if we have no tmpImage, we're copying directly from the real image
if(tmpImage == VK_NULL_HANDLE)
@@ -4935,30 +4939,54 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
}
}
VkImageSubresource sub = {
VkImageAspectFlags(isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT), mip,
arrayIdx};
VkSubresourceLayout sublayout;
VkImageAspectFlags copyAspects = VK_IMAGE_ASPECT_COLOR_BIT;
vt->GetImageSubresourceLayout(Unwrap(dev), srcImage, &sub, &sublayout);
if(isDepth)
copyAspects = VK_IMAGE_ASPECT_DEPTH_BIT;
else if(isStencil)
copyAspects = VK_IMAGE_ASPECT_STENCIL_BIT;
VkBufferImageCopy copyregion = {
0,
0,
0,
{VkImageAspectFlags(isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT), mip,
arrayIdx, 1},
VkBufferImageCopy copyregion[2] = {
{
0, 0, 0,
0,
0,
0,
{copyAspects, mip, arrayIdx, 1},
{
0, 0, 0,
},
imCreateInfo.extent,
},
// second region is only used for combined depth-stencil images
{
0,
0,
0,
{VK_IMAGE_ASPECT_STENCIL_BIT, mip, arrayIdx, 1},
{
0, 0, 0,
},
imCreateInfo.extent,
},
imCreateInfo.extent,
};
// for most combined depth-stencil images this will be large enough for both to be copied
// separately, but for D24S8 we need to add extra space since they won't be copied packed
dataSize = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth,
imCreateInfo.format, mip);
if(imCreateInfo.format == VK_FORMAT_D24_UNORM_S8_UINT)
{
dataSize = AlignUp(dataSize, (VkDeviceSize)4);
dataSize += GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth,
VK_FORMAT_S8_UINT, mip);
}
VkBufferCreateInfo bufInfo = {
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
NULL,
0,
sublayout.size,
dataSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
};
@@ -4971,7 +4999,7 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
vt->GetBufferMemoryRequirements(Unwrap(dev), readbackBuf, &mrq);
VkMemoryAllocateInfo allocInfo = {
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, sublayout.size,
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, dataSize,
m_pDriver->GetReadbackMemoryIndex(mrq.memoryTypeBits),
};
@@ -4982,9 +5010,23 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
vkr = vt->BindBufferMemory(Unwrap(dev), readbackBuf, readbackMem, 0);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
// copy from desired subresource in srcImage to buffer
vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuf,
1, &copyregion);
if(isDepth && isStencil)
{
copyregion[1].bufferOffset =
GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth,
GetDepthOnlyFormat(imCreateInfo.format), mip);
copyregion[1].bufferOffset = AlignUp(copyregion[1].bufferOffset, (VkDeviceSize)4);
vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
readbackBuf, 2, copyregion);
}
else
{
// copy from desired subresource in srcImage to buffer
vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
readbackBuf, 1, copyregion);
}
// if we have no tmpImage, we're copying directly from the real image
if(tmpImage == VK_NULL_HANDLE)
@@ -5007,7 +5049,7 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
VK_QUEUE_FAMILY_IGNORED,
readbackBuf,
0,
sublayout.size,
dataSize,
};
// wait for copy to finish before reading back to host
@@ -5025,10 +5067,82 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
RDCASSERT(pData != NULL);
dataSize = GetByteSize(imInfo.extent.width, imInfo.extent.height, imInfo.extent.depth,
imCreateInfo.format, mip);
byte *ret = new byte[dataSize];
memcpy(ret, pData, dataSize);
if(isDepth && isStencil)
{
size_t pixelCount =
imCreateInfo.extent.width * imCreateInfo.extent.height * imCreateInfo.extent.depth;
if(imCreateInfo.format == VK_FORMAT_D16_UNORM_S8_UINT)
{
uint16_t *dSrc = (uint16_t *)pData;
uint8_t *sSrc = (uint8_t *)(pData + copyregion[1].bufferOffset);
uint16_t *dDst = (uint16_t *)ret;
uint16_t *sDst = dDst + 1; // interleaved, next pixel
for(size_t i = 0; i < pixelCount; i++)
{
*dDst = *dSrc;
*sDst = *sSrc;
// increment source pointers by 1 since they're separate, and dest pointers by 2 since
// they're interleaved
dDst += 2;
sDst += 2;
sSrc++;
dSrc++;
}
}
else if(imCreateInfo.format == VK_FORMAT_D24_UNORM_S8_UINT)
{
// we can copy the depth from D24 as a 32-bit integer, since the remaining bits are garbage
// and we overwrite them with stencil
uint32_t *dSrc = (uint32_t *)pData;
uint8_t *sSrc = (uint8_t *)(pData + copyregion[1].bufferOffset);
uint32_t *dst = (uint32_t *)ret;
for(size_t i = 0; i < pixelCount; i++)
{
// pack the data together again, stencil in top bits
*dst = (*dSrc & 0x00ffffff) | (uint32_t(*sSrc) << 24);
dst++;
sSrc++;
dSrc++;
}
}
else
{
uint32_t *dSrc = (uint32_t *)pData;
uint8_t *sSrc = (uint8_t *)(pData + copyregion[1].bufferOffset);
uint32_t *dDst = (uint32_t *)ret;
uint32_t *sDst = dDst + 1; // interleaved, next pixel
for(size_t i = 0; i < pixelCount; i++)
{
*dDst = *dSrc;
*sDst = *sSrc;
// increment source pointers by 1 since they're separate, and dest pointers by 2 since
// they're interleaved
dDst += 2;
sDst += 2;
sSrc++;
dSrc++;
}
}
// need to manually copy to interleave pixels
}
else
{
memcpy(ret, pData, dataSize);
}
vt->UnmapMemory(Unwrap(dev), readbackMem);
+13
View File
@@ -222,6 +222,19 @@ bool IsStencilFormat(VkFormat f)
return false;
}
VkFormat GetDepthOnlyFormat(VkFormat f)
{
switch(f)
{
case VK_FORMAT_D16_UNORM_S8_UINT: return VK_FORMAT_D16_UNORM;
case VK_FORMAT_D24_UNORM_S8_UINT: return VK_FORMAT_X8_D24_UNORM_PACK32;
case VK_FORMAT_D32_SFLOAT_S8_UINT: return VK_FORMAT_D32_SFLOAT;
default: break;
}
return f;
}
bool IsDepthOnlyFormat(VkFormat f)
{
switch(f)
+2
View File
@@ -1069,4 +1069,6 @@ bool IsSRGBFormat(VkFormat f);
bool IsUIntFormat(VkFormat f);
bool IsSIntFormat(VkFormat f);
VkFormat GetDepthOnlyFormat(VkFormat f);
uint32_t GetByteSize(uint32_t Width, uint32_t Height, uint32_t Depth, VkFormat Format, uint32_t mip);