From d6761de26d945ebcc2c1d2abaf2f8530f81c88d7 Mon Sep 17 00:00:00 2001 From: Benson Joeris Date: Thu, 30 May 2019 15:10:56 -0400 Subject: [PATCH] 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 --- renderdoc/driver/vulkan/imgrefs_tests.cpp | 18 ++++--- renderdoc/driver/vulkan/vk_initstate.cpp | 66 ++++++++++++++++++++--- renderdoc/driver/vulkan/vk_resources.cpp | 4 +- renderdoc/driver/vulkan/vk_resources.h | 28 ++++++++-- 4 files changed, 95 insertions(+), 21 deletions(-) diff --git a/renderdoc/driver/vulkan/imgrefs_tests.cpp b/renderdoc/driver/vulkan/imgrefs_tests.cpp index b081506d4..54165f1cb 100644 --- a/renderdoc/driver/vulkan/imgrefs_tests.cpp +++ b/renderdoc/driver/vulkan/imgrefs_tests.cpp @@ -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") { diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index cbc55156d..7f43a1760 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -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 copyRegions; + std::vector 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(live), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + 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(live), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + 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(live), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + 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(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(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(live), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &val, + (uint32_t)clearRegions.size(), clearRegions.data()); + } + } + // update the live image layout back dstimBarrier.oldLayout = dstimBarrier.newLayout; diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 74e1fc260..d765cc5d3 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -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 diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 1adcfcc34..c1692829c 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -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 FrameRefType Update(ImageRange range, FrameRefType refType, Compose comp);