GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
33 / 38
86.8%
Branches:
8 / 12
66.7%
Functions:
6 / 7, 2 excl
85.7%

device/staging.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file staging.h
3 /// @brief Moving bytes between the host and buffers: batched uploads, and readbacks that complete
4 /// with a ticket.
5 #pragma once
6
7 #include "ernie/device/buffer.h"
8
9 #include <cstddef>
10 #include <cstdint>
11 #include <cstring>
12 #include <memory>
13 #include <span>
14 #include <vector>
15
16 namespace ernie {
17
18 /// @brief Uploads to buffers on one queue. Writes to a mapped destination land in place; the
19 /// rest are staged and copied as batched regions when flushed, the staging retired once the
20 /// copies are done.
21 class Uploader {
22 public:
23 /// @param chunk The size staging buffers are allocated in; larger writes get their own.
24 Uploader(DeviceContext& context, Queue& queue, std::uint64_t chunk = std::uint64_t{16} << 20);
25 ~Uploader();
26 Uploader(const Uploader&) = delete;
27 Uploader& operator=(const Uploader&) = delete;
28
29 /// @brief Writes bytes into `destination` at `offset`: at once if it is mapped, else at the
30 /// next `Flush`.
31 /// @throws std::out_of_range if the bytes do not fit.
32 void Write(const Buffer& destination, std::uint64_t offset, std::span<const std::byte> bytes);
33 template <typename T>
34 249 void Write(const Buffer& destination, std::uint64_t offset, std::span<const T> values) {
35 249 Write(destination, offset, std::as_bytes(values));
36 248 }
37 /// @brief Writes some rows of `host`, rows of `rowBytes` laid out as the destination's from
38 /// `offset`, a run of consecutive rows at a time.
39 /// @param rows The rows to write, ascending and each once.
40 void WriteRows(const Buffer& destination, std::uint64_t offset, std::uint64_t rowBytes,
41 std::span<const std::byte> host, std::span<const std::uint32_t> rows);
42 /// @return The staged bytes waiting for `Flush`; flush when it grows past a limit.
43 3 std::uint64_t Pending() const {
44
3/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
3 return pending_;
45 }
46 /// @brief Submits the staged copies. Work submitted after them on the same queue, or waiting
47 /// on the ticket, sees the bytes.
48 /// @return The copies' ticket; a default one when nothing was staged.
49 Ticket Flush(std::span<const Ticket> waits = {});
50 /// @brief Records the staged copies into `commands` instead, between barriers, for a pass
51 /// that submits them with other work.
52 /// @return The staging the copies read, to retire once that work is submitted.
53 std::vector<std::shared_ptr<const Buffer>> Record(VkCommandBuffer commands);
54 /// @return Whether copies are staged.
55 157 bool Staged() const {
56
5/6
<unknown function 34>:
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 15 times.
<unknown function 55>:
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
157 return !copies_.empty();
57 }
58
59 private:
60 struct Copy {
61 std::size_t staging;
62 VkBuffer destination;
63 VkBufferCopy region;
64 };
65
66 /// Makes the last staging buffer's writes visible to the device.
67 void FlushStaging();
68
69 DeviceContext& context_;
70 Queue& queue_;
71 std::uint64_t chunk_;
72 std::vector<std::shared_ptr<Buffer>> staging_;
73 std::uint64_t used_ = 0;
74 std::uint64_t pending_ = 0;
75 std::vector<Copy> copies_;
76 };
77
78 /// @brief Bytes of a buffer copied to the host after `waits`, readable once its ticket is done.
79 class Readback {
80 public:
81 Readback(DeviceContext& context, Queue& queue, const Buffer& source, std::uint64_t offset,
82 std::uint64_t size, std::span<const Ticket> waits = {});
83 ~Readback();
84 Readback(const Readback&) = delete;
85 Readback& operator=(const Readback&) = delete;
86
87 Ticket Ready() const {
88 return ticket_;
89 }
90 /// @return The bytes, waiting for the copy if it is not done.
91 std::span<const std::byte> Bytes();
92 /// @return The bytes as `T`s, waiting for the copy if it is not done.
93 60 template <typename T> std::vector<T> Values() {
94 60 const std::span<const std::byte> bytes = Bytes();
95 60 std::vector<T> values(bytes.size() / sizeof(T));
96 60 std::memcpy(values.data(), bytes.data(), values.size() * sizeof(T));
97 60 return values;
98 }
99
100 private:
101 DeviceContext& context_;
102 std::shared_ptr<Buffer> host_;
103 Ticket ticket_;
104 };
105
106 } // namespace ernie
107