mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-29 13:20:54 +00:00
[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.
This commit is contained in:
@@ -45,6 +45,7 @@ namespace ResourceIDGen
|
||||
|
||||
void ResourceRecord::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType)
|
||||
{
|
||||
if(id == ResourceId()) return;
|
||||
ResourceManager<void*,void*,ResourceRecord>::MarkReferenced(m_FrameRefs, id, refType);
|
||||
}
|
||||
|
||||
|
||||
@@ -287,6 +287,22 @@ void VulkanResourceManager::SerialiseImageStates(map<ResourceId, ImageLayouts> &
|
||||
}
|
||||
}
|
||||
|
||||
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<ResourceId, ImageRegionState> > &trans, map<ResourceId, ImageLayouts> &states)
|
||||
{
|
||||
TRDBG("Applying %u transitions", (uint32_t)trans.size());
|
||||
|
||||
@@ -228,6 +228,8 @@ class VulkanResourceManager : public ResourceManager<WrappedVkRes*, TypedRealHan
|
||||
delete GetWrapped(obj);
|
||||
}
|
||||
|
||||
// helper for sparse mappings
|
||||
void MarkSparseMapReferenced(SparseMapping *sparse);
|
||||
private:
|
||||
bool SerialisableResource(ResourceId id, VkResourceRecord *record);
|
||||
|
||||
|
||||
@@ -575,7 +575,29 @@ struct SwapchainInfo
|
||||
vector<SwapImage> 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<VkDeviceMemory, VkDeviceSize> > 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<VkDeviceMemory, VkDeviceSize> *pages[VK_IMAGE_ASPECT_NUM];
|
||||
};
|
||||
|
||||
struct CmdBufferRecordingInfo
|
||||
{
|
||||
VkDevice device;
|
||||
@@ -583,6 +605,10 @@ struct CmdBufferRecordingInfo
|
||||
|
||||
vector< pair<ResourceId, ImageRegionState> > imgtransitions;
|
||||
|
||||
// sparse resources referenced by this command buffer (at submit time
|
||||
// need to go through the sparse mapping and reference all memory)
|
||||
set<SparseMapping *> sparse;
|
||||
|
||||
// a list of all resources dirtied by this command buffer
|
||||
set<ResourceId> 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<ResourceId, pair<int, FrameRefType> > bindFrameRefs;
|
||||
// the refcount has the high-bit set if this resource has sparse
|
||||
// mapping information
|
||||
static const uint32_t SPARSE_REF_BIT = 0x80000000;
|
||||
map<ResourceId, pair<uint32_t, FrameRefType> > bindFrameRefs;
|
||||
};
|
||||
|
||||
struct ImageLayouts
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user