From 66609b395f03c1177c06c6a8cbb574db83578e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Aug 2019 16:46:58 +0200 Subject: [PATCH 1/2] Vulkan: Profile individual render passes/steps. --- ext/native/thin3d/VulkanQueueRunner.cpp | 36 ++++++++++++++++++++++- ext/native/thin3d/VulkanQueueRunner.h | 4 ++- ext/native/thin3d/VulkanRenderManager.cpp | 12 ++++---- ext/native/thin3d/VulkanRenderManager.h | 4 +-- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index d9ed03a426..92f3847ef5 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -374,7 +374,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { return pass; } -void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &steps) { +void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &steps, VkQueryPool queryPool, std::vector *timestampDescriptions) { // Optimizes renderpasses, then sequences them. // Planned optimizations: // * Create copies of render target that are rendered to multiple times and textured from in sequence, and push those render passes @@ -461,6 +461,11 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st case VKRStepType::RENDER_SKIP: break; } + + if (queryPool) { + vkCmdWriteTimestamp(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, (uint32_t)timestampDescriptions->size()); + timestampDescriptions->push_back(StepToString(step)); + } } // Deleting all in one go should be easier on the instruction cache than deleting @@ -695,10 +700,39 @@ void VulkanQueueRunner::ApplySonicHack(std::vector &steps) { } } +std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { + char buffer[256]; + switch (step.stepType) { + case VKRStepType::RENDER: + snprintf(buffer, sizeof(buffer), "RenderPass (fb: %p)", step.render.framebuffer); + break; + case VKRStepType::COPY: + snprintf(buffer, sizeof(buffer), "Copy (%dx%d)", step.copy.srcRect.extent.width, step.copy.srcRect.extent.height); + break; + case VKRStepType::BLIT: + snprintf(buffer, sizeof(buffer), "Blit"); + break; + case VKRStepType::READBACK: + snprintf(buffer, sizeof(buffer), "Readback"); + break; + case VKRStepType::READBACK_IMAGE: + snprintf(buffer, sizeof(buffer), "ReadbackImage"); + break; + case VKRStepType::RENDER_SKIP: + snprintf(buffer, sizeof(buffer), "(SKIPPED RenderPass)"); + break; + default: + buffer[0] = 0; + break; + } + return std::string(buffer); +} + void VulkanQueueRunner::LogSteps(const std::vector &steps) { ILOG("======================================="); for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; + ILOG("%s", StepToString(step).c_str()); switch (step.stepType) { case VKRStepType::RENDER: LogRenderPass(step); diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/ext/native/thin3d/VulkanQueueRunner.h index 17f0acb69a..b7f4c33090 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/ext/native/thin3d/VulkanQueueRunner.h @@ -163,9 +163,11 @@ public: } // RunSteps can modify steps but will leave it in a valid state. - void RunSteps(VkCommandBuffer cmd, std::vector &steps); + void RunSteps(VkCommandBuffer cmd, std::vector &steps, VkQueryPool queryPool, std::vector *timestampDescriptions); void LogSteps(const std::vector &steps); + std::string StepToString(const VKRStep &step) const; + void CreateDeviceObjects(); void DestroyDeviceObjects(); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 2fe59d3be0..827ea1ab66 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -350,12 +350,12 @@ void VulkanRenderManager::ThreadFunc() { } void VulkanRenderManager::BeginFrame(bool enableProfiling) { - gpuProfilingEnabled_ = enableProfiling; VLOG("BeginFrame"); VkDevice device = vulkan_->GetDevice(); int curFrame = vulkan_->GetCurFrame(); FrameData &frameData = frameData_[curFrame]; + frameData.profilingEnabled_ = enableProfiling; // Make sure the very last command buffer from the frame before the previous has been fully executed. if (useThread_) { @@ -373,7 +373,7 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling) { uint64_t queryResults[MAX_TIMESTAMP_QUERIES]; - if (gpuProfilingEnabled_) { + if (frameData.profilingEnabled_) { // Pull the profiling results from last time and produce a summary! if (!frameData.timestampDescriptions.empty()) { int numQueries = (int)frameData.timestampDescriptions.size(); @@ -416,7 +416,7 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling) { insideFrame_ = true; frameData.timestampDescriptions.clear(); - if (gpuProfilingEnabled_) { + if (frameData_->profilingEnabled_) { // For various reasons, we need to always use an init cmd buffer in this case to perform the vkCmdResetQueryPool, // unless we want to limit ourselves to only measure the main cmd buffer. // Reserve the first two queries for initCmd. @@ -954,7 +954,7 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) { void VulkanRenderManager::Submit(int frame, bool triggerFence) { FrameData &frameData = frameData_[frame]; if (frameData.hasInitCommands) { - if (gpuProfilingEnabled_ && triggerFence) { + if (frameData.profilingEnabled_ && triggerFence) { // Pre-allocated query ID 1. vkCmdWriteTimestamp(frameData.initCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frameData.timestampQueryPool_, 1); } @@ -962,7 +962,7 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { _assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (init)! result=%s", VulkanResultToString(res)); } - if (gpuProfilingEnabled_) { + if (frameData.profilingEnabled_) { int numQueries = (int)frameData.timestampDescriptions.size(); vkCmdWriteTimestamp(frameData.mainCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frameData.timestampQueryPool_, numQueries); frameData.timestampDescriptions.push_back("mainCmd"); @@ -1063,7 +1063,7 @@ void VulkanRenderManager::Run(int frame) { auto &stepsOnThread = frameData_[frame].steps; VkCommandBuffer cmd = frameData.mainCmd; // queueRunner_.LogSteps(stepsOnThread); - queueRunner_.RunSteps(cmd, stepsOnThread); + queueRunner_.RunSteps(cmd, stepsOnThread, frameData.profilingEnabled_ ? frameData.timestampQueryPool_ : VK_NULL_HANDLE, &frameData.timestampDescriptions); stepsOnThread.clear(); switch (frameData.type) { diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 0b272f1257..a06332aa69 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -291,6 +291,7 @@ private: // Profiling. VkQueryPool timestampQueryPool_ = VK_NULL_HANDLE; + bool profilingEnabled_; std::vector timestampDescriptions; std::string profileSummary; }; @@ -301,9 +302,6 @@ private: MAX_TIMESTAMP_QUERIES = 256, }; - // Global state - bool gpuProfilingEnabled_ = false; - // Submission time state int curWidth_ = -1; int curHeight_ = -1; From e3f1e563f25bb9b1778e595283212d723c7af510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Aug 2019 18:28:20 +0200 Subject: [PATCH 2/2] Improve renderpass profiling descriptions a little --- GPU/Vulkan/DebugVisVulkan.cpp | 1 + ext/native/thin3d/VulkanQueueRunner.cpp | 10 +++++++--- ext/native/thin3d/VulkanRenderManager.cpp | 6 ------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/GPU/Vulkan/DebugVisVulkan.cpp b/GPU/Vulkan/DebugVisVulkan.cpp index 1745cf57c1..091f576679 100644 --- a/GPU/Vulkan/DebugVisVulkan.cpp +++ b/GPU/Vulkan/DebugVisVulkan.cpp @@ -116,6 +116,7 @@ void DrawProfilerVis(UIContext *ui, GPUInterface *gpu) { std::string text = gpuVulkan->GetGpuProfileString(); Draw::DrawContext *draw = ui->GetDrawContext(); + ui->SetFontScale(0.4f, 0.4f); ui->DrawTextShadow(text.c_str(), 10, 50, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); ui->Flush(); } diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 92f3847ef5..5b5d60c74c 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -704,16 +704,20 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { char buffer[256]; switch (step.stepType) { case VKRStepType::RENDER: - snprintf(buffer, sizeof(buffer), "RenderPass (fb: %p)", step.render.framebuffer); + { + int w = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth(); + int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight(); + snprintf(buffer, sizeof(buffer), "RenderPass (draws: %d, %dx%d, fb: %p, )", step.render.numDraws, w, h, step.render.framebuffer); break; + } case VKRStepType::COPY: snprintf(buffer, sizeof(buffer), "Copy (%dx%d)", step.copy.srcRect.extent.width, step.copy.srcRect.extent.height); break; case VKRStepType::BLIT: - snprintf(buffer, sizeof(buffer), "Blit"); + snprintf(buffer, sizeof(buffer), "Blit (%dx%d->%dx%d)", step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height); break; case VKRStepType::READBACK: - snprintf(buffer, sizeof(buffer), "Readback"); + snprintf(buffer, sizeof(buffer), "Readback (%dx%d)", step.readback.srcRect.extent.width, step.readback.srcRect.extent.height); break; case VKRStepType::READBACK_IMAGE: snprintf(buffer, sizeof(buffer), "ReadbackImage"); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 827ea1ab66..77e66ed7b8 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -962,12 +962,6 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { _assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (init)! result=%s", VulkanResultToString(res)); } - if (frameData.profilingEnabled_) { - int numQueries = (int)frameData.timestampDescriptions.size(); - vkCmdWriteTimestamp(frameData.mainCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frameData.timestampQueryPool_, numQueries); - frameData.timestampDescriptions.push_back("mainCmd"); - } - VkResult res = vkEndCommandBuffer(frameData.mainCmd); _assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (main)! result=%s", VulkanResultToString(res));