From 66d6793f5ec56135cfd76b4e0aaee2a0792e81d0 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 20 Dec 2022 16:51:38 +0000 Subject: [PATCH] Handle compute-queues properly with vulkan counters. Closes #2795 --- renderdoc/driver/vulkan/vk_core.cpp | 14 +- renderdoc/driver/vulkan/vk_core.h | 2 + renderdoc/driver/vulkan/vk_counters.cpp | 178 +++++++++++++++++------- 3 files changed, 142 insertions(+), 52 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 570bfa543..126ac8ad6 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -3015,7 +3015,8 @@ RDResult WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t startEv if(!IsStructuredExporting(m_State)) { - ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(GetDev())); + VkResult vkr = ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(GetDev())); + CheckVkResult(vkr); // destroy any events we created for waiting on for(size_t i = 0; i < m_CleanupEvents.size(); i++) @@ -5045,6 +5046,17 @@ LockedImageStateRef WrappedVulkan::InsertImageState(VkImage wrappedHandle, Resou } } +VkQueueFlags WrappedVulkan::GetCommandType(ResourceId cmdId) +{ + auto it = m_commandQueueFamilies.find(cmdId); + if(it == m_commandQueueFamilies.end()) + { + RDCERR("Unknown queue family for %s", ToStr(cmdId).c_str()); + return VkQueueFlags(0); + } + return m_PhysicalDeviceData.queueProps[it->second].queueFlags; +} + bool WrappedVulkan::EraseImageState(ResourceId id) { SCOPED_LOCK(m_ImageStatesLock); diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 64c7ad20d..a512db967 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -1231,6 +1231,8 @@ public: VkDriverInfo GetDriverInfo() { return m_PhysicalDeviceData.driverInfo; } uint32_t FindCommandQueueFamily(ResourceId cmdId); void InsertCommandQueueFamily(ResourceId cmdId, uint32_t queueFamilyIndex); + VkQueueFlags GetCommandType(ResourceId cmdId); + VkQueueFlags GetCommandType() { return GetCommandType(m_LastCmdBufferID); } LockedImageStateRef FindImageState(ResourceId id); LockedConstImageStateRef FindConstImageState(ResourceId id); LockedImageStateRef InsertImageState(VkImage wrappedHandle, ResourceId id, const ImageInfo &info, diff --git a/renderdoc/driver/vulkan/vk_counters.cpp b/renderdoc/driver/vulkan/vk_counters.cpp index 38fd1bb23..134c75844 100644 --- a/renderdoc/driver/vulkan/vk_counters.cpp +++ b/renderdoc/driver/vulkan/vk_counters.cpp @@ -427,7 +427,7 @@ struct VulkanAMDActionCallback : public VulkanActionCallback // multiple times in the frame. We will only get the full callback when we're // recording the command buffer, and will be given the first EID. After that // we'll just be told which other EIDs alias this event. - rdcarray > m_AliasEvents; + rdcarray> m_AliasEvents; }; void VulkanReplay::FillTimersAMD(uint32_t *eventStartID, uint32_t *sampleIndex, @@ -584,7 +584,7 @@ struct VulkanKHRCallback : public VulkanActionCallback // multiple times in the frame. We will only get the full callback when we're // recording the command buffer, and will be given the first EID. After that // we'll just be told which other EIDs alias this event. - rdcarray > m_AliasEvents; + rdcarray> m_AliasEvents; }; rdcarray VulkanReplay::FetchCountersKHR(const rdcarray &counters) @@ -719,23 +719,33 @@ rdcarray VulkanReplay::FetchCountersKHR(const rdcarraySetActionCB(this); } ~VulkanGPUTimerCallback() { m_pDriver->SetActionCB(NULL); } void PreDraw(uint32_t eid, VkCommandBuffer cmd) override { - if(m_OcclusionQueryPool != VK_NULL_HANDLE) - ObjDisp(cmd)->CmdBeginQuery(Unwrap(cmd), m_OcclusionQueryPool, (uint32_t)m_Results.size(), - VK_QUERY_CONTROL_PRECISE_BIT); - if(m_PipeStatsQueryPool != VK_NULL_HANDLE) - ObjDisp(cmd)->CmdBeginQuery(Unwrap(cmd), m_PipeStatsQueryPool, (uint32_t)m_Results.size(), 0); + VkQueueFlags cmdType = m_pDriver->GetCommandType(); + if(cmdType & VK_QUEUE_GRAPHICS_BIT) + { + if(m_OcclusionQueryPool != VK_NULL_HANDLE) + ObjDisp(cmd)->CmdBeginQuery(Unwrap(cmd), m_OcclusionQueryPool, m_GraphicsQueries, + VK_QUERY_CONTROL_PRECISE_BIT); + if(m_PipeStatsQueryPool != VK_NULL_HANDLE) + ObjDisp(cmd)->CmdBeginQuery(Unwrap(cmd), m_PipeStatsQueryPool, m_GraphicsQueries, 0); + } + else if(cmdType & VK_QUEUE_COMPUTE_BIT) + { + if(m_ComputePipeStatsQueryPool != VK_NULL_HANDLE) + ObjDisp(cmd)->CmdBeginQuery(Unwrap(cmd), m_ComputePipeStatsQueryPool, m_ComputeQueries, 0); + } ObjDisp(cmd)->CmdWriteTimestamp(Unwrap(cmd), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_TimeStampQueryPool, (uint32_t)(m_Results.size() * 2 + 0)); } @@ -744,11 +754,23 @@ struct VulkanGPUTimerCallback : public VulkanActionCallback { ObjDisp(cmd)->CmdWriteTimestamp(Unwrap(cmd), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_TimeStampQueryPool, (uint32_t)(m_Results.size() * 2 + 1)); - if(m_OcclusionQueryPool != VK_NULL_HANDLE) - ObjDisp(cmd)->CmdEndQuery(Unwrap(cmd), m_OcclusionQueryPool, (uint32_t)m_Results.size()); - if(m_PipeStatsQueryPool != VK_NULL_HANDLE) - ObjDisp(cmd)->CmdEndQuery(Unwrap(cmd), m_PipeStatsQueryPool, (uint32_t)m_Results.size()); - m_Results.push_back(eid); + + VkQueueFlags cmdType = m_pDriver->GetCommandType(); + if(cmdType & VK_QUEUE_GRAPHICS_BIT) + { + if(m_OcclusionQueryPool != VK_NULL_HANDLE) + ObjDisp(cmd)->CmdEndQuery(Unwrap(cmd), m_OcclusionQueryPool, m_GraphicsQueries); + if(m_PipeStatsQueryPool != VK_NULL_HANDLE) + ObjDisp(cmd)->CmdEndQuery(Unwrap(cmd), m_PipeStatsQueryPool, m_GraphicsQueries); + m_GraphicsQueries++; + } + else if(cmdType & VK_QUEUE_COMPUTE_BIT) + { + if(m_ComputePipeStatsQueryPool != VK_NULL_HANDLE) + ObjDisp(cmd)->CmdEndQuery(Unwrap(cmd), m_ComputePipeStatsQueryPool, m_ComputeQueries); + m_ComputeQueries++; + } + m_Results.push_back({eid, cmdType}); return false; } @@ -796,12 +818,15 @@ struct VulkanGPUTimerCallback : public VulkanActionCallback VkQueryPool m_TimeStampQueryPool; VkQueryPool m_OcclusionQueryPool; VkQueryPool m_PipeStatsQueryPool; - rdcarray m_Results; + VkQueryPool m_ComputePipeStatsQueryPool; + rdcarray> m_Results; + uint32_t m_GraphicsQueries = 0; + uint32_t m_ComputeQueries = 0; // events which are the 'same' from being the same command buffer resubmitted // multiple times in the frame. We will only get the full callback when we're // recording the command buffer, and will be given the first EID. After that // we'll just be told which other EIDs alias this event. - rdcarray > m_AliasEvents; + rdcarray> m_AliasEvents; }; rdcarray VulkanReplay::FetchCounters(const rdcarray &counters) @@ -904,6 +929,16 @@ rdcarray VulkanReplay::FetchCounters(const rdcarray & CheckVkResult(vkr); } + VkQueryPool compPipeStatsPool = VK_NULL_HANDLE; + if(availableFeatures.pipelineStatisticsQuery && statsNeeded) + { + pipeStatsPoolCreateInfo.pipelineStatistics = + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT; + vkr = ObjDisp(dev)->CreateQueryPool(Unwrap(dev), &pipeStatsPoolCreateInfo, NULL, + &compPipeStatsPool); + CheckVkResult(vkr); + } + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); if(cmd == VK_NULL_HANDLE) @@ -920,6 +955,8 @@ rdcarray VulkanReplay::FetchCounters(const rdcarray & ObjDisp(dev)->CmdResetQueryPool(Unwrap(cmd), occlusionPool, 0, maxEID); if(pipeStatsPool != VK_NULL_HANDLE) ObjDisp(dev)->CmdResetQueryPool(Unwrap(cmd), pipeStatsPool, 0, maxEID); + if(compPipeStatsPool != VK_NULL_HANDLE) + ObjDisp(dev)->CmdResetQueryPool(Unwrap(cmd), compPipeStatsPool, 0, maxEID); vkr = ObjDisp(dev)->EndCommandBuffer(Unwrap(cmd)); CheckVkResult(vkr); @@ -928,83 +965,122 @@ rdcarray VulkanReplay::FetchCounters(const rdcarray & m_pDriver->SubmitCmds(); #endif - VulkanGPUTimerCallback cb(m_pDriver, this, timeStampPool, occlusionPool, pipeStatsPool); + VulkanGPUTimerCallback cb(m_pDriver, this, timeStampPool, occlusionPool, pipeStatsPool, + compPipeStatsPool); // replay the events to perform all the queries m_pDriver->ReplayLog(0, maxEID, eReplay_Full); - rdcarray m_TimeStampData; - m_TimeStampData.resize(cb.m_Results.size() * 2); + rdcarray timeStampData; + timeStampData.resize(cb.m_Results.size() * 2); vkr = ObjDisp(dev)->GetQueryPoolResults( - Unwrap(dev), timeStampPool, 0, (uint32_t)m_TimeStampData.size(), - sizeof(uint64_t) * m_TimeStampData.size(), &m_TimeStampData[0], sizeof(uint64_t), + Unwrap(dev), timeStampPool, 0, (uint32_t)timeStampData.size(), + sizeof(uint64_t) * timeStampData.size(), &timeStampData[0], sizeof(uint64_t), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); CheckVkResult(vkr); ObjDisp(dev)->DestroyQueryPool(Unwrap(dev), timeStampPool, NULL); - rdcarray m_OcclusionData; - m_OcclusionData.resize(cb.m_Results.size()); + rdcarray occlusionData; + occlusionData.resize(cb.m_GraphicsQueries); if(occlusionPool != VK_NULL_HANDLE) { - vkr = ObjDisp(dev)->GetQueryPoolResults( - Unwrap(dev), occlusionPool, 0, (uint32_t)m_OcclusionData.size(), - sizeof(uint64_t) * m_OcclusionData.size(), &m_OcclusionData[0], sizeof(uint64_t), - VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); + vkr = VK_SUCCESS; + if(cb.m_GraphicsQueries > 0) + vkr = ObjDisp(dev)->GetQueryPoolResults(Unwrap(dev), occlusionPool, 0, cb.m_GraphicsQueries, + sizeof(uint64_t) * cb.m_GraphicsQueries, + occlusionData.data(), sizeof(uint64_t), + VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); CheckVkResult(vkr); ObjDisp(dev)->DestroyQueryPool(Unwrap(dev), occlusionPool, NULL); } - rdcarray m_PipeStatsData; - m_PipeStatsData.resize(cb.m_Results.size() * 11); + rdcarray pipeStatsData; + pipeStatsData.resize(cb.m_GraphicsQueries * 11); if(pipeStatsPool != VK_NULL_HANDLE) { - vkr = ObjDisp(dev)->GetQueryPoolResults( - Unwrap(dev), pipeStatsPool, 0, (uint32_t)cb.m_Results.size(), - sizeof(uint64_t) * m_PipeStatsData.size(), &m_PipeStatsData[0], sizeof(uint64_t) * 11, - VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); + vkr = VK_SUCCESS; + if(cb.m_GraphicsQueries > 0) + vkr = ObjDisp(dev)->GetQueryPoolResults(Unwrap(dev), pipeStatsPool, 0, cb.m_GraphicsQueries, + sizeof(uint64_t) * cb.m_GraphicsQueries * 11, + pipeStatsData.data(), sizeof(uint64_t) * 11, + VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); CheckVkResult(vkr); ObjDisp(dev)->DestroyQueryPool(Unwrap(dev), pipeStatsPool, NULL); } + rdcarray m_CompPipeStatsData; + m_CompPipeStatsData.resize(cb.m_ComputeQueries); + if(compPipeStatsPool != VK_NULL_HANDLE) + { + vkr = VK_SUCCESS; + if(cb.m_ComputeQueries > 0) + vkr = ObjDisp(dev)->GetQueryPoolResults(Unwrap(dev), compPipeStatsPool, 0, cb.m_ComputeQueries, + sizeof(uint64_t) * cb.m_ComputeQueries, + m_CompPipeStatsData.data(), sizeof(uint64_t), + VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); + CheckVkResult(vkr); + + ObjDisp(dev)->DestroyQueryPool(Unwrap(dev), compPipeStatsPool, NULL); + } + + uint32_t graphicsIdx = 0, computeIdx = 0; + for(size_t i = 0; i < cb.m_Results.size(); i++) { + uint64_t pipeStats[11] = {}; + uint64_t occl = 0; + + if(cb.m_Results[i].second & VK_QUEUE_GRAPHICS_BIT) + { + if(graphicsIdx < cb.m_GraphicsQueries) + { + occl = occlusionData[graphicsIdx]; + memcpy(pipeStats, &pipeStatsData[graphicsIdx * 11], sizeof(pipeStats)); + } + graphicsIdx++; + } + else if(cb.m_Results[i].second & VK_QUEUE_COMPUTE_BIT) + { + if(computeIdx < cb.m_ComputeQueries) + { + pipeStats[10] = m_CompPipeStatsData[computeIdx]; + } + computeIdx++; + } + for(size_t c = 0; c < vkCounters.size(); c++) { CounterResult result; - result.eventId = cb.m_Results[i]; + result.eventId = cb.m_Results[i].first; result.counter = vkCounters[c]; switch(vkCounters[c]) { case GPUCounter::EventGPUDuration: { - uint64_t delta = m_TimeStampData[i * 2 + 1] - m_TimeStampData[i * 2 + 0]; + uint64_t delta = timeStampData[i * 2 + 1] - timeStampData[i * 2 + 0]; result.value.d = (double(m_pDriver->GetDeviceProps().limits.timestampPeriod) * double(delta)) // nanoseconds / (1000.0 * 1000.0 * 1000.0); // to seconds } break; - case GPUCounter::InputVerticesRead: result.value.u64 = m_PipeStatsData[i * 11 + 0]; break; - case GPUCounter::IAPrimitives: result.value.u64 = m_PipeStatsData[i * 11 + 1]; break; - case GPUCounter::GSPrimitives: result.value.u64 = m_PipeStatsData[i * 11 + 4]; break; - case GPUCounter::RasterizerInvocations: - result.value.u64 = m_PipeStatsData[i * 11 + 5]; - break; - case GPUCounter::RasterizedPrimitives: - result.value.u64 = m_PipeStatsData[i * 11 + 6]; - break; - case GPUCounter::SamplesPassed: result.value.u64 = m_OcclusionData[i]; break; - case GPUCounter::VSInvocations: result.value.u64 = m_PipeStatsData[i * 11 + 2]; break; - case GPUCounter::TCSInvocations: result.value.u64 = m_PipeStatsData[i * 11 + 8]; break; - case GPUCounter::TESInvocations: result.value.u64 = m_PipeStatsData[i * 11 + 9]; break; - case GPUCounter::GSInvocations: result.value.u64 = m_PipeStatsData[i * 11 + 3]; break; - case GPUCounter::PSInvocations: result.value.u64 = m_PipeStatsData[i * 11 + 7]; break; - case GPUCounter::CSInvocations: result.value.u64 = m_PipeStatsData[i * 11 + 10]; break; + case GPUCounter::InputVerticesRead: result.value.u64 = pipeStats[0]; break; + case GPUCounter::IAPrimitives: result.value.u64 = pipeStats[1]; break; + case GPUCounter::GSPrimitives: result.value.u64 = pipeStats[4]; break; + case GPUCounter::RasterizerInvocations: result.value.u64 = pipeStats[5]; break; + case GPUCounter::RasterizedPrimitives: result.value.u64 = pipeStats[6]; break; + case GPUCounter::SamplesPassed: result.value.u64 = occl; break; + case GPUCounter::VSInvocations: result.value.u64 = pipeStats[2]; break; + case GPUCounter::TCSInvocations: result.value.u64 = pipeStats[8]; break; + case GPUCounter::TESInvocations: result.value.u64 = pipeStats[9]; break; + case GPUCounter::GSInvocations: result.value.u64 = pipeStats[3]; break; + case GPUCounter::PSInvocations: result.value.u64 = pipeStats[7]; break; + case GPUCounter::CSInvocations: result.value.u64 = pipeStats[10]; break; default: break; } ret.push_back(result);