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 | 1434 | if (capacity > Scan::kMaxItems) { | |
| 25 | 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 | 2866 | m_program(device.CreateProgram({.modules = {"chrono_batch_render.algorithms.kernels.scan"}, | |
| 35 | .library = &kAlgorithmsKernels, | ||
| 36 | .entries = {"SumTiles", "ScanTiles"}, | ||
| 37 | 1433 | .label = "scan"})), | |
| 38 | 1433 | m_sumTiles(&m_program->Entry("SumTiles")), m_scanTiles(&m_program->Entry("ScanTiles")) { | |
| 39 | 1433 | uint64_t words = 0; | |
| 40 | 1455 | for (uint32_t tiles = GroupCount(capacity, kScanTileItems); tiles > 1; | |
| 41 | 22 | tiles = GroupCount(tiles, kScanTileItems)) { | |
| 42 | 22 | m_levelOffsets.push_back(words * 4); | |
| 43 | 22 | words += tiles; | |
| 44 | } | ||
| 45 | 1433 | m_sums = device.CreateBuffer({.bytes = std::max<uint64_t>(words, 1) * 4, .label = "scan sums"}); | |
| 46 | 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 | 5814 | if (count > m_capacity) { | |
| 63 | 2 | throw Error("ExclusiveSum of {} items; the Scan was made for at most {}", count, | |
| 64 | 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 | 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 | 5941 | const uint32_t tiles = GroupCount(params.count, kScanTileItems); | |
| 79 | 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 |