From 702f487170e5e8e85bfa292aa46ab534b09a62d5 Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 8 Nov 2015 16:49:12 +0100 Subject: [PATCH] [Sparse #1] Track memory referencing of sparse resources into queues * Normal resources have a single memory bind that can be added to frame references when the resource is. Sparse resources don't have that easy single mapping. * Calls to MarkResourceFrameReferenced with a 0 ResourceId aren't a real problem, but we have to be careful when dirtying resources. * We don't have to dirty memory that's sparsely bound as we'll dirty it as soon as its sparsely bound. We do have to worry about making sure that memory is correctly frame referenced. * To do this command buffers track the sparsemapping structures (will be created for all sparse resources) that are referenced underneath them. Then at queue submit time the current sparse mapping is iterated and all bound memory marked frame referenced. * For most cases where a buffer is bound or similar, we can directly add the sparsemapping from the resource record. For descriptor sets we must do this indirectly - by marking any bindframerefs in the descset record with a bit indicating that the associated resource is sparse, then at submit time when iterating the bindframerefs, taking any with the bit set and looking up its record to find the sparsemapping. --- renderdoc/core/resource_manager.cpp | 1 + renderdoc/driver/vulkan/vk_manager.cpp | 16 +++++++ renderdoc/driver/vulkan/vk_manager.h | 2 + renderdoc/driver/vulkan/vk_resources.h | 45 ++++++++++++++++--- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 29 +++++++++--- .../vulkan/wrappers/vk_descriptor_funcs.cpp | 24 ++++++---- .../driver/vulkan/wrappers/vk_draw_funcs.cpp | 34 +++++++++++++- .../driver/vulkan/wrappers/vk_queue_funcs.cpp | 10 +++++ 8 files changed, 139 insertions(+), 22 deletions(-) diff --git a/renderdoc/core/resource_manager.cpp b/renderdoc/core/resource_manager.cpp index 96444769a..bede48614 100644 --- a/renderdoc/core/resource_manager.cpp +++ b/renderdoc/core/resource_manager.cpp @@ -45,6 +45,7 @@ namespace ResourceIDGen void ResourceRecord::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType) { + if(id == ResourceId()) return; ResourceManager::MarkReferenced(m_FrameRefs, id, refType); } diff --git a/renderdoc/driver/vulkan/vk_manager.cpp b/renderdoc/driver/vulkan/vk_manager.cpp index b29c22882..81f05d95e 100644 --- a/renderdoc/driver/vulkan/vk_manager.cpp +++ b/renderdoc/driver/vulkan/vk_manager.cpp @@ -287,6 +287,22 @@ void VulkanResourceManager::SerialiseImageStates(map & } } +void VulkanResourceManager::MarkSparseMapReferenced(SparseMapping *sparse) +{ + if(sparse == NULL) + { + RDCERR("Unexpected NULL sparse mapping"); + return; + } + + for(size_t i=0; i < sparse->opaquemappings.size(); i++) + MarkResourceFrameReferenced(GetResID(sparse->opaquemappings[i].first), eFrameRef_Read); + + for(int a=0; a < VK_IMAGE_ASPECT_NUM; a++) + for(VkDeviceSize i=0; sparse->pages[a] && i < sparse->imgdim.width*sparse->imgdim.height*sparse->imgdim.depth; i++) + MarkResourceFrameReferenced(GetResID(sparse->pages[a][i].first), eFrameRef_Read); +} + void VulkanResourceManager::ApplyTransitions(vector< pair > &trans, map &states) { TRDBG("Applying %u transitions", (uint32_t)trans.size()); diff --git a/renderdoc/driver/vulkan/vk_manager.h b/renderdoc/driver/vulkan/vk_manager.h index f7c000c7b..00cc075a8 100644 --- a/renderdoc/driver/vulkan/vk_manager.h +++ b/renderdoc/driver/vulkan/vk_manager.h @@ -228,6 +228,8 @@ class VulkanResourceManager : public ResourceManager images; uint32_t lastPresent; }; - + +struct SparseMapping +{ + SparseMapping() + { + RDCEraseEl(imgdim); + RDCEraseEl(pagedim); + RDCEraseEl(pages); + } + + // for buffers or non-sparse-resident images (bound with opaque mappings) + vector< pair > opaquemappings; + + // for sparse resident images: + // total image size (in pages) + VkExtent3D imgdim; + // size of a page + VkExtent3D pagedim; + // pagetable per image aspect (some may be NULL) + // in order of width first, then height, then depth + pair *pages[VK_IMAGE_ASPECT_NUM]; +}; + struct CmdBufferRecordingInfo { VkDevice device; @@ -583,6 +605,10 @@ struct CmdBufferRecordingInfo vector< pair > imgtransitions; + // sparse resources referenced by this command buffer (at submit time + // need to go through the sparse mapping and reference all memory) + set sparse; + // a list of all resources dirtied by this command buffer set dirtied; @@ -640,9 +666,10 @@ struct VkResourceRecord : public ResourceRecord cmdInfo->boundDescSets.swap(bakedCommands->cmdInfo->boundDescSets); cmdInfo->imgtransitions.swap(bakedCommands->cmdInfo->imgtransitions); cmdInfo->subcmds.swap(bakedCommands->cmdInfo->subcmds); + cmdInfo->sparse.swap(bakedCommands->cmdInfo->sparse); } - void AddBindFrameRef(ResourceId id, FrameRefType ref) + void AddBindFrameRef(ResourceId id, FrameRefType ref, bool hasSparse = false) { if(id == ResourceId()) { @@ -650,9 +677,9 @@ struct VkResourceRecord : public ResourceRecord return; } - if(bindFrameRefs[id].first == 0) + if((bindFrameRefs[id].first&~SPARSE_REF_BIT) == 0) { - bindFrameRefs[id] = std::make_pair(1, ref); + bindFrameRefs[id] = std::make_pair(1 | (hasSparse ? SPARSE_REF_BIT : 0), ref); } else { @@ -669,7 +696,9 @@ struct VkResourceRecord : public ResourceRecord // deleted since it was bound. if(id == ResourceId()) return; - if(--bindFrameRefs[id].first == 0) + --bindFrameRefs[id].first; + + if((bindFrameRefs[id].first&~SPARSE_REF_BIT) == 0) bindFrameRefs.erase(id); } @@ -691,6 +720,7 @@ struct VkResourceRecord : public ResourceRecord // creation or use, this can always be determined ResourceId baseResource; ResourceId baseResourceMem; // for image views, we need to point to both the image and mem + SparseMapping *sparseInfo; // framebuffers are the only object that can point to multiple resources // (as each attachment has an image). @@ -715,7 +745,10 @@ struct VkResourceRecord : public ResourceRecord // contains the framerefs (ref counted) for the bound resources // in the binding slots. Updated when updating descriptor sets // and then applied in a block on descriptor set bind. - map > bindFrameRefs; + // the refcount has the high-bit set if this resource has sparse + // mapping information + static const uint32_t SPARSE_REF_BIT = 0x80000000; + map > bindFrameRefs; }; struct ImageLayouts diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index ff1156c60..4196a5e8b 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -678,7 +678,10 @@ void WrappedVulkan::vkCmdBeginRenderPass( { if(fb->imageAttachments[i] == NULL) break; record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResource, eFrameRef_Write); - record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResourceMem, eFrameRef_Read); + if(fb->imageAttachments[i]->baseResourceMem != ResourceId()) + record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResourceMem, eFrameRef_Read); + if(fb->imageAttachments[i]->sparseInfo) + record->cmdInfo->sparse.insert(fb->imageAttachments[i]->sparseInfo); record->cmdInfo->dirtied.insert(fb->imageAttachments[i]->baseResource); } } @@ -1334,6 +1337,8 @@ void WrappedVulkan::vkCmdBindVertexBuffers( { record->MarkResourceFrameReferenced(GetResID(pBuffers[i]), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(pBuffers[i])->baseResource, eFrameRef_Read); + if(GetRecord(pBuffers[i])->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(pBuffers[i])->sparseInfo); } } } @@ -1402,6 +1407,8 @@ void WrappedVulkan::vkCmdBindIndexBuffer( record->AddChunk(scope.Get()); record->MarkResourceFrameReferenced(GetResID(buffer), eFrameRef_Read); record->MarkResourceFrameReferenced(GetRecord(buffer)->baseResource, eFrameRef_Read); + if(GetRecord(buffer)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(buffer)->sparseInfo); } } @@ -1470,7 +1477,10 @@ void WrappedVulkan::vkCmdUpdateBuffer( // mark buffer just as read, and memory behind as write & dirtied record->MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read); record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->baseResource != ResourceId()) + record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->sparseInfo) + record->cmdInfo->sparse.insert(buf->sparseInfo); } } @@ -1537,7 +1547,10 @@ void WrappedVulkan::vkCmdFillBuffer( // mark buffer just as read, and memory behind as write & dirtied record->MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read); record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->baseResource != ResourceId()) + record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->sparseInfo) + record->cmdInfo->sparse.insert(buf->sparseInfo); } } @@ -1833,7 +1846,10 @@ void WrappedVulkan::vkCmdWriteTimestamp( // mark buffer just as read, and memory behind as write & dirtied record->MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read); record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->baseResource != ResourceId()) + record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->sparseInfo) + record->cmdInfo->sparse.insert(buf->sparseInfo); } } @@ -1912,7 +1928,10 @@ void WrappedVulkan::vkCmdCopyQueryPoolResults( // mark buffer just as read, and memory behind as write & dirtied record->MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read); record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->baseResource != ResourceId()) + record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->sparseInfo) + record->cmdInfo->sparse.insert(buf->sparseInfo); } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index d9dc6d45f..659730b17 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -623,13 +623,15 @@ void WrappedVulkan::vkUpdateDescriptorSets( if(bind.bufferView != VK_NULL_HANDLE) { record->RemoveBindFrameRef(GetResID(bind.bufferView)); - record->RemoveBindFrameRef(GetRecord(bind.bufferView)->baseResource); + if(GetRecord(bind.bufferView)->baseResource != ResourceId()) + record->RemoveBindFrameRef(GetRecord(bind.bufferView)->baseResource); } if(bind.imageView != VK_NULL_HANDLE) { record->RemoveBindFrameRef(GetResID(bind.imageView)); record->RemoveBindFrameRef(GetRecord(bind.imageView)->baseResource); - record->RemoveBindFrameRef(GetRecord(bind.imageView)->baseResourceMem); + if(GetRecord(bind.imageView)->baseResourceMem != ResourceId()) + record->RemoveBindFrameRef(GetRecord(bind.imageView)->baseResourceMem); } if(bind.sampler != VK_NULL_HANDLE) { @@ -638,21 +640,24 @@ void WrappedVulkan::vkUpdateDescriptorSets( if(bind.bufferInfo.buffer != VK_NULL_HANDLE) { record->RemoveBindFrameRef(GetResID(bind.bufferInfo.buffer)); - record->RemoveBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource); + if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) + record->RemoveBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource); } bind = pDescriptorWrites[i].pDescriptors[d]; if(bind.bufferView != VK_NULL_HANDLE) { - record->AddBindFrameRef(GetResID(bind.bufferView), eFrameRef_Read); - record->AddBindFrameRef(GetRecord(bind.bufferView)->baseResource, ref); + record->AddBindFrameRef(GetResID(bind.bufferView), eFrameRef_Read, GetRecord(bind.bufferView)->sparseInfo != NULL); + if(GetRecord(bind.bufferView)->baseResource != ResourceId()) + record->AddBindFrameRef(GetRecord(bind.bufferView)->baseResource, ref); } if(bind.imageView != VK_NULL_HANDLE) { - record->AddBindFrameRef(GetResID(bind.imageView), eFrameRef_Read); + record->AddBindFrameRef(GetResID(bind.imageView), eFrameRef_Read, GetRecord(bind.imageView)->sparseInfo != NULL); record->AddBindFrameRef(GetRecord(bind.imageView)->baseResource, ref); - record->AddBindFrameRef(GetRecord(bind.imageView)->baseResourceMem, eFrameRef_Read); + if(GetRecord(bind.imageView)->baseResourceMem != ResourceId()) + record->AddBindFrameRef(GetRecord(bind.imageView)->baseResourceMem, eFrameRef_Read); } if(bind.sampler != VK_NULL_HANDLE) { @@ -660,8 +665,9 @@ void WrappedVulkan::vkUpdateDescriptorSets( } if(bind.bufferInfo.buffer != VK_NULL_HANDLE) { - record->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read); - record->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref); + record->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read, GetRecord(bind.bufferInfo.buffer)->sparseInfo != NULL); + if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) + record->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp index 31b338651..e538fbb2b 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp @@ -180,6 +180,10 @@ void WrappedVulkan::vkCmdBlitImage( record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); + if(GetRecord(srcImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); + if(GetRecord(destImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); } } @@ -257,6 +261,10 @@ void WrappedVulkan::vkCmdResolveImage( record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); + if(GetRecord(srcImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); + if(GetRecord(destImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); } } @@ -333,6 +341,10 @@ void WrappedVulkan::vkCmdCopyImage( record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); + if(GetRecord(srcImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); + if(GetRecord(destImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); } } @@ -423,6 +435,10 @@ void WrappedVulkan::vkCmdCopyBufferToImage( record->MarkResourceFrameReferenced(GetResID(destImage), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(destImage)->baseResource, eFrameRef_Read); record->cmdInfo->dirtied.insert(GetResID(destImage)); + if(GetRecord(srcBuffer)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(srcBuffer)->sparseInfo); + if(GetRecord(destImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(destImage)->sparseInfo); } } @@ -500,7 +516,12 @@ void WrappedVulkan::vkCmdCopyImageToBuffer( // mark buffer just as read, and memory behind as write & dirtied record->MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read); record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->baseResource != ResourceId()) + record->cmdInfo->dirtied.insert(buf->baseResource); + if(GetRecord(srcImage)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(srcImage)->sparseInfo); + if(buf->sparseInfo) + record->cmdInfo->sparse.insert(buf->sparseInfo); } } @@ -589,7 +610,12 @@ void WrappedVulkan::vkCmdCopyBuffer( // mark buffer just as read, and memory behind as write & dirtied record->MarkResourceFrameReferenced(buf->GetResourceID(), eFrameRef_Read); record->MarkResourceFrameReferenced(buf->baseResource, eFrameRef_Write); - record->cmdInfo->dirtied.insert(buf->baseResource); + if(buf->baseResource != ResourceId()) + record->cmdInfo->dirtied.insert(buf->baseResource); + if(GetRecord(srcBuffer)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(srcBuffer)->sparseInfo); + if(buf->sparseInfo) + record->cmdInfo->sparse.insert(buf->sparseInfo); } } @@ -658,6 +684,8 @@ void WrappedVulkan::vkCmdClearColorImage( record->AddChunk(scope.Get()); record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Read); + if(GetRecord(image)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(image)->sparseInfo); } } @@ -725,6 +753,8 @@ void WrappedVulkan::vkCmdClearDepthStencilImage( record->AddChunk(scope.Get()); record->MarkResourceFrameReferenced(GetResID(image), eFrameRef_Write); record->MarkResourceFrameReferenced(GetRecord(image)->baseResource, eFrameRef_Read); + if(GetRecord(image)->sparseInfo) + record->cmdInfo->sparse.insert(GetRecord(image)->sparseInfo); } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index b62c80268..4c74c98c1 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -399,8 +399,18 @@ VkResult WrappedVulkan::vkQueueSubmit( { refdIDs.insert(refit->first); GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second); + + if(refit->second.first & VkResourceRecord::SPARSE_REF_BIT) + { + VkResourceRecord *record = GetResourceManager()->GetResourceRecord(refit->first); + + GetResourceManager()->MarkSparseMapReferenced(record->sparseInfo); + } } } + + for(auto it = record->bakedCommands->cmdInfo->sparse.begin(); it != record->bakedCommands->cmdInfo->sparse.end(); ++it) + GetResourceManager()->MarkSparseMapReferenced(*it); // pull in frame refs from this baked command buffer record->bakedCommands->AddResourceReferences(GetResourceManager());