Vulkan: Optimize image copies in Apply_InitialState

This uses the new image tracking to avoid unnecessary copying of image
data when applying the initial state.

This change only affects image resets when all of the following apply:
  - The image initial contents tag is `BufferCopy` (not
    `ClearColorImage` or `ClearDepthStencilImage`),
  - The image is single sample,
  - The image is non-sparse,
  - The image has `ImgRefs` data,
  - The image has been completely initialized at least once, and
  - VulkanResourceManager::OptimizeInitialState() is true (currently
    disabled by default).

When all of these conditions are met, data will only be copied for those
image subresources which require reset according to the ImgRefs data.

Change-Id: I449eabfe969229fa64e233760aaadb489776ee23
This commit is contained in:
Benson Joeris
2019-05-30 15:10:56 -04:00
committed by Baldur Karlsson
parent 22203fbb02
commit d6761de26d
4 changed files with 95 additions and 21 deletions
+10 -8
View File
@@ -38,49 +38,51 @@ TEST_CASE("Test ImgRefs type", "[imgrefs]")
SECTION("unsplit")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 0);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) == 0);
};
SECTION("split aspect")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
imgRefs.Split(true, false, false);
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 1);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) == 1);
};
SECTION("split levels")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
imgRefs.Split(false, true, false);
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 2);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) == 2);
};
SECTION("split layers")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
imgRefs.Split(false, false, true);
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 5);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) == 5);
};
SECTION("split aspect and levels")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
imgRefs.Split(true, true, false);
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 11 + 2);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) == 11 + 2);
};
SECTION("split aspect and layers")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
imgRefs.Split(true, false, true);
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 17 + 5);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) == 17 + 5);
};
SECTION("split levels and layers")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
imgRefs.Split(false, true, true);
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 2 * 17 + 5);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) ==
2 * 17 + 5);
};
SECTION("split aspect and levels and layers")
{
ImgRefs imgRefs(ImageInfo(VK_FORMAT_D16_UNORM_S8_UINT, {100, 100, 1}, 11, 17, 1));
imgRefs.Split(true, true, true);
CHECK(imgRefs.SubresourceIndex(VK_IMAGE_ASPECT_STENCIL_BIT, 2, 5) == 11 * 17 + 2 * 17 + 5);
CHECK(imgRefs.SubresourceIndex(imgRefs.AspectIndex(VK_IMAGE_ASPECT_STENCIL_BIT), 2, 5) ==
11 * 17 + 2 * 17 + 5);
};
SECTION("update unsplit")
{
+60 -6
View File
@@ -1375,6 +1375,19 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT};
ResourceId orig = GetResourceManager()->GetOriginalID(id);
ImgRefs *imgRefs = NULL;
bool initialized = false;
if(GetResourceManager()->OptimizeInitialState())
{
imgRefs = GetResourceManager()->FindImgRefs(orig);
if(imgRefs)
{
initialized = imgRefs->initializedLiveRes == live;
imgRefs->initializedLiveRes = live;
}
}
if(initial.tag == VkInitialContents::Sparse)
{
Apply_SparseInitialState((WrappedVkImage *)live, initial);
@@ -1882,6 +1895,24 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
SubmitAndFlushExtQueue(dstimBarrier.srcQueueFamilyIndex);
}
std::vector<VkBufferImageCopy> copyRegions;
std::vector<VkImageSubresourceRange> clearRegions;
#define INIT_REGION() \
if(!initialized) \
{ \
copyRegions.push_back(region); \
} \
else \
{ \
InitReqType initReq = imgRefs->SubresourceInitReq( \
imgRefs->AspectIndex((VkImageAspectFlagBits)region.imageSubresource.aspectMask), m, a); \
if(initReq == eInitReq_Reset) \
copyRegions.push_back(region); \
else if(initReq == eInitReq_Clear) \
clearRegions.push_back(ImageRange(region.imageSubresource)); \
}
// copy each slice/mip individually
for(int a = 0; a < m_CreationInfo.m_Image[id].arrayLayers; a++)
{
@@ -1919,8 +1950,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
bufOffset += GetPlaneByteSize(extent.width, extent.height, extent.depth, fmt, 0, i);
ObjDisp(cmd)->CmdCopyBufferToImage(Unwrap(cmd), Unwrap(buf), ToHandle<VkImage>(live),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
INIT_REGION();
}
}
else
@@ -1934,8 +1964,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
// pass 0 for mip since we've already pre-downscaled extent
bufOffset += GetByteSize(extent.width, extent.height, extent.depth, sizeFormat, 0);
ObjDisp(cmd)->CmdCopyBufferToImage(Unwrap(cmd), Unwrap(buf), ToHandle<VkImage>(live),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
INIT_REGION();
if(sizeFormat != fmt)
{
@@ -1947,8 +1976,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
bufOffset += GetByteSize(extent.width, extent.height, extent.depth, VK_FORMAT_S8_UINT, 0);
ObjDisp(cmd)->CmdCopyBufferToImage(Unwrap(cmd), Unwrap(buf), ToHandle<VkImage>(live),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
INIT_REGION();
}
}
@@ -1959,6 +1987,32 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
}
}
#undef INIT_REGION
if(copyRegions.size() > 0)
ObjDisp(cmd)->CmdCopyBufferToImage(Unwrap(cmd), Unwrap(buf), ToHandle<VkImage>(live),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
(uint32_t)copyRegions.size(), copyRegions.data());
if(clearRegions.size() > 0)
{
if(IsDepthOrStencilFormat(fmt))
{
VkClearDepthStencilValue val = {0, 0};
ObjDisp(cmd)->CmdClearDepthStencilImage(Unwrap(cmd), ToHandle<VkImage>(live),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &val,
(uint32_t)clearRegions.size(), clearRegions.data());
}
else
{
VkClearColorValue val;
memset(&val, 0, sizeof(val));
ObjDisp(cmd)->CmdClearColorImage(Unwrap(cmd), ToHandle<VkImage>(live),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &val,
(uint32_t)clearRegions.size(), clearRegions.data());
}
}
// update the live image layout back
dstimBarrier.oldLayout = dstimBarrier.newLayout;
+2 -2
View File
@@ -2930,7 +2930,7 @@ int ImgRefs::GetAspectCount() const
return aspectCount;
}
int ImgRefs::SubresourceIndex(VkImageAspectFlagBits aspect, int level, int layer) const
int ImgRefs::AspectIndex(VkImageAspectFlagBits aspect) const
{
int aspectIndex = 0;
if(areAspectsSplit)
@@ -2943,7 +2943,7 @@ int ImgRefs::SubresourceIndex(VkImageAspectFlagBits aspect, int level, int layer
++aspectIndex;
}
}
return SubresourceIndex(aspectIndex, level, layer);
return aspectIndex;
}
int ImgRefs::SubresourceIndex(int aspectIndex, int level, int layer) const
+23 -5
View File
@@ -1078,6 +1078,20 @@ struct ImageRange
layerCount(range.layerCount)
{
}
ImageRange(const VkBufferImageCopy &range)
: aspectMask(range.imageSubresource.aspectMask),
baseMipLevel(range.imageSubresource.mipLevel),
levelCount(1),
baseArrayLayer(range.imageSubresource.baseArrayLayer),
layerCount(range.imageSubresource.layerCount),
offset(range.imageOffset),
extent(range.imageExtent)
{
}
inline operator VkImageSubresourceRange() const
{
return {aspectMask, baseMipLevel, levelCount, baseArrayLayer, layerCount};
}
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM;
uint32_t baseMipLevel = 0;
uint32_t levelCount = VK_REMAINING_MIP_LEVELS;
@@ -1115,16 +1129,20 @@ struct ImgRefs
// Depth slices of 3D views are treated as array layers
this->imageInfo.layerCount = imageInfo.extent.depth;
}
int SubresourceIndex(VkImageAspectFlagBits aspect, int level, int layer) const;
int AspectIndex(VkImageAspectFlagBits aspect) const;
int SubresourceIndex(int aspectIndex, int level, int layer) const;
inline FrameRefType SubresourceRef(VkImageAspectFlagBits aspect, int level, int layer) const
{
return rangeRefs[SubresourceIndex(aspect, level, layer)];
}
inline FrameRefType SubresourceRef(int aspectIndex, int level, int layer) const
{
return rangeRefs[SubresourceIndex(aspectIndex, level, layer)];
}
inline InitReqType SubresourceInitReq(int aspectIndex, int level, int layer) const
{
return InitReq(SubresourceRef(aspectIndex, level, layer));
}
inline InitReqType SubresourceInitReq(int aspectIndex, int level, int layer, bool initialized) const
{
return InitReq(SubresourceRef(aspectIndex, level, layer));
}
void Split(bool splitAspects, bool splitLevels, bool splitLayers);
template <typename Compose>
FrameRefType Update(ImageRange range, FrameRefType refType, Compose comp);