Loading...
Searching...
No Matches
BufferGather.hpp
1#pragma once
2#include <Ui/Monitor/BufferDecode.hpp>
3
4#include <array>
5#include <bit>
6#include <cstdint>
7#include <limits>
8#include <span>
9
23namespace Ui::Monitor::Buffer
24{
26enum class Fallback : uint8_t
27{
28 None,
29 NoCompute,
30 NotStorage,
31 TooLarge,
32 Failed
33};
34
37{
39 uint32_t base{};
41 uint32_t sample_stride{};
42 uint32_t element_bytes{};
44 uint32_t out_words{};
46 uint32_t src_words{};
48 uint32_t reduce_count{};
50 uint32_t reduce_base{};
52 uint32_t reduce_stride{};
53 uint32_t type{};
54 uint32_t components{};
55 uint32_t component_bytes{};
56 uint32_t pad{};
57};
58static_assert(sizeof(GatherParams) == 48);
59
62inline constexpr int gather_header_words = 16;
63inline constexpr int64_t gather_header_bytes = gather_header_words * 4;
64inline constexpr int gather_local_size = 256;
67inline constexpr int64_t gather_max_groups = 4096;
69inline constexpr int64_t gather_max_reduce
70 = int64_t(std::numeric_limits<uint32_t>::max())
71 - gather_max_groups * gather_local_size;
74inline constexpr int64_t gather_bind_alignment = 256;
75
78constexpr int64_t gatherReadable(int64_t buffer_bytes) noexcept
79{
80 return buffer_bytes & ~int64_t(3);
81}
82
85{
86 GatherParams params{};
88 int64_t bind_offset{};
89 int64_t bind_size{};
91 int64_t staging_bytes{};
93 int64_t readback_offset{};
94 int64_t readback_size{};
95 int groups_x{};
96 int groups_y{};
97 bool valid{};
98};
99
108 const Layout& l, int64_t origin, int64_t buffer_bytes, const Sampling& s, bool reduce,
109 int64_t max_bind, int max_groups_per_dim) noexcept
110{
111 GatherPlan p;
112 if(s.count <= 0 || origin < 0)
113 return p;
114 constexpr int64_t u32 = std::numeric_limits<uint32_t>::max();
115 const int64_t e = elementBytes(l);
116 const int64_t stride = strideOf(l);
117 const int64_t start = origin + s.first * stride;
118 const int64_t sample_stride = s.count > 1 ? s.step * stride : 0;
119 int64_t end = start + (s.count - 1) * sample_stride + e;
120 const int64_t reduce_count = reduce ? s.window : 0;
121 if(reduce_count > gather_max_reduce)
122 return p;
123 if(reduce)
124 end = std::max(end, start + (reduce_count - 1) * stride + e);
125 const int64_t readable = gatherReadable(buffer_bytes);
126 if(end > readable || buffer_bytes > u32 || sample_stride > u32)
127 return p;
128
130 p.bind_size = std::min(readable, (end + 3) / 4 * 4) - p.bind_offset;
131 if(p.bind_size > max_bind)
132 return p;
133
134 const int64_t out_words = (s.count * e + 3) / 4;
135 auto& g = p.params;
136 g.base = uint32_t(start - p.bind_offset);
137 g.sample_stride = uint32_t(sample_stride);
138 g.element_bytes = uint32_t(e);
139 g.out_words = uint32_t(out_words);
140 g.src_words = uint32_t(p.bind_size / 4);
141 g.reduce_count = uint32_t(reduce_count);
142 g.reduce_base = g.base;
143 g.reduce_stride = uint32_t(stride);
144 g.type = uint32_t(l.type);
145 g.components = uint32_t(components(l));
146 g.component_bytes = uint32_t(componentBytes(l.type));
147
148 p.staging_bytes = gather_header_bytes + out_words * 4;
149 p.readback_offset = reduce ? 0 : gather_header_bytes;
150 p.readback_size = p.staging_bytes - p.readback_offset;
151
152 // Wider than a dimension allows: the rows of groups go on y
153 const int64_t invocations = std::max(out_words, reduce_count);
154 const int64_t groups = std::clamp<int64_t>(
155 (invocations + gather_local_size - 1) / gather_local_size, 1, gather_max_groups);
156 const int64_t max_dim = std::max(1, max_groups_per_dim);
157 p.groups_x = int(std::min(groups, max_dim));
158 p.groups_y = int((groups + p.groups_x - 1) / p.groups_x);
159 p.valid = true;
160 return p;
161}
162
165constexpr uint32_t gatherBytesAt(std::span<const uint32_t> words, uint32_t b, uint32_t n) noexcept
166{
167 auto word = [&](uint32_t w) { return w < words.size() ? words[w] : 0u; };
168 const uint32_t w = b >> 2;
169 const uint32_t shift = (b & 3u) * 8u;
170 uint32_t v = word(w) >> shift;
171 if(shift + n * 8u > 32u)
172 v |= word(w + 1u) << (32u - shift);
173 return n == 4u ? v : (v & ((1u << (n * 8u)) - 1u));
174}
175
177constexpr uint32_t
178gatherWord(const GatherParams& g, std::span<const uint32_t> words, uint32_t w) noexcept
179{
180 const uint32_t b = w * 4u;
181 if(g.element_bytes % 4u == 0u)
182 return gatherBytesAt(
183 words, g.base + (b / g.element_bytes) * g.sample_stride + b % g.element_bytes, 4u);
184 uint32_t v = 0;
185 for(uint32_t i = 0; i < 4u; i++)
186 {
187 const uint32_t at = b + i;
188 v |= gatherBytesAt(
189 words, g.base + (at / g.element_bytes) * g.sample_stride + at % g.element_bytes,
190 1u)
191 << (i * 8u);
192 }
193 return v;
194}
195
197constexpr uint32_t orderedFloat(float f) noexcept
198{
199 const uint32_t u = std::bit_cast<uint32_t>(f);
200 return (u & 0x80000000u) ? ~u : (u | 0x80000000u);
201}
202
203constexpr float unorderedFloat(uint32_t u) noexcept
204{
205 return std::bit_cast<float>((u & 0x80000000u) ? (u & 0x7fffffffu) : ~u);
206}
207
210{
212 std::array<float, 4> lo{}, hi{};
213 int64_t non_finite{};
214};
215
216inline GatherRange readGatherHeader(std::span<const uint32_t> header, int components) noexcept
217{
218 GatherRange r;
219 r.lo.fill(std::numeric_limits<float>::max());
220 r.hi.fill(std::numeric_limits<float>::lowest());
221 if(header.size() < std::size_t(gather_header_words))
222 return r;
223 for(int c = 0; c < std::clamp(components, 1, 4); c++)
224 {
225 // The values the header is reset to: nothing finite was found
226 if(header[c] == 0xffffffffu && header[4 + c] == 0u)
227 continue;
228 r.lo[c] = unorderedFloat(header[c]);
229 r.hi[c] = unorderedFloat(header[4 + c]);
230 }
231 r.non_finite = header[8];
232 return r;
233}
234}
Definition BufferDecode.hpp:16
constexpr uint32_t gatherWord(const GatherParams &g, std::span< const uint32_t > words, uint32_t w) noexcept
The word w of the elements the shader writes. The shader's gathered.
Definition BufferGather.hpp:178
Fallback
Why a buffer is read back as one range instead of through the gather pass.
Definition BufferGather.hpp:27
constexpr uint32_t gatherBytesAt(std::span< const uint32_t > words, uint32_t b, uint32_t n) noexcept
Definition BufferGather.hpp:165
constexpr int64_t elementBytes(const Layout &l) noexcept
Bytes one element covers.
Definition BufferDecode.hpp:62
constexpr uint32_t orderedFloat(float f) noexcept
A float as an unsigned integer in the same order, for atomic min and max.
Definition BufferGather.hpp:197
constexpr int64_t gather_bind_alignment
Definition BufferGather.hpp:74
constexpr int64_t gather_max_groups
Definition BufferGather.hpp:67
constexpr GatherPlan planGather(const Layout &l, int64_t origin, int64_t buffer_bytes, const Sampling &s, bool reduce, int64_t max_bind, int max_groups_per_dim) noexcept
Definition BufferGather.hpp:107
constexpr int gather_header_words
Definition BufferGather.hpp:62
constexpr int64_t gatherReadable(int64_t buffer_bytes) noexcept
Definition BufferGather.hpp:78
constexpr int64_t gather_max_reduce
Elements one pass can measure: an invocation's index never wraps.
Definition BufferGather.hpp:70
The uniforms of the gather shader, as std140 lays them out.
Definition BufferGather.hpp:37
uint32_t reduce_base
Byte of the first element measured, from the start of the bound range.
Definition BufferGather.hpp:50
uint32_t reduce_count
Elements measured; 0 measures none.
Definition BufferGather.hpp:48
uint32_t sample_stride
Bytes from one element read to the next.
Definition BufferGather.hpp:41
uint32_t src_words
Words of the bound range.
Definition BufferGather.hpp:46
uint32_t base
Byte of the first element read, from the start of the bound range.
Definition BufferGather.hpp:39
uint32_t reduce_stride
Bytes from one element measured to the next.
Definition BufferGather.hpp:52
uint32_t out_words
Words of elements written.
Definition BufferGather.hpp:44
What a gather pass reads and where its result goes.
Definition BufferGather.hpp:85
int64_t bind_offset
The range of the source buffer the shader reads.
Definition BufferGather.hpp:88
int64_t readback_offset
The range of the staging buffer read back.
Definition BufferGather.hpp:93
int64_t staging_bytes
Bytes the staging buffer needs: the header and the elements.
Definition BufferGather.hpp:91
What the header of a staging buffer says of the elements measured.
Definition BufferGather.hpp:210
std::array< float, 4 > lo
Empty, lo above hi, for a component without one finite value.
Definition BufferGather.hpp:212
Definition BufferDecode.hpp:29
Which elements of a buffer a view reads.
Definition BufferDecode.hpp:90