blob: 9192f5568cab8d362b4700d2843785c705e90013 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#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::milliseconds present_delay = std::chrono::milliseconds{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::milliseconds 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 {
private:
std::mutex mutex;
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
|