Handle CmdWaitEvents by creating an event to set immediately before

This commit is contained in:
baldurk
2015-11-09 21:44:47 +01:00
parent a9bc609e48
commit 5b7f60ebe1
6 changed files with 59 additions and 44 deletions
-1
View File
@@ -25,7 +25,6 @@ Known Issues
========
* Memory/image barriers are as yet unverified, potentially could lead to bad capture or replay.
* GPU-GPU synchronisation with events might not work correctly.
* Sparse images with mips or array slices will not properly replay
* Stepping inside vkCmdExecuteCommands
* Only 2D non-array non-integer textures can currently be displayed.
+8 -2
View File
@@ -1259,11 +1259,17 @@ void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, u
std::sort(m_Events.begin(), m_Events.end(), SortEID());
m_ParentDrawcall.children.clear();
}
ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(GetDev()));
// destroy any events we created for waiting on
for(size_t i=0; i < m_CleanupEvents.size(); i++)
ObjDisp(GetDev())->DestroyEvent(Unwrap(GetDev()), m_CleanupEvents[i]);
m_CleanupEvents.clear();
if(m_PartialReplayData.resultPartialCmdBuffer != VK_NULL_HANDLE)
{
ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(m_PartialReplayData.partialDevice));
// deliberately call our own function, so this is destroyed as a wrapped object
vkDestroyCommandBuffer(m_PartialReplayData.partialDevice, m_PartialReplayData.resultPartialCmdBuffer);
m_PartialReplayData.resultPartialCmdBuffer = VK_NULL_HANDLE;
+2 -1
View File
@@ -214,7 +214,8 @@ private:
// -> flush/waitidle -> freecmds
} m_InternalCmds;
vector<VkDeviceMemory> m_FreeMems;
vector<VkDeviceMemory> m_CleanupMems;
vector<VkEvent> m_CleanupEvents;
// return the pre-selected device and queue
VkDevice GetDev() { RDCASSERT(m_Device != VK_NULL_HANDLE); return m_Device; }
+4 -4
View File
@@ -512,7 +512,7 @@ bool WrappedVulkan::Serialise_SparseInitialState(ResourceId id, WrappedVkBuffer
SAFE_DELETE_ARRAY(data);
m_FreeMems.push_back(mem);
m_CleanupMems.push_back(mem);
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(GetWrapped(buf), 0, (byte *)info));
}
@@ -723,7 +723,7 @@ bool WrappedVulkan::Serialise_SparseInitialState(ResourceId id, WrappedVkImage *
SAFE_DELETE_ARRAY(data);
m_FreeMems.push_back(mem);
m_CleanupMems.push_back(mem);
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(GetWrapped(buf), eInitialContents_Sparse, blob));
}
@@ -1575,7 +1575,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res)
ObjDisp(d)->FreeMemory(Unwrap(d), uploadmem);
// remember to free this memory on shutdown
m_FreeMems.push_back(mem);
m_CleanupMems.push_back(mem);
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(GetWrapped(im), 0, NULL));
}
@@ -1639,7 +1639,7 @@ bool WrappedVulkan::Serialise_InitialState(WrappedVkRes *res)
SAFE_DELETE_ARRAY(data);
m_FreeMems.push_back(mem);
m_CleanupMems.push_back(mem);
GetResourceManager()->SetInitialContents(id, VulkanResourceManager::InitialContentData(GetWrapped(buf), (uint32_t)dataSize, NULL));
}
@@ -166,12 +166,12 @@ void WrappedVulkan::Shutdown()
// no explicit vkDestroyDevice, we destroy the device here then the instance
// destroy any replay objects that aren't specifically to do with the frame capture
for(size_t i=0; i < m_FreeMems.size(); i++)
for(size_t i=0; i < m_CleanupMems.size(); i++)
{
ObjDisp(m_Device)->FreeMemory(Unwrap(m_Device), Unwrap(m_FreeMems[i]));
GetResourceManager()->ReleaseWrappedResource(m_FreeMems[i]);
ObjDisp(m_Device)->FreeMemory(Unwrap(m_Device), Unwrap(m_CleanupMems[i]));
GetResourceManager()->ReleaseWrappedResource(m_CleanupMems[i]);
}
m_FreeMems.clear();
m_CleanupMems.clear();
// destroy debug manager and any objects it created
SAFE_DELETE(m_DebugManager);
@@ -53,12 +53,11 @@
* DeviceWaitIdle.
*
* On the GPU-side, whenever a command buffer contains a CmdWaitEvents we
* currently just ignore it, assuming any previous work that it was intended
* to wait on has completed. VKTODOMED this might not be the case. Probably we
* will need to record any command buffers that do a CmdWaitEvents and ensure
* there's a sync. E.g. on submit, submit only that command buffer alone and
* then do DeviceWaitIdle, or at least do a GPU stall by inserting an event
* of our own - not the replays - to make the GPU wait.
* create an event, reset it, and call CmdSetEvent right before the
* CmdWaitEvents. This should provide the strictest possible ordering guarantee
* for the CmdWaitEvents (since the event set it was waiting on must have
* happened at or before where we are setting the event, so our event is as or
* more conservative than the original event).
*
* In future it would be nice to save the state of events at the start of
* the frame and restore them, via GetEventStatus/SetEvent/ResetEvent. However
@@ -151,8 +150,6 @@ bool WrappedVulkan::Serialise_vkGetFenceStatus(
{
device = GetResourceManager()->GetLiveHandle<VkDevice>(id);
// VKTODOLOW conservatively assume we have to wait for the device to be idle
// this could probably be smarter
ObjDisp(device)->DeviceWaitIdle(Unwrap(device));
}
@@ -203,9 +200,8 @@ bool WrappedVulkan::Serialise_vkResetFences(
if(m_State < WRITING)
{
// VKTODOMED does it even make sense to reset fences currently?
// when we wait on them, we wait for device idle (as we can't track
// and save/restore signalled status of fence).
// we don't care about fence states as we cannot record them perfectly and just
// do full waitidle flushes.
}
return true;
@@ -264,8 +260,6 @@ bool WrappedVulkan::Serialise_vkWaitForFences(
{
device = GetResourceManager()->GetLiveHandle<VkDevice>(id);
// VKTODOLOW conservatively assume we have to wait for the device to be idle
// this could probably be smarter
ObjDisp(device)->DeviceWaitIdle(Unwrap(device));
}
@@ -447,8 +441,6 @@ bool WrappedVulkan::Serialise_vkGetEventStatus(
{
device = GetResourceManager()->GetLiveHandle<VkDevice>(id);
// VKTODOLOW conservatively assume we have to wait for the device to be idle
// this could probably be smarter
ObjDisp(device)->DeviceWaitIdle(Unwrap(device));
}
@@ -687,22 +679,10 @@ bool WrappedVulkan::Serialise_vkCmdWaitEvents(
SERIALISE_ELEMENT(VkPipelineStageFlags, src, srcStageMask);
SERIALISE_ELEMENT(VkPipelineStageFlags, dest, destStageMask);
SERIALISE_ELEMENT(uint32_t, evcount, eventCount);
vector<VkEvent> events;
for(uint32_t i=0; i < evcount; i++)
{
ResourceId id;
if(m_State >= WRITING)
id = GetResID(pEvents[i]);
localSerialiser->Serialise("pEvents[]", id);
if(m_State < WRITING)
events.push_back(Unwrap(GetResourceManager()->GetLiveHandle<VkEvent>(id)));
}
// we don't serialise the original events as we are going to replace this
// with our own
// we keep the original memory barriers
SERIALISE_ELEMENT(uint32_t, memCount, memBarrierCount);
vector<VkGenericStruct*> mems;
@@ -749,7 +729,22 @@ bool WrappedVulkan::Serialise_vkCmdWaitEvents(
if(IsPartialCmd(cmdid) && InPartialRange())
{
cmdBuffer = PartialCmdBuf();
ObjDisp(cmdBuffer)->CmdWaitEvents(Unwrap(cmdBuffer), evcount, &events[0], src, dest, (uint32_t)mems.size(), (const void **)&mems[0]);
VkEventCreateInfo evInfo = {
VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, NULL, 0,
};
VkEvent ev = VK_NULL_HANDLE;
ObjDisp(cmdBuffer)->CreateEvent(Unwrap(GetDev()), &evInfo, &ev);
// don't wrap this event
ObjDisp(cmdBuffer)->ResetEvent(Unwrap(GetDev()), ev);
ObjDisp(cmdBuffer)->CmdSetEvent(Unwrap(cmdBuffer), ev, VK_PIPELINE_STAGE_ALL_GRAPHICS);
ObjDisp(cmdBuffer)->CmdWaitEvents(Unwrap(cmdBuffer), 1, &ev, src, dest, (uint32_t)mems.size(), (const void **)&mems[0]);
// register to clean this event up once we're done replaying this section of the log
m_CleanupEvents.push_back(ev);
ResourceId cmd = GetResID(PartialCmdBuf());
GetResourceManager()->RecordTransitions(m_BakedCmdBufferInfo[cmd].imgtransitions, m_ImageLayouts, (uint32_t)imTrans.size(), &imTrans[0]);
@@ -759,7 +754,21 @@ bool WrappedVulkan::Serialise_vkCmdWaitEvents(
{
cmdBuffer = GetResourceManager()->GetLiveHandle<VkCmdBuffer>(cmdid);
ObjDisp(cmdBuffer)->CmdWaitEvents(Unwrap(cmdBuffer), evcount, &events[0], src, dest, (uint32_t)mems.size(), (const void **)&mems[0]);
VkEventCreateInfo evInfo = {
VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, NULL, 0,
};
VkEvent ev = VK_NULL_HANDLE;
ObjDisp(cmdBuffer)->CreateEvent(Unwrap(GetDev()), &evInfo, &ev);
// don't wrap this event
ObjDisp(cmdBuffer)->ResetEvent(Unwrap(GetDev()), ev);
ObjDisp(cmdBuffer)->CmdSetEvent(Unwrap(cmdBuffer), ev, VK_PIPELINE_STAGE_ALL_GRAPHICS);
ObjDisp(cmdBuffer)->CmdWaitEvents(Unwrap(cmdBuffer), 1, &ev, src, dest, (uint32_t)mems.size(), (const void **)&mems[0]);
// register to clean this event up once we're done replaying this section of the log
m_CleanupEvents.push_back(ev);
ResourceId cmd = GetResID(cmdBuffer);
GetResourceManager()->RecordTransitions(m_BakedCmdBufferInfo[cmd].imgtransitions, m_ImageLayouts, (uint32_t)imTrans.size(), &imTrans[0]);