chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
104 / 114
91.2%
Branches:
124 / 153
81.0%
Functions:
9 / 10
90.0%

scene/tables/bounds.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/scene/tables/bounds.h"
3
4 #include <algorithm>
5 #include <bit>
6 #include <cmath>
7 #include <limits>
8
9 #include "chrono_batch_render/device/commands.h"
10 #include "chrono_batch_render/device/queue.h"
11 #include "chrono_batch_render/scene/kernels.h"
12 #include "chrono_batch_render/scene/records/render_tables.h"
13 #include "chrono_batch_render/scene/schema/columns.h"
14 #include "chrono_batch_render/scene/tables/kernels/bounds.h"
15 #include "chrono_batch_render/stage/publish/change_set.h"
16 #include "chrono_batch_render/util/error.h"
17 #include "chrono_batch_render/util/profiler.h"
18
19 namespace chrono::batch_render {
20
21 namespace {
22
23 constexpr ColumnRef kInputs[] = {kPointBasedPoints,
24 kSphereRadius,
25 kCubeSize,
26 kPlaneWidth,
27 kPlaneLength,
28 kPlaneAxis,
29 kCylinderRadius,
30 kCylinderHeight,
31 kCylinderAxis,
32 kConeRadius,
33 kConeHeight,
34 kConeAxis,
35 kCapsuleRadius,
36 kCapsuleHeight,
37 kCapsuleAxis,
38 kPointInstancerPrototypes,
39 kPointInstancerProtoIndices,
40 kPointInstancerPositions,
41 kPointInstancerOrientations,
42 kPointInstancerScales,
43 kPointInstancerIds,
44 kPointInstancerInvisibleIds,
45 kPrototypeAPIPrototype};
46
47 1470 uint32_t Ordered(float value) {
48
2/2
✓ Branch 0 taken 735 times.
✓ Branch 1 taken 735 times.
1470 const uint32_t bits = std::bit_cast<uint32_t>(value);
49
2/2
✓ Branch 0 taken 735 times.
✓ Branch 1 taken 735 times.
1470 return (bits & 0x80000000u) != 0 ? ~bits : bits | 0x80000000u;
50 }
51
52 }
53
54 2589 std::span<const ColumnRef> BoundsTable::Inputs() const {
55 2589 return kInputs;
56 }
57
58 462 void BoundsTable::Relayout() {
59
2/2
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 31 times.
462 const Prims& prims = m_structure.GetPrims();
60
2/2
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 31 times.
462 device::Device& device = m_structure.GetColumnStore().GetDevice();
61
2/2
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 31 times.
462 const uint32_t worlds = prims.WorldCount();
62
2/2
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 31 times.
893 std::vector<uint32_t> origins(std::max(worlds, 1u), kNoRow);
63
2/2
✓ Branch 0 taken 11268 times.
✓ Branch 1 taken 462 times.
11730 for (uint32_t prim = 0; prim < prims.Size(); ++prim) {
64
7/7
✓ Branch 1 taken 11268 times.
✓ Branch 3 taken 10457 times.
✓ Branch 4 taken 811 times.
✓ Branch 6 taken 10457 times.
✓ Branch 9 taken 10457 times.
✓ Branch 11 taken 57 times.
✓ Branch 12 taken 10400 times.
11268 if (prims.Alive(prim) && IsA(prims.Record(prim).schema, SchemaId::World)) {
65
2/2
✓ Branch 1 taken 57 times.
✓ Branch 4 taken 57 times.
57 origins[prims.Record(prim).world] = prims.Row(prim, SchemaId::Xformable);
66 }
67 }
68
1/1
✓ Branch 1 taken 462 times.
462 m_origins =
69
3/3
✓ Branch 1 taken 462 times.
✓ Branch 3 taken 188 times.
✓ Branch 4 taken 274 times.
462 device.CreateBuffer({.label = "bounds world origins"}, std::span<const uint32_t>(origins));
70
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 184 times.
462 if (worlds + 1 != m_boxes.Rows()) {
71
1/1
✓ Branch 1 taken 278 times.
278 m_boxes.Allocate(device, worlds + 1);
72
1/1
✓ Branch 1 taken 278 times.
556 m_extents = device.CreateBuffer(
73
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 274 times.
278 {.bytes = uint64_t(m_boxes.Rows()) * 6 * sizeof(uint32_t), .label = "world extents"});
74 }
75
1/1
✓ Branch 1 taken 462 times.
462 m_primBounds.Reserve(device, prims.Size());
76 462 m_epoch = m_structure.Epoch();
77 2220 }
78
79 735 void BoundsTable::Run(const ChangeSet& changes, TableVersions&) {
80
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 730 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
735 CHRONO_BATCH_RENDER_ZONE("Bounds/Run");
81
2/2
✓ Branch 0 taken 461 times.
✓ Branch 1 taken 274 times.
735 ColumnStore& store = m_structure.GetColumnStore();
82
2/2
✓ Branch 0 taken 461 times.
✓ Branch 1 taken 274 times.
735 device::Device& device = store.GetDevice();
83
6/6
✓ Branch 0 taken 461 times.
✓ Branch 1 taken 274 times.
✓ Branch 2 taken 284 times.
✓ Branch 3 taken 177 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 273 times.
735 if (changes.resync || changes.structure || m_epoch != m_structure.Epoch()) {
84
1/1
✓ Branch 1 taken 462 times.
462 Relayout();
85 }
86 735 BoundsParams params{};
87
1/1
✓ Branch 1 taken 735 times.
735 params.scene.address = store.DeviceData();
88
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 params.origins.address = m_origins->Address();
89 735 params.extents.address = m_extents->Address();
90
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 params.boxes.address = m_boxes.Address();
91 735 params.transforms = m_tables.transforms;
92 735 params.imageables = m_tables.imageables;
93 735 params.meshes = m_tables.meshes;
94 735 params.points = m_tables.points;
95 735 params.curves = m_tables.curves;
96
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 params.primBounds.address = m_primBounds.Address();
97
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 params.primCount = m_structure.GetPrims().Size();
98
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 params.slotCount = m_boxes.Rows();
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 735 times.
735 const uint64_t instancerBytes = std::max<uint64_t>(params.primCount, 1) * 6 * sizeof(uint32_t);
100
4/4
✓ Branch 0 taken 461 times.
✓ Branch 1 taken 274 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 443 times.
735 if (!m_instancerExtents || m_instancerExtents->Bytes() < instancerBytes) {
101
1/1
✓ Branch 1 taken 292 times.
584 m_instancerExtents = device.CreateBuffer(
102
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 274 times.
292 {.bytes = std::bit_ceil(instancerBytes), .label = "instancer extents"});
103 }
104
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 params.instancerExtents.address = m_instancerExtents->Address();
105 735 const bool slots = m_tables.instances.address != 0;
106
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 if (slots) {
107 735 params.instances = m_tables.instances;
108 735 params.instanceSlots = uint32_t(m_instances.InstancePrims().size());
109 735 params.tlasCount = uint32_t(m_instances.InstanceCounts().size());
110 }
111
112
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 const uint64_t half = uint64_t(m_boxes.Rows()) * 3 * sizeof(uint32_t);
113
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 730 times.
735 device::Queue& queue = device.GetQueue();
114
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 730 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
735 static const profiler::ZoneId zone = profiler::ZoneId::Named("Bounds/Compute");
115
1/1
✓ Branch 1 taken 735 times.
735 device::CommandEncoder encoder = queue.CreateEncoder();
116 735 {
117
1/1
✓ Branch 1 taken 735 times.
735 const device::ZoneScope scope(encoder, zone);
118
2/2
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
735 encoder.Fill(m_extents->Slice(0, half), Ordered(std::numeric_limits<float>::infinity()));
119
2/2
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
735 encoder.Fill(m_extents->Slice(half), Ordered(-std::numeric_limits<float>::infinity()));
120
3/3
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
✓ Branch 7 taken 735 times.
735 encoder.Dispatch(Kernels().Entry("PrimBounds"), params,
121
1/1
✓ Branch 1 taken 735 times.
735 {.x = device::GroupCount(params.primCount, kBoundsGroup)});
122
2/4
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 735 times.
✗ Branch 3 not taken.
735 if (slots && params.instanceSlots > 0) {
123 735 const uint64_t lowers = uint64_t(params.primCount) * 3 * sizeof(uint32_t);
124
2/2
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
735 encoder.Fill(m_instancerExtents->Slice(0, lowers),
125 Ordered(std::numeric_limits<float>::infinity()));
126
2/2
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
735 encoder.Fill(m_instancerExtents->Slice(lowers, lowers),
127 Ordered(-std::numeric_limits<float>::infinity()));
128
1/1
✓ Branch 1 taken 735 times.
735 encoder.Barrier();
129
3/3
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
✓ Branch 7 taken 735 times.
735 encoder.Dispatch(Kernels().Entry("SlotBounds"), params,
130
1/1
✓ Branch 1 taken 735 times.
735 {.x = device::GroupCount(params.instanceSlots, kBoundsGroup)});
131
1/1
✓ Branch 1 taken 735 times.
735 encoder.Barrier();
132
3/3
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
✓ Branch 7 taken 735 times.
1470 encoder.Dispatch(Kernels().Entry("InstancerBounds"), params,
133
1/1
✓ Branch 1 taken 735 times.
735 {.x = device::GroupCount(params.primCount, kBoundsGroup)});
134 }
135
1/1
✓ Branch 1 taken 735 times.
735 encoder.Barrier();
136
3/3
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
✓ Branch 7 taken 735 times.
735 encoder.Dispatch(Kernels().Entry("FinishBoxes"), params,
137
1/1
✓ Branch 1 taken 735 times.
735 {.x = device::GroupCount(params.slotCount, kBoundsGroup)});
138 735 }
139
2/2
✓ Branch 1 taken 735 times.
✓ Branch 4 taken 735 times.
735 queue.Submit(encoder.Finish());
140 1611 }
141
142 100 device::Download BoundsTable::ReadWorldsAsync() const {
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (!m_boxes.Buffer()) {
144 ✗ return {};
145 }
146
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 return m_structure.GetColumnStore().GetDevice().GetQueue().ReadAsync(
147
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
200 m_boxes.Buffer()->Slice(0, uint64_t(m_boxes.Rows()) * sizeof(BvhBox)));
148 }
149
150 ✗ device::Download BoundsTable::ReadWorldAsync(uint32_t world) const {
151
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (!m_boxes.Buffer()) {
152 ✗ return {};
153 }
154
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ const uint32_t slot = WorldSlot(world);
155
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (slot >= m_boxes.Rows()) {
156
0/1
✗ Branch 2 not taken.
✗ throw Error("The scene has no world {}", world);
157 }
158 ✗ return m_structure.GetColumnStore().GetDevice().GetQueue().ReadAsync(
159 ✗ m_boxes.Buffer()->Slice(uint64_t(slot) * sizeof(BvhBox), sizeof(BvhBox)));
160 }
161
162 114 std::optional<BvhBox> BoundsTable::World(uint32_t world) const {
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 if (!m_boxes.Buffer()) {
164 ✗ return std::nullopt;
165 }
166
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 110 times.
114 const uint32_t slot = WorldSlot(world);
167
3/4
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 113 times.
228 if (slot >= m_boxes.Rows()) {
168
1/1
✓ Branch 2 taken 1 time.
1 throw Error("The scene has no world {}", world);
169 }
170 113 BvhBox box{};
171 113 m_structure.GetColumnStore().GetDevice().GetQueue().Read(
172 113 m_boxes.Buffer()->Slice(uint64_t(slot) * sizeof(BvhBox), sizeof(BvhBox)), &box);
173
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 112 times.
113 if (box.lower[0] > box.upper[0]) {
174 1 return std::nullopt;
175 }
176 112 return box;
177 }
178
179 735 void BoundsTable::Describe(RenderTables& tables) const {
180
1/2
✓ Branch 0 taken 735 times.
✗ Branch 1 not taken.
735 tables.primBounds.address = m_primBounds.Address();
181 735 }
182
183 353 void BoundsTable::Prepare() {
184 353 Kernels();
185 353 }
186
187 3293 device::Program& BoundsTable::Kernels() {
188
2/2
✓ Branch 0 taken 353 times.
✓ Branch 1 taken 2940 times.
3293 if (!m_program) {
189
2/2
✓ Branch 2 taken 353 times.
✓ Branch 5 taken 353 times.
1059 m_program = m_structure.GetColumnStore().GetDevice().CreateProgram(
190 {.modules = {"chrono_batch_render.scene.tables.kernels.bounds"},
191 .library = &kSceneKernels,
192 .entries = {"PrimBounds", "SlotBounds", "InstancerBounds", "FinishBoxes"},
193
2/3
✓ Branch 1 taken 353 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 353 times.
706 .label = "bounds"});
194 }
195 3293 return *m_program;
196 706 }
197
198 }
199