From 035073fac9aa9e9394ff43478497bb79603502aa Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 31 Jul 2020 13:50:01 +0100 Subject: [PATCH] When updating descriptor bind refs, cache resource references * This means we don't have to iterate the whole bindrefs array every time we want to propagate references in the background, but we can submit them in batch. --- renderdoc/core/resource_manager.h | 36 ++++++++++++ renderdoc/driver/vulkan/vk_common.cpp | 57 ++++++++++++++++--- renderdoc/driver/vulkan/vk_common.h | 3 +- renderdoc/driver/vulkan/vk_resources.h | 23 +++++--- .../vulkan/wrappers/vk_descriptor_funcs.cpp | 23 +++++++- .../driver/vulkan/wrappers/vk_queue_funcs.cpp | 15 +---- 6 files changed, 124 insertions(+), 33 deletions(-) diff --git a/renderdoc/core/resource_manager.h b/renderdoc/core/resource_manager.h index ee1adfec3..5ded3f7ec 100644 --- a/renderdoc/core/resource_manager.h +++ b/renderdoc/core/resource_manager.h @@ -609,6 +609,7 @@ public: void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType, Compose comp); inline void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType); + void MarkBackgroundFrameReferenced(const rdcarray> &refs); /////////////////////////////////////////// // Replay-side methods @@ -809,6 +810,41 @@ ResourceManager::~ResourceManager() RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this); } +template +void ResourceManager::MarkBackgroundFrameReferenced( + const rdcarray> &refs) +{ + SCOPED_LOCK(m_Lock); + + if(IsBackgroundCapturing(m_State)) + { + if(refs.size() <= m_ResourceRefTimes.size()) + { + for(const rdcpair &ref : refs) + { + UpdateLastPartialUseTime(ref.first, ref.second); + UpdateLastWriteTime(ref.first, ref.second); + } + } + else + { + for(const ResourceRefTimes &res : m_ResourceRefTimes) + { + const rdcpair *it = std::lower_bound( + refs.begin(), refs.end(), make_rdcpair(res.id, eFrameRef_None), + [](const rdcpair &a, + const rdcpair &b) { return a.first < b.first; }); + + if(it != refs.end() && it->first == res.id) + { + UpdateLastPartialUseTime(it->first, it->second); + UpdateLastWriteTime(it->first, it->second); + } + } + } + } +} + template template void ResourceManager::MarkResourceFrameReferenced(ResourceId id, diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index 8b09bf860..87004cc00 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -1098,37 +1098,76 @@ void DescriptorSetSlot::RemoveBindRefs(VulkanResourceManager *rm, VkResourceReco imageInfo.sampler = ResourceId(); } -void DescriptorSetSlot::AddBindRefs(VulkanResourceManager *rm, VkResourceRecord *record, - FrameRefType ref) +void DescriptorSetSlot::AddBindRefs(std::set &ids, VulkanResourceManager *rm, + VkResourceRecord *record, FrameRefType ref) { SCOPED_LOCK(record->descInfo->refLock); if(texelBufferView != ResourceId()) { VkResourceRecord *bufView = rm->GetResourceRecord(texelBufferView); - record->AddBindFrameRef(bufView->GetResourceID(), eFrameRef_Read, + record->AddBindFrameRef(ids, bufView->GetResourceID(), eFrameRef_Read, bufView->resInfo && bufView->resInfo->IsSparse()); if(bufView->baseResource != ResourceId()) - record->AddBindFrameRef(bufView->baseResource, eFrameRef_Read); + record->AddBindFrameRef(ids, bufView->baseResource, eFrameRef_Read); if(bufView->baseResourceMem != ResourceId()) - record->AddMemFrameRef(bufView->baseResourceMem, bufView->memOffset, bufView->memSize, ref); + record->AddMemFrameRef(ids, bufView->baseResourceMem, bufView->memOffset, bufView->memSize, + ref); } if(imageInfo.imageView != ResourceId()) { VkResourceRecord *view = rm->GetResourceRecord(imageInfo.imageView); - record->AddImgFrameRef(view, ref); + record->AddImgFrameRef(ids, view, ref); } if(imageInfo.sampler != ResourceId()) { - record->AddBindFrameRef(imageInfo.sampler, eFrameRef_Read); + record->AddBindFrameRef(ids, imageInfo.sampler, eFrameRef_Read); } if(bufferInfo.buffer != ResourceId()) { VkResourceRecord *buf = rm->GetResourceRecord(bufferInfo.buffer); - record->AddBindFrameRef(bufferInfo.buffer, eFrameRef_Read, + record->AddBindFrameRef(ids, bufferInfo.buffer, eFrameRef_Read, buf->resInfo && buf->resInfo->IsSparse()); if(buf->baseResource != ResourceId()) - record->AddMemFrameRef(buf->baseResource, buf->memOffset, buf->memSize, ref); + record->AddMemFrameRef(ids, buf->baseResource, buf->memOffset, buf->memSize, ref); + } +} + +void DescriptorSetData::UpdateBackgroundRefCache(VulkanResourceManager *resourceManager, + const std::set &ids) +{ + SCOPED_LOCK(refLock); + + rdcpair *cacheit = backgroundFrameRefs.begin(); + for(auto refit = ids.begin(); refit != ids.end(); ++refit) + { + ResourceId id = *refit; + FrameRefType refType = bindFrameRefs[id].second; + + // find the Id we're looking for in the remainder of the cache. This won't skip over any one + // that we care about because we're iterating in ascending Id order + cacheit = std::lower_bound( + cacheit, backgroundFrameRefs.end(), make_rdcpair(id, eFrameRef_None), + [](const rdcpair &a, const rdcpair &b) { + return a.first < b.first; + }); + + // if we didn't find a match, insert the desired entry here + if(cacheit == backgroundFrameRefs.end() || cacheit->first != id) + { + // calculate the index + size_t idx = cacheit - backgroundFrameRefs.begin(); + // insert the entry + backgroundFrameRefs.insert(idx, {id, refType}); + // re-initialise our iterator to point here, as the above insert might have invalidated it due + // to a resize + cacheit = backgroundFrameRefs.begin() + idx; + } + else + { + // update the frameref + cacheit->second = refType; + } } } diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index bd875b3cd..ce528a66d 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -431,7 +431,8 @@ struct DescriptorSetSlotImageInfo struct DescriptorSetSlot { void RemoveBindRefs(VulkanResourceManager *rm, VkResourceRecord *record); - void AddBindRefs(VulkanResourceManager *rm, VkResourceRecord *record, FrameRefType ref); + void AddBindRefs(std::set &ids, VulkanResourceManager *rm, VkResourceRecord *record, + FrameRefType ref); // VkDescriptorBufferInfo DescriptorSetSlotBufferInfo bufferInfo; diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 744705ad6..b8c68afc1 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -1063,9 +1063,14 @@ struct DescriptorSetData // the refcount has the high-bit set if this resource has sparse // mapping information static const uint32_t SPARSE_REF_BIT = 0x80000000; - std::map > bindFrameRefs; + std::map> bindFrameRefs; std::map bindMemRefs; std::map bindImageStates; + + void UpdateBackgroundRefCache(VulkanResourceManager *resourceManager, + const std::set &ids); + + rdcarray> backgroundFrameRefs; }; struct PipelineLayoutData @@ -1818,7 +1823,7 @@ struct ImgRefs } InitReqType SubresourceRangeMaxInitReq(VkImageSubresourceRange range, InitPolicy policy, bool initialized) const; - rdcarray > SubresourceRangeInitReqs( + rdcarray> SubresourceRangeInitReqs( VkImageSubresourceRange range, InitPolicy policy, bool initialized) const; void Split(bool splitAspects, bool splitLevels, bool splitLayers); template @@ -2116,13 +2121,15 @@ public: cmdInfo->memFrameRefs.swap(bakedCommands->cmdInfo->memFrameRefs); } - void AddBindFrameRef(ResourceId id, FrameRefType ref, bool hasSparse = false) + void AddBindFrameRef(std::set &ids, ResourceId id, FrameRefType ref, + bool hasSparse = false) { if(id == ResourceId()) { RDCERR("Unexpected NULL resource ID being added as a bind frame ref"); return; } + ids.insert(id); rdcpair &p = descInfo->bindFrameRefs[id]; if((p.first & ~DescriptorSetData::SPARSE_REF_BIT) == 0) { @@ -2138,12 +2145,12 @@ public: } } - void AddImgFrameRef(VkResourceRecord *view, FrameRefType refType) + void AddImgFrameRef(std::set &ids, VkResourceRecord *view, FrameRefType refType) { - AddBindFrameRef(view->GetResourceID(), eFrameRef_Read, + AddBindFrameRef(ids, view->GetResourceID(), eFrameRef_Read, view->resInfo && view->resInfo->IsSparse()); if(view->baseResourceMem != ResourceId()) - AddBindFrameRef(view->baseResourceMem, eFrameRef_Read, false); + AddBindFrameRef(ids, view->baseResourceMem, eFrameRef_Read, false); rdcpair &p = descInfo->bindFrameRefs[view->baseResource]; if((p.first & ~DescriptorSetData::SPARSE_REF_BIT) == 0) @@ -2167,13 +2174,15 @@ public: p.second = ComposeFrameRefsDisjoint(p.second, maxRef); } - void AddMemFrameRef(ResourceId mem, VkDeviceSize offset, VkDeviceSize size, FrameRefType refType) + void AddMemFrameRef(std::set &ids, ResourceId mem, VkDeviceSize offset, + VkDeviceSize size, FrameRefType refType) { if(mem == ResourceId()) { RDCERR("Unexpected NULL resource ID being added as a bind frame ref"); return; } + ids.insert(mem); rdcpair &p = descInfo->bindFrameRefs[mem]; if((p.first & ~DescriptorSetData::SPARSE_REF_BIT) == 0) { diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index accb75bab..ce26624ef 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -1054,6 +1054,8 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, // need to track descriptor set contents whether capframing or idle if(IsCaptureMode(m_State)) { + std::set ids; + for(uint32_t i = 0; i < writeCount; i++) { const VkWriteDescriptorSet &descWrite = pDescriptorWrites[i]; @@ -1089,6 +1091,8 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, // start at the dstArrayElement uint32_t curIdx = descWrite.dstArrayElement; + ids.clear(); + for(uint32_t d = 0; d < descWrite.descriptorCount; d++, curIdx++) { // roll over onto the next binding, on the assumption that it is the same @@ -1154,8 +1158,10 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, bind.bufferInfo.SetFrom(descWrite.pBufferInfo[d]); } - bind.AddBindRefs(GetResourceManager(), record, ref); + bind.AddBindRefs(ids, GetResourceManager(), record, ref); } + + record->descInfo->UpdateBackgroundRefCache(GetResourceManager(), ids); } // this is almost identical to the above loop, except that instead of sourcing the descriptors @@ -1192,6 +1198,8 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, uint32_t curSrcIdx = pDescriptorCopies[i].srcArrayElement; uint32_t curDstIdx = pDescriptorCopies[i].dstArrayElement; + ids.clear(); + for(uint32_t d = 0; d < pDescriptorCopies[i].descriptorCount; d++, curSrcIdx++, curDstIdx++) { if(srclayoutBinding->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) @@ -1230,8 +1238,10 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, bind.RemoveBindRefs(GetResourceManager(), dstrecord); bind = (*srcbinding)[curSrcIdx]; - bind.AddBindRefs(GetResourceManager(), dstrecord, ref); + bind.AddBindRefs(ids, GetResourceManager(), dstrecord, ref); } + + dstrecord->descInfo->UpdateBackgroundRefCache(GetResourceManager(), ids); } } } @@ -1475,9 +1485,12 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( // need to track descriptor set contents whether capframing or idle if(IsCaptureMode(m_State)) { + std::set ids; + for(const VkDescriptorUpdateTemplateEntry &entry : tempInfo->updates) { VkResourceRecord *record = GetRecord(descriptorSet); + RDCASSERT(record->descInfo && record->descInfo->layout); const DescSetLayout &layout = *record->descInfo->layout; @@ -1493,6 +1506,8 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( // start at the dstArrayElement uint32_t curIdx = entry.dstArrayElement; + ids.clear(); + for(uint32_t d = 0; d < entry.descriptorCount; d++, curIdx++) { // roll over onto the next binding, on the assumption that it is the same @@ -1559,8 +1574,10 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate( bind.bufferInfo.SetFrom(*(const VkDescriptorBufferInfo *)src); } - bind.AddBindRefs(GetResourceManager(), record, ref); + bind.AddBindRefs(ids, GetResourceManager(), record, ref); } + + record->descInfo->UpdateBackgroundRefCache(GetResourceManager(), ids); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index 65f765820..b102e41de 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -1007,19 +1007,8 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount, SCOPED_LOCK(setrecord->descInfo->refLock); - for(auto refit = setrecord->descInfo->bindFrameRefs.begin(); - refit != setrecord->descInfo->bindFrameRefs.end(); ++refit) - { - GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second); - - if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT) - { - VkResourceRecord *sparserecord = - GetResourceManager()->GetResourceRecord(refit->first); - - GetResourceManager()->MarkSparseMapReferenced(sparserecord->resInfo); - } - } + GetResourceManager()->MarkBackgroundFrameReferenced( + setrecord->descInfo->backgroundFrameRefs); } record->bakedCommands->AddResourceReferences(GetResourceManager());