chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
215 / 221
97.3%
Branches:
216 / 244
88.5%
Functions:
16 / 16, 1 excl
100.0%

bvh/software_builder.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/bvh/software_builder.h"
3
4 #include <algorithm>
5 #include <cstdint>
6 #include <limits>
7 #include <memory>
8 #include <optional>
9 #include <variant>
10 #include <vector>
11
12 #include "chrono_batch_render/bvh/common.h"
13 #include "chrono_batch_render/bvh/kernels.h"
14 #include "chrono_batch_render/bvh/kernels/instances.h"
15 #include "chrono_batch_render/bvh/kernels/refit.h"
16 #include "chrono_batch_render/bvh/lbvh.h"
17 #include "chrono_batch_render/device/device.h"
18 #include "chrono_batch_render/device/program.h"
19 #include "chrono_batch_render/device/queue.h"
20 #include "chrono_batch_render/util/error.h"
21 #include "chrono_batch_render/util/log.h"
22 #include "chrono_batch_render/util/profiler.h"
23
24 namespace chrono::batch_render::bvh {
25
26 using device::Buffer;
27 using device::BufferRange;
28 using device::CommandEncoder;
29 using device::Device;
30 using device::Traversal;
31
32 namespace {
33
34 class SoftwareBuilder final : public Builder {
35 public:
36 414 explicit SoftwareBuilder(Device& device) : Builder(device) {}
37
38 263 Traversal Format() const override {
39 263 return Traversal::Software;
40 }
41
42 356 void Prepare() override {
43 356 Fit(1, 1);
44 356 Updating();
45 356 }
46
47 619 Ref<Blas> CreateBlas(const Geometry& geometry) override {
48
1/1
✓ Branch 2 taken 619 times.
619 return Ref<Blas>(new SoftwareBlas(m_device, geometry));
49 }
50
51 313 Ref<Tlas> CreateTlas(std::span<const uint32_t> capacities) override {
52
1/1
✓ Branch 2 taken 312 times.
313 return Ref<Tlas>(new SoftwareTlas(m_device, capacities));
53 }
54
55 631 void Build(CommandEncoder& encoder, std::span<const Ref<Blas>> blases) override {
56
4/5
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 624 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
631 CHRONO_BATCH_RENDER_ZONE("Bvh/SoftwareBlases");
57
4/5
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 624 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
631 static const profiler::ZoneId zone = profiler::ZoneId::Named("Bvh/BlasBuild");
58
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 586 times.
631 if (blases.empty()) {
59 45 return;
60 }
61
1/1
✓ Branch 1 taken 586 times.
586 Log(LogLevel::Debug, "building {} software BLASes", blases.size());
62
1/1
✓ Branch 1 taken 586 times.
586 const device::ZoneScope scope(encoder, zone);
63
2/2
✓ Branch 0 taken 1172 times.
✓ Branch 1 taken 586 times.
1758 for (const uint32_t kind : {kBvhTriangles, kBvhBoxes}) {
64 1172 std::vector<Geometry> geometries;
65 1172 std::vector<BufferRange> outputs;
66 1172 uint64_t primitives = 0;
67 1172 bool flushed = false;
68 2344 const auto flush = [&] {
69
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 584 times.
1172 if (geometries.empty()) {
70 return;
71 }
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (flushed) {
73 ✗ encoder.Barrier();
74 }
75 588 Fit(primitives, geometries.size()).Build(encoder, geometries, outputs);
76 588 flushed = true;
77 588 geometries.clear();
78 588 outputs.clear();
79 588 primitives = 0;
80 1172 };
81
2/2
✓ Branch 0 taken 1316 times.
✓ Branch 1 taken 1172 times.
2488 for (const Ref<Blas>& blas : blases) {
82
1/1
✓ Branch 1 taken 1316 times.
1316 const auto& software = RequireFormat<SoftwareBlas>("Build", *blas);
83
1/1
✓ Branch 1 taken 1316 times.
1316 const Geometry& geometry = software.GetGeometry();
84
3/3
✓ Branch 1 taken 1316 times.
✓ Branch 3 taken 658 times.
✓ Branch 4 taken 658 times.
1316 if (Kind(geometry) != kind) {
85 658 continue;
86 }
87
1/1
✓ Branch 1 taken 658 times.
658 const uint64_t count = PrimitiveCount(geometry);
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 658 times.
658 if (primitives + count > LbvhBuilder::kMaxPrimitives) {
89
0/1
✗ Branch 1 not taken.
✗ flush();
90 }
91
1/1
✓ Branch 1 taken 658 times.
658 geometries.push_back(geometry);
92
1/1
✓ Branch 1 taken 658 times.
658 outputs.emplace_back(software.Storage());
93 658 primitives += count;
94 }
95
1/1
✓ Branch 1 taken 1172 times.
1172 flush();
96 1172 }
97 631 }
98
99 251 void Refit(CommandEncoder& encoder, std::span<const Ref<Blas>> blases) override {
100
4/5
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 247 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
251 CHRONO_BATCH_RENDER_ZONE("Bvh/SoftwareBlases");
101
4/5
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 247 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
251 static const profiler::ZoneId zone = profiler::ZoneId::Named("Bvh/BlasRefit");
102
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 47 times.
251 if (blases.empty()) {
103 204 return;
104 }
105
1/1
✓ Branch 1 taken 47 times.
47 Log(LogLevel::Debug, "refitting {} software BLASes", blases.size());
106
1/1
✓ Branch 1 taken 47 times.
47 const device::ZoneScope scope(encoder, zone);
107
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 46 times.
139 for (const uint32_t kind : {kBvhTriangles, kBvhBoxes}) {
108 93 std::vector<RefitSegment> segments;
109
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 92 times.
213 for (const Ref<Blas>& blas : blases) {
110
1/1
✓ Branch 1 taken 121 times.
121 const auto& software = RequireFormat<SoftwareBlas>("Refit", *blas);
111
1/1
✓ Branch 1 taken 121 times.
121 const Geometry& geometry = software.GetGeometry();
112
2/2
✓ Branch 1 taken 121 times.
✓ Branch 4 taken 120 times.
121 RequireRefittable("Refit", ToAccelInput(geometry));
113
3/3
✓ Branch 1 taken 120 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 60 times.
120 if (Kind(geometry) == kind) {
114
2/2
✓ Branch 1 taken 60 times.
✓ Branch 4 taken 60 times.
120 segments.push_back({software.Handle(), 0,
115
2/2
✓ Branch 1 taken 60 times.
✓ Branch 4 taken 60 times.
60 LbvhEntry(Updating(), "Refit", geometry),
116
1/1
✓ Branch 1 taken 60 times.
60 PrimitiveCount(geometry)});
117 }
118 }
119
1/1
✓ Branch 1 taken 92 times.
92 RefitSegments(encoder, kind, 0, segments);
120 93 }
121 252 }
122
123 626 void Build(CommandEncoder& encoder, Tlas& tlas, BufferRange instances,
124 std::optional<BufferRange> counts, std::span<const uint32_t> worlds) override {
125
4/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 620 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
626 CHRONO_BATCH_RENDER_ZONE("Bvh/SoftwareTlas");
126
4/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 620 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
626 static const profiler::ZoneId zone = profiler::ZoneId::Named("Bvh/TlasBuild");
127
1/1
✓ Branch 1 taken 626 times.
626 const auto& software = RequireFormat<SoftwareTlas>("Build", tlas);
128
1/1
✓ Branch 1 taken 625 times.
626 RequireInstances("Build", tlas, instances);
129
1/1
✓ Branch 1 taken 623 times.
625 const std::vector<uint32_t> selected = SelectWorlds("Build", tlas, worlds);
130
1/1
✓ Branch 1 taken 623 times.
623 Log(LogLevel::Debug, "building {} of {} software TLAS worlds", selected.size(),
131
1/1
✓ Branch 1 taken 623 times.
623 tlas.Count());
132
1/1
✓ Branch 1 taken 623 times.
623 const device::ZoneScope scope(encoder, zone);
133 623 std::vector<BufferRange> outputs;
134 623 std::vector<uint32_t> capacities;
135
2/2
✓ Branch 0 taken 742 times.
✓ Branch 1 taken 623 times.
1365 for (const uint32_t w : selected) {
136
1/1
✓ Branch 1 taken 742 times.
742 outputs.push_back(software.World(w));
137
1/1
✓ Branch 1 taken 742 times.
742 capacities.push_back(tlas.Capacities()[w]);
138 }
139
2/2
✓ Branch 0 taken 607 times.
✓ Branch 1 taken 16 times.
623 if (selected.size() == tlas.Count()) {
140
3/3
✓ Branch 1 taken 607 times.
✓ Branch 4 taken 607 times.
✓ Branch 7 taken 607 times.
607 Fit(Total(capacities), capacities.size())
141
1/1
✓ Branch 1 taken 607 times.
607 .Build(encoder, instances, capacities, counts, outputs);
142 607 return;
143 }
144
145
1/1
✓ Branch 1 taken 16 times.
16 const std::vector<uint32_t> offsets = Offsets(tlas.Capacities());
146
2/3
✓ Branch 1 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
16 const uint64_t total = std::max<uint64_t>(Total(capacities), 1);
147 16 Buffer& compact =
148
2/2
✓ Branch 1 taken 16 times.
✓ Branch 4 taken 16 times.
16 Reserve(m_device, m_compact,
149 16 {.bytes = total * sizeof(InstanceRecord), .label = "tlas world instances"});
150 16 Buffer& compactCounts =
151
1/1
✓ Branch 1 taken 16 times.
16 Reserve(m_device, m_compactCounts,
152
1/1
✓ Branch 1 taken 16 times.
16 {.bytes = selected.size() * sizeof(uint32_t), .label = "tlas world counts"});
153 16 std::vector<uint32_t> sourceOffsets;
154
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 16 times.
34 for (const uint32_t w : selected) {
155
1/1
✓ Branch 1 taken 18 times.
18 sourceOffsets.push_back(offsets[w]);
156 }
157 16 Tables tables;
158
1/1
✓ Branch 1 taken 16 times.
16 const uint64_t sourceStart = tables.Add(sourceOffsets);
159
2/2
✓ Branch 1 taken 16 times.
✓ Branch 4 taken 16 times.
16 const uint64_t offsetsStart = tables.Add(Offsets(capacities));
160
1/1
✓ Branch 1 taken 16 times.
16 const uint64_t worldsStart = tables.Add(selected);
161
2/2
✓ Branch 1 taken 16 times.
✓ Branch 4 taken 16 times.
16 const Ref<Buffer> table = tables.Upload(m_device, "tlas world gather");
162
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 const GatherWorldsParams params = {.source = {instances.Address()},
163 16 .destination = {compact.Address()},
164 16 .sourceOffsets = {table->Address() + sourceStart},
165 16 .offsets = {table->Address() + offsetsStart},
166
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 .worlds = {table->Address() + worldsStart},
167
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 .counts = {counts ? counts->Address() : 0},
168
1/1
✓ Branch 1 taken 16 times.
16 .gatheredCounts = {compactCounts.Address()},
169
1/1
✓ Branch 1 taken 16 times.
16 .total = uint32_t(Total(capacities)),
170
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 16 times.
✓ Branch 6 taken 16 times.
30 .selected = uint32_t(selected.size())};
171
1/1
✓ Branch 1 taken 16 times.
16 encoder.Barrier();
172
4/5
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✓ Branch 3 taken 16 times.
✓ Branch 6 taken 16 times.
✓ Branch 9 taken 16 times.
16 encoder.Dispatch(Updating().Entry("GatherWorlds"), params,
173
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✓ Branch 3 taken 16 times.
16 {.x = device::GroupCount(std::max<uint64_t>(params.total, params.selected),
174 kGatherWorldsThreads)});
175
1/1
✓ Branch 1 taken 16 times.
16 encoder.Barrier();
176 16 std::optional<BufferRange> compactRange;
177
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 if (counts) {
178
1/1
✓ Branch 1 taken 14 times.
14 compactRange = compactCounts.Slice(0, selected.size() * sizeof(uint32_t));
179 }
180
3/3
✓ Branch 1 taken 16 times.
✓ Branch 4 taken 16 times.
✓ Branch 7 taken 16 times.
16 Fit(Total(capacities), capacities.size())
181
3/6
✓ Branch 1 taken 16 times.
✓ Branch 4 taken 16 times.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
16 .Build(encoder, compact.Slice(0, total * sizeof(InstanceRecord)), capacities,
182 compactRange, outputs);
183 674 }
184
185 159 void Refit(CommandEncoder& encoder, Tlas& tlas, BufferRange instances,
186 std::optional<BufferRange>, std::span<const uint32_t> worlds) override {
187
4/5
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 155 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
159 CHRONO_BATCH_RENDER_ZONE("Bvh/SoftwareTlas");
188
4/5
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 155 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
159 static const profiler::ZoneId zone = profiler::ZoneId::Named("Bvh/TlasRefit");
189
1/1
✓ Branch 1 taken 159 times.
159 RequireFormat<SoftwareTlas>("Refit", tlas);
190
1/1
✓ Branch 1 taken 159 times.
159 RequireInstances("Refit", tlas, instances);
191
1/1
✓ Branch 1 taken 159 times.
159 const std::vector<uint32_t> offsets = Offsets(tlas.Capacities());
192
1/1
✓ Branch 1 taken 159 times.
159 const std::vector<uint32_t> selected = SelectWorlds("Refit", tlas, worlds);
193
1/1
✓ Branch 1 taken 159 times.
159 Log(LogLevel::Debug, "refitting {} of {} software TLAS worlds", selected.size(),
194
1/1
✓ Branch 1 taken 159 times.
159 tlas.Count());
195
1/1
✓ Branch 1 taken 159 times.
159 const device::ZoneScope scope(encoder, zone);
196 159 std::vector<RefitSegment> segments;
197
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 159 times.
328 for (const uint32_t w : selected) {
198
2/2
✓ Branch 1 taken 169 times.
✓ Branch 4 taken 169 times.
169 segments.push_back({tlas.Handle(w), offsets[w], {}, tlas.Capacities()[w]});
199 }
200
1/1
✓ Branch 1 taken 159 times.
159 RefitSegments(encoder, kBvhInstances, instances.Address(), segments);
201 159 }
202
203 private:
204 struct RefitSegment {
205 uint64_t header = 0;
206 uint32_t instanceOffset = 0;
207 LbvhGeometry geometry{};
208 uint32_t primitives = 0;
209 };
210
211 638 device::Program& Updating() {
212
2/2
✓ Branch 0 taken 383 times.
✓ Branch 1 taken 255 times.
638 if (!m_updating) {
213 383 m_updating =
214
2/2
✓ Branch 1 taken 383 times.
✓ Branch 4 taken 383 times.
1149 m_device.CreateProgram({.modules = {"chrono_batch_render.bvh.kernels.refit",
215 "chrono_batch_render.bvh.kernels.instances"},
216 .library = &kBvhKernels,
217 .entries = {"RefitLeaves", "RefitNodes", "GatherWorlds"},
218
2/3
✓ Branch 1 taken 383 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 383 times.
766 .label = "bvh updates"});
219 }
220 638 return *m_updating;
221 766 }
222
223 251 void RefitSegments(CommandEncoder& encoder, uint32_t kind, uint64_t instances,
224 std::span<const RefitSegment> segments) {
225
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 206 times.
251 if (segments.empty()) {
226 45 return;
227 }
228 206 std::vector<uint64_t> headers;
229 206 std::vector<LbvhGeometry> geometries;
230 206 std::vector<uint32_t> instanceOffsets;
231 206 std::vector<uint32_t> rooms;
232
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 206 times.
435 for (const RefitSegment& segment : segments) {
233
1/1
✓ Branch 1 taken 229 times.
229 headers.push_back(segment.header);
234
1/1
✓ Branch 1 taken 229 times.
229 geometries.push_back(segment.geometry);
235
1/1
✓ Branch 1 taken 229 times.
229 instanceOffsets.push_back(segment.instanceOffset);
236
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
✓ Branch 3 taken 229 times.
229 rooms.push_back(std::max(segment.primitives, 1u));
237 }
238
1/1
✓ Branch 1 taken 206 times.
206 const std::vector<uint32_t> nodeOffsets = Offsets(rooms);
239 206 const uint32_t nodes = nodeOffsets.back();
240
241 206 Tables tables;
242
1/1
✓ Branch 1 taken 206 times.
206 const uint64_t headersStart = tables.Add(headers);
243
1/1
✓ Branch 1 taken 206 times.
206 const uint64_t geometriesStart = tables.Add(geometries);
244
1/1
✓ Branch 1 taken 206 times.
206 const uint64_t instanceOffsetsStart = tables.Add(instanceOffsets);
245
1/1
✓ Branch 1 taken 206 times.
206 const uint64_t nodeOffsetsStart = tables.Add(nodeOffsets);
246
2/2
✓ Branch 1 taken 206 times.
✓ Branch 4 taken 206 times.
206 const Ref<Buffer> table = tables.Upload(m_device, "bvh refit tables");
247
248 206 const uint64_t bytes = uint64_t(nodes) * 16 * sizeof(uint32_t);
249 206 const uint64_t base =
250
2/2
✓ Branch 1 taken 206 times.
✓ Branch 4 taken 206 times.
206 Reserve(m_device, m_refitScratch, {.bytes = bytes, .label = "bvh refit scratch"})
251 206 .Address();
252 206 const RefitParams params = {.headers = {table->Address() + headersStart},
253 .instances = {instances},
254 206 .instanceOffsets = {table->Address() + instanceOffsetsStart},
255 206 .geometries = {table->Address() + geometriesStart},
256 206 .nodeOffsets = {table->Address() + nodeOffsetsStart},
257 .parents = {base},
258 206 .arrivals = {base + uint64_t(nodes) * sizeof(uint32_t)},
259 206 .boxes = {base + uint64_t(nodes) * 2 * sizeof(uint32_t)},
260 206 .leafBoxes = {base + uint64_t(nodes) * 8 * sizeof(uint32_t)},
261 206 .segments = uint32_t(segments.size()),
262 .nodes = nodes,
263
1/1
✓ Branch 1 taken 206 times.
206 .kind = kind};
264
265
1/1
✓ Branch 1 taken 206 times.
206 const device::Size3 groups{.x = device::GroupCount(nodes, kRefitThreads)};
266
1/1
✓ Branch 1 taken 206 times.
206 device::Program& program = Updating();
267
1/1
✓ Branch 1 taken 206 times.
206 encoder.Barrier();
268
2/2
✓ Branch 1 taken 206 times.
✓ Branch 4 taken 206 times.
206 encoder.Dispatch(program.Entry("RefitLeaves"), params, groups);
269
1/1
✓ Branch 1 taken 206 times.
206 encoder.Barrier();
270
3/4
✓ Branch 1 taken 206 times.
✓ Branch 4 taken 206 times.
✓ Branch 6 taken 206 times.
✗ Branch 7 not taken.
412 encoder.Dispatch(program.Entry("RefitNodes"), params, groups);
271 618 }
272
273 1567 LbvhBuilder& Fit(uint64_t primitives, size_t segments) {
274
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1567 times.
1567 if (primitives > LbvhBuilder::kMaxPrimitives) {
275 ✗ throw Error("Build of {} primitives; a build takes at most {}", primitives,
276
0/1
✗ Branch 2 not taken.
✗ LbvhBuilder::kMaxPrimitives);
277 }
278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1567 times.
1567 if (segments > std::numeric_limits<uint32_t>::max()) {
279 ✗ throw Error("Build of {} BVHs; a build takes at most {}", segments,
280
0/1
✗ Branch 2 not taken.
✗ std::numeric_limits<uint32_t>::max());
281 }
282
283
6/6
✓ Branch 0 taken 1157 times.
✓ Branch 1 taken 410 times.
✓ Branch 2 taken 743 times.
✓ Branch 3 taken 414 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 741 times.
1567 if (!m_lbvh || m_lbvh->Capacity() < primitives || m_lbvh->Segments() < segments) {
284 826 uint64_t capacity = primitives;
285 826 uint64_t most = segments;
286
2/2
✓ Branch 0 taken 416 times.
✓ Branch 1 taken 410 times.
826 if (m_lbvh) {
287
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 409 times.
416 capacity = std::max(capacity, uint64_t(m_lbvh->Capacity()) * 3 / 2);
288
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 402 times.
430 most = std::max(most, uint64_t(m_lbvh->Segments()) * 3 / 2);
289 }
290 826 Log(LogLevel::Debug, "the LBVH builder grows to {} primitives in {} BVHs", capacity,
291 most);
292 1652 m_lbvh.emplace(
293 826 m_device, uint32_t(std::min<uint64_t>(capacity, LbvhBuilder::kMaxPrimitives)),
294
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 826 times.
1652 uint32_t(std::min<uint64_t>(most, std::numeric_limits<uint32_t>::max())));
295 }
296 1567 return *m_lbvh;
297 }
298
299 std::optional<LbvhBuilder> m_lbvh;
300 Ref<device::Program> m_updating;
301 Ref<Buffer> m_refitScratch;
302 Ref<Buffer> m_compact;
303 Ref<Buffer> m_compactCounts;
304 };
305
306 }
307
308 619 SoftwareBlas::SoftwareBlas(Device& device, const Geometry& geometry)
309
1/1
✓ Branch 1 taken 619 times.
619 : Blas(kFormat), m_geometry(geometry), m_buffers(GeometryBuffers(geometry)),
310
1/1
✓ Branch 1 taken 619 times.
619 m_storage(device.CreateBuffer(
311
5/5
✓ Branch 1 taken 619 times.
✓ Branch 4 taken 619 times.
✓ Branch 7 taken 619 times.
✓ Branch 10 taken 619 times.
✓ Branch 13 taken 619 times.
1238 {.bytes = StorageBytes(PrimitiveCount(geometry), Kind(geometry)), .label = "blas"})) {}
312
313 313 SoftwareTlas::SoftwareTlas(Device& device, std::span<const uint32_t> capacities)
314 313 : Tlas(kFormat, capacities) {
315 312 std::vector<uint64_t> handles;
316 312 uint64_t bytes = 0;
317
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 312 times.
734 for (const uint32_t capacity : capacities) {
318
1/1
✓ Branch 1 taken 422 times.
422 handles.push_back(bytes);
319
1/1
✓ Branch 1 taken 422 times.
422 bytes += StorageBytes(capacity, kBvhInstances);
320 }
321
2/3
✓ Branch 1 taken 312 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 312 times.
312 m_storage = device.CreateBuffer({.bytes = bytes, .label = "tlas"});
322
2/2
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 312 times.
734 for (uint64_t& handle : handles) {
323 422 handle += m_storage->Address();
324 }
325
1/1
✓ Branch 1 taken 312 times.
312 SetHandles(device, std::move(handles));
326 936 }
327
328 750 BufferRange SoftwareTlas::World(uint32_t world) const {
329 750 return m_storage->Slice(Handle(world) - m_storage->Address(),
330 750 StorageBytes(Capacities()[world], kBvhInstances));
331 }
332
333 414 std::unique_ptr<Builder> CreateSoftwareBuilder(Device& device) {
334
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 414 times.
414 return std::make_unique<SoftwareBuilder>(device);
335 }
336
337 }
338