chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
47 / 47
100.0%
Branches:
25 / 27
92.6%
Functions:
6 / 6
100.0%

algorithms/scan.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/algorithms/scan.h"
3
4 #include <algorithm>
5 #include <vector>
6
7 #include "chrono_batch_render/algorithms/kernels.h"
8 #include "chrono_batch_render/algorithms/kernels/scan.h"
9 #include "chrono_batch_render/device/device.h"
10 #include "chrono_batch_render/device/slang/dispatch.h"
11 #include "chrono_batch_render/util/error.h"
12
13 namespace chrono::batch_render::algorithms {
14
15 using device::BufferRange;
16 using device::CommandEncoder;
17 using device::Device;
18 using device::GroupCount;
19 using device::RequireRange;
20
21 namespace {
22
23 1434 uint32_t RequireCapacity(uint32_t capacity) {
24
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1433 times.
1434 if (capacity > Scan::kMaxItems) {
25
1/1
✓ Branch 2 taken 1 time.
1 throw Error("Scan of {} items; it scans at most {}", capacity, Scan::kMaxItems);
26 }
27 1433 return capacity;
28 }
29
30 }
31
32 1434 Scan::Scan(Device& device, uint32_t capacity)
33 1434 : m_capacity(RequireCapacity(capacity)),
34
3/3
✓ Branch 2 taken 1433 times.
✓ Branch 5 taken 1433 times.
✓ Branch 9 taken 1433 times.
2866 m_program(device.CreateProgram({.modules = {"chrono_batch_render.algorithms.kernels.scan"},
35 .library = &kAlgorithmsKernels,
36 .entries = {"SumTiles", "ScanTiles"},
37
1/1
✓ Branch 1 taken 1433 times.
1433 .label = "scan"})),
38
1/1
✓ Branch 1 taken 1433 times.
1433 m_sumTiles(&m_program->Entry("SumTiles")), m_scanTiles(&m_program->Entry("ScanTiles")) {
39 1433 uint64_t words = 0;
40
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1433 times.
1455 for (uint32_t tiles = GroupCount(capacity, kScanTileItems); tiles > 1;
41 22 tiles = GroupCount(tiles, kScanTileItems)) {
42
1/1
✓ Branch 1 taken 22 times.
22 m_levelOffsets.push_back(words * 4);
43 22 words += tiles;
44 }
45
2/3
✓ Branch 1 taken 1433 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1433 times.
1433 m_sums = device.CreateBuffer({.bytes = std::max<uint64_t>(words, 1) * 4, .label = "scan sums"});
46
3/4
✓ Branch 1 taken 1433 times.
✓ Branch 4 taken 1433 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1433 times.
2866 m_unlimitedCount = device.CreateBuffer({.label = "scan unlimited count"}, std::vector{~0u});
47 8577 }
48
49 5807 void Scan::ExclusiveSum(CommandEncoder& encoder, BufferRange input, BufferRange output,
50 uint32_t count) const {
51 5807 Record(encoder, input, output, count, {m_unlimitedCount->Address()});
52 5804 }
53
54 7 void Scan::ExclusiveSum(CommandEncoder& encoder, BufferRange input, BufferRange output,
55 BufferRange count, uint32_t capacity) const {
56 7 Record(encoder, input, output, capacity,
57 7 RequireRange<uint32_t>(*m_program, "ExclusiveSum", count, 1));
58 5 }
59
60 5814 void Scan::Record(CommandEncoder& encoder, BufferRange input, BufferRange output, uint32_t count,
61 Ptr<uint32_t> liveCount) const {
62
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5812 times.
5814 if (count > m_capacity) {
63 2 throw Error("ExclusiveSum of {} items; the Scan was made for at most {}", count,
64
1/1
✓ Branch 2 taken 2 times.
2 m_capacity);
65 }
66 5812 const ScanParams params{
67 5812 .input = RequireRange<uint32_t>(*m_program, "ExclusiveSum", input, count),
68 5810 .output = RequireRange<uint32_t>(*m_program, "ExclusiveSum", output, count),
69 .deviceCount = liveCount,
70 5809 .count = count};
71
72
2/2
✓ Branch 0 taken 5807 times.
✓ Branch 1 taken 2 times.
5809 if (count > 0) {
73 5807 RecordLevel(encoder, params, 0);
74 }
75 5809 }
76
77 5941 void Scan::RecordLevel(CommandEncoder& encoder, ScanParams params, size_t level) const {
78
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 5807 times.
5941 const uint32_t tiles = GroupCount(params.count, kScanTileItems);
79
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 5807 times.
5941 if (tiles > 1) {
80 134 params.sums = {m_sums->Address() + m_levelOffsets[level]};
81 134 params.hasSums = 1;
82 134 encoder.Barrier();
83 134 encoder.Dispatch(*m_sumTiles, params, {.x = tiles});
84 134 RecordLevel(encoder,
85 {.input = params.sums,
86 .output = params.sums,
87 134 .deviceCount = {m_unlimitedCount->Address()},
88 .count = tiles},
89 level + 1);
90 }
91
92 5941 encoder.Barrier();
93 5941 encoder.Dispatch(*m_scanTiles, params, {.x = tiles});
94 5941 }
95
96 }
97