chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
183 / 258
70.9%
Branches:
85 / 188
45.2%
Functions:
30 / 35
85.7%

device/commands.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/device/commands.h"
3
4 #include <algorithm>
5 #include <cstring>
6 #include <utility>
7
8 #include "chrono_batch_render/device/device.h"
9 #include "chrono_batch_render/device/kernels/shared.h"
10 #include "chrono_batch_render/device/queue.h"
11 #include "chrono_batch_render/util/error.h"
12 #include "chrono_batch_render/util/log.h"
13
14 namespace chrono::batch_render::device {
15 namespace {
16
17 341734 void RequireWords(BufferRange range, const char* what) {
18
2/4
✓ Branch 0 taken 341734 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 341734 times.
341734 if (range.Offset() % 4 != 0 || range.Bytes() % 4 != 0) {
19 ✗ throw Error("{} of buffer \"{}\" has offset {} and size {}; both must be "
20 "multiples of 4",
21
0/1
✗ Branch 2 not taken.
✗ what, range.GetBuffer().Label(), range.Offset(), range.Bytes());
22 }
23 341734 }
24
25 constexpr uint32_t kMaxGroups = kMaxGroupsPerAxis;
26
27 constexpr bool Covers(Size3 folded, uint32_t count) {
28 return folded.x <= kMaxGroups && folded.y <= kMaxGroups && folded.z <= kMaxGroups &&
29 uint64_t(folded.x) * folded.y * folded.z >= count;
30 }
31
32 static_assert(FoldGroups(65536) == Size3{32768, 2, 1});
33 static_assert(Covers(FoldGroups(65536), 65536));
34 static_assert(Covers(FoldGroups(70001), 70001));
35 static_assert(Covers(FoldGroups(uint32_t(kMaxGroups) * kMaxGroups),
36 uint32_t(kMaxGroups) * kMaxGroups));
37 static_assert(FoldGroups(~uint32_t(0)).z == 2 && Covers(FoldGroups(~uint32_t(0)), ~uint32_t(0)));
38
39 154685 Size3 Grid(const Kernel& kernel, Size3 groups) {
40
2/4
✓ Branch 0 taken 154685 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 154685 times.
154685 if (groups.y > kMaxGroups || groups.z > kMaxGroups) {
41 ✗ throw Error("Dispatch of kernel {} over {} x {} x {} groups; y and z take at most {}",
42
0/1
✗ Branch 2 not taken.
✗ kernel.Name(), groups.x, groups.y, groups.z, kMaxGroups);
43 }
44
1/2
✓ Branch 0 taken 154685 times.
✗ Branch 1 not taken.
154685 if (groups.x <= kMaxGroups) {
45 154685 return groups;
46 }
47
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (groups.y != 1 || groups.z != 1) {
48 ✗ throw Error("Dispatch of kernel {} over {} x {} x {} groups; only x takes more than {}, "
49 "and only when y and z are 1",
50
0/1
✗ Branch 2 not taken.
✗ kernel.Name(), groups.x, groups.y, groups.z, kMaxGroups);
51 }
52
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (!kernel.Foldable()) {
53 ✗ throw Error("Dispatch of kernel {} over {} groups, which fold into more axes; it reads "
54 "SV_DispatchThreadID or SV_GroupID, which folding changes: index it with "
55 "LinearThreadIndex()",
56
0/1
✗ Branch 2 not taken.
✗ kernel.Name(), groups.x);
57 }
58 ✗ return FoldGroups(groups.x);
59 }
60
61 77897 void RequireCounts(const Kernel& kernel, BufferRange counts, Size3 groups) {
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77897 times.
77897 if (!Has(counts.GetBuffer().Usage(), BufferUsage::Indirect)) {
63 ✗ throw Error("Dispatch of kernel {} reads its counts from buffer \"{}\", which lacks "
64 "BufferUsage::Indirect",
65
0/1
✗ Branch 2 not taken.
✗ kernel.Name(), counts.GetBuffer().Label());
66 }
67
2/4
✓ Branch 0 taken 77897 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77897 times.
77897 if (counts.Offset() % 4 != 0 || counts.Bytes() < 12) {
68 ✗ throw Error("Dispatch of kernel {} reads its counts at offset {} of {} bytes of buffer "
69 "\"{}\"; they are 12 bytes at a multiple of 4",
70
0/1
✗ Branch 2 not taken.
✗ kernel.Name(), counts.Offset(), counts.Bytes(), counts.GetBuffer().Label());
71 }
72
3/6
✓ Branch 0 taken 77897 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 77897 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 77897 times.
77897 if (groups.x > kMaxGroups || groups.y > kMaxGroups || groups.z > kMaxGroups) {
73 ✗ throw Error("Dispatch of kernel {} over at most {} x {} x {} groups read; each count "
74 "is at most {}, as they don't fold",
75
0/1
✗ Branch 2 not taken.
✗ kernel.Name(), groups.x, groups.y, groups.z, kMaxGroups);
76 }
77 77897 }
78
79 }
80
81
2/2
✓ Branch 0 taken 127290 times.
✓ Branch 1 taken 111262 times.
238552 CommandBuffer::CommandBuffer(Queue& queue, bool own) : m_queue(&queue), m_open(!own) {
82
2/2
✓ Branch 0 taken 127290 times.
✓ Branch 1 taken 111262 times.
238552 if (!own) {
83
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 127290 times.
127290 m_device = Ref<Device>(&queue.GetDevice());
84
1/1
✓ Branch 1 taken 127290 times.
127290 queue.OpenRecording();
85 }
86 238552 }
87
88 146660 CommandBuffer::CommandBuffer(CommandBuffer&& other) noexcept
89 146660 : m_queue(other.m_queue), m_device(std::move(other.m_device)),
90 146660 m_commands(std::move(other.m_commands)), m_data(std::move(other.m_data)),
91 146660 m_zones(std::move(other.m_zones)), m_open(std::exchange(other.m_open, false)),
92 146660 m_reusable(other.m_reusable), m_held(std::move(other.m_held)),
93 146660 m_submission(other.m_submission), m_recorded(std::move(other.m_recorded)) {}
94
95 148281 CommandBuffer& CommandBuffer::operator=(CommandBuffer&& other) noexcept {
96
1/2
✓ Branch 0 taken 148281 times.
✗ Branch 1 not taken.
148281 if (this != &other) {
97 148281 Close();
98 148281 Release();
99 148281 m_queue = other.m_queue;
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148281 times.
148281 m_device = std::move(other.m_device);
101 148281 m_commands = std::move(other.m_commands);
102 148281 m_data = std::move(other.m_data);
103 148281 m_zones = std::move(other.m_zones);
104 148281 m_open = std::exchange(other.m_open, false);
105 148281 m_reusable = other.m_reusable;
106 148281 m_held = std::move(other.m_held);
107 148281 m_submission = other.m_submission;
108 148281 m_recorded = std::move(other.m_recorded);
109 }
110 148281 return *this;
111 }
112
113 385212 CommandBuffer::~CommandBuffer() {
114 385212 Close();
115 385212 Release();
116 385212 }
117
118 533493 void CommandBuffer::Release() {
119
3/4
✓ Branch 0 taken 533491 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 533491 times.
533493 if (m_recorded.native || m_recorded.timestamps) {
120
3/4
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
4 m_queue->Retire(std::make_shared<Recorded>(std::exchange(m_recorded, {})), m_submission);
121 }
122 533493 }
123
124 597130 void CommandBuffer::Close() {
125
2/2
✓ Branch 0 taken 127290 times.
✓ Branch 1 taken 469840 times.
597130 if (std::exchange(m_open, false)) {
126 127290 m_queue->CloseRecording();
127 }
128 597130 }
129
130 2 void CommandBuffer::HoldResources() {
131 7 const auto hold = [&](Resource* resource) {
132
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 time.
5 if (resource != nullptr &&
133
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 time.
5 std::none_of(m_held.begin(), m_held.end(), [resource](const Ref<Resource>& held) {
134
2/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 time.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
3 return held.Get() == resource;
135 })) {
136 4 m_held.emplace_back(resource);
137 }
138 7 };
139
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (const Command& command : m_commands) {
140 6 std::visit(Overloaded{
141 2 [&](const CopyCommand& c) {
142 2 hold(c.src);
143 2 hold(c.dst);
144 2 },
145 ✗ [&](const TextureCopyCommand& c) {
146 ✗ hold(c.src);
147 ✗ hold(c.dst);
148 ✗ },
149 1 [&](const FillCommand& c) { hold(c.dst); },
150 ✗ [&](const UpdateCommand& c) { hold(c.dst); },
151 ✗ [&](const DispatchCommand& c) {
152 ✗ hold(&c.kernel->GetProgram());
153 ✗ hold(c.counts);
154 ✗ },
155 ✗ [&](const BuildAccelCommand& c) {
156 ✗ hold(c.dst);
157 ✗ hold(c.scratch);
158 ✗ ForEachBuffer(c.input,
159 ✗ [&](BufferRange range) { hold(&range.GetBuffer()); });
160 ✗ },
161 [&](const BarrierCommand&) {},
162 [&](const ZoneCommand&) {},
163 },
164 command);
165 }
166 2 }
167
168 65916 CommandEncoder::CommandEncoder(Queue& queue, bool own) : m_recording(queue, own), m_own(own) {}
169
170 12395 void CommandEncoder::Append(const CommandBuffer& commands) {
171 12395 const auto zones = uint32_t(m_recording.m_zones.size());
172 12395 m_recording.m_zones.insert(m_recording.m_zones.end(), commands.m_zones.begin(),
173 commands.m_zones.end());
174 12395 m_recording.m_commands.push_back(BarrierCommand{});
175
2/2
✓ Branch 0 taken 729520 times.
✓ Branch 1 taken 12395 times.
741915 for (Command command : commands.m_commands) {
176 729520 std::visit(Overloaded{
177 47537 [&](UpdateCommand& c) {
178 47537 c.data = Store(commands.m_data.data() + c.data, c.bytes, 4);
179 47537 },
180 265765 [&](DispatchCommand& c) {
181 265765 c.data = Store(commands.m_data.data() + c.data, c.paramBytes, 8);
182 265765 },
183 30200 [&](ZoneCommand& c) { c.index += zones; },
184 [](auto&) {},
185 },
186 command);
187 729520 m_recording.m_commands.push_back(command);
188 }
189 12395 m_barrier = true;
190 12395 }
191
192 705653 void CommandEncoder::Require(const Resource& resource, const char* what) const {
193 705653 m_recording.m_queue->GetDevice().Require(resource, what);
194 705653 }
195
196 755916 size_t CommandEncoder::Store(const void* data, size_t bytes, size_t alignment) {
197 755916 std::vector<std::byte>& stored = m_recording.m_data;
198 755916 const size_t at = RoundUp(stored.size(), alignment);
199 755916 stored.resize(at + RoundUp(bytes, 4));
200
1/2
✓ Branch 0 taken 755916 times.
✗ Branch 1 not taken.
755916 if (bytes > 0) {
201 755916 std::memcpy(stored.data() + at, data, bytes);
202 }
203 755916 return at;
204 }
205
206 601035 void CommandEncoder::Record(const Command& command) {
207
4/4
✓ Branch 0 taken 3516 times.
✓ Branch 1 taken 597519 times.
✓ Branch 2 taken 3515 times.
✓ Branch 3 taken 1 time.
601035 if (!m_concurrent || m_barrier) {
208 601034 m_recording.m_commands.push_back(BarrierCommand{});
209 601034 m_barrier = false;
210 }
211 601035 m_recording.m_commands.push_back(command);
212 601035 }
213
214 26590 void CommandEncoder::Copy(BufferRange src, BufferRange dst) {
215 26590 Require(src.GetBuffer(), "Copy");
216 26590 Require(dst.GetBuffer(), "Copy");
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26590 times.
26590 if (dst.Bytes() < src.Bytes()) {
218
0/1
✗ Branch 1 not taken.
✗ throw Error("Copy of {} bytes into {} bytes of buffer \"{}\"", src.Bytes(), dst.Bytes(),
219
0/1
✗ Branch 2 not taken.
✗ dst.GetBuffer().Label());
220 }
221 26590 const bool sameBuffer = &src.GetBuffer() == &dst.GetBuffer();
222
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 26575 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 1 time.
26590 if (sameBuffer && src.Offset() < dst.Offset() + src.Bytes() &&
223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 dst.Offset() < src.Offset() + src.Bytes()) {
224
0/1
✗ Branch 2 not taken.
✗ throw Error("Copy within buffer \"{}\" overlaps itself", src.GetBuffer().Label());
225 }
226
1/2
✓ Branch 0 taken 26590 times.
✗ Branch 1 not taken.
26590 if (src.Bytes() > 0) {
227 51252 const auto staging = [](const Buffer& buffer) {
228
3/4
✓ Branch 0 taken 24662 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 483 times.
✓ Branch 3 taken 24179 times.
49324 return buffer.GetMemory() == Memory::Upload || buffer.GetMemory() == Memory::Readback;
229 };
230
3/4
✓ Branch 0 taken 24662 times.
✓ Branch 1 taken 1928 times.
✓ Branch 2 taken 24662 times.
✗ Branch 3 not taken.
51252 if (!staging(src.GetBuffer()) && !staging(dst.GetBuffer())) {
231 483 m_recording.m_queue->GetDevice().CountTraffic({.copyBytes = src.Bytes()});
232 }
233 26590 Record(CopyCommand{&src.GetBuffer(), src.Offset(), &dst.GetBuffer(), dst.Offset(),
234 26590 src.Bytes()});
235 }
236 26590 }
237
238 130 void CommandEncoder::Copy(BufferRange src, Texture& dst, uint32_t level) {
239 130 Require(src.GetBuffer(), "Copy");
240 130 Require(dst, "Copy");
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
130 if (level >= dst.Desc().levels) {
242 ✗ throw Error("Copy into level {} of texture \"{}\", which has {}", level, dst.Label(),
243
0/1
✗ Branch 2 not taken.
✗ dst.Desc().levels);
244 }
245 130 const uint64_t bytes = dst.LevelBytes(level);
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
130 if (src.Bytes() < bytes) {
247
0/1
✗ Branch 1 not taken.
✗ throw Error("Copy of {} bytes into level {} of texture \"{}\", which takes {}", src.Bytes(),
248
0/1
✗ Branch 2 not taken.
✗ level, dst.Label(), bytes);
249 }
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
130 if (src.Offset() % 16 != 0) {
251 ✗ throw Error("Copy into texture \"{}\" from offset {} of buffer \"{}\"; it takes a "
252 "multiple of 16",
253
0/1
✗ Branch 2 not taken.
✗ dst.Label(), src.Offset(), src.GetBuffer().Label());
254 }
255 130 Record(TextureCopyCommand{&src.GetBuffer(), src.Offset(), &dst, level});
256 130 }
257
258 131701 void CommandEncoder::Fill(BufferRange dst, uint32_t value) {
259 131701 Require(dst.GetBuffer(), "Fill");
260 131701 RequireWords(dst, "Fill");
261
1/2
✓ Branch 0 taken 131701 times.
✗ Branch 1 not taken.
131701 if (dst.Bytes() > 0) {
262 131701 Record(FillCommand{&dst.GetBuffer(), dst.Offset(), dst.Bytes(), value});
263 }
264 131701 }
265
266 210033 void CommandEncoder::Update(BufferRange dst, const void* data) {
267 210033 Require(dst.GetBuffer(), "Update");
268 210033 RequireWords(dst, "Update");
269
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 210032 times.
210033 if (dst.Bytes() > kMaxUpdateBytes) {
270 1 throw Error("Update of {} bytes of buffer \"{}\"; it writes at most {}; Queue::Write "
271 "stages larger writes",
272
1/1
✓ Branch 2 taken 1 time.
1 dst.Bytes(), dst.GetBuffer().Label(), kMaxUpdateBytes);
273 }
274
1/2
✓ Branch 0 taken 210032 times.
✗ Branch 1 not taken.
210032 if (dst.Bytes() > 0) {
275 210032 Record(UpdateCommand{&dst.GetBuffer(), dst.Offset(), dst.Bytes(),
276 210032 Store(data, dst.Bytes(), 4)});
277 }
278 210032 }
279
280 ✗ void CommandEncoder::BuildAccel(Accel& dst, const AccelInput& input, BufferRange scratch,
281 bool update) {
282 ✗ Require(dst, "BuildAccel");
283 ✗ Require(scratch.GetBuffer(), "BuildAccel");
284 ✗ ForEachBuffer(input, [&](BufferRange range) {
285 ✗ Require(range.GetBuffer(), "BuildAccel");
286
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (!Has(range.GetBuffer().Usage(), BufferUsage::AccelBuildInput)) {
287 ✗ throw Error("BuildAccel of \"{}\" reads buffer \"{}\", which lacks "
288 "BufferUsage::AccelBuildInput",
289
0/1
✗ Branch 2 not taken.
✗ dst.Label(), range.GetBuffer().Label());
290 }
291 ✗ });
292
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (GetLevel(input) != dst.Level()) {
293 ✗ const bool top = dst.Level() == AccelLevel::Top;
294 ✗ throw Error("BuildAccel of {} \"{}\" of {}", top ? "TLAS" : "BLAS", dst.Label(),
295
0/5
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ top ? "geometry" : "instances");
296 }
297
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (update && !Refittable(input)) {
298
0/1
✗ Branch 2 not taken.
✗ throw Error("BuildAccel updating BLAS \"{}\", which wasn't made refittable", dst.Label());
299 }
300
301 ✗ const AccelSizes sizes = m_recording.m_queue->GetDevice().AccelBuildSizes(input);
302
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ const uint64_t needed = update ? sizes.updateScratch : sizes.scratch;
303
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (!Has(scratch.GetBuffer().Usage(), BufferUsage::AccelStorage) || scratch.Bytes() < needed) {
304 ✗ throw Error(
305 "BuildAccel of \"{}\" with {} bytes of scratch in buffer \"{}\"; it takes {} of "
306 "BufferUsage::AccelStorage",
307
0/1
✗ Branch 2 not taken.
✗ dst.Label(), scratch.Bytes(), scratch.GetBuffer().Label(), needed);
308 }
309
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (dst.Storage().Bytes() < sizes.storage) {
310
0/1
✗ Branch 1 not taken.
✗ throw Error("BuildAccel of \"{}\", of {} bytes, of an input that takes {}", dst.Label(),
311
0/1
✗ Branch 2 not taken.
✗ dst.Storage().Bytes(), sizes.storage);
312 }
313
314 ✗ Record(BuildAccelCommand{&dst, input, &scratch.GetBuffer(), scratch.Offset(), update});
315 ✗ }
316
317 232582 void CommandEncoder::Dispatch(Kernel& kernel, const void* params, size_t bytes, Size3 groups,
318 std::optional<BufferRange> counts) {
319 232582 Require(kernel.GetProgram(), "Dispatch");
320
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 232582 times.
232582 if (bytes != kernel.ParamBytes()) {
321
0/1
✗ Branch 1 not taken.
✗ throw Error("Dispatch of kernel {} with {} bytes of parameters; it takes {}", kernel.Name(),
322
0/2
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ bytes, kernel.ParamBytes());
323 }
324
2/2
✓ Branch 0 taken 77897 times.
✓ Branch 1 taken 154685 times.
232582 if (counts) {
325 77897 Require(counts->GetBuffer(), "Dispatch");
326 77897 RequireCounts(kernel, *counts, groups);
327 } else {
328 154685 groups = Grid(kernel, groups);
329 }
330
331
3/6
✓ Branch 0 taken 232582 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 232582 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 232582 times.
✗ Branch 5 not taken.
232582 if (groups.x > 0 && groups.y > 0 && groups.z > 0) {
332
4/4
✓ Branch 0 taken 77897 times.
✓ Branch 1 taken 154685 times.
✓ Branch 2 taken 77897 times.
✓ Branch 3 taken 154685 times.
388376 Record(DispatchCommand{.kernel = &kernel,
333 .groups = groups,
334 232582 .data = Store(params, bytes, 8),
335 .paramBytes = uint32_t(bytes),
336
2/2
✓ Branch 0 taken 77897 times.
✓ Branch 1 taken 154685 times.
232582 .counts = counts ? &counts->GetBuffer() : nullptr,
337
2/2
✓ Branch 0 taken 77897 times.
✓ Branch 1 taken 154685 times.
232582 .countsOffset = counts ? counts->Offset() : 0});
338 }
339 232582 }
340
341 7028 void CommandEncoder::Concurrent(bool concurrent) {
342 7028 m_concurrent = concurrent;
343 7028 m_barrier = true;
344 7028 }
345
346 188585 void CommandEncoder::Barrier() {
347 188585 m_barrier = true;
348 188585 }
349
350 49186 void CommandEncoder::BeginZone(ZoneId zone) {
351 49186 const auto index = uint32_t(m_recording.m_zones.size());
352 49186 m_recording.m_zones.push_back(zone);
353 49186 m_recording.m_commands.push_back(ZoneCommand{index, true});
354 49186 m_open.push_back(index);
355 49186 }
356
357 49186 void CommandEncoder::EndZone() {
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49186 times.
49186 if (m_open.empty()) {
359
0/2
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ throw Error("EndZone with no zone open");
360 }
361 49186 m_recording.m_commands.push_back(ZoneCommand{m_open.back(), false});
362 49186 m_open.pop_back();
363 49186 }
364
365 146031 CommandBuffer CommandEncoder::Finish(const FinishDesc& desc) {
366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 146031 times.
146031 if (!m_open.empty()) {
367 ✗ throw Error("Finish with zone \"{}\" still open",
368
0/2
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ m_recording.m_zones[m_open.back()].Name());
369 }
370 146031 m_concurrent = false;
371 146031 m_barrier = false;
372
373 292062 CommandBuffer finished = std::exchange(m_recording, CommandBuffer(*m_recording.m_queue, m_own));
374
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 146029 times.
146031 if (desc.reusable) {
375 2 finished.m_reusable = true;
376
1/1
✓ Branch 1 taken 2 times.
2 finished.Close();
377
1/1
✓ Branch 1 taken 2 times.
2 finished.HoldResources();
378 }
379 146031 return finished;
380 ✗ }
381
382 44741 ZoneScope::~ZoneScope() {
383 44741 try {
384
1/1
✓ Branch 1 taken 44741 times.
44741 m_encoder.EndZone();
385
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } catch (const Error& error) {
386 ✗ Log(LogLevel::Error, "{}", error.what());
387 ✗ }
388 44741 }
389
390 }
391