aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/device_context.cc30
-rw-r--r--src/device_context.hh16
-rw-r--r--src/layer.cc92
-rw-r--r--src/queue_context.cc87
-rw-r--r--src/queue_context.hh76
-rw-r--r--src/submissions.cc0
-rw-r--r--src/submissions.hh12
-rw-r--r--src/swapchain_monitor.cc165
-rw-r--r--src/swapchain_monitor.hh122
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