From 5120622dac219e30ca371fcfc5909e128a70f270 Mon Sep 17 00:00:00 2001 From: Benson Joeris Date: Mon, 8 Jul 2019 14:32:47 -0400 Subject: [PATCH] Added InitPolicy This allows finer control of the initialization/reset behaviour of resources based on their ref type. Currently, these policies only apply to the initialization/reseting of VkDeviceMemory and VkImage resources. Change-Id: Ib647cbaf99b650e8da40d07944400ace7dde504d --- renderdoc/core/resource_manager.h | 104 +++++++++++++++++------ renderdoc/driver/vulkan/vk_core.h | 2 +- renderdoc/driver/vulkan/vk_initstate.cpp | 58 +++++++------ renderdoc/driver/vulkan/vk_manager.h | 2 + renderdoc/driver/vulkan/vk_resources.cpp | 5 +- renderdoc/driver/vulkan/vk_resources.h | 11 +-- 6 files changed, 121 insertions(+), 61 deletions(-) diff --git a/renderdoc/core/resource_manager.h b/renderdoc/core/resource_manager.h index 87b540b82..f0ed88862 100644 --- a/renderdoc/core/resource_manager.h +++ b/renderdoc/core/resource_manager.h @@ -139,41 +139,97 @@ bool IsDirtyFrameRef(FrameRefType refType); // init/reset requirements. enum InitReqType { - // Initial contents of the resource are not used, and also not modified. - // No initialization/reset is required for correct replay, but may be helpful - // to avoid user confusion when analyzing the resource. - // Corresponds to `None` ref type. + // No initialization required. eInitReq_None, - // Initial contents of the resource are not used, but the contents are - // potentially modified during the frame. - // No initialization/reset is required for correct replay, but may be helpful - // to avoid user confusion when analyzing the resource. - // Corresponds to `PartialWrite` and `CompleteWrite` ref types. + // Initialize the resource by clearing. eInitReq_Clear, - // Initial contents of the resource are read, but not overwritten; - // the resource needs to be initialized before the first replay, but need not - // be reset before subsequent replays. - // Corresponds to `Read` ref type. - eInitReq_InitOnce, + // Initialize the resource by copying initial data. + eInitReq_Copy, +}; - // Initial contents of the resource are read, and later overwritten; - // the resource needs to be reset before each replay. - // Corresponds to `ReadBeforeWrite` ref type. - eInitReq_Reset, +enum InitPolicy +{ + // Completely disable optimizations--copy initial data into every resource + // before every replay. + eInitPolicy_NoOpt, + + // CopyAll--conservative policy which ensures each subresource begins each + // replay with the correct initial data. + // + // Initialization policy: + // Copy initial data into each subresource + // + // Reset policy: + // Copy initial data into each subresource which is written + eInitPolicy_CopyAll, + + // ClearUnread--avoid copying initial data which is never read by the replay + // commands. A user inspecting a resource before it is written may observe + // cleared data, rather than the actual initial data. + // + // Initialization policy: + // Copy initial data into each subresource that is read. + // Clear each subresource that is not read. + // + // Reset policy: + // Copy initial data into each subresource where the initial data is read + // and then overwritten. + // Clear each subresource which is written, but whose initial data is not read. + eInitPolicy_ClearUnread, + + // Fastest--Initialize/reset as little as possible for correct replay. + // A user inspecting a resource before it is written may observe the data + // from a future write (from the previous replay). + // + // Initialization policy: + // Copy initial data into each subresource that is read. + // Clear each subresource that is not read. + // + // Reset policy: + // Copy initial data into each subresource where the initial data is read + // and then overwritten. + eInitPolicy_Fastest, }; // Return the initialization/reset requirements for a FrameRefType -inline InitReqType InitReq(FrameRefType refType) +inline InitReqType InitReq(FrameRefType refType, InitPolicy policy, bool initialized) { - switch(refType) +#define COPY_ONCE (initialized ? eInitReq_None : eInitReq_Copy) +#define CLEAR_ONCE (initialized ? eInitReq_None : eInitReq_Clear) + switch(policy) { - case eFrameRef_None: return eInitReq_None; - case eFrameRef_Read: return eInitReq_InitOnce; - case eFrameRef_ReadBeforeWrite: return eInitReq_Reset; - default: return eInitReq_Clear; + case eInitPolicy_NoOpt: return eInitReq_Copy; + case eInitPolicy_CopyAll: + switch(refType) + { + case eFrameRef_None: return COPY_ONCE; + case eFrameRef_Read: return COPY_ONCE; + default: return eInitReq_Copy; + } + case eInitPolicy_ClearUnread: + switch(refType) + { + case eFrameRef_None: return CLEAR_ONCE; + case eFrameRef_Read: return COPY_ONCE; + case eFrameRef_ReadBeforeWrite: return eInitReq_Copy; + case eFrameRef_WriteBeforeRead: return eInitReq_Copy; + default: return eInitReq_Clear; + } + case eInitPolicy_Fastest: + switch(refType) + { + case eFrameRef_None: return CLEAR_ONCE; + case eFrameRef_Read: return COPY_ONCE; + case eFrameRef_ReadBeforeWrite: return eInitReq_Copy; + case eFrameRef_WriteBeforeRead: return COPY_ONCE; + default: return CLEAR_ONCE; + } + default: RDCERR("Unknown initialization policy (%d).", policy); return eInitReq_Copy; } +#undef COPY_ONCE +#undef CLEAR_ONCE } // handle marking a resource referenced for read or write and storing RAW access etc. diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 21e18b1be..e1e6cdbf9 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -900,7 +900,7 @@ private: const char *pMessage, void *pUserData); void AddFrameTerminator(uint64_t queueMarkerTag); std::vector ImageInitializationBarriers(ResourceId id, WrappedVkRes *live, - bool initialized, + InitPolicy policy, bool initialized, const ImgRefs *imgRefs) const; void SubmitExtQBarriers(const std::map> &extQBarriers); diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 93c7b660c..042394b83 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -1314,7 +1314,7 @@ void WrappedVulkan::Create_InitialState(ResourceId id, WrappedVkRes *live, bool } std::vector WrappedVulkan::ImageInitializationBarriers( - ResourceId id, WrappedVkRes *live, bool initialized, const ImgRefs *imgRefs) const + ResourceId id, WrappedVkRes *live, InitPolicy policy, bool initialized, const ImgRefs *imgRefs) const { std::vector barriers; @@ -1346,10 +1346,11 @@ std::vector WrappedVulkan::ImageInitializationBarriers( } else { - auto initReqs = imgRefs->SubresourceRangeInitReqs(barrier.subresourceRange); + auto initReqs = + imgRefs->SubresourceRangeInitReqs(barrier.subresourceRange, policy, initialized); for(auto initIt = initReqs.begin(); initIt != initReqs.end(); ++initIt) { - if(initIt->second == eInitReq_Reset || initIt->second == eInitReq_Clear) + if(initIt->second != eInitReq_None) { barrier.subresourceRange = initIt->first; barriers.push_back(barrier); @@ -1478,6 +1479,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten ResourceId orig = GetResourceManager()->GetOriginalID(id); ImgRefs *imgRefs = NULL; bool initialized = false; + InitPolicy policy = GetResourceManager()->GetInitPolicy(); if(GetResourceManager()->OptimizeInitialState()) { imgRefs = GetResourceManager()->FindImgRefs(orig); @@ -1934,8 +1936,8 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten } } - std::vector barriers = - ImageInitializationBarriers(id, live, initialized, imgRefs); + std::vector barriers = ImageInitializationBarriers( + id, live, GetResourceManager()->GetInitPolicy(), initialized, imgRefs); DoPipelineBarrier(cmd, (uint32_t)barriers.size(), barriers.data()); std::map > extQBarriers = GetExtQBarriers(barriers); @@ -1951,19 +1953,20 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten 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)); \ +#define INIT_REGION() \ + if(!initialized) \ + { \ + copyRegions.push_back(region); \ + } \ + else \ + { \ + InitReqType initReq = imgRefs->SubresourceInitReq( \ + imgRefs->AspectIndex((VkImageAspectFlagBits)region.imageSubresource.aspectMask), m, a, \ + policy, initialized); \ + if(initReq == eInitReq_Copy) \ + copyRegions.push_back(region); \ + else if(initReq == eInitReq_Clear) \ + clearRegions.push_back(ImageRange(region.imageSubresource)); \ } // copy each slice/mip individually @@ -2100,22 +2103,23 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten { // No information about the memory usage in the frame. // Pessimistically assume the entire memory needs to be reset. - resetReq.update(0, initial.mem.size, eInitReq_Reset, - [](InitReqType x, InitReqType y) -> InitReqType { return std::max(x, y); }); + resetReq.update(0, initial.mem.size, eInitReq_Copy, + [](InitReqType x, InitReqType y) -> InitReqType { return RDCMAX(x, y); }); } else { bool initialized = memRefs->initializedLiveRes == live; memRefs->initializedLiveRes = live; + InitPolicy policy = GetResourceManager()->GetInitPolicy(); for(auto it = memRefs->rangeRefs.begin(); it != memRefs->rangeRefs.end(); it++) { - InitReqType t = InitReq(it->value()); - if(t == eInitReq_Reset || (t == eInitReq_InitOnce && !initialized)) - resetReq.update(it->start(), it->finish(), eInitReq_Reset, - [](InitReqType x, InitReqType y) -> InitReqType { return std::max(x, y); }); - else if(t == eInitReq_Clear || (t == eInitReq_None && !initialized)) + InitReqType t = InitReq(it->value(), policy, initialized); + if(t == eInitReq_Copy) + resetReq.update(it->start(), it->finish(), eInitReq_Copy, + [](InitReqType x, InitReqType y) -> InitReqType { return RDCMAX(x, y); }); + else if(t == eInitReq_Clear) resetReq.update(it->start(), it->finish(), eInitReq_Clear, - [](InitReqType x, InitReqType y) -> InitReqType { return std::max(x, y); }); + [](InitReqType x, InitReqType y) -> InitReqType { return RDCMAX(x, y); }); } } @@ -2158,7 +2162,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten ObjDisp(cmd)->CmdFillBuffer(Unwrap(cmd), Unwrap(dstBuf), it->start(), size, 0); fillCount++; break; - case eInitReq_Reset: regions.push_back({it->start(), it->start(), size}); break; + case eInitReq_Copy: regions.push_back({it->start(), it->start(), size}); break; default: break; } } diff --git a/renderdoc/driver/vulkan/vk_manager.h b/renderdoc/driver/vulkan/vk_manager.h index 320d7d975..7a1b50d8c 100644 --- a/renderdoc/driver/vulkan/vk_manager.h +++ b/renderdoc/driver/vulkan/vk_manager.h @@ -441,6 +441,7 @@ public: ImgRefs *FindImgRefs(ResourceId img); inline bool OptimizeInitialState() { return m_OptimizeInitialState; } + inline InitPolicy GetInitPolicy() { return m_InitPolicy; } private: bool ResourceTypeRelease(WrappedVkRes *res); @@ -457,4 +458,5 @@ private: std::map m_MemFrameRefs; std::map m_ImgFrameRefs; bool m_OptimizeInitialState = false; + InitPolicy m_InitPolicy = eInitPolicy_CopyAll; }; diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index ffbb5729e..1b15ffb2d 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -2964,7 +2964,7 @@ int ImgRefs::SubresourceIndex(int aspectIndex, int level, int layer) const } std::vector > ImgRefs::SubresourceRangeInitReqs( - VkImageSubresourceRange range) const + VkImageSubresourceRange range, InitPolicy policy, bool initialized) const { VkImageSubresourceRange out(range); std::vector > res; @@ -3004,7 +3004,8 @@ std::vector > ImgRefs::Subresource for(int layer = range.baseArrayLayer; layer < splitLayerCount; ++layer) { out.baseArrayLayer = layer; - res.push_back(make_rdcpair(out, SubresourceInitReq(aspectIndex, level, layer))); + res.push_back( + make_rdcpair(out, SubresourceInitReq(aspectIndex, level, layer, policy, initialized))); } } } diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 62c55d746..7b915920b 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -1136,16 +1136,13 @@ struct ImgRefs { return rangeRefs[SubresourceIndex(aspectIndex, level, layer)]; } - inline InitReqType SubresourceInitReq(int aspectIndex, int level, int layer) const + inline InitReqType SubresourceInitReq(int aspectIndex, int level, int layer, InitPolicy policy, + bool initialized) 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)); + return InitReq(SubresourceRef(aspectIndex, level, layer), policy, initialized); } std::vector > SubresourceRangeInitReqs( - VkImageSubresourceRange range) const; + VkImageSubresourceRange range, InitPolicy policy, bool initialized) const; void Split(bool splitAspects, bool splitLevels, bool splitLayers); template FrameRefType Update(ImageRange range, FrameRefType refType, Compose comp);