GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
7 / 7
100.0%
Branches:
3 / 6
50.0%
Functions:
-
-%

device/bindless.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file bindless.h
3 /// @brief One heap of every image and sampler shaders reach, by index.
4 #pragma once
5
6 #include "ernie/device/image.h"
7
8 #include <array>
9 #include <cstdint>
10 #include <mutex>
11 #include <vector>
12
13 namespace ernie {
14
15 /// @brief A slot of the bindless heap: what shaders index its arrays with.
16
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 struct BindlessIndex {
17 2 std::uint32_t value = 0;
18
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
2 bool operator==(const BindlessIndex&) const = default;
19 };
20
21 /// @brief The bindless heap: one descriptor set of three arrays, updated after bind and partially
22 /// bound, which every kernel binds as set 0:
23 ///
24 /// [[vk::binding(0, 0)]] Texture2D textures[];
25 /// [[vk::binding(1, 0)]] RWTexture2D<float4> images[];
26 /// [[vk::binding(2, 0)]] SamplerState samplers[];
27 ///
28 /// Indices come from free lists and return to them once the GPU is done with their slot. On
29 /// WebGPU the same indices pick from texture arrays.
30 class BindlessHeap {
31 public:
32 explicit BindlessHeap(DeviceContext& context);
33 ~BindlessHeap();
34 BindlessHeap(const BindlessHeap&) = delete;
35 BindlessHeap& operator=(const BindlessHeap&) = delete;
36
37 /// @throws DeviceError when the array is full.
38 BindlessIndex AddTexture(const DeviceImage& image);
39 BindlessIndex AddStorageImage(const DeviceImage& image);
40 BindlessIndex AddSampler(const Sampler& sampler);
41 /// @brief Frees slots once every queue's work submitted so far is done.
42 void RemoveTexture(BindlessIndex index);
43 void RemoveStorageImage(BindlessIndex index);
44 void RemoveSampler(BindlessIndex index);
45
46 12 VkDescriptorSetLayout Layout() const {
47 12 return layout_;
48 }
49 12 VkDescriptorSet Set() const {
50 12 return set_;
51 }
52
53 private:
54 /// @brief The slots of one array.
55 struct Slots {
56 std::uint32_t capacity = 0;
57 std::uint32_t next = 0;
58 std::vector<std::uint32_t> free;
59 };
60
61 /// Takes a slot of `binding` and writes its descriptor, under the lock: the set's updates
62 /// need it to themselves.
63 BindlessIndex Add(std::uint32_t binding, const VkDescriptorImageInfo& info);
64 void Remove(std::uint32_t binding, BindlessIndex index);
65
66 DeviceContext& context_;
67 VkDescriptorSetLayout layout_ = VK_NULL_HANDLE;
68 VkDescriptorPool pool_ = VK_NULL_HANDLE;
69 VkDescriptorSet set_ = VK_NULL_HANDLE;
70 std::mutex mutex_;
71 std::array<Slots, 3> slots_{};
72 };
73
74 } // namespace ernie
75