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
|
#include "swapchain_monitor.hh"
#include "device_context.hh"
#include "helper.hh"
namespace low_latency {
void SwapchainMonitor::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 SwapchainMonitor::update_params(const bool was_low_latency_requested,
const std::chrono::microseconds delay) {
const auto lock = std::scoped_lock{this->mutex};
this->was_low_latency_requested = was_low_latency_requested;
this->present_delay = delay;
}
void SwapchainMonitor::do_monitor(const std::stop_token stoken) {
for (;;) {
auto lock = std::unique_lock{this->mutex};
this->cv.wait(lock, stoken,
[&]() { return this->semaphore_submission.has_value(); });
// Stop only if we're stopped and we have nothing to signal.
if (stoken.stop_requested() &&
!this->semaphore_submission.has_value()) {
break;
}
// Grab the most recent semaphore. When work completes, signal it.
const auto semaphore_submission =
std::move(*this->semaphore_submission);
this->semaphore_submission.reset();
// 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();
// Ugly and duplicated - will fix this soon.
if (!semaphore_submission.submissions->empty()) {
semaphore_submission.submissions->back().end->await_time();
}
// TODO add wait for frame pacing
semaphore_submission.wakeup_semaphore.signal(this->device);
}
}
void SwapchainMonitor::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) {
wakeup_semaphore.signal(this->device);
return;
}
// Signal immediately if we have no outstanding work.
if (!this->pending_submissions) {
this->pending_submissions.reset();
wakeup_semaphore.signal(this->device);
return;
}
this->semaphore_submission.emplace(SemaphoreSubmissions{
.wakeup_semaphore = wakeup_semaphore,
.submissions = std::move(this->pending_submissions),
});
this->pending_submissions.reset();
lock.unlock();
this->cv.notify_one();
}
void SwapchainMonitor::attach_work(
std::unique_ptr<std::deque<Submission>> submissions) {
const auto lock = std::scoped_lock{this->mutex};
if (!this->was_low_latency_requested) {
return;
}
this->pending_submissions = std::move(submissions);
}
} // namespace low_latency
|