Implement Present Wait

This commit is contained in:
Scott Mansell 2023-01-19 15:52:59 +13:00 committed by nyanpasu64
parent 0a532adfef
commit ae837c3493
10 changed files with 141 additions and 5 deletions

View File

@ -610,6 +610,7 @@
<ClInclude Include="VideoBackends\Vulkan\CommandBufferManager.h" />
<ClInclude Include="VideoBackends\Vulkan\Constants.h" />
<ClInclude Include="VideoBackends\Vulkan\ObjectCache.h" />
<ClInclude Include="VideoBackends\Vulkan\PresentWait.h" />
<ClInclude Include="VideoBackends\Vulkan\ShaderCompiler.h" />
<ClInclude Include="VideoBackends\Vulkan\StagingBuffer.h" />
<ClInclude Include="VideoBackends\Vulkan\StateTracker.h" />
@ -1228,6 +1229,7 @@
<ClCompile Include="VideoBackends\Software\TransformUnit.cpp" />
<ClCompile Include="VideoBackends\Vulkan\CommandBufferManager.cpp" />
<ClCompile Include="VideoBackends\Vulkan\ObjectCache.cpp" />
<ClCompile Include="VideoBackends\Vulkan\PresentWait.cpp" />
<ClCompile Include="VideoBackends\Vulkan\ShaderCompiler.cpp" />
<ClCompile Include="VideoBackends\Vulkan\StagingBuffer.cpp" />
<ClCompile Include="VideoBackends\Vulkan\StateTracker.cpp" />

View File

@ -4,6 +4,8 @@ add_library(videovulkan
Constants.h
ObjectCache.cpp
ObjectCache.h
PresentWait.cpp
PresentWait.h
ShaderCompiler.cpp
ShaderCompiler.h
StagingBuffer.cpp

View File

@ -10,6 +10,7 @@
#include "Common/MsgHandler.h"
#include "Common/Thread.h"
#include "VideoBackends/Vulkan/PresentWait.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoCommon/Constants.h"
@ -223,7 +224,7 @@ bool CommandBufferManager::CreateSubmitThread()
{
m_submit_thread.Reset("VK submission thread", [this](PendingCommandBufferSubmit submit) {
SubmitCommandBuffer(submit.command_buffer_index, submit.present_swap_chain,
submit.present_image_index);
submit.present_image_index, submit.frame_id);
CmdBufferResources& resources = m_command_buffers[submit.command_buffer_index];
resources.waiting_for_submit.store(false, std::memory_order_release);
});
@ -317,19 +318,25 @@ void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
}
}
uint64_t frame_id = 0;
if (present_swap_chain != VK_NULL_HANDLE)
{
frame_id = g_vulkan_context->NextPresentCount();
}
// Submitting off-thread?
if (m_use_threaded_submission && submit_on_worker_thread && !wait_for_completion)
{
resources.waiting_for_submit.store(true, std::memory_order_relaxed);
// Push to the pending submit queue.
m_submit_thread.Push({present_swap_chain, present_image_index, m_current_cmd_buffer});
m_submit_thread.Push({present_swap_chain, present_image_index, m_current_cmd_buffer, frame_id});
}
else
{
WaitForWorkerThreadIdle();
// Pass through to normal submission path.
SubmitCommandBuffer(m_current_cmd_buffer, present_swap_chain, present_image_index);
SubmitCommandBuffer(m_current_cmd_buffer, present_swap_chain, present_image_index, frame_id);
if (wait_for_completion)
WaitForCommandBufferCompletion(m_current_cmd_buffer);
}
@ -382,7 +389,7 @@ void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
void CommandBufferManager::SubmitCommandBuffer(u32 command_buffer_index,
VkSwapchainKHR present_swap_chain,
u32 present_image_index)
u32 present_image_index, u64 frame_id)
{
CmdBufferResources& resources = m_command_buffers[command_buffer_index];
@ -439,6 +446,14 @@ void CommandBufferManager::SubmitCommandBuffer(u32 command_buffer_index,
&present_image_index,
nullptr};
VkPresentIdKHR present_id = {VK_STRUCTURE_TYPE_PRESENT_ID_KHR, nullptr, 1, &frame_id};
if (g_vulkan_context->SupportsPresentWait())
{
present_info.pNext = &present_id;
PresentQueued(frame_id, present_swap_chain);
}
m_last_present_result = vkQueuePresentKHR(g_vulkan_context->GetPresentQueue(), &present_info);
m_last_present_done.Set();
if (m_last_present_result != VK_SUCCESS)

View File

@ -102,7 +102,7 @@ private:
void WaitForCommandBufferCompletion(u32 command_buffer_index);
void SubmitCommandBuffer(u32 command_buffer_index, VkSwapchainKHR present_swap_chain,
u32 present_image_index);
u32 present_image_index, u64 frame_id);
void BeginCommandBuffer();
VkDescriptorPool CreateDescriptorPool(u32 descriptor_sizes);
@ -152,6 +152,7 @@ private:
VkSwapchainKHR present_swap_chain;
u32 present_image_index;
u32 command_buffer_index;
u64 frame_id;
};
Common::WorkQueueThread<PendingCommandBufferSubmit> m_submit_thread;
VkSemaphore m_present_semaphore = VK_NULL_HANDLE;

View File

@ -0,0 +1,81 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Vulkan/PresentWait.h"
#include <deque>
#include <thread>
#include <tuple>
#include "Common/BlockingLoop.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoBackends/Vulkan/VulkanLoader.h"
#include "VideoCommon/PerformanceMetrics.h"
#include <chrono>
namespace Vulkan
{
static std::thread s_present_wait_thread;
static Common::BlockingLoop s_present_wait_loop;
static std::deque<std::tuple<u64, VkSwapchainKHR>> s_present_wait_queue;
static void PresentWaitThreadFunc()
{
VkDevice device = g_vulkan_context->GetDevice();
s_present_wait_loop.Run([device]() {
if (s_present_wait_queue.empty())
{
s_present_wait_loop.AllowSleep();
return;
}
u64 present_id;
VkSwapchainKHR swapchain;
std::tie(present_id, swapchain) = s_present_wait_queue.back();
auto start = std::chrono::high_resolution_clock::now();
VkResult res = vkWaitForPresentKHR(device, swapchain, present_id, 100'000'000); // 100ms
if (res == VK_TIMEOUT)
{
WARN_LOG_FMT(VIDEO, "vkWaitForPresentKHR timed out, retrying {}", present_id);
return;
}
s_present_wait_queue.pop_back();
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkWaitForPresentKHR failed: ");
}
if (res == VK_SUCCESS)
{
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
fmt::print("vkWaitForPresentKHR took {}us\n", duration.count());
g_perf_metrics.CountPresent();
}
});
}
void StartPresentWaitThread()
{
fmt::print("Starting PresentWaitThread");
s_present_wait_thread = std::thread(PresentWaitThreadFunc);
}
void PresentQueued(u64 present_id, VkSwapchainKHR swapchain)
{
s_present_wait_queue.emplace_front(std::make_tuple(present_id, swapchain));
s_present_wait_loop.Wakeup();
}
} // namespace Vulkan

View File

@ -0,0 +1,15 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "Common/CommonTypes.h"
#include "VideoBackends/Vulkan/VulkanLoader.h"
namespace Vulkan
{
void StartPresentWaitThread();
void PresentQueued(u64 present_id, VkSwapchainKHR swapchain);
} // namespace Vulkan

View File

@ -11,6 +11,7 @@
#include "VideoBackends/Vulkan/CommandBufferManager.h"
#include "VideoBackends/Vulkan/Constants.h"
#include "VideoBackends/Vulkan/ObjectCache.h"
#include "VideoBackends/Vulkan/PresentWait.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKBoundingBox.h"
#include "VideoBackends/Vulkan/VKGfx.h"
@ -225,6 +226,11 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
Shutdown();
return false;
}
if (g_vulkan_context->SupportsPresentWait())
{
StartPresentWaitThread();
}
}
if (!StateTracker::CreateInstance())

View File

@ -139,6 +139,9 @@ public:
bool SupportsPresentWait() const { return m_device_features.present_wait.presentWait; }
// Present Count is required to be non-zero and always increasing.
uint64_t NextPresentCount() { return ++m_present_count; }
VmaAllocator GetMemoryAllocator() const { return m_allocator; }
#ifdef WIN32
@ -180,6 +183,8 @@ private:
bool m_supports_shader_subgroup_operations = false;
std::vector<std::string> m_device_extensions;
uint64_t m_present_count = 0;
};
extern std::unique_ptr<VulkanContext> g_vulkan_context;

View File

@ -19,6 +19,7 @@ void PerformanceMetrics::Reset()
{
m_fps_counter.Reset();
m_vps_counter.Reset();
m_present_counter.Reset();
m_speed_counter.Reset();
m_time_sleeping = DT::zero();
@ -36,6 +37,11 @@ void PerformanceMetrics::CountVBlank()
m_vps_counter.Count();
}
void PerformanceMetrics::CountPresent()
{
m_present_counter.Count();
}
void PerformanceMetrics::CountThrottleSleep(DT sleep)
{
std::unique_lock lock(m_time_lock);
@ -178,6 +184,7 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
ImPlot::SetupLegend(ImPlotLocation_SouthEast, ImPlotLegendFlags_None);
m_vps_counter.ImPlotPlotLines("V-Blank (ms)");
m_fps_counter.ImPlotPlotLines("Frame (ms)");
m_present_counter.ImPlotPlotLines("Present (ms)");
ImPlot::EndPlot();
ImPlot::PopStyleVar(2);
ImPlot::PopStyleColor(2);

View File

@ -29,6 +29,7 @@ public:
void Reset();
void CountFrame();
void CountVBlank();
void CountPresent();
void CountThrottleSleep(DT sleep);
void CountPerformanceMarker(Core::System& system, s64 cyclesLate);
@ -47,6 +48,7 @@ public:
private:
PerformanceTracker m_fps_counter{"render_times.txt"};
PerformanceTracker m_vps_counter{"vblank_times.txt"};
PerformanceTracker m_present_counter{std::nullopt};
PerformanceTracker m_speed_counter{std::nullopt, 1000000};
double m_graph_max_time = 0.0;