chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
186 / 189
98.4%
Branches:
161 / 175
92.0%
Functions:
10 / 10, 6 excl
100.0%

bvh/kernels/bvh.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #pragma once
3
4 #include "chrono_batch_render/device/kernels/shared.h"
5
6 namespace chrono::batch_render {
7
8 static const uint kBvhVersion = 3;
9
10 static const uint kBvhWidth = 8;
11 static const uint kBvhHeaderBytes = 64;
12 static const uint kBvhNodeBytes = 80;
13 static const uint kBvhTriangleBytes = 48;
14 static const uint kBvhInstanceBytes = 64;
15 static const uint kBvhBoxBytes = 32;
16
17 static const uint kBvhLeafSize = 3;
18
19 static const uint kBvhTriangles = 0;
20 static const uint kBvhInstances = 1;
21 static const uint kBvhBoxes = 2;
22
23 static const uint kBvhIndexMask = 0xFFFFFF;
24 static const uint kInstanceFacingCullDisable = 1u;
25 static const uint kInstanceFlipFacing = 2u;
26
27 struct BvhHeader {
28 float lower[3];
29 uint primitives;
30 float upper[3];
31 uint version;
32 uint64_t nodes;
33 uint64_t leaves;
34 uint nodeCount;
35 uint leafCount;
36 uint kind;
37 uint padding;
38 };
39
40 CHRONO_BATCH_RENDER_CHECK_SIZE(BvhHeader, kBvhHeaderBytes);
41
42 struct BvhNode {
43 float origin[3];
44 uint exponents;
45 uint firstChild;
46 uint firstLeaf;
47 uint meta[2];
48 uint lower[3][2];
49 uint upper[3][2];
50 };
51
52 CHRONO_BATCH_RENDER_CHECK_SIZE(BvhNode, kBvhNodeBytes);
53
54 struct BvhTriangle {
55 float edgeC[3];
56 uint padding0;
57 float edgeB[3];
58 uint padding1;
59 float a[3];
60 uint index;
61 };
62
63 CHRONO_BATCH_RENDER_CHECK_SIZE(BvhTriangle, kBvhTriangleBytes);
64
65 struct BvhInstance {
66 uint64_t blas;
67 float toObject[12];
68 uint custom;
69 uint index;
70 };
71
72 CHRONO_BATCH_RENDER_CHECK_SIZE(BvhInstance, kBvhInstanceBytes);
73
74 struct BvhBoxRecord {
75 float lower[3];
76 uint index;
77 float upper[3];
78 uint padding;
79 };
80
81 CHRONO_BATCH_RENDER_CHECK_SIZE(BvhBoxRecord, kBvhBoxBytes);
82
83 struct BvhBox {
84 float lower[3];
85 float upper[3];
86 };
87
88 3238 CHRONO_BATCH_RENDER_SHARED uint64_t BvhLeavesOffset(uint capacity) {
89
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3225 times.
✓ Branch 2 taken 1299 times.
✓ Branch 3 taken 1939 times.
3251 return kBvhHeaderBytes + uint64_t(max(capacity, 1u)) * kBvhNodeBytes;
90 }
91
92 3300 CHRONO_BATCH_RENDER_SHARED uint BvhRecordWords(uint kind) {
93
4/4
<unknown function 88>:
✓ Branch 0 taken 1299 times.
✓ Branch 1 taken 1939 times.
<unknown function 92>:
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 18 times.
3300 return kind == kBvhInstances ? kBvhInstanceBytes / 16
94
4/4
<unknown function 88>:
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 1049 times.
<unknown function 92>:
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 7 times.
1343 : kind == kBvhBoxes ? kBvhBoxBytes / 16
95 : kBvhTriangleBytes / 16;
96 }
97
98 66353 CHRONO_BATCH_RENDER_SHARED uint BvhByte(uint words[2], uint slot) {
99
3/4
<unknown function 92>:
✓ Branch 0 taken 6619 times.
✓ Branch 1 taken 14933 times.
<unknown function 98>:
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
21554 return (words[slot >> 2] >> ((slot & 3) * 8)) & 0xFF;
100 }
101
102 15917 CHRONO_BATCH_RENDER_SHARED uint BvhInternalMeta(uint slot) {
103
7/7
<unknown function 102>:
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 29 times.
✓ Branch 7 taken 940 times.
<unknown function 92>:
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2643 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 12286 times.
15917 return 1u << 5 | (24 + slot);
104 }
105
106 5793 CHRONO_BATCH_RENDER_SHARED uint BvhLeafMeta(uint count, uint before) {
107 5793 return ((1u << count) - 1) << 5 | before;
108 }
109
110 14933 CHRONO_BATCH_RENDER_SHARED BvhBox BvhChildBox(BvhNode node, uint slot) {
111 14933 BvhBox box;
112
2/2
✓ Branch 0 taken 44799 times.
✓ Branch 1 taken 14933 times.
59732 for (uint axis = 0; axis < 3; ++axis) {
113 44799 const float scale = asfloat(((node.exponents >> (axis * 8)) & 0xFF) << 23);
114 44799 box.lower[axis] = node.origin[axis] + float(BvhByte(node.lower[axis], slot)) * scale;
115 44799 box.upper[axis] = node.origin[axis] + float(BvhByte(node.upper[axis], slot)) * scale;
116 }
117 14933 return box;
118 }
119
120 static const uint kInstanceCustomMask = 0xFFFFFF;
121
122 struct InstanceRecord {
123 float transform[12];
124 uint custom;
125 uint flags;
126 uint64_t blas;
127 };
128
129 CHRONO_BATCH_RENDER_CHECK_SIZE(InstanceRecord, 64);
130
131 struct BvhCorners {
132 float a[3];
133 float b[3];
134 float c[3];
135 };
136
137 CHRONO_BATCH_RENDER_CHECK_SIZE(BvhCorners, 36);
138
139 static const uint kBvhEmptySlot = 0xFFFFFFFF;
140 static const float kBvhFar = 3.402823466e+38f;
141
142 struct BvhSlots {
143 uint child[8];
144 };
145
146 47439 CHRONO_BATCH_RENDER_SHARED uint BvhWithByte(uint word, uint index, uint value) {
147 47439 const uint shift = index * 8;
148 6777 return (word & ~(0xFFu << shift)) | (value << shift);
149 }
150
151 17345 CHRONO_BATCH_RENDER_SHARED BvhBox BvhEmptyBox() {
152 17345 BvhBox box;
153
48/48
<unknown function 102>:
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 828 times.
✓ Branch 3 taken 276 times.
✓ Branch 4 taken 828 times.
✓ Branch 5 taken 276 times.
✓ Branch 6 taken 828 times.
✓ Branch 7 taken 276 times.
✓ Branch 8 taken 381 times.
✓ Branch 9 taken 127 times.
✓ Branch 10 taken 1143 times.
✓ Branch 11 taken 381 times.
✓ Branch 12 taken 1143 times.
✓ Branch 13 taken 381 times.
✓ Branch 14 taken 1143 times.
✓ Branch 15 taken 381 times.
✓ Branch 16 taken 16680 times.
✓ Branch 17 taken 5560 times.
✓ Branch 18 taken 25080 times.
✓ Branch 19 taken 8360 times.
✓ Branch 20 taken 25080 times.
✓ Branch 21 taken 8360 times.
✓ Branch 22 taken 25080 times.
✓ Branch 23 taken 8360 times.
✓ Branch 24 taken 276 times.
✓ Branch 25 taken 92 times.
✓ Branch 26 taken 276 times.
✓ Branch 27 taken 92 times.
✓ Branch 28 taken 381 times.
✓ Branch 29 taken 127 times.
✓ Branch 30 taken 381 times.
✓ Branch 31 taken 127 times.
✓ Branch 32 taken 16680 times.
✓ Branch 33 taken 5560 times.
✓ Branch 34 taken 16680 times.
✓ Branch 35 taken 5560 times.
✓ Branch 36 taken 6 times.
✓ Branch 37 taken 2 times.
✓ Branch 38 taken 3 times.
✓ Branch 39 taken 1 time.
✓ Branch 40 taken 33 times.
✓ Branch 41 taken 11 times.
<unknown function 151>:
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
<unknown function 153>:
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 time.
171869 for (uint axis = 0; axis < 3; ++axis) {
154 133236 box.lower[axis] = kBvhFar;
155 133236 box.upper[axis] = -kBvhFar;
156 }
157 17360 return box;
158 }
159
160 796442 CHRONO_BATCH_RENDER_SHARED BvhBox BvhUnion(BvhBox a, BvhBox b) {
161 796442 BvhBox box;
162
2/2
✓ Branch 0 taken 2389326 times.
✓ Branch 1 taken 796442 times.
3185768 for (uint axis = 0; axis < 3; ++axis) {
163
2/2
✓ Branch 0 taken 493059 times.
✓ Branch 1 taken 1896267 times.
2389326 box.lower[axis] = min(a.lower[axis], b.lower[axis]);
164
2/2
✓ Branch 0 taken 493344 times.
✓ Branch 1 taken 1895982 times.
2882670 box.upper[axis] = max(a.upper[axis], b.upper[axis]);
165 }
166 796442 return box;
167 }
168
169 294693 CHRONO_BATCH_RENDER_SHARED float BvhArea(BvhBox box) {
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294693 times.
294693 const float x = max(box.upper[0] - box.lower[0], 0.0f);
171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294693 times.
294693 const float y = max(box.upper[1] - box.lower[1], 0.0f);
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 294693 times.
294693 const float z = max(box.upper[2] - box.lower[2], 0.0f);
173 294693 return 2 * (x * y + y * z + z * x);
174 }
175
176 67668 CHRONO_BATCH_RENDER_SHARED float BvhCenter(BvhBox box, uint axis) {
177 67668 return (box.lower[axis] + box.upper[axis]) * 0.5f;
178 }
179
180 46475 CHRONO_BATCH_RENDER_SHARED BvhBox BvhTriangleBox(BvhCorners corners) {
181 46475 BvhBox box;
182
2/2
✓ Branch 0 taken 139425 times.
✓ Branch 1 taken 46475 times.
185900 for (uint axis = 0; axis < 3; ++axis) {
183
4/4
✓ Branch 0 taken 49964 times.
✓ Branch 1 taken 89461 times.
✓ Branch 2 taken 63344 times.
✓ Branch 3 taken 76081 times.
189389 box.lower[axis] = min(corners.a[axis], min(corners.b[axis], corners.c[axis]));
184
4/4
✓ Branch 0 taken 49353 times.
✓ Branch 1 taken 90072 times.
✓ Branch 2 taken 72361 times.
✓ Branch 3 taken 67064 times.
261139 box.upper[axis] = max(corners.a[axis], max(corners.b[axis], corners.c[axis]));
185 }
186 46475 return box;
187 }
188
189 12942 CHRONO_BATCH_RENDER_SHARED BvhTriangle BvhMakeTriangle(BvhCorners corners, uint index) {
190 12942 BvhTriangle triangle;
191
2/2
✓ Branch 0 taken 38826 times.
✓ Branch 1 taken 12942 times.
51768 for (uint axis = 0; axis < 3; ++axis) {
192 38826 triangle.edgeC[axis] = corners.c[axis] - corners.a[axis];
193 38826 triangle.edgeB[axis] = corners.b[axis] - corners.a[axis];
194 38826 triangle.a[axis] = corners.a[axis];
195 }
196 12942 triangle.padding0 = 0;
197 12942 triangle.padding1 = 0;
198 12942 triangle.index = index;
199 12942 return triangle;
200 }
201
202 300 CHRONO_BATCH_RENDER_SHARED BvhBoxRecord BvhMakeBox(BvhBox box, uint index) {
203 300 BvhBoxRecord record;
204
2/2
✓ Branch 0 taken 900 times.
✓ Branch 1 taken 300 times.
1200 for (uint axis = 0; axis < 3; ++axis) {
205 900 record.lower[axis] = box.lower[axis];
206 900 record.upper[axis] = box.upper[axis];
207 }
208 300 record.index = index;
209 300 record.padding = 0;
210 300 return record;
211 }
212
213 210 CHRONO_BATCH_RENDER_SHARED BvhInstance BvhMakeInstance(InstanceRecord instance, uint index) {
214 210 BvhInstance record;
215 210 record.blas = instance.blas;
216 210 record.custom = instance.custom;
217 210 record.index = index | (instance.flags >> 24 << 24);
218 210 float m[12];
219
2/2
✓ Branch 0 taken 2520 times.
✓ Branch 1 taken 210 times.
2730 for (uint i = 0; i < 12; ++i) {
220 2520 m[i] = instance.transform[i];
221 }
222 210 float inverse[9];
223 210 inverse[0] = m[5] * m[10] - m[6] * m[9];
224 210 inverse[1] = m[2] * m[9] - m[1] * m[10];
225 210 inverse[2] = m[1] * m[6] - m[2] * m[5];
226 210 inverse[3] = m[6] * m[8] - m[4] * m[10];
227 210 inverse[4] = m[0] * m[10] - m[2] * m[8];
228 210 inverse[5] = m[2] * m[4] - m[0] * m[6];
229 210 inverse[6] = m[4] * m[9] - m[5] * m[8];
230 210 inverse[7] = m[1] * m[8] - m[0] * m[9];
231 210 inverse[8] = m[0] * m[5] - m[1] * m[4];
232 210 const float determinant = m[0] * inverse[0] + m[1] * inverse[3] + m[2] * inverse[6];
233
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 const float scale = determinant != 0 ? 1.0f / determinant : 0.0f;
234
2/2
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 210 times.
840 for (uint row = 0; row < 3; ++row) {
235 float moved = 0;
236
2/2
✓ Branch 0 taken 1890 times.
✓ Branch 1 taken 630 times.
2520 for (uint column = 0; column < 3; ++column) {
237 1890 const float value = inverse[row * 3 + column] * scale;
238 1890 record.toObject[row * 4 + column] = value;
239 1890 moved += value * m[column * 4 + 3];
240 }
241 630 record.toObject[row * 4 + 3] = -moved;
242 }
243 210 return record;
244 }
245
246 550 CHRONO_BATCH_RENDER_SHARED BvhBox BvhInstanceBox(InstanceRecord instance, BvhBox bounds) {
247 550 BvhBox box;
248
2/2
✓ Branch 0 taken 1650 times.
✓ Branch 1 taken 550 times.
2200 for (uint row = 0; row < 3; ++row) {
249 1650 float lower = instance.transform[row * 4 + 3];
250 1650 float upper = lower;
251
2/2
✓ Branch 0 taken 4950 times.
✓ Branch 1 taken 1650 times.
6600 for (uint column = 0; column < 3; ++column) {
252 4950 const float m = instance.transform[row * 4 + column];
253 4950 const float a = m * bounds.lower[column];
254 4950 const float b = m * bounds.upper[column];
255
2/2
✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 3868 times.
4950 lower += min(a, b);
256
2/2
✓ Branch 0 taken 1625 times.
✓ Branch 1 taken 3325 times.
6575 upper += max(a, b);
257 }
258 1650 box.lower[row] = lower;
259 1650 box.upper[row] = upper;
260 }
261 550 return box;
262 }
263
264 #ifdef __SLANG__
265 BvhBox BvhInstanceWorldBox(InstanceRecord instance) {
266 if (instance.blas == 0) {
267 return BvhEmptyBox();
268 }
269 BvhHeader* blas = (BvhHeader*)instance.blas;
270 BvhBox bounds;
271 for (uint axis = 0; axis < 3; ++axis) {
272 bounds.lower[axis] = blas.lower[axis];
273 bounds.upper[axis] = blas.upper[axis];
274 }
275 return BvhInstanceBox(instance, bounds);
276 }
277 #endif
278
279 2994 CHRONO_BATCH_RENDER_SHARED int BvhGridExponent(float extent) {
280
2/2
✓ Branch 0 taken 1950 times.
✓ Branch 1 taken 1044 times.
2994 if (!(extent > 0)) {
281 return -126;
282 }
283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1950 times.
3900 return int(clamp(ceil(log2(extent * (1.0f / 255.0f))), -126.0f, 126.0f));
284 }
285
286 998 CHRONO_BATCH_RENDER_SHARED BvhSlots BvhAssignSlots(BvhBox box, BvhBox children[8], uint count) {
287 998 float cost[8][8];
288
2/2
✓ Branch 0 taken 7984 times.
✓ Branch 1 taken 998 times.
8982 for (uint i = 0; i < 8; ++i) {
289
2/2
✓ Branch 0 taken 63872 times.
✓ Branch 1 taken 7984 times.
71856 for (uint slot = 0; slot < 8; ++slot) {
290
2/2
✓ Branch 0 taken 9656 times.
✓ Branch 1 taken 54216 times.
63872 if (i >= count) {
291 9656 cost[slot][i] = kBvhFar;
292 9656 continue;
293 }
294 54216 const float dx = BvhCenter(children[i], 0) - BvhCenter(box, 0);
295 54216 const float dy = BvhCenter(children[i], 1) - BvhCenter(box, 1);
296 54216 const float dz = BvhCenter(children[i], 2) - BvhCenter(box, 2);
297
4/4
✓ Branch 0 taken 27108 times.
✓ Branch 1 taken 27108 times.
✓ Branch 2 taken 27108 times.
✓ Branch 3 taken 27108 times.
108432 cost[slot][i] = ((slot & 4) != 0 ? -dx : dx) + ((slot & 2) != 0 ? -dy : dy) +
298
2/2
✓ Branch 0 taken 27108 times.
✓ Branch 1 taken 27108 times.
54216 ((slot & 1) != 0 ? -dz : dz);
299 }
300 }
301 BvhSlots slots;
302 bool assigned[8];
303
2/2
✓ Branch 0 taken 7984 times.
✓ Branch 1 taken 998 times.
8982 for (uint slot = 0; slot < 8; ++slot) {
304 7984 slots.child[slot] = kBvhEmptySlot;
305 7984 assigned[slot] = false;
306 }
307
2/2
✓ Branch 0 taken 7098 times.
✓ Branch 1 taken 677 times.
7775 for (uint round = 0; round < 8; ++round) {
308 float least = kBvhFar;
309 uint bestSlot = kBvhEmptySlot;
310 uint bestChild = 0;
311
2/2
✓ Branch 0 taken 56784 times.
✓ Branch 1 taken 7098 times.
63882 for (uint slot = 0; slot < 8; ++slot) {
312
2/2
✓ Branch 0 taken 413712 times.
✓ Branch 1 taken 56784 times.
470496 for (uint i = 0; i < count; ++i) {
313
6/6
✓ Branch 0 taken 238203 times.
✓ Branch 1 taken 175509 times.
✓ Branch 2 taken 165096 times.
✓ Branch 3 taken 73107 times.
✓ Branch 4 taken 12748 times.
✓ Branch 5 taken 152348 times.
413712 if (slots.child[slot] == kBvhEmptySlot && !assigned[i] && cost[slot][i] < least) {
314 12748 least = cost[slot][i];
315 12748 bestSlot = slot;
316 12748 bestChild = i;
317 }
318 }
319 }
320
2/2
✓ Branch 0 taken 6777 times.
✓ Branch 1 taken 321 times.
7098 if (bestSlot == kBvhEmptySlot) {
321 break;
322 }
323 6777 slots.child[bestSlot] = bestChild;
324 6777 assigned[bestChild] = true;
325 }
326
2/2
✓ Branch 0 taken 6777 times.
✓ Branch 1 taken 998 times.
7775 for (uint i = 0; i < count; ++i) {
327
2/4
✓ Branch 0 taken 6777 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6777 times.
6777 for (uint slot = 0; slot < 8 && !assigned[i]; ++slot) {
328
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (slots.child[slot] == kBvhEmptySlot) {
329 ✗ slots.child[slot] = i;
330 ✗ assigned[i] = true;
331 }
332 }
333 }
334 998 return slots;
335 }
336
337 998 CHRONO_BATCH_RENDER_SHARED BvhNode BvhQuantizeSlots(BvhBox box, BvhBox children[8], uint occupied) {
338 998 BvhNode node;
339 998 node.firstChild = 0;
340 998 node.firstLeaf = 0;
341 998 node.exponents = 0;
342 998 node.meta[0] = 0;
343 998 node.meta[1] = 0;
344
2/2
✓ Branch 0 taken 2994 times.
✓ Branch 1 taken 998 times.
3992 for (uint axis = 0; axis < 3; ++axis) {
345 2994 node.origin[axis] = box.lower[axis];
346 2994 const int exponent = BvhGridExponent(box.upper[axis] - box.lower[axis]);
347 2994 node.exponents |= uint(exponent + 127) << (axis * 8);
348 2994 const float inverse = asfloat(uint(127 - exponent) << 23);
349
2/2
✓ Branch 0 taken 5988 times.
✓ Branch 1 taken 2994 times.
8982 for (uint word = 0; word < 2; ++word) {
350 5988 node.lower[axis][word] = 0;
351 5988 node.upper[axis][word] = 0;
352 }
353
2/2
✓ Branch 0 taken 23952 times.
✓ Branch 1 taken 2994 times.
26946 for (uint slot = 0; slot < 8; ++slot) {
354
2/2
✓ Branch 0 taken 3621 times.
✓ Branch 1 taken 20331 times.
23952 if ((occupied >> slot & 1) == 0) {
355 3621 continue;
356 }
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20331 times.
20331 const float low = floor((children[slot].lower[axis] - box.lower[axis]) * inverse);
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20331 times.
20331 const float high = ceil((children[slot].upper[axis] - box.lower[axis]) * inverse);
359 40662 node.lower[axis][slot >> 2] =
360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20331 times.
20331 BvhWithByte(node.lower[axis][slot >> 2], slot & 3, uint(clamp(int(low), 0, 255)));
361 40662 node.upper[axis][slot >> 2] =
362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20331 times.
40662 BvhWithByte(node.upper[axis][slot >> 2], slot & 3, uint(clamp(int(high), 0, 255)));
363 }
364 }
365 998 return node;
366 }
367
368 998 CHRONO_BATCH_RENDER_SHARED BvhNode BvhQuantize(BvhBox box, BvhBox children[8], BvhSlots slots) {
369 998 BvhBox ordered[8];
370 998 uint occupied = 0;
371
2/2
✓ Branch 0 taken 7984 times.
✓ Branch 1 taken 998 times.
8982 for (uint slot = 0; slot < 8; ++slot) {
372
2/2
✓ Branch 0 taken 6777 times.
✓ Branch 1 taken 1207 times.
7984 if (slots.child[slot] != kBvhEmptySlot) {
373 6777 ordered[slot] = children[slots.child[slot]];
374 6777 occupied |= 1u << slot;
375 }
376 }
377 998 return BvhQuantizeSlots(box, ordered, occupied);
378 }
379
380 }
381