mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
Track frame references to ranges of Vulkan VkDeviceMemorys
The current frame reference tracking handles `VkDeviceMemory`s as single resource--e.g. if one region of the memory is read, and a disjoint region of the memory is written, this is treated exactly the same way as if the read and write were on the same region of the memory. The new behaviour tracks the frame references for ranges of device memory; this will be used to improve the detection of device memory that does not require initialization or resetting. The `FrameRefType` associated with the entire memory resource (e.g. through `MarkResourceFrameReferenced`), should now keep an up-to-date maximum of the `FrameRefType`s of all of the intervals within that memory. Maximum is used here because `FrameRefType`s with stronger init/reset requirements have larger values.
This commit is contained in:
committed by
Baldur Karlsson
parent
3bc53094da
commit
2828232ae8
@@ -132,28 +132,6 @@ bool IsDirtyFrameRef(FrameRefType refType)
|
||||
return (refType != eFrameRef_None && refType != eFrameRef_Read);
|
||||
}
|
||||
|
||||
bool MarkReferenced(std::map<ResourceId, FrameRefType> &refs, ResourceId id, FrameRefType refType)
|
||||
{
|
||||
auto refit = refs.find(id);
|
||||
if(refit == refs.end())
|
||||
{
|
||||
refs[id] = refType;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
refit->second = ComposeFrameRefs(refit->second, refType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResourceRecord::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType)
|
||||
{
|
||||
if(id == ResourceId())
|
||||
return false;
|
||||
return MarkReferenced(m_FrameRefs, id, refType);
|
||||
}
|
||||
|
||||
void ResourceRecord::AddResourceReferences(ResourceRecordHandler *mgr)
|
||||
{
|
||||
for(auto it = m_FrameRefs.begin(); it != m_FrameRefs.end(); ++it)
|
||||
|
||||
@@ -158,7 +158,28 @@ inline InitReqType InitReq(FrameRefType refType)
|
||||
}
|
||||
|
||||
// handle marking a resource referenced for read or write and storing RAW access etc.
|
||||
bool MarkReferenced(std::map<ResourceId, FrameRefType> &refs, ResourceId id, FrameRefType refType);
|
||||
template <typename Compose>
|
||||
bool MarkReferenced(std::map<ResourceId, FrameRefType> &refs, ResourceId id, FrameRefType refType,
|
||||
Compose comp)
|
||||
{
|
||||
auto refit = refs.find(id);
|
||||
if(refit == refs.end())
|
||||
{
|
||||
refs[id] = refType;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
refit->second = comp(refit->second, refType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool MarkReferenced(std::map<ResourceId, FrameRefType> &refs, ResourceId id,
|
||||
FrameRefType refType)
|
||||
{
|
||||
return MarkReferenced(refs, id, refType, ComposeFrameRefs);
|
||||
}
|
||||
|
||||
// verbose prints with IDs of each dirty resource and whether it was prepared,
|
||||
// and whether it was serialised.
|
||||
@@ -353,7 +374,12 @@ struct ResourceRecord
|
||||
bool HasDataPtr() { return DataPtr != NULL; }
|
||||
void SetDataOffset(uint64_t offs) { DataOffset = offs; }
|
||||
void SetDataPtr(byte *ptr) { DataPtr = ptr; }
|
||||
bool MarkResourceFrameReferenced(ResourceId id, FrameRefType refType);
|
||||
template <typename Compose>
|
||||
bool MarkResourceFrameReferenced(ResourceId id, FrameRefType refType, Compose comp);
|
||||
inline bool MarkResourceFrameReferenced(ResourceId id, FrameRefType refType)
|
||||
{
|
||||
return MarkResourceFrameReferenced(id, refType, ComposeFrameRefs);
|
||||
}
|
||||
void AddResourceReferences(ResourceRecordHandler *mgr);
|
||||
void AddReferencedIDs(std::set<ResourceId> &ids)
|
||||
{
|
||||
@@ -400,6 +426,14 @@ protected:
|
||||
map<ResourceId, FrameRefType> m_FrameRefs;
|
||||
};
|
||||
|
||||
template <typename Compose>
|
||||
bool ResourceRecord::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType, Compose comp)
|
||||
{
|
||||
if(id == ResourceId())
|
||||
return false;
|
||||
return MarkReferenced(m_FrameRefs, id, refType, comp);
|
||||
}
|
||||
|
||||
// the resource manager is a utility class that's not required but is likely wanted by any API
|
||||
// implementation.
|
||||
// It keeps track of resource records, which resources are alive and allows you to query for them by
|
||||
@@ -488,6 +522,9 @@ public:
|
||||
|
||||
// mark resource referenced somewhere in the main frame-affecting calls.
|
||||
// That means this resource should be included in the final serialise out
|
||||
template <typename Compose>
|
||||
void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType, Compose comp);
|
||||
|
||||
inline void MarkResourceFrameReferenced(ResourceId id, FrameRefType refType);
|
||||
|
||||
///////////////////////////////////////////
|
||||
@@ -626,14 +663,16 @@ ResourceManager<Configuration>::~ResourceManager()
|
||||
}
|
||||
|
||||
template <typename Configuration>
|
||||
void ResourceManager<Configuration>::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType)
|
||||
template <typename Compose>
|
||||
void ResourceManager<Configuration>::MarkResourceFrameReferenced(ResourceId id,
|
||||
FrameRefType refType, Compose comp)
|
||||
{
|
||||
SCOPED_LOCK(m_Lock);
|
||||
|
||||
if(id == ResourceId())
|
||||
return;
|
||||
|
||||
bool newRef = MarkReferenced(m_FrameReferencedResources, id, refType);
|
||||
bool newRef = MarkReferenced(m_FrameReferencedResources, id, refType, comp);
|
||||
|
||||
if(newRef)
|
||||
{
|
||||
@@ -644,6 +683,12 @@ void ResourceManager<Configuration>::MarkResourceFrameReferenced(ResourceId id,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Configuration>
|
||||
void ResourceManager<Configuration>::MarkResourceFrameReferenced(ResourceId id, FrameRefType refType)
|
||||
{
|
||||
return MarkResourceFrameReferenced(id, refType, ComposeFrameRefs);
|
||||
}
|
||||
|
||||
template <typename Configuration>
|
||||
void ResourceManager<Configuration>::MarkDirtyResource(ResourceId res)
|
||||
{
|
||||
|
||||
@@ -837,10 +837,12 @@ void DescriptorSetSlot::AddBindRefs(VkResourceRecord *record, FrameRefType ref)
|
||||
{
|
||||
if(texelBufferView != VK_NULL_HANDLE)
|
||||
{
|
||||
record->AddBindFrameRef(GetResID(texelBufferView), eFrameRef_Read,
|
||||
GetRecord(texelBufferView)->resInfo != NULL);
|
||||
if(GetRecord(texelBufferView)->baseResource != ResourceId())
|
||||
record->AddBindFrameRef(GetRecord(texelBufferView)->baseResource, ref);
|
||||
VkResourceRecord *bufView = GetRecord(texelBufferView);
|
||||
record->AddBindFrameRef(bufView->GetResourceID(), eFrameRef_Read, bufView->resInfo != NULL);
|
||||
if(bufView->baseResource != ResourceId())
|
||||
record->AddBindFrameRef(bufView->baseResource, eFrameRef_Read);
|
||||
if(bufView->baseResourceMem != ResourceId())
|
||||
record->AddMemFrameRef(bufView->baseResourceMem, bufView->memOffset, bufView->memSize, ref);
|
||||
}
|
||||
if(imageInfo.imageView != VK_NULL_HANDLE)
|
||||
{
|
||||
@@ -856,9 +858,9 @@ void DescriptorSetSlot::AddBindRefs(VkResourceRecord *record, FrameRefType ref)
|
||||
}
|
||||
if(bufferInfo.buffer != VK_NULL_HANDLE)
|
||||
{
|
||||
record->AddBindFrameRef(GetResID(bufferInfo.buffer), eFrameRef_Read,
|
||||
GetRecord(bufferInfo.buffer)->resInfo != NULL);
|
||||
if(GetRecord(bufferInfo.buffer)->baseResource != ResourceId())
|
||||
record->AddBindFrameRef(GetRecord(bufferInfo.buffer)->baseResource, ref);
|
||||
VkResourceRecord *buf = GetRecord(bufferInfo.buffer);
|
||||
record->AddBindFrameRef(GetResID(bufferInfo.buffer), eFrameRef_Read, buf->resInfo != NULL);
|
||||
if(buf->baseResource != ResourceId())
|
||||
record->AddMemFrameRef(buf->baseResource, buf->memOffset, buf->memSize, ref);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1301,6 +1301,7 @@ void WrappedVulkan::StartFrameCapture(void *dev, void *wnd)
|
||||
m_CapturedFrames.push_back(frame);
|
||||
|
||||
GetResourceManager()->ClearReferencedResources();
|
||||
GetResourceManager()->ClearReferencedMemory();
|
||||
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(m_Instance), eFrameRef_Read);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(m_Device), eFrameRef_Read);
|
||||
@@ -1751,6 +1752,8 @@ bool WrappedVulkan::EndFrameCapture(void *dev, void *wnd)
|
||||
|
||||
GetResourceManager()->MarkUnwrittenResources();
|
||||
|
||||
GetResourceManager()->ClearReferencedMemory();
|
||||
|
||||
GetResourceManager()->ClearReferencedResources();
|
||||
|
||||
GetResourceManager()->FreeInitialContents();
|
||||
|
||||
@@ -610,7 +610,26 @@ ResourceId VulkanResourceManager::GetFirstIDForHandle(uint64_t handle)
|
||||
void VulkanResourceManager::MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize offset,
|
||||
VkDeviceSize size, FrameRefType refType)
|
||||
{
|
||||
MarkResourceFrameReferenced(mem, refType);
|
||||
FrameRefType maxRef = MarkMemoryReferenced(m_MemFrameRefs, mem, offset, size, refType);
|
||||
MarkResourceFrameReferenced(
|
||||
mem, maxRef, [](FrameRefType x, FrameRefType y) -> FrameRefType { return std::max(x, y); });
|
||||
}
|
||||
|
||||
void VulkanResourceManager::MergeReferencedMemory(std::map<ResourceId, MemRefs> &memRefs)
|
||||
{
|
||||
for(auto j = memRefs.begin(); j != memRefs.end(); j++)
|
||||
{
|
||||
auto i = m_MemFrameRefs.find(j->first);
|
||||
if(i == m_MemFrameRefs.end())
|
||||
m_MemFrameRefs.insert(*j);
|
||||
else
|
||||
i->second.Merge(j->second);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanResourceManager::ClearReferencedMemory()
|
||||
{
|
||||
m_MemFrameRefs.clear();
|
||||
}
|
||||
|
||||
bool VulkanResourceManager::Force_InitialState(WrappedVkRes *res, bool prepare)
|
||||
|
||||
@@ -413,6 +413,9 @@ public:
|
||||
void MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize start, VkDeviceSize end,
|
||||
FrameRefType refType);
|
||||
|
||||
void MergeReferencedMemory(std::map<ResourceId, MemRefs> &memRefs);
|
||||
void ClearReferencedMemory();
|
||||
|
||||
private:
|
||||
bool ResourceTypeRelease(WrappedVkRes *res);
|
||||
|
||||
@@ -428,4 +431,5 @@ private:
|
||||
|
||||
CaptureState m_State;
|
||||
WrappedVulkan *m_Core;
|
||||
std::map<ResourceId, MemRefs> m_MemFrameRefs;
|
||||
};
|
||||
|
||||
@@ -3033,7 +3033,11 @@ VkResourceRecord::~VkResourceRecord()
|
||||
void VkResourceRecord::MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize offset,
|
||||
VkDeviceSize size, FrameRefType refType)
|
||||
{
|
||||
MarkResourceFrameReferenced(mem, refType);
|
||||
if(refType != eFrameRef_Read && refType != eFrameRef_None)
|
||||
cmdInfo->dirtied.insert(mem);
|
||||
FrameRefType maxRef = MarkMemoryReferenced(cmdInfo->memFrameRefs, mem, offset, size, refType);
|
||||
MarkResourceFrameReferenced(
|
||||
mem, maxRef, [](FrameRefType x, FrameRefType y) -> FrameRefType { return std::max(x, y); });
|
||||
}
|
||||
|
||||
void VkResourceRecord::MarkBufferFrameReferenced(VkResourceRecord *buf, VkDeviceSize offset,
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/wrapped_pool.h"
|
||||
#include "core/intervals.h"
|
||||
#include "core/resource_manager.h"
|
||||
#include "vk_common.h"
|
||||
#include "vk_hookset_defs.h"
|
||||
@@ -906,6 +907,8 @@ struct ResourceInfo
|
||||
void Update(uint32_t numBindings, const VkSparseImageMemoryBind *pBindings);
|
||||
};
|
||||
|
||||
struct MemRefs;
|
||||
|
||||
struct CmdBufferRecordingInfo
|
||||
{
|
||||
VkDevice device;
|
||||
@@ -930,6 +933,8 @@ struct CmdBufferRecordingInfo
|
||||
|
||||
vector<VkResourceRecord *> subcmds;
|
||||
|
||||
std::map<ResourceId, MemRefs> memFrameRefs;
|
||||
|
||||
// AdvanceFrame/Present should be called after this buffer is submitted
|
||||
bool present;
|
||||
};
|
||||
@@ -959,6 +964,7 @@ struct DescriptorSetData
|
||||
// mapping information
|
||||
static const uint32_t SPARSE_REF_BIT = 0x80000000;
|
||||
map<ResourceId, pair<uint32_t, FrameRefType> > bindFrameRefs;
|
||||
map<ResourceId, MemRefs> bindMemRefs;
|
||||
};
|
||||
|
||||
struct PipelineLayoutData
|
||||
@@ -997,6 +1003,77 @@ struct AttachmentInfo
|
||||
VkImageMemoryBarrier barrier;
|
||||
};
|
||||
|
||||
struct MemRefs
|
||||
{
|
||||
Intervals<FrameRefType> rangeRefs;
|
||||
inline MemRefs() {}
|
||||
inline MemRefs(VkDeviceSize offset, VkDeviceSize size, FrameRefType refType)
|
||||
{
|
||||
rangeRefs.update(offset, offset + size, refType, ComposeFrameRefs);
|
||||
}
|
||||
template <typename Compose>
|
||||
FrameRefType Update(VkDeviceSize offset, VkDeviceSize size, FrameRefType refType, Compose comp);
|
||||
inline FrameRefType Update(VkDeviceSize offset, VkDeviceSize size, FrameRefType refType)
|
||||
{
|
||||
return Update(offset, size, refType, ComposeFrameRefs);
|
||||
}
|
||||
template <typename Compose>
|
||||
FrameRefType Merge(MemRefs &other, Compose comp);
|
||||
inline FrameRefType Merge(MemRefs &other) { return Merge(other, ComposeFrameRefs); }
|
||||
};
|
||||
|
||||
template <typename Compose>
|
||||
FrameRefType MemRefs::Update(VkDeviceSize offset, VkDeviceSize size, FrameRefType refType,
|
||||
Compose comp)
|
||||
{
|
||||
FrameRefType maxRefType = eFrameRef_None;
|
||||
rangeRefs.update(offset, offset + size, refType,
|
||||
[&maxRefType, comp](FrameRefType oldRef, FrameRefType newRef) -> FrameRefType {
|
||||
FrameRefType ref = comp(oldRef, newRef);
|
||||
maxRefType = std::max(maxRefType, ref);
|
||||
return ref;
|
||||
});
|
||||
return maxRefType;
|
||||
}
|
||||
|
||||
template <typename Compose>
|
||||
FrameRefType MemRefs::Merge(MemRefs &other, Compose comp)
|
||||
{
|
||||
FrameRefType maxRefType = eFrameRef_None;
|
||||
rangeRefs.merge(other.rangeRefs,
|
||||
[&maxRefType, comp](FrameRefType oldRef, FrameRefType newRef) -> FrameRefType {
|
||||
FrameRefType ref = comp(oldRef, newRef);
|
||||
maxRefType = std::max(maxRefType, ref);
|
||||
return ref;
|
||||
});
|
||||
return maxRefType;
|
||||
}
|
||||
|
||||
template <typename Compose>
|
||||
FrameRefType MarkMemoryReferenced(std::map<ResourceId, MemRefs> &memRefs, ResourceId mem,
|
||||
VkDeviceSize offset, VkDeviceSize size, FrameRefType refType,
|
||||
Compose comp)
|
||||
{
|
||||
if(refType == eFrameRef_None)
|
||||
return refType;
|
||||
auto refs = memRefs.find(mem);
|
||||
if(refs == memRefs.end())
|
||||
{
|
||||
memRefs.insert(std::make_pair(mem, MemRefs(offset, size, refType)));
|
||||
return refType;
|
||||
}
|
||||
else
|
||||
{
|
||||
return refs->second.Update(offset, size, refType, comp);
|
||||
}
|
||||
}
|
||||
|
||||
inline FrameRefType MarkMemoryReferenced(std::map<ResourceId, MemRefs> &memRefs, ResourceId mem,
|
||||
VkDeviceSize offset, VkDeviceSize size, FrameRefType refType)
|
||||
{
|
||||
return MarkMemoryReferenced(memRefs, mem, offset, size, refType, ComposeFrameRefs);
|
||||
}
|
||||
|
||||
struct DescUpdateTemplate;
|
||||
|
||||
struct VkResourceRecord : public ResourceRecord
|
||||
@@ -1030,6 +1107,7 @@ public:
|
||||
cmdInfo->imgbarriers.swap(bakedCommands->cmdInfo->imgbarriers);
|
||||
cmdInfo->subcmds.swap(bakedCommands->cmdInfo->subcmds);
|
||||
cmdInfo->sparse.swap(bakedCommands->cmdInfo->sparse);
|
||||
cmdInfo->memFrameRefs.swap(bakedCommands->cmdInfo->memFrameRefs);
|
||||
}
|
||||
|
||||
void AddBindFrameRef(ResourceId id, FrameRefType ref, bool hasSparse = false)
|
||||
@@ -1054,6 +1132,29 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void AddMemFrameRef(ResourceId mem, VkDeviceSize offset, VkDeviceSize size, FrameRefType refType)
|
||||
{
|
||||
if(mem == ResourceId())
|
||||
{
|
||||
RDCERR("Unexpected NULL resource ID being added as a bind frame ref");
|
||||
return;
|
||||
}
|
||||
pair<uint32_t, FrameRefType> &p = descInfo->bindFrameRefs[mem];
|
||||
if((p.first & ~DescriptorSetData::SPARSE_REF_BIT) == 0)
|
||||
{
|
||||
descInfo->bindMemRefs.erase(mem);
|
||||
p.first = 1;
|
||||
p.second = eFrameRef_None;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.first++;
|
||||
}
|
||||
FrameRefType maxRef = MarkMemoryReferenced(descInfo->bindMemRefs, mem, offset, size, refType,
|
||||
ComposeFrameRefsUnordered);
|
||||
p.second = std::max(p.second, maxRef);
|
||||
}
|
||||
|
||||
void RemoveBindFrameRef(ResourceId id)
|
||||
{
|
||||
// ignore any NULL IDs - probably an object that was
|
||||
|
||||
@@ -857,6 +857,7 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
|
||||
GetResourceManager()->MarkSparseMapReferenced(sparserecord->resInfo);
|
||||
}
|
||||
}
|
||||
GetResourceManager()->MergeReferencedMemory(setrecord->descInfo->bindMemRefs);
|
||||
}
|
||||
|
||||
for(auto it = record->bakedCommands->cmdInfo->sparse.begin();
|
||||
@@ -867,6 +868,8 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
|
||||
record->bakedCommands->AddResourceReferences(GetResourceManager());
|
||||
record->bakedCommands->AddReferencedIDs(refdIDs);
|
||||
|
||||
GetResourceManager()->MergeReferencedMemory(record->bakedCommands->cmdInfo->memFrameRefs);
|
||||
|
||||
// ref the parent command buffer's alloc record, this will pull in the cmd buffer pool
|
||||
GetResourceManager()->MarkResourceFrameReferenced(
|
||||
record->cmdInfo->allocRecord->GetResourceID(), eFrameRef_Read);
|
||||
@@ -876,6 +879,8 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddResourceReferences(
|
||||
GetResourceManager());
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddReferencedIDs(refdIDs);
|
||||
GetResourceManager()->MergeReferencedMemory(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->cmdInfo->memFrameRefs);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->cmdInfo->allocRecord->GetResourceID(),
|
||||
eFrameRef_Read);
|
||||
|
||||
Reference in New Issue
Block a user