GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
22 / 30
73.3%
Branches:
16 / 41
39.0%
Functions:
1 / 1, 4 excl
100.0%

device/queue.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file queue.h
3 /// @brief Timeline semaphores and the tickets that name points on them, and device queues whose
4 /// submissions are numbered on one.
5 #pragma once
6
7 #include "ernie/device/external.h"
8 #include "ernie/device/vulkan.h"
9
10 #include <cstdint>
11 #include <functional>
12 #include <mutex>
13 #include <span>
14 #include <string>
15 #include <vector>
16
17 namespace ernie {
18
19 class Timeline;
20
21 /// @brief A point on a timeline, reached once the timeline's value reaches `value`. Tickets name
22 /// their timeline, and through it its queue or source and its device, so they stay meaningful
23 /// across queues, devices and APIs. A default ticket is always done.
24
3/5
✓ Branch 0 taken 84 times.
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
227 struct Ticket {
25 2 const Timeline* timeline = nullptr;
26 2 std::uint64_t value = 0;
27
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 bool operator==(const Ticket&) const = default;
28
29 bool Done() const;
30 /// @brief Blocks until the ticket is reached.
31 /// @throws DeviceError on device loss.
32 void Wait() const;
33 };
34
35 /// @brief A timeline semaphore: a queue's, signalled by its submissions, or one shared with
36 /// another API or context, which signals it there.
37 class Timeline {
38 public:
39 /// @param exportable Whether `Export` may share it; the device needs
40 /// `DeviceCapabilities::externalTimeline`.
41 Timeline(VkDevice device, std::string name, bool exportable = false);
42 /// @brief Imports a timeline exported by another API or context, taking `handle` where the
43 /// platform does.
44 Timeline(VkDevice device, std::string name, ExternalHandle handle);
45 ~Timeline();
46 Timeline(const Timeline&) = delete;
47 Timeline& operator=(const Timeline&) = delete;
48
49 /// @return The value reached so far.
50 std::uint64_t Reached() const;
51 /// @brief Sets the value from the host, as a producer outside any queue does.
52 void Signal(std::uint64_t value) const;
53 /// @return A handle another API or context imports the timeline from.
54 /// @throws DeviceError unless it was created exportable.
55 ExternalHandle Export() const;
56
57 1493 Ticket At(std::uint64_t value) const {
58
1/4
<unknown function 24>:
✓ Branch 0 taken 268 times.
✗ Branch 1 not taken.
<unknown function 57>:
✗ Branch 1 not taken.
✗ Branch 2 not taken.
1493 return {this, value};
59 }
60 717 VkSemaphore Handle() const {
61
3/6
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 268 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 374 times.
✗ Branch 7 not taken.
717 return semaphore_;
62 }
63 524 VkDevice Device() const {
64
3/6
<unknown function 24>:
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 149 times.
✓ Branch 3 taken 374 times.
✗ Branch 4 not taken.
<unknown function 57>:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
524 return device_;
65 }
66 1 const std::string& Name() const {
67
1/8
<unknown function 24>:
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
<unknown function 57>:
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1 return name_;
68 }
69
70 private:
71 VkDevice device_;
72 std::string name_;
73 bool exportable_;
74 VkSemaphore semaphore_ = VK_NULL_HANDLE;
75 };
76
77 /// @brief Binary semaphores a submission waits on and signals besides its tickets, as swapchain
78 /// images need.
79 struct BinarySemaphores {
80 VkSemaphore wait = VK_NULL_HANDLE;
81 VkSemaphore signal = VK_NULL_HANDLE;
82 };
83
84 /// @brief A queue of one family. Submissions take a recording function and return a ticket on the
85 /// queue's timeline; command buffers are recycled once their tickets complete. Any thread may
86 /// submit, one recording at a time, and test or wait on tickets.
87 class Queue {
88 public:
89 /// @param exportable Whether its timeline may be shared, for other APIs to wait on its work.
90 Queue(VkDevice device, std::uint32_t family, std::string name, bool exportable = false);
91 ~Queue();
92 Queue(const Queue&) = delete;
93 Queue& operator=(const Queue&) = delete;
94
95 /// @brief Records commands and submits them once `waits` are done.
96 /// @return The submission's ticket.
97 /// @throws DeviceError if a wait is another device's, or submission fails.
98 Ticket Submit(const std::function<void(VkCommandBuffer)>& record,
99 std::span<const Ticket> waits = {}, BinarySemaphores binary = {});
100 /// @return The ticket of the latest submission: waiting on it waits for all of them.
101 Ticket Last() const;
102 /// @brief Presents swapchain images, between submissions from any thread.
103 /// @return What vkQueuePresentKHR returned, as suboptimal and out-of-date swapchains are
104 /// the caller's to handle.
105 VkResult Present(const VkPresentInfoKHR& info);
106 /// @brief Lends the queue's handle to `use`, with no submission or present in between, for
107 /// libraries that submit to it themselves. `use` must not call back into this queue.
108 void Borrow(const std::function<void(VkQueue)>& use);
109
110 ✗ const ernie::Timeline& Timeline() const {
111
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ return timeline_;
112 }
113 80 VkQueue Handle() const {
114
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
80 return queue_;
115 }
116 233 std::uint32_t Family() const {
117
2/4
<unknown function 113>:
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
<unknown function 116>:
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
233 return family_;
118 }
119 VkDevice Device() const {
120 return device_;
121 }
122 const std::string& Name() const {
123 return name_;
124 }
125
126 private:
127 /// Moves finished command buffers to the free list.
128 void Recycle();
129
130 VkDevice device_;
131 std::uint32_t family_;
132 std::string name_;
133 VkQueue queue_ = VK_NULL_HANDLE;
134 ernie::Timeline timeline_;
135 VkCommandPool pool_ = VK_NULL_HANDLE;
136 /// Held while recording and submitting; a recording may still ask for tickets.
137 std::mutex recording_;
138 mutable std::mutex mutex_;
139 std::uint64_t submitted_ = 0;
140 std::vector<std::pair<VkCommandBuffer, std::uint64_t>> inFlight_;
141 std::vector<VkCommandBuffer> free_;
142 };
143
144 } // namespace ernie
145