citra/src/video_core/renderer_vulkan/vk_master_semaphore.h

108 lines
2.7 KiB
C++

// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <condition_variable>
#include <queue>
#include "common/common_types.h"
#include "common/polyfill_thread.h"
#include "video_core/renderer_vulkan/vk_common.h"
namespace Vulkan {
class Instance;
class Scheduler;
class MasterSemaphore {
public:
virtual ~MasterSemaphore() = default;
[[nodiscard]] u64 CurrentTick() const noexcept {
return current_tick.load(std::memory_order_acquire);
}
[[nodiscard]] u64 KnownGpuTick() const noexcept {
return gpu_tick.load(std::memory_order_acquire);
}
[[nodiscard]] bool IsFree(u64 tick) const noexcept {
return KnownGpuTick() >= tick;
}
[[nodiscard]] u64 NextTick() noexcept {
return current_tick.fetch_add(1, std::memory_order_release);
}
/// Refresh the known GPU tick
virtual void Refresh() = 0;
/// Waits for a tick to be hit on the GPU
virtual void Wait(u64 tick) = 0;
/// Submits the provided command buffer for execution
virtual void SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wait, vk::Semaphore signal,
u64 signal_value) = 0;
protected:
std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
std::atomic<u64> current_tick{1}; ///< Current logical tick.
};
class MasterSemaphoreTimeline : public MasterSemaphore {
public:
explicit MasterSemaphoreTimeline(const Instance& instance);
~MasterSemaphoreTimeline() override;
[[nodiscard]] vk::Semaphore Handle() const noexcept {
return semaphore.get();
}
void Refresh() override;
void Wait(u64 tick) override;
void SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wait, vk::Semaphore signal,
u64 signal_value) override;
private:
const Instance& instance;
vk::UniqueSemaphore semaphore; ///< Timeline semaphore.
};
class MasterSemaphoreFence : public MasterSemaphore {
public:
explicit MasterSemaphoreFence(const Instance& instance);
~MasterSemaphoreFence() override;
void Refresh() override;
void Wait(u64 tick) override;
void SubmitWork(vk::CommandBuffer cmdbuf, vk::Semaphore wait, vk::Semaphore signal,
u64 signal_value) override;
private:
void WaitThread(std::stop_token token);
vk::UniqueFence GetFreeFence();
private:
const Instance& instance;
struct Fence {
vk::UniqueFence handle;
u64 signal_value;
};
std::queue<vk::UniqueFence> free_queue;
std::queue<Fence> wait_queue;
std::mutex free_mutex;
std::mutex wait_mutex;
std::condition_variable_any wait_cv;
std::jthread wait_thread;
};
} // namespace Vulkan