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:
Benson Joeris
2019-02-01 12:50:51 -05:00
committed by Baldur Karlsson
parent 3bc53094da
commit 2828232ae8
9 changed files with 197 additions and 36 deletions
-22
View File
@@ -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)
+49 -4
View File
@@ -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)
{
+10 -8
View File
@@ -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);
}
}
+3
View File
@@ -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();
+20 -1
View File
@@ -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)
+4
View File
@@ -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;
};
+5 -1
View File
@@ -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,
+101
View File
@@ -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);