GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
73 / 74
98.6%
Branches:
38 / 62
61.3%
Functions:
6 / 6
100.0%

render/instances.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file instances.cpp
3 /// @brief Keeping instance rows dense as prims come and go, and uploading the rows that changed.
4 #include "ernie/render/instances.h"
5
6 #include "ernie/util/profiler.h"
7
8 #include <algorithm>
9 #include <limits>
10
11 namespace ernie {
12 namespace {
13
14 constexpr std::uint32_t kNoRow = std::numeric_limits<std::uint32_t>::max();
15
16 } // namespace
17
18 15 InstanceTable::InstanceTable(DeviceContext& context, Arenas& arenas)
19
1/2
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 : context_(context), uploader_(context, context.Main()) {
20 60 const auto column = [&](std::string_view name, DType type, std::vector<std::int64_t> element) {
21
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
30 return std::make_unique<DeviceColumn>(arenas, name, type, std::move(element), 0);
22 15 };
23
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 nodes_ = column("instance nodes", DType::UInt32, {});
24
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 geometries_ = column("instance geometries", DType::UInt32, {});
25
3/6
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
15 shapes_ = column("instance shapes", DType::Float32, {3, 4});
26
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
15 colours_ = column("instance colours", DType::Float32, {3});
27 15 }
28
29 33 std::optional<std::uint32_t> InstanceTable::Row(PrimId prim) const {
30
3/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 24 times.
33 if (prim.slot >= rows_.size() || rows_[prim.slot] == kNoRow ||
31
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 !(prims_[rows_[prim.slot]] == prim)) {
32 24 return std::nullopt;
33 }
34 9 return rows_[prim.slot];
35 }
36
37 25 void InstanceTable::Set(std::uint32_t row, const PrimGeometry& placed) {
38 25 prims_[row] = placed.prim;
39 25 hostNodes_[row] = placed.prim.slot;
40 25 hostGeometries_[row] = placed.geometry;
41 25 hostShapes_[row] = ToAffineRows(placed.shape);
42 25 hostColours_[row] = placed.colour;
43 25 rows_[placed.prim.slot] = row;
44 25 dirty_.push_back(row);
45 25 }
46
47 1 void InstanceTable::Remove(PrimId prim) {
48 1 const std::optional<std::uint32_t> row = Row(prim);
49
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (!row) {
50 ✗ return;
51 }
52 // The last row moves into the gap.
53
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 const auto last = static_cast<std::uint32_t>(prims_.size() - 1);
54
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (*row != last) {
55 1 prims_[*row] = prims_[last];
56 1 hostNodes_[*row] = hostNodes_[last];
57 1 hostGeometries_[*row] = hostGeometries_[last];
58 1 hostShapes_[*row] = hostShapes_[last];
59 1 hostColours_[*row] = hostColours_[last];
60 1 rows_[prims_[*row].slot] = *row;
61 1 dirty_.push_back(*row);
62 }
63 1 rows_[prim.slot] = kNoRow;
64 1 prims_.pop_back();
65 1 hostNodes_.pop_back();
66 1 hostGeometries_.pop_back();
67 1 hostShapes_.pop_back();
68 1 hostColours_.pop_back();
69 }
70
71 27 void InstanceTable::Apply(const GeometryPool::Changes& changes) {
72 27 ERNIE_ZONE("Update instances");
73
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 27 times.
28 for (const PrimId prim : changes.removed) {
74
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 Remove(prim);
75 }
76
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 27 times.
52 for (const PrimGeometry& placed : changes.placed) {
77
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 4 times.
25 if (placed.prim.slot >= rows_.size()) {
78
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 16 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
26 rows_.resize(std::max<std::size_t>(placed.prim.slot + 1, 2 * rows_.size()), kNoRow);
79 }
80 25 const std::optional<std::uint32_t> row = Row(placed.prim);
81
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 24 times.
25 if (row) {
82
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 Set(*row, placed);
83 1 continue;
84 }
85
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 prims_.emplace_back();
86
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 hostNodes_.emplace_back();
87
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 hostGeometries_.emplace_back();
88
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 hostShapes_.emplace_back();
89
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 hostColours_.emplace_back();
90
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 Set(static_cast<std::uint32_t>(prims_.size() - 1), placed);
91 }
92 27 }
93
94 27 void InstanceTable::AddUploads(graph::Graph& graph) {
95 27 const std::size_t rows = prims_.size();
96
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 27 times.
135 for (DeviceColumn* column : {nodes_.get(), geometries_.get(), shapes_.get(), colours_.get()}) {
97 108 column->Resize(rows, context_.Main());
98 }
99 27 StageRows(uploader_, *nodes_, hostNodes_, dirty_);
100 27 StageRows(uploader_, *geometries_, hostGeometries_, dirty_);
101 27 StageRows(uploader_, *shapes_, hostShapes_, dirty_);
102 27 StageRows(uploader_, *colours_, hostColours_, dirty_);
103 27 dirty_.clear();
104 27 std::array columns{graph.Import(*nodes_), graph.Import(*geometries_), graph.Import(*shapes_),
105 27 graph.Import(*colours_)};
106 27 graph::AddUploadPass(graph, "Upload instances", uploader_, columns);
107 27 }
108
109 } // namespace ernie
110