diff options
| author | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2026-04-05 16:59:32 +1000 |
|---|---|---|
| committer | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2026-04-05 16:59:32 +1000 |
| commit | 411f7acb1f92db88d2a3c92bb40da2133852b40e (patch) | |
| tree | a37377abea35bb01e6e1074e15e4c1b50f66ccf1 /src | |
| parent | 6cae1c14ebdd9d026134212ed8561fb845a11ff6 (diff) | |
Nuke old implementation, silence warnings
Diffstat (limited to 'src')
| -rw-r--r-- | src/device_context.cc | 30 | ||||
| -rw-r--r-- | src/device_context.hh | 16 | ||||
| -rw-r--r-- | src/layer.cc | 92 | ||||
| -rw-r--r-- | src/queue_context.cc | 87 | ||||
| -rw-r--r-- | src/queue_context.hh | 76 | ||||
| -rw-r--r-- | src/submissions.cc | 0 | ||||
| -rw-r--r-- | src/submissions.hh | 12 | ||||
| -rw-r--r-- | src/swapchain_monitor.cc | 165 | ||||
| -rw-r--r-- | src/swapchain_monitor.hh | 122 |
9 files changed, 25 insertions, 575 deletions
diff --git a/src/device_context.cc b/src/device_context.cc index 35ae9c4..d61c1bf 100644 --- a/src/device_context.cc +++ b/src/device_context.cc @@ -28,34 +28,4 @@ DeviceContext::~DeviceContext() { } } -void DeviceContext::update_params( - const std::optional<VkSwapchainKHR> target, - const std::chrono::microseconds& present_delay, - const bool was_low_latency_requested) { - - // If we don't have a target (AMD's anti_lag doesn't differentiate between - // swapchains) just write it to everything. - if (!target.has_value()) { - for (auto& iter : this->swapchain_monitors) { - iter.second->update_params(was_low_latency_requested, - present_delay); - } - return; - } - - const auto iter = this->swapchain_monitors.find(*target); - assert(iter != std::end(this->swapchain_monitors)); - iter->second->update_params(was_low_latency_requested, present_delay); -} - -void DeviceContext::notify_present( - const VkSwapchainKHR& swapchain, - std::unique_ptr<QueueContext::Submissions> submissions) { - - const auto iter = this->swapchain_monitors.find(swapchain); - assert(iter != std::end(this->swapchain_monitors)); - - iter->second->notify_present(std::move(submissions)); -} - } // namespace low_latency
\ No newline at end of file diff --git a/src/device_context.hh b/src/device_context.hh index f94b84f..c4d6a43 100644 --- a/src/device_context.hh +++ b/src/device_context.hh @@ -1,7 +1,6 @@ #ifndef DEVICE_CONTEXT_HH_ #define DEVICE_CONTEXT_HH_ -#include <chrono> #include <memory> #include <unordered_map> @@ -15,7 +14,6 @@ #include "instance_context.hh" #include "physical_device_context.hh" #include "queue_context.hh" -#include "swapchain_monitor.hh" namespace low_latency { @@ -32,28 +30,14 @@ class DeviceContext final : public Context { const VkuDeviceDispatchTable vtable; std::unique_ptr<DeviceClock> clock; - std::unordered_map<VkQueue, std::shared_ptr<QueueContext>> queues; - std::unordered_map<VkSwapchainKHR, std::unique_ptr<SwapchainMonitor>> - swapchain_monitors; - public: DeviceContext(InstanceContext& parent_instance, PhysicalDeviceContext& parent_physical, const VkDevice& device, const bool was_capability_requested, VkuDeviceDispatchTable&& vtable); virtual ~DeviceContext(); - - public: - // Updates the settings associated with that swapchain. If no swapchain - // target is provided all swapchains are set to this value. - void update_params(const std::optional<VkSwapchainKHR> target, - const std::chrono::microseconds& present_delay, - const bool was_low_latency_requested); - - void notify_present(const VkSwapchainKHR& swapchain, - std::unique_ptr<QueueContext::Submissions> submissions); }; }; // namespace low_latency diff --git a/src/layer.cc b/src/layer.cc index cb045c4..516f9d3 100644 --- a/src/layer.cc +++ b/src/layer.cc @@ -20,7 +20,6 @@ #include "instance_context.hh" #include "layer_context.hh" #include "queue_context.hh" -#include "swapchain_monitor.hh" #include "timestamp_pool.hh" namespace low_latency { @@ -394,7 +393,7 @@ vkQueueSubmit(VkQueue queue, std::uint32_t submit_count, // more explicit + insurance if that changes. auto handles = std::vector<std::shared_ptr<TimestampPool::Handle>>{}; - const auto now = DeviceClock::now(); + [[maybe_unused]] const auto now = DeviceClock::now(); std::ranges::transform( std::span{submit_infos, submit_count}, std::back_inserter(next_submits), @@ -405,9 +404,6 @@ vkQueueSubmit(VkQueue queue, std::uint32_t submit_count, const auto tail_handle = context->timestamp_pool->acquire(); tail_handle->write_command(VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT); - context->notify_submit(extract_present_id(submit), head_handle, - tail_handle, now); - handles.emplace_back(head_handle); handles.emplace_back(tail_handle); next_cbs.emplace_back([&]() -> auto { @@ -449,7 +445,7 @@ vkQueueSubmit2(VkQueue queue, std::uint32_t submit_count, auto next_cbs = std::vector<std::unique_ptr<cbs_t>>{}; auto handles = std::vector<std::shared_ptr<TimestampPool::Handle>>{}; - const auto now = DeviceClock::now(); + [[maybe_unused]] const auto now = DeviceClock::now(); std::ranges::transform( std::span{submit_infos, submit_count}, std::back_inserter(next_submits), @@ -459,9 +455,6 @@ vkQueueSubmit2(VkQueue queue, std::uint32_t submit_count, const auto tail_handle = context->timestamp_pool->acquire(); tail_handle->write_command(VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT); - context->notify_submit(extract_present_id(submit), head_handle, - tail_handle, now); - handles.emplace_back(head_handle); handles.emplace_back(tail_handle); next_cbs.emplace_back([&]() -> auto { @@ -514,13 +507,11 @@ vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { present_info, VK_STRUCTURE_TYPE_PRESENT_ID_KHR); for (auto i = std::uint32_t{0}; i < present_info->swapchainCount; ++i) { - const auto& swapchain = present_info->pSwapchains[i]; + [[maybe_unused]] const auto& swapchain = present_info->pSwapchains[i]; // For VK_AMD_anti_lag, providing a pPresentId isn't part of the spec. // So we just set it to 0 if it isn't provided. - const auto present_id = pid ? pid->pPresentIds[i] : 0; - - context->notify_present(swapchain, present_id); + [[maybe_unused]] const auto present_id = pid ? pid->pPresentIds[i] : 0; } return result; @@ -770,7 +761,8 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR( // VK_NV_low_latency2 allows a swapchain to be created with the low latency // mode already on via VkSwapchainLatencyCreateInfoNV. - auto was_low_latency_requested = true; // enable by default? + [[maybe_unused]] auto was_low_latency_requested = + true; // enable by default? if (const auto slci = find_next<VkSwapchainLatencyCreateInfoNV>( pCreateInfo, VK_STRUCTURE_TYPE_SWAPCHAIN_LATENCY_CREATE_INFO_NV); slci) { @@ -778,19 +770,6 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR( was_low_latency_requested = slci->latencyModeEnable; } - auto insertion = [&]() -> std::unique_ptr<SwapchainMonitor> { - if (layer_context.should_expose_reflex) { - return std::make_unique<ReflexSwapchainMonitor>( - *context, was_low_latency_requested); - } - return std::make_unique<AntiLagSwapchainMonitor>( - *context, was_low_latency_requested); - }(); - const auto did_emplace = context->swapchain_monitors - .try_emplace(*pSwapchain, std::move(insertion)) - .second; - assert(did_emplace); - return VK_SUCCESS; } @@ -799,9 +778,6 @@ DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { const auto context = layer_context.get_context(device); - assert(context->swapchain_monitors.contains(swapchain)); - context->swapchain_monitors.erase(swapchain); - context->vtable.DestroySwapchainKHR(device, swapchain, pAllocator); } @@ -815,7 +791,8 @@ AntiLagUpdateAMD(VkDevice device, const VkAntiLagDataAMD* pData) { // but it's easy to do the inverse. AMD's extension piggybacks on NVIDIA's // more complicated implementation. - const auto present_delay = [&]() -> std::chrono::milliseconds { + [[maybe_unused]] const auto present_delay = + [&]() -> std::chrono::milliseconds { using namespace std::chrono; if (!pData->maxFPS) { return 0ms; @@ -823,52 +800,20 @@ AntiLagUpdateAMD(VkDevice device, const VkAntiLagDataAMD* pData) { return duration_cast<milliseconds>(1s / pData->maxFPS); }(); - context->update_params(std::nullopt, present_delay, - (pData->mode == VK_ANTI_LAG_MODE_ON_AMD)); - if (!pData->pPresentationInfo || pData->pPresentationInfo->stage != VK_ANTI_LAG_STAGE_INPUT_AMD) { return; } - - // VK_AMD_anti_lag doesn't provide a swapchain, so we can't map it to - // a queue. Our previous implementation used the last queue that presented - // and made sure that at least that one completed. I think it's more robust - // to make sure they all complete. - for (auto& iter : context->swapchain_monitors) { - - // All swapchains should be of type AntiLagSwapchainMonitor here. - const auto ptr = - dynamic_cast<AntiLagSwapchainMonitor*>(iter.second.get()); - assert(ptr); - - ptr->await_submissions(); - } } -VkResult LatencySleepNV(VkDevice device, VkSwapchainKHR swapchain, +VkResult LatencySleepNV(VkDevice device, + [[maybe_unused]] VkSwapchainKHR swapchain, const VkLatencySleepInfoNV* pSleepInfo) { const auto context = layer_context.get_context(device); assert(pSleepInfo); - // We're associating an application-provided timeline semaphore + value with - // a swapchain that says 'signal me when we should move past input'. - auto swapchain_monitor_ptr = [&]() -> auto { - const auto iter = context->swapchain_monitors.find(swapchain); - assert(iter != std::end(context->swapchain_monitors)); - const auto ptr = - dynamic_cast<ReflexSwapchainMonitor*>(iter->second.get()); - assert(ptr); - return ptr; - }(); - - // Tell our swapchain monitor that if they want us to proceed they should - // signal this semaphore. - swapchain_monitor_ptr->notify_semaphore(pSleepInfo->signalSemaphore, - pSleepInfo->value); - return VK_SUCCESS; } @@ -880,24 +825,13 @@ void QueueNotifyOutOfBandNV( // Also I really have no idea why pQueueTypeInfo's VkOutOfBandQueueTypeNV // enum even exists (I guess we will find out later when nothing works). const auto context = layer_context.get_context(queue); - - context->is_out_of_band = true; } -VkResult SetLatencySleepModeNV(VkDevice device, VkSwapchainKHR swapchain, - const VkLatencySleepModeInfoNV* pSleepModeInfo) { +VkResult SetLatencySleepModeNV( + VkDevice device, [[maybe_unused]] VkSwapchainKHR swapchain, + [[maybe_unused]] const VkLatencySleepModeInfoNV* pSleepModeInfo) { const auto context = layer_context.get_context(device); - if (pSleepModeInfo) { - context->update_params( - swapchain, - std::chrono::microseconds{pSleepModeInfo->minimumIntervalUs}, - pSleepModeInfo->lowLatencyMode); - } else { - // If pSleepModeInfo is nullptr, it means no delay and no low latency. - context->update_params(swapchain, std::chrono::microseconds{0}, false); - } - return VK_SUCCESS; } diff --git a/src/queue_context.cc b/src/queue_context.cc index b4591f8..635b593 100644 --- a/src/queue_context.cc +++ b/src/queue_context.cc @@ -43,91 +43,9 @@ QueueContext::QueueContext(DeviceContext& device, const VkQueue& queue, } QueueContext::~QueueContext() { - this->unpresented_submissions.clear(); this->timestamp_pool.reset(); } -QueueContext::Submissions::Submissions() {} - -QueueContext::Submissions::~Submissions() {} - -void QueueContext::Submissions::add_submission( - const std::shared_ptr<TimestampPool::Handle> head, - const std::shared_ptr<TimestampPool::Handle> tail, - const DeviceClock::time_point_t& now) { - - this->submissions.emplace_back(std::make_unique<Submission>(Submission{ - .head_handle = head, - .tail_handle = tail, - .cpu_present_time = now, - })); - - // Manual eviction of likely irrelevant timing information. - if (std::size(this->submissions) > this->MAX_TRACKED_SUBMISSIONS) { - this->submissions.pop_front(); - } -} - -bool QueueContext::Submissions::has_completed() const { - if (this->submissions.empty()) { - return true; - } - - const auto& last_submission = this->submissions.back(); - return last_submission->tail_handle->get_time().has_value(); -} - -void QueueContext::Submissions::await_completed() const { - if (this->submissions.empty()) { - return; - } - - const auto& last_submission = this->submissions.back(); - last_submission->tail_handle->await_time(); -} - -void QueueContext::notify_submit( - const present_id_t& present_id, - const std::shared_ptr<TimestampPool::Handle> head_handle, - const std::shared_ptr<TimestampPool::Handle> tail_handle, - const DeviceClock::time_point_t& now) { - - // Push this submission onto our unpresented_submissions at our present_id - // mapping (might be empty, but handled with operator[]). - auto& submissions = this->unpresented_submissions[present_id]; - if (submissions == nullptr) { - submissions = std::make_unique<Submissions>(); - if (present_id) { - this->present_id_ring.emplace_back(present_id); - } - } - - submissions->add_submission(head_handle, tail_handle, now); - - if (std::size(this->present_id_ring) > MAX_TRACKED_PRESENT_IDS) { - const auto evicted_present_id = this->present_id_ring.front(); - this->present_id_ring.pop_front(); - - this->unpresented_submissions.erase(evicted_present_id); - } -} - -void QueueContext::notify_present(const VkSwapchainKHR& swapchain, - const present_id_t& present_id) { - - // Notify the device that this swapchain was just presented to. - // We're avoiding a double hash here - don't use operator[] and erase. - auto iter = this->unpresented_submissions.try_emplace(present_id).first; - if (iter->second == nullptr) { - iter->second = std::make_unique<Submissions>(); - } - - this->device.notify_present(swapchain, std::move(iter->second)); - - // Important, we nuke the submission because now it's presented. - this->unpresented_submissions.erase(iter); -} - bool QueueContext::should_inject_timestamps() const { const auto& physical_device = this->device.physical_device; @@ -142,11 +60,6 @@ bool QueueContext::should_inject_timestamps() const { return false; } - // Don't do it if we've been marked as 'out of band' by nvidia's extension. - if (this->is_out_of_band) { - return false; - } - assert(physical_device.queue_properties); const auto& queue_props = *physical_device.queue_properties; assert(this->queue_family_index < std::size(queue_props)); diff --git a/src/queue_context.hh b/src/queue_context.hh index 326ee79..f10c796 100644 --- a/src/queue_context.hh +++ b/src/queue_context.hh @@ -8,9 +8,7 @@ #include <vulkan/utility/vk_dispatch_table.h> #include <vulkan/vulkan.hpp> -#include <deque> #include <memory> -#include <unordered_map> namespace low_latency { @@ -44,86 +42,12 @@ class QueueContext final : public Context { std::unique_ptr<TimestampPool> timestamp_pool; - // NVIDIA's extension lets the application explicitly state that this queue - // does not contribute to the frame. AMD's extension has no such mechanism - - // so this will always be false when using VK_AMD_anti_lag. - bool is_out_of_band = false; - - public: - // I want our queue bookkeeping to be fairly simple and do one thing - track - // submissions that have yet to have been presented to a swapchain. General - // idea: - // - // For each vkQueueSubmit (specifically for each pSubmitInfo in that - // hook) grab the VK_EXT_present_id value provided by the application for - // that submission. Once we add our timing objects as part of the hook, we - // then take those timing objects, bundle them into a Submission struct, and - // append it to the (potentially currently nonexistent) mapping of - // present_id's to deque<Submission>'s. Now we cleanly track what queue - // submissions refer to what present_id. - // - // When our hook sees a VkQueuePresentKHR, we take the provided present_id - // and notify our device that it needs to watch for when this completes. - // We give it our submissions. Now, it's out of our hands. We remove the - // present_id_t mapping when doing so. - - class Submissions final { - // The amount of queue submissions we allow tracked per queue before - // we give up tracking them. This is neccessary for queues which do not - // present anything. - static constexpr auto MAX_TRACKED_SUBMISSIONS = 50u; - - struct Submission final { - std::shared_ptr<TimestampPool::Handle> head_handle, tail_handle; - DeviceClock::time_point_t cpu_present_time; - }; - std::deque<std::unique_ptr<Submission>> submissions; - - public: - Submissions(); - Submissions(const Submissions&) = delete; - Submissions(Submissions&&) = delete; - Submissions operator=(const Submissions&) = delete; - Submissions operator=(Submissions&&) = delete; - ~Submissions(); - - public: - void add_submission(const std::shared_ptr<TimestampPool::Handle> head, - const std::shared_ptr<TimestampPool::Handle> tail, - const DeviceClock::time_point_t& now); - - // Non-blocking - true if this submission has completed on the GPU. - bool has_completed() const; - // Blocking wait until the last submission has completed. - void await_completed() const; - }; - - using present_id_t = std::uint64_t; - std::unordered_map<present_id_t, std::unique_ptr<Submissions>> - unpresented_submissions; - - // We might be tracking present_ids which aren't presented to - and as a - // result we don't ever clear those Submissions. So manually evict them by - // removing the n'th oldest. This is elegant because even if our - // SwapchainMonitor has these stored (unlikely) they won't be destructed as - // it just decrements their std::shared_ptr use count. - std::deque<present_id_t> present_id_ring; - public: QueueContext(DeviceContext& device_context, const VkQueue& queue, const std::uint32_t& queue_family_index); virtual ~QueueContext(); public: - void notify_submit(const present_id_t& present_id, - const std::shared_ptr<TimestampPool::Handle> head_handle, - const std::shared_ptr<TimestampPool::Handle> tail_handle, - const DeviceClock::time_point_t& now); - - void notify_present(const VkSwapchainKHR& swapchain, - const std::uint64_t& present_id); - - public: bool should_inject_timestamps() const; }; diff --git a/src/submissions.cc b/src/submissions.cc new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/submissions.cc diff --git a/src/submissions.hh b/src/submissions.hh new file mode 100644 index 0000000..41c963f --- /dev/null +++ b/src/submissions.hh @@ -0,0 +1,12 @@ +#ifndef SUBMISSIONS_HH_ +#define SUBMISSIONS_HH_ + +// + +class Submissions { + + + +}; + +#endif
\ No newline at end of file diff --git a/src/swapchain_monitor.cc b/src/swapchain_monitor.cc deleted file mode 100644 index e3be104..0000000 --- a/src/swapchain_monitor.cc +++ /dev/null @@ -1,165 +0,0 @@ -#include "swapchain_monitor.hh" -#include "device_context.hh" -#include "helper.hh" - -#include <chrono> -#include <vulkan/vulkan_core.h> - -#include <functional> -#include <mutex> - -namespace low_latency { - -SwapchainMonitor::SwapchainMonitor(const DeviceContext& device, - const bool was_low_latency_requested) - : device(device), was_low_latency_requested(was_low_latency_requested) {} - -SwapchainMonitor::~SwapchainMonitor() {} - -void SwapchainMonitor::update_params( - const bool was_low_latency_requested, - const std::chrono::microseconds present_delay) { - - const auto lock = std::scoped_lock{this->mutex}; - - this->was_low_latency_requested = was_low_latency_requested; - this->present_delay = present_delay; -} - -void SwapchainMonitor::prune_submissions() { - // If our submissions grow too large, we should delete them from our - // tracking. It would be nice if this was handled elegantly by some custom - // container and we didn't have to call this manually each time we insert. - // Also this exact logic is repeated in QueueContext's Submission. - if (std::size(this->in_flight_submissions) > - this->MAX_TRACKED_IN_FLIGHT_SUBMISSIONS) { - - this->in_flight_submissions.pop_front(); - } -} - -ReflexSwapchainMonitor::ReflexSwapchainMonitor( - const DeviceContext& device, const bool was_low_latency_requested) - : SwapchainMonitor(device, was_low_latency_requested), - monitor_worker( - std::bind_front(&ReflexSwapchainMonitor::do_monitor, this)) {} - -ReflexSwapchainMonitor::~ReflexSwapchainMonitor() {} - -void ReflexSwapchainMonitor::WakeupSemaphore::signal( - const DeviceContext& device) const { - - const auto ssi = - VkSemaphoreSignalInfo{.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, - .semaphore = this->timeline_semaphore, - .value = this->value}; - THROW_NOT_VKSUCCESS(device.vtable.SignalSemaphore(device.device, &ssi)); -} - -void ReflexSwapchainMonitor::do_monitor(const std::stop_token stoken) { - for (;;) { - auto lock = std::unique_lock{this->mutex}; - this->cv.wait(lock, stoken, - [&]() { return !this->semaphore_submissions.empty(); }); - - // No work implies stopped so break immediately. - if (this->semaphore_submissions.empty()) { - break; - } - - // Pop the oldest semaphore we want to signal off the queue. - const auto semaphore_submission = - std::move(this->semaphore_submissions.front()); - this->semaphore_submissions.pop_front(); - - // If we're stopping, signal the semaphore and don't worry about work - // actually completing. - if (stoken.stop_requested()) { - semaphore_submission.wakeup_semaphore.signal(this->device); - break; - } - - // Unlock, wait for work to finish, signal semaphore. - lock.unlock(); - semaphore_submission.submissions->await_completed(); - semaphore_submission.wakeup_semaphore.signal(this->device); - } -} - -void ReflexSwapchainMonitor::notify_semaphore( - const VkSemaphore& timeline_semaphore, const std::uint64_t& value) { - - auto lock = std::unique_lock{this->mutex}; - - const auto wakeup_semaphore = WakeupSemaphore{ - .timeline_semaphore = timeline_semaphore, .value = value}; - - // Signal immediately if reflex is off or it's a no-op submit. - if (!this->was_low_latency_requested || - this->in_flight_submissions.empty()) { - - wakeup_semaphore.signal(this->device); - return; - } - - // Signal immediately if our outstanding work has already completed. - if (this->in_flight_submissions.back()->has_completed()) { - this->in_flight_submissions.clear(); - wakeup_semaphore.signal(this->device); - return; - } - - this->semaphore_submissions.emplace_back(SemaphoreSubmissions{ - .wakeup_semaphore = wakeup_semaphore, - .submissions = std::move(this->in_flight_submissions.back()), - }); - this->in_flight_submissions.clear(); - - lock.unlock(); - this->cv.notify_one(); -} - -void ReflexSwapchainMonitor::notify_present( - std::unique_ptr<QueueContext::Submissions> submissions) { - - const auto lock = std::scoped_lock{this->mutex}; - if (!this->was_low_latency_requested) { - return; - } - - this->in_flight_submissions.emplace_back(std::move(submissions)); - this->prune_submissions(); -} - -AntiLagSwapchainMonitor::AntiLagSwapchainMonitor( - const DeviceContext& device, const bool was_low_latency_requested) - : SwapchainMonitor(device, was_low_latency_requested) {} - -AntiLagSwapchainMonitor::~AntiLagSwapchainMonitor() {} -void AntiLagSwapchainMonitor::notify_present( - std::unique_ptr<QueueContext::Submissions> submissions) { - - const auto lock = std::scoped_lock{this->mutex}; - if (!this->was_low_latency_requested) { - return; - } - - this->in_flight_submissions.emplace_back(std::move(submissions)); - this->prune_submissions(); -} - -void AntiLagSwapchainMonitor::await_submissions() { - - auto lock = std::unique_lock{this->mutex}; - if (this->in_flight_submissions.empty()) { - return; - } - - const auto last = std::move(this->in_flight_submissions.back()); - this->in_flight_submissions.clear(); - lock.unlock(); - - last->await_completed(); -} - -} // namespace low_latency
\ No newline at end of file diff --git a/src/swapchain_monitor.hh b/src/swapchain_monitor.hh deleted file mode 100644 index 8ffcd04..0000000 --- a/src/swapchain_monitor.hh +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef SWAPCHAIN_MONITOR_HH_ -#define SWAPCHAIN_MONITOR_HH_ - -// The purpose of this file is to provide a SwapchainMonitor - -#include <vulkan/vulkan_core.h> - -#include <chrono> -#include <condition_variable> -#include <deque> -#include <memory> -#include <mutex> -#include <thread> - -#include "queue_context.hh" - -namespace low_latency { - -class DeviceContext; - -// Abstract base class for swapchain completion monitoring. Both implementations -// currently have an option to frame pace, to disable low_latency mode -// (become a no-op), and must track in_flight_submissions to function. -class SwapchainMonitor { - private: - static constexpr auto MAX_TRACKED_IN_FLIGHT_SUBMISSIONS = 50u; - - protected: - const DeviceContext& device; - - std::mutex mutex; - - // Configurarable params for this swapchain. - std::chrono::microseconds present_delay = std::chrono::microseconds{0}; - bool was_low_latency_requested = false; - - std::deque<std::unique_ptr<QueueContext::Submissions>> - in_flight_submissions; - - protected: - // Small fix to avoid submissions growing limitlessly in size if this - // swapchain is never presented to. - void prune_submissions(); - - public: - SwapchainMonitor(const DeviceContext& device, - const bool was_low_latency_requested); - SwapchainMonitor(const SwapchainMonitor&) = delete; - SwapchainMonitor(SwapchainMonitor&&) = delete; - SwapchainMonitor operator=(const SwapchainMonitor&) = delete; - SwapchainMonitor operator=(SwapchainMonitor&&) = delete; - virtual ~SwapchainMonitor(); - - public: - void update_params(const bool was_low_latency_requested, - const std::chrono::microseconds present_delay); - - public: - virtual void - notify_present(std::unique_ptr<QueueContext::Submissions> submissions) = 0; -}; - -// Provides asynchronous monitoring of submissions and signalling of some -// timeline semaphore via a worker thread. -class ReflexSwapchainMonitor final : public SwapchainMonitor { - private: - struct WakeupSemaphore { - VkSemaphore timeline_semaphore; - std::uint64_t value; - - public: - void signal(const DeviceContext& device) const; - }; - - // A pairing of semaphore -> submissions. - // If the Submissions completes then signal the bundled semaphore. - struct SemaphoreSubmissions { - WakeupSemaphore wakeup_semaphore; - std::unique_ptr<QueueContext::Submissions> submissions; - }; - std::deque<SemaphoreSubmissions> semaphore_submissions; - - std::condition_variable_any cv; - std::jthread monitor_worker; - - private: - void do_monitor(const std::stop_token stoken); - - public: - ReflexSwapchainMonitor(const DeviceContext& device, - const bool was_low_latency_requested); - virtual ~ReflexSwapchainMonitor(); - - public: - void notify_semaphore(const VkSemaphore& timeline_semaphore, - const std::uint64_t& value); - - public: - virtual void notify_present( - std::unique_ptr<QueueContext::Submissions> submissions) override; -}; - -// Much simpler synchronous waiting without another monitor thread - still need -// to synchronise across threads however. -class AntiLagSwapchainMonitor final : public SwapchainMonitor { - public: - AntiLagSwapchainMonitor(const DeviceContext& device, - const bool was_low_latency_requested); - virtual ~AntiLagSwapchainMonitor(); - - public: - // Synchronously wait until all in-flight submissions have completed. - void await_submissions(); - - public: - virtual void notify_present( - std::unique_ptr<QueueContext::Submissions> submissions) override; -}; - -} // namespace low_latency - -#endif
\ No newline at end of file |
