diff --git a/renderdoc/driver/vulkan/Makefile b/renderdoc/driver/vulkan/Makefile index b3b85bd13..8b2911136 100644 --- a/renderdoc/driver/vulkan/Makefile +++ b/renderdoc/driver/vulkan/Makefile @@ -20,6 +20,7 @@ vk_manager.o \ vk_resources.o \ vk_debug.o \ vk_replay.o \ +vk_counters.o \ vk_info.o \ vk_state.o \ vk_linux.o \ diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj index eb3f4eafd..06f7ef630 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj @@ -19,6 +19,7 @@ + diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters index cbeef41e3..a29bf05b3 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters @@ -79,6 +79,9 @@ Util + + Replay + diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index c24568588..7d6ffa562 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -508,6 +508,7 @@ public: vector &GetFrameRecord() { return m_FrameRecord; } FetchAPIEvent GetEvent(uint32_t eventID); + uint32_t GetMaxEID() { return m_Events.back().eventID; } const FetchDrawcall *GetDrawcall(uint32_t frameID, uint32_t eventID); // return the pre-selected device and queue diff --git a/renderdoc/driver/vulkan/vk_counters.cpp b/renderdoc/driver/vulkan/vk_counters.cpp new file mode 100644 index 000000000..56b671c1b --- /dev/null +++ b/renderdoc/driver/vulkan/vk_counters.cpp @@ -0,0 +1,169 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2015 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "vk_replay.h" +#include "vk_core.h" +#include "vk_resources.h" + +void VulkanReplay::PreDeviceInitCounters() +{ +} + +void VulkanReplay::PostDeviceInitCounters() +{ +} + +void VulkanReplay::PreDeviceShutdownCounters() +{ +} + +void VulkanReplay::PostDeviceShutdownCounters() +{ +} + +vector VulkanReplay::EnumerateCounters() +{ + vector ret; + + ret.push_back(eCounter_EventGPUDuration); + + return ret; +} + +void VulkanReplay::DescribeCounter(uint32_t counterID, CounterDescription &desc) +{ + desc.counterID = counterID; + + if(counterID == eCounter_EventGPUDuration) + { + desc.name = "GPU Duration"; + desc.description = "Time taken for this event on the GPU, as measured by delta between two GPU timestamps, top to bottom of the pipe."; + desc.resultByteWidth = 8; + desc.resultCompType = eCompType_Double; + desc.units = eUnits_Seconds; + } + else + { + desc.name = "Unknown"; + desc.description = "Unknown counter ID"; + desc.resultByteWidth = 0; + desc.resultCompType = eCompType_None; + desc.units = eUnits_Absolute; + } +} +struct GPUTimerCallback : public DrawcallCallback +{ + GPUTimerCallback(WrappedVulkan *vk, VulkanReplay *rp, VkQueryPool qp) + : m_pDriver(vk) + , m_pReplay(rp) + , m_QueryPool(qp) + { m_pDriver->SetDrawcallCB(this); } + ~GPUTimerCallback() + { m_pDriver->SetDrawcallCB(NULL); } + + void PreDraw(uint32_t eid, VkCommandBuffer cmd) + { + ObjDisp(cmd)->CmdWriteTimestamp(Unwrap(cmd), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_QueryPool, (uint32_t)(m_Results.size()*2 + 0)); + } + + bool PostDraw(uint32_t eid, VkCommandBuffer cmd) + { + ObjDisp(cmd)->CmdWriteTimestamp(Unwrap(cmd), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, m_QueryPool, (uint32_t)(m_Results.size()*2 + 1)); + m_Results.push_back(eid); + return false; + } + + void PostRedraw(uint32_t eid, VkCommandBuffer cmd) + { + } + + WrappedVulkan *m_pDriver; + VulkanReplay *m_pReplay; + VkQueryPool m_QueryPool; + vector m_Results; +}; + +vector VulkanReplay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) +{ + uint32_t maxEID = m_pDriver->GetMaxEID(); + + VkDevice dev = m_pDriver->GetDev(); + + VkQueryPoolCreateInfo poolCreateInfo = { + VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, NULL, + 0, VK_QUERY_TYPE_TIMESTAMP, maxEID*2, 0 + }; + + VkQueryPool pool; + VkResult vkr = ObjDisp(dev)->CreateQueryPool(Unwrap(dev), &poolCreateInfo, NULL, &pool); + RDCASSERT(vkr == VK_SUCCESS); + + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); + + VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT }; + + vkr = ObjDisp(dev)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERT(vkr == VK_SUCCESS); + + ObjDisp(dev)->CmdResetQueryPool(Unwrap(cmd), pool, 0, maxEID*2); + + vkr = ObjDisp(dev)->EndCommandBuffer(Unwrap(cmd)); + RDCASSERT(vkr == VK_SUCCESS); + + GPUTimerCallback cb(m_pDriver, this, pool); + + // replay the events to perform all the queries + m_pDriver->ReplayLog(frameID, 0, maxEID, eReplay_Full); + + vector m_Data; + m_Data.resize(cb.m_Results.size()*2); + + vkr = ObjDisp(dev)->GetQueryPoolResults(Unwrap(dev), pool, 0, (uint32_t)m_Data.size(), + sizeof(uint64_t)*m_Data.size(), &m_Data[0], sizeof(uint64_t), + VK_QUERY_RESULT_64_BIT|VK_QUERY_RESULT_WAIT_BIT); + RDCASSERT(vkr == VK_SUCCESS); + + ObjDisp(dev)->DestroyQueryPool(Unwrap(dev), pool, NULL); + + vector ret; + + for(size_t i=0; i < cb.m_Results.size(); i++) + { + CounterResult result; + + uint64_t delta = m_Data[i*2 + 1] - m_Data[i*2 + 0]; + + result.eventID = cb.m_Results[i]; + result.counterID = eCounter_EventGPUDuration; + result.value.d = + (double(m_pDriver->GetDeviceProps().limits.timestampPeriod) * double(delta)) // nanoseconds + / + (1000.0*1000.0*1000.0); // to seconds + + ret.push_back(result); + } + + return ret; +} + diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 8c8880da5..8646d20fa 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -242,6 +242,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) m_pDriver = driver; m_State = m_pDriver->GetState(); + driver->GetReplay()->PostDeviceInitCounters(); + m_ResourceManager = m_pDriver->GetResourceManager(); m_DescriptorPool = VK_NULL_HANDLE; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 4857f9364..0d1e21a8a 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -511,8 +511,12 @@ VulkanResourceManager *VulkanReplay::GetResourceManager() void VulkanReplay::Shutdown() { + PreDeviceShutdownCounters(); + m_pDriver->Shutdown(); delete m_pDriver; + + VulkanReplay::PostDeviceShutdownCounters(); } APIProperties VulkanReplay::GetAPIProperties() @@ -4314,23 +4318,6 @@ void VulkanReplay::RemoveReplacement(ResourceId id) VULKANNOTIMP("RemoveReplacement"); } -vector VulkanReplay::EnumerateCounters() -{ - VULKANNOTIMP("EnumerateCounters"); - return vector(); -} - -void VulkanReplay::DescribeCounter(uint32_t counterID, CounterDescription &desc) -{ - RDCUNIMPLEMENTED("DescribeCounter"); -} - -vector VulkanReplay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) -{ - RDCUNIMPLEMENTED("FetchCounters"); - return vector(); -} - void VulkanReplay::BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) { VULKANNOTIMP("BuildTargetShader"); @@ -4429,6 +4416,8 @@ ReplayCreateStatus Vulkan_CreateReplayDevice(const char *logfile, IReplayDriver RDCLOG("Captured API version is not the same as RenderDoc's built version, expected %d got %d", VK_API_VERSION, initParams.APIVersion); RDCLOG("This isn't a problem as this information is optional, but RenderDoc will replay with its own API version"); } + + VulkanReplay::PreDeviceInitCounters(); WrappedVulkan *vk = new WrappedVulkan(logfile); vk->Initialise(initParams); diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 40b600c62..c82662281 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -172,6 +172,13 @@ class VulkanReplay : public IReplayDriver void InitCallstackResolver(); bool HasCallstacks(); Callstack::StackResolver *GetCallstackResolver(); + + // called before any VkDevice is created, to init any counters + static void PreDeviceInitCounters(); + // called after any VkDevice is destroyed, to do corresponding shutdown of counters + static void PostDeviceShutdownCounters(); + // called after the VkDevice is created, to init any counters + void PostDeviceInitCounters(); private: struct OutputWindow { @@ -249,7 +256,10 @@ class VulkanReplay : public IReplayDriver void CreateTexImageView(VkImageAspectFlags aspectFlags, VkImage liveIm, VulkanCreationInfo::Image &iminfo); void FillCBufferVariables(rdctype::array, vector &outvars, const vector &data, size_t &offset); - + + // called before the VkDevice is destroyed, to shutdown any counters + void PreDeviceShutdownCounters(); + VulkanDebugManager *GetDebugManager(); VulkanResourceManager *GetResourceManager(); };