From 72bae9bdc9b99ab875044cc1c966284ae1c7273c Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 27 Jul 2017 14:50:42 +0100 Subject: [PATCH] Re-organise debug marker handling during replay * Where available or allowed, we replay the captured user markers. * When we're doing partial replay and we only push some of the markers then stop, we keep track of how many were pushed so we can pop them again and keep things balanced. * Also for renderdoc internal book-keeping around the frame replay itself we explicitly annotate the renderdoc internals * On vulkan since there are no queue-level markers, we fire single-shot command buffers that do nothing but push/pop/insert a marker. --- renderdoc/driver/d3d11/d3d11_common.cpp | 24 +++-- renderdoc/driver/d3d11/d3d11_common.h | 2 + renderdoc/driver/d3d11/d3d11_context_wrap.cpp | 15 +++ renderdoc/driver/d3d11/d3d11_device.cpp | 27 +++--- renderdoc/driver/d3d11/d3d11_device.h | 3 + renderdoc/driver/d3d12/d3d12_command_list.h | 2 + .../driver/d3d12/d3d12_command_list_wrap.cpp | 63 +++++++++++- renderdoc/driver/d3d12/d3d12_commands.h | 4 + renderdoc/driver/d3d12/d3d12_common.cpp | 50 +++++++++- renderdoc/driver/d3d12/d3d12_common.h | 13 ++- renderdoc/driver/d3d12/d3d12_device.cpp | 25 ++++- renderdoc/driver/gl/gl_common.cpp | 12 ++- renderdoc/driver/gl/gl_common.h | 3 + renderdoc/driver/gl/gl_driver.cpp | 30 +++--- renderdoc/driver/gl/gl_driver.h | 2 + .../driver/gl/wrappers/gl_debug_funcs.cpp | 20 +++- renderdoc/driver/vulkan/vk_common.cpp | 96 +++++++++++++++++++ renderdoc/driver/vulkan/vk_common.h | 23 +++++ renderdoc/driver/vulkan/vk_core.cpp | 9 ++ renderdoc/driver/vulkan/vk_core.h | 2 + .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 85 +++++++++++++++- .../vulkan/wrappers/vk_device_funcs.cpp | 8 ++ 22 files changed, 463 insertions(+), 55 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_common.cpp b/renderdoc/driver/d3d11/d3d11_common.cpp index f142d5e90..b9c6795c2 100644 --- a/renderdoc/driver/d3d11/d3d11_common.cpp +++ b/renderdoc/driver/d3d11/d3d11_common.cpp @@ -34,13 +34,12 @@ WrappedID3D11Device *D3D11MarkerRegion::device; D3D11MarkerRegion::D3D11MarkerRegion(const std::string &marker) { - if(device == NULL) - return; + D3D11MarkerRegion::Begin(marker); +} - ID3DUserDefinedAnnotation *annot = device->GetAnnotations(); - - if(annot) - annot->BeginEvent(StringFormat::UTF82Wide(marker).c_str()); +D3D11MarkerRegion::~D3D11MarkerRegion() +{ + D3D11MarkerRegion::End(); } void D3D11MarkerRegion::Set(const std::string &marker) @@ -54,7 +53,18 @@ void D3D11MarkerRegion::Set(const std::string &marker) annot->SetMarker(StringFormat::UTF82Wide(marker).c_str()); } -D3D11MarkerRegion::~D3D11MarkerRegion() +void D3D11MarkerRegion::Begin(const std::string &marker) +{ + if(device == NULL) + return; + + ID3DUserDefinedAnnotation *annot = device->GetAnnotations(); + + if(annot) + annot->BeginEvent(StringFormat::UTF82Wide(marker).c_str()); +} + +void D3D11MarkerRegion::End() { if(device == NULL) return; diff --git a/renderdoc/driver/d3d11/d3d11_common.h b/renderdoc/driver/d3d11/d3d11_common.h index 7fe6b4c5d..e101591f1 100644 --- a/renderdoc/driver/d3d11/d3d11_common.h +++ b/renderdoc/driver/d3d11/d3d11_common.h @@ -43,6 +43,8 @@ struct D3D11MarkerRegion D3D11MarkerRegion(const std::string &marker); ~D3D11MarkerRegion(); static void Set(const std::string &marker); + static void Begin(const std::string &marker); + static void End(); static WrappedID3D11Device *device; }; diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index 6f8c4375b..ab4b65b44 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -53,6 +53,9 @@ bool WrappedID3D11DeviceContext::Serialise_SetMarker(uint32_t col, const wchar_t m_pSerialiser->Serialise("Name", name); + if(m_State <= EXECUTING) + D3D11MarkerRegion::Set(name); + if(m_State == READING) { DrawcallDescription draw; @@ -89,6 +92,12 @@ bool WrappedID3D11DeviceContext::Serialise_PushEvent(uint32_t col, const wchar_t m_pSerialiser->Serialise("Name", name); + if(m_State <= EXECUTING) + { + D3D11MarkerRegion::Begin(name); + m_pDevice->ReplayPushEvent(); + } + if(m_State == READING) { DrawcallDescription draw; @@ -113,6 +122,12 @@ bool WrappedID3D11DeviceContext::Serialise_PushEvent(uint32_t col, const wchar_t bool WrappedID3D11DeviceContext::Serialise_PopEvent() { + if(m_State <= EXECUTING) + { + D3D11MarkerRegion::End(); + m_pDevice->ReplayPopEvent(); + } + if(m_State == READING && !m_CurEvents.empty()) { DrawcallDescription draw; diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index 6388f21fa..b7236f93d 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -2469,35 +2469,32 @@ void WrappedID3D11Device::ReplayLog(uint32_t startEventID, uint32_t endEventID, if(!partial) { - D3D11MarkerRegion apply("ApplyInitialContents"); + D3D11MarkerRegion apply("!!!!RenderDoc Internal: ApplyInitialContents"); GetResourceManager()->ApplyInitialContents(); GetResourceManager()->ReleaseInFrameResources(); } m_State = EXECUTING; + D3D11MarkerRegion::Set(StringFormat::Fmt("!!!!RenderDoc Internal: Replay %d (%d): %u->%u", + (int)replayType, (int)partial, startEventID, endEventID)); + + m_ReplayEventCount = 0; + if(replayType == eReplay_Full) - { - D3D11MarkerRegion exec( - StringFormat::Fmt("Replay: Full %u->%u (partial %u)", startEventID, endEventID, partial)); m_pImmediateContext->ReplayLog(EXECUTING, startEventID, endEventID, partial); - } else if(replayType == eReplay_WithoutDraw) - { - D3D11MarkerRegion exec(StringFormat::Fmt("Replay: W/O Draw %u->%u (partial %u)", startEventID, - endEventID, partial)); m_pImmediateContext->ReplayLog(EXECUTING, startEventID, RDCMAX(1U, endEventID) - 1, partial); - } else if(replayType == eReplay_OnlyDraw) - { - D3D11MarkerRegion exec(StringFormat::Fmt("Replay: Draw Only %u->%u (partial %u)", endEventID, - endEventID, partial)); m_pImmediateContext->ReplayLog(EXECUTING, endEventID, endEventID, partial); - } else - { RDCFATAL("Unexpected replay type"); - } + + // make sure to end any unbalanced replay events if we stopped in the middle of a frame + for(int i = 0; i < m_ReplayEventCount; i++) + D3D11MarkerRegion::End(); + + D3D11MarkerRegion::Set("!!!!RenderDoc Internal: Done replay"); } void WrappedID3D11Device::ReleaseSwapchainResources(WrappedIDXGISwapChain4 *swap, UINT QueueCount, diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h index bf623c568..14d3a402d 100644 --- a/renderdoc/driver/d3d11/d3d11_device.h +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -327,6 +327,7 @@ private: WrappedID3D11Debug m_WrappedDebug; ID3DUserDefinedAnnotation *m_RealAnnotations; + int m_ReplayEventCount; unsigned int m_InternalRefcount; RefCounter m_RefCounter; @@ -434,6 +435,8 @@ public: FrameStatistics &GetFrameStats() { return m_FrameRecord.frameInfo.stats; } const DrawcallDescription *GetDrawcall(uint32_t eventID); + void ReplayPushEvent() { m_ReplayEventCount++; } + void ReplayPopEvent() { m_ReplayEventCount = RDCMAX(0, m_ReplayEventCount - 1); } void LockForChunkFlushing(); void UnlockForChunkFlushing(); void LockForChunkRemoval(); diff --git a/renderdoc/driver/d3d12/d3d12_command_list.h b/renderdoc/driver/d3d12/d3d12_command_list.h index 0b981fd48..301cf5a31 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list.h +++ b/renderdoc/driver/d3d12/d3d12_command_list.h @@ -123,7 +123,9 @@ public: WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; } D3D12ResourceRecord *GetResourceRecord() { return m_ListRecord; } ID3D12GraphicsCommandList *GetList(ResourceId id); + ID3D12GraphicsCommandList *GetWrappedList(ResourceId id); ID3D12GraphicsCommandList *GetCrackedList(ResourceId id); + ID3D12GraphicsCommandList *GetWrappedCrackedList(ResourceId id); void SetCommandData(D3D12CommandData *cmd) { m_Cmd = cmd; } void SetInitParams(REFIID riid, UINT nodeMask, D3D12_COMMAND_LIST_TYPE type) diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index a7b167d3b..1134a5bbc 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -30,11 +30,21 @@ ID3D12GraphicsCommandList *WrappedID3D12GraphicsCommandList::GetList(ResourceId return GetResourceManager()->GetLiveAs(id)->GetReal(); } +ID3D12GraphicsCommandList *WrappedID3D12GraphicsCommandList::GetWrappedList(ResourceId id) +{ + return GetResourceManager()->GetLiveAs(id); +} + ID3D12GraphicsCommandList *WrappedID3D12GraphicsCommandList::GetCrackedList(ResourceId id) { return Unwrap(m_Cmd->m_BakedCmdListInfo[id].crackedLists.back()); } +ID3D12GraphicsCommandList *WrappedID3D12GraphicsCommandList::GetWrappedCrackedList(ResourceId id) +{ + return m_Cmd->m_BakedCmdListInfo[id].crackedLists.back(); +} + bool WrappedID3D12GraphicsCommandList::Serialise_Close() { SERIALISE_ELEMENT(ResourceId, CommandList, GetResourceID()); @@ -63,6 +73,11 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Close() RDCDEBUG("Ending partial command list for %llu baked to %llu", CommandList, bakeId); #endif + int &markerCount = m_Cmd->m_BakedCmdListInfo[CommandList].markerCount; + + for(int i = 0; i < markerCount; i++) + D3D12MarkerRegion::End(list); + list->Close(); // erase the non-baked reference to this command list so that we don't have @@ -219,6 +234,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *p m_Cmd->m_RenderState.pipe = GetResID(pInitialState); } + m_Cmd->m_BakedCmdListInfo[CommandList].markerCount = 0; m_Cmd->m_BakedCmdListInfo[CommandList].curEventID = 0; m_Cmd->m_BakedCmdListInfo[CommandList].executeEvents = m_Cmd->m_BakedCmdListInfo[bakeId].executeEvents; @@ -2653,8 +2669,20 @@ bool WrappedID3D12GraphicsCommandList::Serialise_SetMarker(UINT Metadata, const if(m_State < WRITING) m_Cmd->m_LastCmdListID = CommandList; - if(m_State == READING) + if(m_State == EXECUTING) { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); + + D3D12MarkerRegion::Set(list, markerText); + } + } + else if(m_State == READING) + { + D3D12MarkerRegion::Set(GetWrappedList(CommandList), markerText); + D3D12MarkerRegion::Set(GetWrappedCrackedList(CommandList), markerText); + DrawcallDescription draw; draw.name = markerText; draw.flags |= DrawFlags::SetMarker; @@ -2711,8 +2739,22 @@ bool WrappedID3D12GraphicsCommandList::Serialise_BeginEvent(UINT Metadata, const if(m_State < WRITING) m_Cmd->m_LastCmdListID = CommandList; - if(m_State == READING) + if(m_State == EXECUTING) { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); + + m_Cmd->m_BakedCmdListInfo[CommandList].markerCount++; + + D3D12MarkerRegion::Begin(list, markerText); + } + } + else if(m_State == READING) + { + D3D12MarkerRegion::Begin(GetWrappedList(CommandList), markerText); + D3D12MarkerRegion::Begin(GetWrappedCrackedList(CommandList), markerText); + DrawcallDescription draw; draw.name = markerText; draw.flags |= DrawFlags::PushMarker; @@ -2752,8 +2794,23 @@ bool WrappedID3D12GraphicsCommandList::Serialise_EndEvent() m_Cmd->AddDrawcall(draw, true); } - if(m_State == READING) + if(m_State == EXECUTING) { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); + + int &markerCount = m_Cmd->m_BakedCmdListInfo[CommandList].markerCount; + markerCount = RDCMAX(0, markerCount - 1); + + D3D12MarkerRegion::End(list); + } + } + else if(m_State == READING) + { + D3D12MarkerRegion::End(GetWrappedList(CommandList)); + D3D12MarkerRegion::End(GetWrappedCrackedList(CommandList)); + // dummy draw that is consumed when this command buffer // is being in-lined into the call stream DrawcallDescription draw; diff --git a/renderdoc/driver/d3d12/d3d12_commands.h b/renderdoc/driver/d3d12/d3d12_commands.h index 8b436edfe..b8ae20779 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.h +++ b/renderdoc/driver/d3d12/d3d12_commands.h @@ -192,6 +192,10 @@ struct BakedCmdListInfo ResourceId parentList; + // modified during recording to ensure we end any markers that should be ended but weren't due to + // a partial replay + int markerCount; + D3D12DrawcallTreeNode *draw; // the root draw to copy from when submitting uint32_t eventCount; // how many events are in this cmd list, for quick skipping uint32_t curEventID; // current event ID while reading or executing diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index a1f724d4d..fb4ffccd5 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -31,7 +31,29 @@ D3D12MarkerRegion::D3D12MarkerRegion(ID3D12GraphicsCommandList *l, const std::string &marker) { list = l; + queue = NULL; + D3D12MarkerRegion::Begin(list, marker); +} + +D3D12MarkerRegion::D3D12MarkerRegion(ID3D12CommandQueue *q, const std::string &marker) +{ + list = NULL; + queue = q; + + D3D12MarkerRegion::Begin(queue, marker); +} + +D3D12MarkerRegion::~D3D12MarkerRegion() +{ + if(list) + D3D12MarkerRegion::End(list); + if(queue) + D3D12MarkerRegion::End(queue); +} + +void D3D12MarkerRegion::Begin(ID3D12GraphicsCommandList *list, const std::string &marker) +{ if(list) { std::wstring text = StringFormat::UTF82Wide(marker); @@ -39,6 +61,15 @@ D3D12MarkerRegion::D3D12MarkerRegion(ID3D12GraphicsCommandList *l, const std::st } } +void D3D12MarkerRegion::Begin(ID3D12CommandQueue *queue, const std::string &marker) +{ + if(queue) + { + std::wstring text = StringFormat::UTF82Wide(marker); + queue->BeginEvent(0, text.c_str(), (UINT)text.size()); + } +} + void D3D12MarkerRegion::Set(ID3D12GraphicsCommandList *list, const std::string &marker) { if(list) @@ -48,10 +79,23 @@ void D3D12MarkerRegion::Set(ID3D12GraphicsCommandList *list, const std::string & } } -D3D12MarkerRegion::~D3D12MarkerRegion() +void D3D12MarkerRegion::Set(ID3D12CommandQueue *queue, const std::string &marker) { - if(list) - list->EndEvent(); + if(queue) + { + std::wstring text = StringFormat::UTF82Wide(marker); + queue->SetMarker(0, text.c_str(), (UINT)text.size()); + } +} + +void D3D12MarkerRegion::End(ID3D12GraphicsCommandList *list) +{ + list->EndEvent(); +} + +void D3D12MarkerRegion::End(ID3D12CommandQueue *queue) +{ + queue->EndEvent(); } TextureDim MakeTextureDim(D3D12_SRV_DIMENSION dim) diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 2d5fe776f..ac3833bbe 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -37,10 +37,19 @@ struct D3D12MarkerRegion { D3D12MarkerRegion(ID3D12GraphicsCommandList *list, const std::string &marker); + D3D12MarkerRegion(ID3D12CommandQueue *queue, const std::string &marker); ~D3D12MarkerRegion(); - static void Set(ID3D12GraphicsCommandList *list, const std::string &marker); - ID3D12GraphicsCommandList *list; + static void Set(ID3D12GraphicsCommandList *list, const std::string &marker); + static void Set(ID3D12CommandQueue *queue, const std::string &marker); + + static void Begin(ID3D12GraphicsCommandList *list, const std::string &marker); + static void End(ID3D12GraphicsCommandList *list); + static void Begin(ID3D12CommandQueue *queue, const std::string &marker); + static void End(ID3D12CommandQueue *queue); + + ID3D12GraphicsCommandList *list = NULL; + ID3D12CommandQueue *queue = NULL; }; inline void SetObjName(ID3D12Object *obj, const std::string &utf8name) diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index 515570b2f..9ea771e6b 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -589,7 +589,10 @@ void WrappedID3D12Device::ApplyInitialContents() // close the final list if(initStateCurList) + { + D3D12MarkerRegion::End(initStateCurList); initStateCurList->Close(); + } initStateCurBatch = 0; initStateCurList = NULL; @@ -2159,13 +2162,22 @@ ID3D12GraphicsCommandList *WrappedID3D12Device::GetInitialStateList() } if(initStateCurList == NULL) + { initStateCurList = GetNewList(); + if(m_State < WRITING) + { + D3D12MarkerRegion::Begin(initStateCurList, + "!!!!RenderDoc Internal: ApplyInitialContents batched list"); + } + } + return initStateCurList; } void WrappedID3D12Device::CloseInitialStateList() { + D3D12MarkerRegion::End(initStateCurList); initStateCurList->Close(); initStateCurList = NULL; initStateCurBatch = 0; @@ -2467,8 +2479,11 @@ void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID, if(!partial) { - ApplyInitialContents(); - GetResourceManager()->ReleaseInFrameResources(); + { + D3D12MarkerRegion apply(GetQueue(), "!!!!RenderDoc Internal: ApplyInitialContents"); + ApplyInitialContents(); + GetResourceManager()->ReleaseInFrameResources(); + } ExecuteLists(); FlushLists(true); @@ -2476,6 +2491,10 @@ void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID, m_State = EXECUTING; + D3D12MarkerRegion::Set( + GetQueue(), StringFormat::Fmt("!!!!RenderDoc Internal: RenderDoc Replay %d (%d): %u->%u", + (int)replayType, (int)partial, startEventID, endEventID)); + { D3D12CommandData &cmd = *m_Queue->GetCommandData(); @@ -2526,6 +2545,8 @@ void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID, #endif } + D3D12MarkerRegion::Set(GetQueue(), "!!!!RenderDoc Internal: Done replay"); + // ensure all UAV writes have finished before subsequent work ID3D12GraphicsCommandList *list = GetNewList(); diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 439f19fcb..9082c4ad0 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -738,6 +738,16 @@ void DoVendorChecks(const GLHookSet &gl, GLPlatform &platform, GLWindowingData c const GLHookSet *GLMarkerRegion::gl; GLMarkerRegion::GLMarkerRegion(const std::string &marker) +{ + Begin(marker); +} + +GLMarkerRegion::~GLMarkerRegion() +{ + End(); +} + +void GLMarkerRegion::Begin(const std::string &marker) { if(gl == NULL || !HasExt[KHR_debug] || !gl->glPushDebugGroup) return; @@ -754,7 +764,7 @@ void GLMarkerRegion::Set(const std::string &marker) eGL_DEBUG_SEVERITY_NOTIFICATION, -1, marker.c_str()); } -GLMarkerRegion::~GLMarkerRegion() +void GLMarkerRegion::End() { if(gl == NULL || !HasExt[KHR_debug] || !gl->glPopDebugGroup) return; diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 48da01959..5034dabca 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -250,7 +250,10 @@ struct GLMarkerRegion { GLMarkerRegion(const std::string &marker); ~GLMarkerRegion(); + + static void Begin(const std::string &marker); static void Set(const std::string &marker); + static void End(); static const GLHookSet *gl; }; diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index ff3519c51..3d2c5de0b 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -3312,7 +3312,8 @@ bool WrappedOpenGL::RecordUpdateCheck(GLResourceRecord *record) void WrappedOpenGL::DebugSnoop(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message) { - if(type != eGL_DEBUG_TYPE_PUSH_GROUP && type != eGL_DEBUG_TYPE_POP_GROUP) + if(type != eGL_DEBUG_TYPE_PUSH_GROUP && type != eGL_DEBUG_TYPE_POP_GROUP && + type != eGL_DEBUG_TYPE_MARKER) { if(type != eGL_DEBUG_TYPE_PERFORMANCE && type != eGL_DEBUG_TYPE_OTHER) { @@ -4503,31 +4504,28 @@ void WrappedOpenGL::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay if(!partial) { - GLMarkerRegion apply("ApplyInitialContents"); + GLMarkerRegion apply("!!!!RenderDoc Internal: ApplyInitialContents"); GetResourceManager()->ApplyInitialContents(); GetResourceManager()->ReleaseInFrameResources(); } + GLMarkerRegion::Set(StringFormat::Fmt("!!!!RenderDoc Internal: Replay %d (%d): %u->%u", + (int)replayType, (int)partial, startEventID, endEventID)); + + m_ReplayEventCount = 0; + if(replayType == eReplay_Full) - { - GLMarkerRegion exec( - StringFormat::Fmt("Replay: Full %u->%u (partial %u)", startEventID, endEventID, partial)); ContextReplayLog(EXECUTING, startEventID, endEventID, partial); - } else if(replayType == eReplay_WithoutDraw) - { - GLMarkerRegion exec(StringFormat::Fmt("Replay: W/O Draw %u->%u (partial %u)", startEventID, - endEventID, partial)); ContextReplayLog(EXECUTING, startEventID, RDCMAX(1U, endEventID) - 1, partial); - } else if(replayType == eReplay_OnlyDraw) - { - GLMarkerRegion exec(StringFormat::Fmt("Replay: Draw Only %u->%u (partial %u)", endEventID, - endEventID, partial)); ContextReplayLog(EXECUTING, endEventID, endEventID, partial); - } else - { RDCFATAL("Unexpected replay type"); - } + + // make sure to end any unbalanced replay events if we stopped in the middle of a frame + for(int i = 0; i < m_ReplayEventCount; i++) + GLMarkerRegion::End(); + + GLMarkerRegion::Set("!!!!RenderDoc Internal: Done replay"); } diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 986d8bf7a..4ac92f760 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -192,6 +192,8 @@ private: set m_HighTrafficResources; + int m_ReplayEventCount; + // we store two separate sets of maps, since for an explicit glMemoryBarrier // we need to flush both types of maps, but for implicit sync points we only // want to consider coherent maps, and since that happens often we want it to diff --git a/renderdoc/driver/gl/wrappers/gl_debug_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_debug_funcs.cpp index de8c491d6..d1d1194c1 100644 --- a/renderdoc/driver/gl/wrappers/gl_debug_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_debug_funcs.cpp @@ -158,7 +158,11 @@ bool WrappedOpenGL::Serialise_glDebugMessageInsert(GLenum source, GLenum type, G m_pSerialiser->Serialise("Name", name); - if(m_State == READING) + if(m_State == EXECUTING) + { + GLMarkerRegion::Set(name); + } + else if(m_State == READING) { DrawcallDescription draw; draw.name = name; @@ -240,7 +244,12 @@ bool WrappedOpenGL::Serialise_glPushDebugGroup(GLenum source, GLuint id, GLsizei m_pSerialiser->Serialise("Name", name); - if(m_State == READING) + if(m_State == EXECUTING) + { + GLMarkerRegion::Begin(name); + m_ReplayEventCount++; + } + else if(m_State == READING) { DrawcallDescription draw; draw.name = name; @@ -267,7 +276,12 @@ void WrappedOpenGL::glPushDebugGroup(GLenum source, GLuint id, GLsizei length, c bool WrappedOpenGL::Serialise_glPopDebugGroup() { - if(m_State == READING && !m_CurEvents.empty()) + if(m_State == EXECUTING) + { + GLMarkerRegion::End(); + m_ReplayEventCount = RDCMAX(0, m_ReplayEventCount - 1); + } + else if(m_State == READING && !m_CurEvents.empty()) { DrawcallDescription draw; draw.name = "API Calls"; diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index b69fd110d..fda9cf395 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -23,12 +23,108 @@ ******************************************************************************/ #include "vk_common.h" +#include "vk_core.h" #include "vk_manager.h" #include "vk_resources.h" const uint32_t AMD_PCI_ID = 0x1002; const uint32_t NV_PCI_ID = 0x10DE; +// utility struct for firing one-shot command buffers to begin/end markers +struct ScopedCommandBuffer +{ + ScopedCommandBuffer(VkCommandBuffer cmdbuf, WrappedVulkan *vk) + { + core = vk; + cmd = cmdbuf; + local = (cmd == VK_NULL_HANDLE); + + if(local) + { + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + cmd = vk->GetNextCmd(); + + VkResult vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + } + ~ScopedCommandBuffer() + { + VkResult vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + core->SubmitCmds(); + } + + WrappedVulkan *core; + VkCommandBuffer cmd; + bool local; +}; + +WrappedVulkan *VkMarkerRegion::vk = NULL; + +VkMarkerRegion::VkMarkerRegion(const std::string &marker, VkCommandBuffer cmd) +{ + if(cmd == VK_NULL_HANDLE) + { + RDCERR("Cannot auto-allocate a command buffer for a scoped VkMarkerRegion"); + return; + } + + cmdbuf = cmd; + Begin(marker, cmd); +} + +VkMarkerRegion::~VkMarkerRegion() +{ + if(cmdbuf) + End(cmdbuf); +} + +void VkMarkerRegion::Begin(const std::string &marker, VkCommandBuffer cmd) +{ + if(!vk) + return; + + // check for presence of the marker extension + if(!ObjDisp(vk->GetDev())->CmdDebugMarkerBeginEXT) + return; + + ScopedCommandBuffer scope(cmd, vk); + + VkDebugMarkerMarkerInfoEXT markerInfo = {}; + markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + markerInfo.pMarkerName = marker.c_str(); + ObjDisp(scope.cmd)->CmdDebugMarkerBeginEXT(Unwrap(scope.cmd), &markerInfo); +} + +void VkMarkerRegion::Set(const std::string &marker, VkCommandBuffer cmd) +{ + // check for presence of the marker extension + if(!ObjDisp(vk->GetDev())->CmdDebugMarkerBeginEXT) + return; + + ScopedCommandBuffer scope(cmd, vk); + + VkDebugMarkerMarkerInfoEXT markerInfo = {}; + markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + markerInfo.pMarkerName = marker.c_str(); + ObjDisp(scope.cmd)->CmdDebugMarkerInsertEXT(Unwrap(scope.cmd), &markerInfo); +} + +void VkMarkerRegion::End(VkCommandBuffer cmd) +{ + // check for presence of the marker extension + if(!ObjDisp(vk->GetDev())->CmdDebugMarkerBeginEXT) + return; + + ScopedCommandBuffer scope(cmd, vk); + + ObjDisp(scope.cmd)->CmdDebugMarkerEndEXT(Unwrap(scope.cmd)); +} + VkAccessFlags MakeAccessMask(VkImageLayout layout) { switch(layout) diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 410596d90..82a428560 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -104,6 +104,29 @@ int SampleCount(VkSampleCountFlagBits countFlag); int SampleIndex(VkSampleCountFlagBits countFlag); int StageIndex(VkShaderStageFlagBits stageFlag); +class WrappedVulkan; + +// replay only class for handling marker regions. +// +// The cmd allows you to pass in an existing command buffer to insert/add the marker to. +// If cmd is NULL, then a new command buffer is fetched, begun, the marker is applied to, then +// closed again. Note that when constructing a scoped marker, cmd cannot be NULL +// +// If VK_EXT_debug_marker isn't supported, will silently do nothing +struct VkMarkerRegion +{ + VkMarkerRegion(const std::string &marker, VkCommandBuffer cmd); + ~VkMarkerRegion(); + + static void Begin(const std::string &marker, VkCommandBuffer cmd = VK_NULL_HANDLE); + static void Set(const std::string &marker, VkCommandBuffer cmd = VK_NULL_HANDLE); + static void End(VkCommandBuffer cmd = VK_NULL_HANDLE); + + VkCommandBuffer cmdbuf = VK_NULL_HANDLE; + + static WrappedVulkan *vk; +}; + // in vk_.cpp extern const char *VulkanLibraryName; diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 367ffe525..52d3563e5 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -266,6 +266,8 @@ WrappedVulkan::WrappedVulkan(const char *logFilename) : m_RenderState(this, &m_C if(RenderDoc::Inst().IsReplayApp()) { + VkMarkerRegion::vk = this; + m_State = READING; if(logFilename) { @@ -2352,7 +2354,9 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay if(!partial) { + VkMarkerRegion::Begin("!!!!RenderDoc Internal: ApplyInitialContents"); ApplyInitialContents(); + VkMarkerRegion::End(); SubmitCmds(); FlushQ(); @@ -2360,6 +2364,9 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay GetResourceManager()->ReleaseInFrameResources(); } + VkMarkerRegion::Set(StringFormat::Fmt("!!!!RenderDoc Internal: RenderDoc Replay %d (%d): %u->%u", + (int)replayType, (int)partial, startEventID, endEventID)); + { if(!partial) { @@ -2488,6 +2495,8 @@ void WrappedVulkan::ReplayLog(uint32_t startEventID, uint32_t endEventID, Replay SubmitCmds(); #endif } + + VkMarkerRegion::Set("!!!!RenderDoc Internal: Done replay"); } void WrappedVulkan::Serialise_DebugMessages(Serialiser *localSerialiser, bool isDrawcall) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 7497aa818..4e126092d 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -409,6 +409,8 @@ private: VkCommandBufferLevel level; VkCommandBufferUsageFlags beginFlags; + int markerCount; + vector > resourceUsage; struct CmdBufferState diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index e49903dd8..2a1135c94 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -500,6 +500,7 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(Serialiser *localSerialiser, m_BakedCmdBufferInfo[cmdId].level = m_BakedCmdBufferInfo[bakeId].level = allocInfo.level; m_BakedCmdBufferInfo[cmdId].beginFlags = m_BakedCmdBufferInfo[bakeId].beginFlags = info.flags; + m_BakedCmdBufferInfo[cmdId].markerCount = 0; } if(m_State == EXECUTING) @@ -737,6 +738,10 @@ bool WrappedVulkan::Serialise_vkEndCommandBuffer(Serialiser *localSerialiser, ObjDisp(commandBuffer)->CmdEndRenderPass(Unwrap(commandBuffer)); } + if(ObjDisp(commandBuffer)->CmdDebugMarkerEndEXT) + for(int i = 0; i < m_BakedCmdBufferInfo[cmdid].markerCount; i++) + ObjDisp(commandBuffer)->CmdDebugMarkerEndEXT(Unwrap(commandBuffer)); + ObjDisp(commandBuffer)->EndCommandBuffer(Unwrap(commandBuffer)); // erase the non-baked reference to this command buffer so that we don't have @@ -2654,8 +2659,37 @@ bool WrappedVulkan::Serialise_vkCmdDebugMarkerBeginEXT(Serialiser *localSerialis if(m_State < WRITING) m_LastCmdBufferID = cmdid; - if(m_State == READING) + if(m_State == EXECUTING) { + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid)) + { + commandBuffer = RerecordCmdBuf(cmdid); + + m_BakedCmdBufferInfo[m_LastCmdBufferID].markerCount++; + + if(ObjDisp(commandBuffer)->CmdDebugMarkerBeginEXT) + { + VkDebugMarkerMarkerInfoEXT marker = {}; + marker.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + memcpy(marker.color, color, sizeof(color)); + marker.pMarkerName = name.c_str(); + ObjDisp(commandBuffer)->CmdDebugMarkerBeginEXT(Unwrap(commandBuffer), &marker); + } + } + } + else if(m_State == READING) + { + commandBuffer = GetResourceManager()->GetLiveHandle(cmdid); + + if(ObjDisp(commandBuffer)->CmdDebugMarkerBeginEXT) + { + VkDebugMarkerMarkerInfoEXT marker = {}; + marker.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + memcpy(marker.color, color, sizeof(color)); + marker.pMarkerName = name.c_str(); + ObjDisp(commandBuffer)->CmdDebugMarkerBeginEXT(Unwrap(commandBuffer), &marker); + } + DrawcallDescription draw; draw.name = name; draw.flags |= DrawFlags::PushMarker; @@ -2707,8 +2741,26 @@ bool WrappedVulkan::Serialise_vkCmdDebugMarkerEndEXT(Serialiser *localSerialiser AddDrawcall(draw, true); } - if(m_State == READING) + if(m_State == EXECUTING) { + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid)) + { + commandBuffer = RerecordCmdBuf(cmdid); + + int &markerCount = m_BakedCmdBufferInfo[m_LastCmdBufferID].markerCount; + markerCount = RDCMAX(0, markerCount - 1); + + if(ObjDisp(commandBuffer)->CmdDebugMarkerEndEXT) + ObjDisp(commandBuffer)->CmdDebugMarkerEndEXT(Unwrap(commandBuffer)); + } + } + else if(m_State == READING) + { + commandBuffer = GetResourceManager()->GetLiveHandle(cmdid); + + if(ObjDisp(commandBuffer)->CmdDebugMarkerEndEXT) + ObjDisp(commandBuffer)->CmdDebugMarkerEndEXT(Unwrap(commandBuffer)); + // dummy draw that is consumed when this command buffer // is being in-lined into the call stream DrawcallDescription draw; @@ -2756,8 +2808,35 @@ bool WrappedVulkan::Serialise_vkCmdDebugMarkerInsertEXT(Serialiser *localSeriali if(m_State < WRITING) m_LastCmdBufferID = cmdid; - if(m_State == READING) + if(m_State == EXECUTING) { + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid)) + { + commandBuffer = RerecordCmdBuf(cmdid); + + if(ObjDisp(commandBuffer)->CmdDebugMarkerInsertEXT) + { + VkDebugMarkerMarkerInfoEXT marker = {}; + marker.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + memcpy(marker.color, color, sizeof(color)); + marker.pMarkerName = name.c_str(); + ObjDisp(commandBuffer)->CmdDebugMarkerInsertEXT(Unwrap(commandBuffer), &marker); + } + } + } + else if(m_State == READING) + { + commandBuffer = GetResourceManager()->GetLiveHandle(cmdid); + + if(ObjDisp(commandBuffer)->CmdDebugMarkerInsertEXT) + { + VkDebugMarkerMarkerInfoEXT marker = {}; + marker.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT; + memcpy(marker.color, color, sizeof(color)); + marker.pMarkerName = name.c_str(); + ObjDisp(commandBuffer)->CmdDebugMarkerInsertEXT(Unwrap(commandBuffer), &marker); + } + DrawcallDescription draw; draw.name = name; draw.flags |= DrawFlags::SetMarker; diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 04b9570be..7af5aadc9 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -934,6 +934,14 @@ bool WrappedVulkan::Serialise_vkCreateDevice(Serialiser *localSerialiser, AddRequiredExtensions(false, Extensions, supportedExtensions); + // enable VK_EXT_debug_marker if it's available, to replay markers to the driver/any other + // layers that might be listening + if(supportedExtensions.find(VK_EXT_DEBUG_MARKER_EXTENSION_NAME) != supportedExtensions.end()) + { + Extensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); + RDCLOG("Enabling VK_EXT_debug_marker"); + } + #if ENABLED(FORCE_VALIDATION_LAYERS) Layers.push_back("VK_LAYER_LUNARG_standard_validation"); #endif