Browse Source

[vk] use boost::container::deque instead of std::queue for presentation swapchain of frames

This may reduce total overhead (as benchmarks show boost::container::deque being better performing than std::deque, especially with the limited set of ops like push_front and pop_back
May actually not help at all and be worse through, as always, performance tests are welcome

Signed-off-by: lizzie <lizzie@eden-emu.dev>
pull/3120/head
lizzie 3 weeks ago
committed by crueter
parent
commit
c2dc8b5d81
  1. 57
      src/video_core/renderer_vulkan/vk_present_manager.cpp
  2. 6
      src/video_core/renderer_vulkan/vk_present_manager.h

57
src/video_core/renderer_vulkan/vk_present_manager.cpp

@ -146,7 +146,7 @@ PresentManager::PresentManager(const vk::Instance& instance_,
.pNext = nullptr, .pNext = nullptr,
.flags = VK_FENCE_CREATE_SIGNALED_BIT, .flags = VK_FENCE_CREATE_SIGNALED_BIT,
}); });
free_queue.push(&frame);
free_queue.push_back(&frame);
} }
if (use_present_thread) { if (use_present_thread) {
@ -164,7 +164,7 @@ Frame* PresentManager::GetRenderFrame() {
// Take the frame from the queue // Take the frame from the queue
Frame* frame = free_queue.front(); Frame* frame = free_queue.front();
free_queue.pop();
free_queue.pop_front();
// Wait for the presentation to be finished so all frame resources are free // Wait for the presentation to be finished so all frame resources are free
frame->present_done.Wait(); frame->present_done.Wait();
@ -174,18 +174,17 @@ Frame* PresentManager::GetRenderFrame() {
} }
void PresentManager::Present(Frame* frame) { void PresentManager::Present(Frame* frame) {
if (!use_present_thread) {
if (use_present_thread) {
scheduler.Record([this, frame](vk::CommandBuffer) {
std::unique_lock lock{queue_mutex};
present_queue.push_back(frame);
frame_cv.notify_one();
});
} else {
scheduler.WaitWorker(); scheduler.WaitWorker();
CopyToSwapchain(frame); CopyToSwapchain(frame);
free_queue.push(frame);
return;
free_queue.push_back(frame);
} }
scheduler.Record([this, frame](vk::CommandBuffer) {
std::unique_lock lock{queue_mutex};
present_queue.push(frame);
frame_cv.notify_one();
});
} }
void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
@ -277,29 +276,25 @@ void PresentManager::PresentThread(std::stop_token token) {
Common::SetCurrentThreadName("VulkanPresent"); Common::SetCurrentThreadName("VulkanPresent");
while (!token.stop_requested()) { while (!token.stop_requested()) {
std::unique_lock lock{queue_mutex}; std::unique_lock lock{queue_mutex};
// Wait for presentation frames // Wait for presentation frames
frame_cv.wait(lock, token, [this] { return !present_queue.empty(); }); frame_cv.wait(lock, token, [this] { return !present_queue.empty(); });
if (token.stop_requested()) {
return;
if (!token.stop_requested()) {
// Take the frame and notify anyone waiting
Frame* frame = present_queue.front();
present_queue.pop_front();
frame_cv.notify_one();
// By exchanging the lock ownership we take the swapchain lock
// before the queue lock goes out of scope. This way the swapchain
// lock in WaitPresent is guaranteed to occur after here.
std::exchange(lock, std::unique_lock{swapchain_mutex});
CopyToSwapchain(frame);
// Free the frame for reuse
std::scoped_lock fl{free_mutex};
free_queue.push_back(frame);
free_cv.notify_one();
} }
// Take the frame and notify anyone waiting
Frame* frame = present_queue.front();
present_queue.pop();
frame_cv.notify_one();
// By exchanging the lock ownership we take the swapchain lock
// before the queue lock goes out of scope. This way the swapchain
// lock in WaitPresent is guaranteed to occur after here.
std::exchange(lock, std::unique_lock{swapchain_mutex});
CopyToSwapchain(frame);
// Free the frame for reuse
std::scoped_lock fl{free_mutex};
free_queue.push(frame);
free_cv.notify_one();
} }
} }

6
src/video_core/renderer_vulkan/vk_present_manager.h

@ -5,7 +5,7 @@
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <queue>
#include <boost/container/deque.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/polyfill_thread.h" #include "common/polyfill_thread.h"
@ -88,8 +88,8 @@ private:
#endif #endif
vk::CommandPool cmdpool; vk::CommandPool cmdpool;
std::vector<Frame> frames; std::vector<Frame> frames;
std::queue<Frame*> present_queue;
std::queue<Frame*> free_queue;
boost::container::deque<Frame*> present_queue;
boost::container::deque<Frame*> free_queue;
std::condition_variable_any frame_cv; std::condition_variable_any frame_cv;
std::condition_variable free_cv; std::condition_variable free_cv;
std::mutex swapchain_mutex; std::mutex swapchain_mutex;

Loading…
Cancel
Save