Implement Present Wait
This commit is contained in:
parent
0a532adfef
commit
ae837c3493
|
@ -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" />
|
||||
|
|
|
@ -4,6 +4,8 @@ add_library(videovulkan
|
|||
Constants.h
|
||||
ObjectCache.cpp
|
||||
ObjectCache.h
|
||||
PresentWait.cpp
|
||||
PresentWait.h
|
||||
ShaderCompiler.cpp
|
||||
ShaderCompiler.h
|
||||
StagingBuffer.cpp
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue