scene/tables/pack.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | #include "chrono_batch_render/scene/tables/pack.h" | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | |||
| 6 | #include "chrono_batch_render/device/commands.h" | ||
| 7 | #include "chrono_batch_render/device/device.h" | ||
| 8 | #include "chrono_batch_render/device/queue.h" | ||
| 9 | #include "chrono_batch_render/scene/kernels.h" | ||
| 10 | #include "chrono_batch_render/scene/tables/kernels/pack.h" | ||
| 11 | #include "chrono_batch_render/util/profiler.h" | ||
| 12 | |||
| 13 | namespace chrono::batch_render { | ||
| 14 | |||
| 15 | 789 | void PackPlan::Clear() { | |
| 16 | 789 | m_copies.clear(); | |
| 17 | 789 | m_literals.clear(); | |
| 18 | 789 | m_columns.clear(); | |
| 19 | 789 | m_count = 0; | |
| 20 | 789 | } | |
| 21 | |||
| 22 | 1493 | void PackPlan::Copy(ColumnRef column, uint32_t row, uint32_t destination) { | |
| 23 | 1493 | m_copies.push_back({column, row, destination}); | |
| 24 | 1493 | if (!Reads(column.column)) { | |
| 25 | 1121 | m_columns.push_back(column); | |
| 26 | } | ||
| 27 | 1493 | } | |
| 28 | |||
| 29 | 3381 | uint32_t PackPlan::Literal(uint32_t destination, uint32_t value) { | |
| 30 | 3381 | m_literals.push_back({destination, value}); | |
| 31 | 3381 | return uint32_t(m_literals.size() - 1); | |
| 32 | } | ||
| 33 | |||
| 34 | 50 | void PackPlan::SetLiteral(uint32_t literal, uint32_t value) { | |
| 35 | 50 | m_literals[literal].value = value; | |
| 36 | 50 | m_literals[literal].late = true; | |
| 37 | 50 | } | |
| 38 | |||
| 39 | 1516 | bool PackPlan::Reads(const ColumnInfo* column) const { | |
| 40 | 1516 | return std::ranges::find(m_columns, column, &ColumnRef::column) != m_columns.end(); | |
| 41 | } | ||
| 42 | |||
| 43 | 186 | bool PackPlan::Stale(const ColumnStore& store, uint64_t since) const { | |
| 44 | 186 | return std::ranges::any_of(m_columns, | |
| 45 | 473 | [&](ColumnRef column) { return store.LastWrite(column) > since; }); | |
| 46 | } | ||
| 47 | |||
| 48 | 311 | uint32_t PackPlan::Twice(uint32_t words) const { | |
| 49 | 311 | std::vector<uint8_t> written(words, 0); | |
| 50 | 311 | uint32_t twice = kNoPrim; | |
| 51 | 6066 | const auto write = [&](uint32_t word) { | |
| 52 | 5755 | if (word < written.size() && written[word]++ != 0 && twice == kNoPrim) { | |
| 53 | ✗ | twice = word; | |
| 54 | } | ||
| 55 | 6066 | }; | |
| 56 | 1703 | for (const Cell& copy : m_copies) { | |
| 57 | 1392 | const uint32_t cells = ElementBytes(copy.column.column->type) / sizeof(uint32_t); | |
| 58 | 3766 | for (uint32_t word = 0; word < cells; ++word) { | |
| 59 | 2374 | write(copy.destination + word); | |
| 60 | } | ||
| 61 | } | ||
| 62 | 3692 | for (const Word& literal : m_literals) { | |
| 63 | 3381 | write(literal.destination); | |
| 64 | } | ||
| 65 | 311 | return twice; | |
| 66 | 311 | } | |
| 67 | |||
| 68 | 828 | void PackPlan::Build(ColumnStore& store, bool zeroed) { | |
| 69 | 828 | std::vector<PackEntry> entries; | |
| 70 | 828 | entries.reserve(m_copies.size() + m_literals.size()); | |
| 71 | 2919 | for (const Cell& copy : m_copies) { | |
| 72 | 2091 | const ColumnTable& table = store.Schema(copy.column.schema); | |
| 73 | 4182 | entries.push_back({.pages = table.Pages(copy.column.index), | |
| 74 | 2091 | .row = copy.row, | |
| 75 | 2091 | .words = table.CellBytes(copy.column.index) / uint32_t(sizeof(uint32_t)), | |
| 76 | 2091 | .destination = copy.destination}); | |
| 77 | } | ||
| 78 | 5583 | for (const Word& literal : m_literals) { | |
| 79 | 4755 | if (!zeroed || literal.late || literal.value != 0) { | |
| 80 | 1826 | entries.push_back( | |
| 81 | 1826 | {.words = 1, .destination = literal.destination, .value = literal.value}); | |
| 82 | } | ||
| 83 | } | ||
| 84 | 828 | m_count = uint32_t(entries.size()); | |
| 85 | 828 | if (entries.empty()) { | |
| 86 | 715 | return; | |
| 87 | } | ||
| 88 | 113 | device::Device& device = store.GetDevice(); | |
| 89 | 113 | const uint64_t bytes = entries.size() * sizeof(PackEntry); | |
| 90 | 113 | if (!m_entries || m_entries->Bytes() < bytes) { | |
| 91 | 80 | m_entries = device.CreateBuffer({.bytes = bytes, .label = m_label + " pack entries"}); | |
| 92 | } | ||
| 93 | 113 | device.GetQueue().Write(m_entries->Slice(0, bytes), entries.data()); | |
| 94 | 898 | } | |
| 95 | |||
| 96 | 854 | void PackPlan::Pack(ColumnStore& store, uint64_t words) { | |
| 97 | 854 | if (m_count == 0) { | |
| 98 | 715 | return; | |
| 99 | } | ||
| 100 | 139 | device::Device& device = store.GetDevice(); | |
| 101 | 139 | if (!m_program) { | |
| 102 | 60 | m_program = | |
| 103 | 180 | device.CreateProgram({.modules = {"chrono_batch_render.scene.tables.kernels.pack"}, | |
| 104 | .library = &kSceneKernels, | ||
| 105 | .entries = {"PackWords"}, | ||
| 106 | 60 | .label = m_label + " pack"}); | |
| 107 | } | ||
| 108 | 139 | PackParams params{}; | |
| 109 | 139 | params.entries.address = m_entries->Address(); | |
| 110 | 139 | params.words.address = words; | |
| 111 | 139 | params.count = m_count; | |
| 112 | 139 | static const profiler::ZoneId zone = profiler::ZoneId::Named("Tables/Pack"); | |
| 113 | 139 | device::Queue& queue = device.GetQueue(); | |
| 114 | 139 | device::CommandEncoder encoder = queue.CreateEncoder(); | |
| 115 | 139 | { | |
| 116 | 139 | const device::ZoneScope scope(encoder, zone); | |
| 117 | 139 | encoder.Dispatch(m_program->Entry("PackWords"), params, | |
| 118 | 139 | {.x = device::GroupCount(params.count, kPackGroup)}); | |
| 119 | 139 | } | |
| 120 | 139 | queue.Submit(encoder.Finish()); | |
| 121 | 259 | } | |
| 122 | |||
| 123 | } | ||
| 124 |