GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
14 / 20
70.0%
Branches:
23 / 47
48.9%
Functions:
-
-%

device/buffer.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file buffer.h
3 /// @brief Device buffers, allocated by what they are for, each with its device address.
4 #pragma once
5
6 #include "ernie/device/context.h"
7
8 #include <cstddef>
9 #include <cstdint>
10 #include <span>
11 #include <string_view>
12
13 namespace ernie {
14
15 /// @brief What a buffer's memory is for, from which its placement follows.
16 enum class MemoryUse : std::uint8_t {
17 /// Read and written by the GPU only: device-local.
18 Device,
19 /// Written by the host, read by the GPU: mapped, device-local when the device offers it.
20 Upload,
21 /// Written by the GPU, read by the host: mapped and cached.
22 Readback,
23 /// Read and written by the GPU and by another API or context, such as CUDA: device-local, in
24 /// dedicated memory that `Buffer::Export` shares. The device needs
25 /// `DeviceCapabilities::externalMemory`.
26 Shared,
27 };
28
29 /// @brief Who allocated memory a buffer imports.
30 enum class SharedFrom : std::uint8_t { Vulkan, OtherApi };
31
32 /// @brief A buffer and its memory. Every buffer takes device-address and transfer usage, so
33 /// shaders reach it by address and copies need no extra flags. Destroying one the GPU may still
34 /// use is an error: hand it to `DeviceContext::Retire` instead.
35 class Buffer {
36 public:
37 Buffer() = default;
38 /// @throws DeviceError when the memory cannot be allocated.
39 Buffer(DeviceContext& context, std::uint64_t size, MemoryUse use, std::string_view name,
40 VkBufferUsageFlags usage = 0);
41 /// @brief Imports a shared buffer of `size` bytes, taking `handle` where the platform does.
42 /// It is a `MemoryUse::Shared` buffer on this context.
43 /// @param from Who allocated it: another Vulkan context's `Export`, or another API, such as
44 /// CUDA's virtual memory, whose allocations are not Vulkan's dedicated ones.
45 /// @throws DeviceError when the device cannot import it.
46 Buffer(DeviceContext& context, ExternalHandle handle, std::uint64_t size, std::string_view name,
47 SharedFrom from = SharedFrom::Vulkan);
48 ~Buffer();
49 Buffer(Buffer&& other) noexcept;
50 Buffer& operator=(Buffer&& other) noexcept;
51 Buffer(const Buffer&) = delete;
52 Buffer& operator=(const Buffer&) = delete;
53
54 /// @return An id no other buffer of the process has had, unlike handles, which drivers reuse.
55 ✗ std::uint64_t Id() const {
56
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ return id_;
57 }
58 852 VkBuffer Handle() const {
59
4/8
✓ Branch 1 taken 1 time.
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✗ Branch 2 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
826 return buffer_;
60 }
61 1136 std::uint64_t Size() const {
62
8/19
<unknown function 55>:
✗ Branch 1 not taken.
✗ Branch 2 not taken.
<unknown function 58>:
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 84 times.
✓ Branch 7 taken 481 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 time.
✓ Branch 10 taken 359 times.
<unknown function 61>:
✓ Branch 1 taken 1 time.
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✗ Branch 2 not taken.
1052 return size_;
63 }
64 942 VkDeviceAddress Address() const {
65
6/10
<unknown function 58>:
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
<unknown function 64>:
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
471 return address_;
66 }
67 /// @return Its bytes on the host, for upload and readback buffers; empty otherwise.
68 1049 std::span<std::byte> Mapped() const {
69
5/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 479 times.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
1048 return mapped_;
70 }
71 /// @brief Makes host writes to a mapped range visible to the device, where memory is not
72 /// coherent.
73 void Flush(std::uint64_t offset, std::uint64_t size) const;
74 /// @brief Makes device writes to a mapped range visible to the host, where memory is not
75 /// coherent.
76 void Invalidate(std::uint64_t offset, std::uint64_t size) const;
77 /// @return A handle to the buffer's memory, which another API or context imports with its
78 /// size. Each call returns a new handle.
79 /// @throws DeviceError unless the buffer is `MemoryUse::Shared`.
80 ExternalHandle Export() const;
81 /// @return The size of the buffer's memory, at least `Size`: what an importer maps.
82 ✗ std::uint64_t MemorySize() const {
83 ✗ return memorySize_;
84 }
85
86 private:
87 void Finish(DeviceContext& context, const VmaAllocationInfo& allocated, std::string_view name);
88 void Destroy();
89
90 VmaAllocator allocator_ = VK_NULL_HANDLE;
91 VkDevice device_ = VK_NULL_HANDLE;
92 bool shared_ = false;
93 VkBuffer buffer_ = VK_NULL_HANDLE;
94 VmaAllocation allocation_ = VK_NULL_HANDLE;
95 /// Memory another API allocated, which VMA does not manage.
96 VkDeviceMemory memory_ = VK_NULL_HANDLE;
97 std::uint64_t size_ = 0;
98 std::uint64_t memorySize_ = 0;
99 std::uint64_t id_ = 0;
100 VkDeviceAddress address_ = 0;
101 std::span<std::byte> mapped_;
102 };
103
104 } // namespace ernie
105