forked from ShuriZma/suyu
vk_master_semaphore: Move fence wait on separate thread
This commit is contained in:
parent
1e398e6c36
commit
4e491ab59b
|
@ -10,11 +10,16 @@
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
|
constexpr u64 FENCE_RESERVE_SIZE = 8;
|
||||||
|
|
||||||
MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) {
|
MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) {
|
||||||
if (!device.HasTimelineSemaphore()) {
|
if (!device.HasTimelineSemaphore()) {
|
||||||
static constexpr VkFenceCreateInfo fence_ci{
|
static constexpr VkFenceCreateInfo fence_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0};
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0};
|
||||||
fence = device.GetLogical().CreateFence(fence_ci);
|
free_queue.resize(FENCE_RESERVE_SIZE);
|
||||||
|
std::ranges::generate(free_queue,
|
||||||
|
[&] { return device.GetLogical().CreateFence(fence_ci); });
|
||||||
|
wait_thread = std::jthread([this](std::stop_token token) { WaitThread(token); });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,16 +172,53 @@ VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphor
|
||||||
.pSignalSemaphores = &signal_semaphore,
|
.pSignalSemaphores = &signal_semaphore,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto fence = GetFreeFence();
|
||||||
auto result = device.GetGraphicsQueue().Submit(submit_info, *fence);
|
auto result = device.GetGraphicsQueue().Submit(submit_info, *fence);
|
||||||
|
|
||||||
if (result == VK_SUCCESS) {
|
if (result == VK_SUCCESS) {
|
||||||
fence.Wait();
|
std::scoped_lock lock{wait_mutex};
|
||||||
fence.Reset();
|
wait_queue.emplace(host_tick, std::move(fence));
|
||||||
gpu_tick.store(host_tick);
|
wait_cv.notify_one();
|
||||||
gpu_tick.notify_all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MasterSemaphore::WaitThread(std::stop_token token) {
|
||||||
|
while (!token.stop_requested()) {
|
||||||
|
u64 host_tick;
|
||||||
|
vk::Fence fence;
|
||||||
|
{
|
||||||
|
std::unique_lock lock{wait_mutex};
|
||||||
|
Common::CondvarWait(wait_cv, lock, token, [this] { return !wait_queue.empty(); });
|
||||||
|
if (token.stop_requested()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::tie(host_tick, fence) = std::move(wait_queue.front());
|
||||||
|
wait_queue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
fence.Wait();
|
||||||
|
fence.Reset();
|
||||||
|
gpu_tick.store(host_tick);
|
||||||
|
gpu_tick.notify_all();
|
||||||
|
|
||||||
|
std::scoped_lock lock{free_mutex};
|
||||||
|
free_queue.push_front(std::move(fence));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Fence MasterSemaphore::GetFreeFence() {
|
||||||
|
std::scoped_lock lock{free_mutex};
|
||||||
|
if (free_queue.empty()) {
|
||||||
|
static constexpr VkFenceCreateInfo fence_ci{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0};
|
||||||
|
return device.GetLogical().CreateFence(fence_ci);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fence = std::move(free_queue.back());
|
||||||
|
free_queue.pop_back();
|
||||||
|
return fence;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/polyfill_thread.h"
|
#include "common/polyfill_thread.h"
|
||||||
|
@ -17,6 +19,8 @@ namespace Vulkan {
|
||||||
class Device;
|
class Device;
|
||||||
|
|
||||||
class MasterSemaphore {
|
class MasterSemaphore {
|
||||||
|
using Waitable = std::pair<u64, vk::Fence>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MasterSemaphore(const Device& device);
|
explicit MasterSemaphore(const Device& device);
|
||||||
~MasterSemaphore();
|
~MasterSemaphore();
|
||||||
|
@ -57,13 +61,22 @@ private:
|
||||||
VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
|
VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
|
||||||
VkSemaphore wait_semaphore, u64 host_tick);
|
VkSemaphore wait_semaphore, u64 host_tick);
|
||||||
|
|
||||||
|
void WaitThread(std::stop_token token);
|
||||||
|
|
||||||
|
vk::Fence GetFreeFence();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Device& device; ///< Device.
|
const Device& device; ///< Device.
|
||||||
vk::Fence fence; ///< Fence.
|
|
||||||
vk::Semaphore semaphore; ///< Timeline semaphore.
|
vk::Semaphore semaphore; ///< Timeline semaphore.
|
||||||
std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
|
std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
|
||||||
std::atomic<u64> current_tick{1}; ///< Current logical tick.
|
std::atomic<u64> current_tick{1}; ///< Current logical tick.
|
||||||
|
std::mutex wait_mutex;
|
||||||
|
std::mutex free_mutex;
|
||||||
|
std::condition_variable_any wait_cv;
|
||||||
|
std::queue<Waitable> wait_queue; ///< Queue for the fences to be waited on by the wait thread.
|
||||||
|
std::deque<vk::Fence> free_queue; ///< Holds available fences for submission.
|
||||||
std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs.
|
std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs.
|
||||||
|
std::jthread wait_thread; ///< Helper thread that waits for submitted fences.
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
Loading…
Reference in New Issue