mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-08 08:40:55 +00:00
Expand locking around vulkan queues
* Submits need to be atomic vs starting and ending captures, or a partial submit could be included in the capture.
This commit is contained in:
@@ -1489,7 +1489,7 @@ void WrappedVulkan::StartFrameCapture(void *dev, void *wnd)
|
||||
// will check to see if they need to markdirty or markpendingdirty
|
||||
// and go into the frame record.
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
SCOPED_WRITELOCK(m_CapTransitionLock);
|
||||
|
||||
// wait for all work to finish and apply a memory barrier to ensure all memory is visible
|
||||
for(size_t i = 0; i < m_QueueFamilies.size(); i++)
|
||||
@@ -1627,7 +1627,7 @@ bool WrappedVulkan::EndFrameCapture(void *dev, void *wnd)
|
||||
|
||||
// transition back to IDLE atomically
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
SCOPED_WRITELOCK(m_CapTransitionLock);
|
||||
EndCaptureFrame(backbuffer);
|
||||
|
||||
m_State = CaptureState::BackgroundCapturing;
|
||||
@@ -1969,7 +1969,7 @@ bool WrappedVulkan::DiscardFrameCapture(void *dev, void *wnd)
|
||||
|
||||
// transition back to IDLE atomically
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
SCOPED_WRITELOCK(m_CapTransitionLock);
|
||||
|
||||
m_State = CaptureState::BackgroundCapturing;
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ private:
|
||||
VulkanShaderCache *m_ShaderCache = NULL;
|
||||
VulkanTextRenderer *m_TextRenderer = NULL;
|
||||
|
||||
Threading::CriticalSection m_CapTransitionLock;
|
||||
Threading::RWLock m_CapTransitionLock;
|
||||
|
||||
VulkanDrawcallCallback *m_DrawcallCallback;
|
||||
|
||||
|
||||
@@ -929,68 +929,69 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount,
|
||||
Unwrap(device), writeCount, unwrappedWrites, copyCount, unwrappedCopies));
|
||||
}
|
||||
|
||||
bool capframe = false;
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
capframe = IsActiveCapturing(m_State);
|
||||
}
|
||||
|
||||
if(capframe)
|
||||
{
|
||||
// don't have to mark referenced any of the resources pointed to by the descriptor set - that's
|
||||
// handled on queue submission by marking ref'd all the current bindings of the sets referenced
|
||||
// by the cmd buffer
|
||||
SCOPED_READLOCK(m_CapTransitionLock);
|
||||
|
||||
if(IsActiveCapturing(m_State))
|
||||
{
|
||||
CACHE_THREAD_SERIALISER();
|
||||
// don't have to mark referenced any of the resources pointed to by the descriptor set -
|
||||
// that's
|
||||
// handled on queue submission by marking ref'd all the current bindings of the sets
|
||||
// referenced
|
||||
// by the cmd buffer
|
||||
|
||||
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkUpdateDescriptorSets);
|
||||
Serialise_vkUpdateDescriptorSets(ser, device, writeCount, pDescriptorWrites, copyCount,
|
||||
pDescriptorCopies);
|
||||
|
||||
m_FrameCaptureRecord->AddChunk(scope.Get());
|
||||
}
|
||||
|
||||
// previously we would not mark descriptor set destinations as ref'd here. This is because all
|
||||
// descriptor sets are implicitly dirty and they're only actually *needed* when bound - we can
|
||||
// safely skip any updates of unused descriptor sets. However for consistency with template
|
||||
// updates below, we pull them in here even if they won't technically be needed.
|
||||
|
||||
for(uint32_t i = 0; i < writeCount; i++)
|
||||
{
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorWrites[i].dstSet),
|
||||
eFrameRef_PartialWrite);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < copyCount; i++)
|
||||
{
|
||||
// At the same time as ref'ing the source set, we must ref all of its resources (via the
|
||||
// bindFrameRefs). This is because they must be valid even if the source set is not ever bound
|
||||
// (and so its bindings aren't pulled in).
|
||||
//
|
||||
// We just ref all rather than looking at only the copied sets to keep things simple.
|
||||
// This does mean a slightly conservative ref'ing if the dest set doesn't end up getting
|
||||
// bound, but we only do this during frame capture so it's not too bad.
|
||||
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].dstSet),
|
||||
eFrameRef_PartialWrite);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].srcSet),
|
||||
eFrameRef_Read);
|
||||
|
||||
VkResourceRecord *setrecord = GetRecord(pDescriptorCopies[i].srcSet);
|
||||
|
||||
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);
|
||||
CACHE_THREAD_SERIALISER();
|
||||
|
||||
if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT)
|
||||
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkUpdateDescriptorSets);
|
||||
Serialise_vkUpdateDescriptorSets(ser, device, writeCount, pDescriptorWrites, copyCount,
|
||||
pDescriptorCopies);
|
||||
|
||||
m_FrameCaptureRecord->AddChunk(scope.Get());
|
||||
}
|
||||
|
||||
// previously we would not mark descriptor set destinations as ref'd here. This is because all
|
||||
// descriptor sets are implicitly dirty and they're only actually *needed* when bound - we can
|
||||
// safely skip any updates of unused descriptor sets. However for consistency with template
|
||||
// updates below, we pull them in here even if they won't technically be needed.
|
||||
|
||||
for(uint32_t i = 0; i < writeCount; i++)
|
||||
{
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorWrites[i].dstSet),
|
||||
eFrameRef_PartialWrite);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < copyCount; i++)
|
||||
{
|
||||
// At the same time as ref'ing the source set, we must ref all of its resources (via the
|
||||
// bindFrameRefs). This is because they must be valid even if the source set is not ever
|
||||
// bound
|
||||
// (and so its bindings aren't pulled in).
|
||||
//
|
||||
// We just ref all rather than looking at only the copied sets to keep things simple.
|
||||
// This does mean a slightly conservative ref'ing if the dest set doesn't end up getting
|
||||
// bound, but we only do this during frame capture so it's not too bad.
|
||||
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].dstSet),
|
||||
eFrameRef_PartialWrite);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].srcSet),
|
||||
eFrameRef_Read);
|
||||
|
||||
VkResourceRecord *setrecord = GetRecord(pDescriptorCopies[i].srcSet);
|
||||
|
||||
SCOPED_LOCK(setrecord->descInfo->refLock);
|
||||
|
||||
for(auto refit = setrecord->descInfo->bindFrameRefs.begin();
|
||||
refit != setrecord->descInfo->bindFrameRefs.end(); ++refit)
|
||||
{
|
||||
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(refit->first);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second);
|
||||
|
||||
GetResourceManager()->MarkSparseMapReferenced(record->resInfo);
|
||||
if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT)
|
||||
{
|
||||
VkResourceRecord *record = GetResourceManager()->GetResourceRecord(refit->first);
|
||||
|
||||
GetResourceManager()->MarkSparseMapReferenced(record->resInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1360,27 +1361,25 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate(
|
||||
Unwrap(device), Unwrap(descriptorSet), Unwrap(descriptorUpdateTemplate), memory));
|
||||
}
|
||||
|
||||
bool capframe = false;
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
capframe = IsActiveCapturing(m_State);
|
||||
}
|
||||
SCOPED_READLOCK(m_CapTransitionLock);
|
||||
|
||||
if(capframe)
|
||||
{
|
||||
CACHE_THREAD_SERIALISER();
|
||||
if(IsActiveCapturing(m_State))
|
||||
{
|
||||
CACHE_THREAD_SERIALISER();
|
||||
|
||||
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkUpdateDescriptorSetWithTemplate);
|
||||
Serialise_vkUpdateDescriptorSetWithTemplate(ser, device, descriptorSet,
|
||||
descriptorUpdateTemplate, pData);
|
||||
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkUpdateDescriptorSetWithTemplate);
|
||||
Serialise_vkUpdateDescriptorSetWithTemplate(ser, device, descriptorSet,
|
||||
descriptorUpdateTemplate, pData);
|
||||
|
||||
m_FrameCaptureRecord->AddChunk(scope.Get());
|
||||
m_FrameCaptureRecord->AddChunk(scope.Get());
|
||||
|
||||
// mark the destination set and template as referenced
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(descriptorSet),
|
||||
eFrameRef_PartialWrite);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(descriptorUpdateTemplate),
|
||||
eFrameRef_Read);
|
||||
// mark the destination set and template as referenced
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(descriptorSet),
|
||||
eFrameRef_PartialWrite);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(descriptorUpdateTemplate),
|
||||
eFrameRef_Read);
|
||||
}
|
||||
}
|
||||
|
||||
// need to track descriptor set contents whether capframing or idle
|
||||
|
||||
@@ -781,247 +781,249 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
|
||||
SERIALISE_TIME_CALL(ret = ObjDisp(queue)->QueueSubmit(Unwrap(queue), submitCount,
|
||||
unwrappedSubmits, Unwrap(fence)));
|
||||
|
||||
bool capframe = false;
|
||||
bool present = false;
|
||||
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
capframe = IsActiveCapturing(m_State);
|
||||
}
|
||||
SCOPED_READLOCK(m_CapTransitionLock);
|
||||
|
||||
std::set<ResourceId> refdIDs;
|
||||
bool capframe = IsActiveCapturing(m_State);
|
||||
|
||||
VkResourceRecord *queueRecord = GetRecord(queue);
|
||||
std::set<ResourceId> refdIDs;
|
||||
|
||||
for(uint32_t s = 0; s < submitCount; s++)
|
||||
{
|
||||
for(uint32_t i = 0; i < pSubmits[s].commandBufferCount; i++)
|
||||
VkResourceRecord *queueRecord = GetRecord(queue);
|
||||
|
||||
for(uint32_t s = 0; s < submitCount; s++)
|
||||
{
|
||||
ResourceId cmd = GetResID(pSubmits[s].pCommandBuffers[i]);
|
||||
|
||||
VkResourceRecord *record = GetRecord(pSubmits[s].pCommandBuffers[i]);
|
||||
present |= record->bakedCommands->cmdInfo->present;
|
||||
|
||||
for(uint32_t i = 0; i < pSubmits[s].commandBufferCount; i++)
|
||||
{
|
||||
SCOPED_LOCK(m_ImageLayoutsLock);
|
||||
GetResourceManager()->ApplyBarriers(queueRecord->queueFamilyIndex,
|
||||
record->bakedCommands->cmdInfo->imgbarriers,
|
||||
m_ImageLayouts);
|
||||
}
|
||||
ResourceId cmd = GetResID(pSubmits[s].pCommandBuffers[i]);
|
||||
|
||||
for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
|
||||
it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
|
||||
{
|
||||
if(GetResourceManager()->HasCurrentResource(*it))
|
||||
GetResourceManager()->MarkDirtyResource(*it);
|
||||
}
|
||||
VkResourceRecord *record = GetRecord(pSubmits[s].pCommandBuffers[i]);
|
||||
present |= record->bakedCommands->cmdInfo->present;
|
||||
|
||||
// with EXT_descriptor_indexing a binding might have been updated after
|
||||
// vkCmdBindDescriptorSets, so we need to track dirtied here at the last second.
|
||||
for(auto it = record->bakedCommands->cmdInfo->boundDescSets.begin();
|
||||
it != record->bakedCommands->cmdInfo->boundDescSets.end(); ++it)
|
||||
{
|
||||
VkResourceRecord *setrecord = GetRecord(*it);
|
||||
|
||||
SCOPED_LOCK(setrecord->descInfo->refLock);
|
||||
|
||||
const std::map<ResourceId, rdcpair<uint32_t, FrameRefType>> &frameRefs =
|
||||
setrecord->descInfo->bindFrameRefs;
|
||||
|
||||
for(auto refit = frameRefs.begin(); refit != frameRefs.end(); ++refit)
|
||||
{
|
||||
if(refit->second.second == eFrameRef_PartialWrite ||
|
||||
refit->second.second == eFrameRef_ReadBeforeWrite)
|
||||
{
|
||||
if(GetResourceManager()->HasCurrentResource(refit->first))
|
||||
GetResourceManager()->MarkDirtyResource(refit->first);
|
||||
}
|
||||
SCOPED_LOCK(m_ImageLayoutsLock);
|
||||
GetResourceManager()->ApplyBarriers(queueRecord->queueFamilyIndex,
|
||||
record->bakedCommands->cmdInfo->imgbarriers,
|
||||
m_ImageLayouts);
|
||||
}
|
||||
}
|
||||
|
||||
if(capframe)
|
||||
{
|
||||
// for each bound descriptor set, mark it referenced as well as all resources currently
|
||||
// bound to it
|
||||
for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
|
||||
it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
|
||||
{
|
||||
if(GetResourceManager()->HasCurrentResource(*it))
|
||||
GetResourceManager()->MarkDirtyResource(*it);
|
||||
}
|
||||
|
||||
// with EXT_descriptor_indexing a binding might have been updated after
|
||||
// vkCmdBindDescriptorSets, so we need to track dirtied here at the last second.
|
||||
for(auto it = record->bakedCommands->cmdInfo->boundDescSets.begin();
|
||||
it != record->bakedCommands->cmdInfo->boundDescSets.end(); ++it)
|
||||
{
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(*it), eFrameRef_Read);
|
||||
|
||||
VkResourceRecord *setrecord = GetRecord(*it);
|
||||
|
||||
SCOPED_LOCK(setrecord->descInfo->refLock);
|
||||
|
||||
for(auto refit = setrecord->descInfo->bindFrameRefs.begin();
|
||||
refit != setrecord->descInfo->bindFrameRefs.end(); ++refit)
|
||||
const std::map<ResourceId, rdcpair<uint32_t, FrameRefType>> &frameRefs =
|
||||
setrecord->descInfo->bindFrameRefs;
|
||||
|
||||
for(auto refit = frameRefs.begin(); refit != frameRefs.end(); ++refit)
|
||||
{
|
||||
refdIDs.insert(refit->first);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second);
|
||||
|
||||
if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT)
|
||||
if(refit->second.second == eFrameRef_PartialWrite ||
|
||||
refit->second.second == eFrameRef_ReadBeforeWrite)
|
||||
{
|
||||
VkResourceRecord *sparserecord = GetResourceManager()->GetResourceRecord(refit->first);
|
||||
|
||||
GetResourceManager()->MarkSparseMapReferenced(sparserecord->resInfo);
|
||||
if(GetResourceManager()->HasCurrentResource(refit->first))
|
||||
GetResourceManager()->MarkDirtyResource(refit->first);
|
||||
}
|
||||
}
|
||||
GetResourceManager()->MergeReferencedImages(setrecord->descInfo->bindImgRefs);
|
||||
GetResourceManager()->MergeReferencedMemory(setrecord->descInfo->bindMemRefs);
|
||||
}
|
||||
|
||||
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());
|
||||
record->bakedCommands->AddReferencedIDs(refdIDs);
|
||||
|
||||
GetResourceManager()->MergeReferencedImages(record->bakedCommands->cmdInfo->imgFrameRefs);
|
||||
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);
|
||||
|
||||
for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++)
|
||||
if(capframe)
|
||||
{
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddResourceReferences(
|
||||
GetResourceManager());
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddReferencedIDs(refdIDs);
|
||||
GetResourceManager()->MergeReferencedImages(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->cmdInfo->imgFrameRefs);
|
||||
GetResourceManager()->MergeReferencedMemory(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->cmdInfo->memFrameRefs);
|
||||
// for each bound descriptor set, mark it referenced as well as all resources currently
|
||||
// bound to it
|
||||
for(auto it = record->bakedCommands->cmdInfo->boundDescSets.begin();
|
||||
it != record->bakedCommands->cmdInfo->boundDescSets.end(); ++it)
|
||||
{
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(*it), eFrameRef_Read);
|
||||
|
||||
VkResourceRecord *setrecord = GetRecord(*it);
|
||||
|
||||
SCOPED_LOCK(setrecord->descInfo->refLock);
|
||||
|
||||
for(auto refit = setrecord->descInfo->bindFrameRefs.begin();
|
||||
refit != setrecord->descInfo->bindFrameRefs.end(); ++refit)
|
||||
{
|
||||
refdIDs.insert(refit->first);
|
||||
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()->MergeReferencedImages(setrecord->descInfo->bindImgRefs);
|
||||
GetResourceManager()->MergeReferencedMemory(setrecord->descInfo->bindMemRefs);
|
||||
}
|
||||
|
||||
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());
|
||||
record->bakedCommands->AddReferencedIDs(refdIDs);
|
||||
|
||||
GetResourceManager()->MergeReferencedImages(record->bakedCommands->cmdInfo->imgFrameRefs);
|
||||
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->bakedCommands->cmdInfo->subcmds[sub]->cmdInfo->allocRecord->GetResourceID(),
|
||||
eFrameRef_Read);
|
||||
record->cmdInfo->allocRecord->GetResourceID(), eFrameRef_Read);
|
||||
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddRef();
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_LOCK(m_CmdBufferRecordsLock);
|
||||
m_CmdBufferRecords.push_back(record->bakedCommands);
|
||||
for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++)
|
||||
m_CmdBufferRecords.push_back(record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands);
|
||||
{
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddResourceReferences(
|
||||
GetResourceManager());
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddReferencedIDs(refdIDs);
|
||||
GetResourceManager()->MergeReferencedImages(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->cmdInfo->imgFrameRefs);
|
||||
GetResourceManager()->MergeReferencedMemory(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->cmdInfo->memFrameRefs);
|
||||
GetResourceManager()->MarkResourceFrameReferenced(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->cmdInfo->allocRecord->GetResourceID(),
|
||||
eFrameRef_Read);
|
||||
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddRef();
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_LOCK(m_CmdBufferRecordsLock);
|
||||
m_CmdBufferRecords.push_back(record->bakedCommands);
|
||||
for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++)
|
||||
m_CmdBufferRecords.push_back(
|
||||
record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands);
|
||||
}
|
||||
|
||||
record->bakedCommands->AddRef();
|
||||
}
|
||||
|
||||
record->bakedCommands->AddRef();
|
||||
record->cmdInfo->dirtied.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if(capframe)
|
||||
{
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(queue), eFrameRef_Read);
|
||||
|
||||
if(fence != VK_NULL_HANDLE)
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(fence), eFrameRef_Read);
|
||||
|
||||
std::vector<VkResourceRecord *> maps;
|
||||
{
|
||||
SCOPED_LOCK(m_CoherentMapsLock);
|
||||
maps = m_CoherentMaps;
|
||||
}
|
||||
|
||||
record->cmdInfo->dirtied.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if(capframe)
|
||||
{
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(queue), eFrameRef_Read);
|
||||
|
||||
if(fence != VK_NULL_HANDLE)
|
||||
GetResourceManager()->MarkResourceFrameReferenced(GetResID(fence), eFrameRef_Read);
|
||||
|
||||
std::vector<VkResourceRecord *> maps;
|
||||
{
|
||||
SCOPED_LOCK(m_CoherentMapsLock);
|
||||
maps = m_CoherentMaps;
|
||||
}
|
||||
|
||||
for(auto it = maps.begin(); it != maps.end(); ++it)
|
||||
{
|
||||
VkResourceRecord *record = *it;
|
||||
MemMapState &state = *record->memMapState;
|
||||
|
||||
// potential persistent map
|
||||
if(state.mapCoherent && state.mappedPtr && !state.mapFlushed)
|
||||
for(auto it = maps.begin(); it != maps.end(); ++it)
|
||||
{
|
||||
// only need to flush memory that could affect this submitted batch of work
|
||||
if(refdIDs.find(record->GetResourceID()) == refdIDs.end())
|
||||
{
|
||||
RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing",
|
||||
record->GetResourceID());
|
||||
continue;
|
||||
}
|
||||
VkResourceRecord *record = *it;
|
||||
MemMapState &state = *record->memMapState;
|
||||
|
||||
size_t diffStart = 0, diffEnd = 0;
|
||||
bool found = true;
|
||||
// potential persistent map
|
||||
if(state.mapCoherent && state.mappedPtr && !state.mapFlushed)
|
||||
{
|
||||
// only need to flush memory that could affect this submitted batch of work
|
||||
if(refdIDs.find(record->GetResourceID()) == refdIDs.end())
|
||||
{
|
||||
RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing",
|
||||
record->GetResourceID());
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t diffStart = 0, diffEnd = 0;
|
||||
bool found = true;
|
||||
|
||||
// enabled as this is necessary for programs with very large coherent mappings
|
||||
// (> 1GB) as otherwise more than a couple of vkQueueSubmit calls leads to vast
|
||||
// memory allocation. There might still be bugs lurking in here though
|
||||
#if 1
|
||||
// this causes vkFlushMappedMemoryRanges call to allocate and copy to refData
|
||||
// from serialised buffer. We want to copy *precisely* the serialised data,
|
||||
// otherwise there is a gap in time between serialising out a snapshot of
|
||||
// the buffer and whenever we then copy into the ref data, e.g. below.
|
||||
// during this time, data could be written to the buffer and it won't have
|
||||
// been caught in the serialised snapshot, and if it doesn't change then
|
||||
// it *also* won't be caught in any future FindDiffRange() calls.
|
||||
//
|
||||
// Likewise once refData is allocated, the call below will also update it
|
||||
// with the data serialised out for the same reason.
|
||||
//
|
||||
// Note: it's still possible that data is being written to by the
|
||||
// application while it's being serialised out in the snapshot below. That
|
||||
// is OK, since the application is responsible for ensuring it's not writing
|
||||
// data that would be needed by the GPU in this submit. As long as the
|
||||
// refdata we use for future use is identical to what was serialised, we
|
||||
// shouldn't miss anything
|
||||
state.needRefData = true;
|
||||
// this causes vkFlushMappedMemoryRanges call to allocate and copy to refData
|
||||
// from serialised buffer. We want to copy *precisely* the serialised data,
|
||||
// otherwise there is a gap in time between serialising out a snapshot of
|
||||
// the buffer and whenever we then copy into the ref data, e.g. below.
|
||||
// during this time, data could be written to the buffer and it won't have
|
||||
// been caught in the serialised snapshot, and if it doesn't change then
|
||||
// it *also* won't be caught in any future FindDiffRange() calls.
|
||||
//
|
||||
// Likewise once refData is allocated, the call below will also update it
|
||||
// with the data serialised out for the same reason.
|
||||
//
|
||||
// Note: it's still possible that data is being written to by the
|
||||
// application while it's being serialised out in the snapshot below. That
|
||||
// is OK, since the application is responsible for ensuring it's not writing
|
||||
// data that would be needed by the GPU in this submit. As long as the
|
||||
// refdata we use for future use is identical to what was serialised, we
|
||||
// shouldn't miss anything
|
||||
state.needRefData = true;
|
||||
|
||||
// if we have a previous set of data, compare.
|
||||
// otherwise just serialise it all
|
||||
if(state.refData)
|
||||
found = FindDiffRange((byte *)state.mappedPtr, state.refData, (size_t)state.mapSize,
|
||||
diffStart, diffEnd);
|
||||
else
|
||||
// if we have a previous set of data, compare.
|
||||
// otherwise just serialise it all
|
||||
if(state.refData)
|
||||
found = FindDiffRange((byte *)state.mappedPtr, state.refData, (size_t)state.mapSize,
|
||||
diffStart, diffEnd);
|
||||
else
|
||||
#endif
|
||||
diffEnd = (size_t)state.mapSize;
|
||||
|
||||
if(found)
|
||||
{
|
||||
// MULTIDEVICE should find the device for this queue.
|
||||
// MULTIDEVICE only want to flush maps associated with this queue
|
||||
VkDevice dev = GetDev();
|
||||
diffEnd = (size_t)state.mapSize;
|
||||
|
||||
if(found)
|
||||
{
|
||||
RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", record->GetResourceID(),
|
||||
(uint64_t)diffStart, (uint64_t)diffEnd);
|
||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, NULL,
|
||||
(VkDeviceMemory)(uint64_t)record->Resource,
|
||||
state.mapOffset + diffStart, diffEnd - diffStart};
|
||||
vkFlushMappedMemoryRanges(dev, 1, &range);
|
||||
state.mapFlushed = false;
|
||||
}
|
||||
// MULTIDEVICE should find the device for this queue.
|
||||
// MULTIDEVICE only want to flush maps associated with this queue
|
||||
VkDevice dev = GetDev();
|
||||
|
||||
GetResourceManager()->MarkDirtyResource(record->GetResourceID());
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCDEBUG("Persistent map flush not needed for %llu", record->GetResourceID());
|
||||
{
|
||||
RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", record->GetResourceID(),
|
||||
(uint64_t)diffStart, (uint64_t)diffEnd);
|
||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, NULL,
|
||||
(VkDeviceMemory)(uint64_t)record->Resource,
|
||||
state.mapOffset + diffStart, diffEnd - diffStart};
|
||||
vkFlushMappedMemoryRanges(dev, 1, &range);
|
||||
state.mapFlushed = false;
|
||||
}
|
||||
|
||||
GetResourceManager()->MarkDirtyResource(record->GetResourceID());
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCDEBUG("Persistent map flush not needed for %llu", record->GetResourceID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
CACHE_THREAD_SERIALISER();
|
||||
{
|
||||
CACHE_THREAD_SERIALISER();
|
||||
|
||||
ser.SetDrawChunk();
|
||||
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkQueueSubmit);
|
||||
Serialise_vkQueueSubmit(ser, queue, submitCount, pSubmits, fence);
|
||||
ser.SetDrawChunk();
|
||||
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkQueueSubmit);
|
||||
Serialise_vkQueueSubmit(ser, queue, submitCount, pSubmits, fence);
|
||||
|
||||
m_FrameCaptureRecord->AddChunk(scope.Get());
|
||||
}
|
||||
m_FrameCaptureRecord->AddChunk(scope.Get());
|
||||
}
|
||||
|
||||
for(uint32_t s = 0; s < submitCount; s++)
|
||||
{
|
||||
for(uint32_t sem = 0; sem < pSubmits[s].waitSemaphoreCount; sem++)
|
||||
GetResourceManager()->MarkResourceFrameReferenced(
|
||||
GetResID(pSubmits[s].pWaitSemaphores[sem]), eFrameRef_Read);
|
||||
for(uint32_t s = 0; s < submitCount; s++)
|
||||
{
|
||||
for(uint32_t sem = 0; sem < pSubmits[s].waitSemaphoreCount; sem++)
|
||||
GetResourceManager()->MarkResourceFrameReferenced(
|
||||
GetResID(pSubmits[s].pWaitSemaphores[sem]), eFrameRef_Read);
|
||||
|
||||
for(uint32_t sem = 0; sem < pSubmits[s].signalSemaphoreCount; sem++)
|
||||
GetResourceManager()->MarkResourceFrameReferenced(
|
||||
GetResID(pSubmits[s].pSignalSemaphores[sem]), eFrameRef_Read);
|
||||
for(uint32_t sem = 0; sem < pSubmits[s].signalSemaphoreCount; sem++)
|
||||
GetResourceManager()->MarkResourceFrameReferenced(
|
||||
GetResID(pSubmits[s].pSignalSemaphores[sem]), eFrameRef_Read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -634,7 +634,7 @@ void WrappedVulkan::vkUnmapMemory(VkDevice device, VkDeviceMemory mem)
|
||||
|
||||
bool capframe = false;
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
SCOPED_READLOCK(m_CapTransitionLock);
|
||||
capframe = IsActiveCapturing(m_State);
|
||||
|
||||
if(!capframe)
|
||||
@@ -783,7 +783,7 @@ VkResult WrappedVulkan::vkFlushMappedMemoryRanges(VkDevice device, uint32_t memR
|
||||
{
|
||||
bool capframe = false;
|
||||
{
|
||||
SCOPED_LOCK(m_CapTransitionLock);
|
||||
SCOPED_READLOCK(m_CapTransitionLock);
|
||||
capframe = IsActiveCapturing(m_State);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user