diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 28d39d5aa..037ece8ae 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -1562,6 +1562,12 @@ void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, u m_FirstEventID = startEventID; m_LastEventID = endEventID; + + // when selecting a marker we can get into an inconsistent state - + // make sure that we make things consistent again here, replay the event + // that we ended up selecting (the one that was closest) + if(startEventID == endEventID && m_RootEventID != m_FirstEventID) + m_FirstEventID = m_LastEventID = m_RootEventID; } else if(m_State == READING) { @@ -2333,6 +2339,36 @@ vector WrappedVulkan::GetDebugMessages() return ret; } +void WrappedVulkan::AddDebugMessage(DebugMessageCategory c, DebugMessageSeverity sv, + DebugMessageSource src, std::string d) +{ + DebugMessage msg; + msg.eventID = 0; + if(m_State == EXECUTING) + { + // look up the EID this drawcall came from + DrawcallUse use(m_CurChunkOffset, 0); + auto it = std::lower_bound(m_DrawcallUses.begin(), m_DrawcallUses.end(), use); + RDCASSERT(it != m_DrawcallUses.end()); + + msg.eventID = it->eventID; + } + msg.messageID = 0; + msg.source = src; + msg.category = c; + msg.severity = sv; + msg.description = d; + AddDebugMessage(msg); +} + +void WrappedVulkan::AddDebugMessage(DebugMessage msg) +{ + if(m_State == READING) + m_EventMessages.push_back(msg); + else + m_DebugMessages.push_back(msg); +} + VkBool32 WrappedVulkan::DebugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index c1c79dac4..63e5dc101 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -191,6 +191,9 @@ private: vector m_DebugMessages; void Serialise_DebugMessages(Serialiser *localSerialiser, bool isDrawcall); vector GetDebugMessages(); + void AddDebugMessage(DebugMessage msg); + void AddDebugMessage(DebugMessageCategory c, DebugMessageSeverity sv, DebugMessageSource src, + std::string d); enum { @@ -368,12 +371,23 @@ private: struct BakedCmdBufferInfo { - BakedCmdBufferInfo() : draw(NULL), eventCount(0), curEventID(0), drawCount(0) {} + BakedCmdBufferInfo() + : draw(NULL), + eventCount(0), + curEventID(0), + drawCount(0), + level(VK_COMMAND_BUFFER_LEVEL_PRIMARY), + beginFlags(0) + { + } ~BakedCmdBufferInfo() { SAFE_DELETE(draw); } vector curEvents; vector debugMessages; list drawStack; + VkCommandBufferLevel level; + VkCommandBufferUsageFlags beginFlags; + vector > resourceUsage; struct CmdBufferState @@ -575,6 +589,8 @@ private: void MakeSubpassLoadRP(VkRenderPassCreateInfo &info, const VkRenderPassCreateInfo *origInfo, uint32_t s); + bool IsDrawInRenderPass(); + void StartFrameCapture(void *dev, void *wnd); bool EndFrameCapture(void *dev, void *wnd); diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index c828c9884..71eaff21d 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -6350,7 +6350,7 @@ void VulkanDebugManager::InitPostVSBuffers(uint32_t eventID) const VulkanRenderState &state = m_pDriver->m_RenderState; VulkanCreationInfo &creationInfo = m_pDriver->m_CreationInfo; - if(state.graphics.pipeline == ResourceId()) + if(state.graphics.pipeline == ResourceId() || state.renderPass == ResourceId()) return; const VulkanCreationInfo::Pipeline &pipeInfo = creationInfo.m_Pipeline[state.graphics.pipeline]; diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 181bcb41a..d7ffb3647 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -466,8 +466,13 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(Serialiser *localSerialiser, localSerialiser->Serialise("allocInfo", allocInfo); if(m_State < WRITING) + { device = GetResourceManager()->GetLiveHandle(devId); + m_BakedCmdBufferInfo[cmdId].level = m_BakedCmdBufferInfo[bakeId].level = allocInfo.level; + m_BakedCmdBufferInfo[cmdId].beginFlags = m_BakedCmdBufferInfo[bakeId].beginFlags = info.flags; + } + if(m_State == EXECUTING) { const uint32_t length = m_BakedCmdBufferInfo[bakeId].eventCount; @@ -2344,6 +2349,14 @@ bool WrappedVulkan::Serialise_vkCmdExecuteCommands(Serialiser *localSerialiser, BakedCmdBufferInfo &cmdBufInfo = m_BakedCmdBufferInfo[cmdids[c]]; + if(m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass == ResourceId() && + (cmdBufInfo.beginFlags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) + { + AddDebugMessage( + eDbgCategory_Execution, eDbgSeverity_High, eDbgSource_IncorrectAPIUse, + "Executing a command buffer with RENDER_PASS_CONTINUE_BIT outside of render pass"); + } + // insert the baked command buffer in-line into this list of notes, assigning new event and // drawIDs parentCmdBufInfo.draw->InsertAndUpdateIDs(*cmdBufInfo.draw, parentCmdBufInfo.curEventID, diff --git a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp index f84ee392e..efcde26e3 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp @@ -25,6 +25,46 @@ #include "../vk_core.h" #include "../vk_debug.h" +bool WrappedVulkan::IsDrawInRenderPass() +{ + ResourceId rp; + + if(m_State == READING) + rp = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass; + else + rp = m_RenderState.renderPass; + + ResourceId cmdid = m_LastCmdBufferID; + + bool rpActive = true; + + if(m_State == EXECUTING) + { + cmdid = GetResID(RerecordCmdBuf(cmdid)); + + rpActive = + m_Partial[m_BakedCmdBufferInfo[cmdid].level == VK_COMMAND_BUFFER_LEVEL_PRIMARY ? Primary : Secondary] + .renderPassActive; + } + + if(m_BakedCmdBufferInfo[cmdid].level == VK_COMMAND_BUFFER_LEVEL_PRIMARY && + (rp == ResourceId() || !rpActive)) + { + return false; + } + else if(m_BakedCmdBufferInfo[cmdid].level == VK_COMMAND_BUFFER_LEVEL_SECONDARY && + (m_BakedCmdBufferInfo[cmdid].beginFlags & + VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) == 0 && + (rp == ResourceId() || !rpActive)) + { + return false; + } + + // assume a secondary buffer with RENDER_PASS_CONTINUE_BIT is in a render pass. + + return true; +} + bool WrappedVulkan::Serialise_vkCmdDraw(Serialiser *localSerialiser, VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) @@ -42,7 +82,7 @@ bool WrappedVulkan::Serialise_vkCmdDraw(Serialiser *localSerialiser, VkCommandBu if(m_State == EXECUTING) { - if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid)) + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid) && m_RenderState.renderPass != ResourceId()) { commandBuffer = RerecordCmdBuf(cmdid); @@ -65,6 +105,13 @@ bool WrappedVulkan::Serialise_vkCmdDraw(Serialiser *localSerialiser, VkCommandBu const string desc = localSerialiser->GetDebugStr(); + if(!IsDrawInRenderPass()) + { + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_High, eDbgSource_IncorrectAPIUse, + "Drawcall in happening outside of render pass, or in secondary command " + "buffer without RENDER_PASS_CONTINUE_BIT"); + } + { AddEvent(DRAW, desc); string name = "vkCmdDraw(" + ToStr::Get(vtxCount) + "," + ToStr::Get(instCount) + ")"; @@ -127,7 +174,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexed(Serialiser *localSerialiser, if(m_State == EXECUTING) { - if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid)) + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid) && IsDrawInRenderPass()) { commandBuffer = RerecordCmdBuf(cmdid); @@ -154,6 +201,13 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexed(Serialiser *localSerialiser, const string desc = localSerialiser->GetDebugStr(); + if(!IsDrawInRenderPass()) + { + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_High, eDbgSource_IncorrectAPIUse, + "Drawcall in happening outside of render pass, or in secondary command " + "buffer without RENDER_PASS_CONTINUE_BIT"); + } + { AddEvent(DRAW_INDEXED, desc); string name = "vkCmdDrawIndexed(" + ToStr::Get(idxCount) + "," + ToStr::Get(instCount) + ")"; @@ -228,7 +282,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndirect(Serialiser *localSerialiser, // for single draws, it's pretty simple buffer = GetResourceManager()->GetLiveHandle(bufid); - if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid)) + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid) && IsDrawInRenderPass()) { commandBuffer = RerecordCmdBuf(cmdid); @@ -271,7 +325,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndirect(Serialiser *localSerialiser, uint32_t baseEventID = it->eventID; // when re-recording all, submit every drawcall individually to the callback - if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds()) + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid) && IsDrawInRenderPass()) { for(uint32_t i = 0; i < cnt; i++) { @@ -314,14 +368,18 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndirect(Serialiser *localSerialiser, cnt = 1; } - uint32_t eventID = HandlePreCallback(commandBuffer, false, drawidx + 1); - - ObjDisp(commandBuffer)->CmdDrawIndirect(Unwrap(commandBuffer), Unwrap(buffer), offs, cnt, strd); - - if(eventID && m_DrawcallCallback->PostDraw(eventID, commandBuffer)) + if(IsDrawInRenderPass()) { + uint32_t eventID = HandlePreCallback(commandBuffer, false, drawidx + 1); + ObjDisp(commandBuffer)->CmdDrawIndirect(Unwrap(commandBuffer), Unwrap(buffer), offs, cnt, strd); - m_DrawcallCallback->PostRedraw(eventID, commandBuffer); + + if(eventID && m_DrawcallCallback->PostDraw(eventID, commandBuffer)) + { + ObjDisp(commandBuffer) + ->CmdDrawIndirect(Unwrap(commandBuffer), Unwrap(buffer), offs, cnt, strd); + m_DrawcallCallback->PostRedraw(eventID, commandBuffer); + } } } } @@ -340,6 +398,13 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndirect(Serialiser *localSerialiser, string name = "vkCmdDrawIndirect(" + ToStr::Get(cnt) + ")"; + if(!IsDrawInRenderPass()) + { + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_High, eDbgSource_IncorrectAPIUse, + "Drawcall in happening outside of render pass, or in secondary command " + "buffer without RENDER_PASS_CONTINUE_BIT"); + } + // for 'single' draws, don't do complex multi-draw just inline it if(cnt <= 1) { @@ -482,7 +547,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirect(Serialiser *localSerialis // for single draws, it's pretty simple buffer = GetResourceManager()->GetLiveHandle(bufid); - if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid)) + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid) && IsDrawInRenderPass()) { commandBuffer = RerecordCmdBuf(cmdid); @@ -527,7 +592,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirect(Serialiser *localSerialis uint32_t baseEventID = it->eventID; // when re-recording all, submit every drawcall individually to the callback - if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds()) + if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds() && IsDrawInRenderPass()) { for(uint32_t i = 0; i < cnt; i++) { @@ -584,16 +649,19 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirect(Serialiser *localSerialis } } - uint32_t eventID = HandlePreCallback(commandBuffer, false, drawidx + 1); - - ObjDisp(commandBuffer) - ->CmdDrawIndexedIndirect(Unwrap(commandBuffer), Unwrap(buffer), offs, cnt, strd); - - if(eventID && m_DrawcallCallback->PostDraw(eventID, commandBuffer)) + if(IsDrawInRenderPass()) { + uint32_t eventID = HandlePreCallback(commandBuffer, false, drawidx + 1); + ObjDisp(commandBuffer) ->CmdDrawIndexedIndirect(Unwrap(commandBuffer), Unwrap(buffer), offs, cnt, strd); - m_DrawcallCallback->PostRedraw(eventID, commandBuffer); + + if(eventID && m_DrawcallCallback->PostDraw(eventID, commandBuffer)) + { + ObjDisp(commandBuffer) + ->CmdDrawIndexedIndirect(Unwrap(commandBuffer), Unwrap(buffer), offs, cnt, strd); + m_DrawcallCallback->PostRedraw(eventID, commandBuffer); + } } } } @@ -612,6 +680,13 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirect(Serialiser *localSerialis string name = "vkCmdDrawIndexedIndirect(" + ToStr::Get(cnt) + ")"; + if(!IsDrawInRenderPass()) + { + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_High, eDbgSource_IncorrectAPIUse, + "Drawcall in happening outside of render pass, or in secondary command " + "buffer without RENDER_PASS_CONTINUE_BIT"); + } + // for 'single' draws, don't do complex multi-draw just inline it if(cnt <= 1) {