chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
317 / 320
99.1%
Branches:
283 / 318
89.0%
Functions:
19 / 19
100.0%

scene/tables/lights.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/scene/tables/lights.h"
3
4 #include <algorithm>
5 #include <cmath>
6 #include <cstring>
7 #include <iterator>
8
9 #include "chrono_batch_render/scene/kernels.h"
10 #include "chrono_batch_render/scene/records/render_tables.h"
11 #include "chrono_batch_render/scene/schema/columns.h"
12 #include "chrono_batch_render/scene/tables/kernels/instance_layout.h"
13 #include "chrono_batch_render/scene/tables/kernels/lights.h"
14 #include "chrono_batch_render/stage/publish/change_set.h"
15 #include "chrono_batch_render/util/profiler.h"
16
17 namespace chrono::batch_render {
18
19 namespace {
20
21 constexpr double kCmf[kSpectralRows][3] = {
22 {1.299000e-04, 3.917000e-06, 6.061000e-04}, {2.321000e-04, 6.965000e-06, 1.086000e-03},
23 {4.149000e-04, 1.239000e-05, 1.946000e-03}, {7.416000e-04, 2.202000e-05, 3.486000e-03},
24 {1.368000e-03, 3.900000e-05, 6.450001e-03}, {2.236000e-03, 6.400000e-05, 1.054999e-02},
25 {4.243000e-03, 1.200000e-04, 2.005001e-02}, {7.650000e-03, 2.170000e-04, 3.621000e-02},
26 {1.431000e-02, 3.960000e-04, 6.785001e-02}, {2.319000e-02, 6.400000e-04, 1.102000e-01},
27 {4.351000e-02, 1.210000e-03, 2.074000e-01}, {7.763000e-02, 2.180000e-03, 3.713000e-01},
28 {1.343800e-01, 4.000000e-03, 6.456000e-01}, {2.147700e-01, 7.300000e-03, 1.039050e+00},
29 {2.839000e-01, 1.160000e-02, 1.385600e+00}, {3.285000e-01, 1.684000e-02, 1.622960e+00},
30 {3.482800e-01, 2.300000e-02, 1.747060e+00}, {3.480600e-01, 2.980000e-02, 1.782600e+00},
31 {3.362000e-01, 3.800000e-02, 1.772110e+00}, {3.187000e-01, 4.800000e-02, 1.744100e+00},
32 {2.908000e-01, 6.000000e-02, 1.669200e+00}, {2.511000e-01, 7.390000e-02, 1.528100e+00},
33 {1.953600e-01, 9.098000e-02, 1.287640e+00}, {1.421000e-01, 1.126000e-01, 1.041900e+00},
34 {9.564000e-02, 1.390200e-01, 8.129501e-01}, {5.795001e-02, 1.693000e-01, 6.162000e-01},
35 {3.201000e-02, 2.080200e-01, 4.651800e-01}, {1.470000e-02, 2.586000e-01, 3.533000e-01},
36 {4.900000e-03, 3.230000e-01, 2.720000e-01}, {2.400000e-03, 4.073000e-01, 2.123000e-01},
37 {9.300000e-03, 5.030000e-01, 1.582000e-01}, {2.910000e-02, 6.082000e-01, 1.117000e-01},
38 {6.327000e-02, 7.100000e-01, 7.824999e-02}, {1.096000e-01, 7.932000e-01, 5.725001e-02},
39 {1.655000e-01, 8.620000e-01, 4.216000e-02}, {2.257499e-01, 9.148501e-01, 2.984000e-02},
40 {2.904000e-01, 9.540000e-01, 2.030000e-02}, {3.597000e-01, 9.803000e-01, 1.340000e-02},
41 {4.334499e-01, 9.949501e-01, 8.749999e-03}, {5.120501e-01, 1.000000e+00, 5.749999e-03},
42 {5.945000e-01, 9.950000e-01, 3.900000e-03}, {6.784000e-01, 9.786000e-01, 2.749999e-03},
43 {7.621000e-01, 9.520000e-01, 2.100000e-03}, {8.425000e-01, 9.154000e-01, 1.800000e-03},
44 {9.163000e-01, 8.700000e-01, 1.650001e-03}, {9.786000e-01, 8.163000e-01, 1.400000e-03},
45 {1.026300e+00, 7.570000e-01, 1.100000e-03}, {1.056700e+00, 6.949000e-01, 1.000000e-03},
46 {1.062200e+00, 6.310000e-01, 8.000000e-04}, {1.045600e+00, 5.668000e-01, 6.000000e-04},
47 {1.002600e+00, 5.030000e-01, 3.400000e-04}, {9.384000e-01, 4.412000e-01, 2.400000e-04},
48 {8.544499e-01, 3.810000e-01, 1.900000e-04}, {7.514000e-01, 3.210000e-01, 1.000000e-04},
49 {6.424000e-01, 2.650000e-01, 4.999999e-05}, {5.419000e-01, 2.170000e-01, 3.000000e-05},
50 {4.479000e-01, 1.750000e-01, 2.000000e-05}, {3.608000e-01, 1.382000e-01, 1.000000e-05},
51 {2.835000e-01, 1.070000e-01, 0.000000e+00}, {2.187000e-01, 8.160000e-02, 0.000000e+00},
52 {1.649000e-01, 6.100000e-02, 0.000000e+00}, {1.212000e-01, 4.458000e-02, 0.000000e+00},
53 {8.740000e-02, 3.200000e-02, 0.000000e+00}, {6.360000e-02, 2.320000e-02, 0.000000e+00},
54 {4.677000e-02, 1.700000e-02, 0.000000e+00}, {3.290000e-02, 1.192000e-02, 0.000000e+00},
55 {2.270000e-02, 8.210000e-03, 0.000000e+00}, {1.584000e-02, 5.723000e-03, 0.000000e+00},
56 {1.135916e-02, 4.102000e-03, 0.000000e+00}, {8.110916e-03, 2.929000e-03, 0.000000e+00},
57 {5.790346e-03, 2.091000e-03, 0.000000e+00}, {4.109457e-03, 1.484000e-03, 0.000000e+00},
58 {2.899327e-03, 1.047000e-03, 0.000000e+00}, {2.049190e-03, 7.400000e-04, 0.000000e+00},
59 {1.439971e-03, 5.200000e-04, 0.000000e+00}, {9.999493e-04, 3.611000e-04, 0.000000e+00},
60 {6.900786e-04, 2.492000e-04, 0.000000e+00}, {4.760213e-04, 1.719000e-04, 0.000000e+00},
61 {3.323011e-04, 1.200000e-04, 0.000000e+00}, {2.348261e-04, 8.480000e-05, 0.000000e+00},
62 {1.661505e-04, 6.000000e-05, 0.000000e+00}, {1.174130e-04, 4.240000e-05, 0.000000e+00},
63 {8.307527e-05, 3.000000e-05, 0.000000e+00}, {5.870652e-05, 2.120000e-05, 0.000000e+00},
64 {4.150994e-05, 1.499000e-05, 0.000000e+00}, {2.935326e-05, 1.060000e-05, 0.000000e+00},
65 {2.067383e-05, 7.465700e-06, 0.000000e+00}, {1.455977e-05, 5.257800e-06, 0.000000e+00},
66 {1.025398e-05, 3.702900e-06, 0.000000e+00}, {7.221456e-06, 2.607800e-06, 0.000000e+00},
67 {5.085868e-06, 1.836600e-06, 0.000000e+00}, {3.581652e-06, 1.293400e-06, 0.000000e+00},
68 {2.522525e-06, 9.109300e-07, 0.000000e+00}, {1.776509e-06, 6.415300e-07, 0.000000e+00},
69 {1.251141e-06, 4.518100e-07, 0.000000e+00},
70 };
71
72 constexpr uint32_t kDaylightRows = 54;
73 constexpr double kDaylight[kDaylightRows][3] = {
74 {0.04, 0.02, 0.0}, {6.0, 4.5, 2.0}, {29.6, 22.4, 4.0}, {55.3, 42.0, 8.5},
75 {57.3, 40.6, 7.8}, {61.8, 41.6, 6.7}, {61.5, 38.0, 5.3}, {68.8, 42.4, 6.1},
76 {63.4, 38.5, 3.0}, {65.8, 35.0, 1.2}, {94.8, 43.4, -1.1}, {104.8, 46.3, -0.5},
77 {105.9, 43.9, -0.7}, {96.8, 37.1, -1.2}, {113.9, 36.7, -2.6}, {125.6, 35.9, -2.9},
78 {125.5, 32.6, -2.8}, {121.3, 27.9, -2.6}, {121.3, 24.3, -2.6}, {113.5, 20.1, -1.8},
79 {113.1, 16.2, -1.5}, {110.8, 13.2, -1.3}, {106.5, 8.6, -1.2}, {108.8, 6.1, -1.0},
80 {105.3, 4.2, -0.5}, {104.4, 1.9, -0.3}, {100.0, 0.0, 0.0}, {96.0, -1.6, 0.2},
81 {95.1, -3.5, 0.5}, {89.1, -3.5, 2.1}, {90.5, -5.8, 3.2}, {90.3, -7.2, 4.1},
82 {88.4, -8.6, 4.7}, {84.0, -9.5, 5.1}, {85.1, -10.9, 6.7}, {81.9, -10.7, 7.3},
83 {82.6, -12.0, 8.6}, {84.9, -14.0, 9.8}, {81.3, -13.6, 10.2}, {71.9, -12.0, 8.3},
84 {74.3, -13.3, 9.6}, {76.4, -12.9, 8.5}, {63.3, -10.6, 7.0}, {71.7, -11.6, 7.6},
85 {77.0, -12.2, 8.0}, {65.2, -10.2, 6.7}, {47.7, -7.8, 5.2}, {68.6, -11.2, 7.4},
86 {65.0, -10.4, 6.8}, {66.0, -10.6, 7.0}, {61.0, -9.7, 6.4}, {53.3, -8.3, 5.5},
87 {58.9, -9.3, 6.1}, {61.9, -9.8, 6.5},
88 };
89
90 struct Rgb {
91 double r = 0;
92 double g = 0;
93 double b = 0;
94 };
95
96 8584960 double Planck(double nm, double kelvin) {
97 8584960 return 1.0 / (std::pow(nm, 5.0) * std::expm1(1.438776877e7 / (nm * kelvin)));
98 }
99
100 8618495 double Daylight(double nm, double kelvin) {
101
2/2
✓ Branch 0 taken 6438720 times.
✓ Branch 1 taken 2179775 times.
8618495 const double t = std::clamp(kelvin, 4000.0, 25000.0);
102 17236990 const double x = t <= 7000
103
2/2
✓ Branch 0 taken 7377700 times.
✓ Branch 1 taken 1240795 times.
8618495 ? -4.6070e9 / (t * t * t) + 2.9678e6 / (t * t) + 99.11 / t + 0.244063
104 1240795 : -2.0064e9 / (t * t * t) + 1.9018e6 / (t * t) + 247.48 / t + 0.237040;
105 8618495 const double y = -3 * x * x + 2.870 * x - 0.275;
106 8618495 const double m = 0.0241 + 0.2562 * x - 0.7341 * y;
107 8618495 const double m1 = (-1.3515 - 1.7703 * x + 5.9114 * y) / m;
108 8618495 const double m2 = (0.0300 - 31.4424 * x + 30.0717 * y) / m;
109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8618495 times.
8618495 const double at = std::clamp((nm - 300) / 10, 0.0, double(kDaylightRows - 1));
110
2/2
✓ Branch 0 taken 90721 times.
✓ Branch 1 taken 8527774 times.
8618495 const uint32_t row = std::min(uint32_t(at), kDaylightRows - 2);
111 8618495 const double f = at - row;
112 8618495 double value = 0;
113 8618495 const double weights[3] = {1, m1, m2};
114
2/2
✓ Branch 0 taken 25855485 times.
✓ Branch 1 taken 8618495 times.
34473980 for (uint32_t component = 0; component < 3; ++component) {
115 25855485 value += weights[component] *
116 25855485 std::lerp(kDaylight[row][component], kDaylight[row + 1][component], f);
117 }
118 8618495 return value;
119 }
120
121 181089 template <class Spectrum> Rgb SpectrumRgb(const Spectrum& spectrum) {
122 181089 double x = 0;
123 181089 double y = 0;
124 181089 double z = 0;
125
6/6
chrono::batch_render::(anonymous namespace)::Rgb chrono::batch_render::(anonymous namespace)::SpectrumRgb<chrono::batch_render::(anonymous namespace)::BuildSpectralTables()::{lambda(double)#1}>(chrono::batch_render::(anonymous namespace)::BuildSpectralTables()::{lambda(double)#1} const&):
✓ Branch 0 taken 33535 times.
✓ Branch 1 taken 353 times.
chrono::batch_render::(anonymous namespace)::Rgb chrono::batch_render::(anonymous namespace)::SpectrumRgb<chrono::batch_render::(anonymous namespace)::BuildSpectralTables()::{lambda(double)#2}>(chrono::batch_render::(anonymous namespace)::BuildSpectralTables()::{lambda(double)#2} const&):
✓ Branch 0 taken 8584960 times.
✓ Branch 1 taken 90368 times.
chrono::batch_render::(anonymous namespace)::Rgb chrono::batch_render::(anonymous namespace)::SpectrumRgb<chrono::batch_render::(anonymous namespace)::BuildSpectralTables()::{lambda(double)#3}>(chrono::batch_render::(anonymous namespace)::BuildSpectralTables()::{lambda(double)#3} const&):
✓ Branch 0 taken 8584960 times.
✓ Branch 1 taken 90368 times.
17384544 for (uint32_t row = 0; row < kSpectralRows; ++row) {
126 25788415 const double value = spectrum(kSpectralFirstNm + row * kSpectralStepNm);
127 17203455 x += value * kCmf[row][0];
128 17203455 y += value * kCmf[row][1];
129 17203455 z += value * kCmf[row][2];
130 }
131 181089 return {(3.2404542 * x - 1.5371385 * y - 0.4985314 * z) / y,
132 181089 (-0.9692660 * x + 1.8760108 * y + 0.0415560 * z) / y,
133 181089 (0.0556434 * x - 0.2040259 * y + 1.0572252 * z) / y};
134 }
135
136 180736 Float3 UnitLuminance(Rgb rgb, Rgb white) {
137
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 180736 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 180736 times.
180736 rgb = {std::max(rgb.r / white.r, 0.0), std::max(rgb.g / white.g, 0.0),
138
2/2
✓ Branch 0 taken 42713 times.
✓ Branch 1 taken 138023 times.
180736 std::max(rgb.b / white.b, 0.0)};
139 180736 const double luminance = 0.2126729 * rgb.r + 0.7151522 * rgb.g + 0.0721750 * rgb.b;
140 180736 return {float(rgb.r / luminance), float(rgb.g / luminance), float(rgb.b / luminance)};
141 }
142
143 353 SpectralTables BuildSpectralTables() {
144 353 SpectralTables tables{};
145
2/2
✓ Branch 0 taken 33535 times.
✓ Branch 1 taken 353 times.
33888 for (uint32_t row = 0; row < kSpectralRows; ++row) {
146 33535 tables.cmf[row] = {float(kCmf[row][0]), float(kCmf[row][1]), float(kCmf[row][2])};
147 }
148 33535 const Rgb white = SpectrumRgb([](double nm) { return Daylight(nm, 6504); });
149 353 tables.white = {float(white.r), float(white.g), float(white.b)};
150
2/2
✓ Branch 0 taken 90368 times.
✓ Branch 1 taken 353 times.
90721 for (uint32_t row = 0; row < kTemperatureRows; ++row) {
151
2/2
✓ Branch 0 taken 353 times.
✓ Branch 1 taken 90015 times.
90368 const double mired = std::max(double(row) / (kTemperatureRows - 1) * kMaxMired, 1e-3);
152 90368 const double kelvin = 1e6 / mired;
153 90368 tables.blackbody[row] =
154 8675328 UnitLuminance(SpectrumRgb([&](double nm) { return Planck(nm, kelvin); }), white);
155 90368 tables.daylight[row] =
156 8675328 UnitLuminance(SpectrumRgb([&](double nm) { return Daylight(nm, kelvin); }), white);
157 }
158 353 return tables;
159 }
160
161 5 std::vector<ColumnRef> LightInputs() {
162 5 std::vector<ColumnRef> inputs = {kRenderProductCamera};
163 5 const SchemaId schemas[] = {SchemaId::LightAPI,
164 SchemaId::DistantLight,
165 SchemaId::SphereLight,
166 SchemaId::RectLight,
167 SchemaId::DiskLight,
168 SchemaId::CylinderLight,
169 SchemaId::DomeLight,
170 SchemaId::PortalLight,
171 SchemaId::ShapingAPI,
172 SchemaId::OmniShapingAPI,
173 SchemaId::ShadowAPI,
174 SchemaId::PhysicalLightIlluminantAPI,
175 SchemaId::PhotometricAreaLightAPI,
176 SchemaId::PhotometricDistantLightAPI,
177 SchemaId::CollectionAPI,
178 SchemaId::PointInstancer,
179 SchemaId::PrototypeAPI};
180
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 5 times.
90 for (const SchemaId schema : schemas) {
181
1/1
✓ Branch 1 taken 85 times.
85 const Span<const ColumnInfo> columns = Columns(schema);
182
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 85 times.
400 for (uint32_t index = 0; index < columns.size(); ++index) {
183
1/1
✓ Branch 1 taken 315 times.
315 inputs.push_back({schema, &columns[index], index});
184 }
185 }
186 5 return inputs;
187 ✗ }
188
189 }
190
191 2545 std::span<const ColumnRef> LightTable::Inputs() const {
192
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2540 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
2545 static const std::vector<ColumnRef> inputs = LightInputs();
193 2545 return inputs;
194 }
195
196 691 void LightTable::Describe(RenderTables& tables) const {
197
1/2
✓ Branch 0 taken 691 times.
✗ Branch 1 not taken.
691 tables.lights.address = m_layout ? m_layout->Address() : 0;
198
1/2
✓ Branch 0 taken 691 times.
✗ Branch 1 not taken.
691 tables.minimalLights.address = m_minimal ? m_minimal->Address() : 0;
199
1/2
✓ Branch 0 taken 691 times.
✗ Branch 1 not taken.
691 tables.collections.address = m_collections.Address();
200
1/2
✓ Branch 0 taken 691 times.
✗ Branch 1 not taken.
691 tables.lightShapes.address = m_shapes.Address();
201 691 }
202
203 928 void LightTable::Hold(std::vector<Ref<const RefCounted>>& held) const {
204
4/8
✓ Branch 1 taken 7424 times.
✓ Branch 2 taken 928 times.
✓ Branch 3 taken 7417 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
9280 HoldBuffers(held, {m_layout, m_minimal, m_records, m_cdf, m_maps, m_spectra,
205 m_collections.Buffer(), m_shapes.Buffer()});
206 1856 }
207
208 353 void LightTable::Prepare() {
209 353 Kernels();
210 353 Spectra();
211 353 }
212
213 429 const Ref<device::Buffer>& LightTable::Spectra() {
214
2/2
✓ Branch 0 taken 353 times.
✓ Branch 1 taken 76 times.
429 if (!m_spectra) {
215 353 const std::vector<SpectralTables> tables = {BuildSpectralTables()};
216
2/2
✓ Branch 1 taken 353 times.
✓ Branch 4 taken 353 times.
706 m_spectra = m_structure.GetColumnStore().GetDevice().CreateBuffer(
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 353 times.
353 {.label = "spectral tables"}, tables);
218 353 }
219 429 return m_spectra;
220 706 }
221
222 417 bool LightTable::Restructured(const ChangeSet& changes) const {
223
4/4
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 401 times.
417 if (m_structure.GetPrims().WorldCount() != m_worlds || changes.Wrote(TableId::Instances)) {
224 16 return true;
225 }
226
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 399 times.
539 for (const StructureEntry& entry : changes.removed) {
227
3/4
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
140 if (m_lights.contains(entry.prim) || m_worldPrims.contains(entry.prim)) {
228 2 return true;
229 }
230 }
231 399 const Prims& prims = m_structure.GetPrims();
232
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 399 times.
635 for (const StructureEntry& entry : changes.added) {
233
5/6
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 16 times.
✓ Branch 4 taken 210 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 210 times.
✗ Branch 7 not taken.
446 if (prims.Alive(entry.prim) && prims.Generation(entry.prim) == entry.generation &&
234
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 210 times.
420 (prims.HasApi(entry.prim, SchemaId::LightAPI) ||
235 210 IsA(prims.Record(entry.prim).schema, SchemaId::World))) {
236 ✗ return true;
237 }
238 }
239 399 return std::ranges::any_of(
240
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 time.
410 changes.apis, [](const StructureEntry& entry) { return entry.api == SchemaId::LightAPI; });
241 }
242
243 293 void LightTable::Relayout() {
244
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 288 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
293 CHRONO_BATCH_RENDER_ZONE("Lights/Relayout");
245 293 const Prims& prims = m_structure.GetPrims();
246 293 device::Device& device = m_structure.GetColumnStore().GetDevice();
247 293 m_worlds = prims.WorldCount();
248 293 m_lights.clear();
249 293 m_worldPrims.clear();
250
1/1
✓ Branch 1 taken 293 times.
293 std::vector<std::vector<uint32_t>> lists(m_worlds + 1);
251
2/2
✓ Branch 0 taken 7219 times.
✓ Branch 1 taken 293 times.
7512 for (uint32_t prim = 0; prim < prims.Size(); ++prim) {
252
3/3
✓ Branch 1 taken 7219 times.
✓ Branch 3 taken 258 times.
✓ Branch 4 taken 6961 times.
7219 if (!prims.Alive(prim)) {
253 258 continue;
254 }
255
1/1
✓ Branch 1 taken 6961 times.
6961 const PrimRecord& record = prims.Record(prim);
256
3/3
✓ Branch 1 taken 6961 times.
✓ Branch 3 taken 52 times.
✓ Branch 4 taken 6909 times.
6961 if (IsA(record.schema, SchemaId::World)) {
257
1/1
✓ Branch 1 taken 52 times.
52 m_worldPrims.insert(prim);
258 }
259
3/3
✓ Branch 1 taken 6961 times.
✓ Branch 3 taken 76 times.
✓ Branch 4 taken 6885 times.
6961 if (HasApi(record.apis, SchemaId::LightAPI)) {
260
1/1
✓ Branch 1 taken 76 times.
76 m_lights.insert(prim);
261
2/2
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 5 times.
76 if (!m_instances.Members().contains(prim)) {
262
3/3
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 71 times.
127 lists[TlasIndex(record.world, m_worlds)].push_back(prim);
263 }
264 }
265 }
266 293 std::vector<uint32_t> domes;
267
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 293 times.
369 for (const uint32_t prim : m_lights) {
268
3/3
✓ Branch 1 taken 76 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 62 times.
76 if (prims.Record(prim).schema == SchemaId::DomeLight) {
269
1/1
✓ Branch 1 taken 14 times.
14 domes.push_back(prim);
270 }
271 }
272
1/1
✓ Branch 1 taken 293 times.
293 m_domes = uint32_t(domes.size());
273 293 std::vector<uint32_t> items;
274 293 std::vector<uint32_t> copies;
275
1/1
✓ Branch 1 taken 293 times.
293 std::vector<uint32_t> starts = {0};
276 293 m_counts.clear();
277 293 m_compositions = m_structure.CompositionVersion();
278 293 m_shownIn.clear();
279 293 const std::map<uint32_t, ComposedWorldDesc>& composed = m_structure.Compositions();
280
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 293 times.
638 for (uint32_t tlas = 0; tlas <= m_worlds; ++tlas) {
281
1/1
✓ Branch 1 taken 345 times.
345 items.insert(items.end(), lists[tlas].begin(), lists[tlas].end());
282
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 293 times.
397 const auto composition = tlas < m_worlds ? composed.find(tlas) : composed.end();
283
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 344 times.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
345 const bool stage = composition == composed.end() || composition->second.stageLights;
284
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 344 times.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
345 if (composition != composed.end() && stage) {
285
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for (const uint32_t world : composition->second.worlds) {
286
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if (world < m_worlds && world != tlas) {
287
1/1
✓ Branch 1 taken 1 time.
1 items.insert(items.end(), lists[world].begin(), lists[world].end());
288
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
1 m_shownIn[world].insert(tlas);
289 }
290 }
291 }
292
3/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 293 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
345 if (tlas < m_worlds && stage) {
293
1/1
✓ Branch 1 taken 52 times.
52 items.insert(items.end(), lists[m_worlds].begin(), lists[m_worlds].end());
294 }
295
3/3
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 345 times.
355 for (const auto& [block, offset] : m_instances.LightCopies(tlas)) {
296
1/1
✓ Branch 1 taken 10 times.
10 items.push_back(kInstancerSlot | uint32_t(copies.size() / 2));
297
1/1
✓ Branch 1 taken 10 times.
10 copies.push_back(block);
298
1/1
✓ Branch 1 taken 10 times.
10 copies.push_back(offset);
299 }
300
1/1
✓ Branch 1 taken 345 times.
345 starts.push_back(uint32_t(items.size()));
301
1/1
✓ Branch 1 taken 345 times.
345 m_counts.push_back(starts.back() - starts[starts.size() - 2]);
302 }
303
304
1/1
✓ Branch 1 taken 293 times.
586 m_records = device.CreateBuffer(
305
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 274 times.
293 {.bytes = std::max<uint64_t>(items.size(), 1) * sizeof(LightRecord), .label = "lights"});
306
1/1
✓ Branch 1 taken 293 times.
586 m_cdf = device.CreateBuffer(
307
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 274 times.
293 {.bytes = std::max<uint64_t>(items.size(), 1) * sizeof(float), .label = "light cdf"});
308 586 std::vector<uint32_t> words(sizeof(LightLayout) / sizeof(uint32_t));
309 2344 const auto append = [&](std::span<const uint32_t> values) {
310 2051 const uint64_t at = words.size() * sizeof(uint32_t);
311 2051 words.insert(words.end(), values.begin(), values.end());
312 2051 return at;
313 293 };
314
1/1
✓ Branch 1 taken 293 times.
293 const uint64_t first = append(starts);
315
1/1
✓ Branch 1 taken 293 times.
293 const uint64_t listed = append(items);
316
1/1
✓ Branch 1 taken 293 times.
293 std::vector<uint32_t> slots(items.size(), kNoRow);
317
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 293 times.
384 for (size_t slot = 0; slot < items.size(); ++slot) {
318 91 const auto dome = std::ranges::find(domes, items[slot]);
319
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 77 times.
91 if (dome != domes.end()) {
320 14 slots[slot] = uint32_t(dome - domes.begin());
321 }
322 }
323
1/1
✓ Branch 1 taken 293 times.
293 const uint64_t domePrims = append(domes);
324
1/1
✓ Branch 1 taken 293 times.
293 const uint64_t domeSlots = append(slots);
325
1/1
✓ Branch 1 taken 293 times.
293 std::vector<uint32_t> bases(m_worlds + 1, kNoRow);
326 293 std::vector<Float3> shifts;
327
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 293 times.
294 for (const auto& [world, desc] : composed) {
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (world >= m_worlds) {
329 ✗ continue;
330 }
331
1/1
✓ Branch 1 taken 1 time.
1 bases[world] = uint32_t(shifts.size());
332
1/1
✓ Branch 1 taken 1 time.
1 shifts.resize(shifts.size() + m_worlds, Float3{0, 0, 0});
333
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
2 for (size_t at = 0; at < desc.worlds.size() && at < desc.offsets.size(); ++at) {
334
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (desc.worlds[at] < m_worlds) {
335 1 const Double3& offset = desc.offsets[at];
336 1 shifts[bases[world] + desc.worlds[at]] = {float(offset.x), float(offset.y),
337 1 float(offset.z)};
338 }
339 }
340 }
341
1/1
✓ Branch 1 taken 293 times.
293 const uint64_t copiesStart = append(copies);
342
1/1
✓ Branch 1 taken 293 times.
293 const uint64_t offsetBases = append(bases);
343
1/1
✓ Branch 1 taken 293 times.
293 const uint64_t offsets =
344
1/1
✓ Branch 1 taken 293 times.
293 append(std::span(reinterpret_cast<const uint32_t*>(shifts.data()), shifts.size() * 3));
345
1/1
✓ Branch 1 taken 293 times.
586 m_maps = device.CreateBuffer(
346 879 {.bytes = std::max<uint64_t>(m_domes, 1) * kDomeMapFloats * sizeof(float),
347
3/3
✓ Branch 1 taken 293 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 274 times.
586 .label = "dome maps"});
348 293 m_layout =
349
4/4
✓ Branch 1 taken 293 times.
✓ Branch 4 taken 293 times.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 274 times.
312 device.CreateBuffer({.bytes = words.size() * sizeof(uint32_t), .label = "light layout"});
350 293 LightLayout layout{};
351 293 layout.records.address = m_records->Address();
352 293 layout.firstLights.address = m_layout->Address() + first;
353 293 layout.prims.address = m_layout->Address() + listed;
354 293 layout.cdf.address = m_cdf->Address();
355 293 layout.maps.address = m_maps->Address();
356 293 layout.domePrims.address = m_layout->Address() + domePrims;
357 293 layout.domeSlots.address = m_layout->Address() + domeSlots;
358 293 layout.offsetBases.address = m_layout->Address() + offsetBases;
359 293 layout.offsets.address = m_layout->Address() + offsets;
360 293 layout.copies.address = m_layout->Address() + copiesStart;
361 293 layout.worldCount = m_worlds;
362 293 layout.domeCount = m_domes;
363
1/1
✓ Branch 1 taken 293 times.
293 std::memcpy(words.data(), &layout, sizeof(layout));
364
1/1
✓ Branch 1 taken 293 times.
293 device.GetQueue().Write(*m_layout, words.data());
365
2/2
✓ Branch 1 taken 293 times.
✓ Branch 4 taken 293 times.
293 const std::vector<MinimalLightRecord> headlights(m_worlds + 1, {.headlight = 1});
366
2/2
✓ Branch 1 taken 293 times.
✓ Branch 4 taken 293 times.
586 m_minimal = device.CreateBuffer({.label = "minimal lights"},
367
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 274 times.
293 std::span<const MinimalLightRecord>(headlights));
368 3109 }
369
370 691 void LightTable::Run(const ChangeSet& changes, TableVersions&) {
371
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 686 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
691 CHRONO_BATCH_RENDER_ZONE("Lights/Run");
372 691 m_written = 0;
373
7/9
✓ Branch 0 taken 417 times.
✓ Branch 1 taken 274 times.
✓ Branch 2 taken 417 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 417 times.
✓ Branch 7 taken 398 times.
✓ Branch 8 taken 19 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 398 times.
691 const bool relaid = changes.resync || !m_layout || Restructured(changes) ||
374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 398 times.
398 m_structure.CompositionVersion() != m_compositions;
375 293 if (relaid) {
376
1/1
✓ Branch 1 taken 293 times.
293 Relayout();
377 }
378
1/1
✓ Branch 1 taken 691 times.
691 ColumnStore& store = m_structure.GetColumnStore();
379
1/1
✓ Branch 1 taken 691 times.
691 WriteCollectionsAndShapes();
380
1/1
✓ Branch 1 taken 691 times.
691 const bool viewed = store.LastWrite(kRenderProductCamera) > m_seen;
381
2/2
✓ Branch 0 taken 394 times.
✓ Branch 1 taken 297 times.
691 m_seen = store.WriteSequence();
382 691 std::vector<uint32_t> dirty;
383
5/5
✓ Branch 0 taken 394 times.
✓ Branch 1 taken 297 times.
✓ Branch 3 taken 394 times.
✓ Branch 5 taken 385 times.
✓ Branch 6 taken 9 times.
691 const bool global = relaid || viewed || changes.Global();
384 691 std::set<uint32_t> shown;
385
2/2
✓ Branch 0 taken 746 times.
✓ Branch 1 taken 691 times.
1437 for (const uint32_t world : changes.worlds) {
386
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 744 times.
746 if (const auto found = m_shownIn.find(world); found != m_shownIn.end()) {
387
1/1
✓ Branch 1 taken 2 times.
2 shown.insert(found->second.begin(), found->second.end());
388 }
389 }
390
2/2
✓ Branch 0 taken 772 times.
✓ Branch 1 taken 691 times.
1463 for (uint32_t tlas = 0; tlas <= m_worlds; ++tlas) {
391 772 const bool touched =
392
6/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 745 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 1 time.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 16 times.
1528 global || shown.contains(tlas) || std::ranges::binary_search(changes.worlds, tlas);
393
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 656 times.
756 if (touched && m_counts[tlas] > 0) {
394
1/1
✓ Branch 1 taken 100 times.
100 dirty.push_back(tlas);
395 }
396 }
397
2/2
✓ Branch 0 taken 615 times.
✓ Branch 1 taken 76 times.
691 if (dirty.empty()) {
398 615 return;
399 }
400 76 uint32_t widest = 0;
401
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 76 times.
176 for (const uint32_t tlas : dirty) {
402
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 22 times.
100 widest = std::max(widest, m_counts[tlas]);
403 100 m_written += m_counts[tlas];
404 }
405
406
1/1
✓ Branch 1 taken 76 times.
76 device::Device& device = store.GetDevice();
407
1/1
✓ Branch 1 taken 76 times.
76 const Ref<device::Buffer> tlases = device.CreateBuffer({.label = "dirty light lists"}, dirty);
408 76 LightParams params{};
409 152 params.scene.address = store.DeviceData();
410
1/1
✓ Branch 1 taken 76 times.
76 params.layout.address = m_layout->Address();
411 76 params.instances = m_tables.instances;
412 76 params.origins = m_tables.origins;
413 76 params.transforms = m_tables.transforms;
414 76 params.imageables = m_tables.imageables;
415 76 params.textures = m_tables.textures;
416 76 params.textureBindings = m_tables.textureBindings;
417 76 params.tlases.address = tlases->Address();
418
2/2
✓ Branch 1 taken 76 times.
✓ Branch 4 taken 76 times.
76 params.spectra.address = Spectra()->Address();
419 76 params.minimal.address = m_minimal->Address();
420
1/1
✓ Branch 1 taken 76 times.
76 params.tlasCount = uint32_t(dirty.size());
421
1/1
✓ Branch 1 taken 76 times.
76 params.lightLink = m_structure.GetTokens().Intern("lightLink").id;
422
1/3
✓ Branch 1 taken 76 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
76 params.shadowLink = m_structure.GetTokens().Intern("shadowLink").id;
423
1/1
✓ Branch 1 taken 76 times.
76 device::Queue& queue = device.GetQueue();
424
1/1
✓ Branch 1 taken 76 times.
76 device::CommandEncoder encoder = queue.CreateEncoder();
425
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 56 times.
76 if (m_domes > 0) {
426
3/3
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
✓ Branch 7 taken 20 times.
20 encoder.Dispatch(Kernels().Entry("WriteDomeMaps"), params,
427 {.x = device::GroupCount(kDomeMapCells, kLightGroup), .y = m_domes});
428
1/1
✓ Branch 1 taken 20 times.
20 encoder.Barrier();
429
3/3
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
✓ Branch 7 taken 20 times.
20 encoder.Dispatch(Kernels().Entry("WriteDomeRows"), params,
430
1/1
✓ Branch 1 taken 20 times.
20 {.x = device::GroupCount(kDomeMapHeight, kLightGroup), .y = m_domes});
431
1/1
✓ Branch 1 taken 20 times.
20 encoder.Barrier();
432
3/3
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
✓ Branch 7 taken 20 times.
20 encoder.Dispatch(Kernels().Entry("WriteDomeMarginals"), params,
433
1/1
✓ Branch 1 taken 20 times.
20 {.x = device::GroupCount(m_domes, kLightGroup)});
434
1/1
✓ Branch 1 taken 20 times.
20 encoder.Barrier();
435 }
436
3/3
✓ Branch 1 taken 76 times.
✓ Branch 4 taken 76 times.
✓ Branch 7 taken 76 times.
76 encoder.Dispatch(Kernels().Entry("WriteLights"), params,
437
1/1
✓ Branch 1 taken 76 times.
76 {.x = device::GroupCount(widest, kLightGroup), .y = uint32_t(dirty.size())});
438
1/1
✓ Branch 1 taken 76 times.
76 encoder.Barrier();
439
3/3
✓ Branch 1 taken 76 times.
✓ Branch 4 taken 76 times.
✓ Branch 7 taken 76 times.
76 encoder.Dispatch(Kernels().Entry("WriteLightCdf"), params,
440
1/1
✓ Branch 1 taken 76 times.
76 {.x = device::GroupCount(uint32_t(dirty.size()), kLightGroup)});
441
3/3
✓ Branch 1 taken 76 times.
✓ Branch 4 taken 76 times.
✓ Branch 7 taken 76 times.
76 encoder.Dispatch(Kernels().Entry("WriteMinimalLights"), params,
442
1/1
✓ Branch 1 taken 76 times.
76 {.x = device::GroupCount(uint32_t(dirty.size()), kLightGroup)});
443
2/2
✓ Branch 1 taken 76 times.
✓ Branch 4 taken 76 times.
76 queue.Submit(encoder.Finish());
444 919 }
445
446 691 void LightTable::WriteCollectionsAndShapes() {
447 691 ColumnStore& store = m_structure.GetColumnStore();
448 691 device::Device& device = store.GetDevice();
449 691 LightParams params{};
450 691 params.collectionRows = store.Schema(SchemaId::CollectionAPI).Rows();
451 691 params.shapeRows = store.Schema(SchemaId::LightAPI).Rows();
452 691 m_collections.Reserve(device, store.Schema(SchemaId::CollectionAPI).Capacity());
453 691 m_shapes.Reserve(device, store.Schema(SchemaId::LightAPI).Capacity());
454 691 params.scene.address = store.DeviceData();
455
1/2
✓ Branch 0 taken 691 times.
✗ Branch 1 not taken.
691 params.collections.address = m_collections.Address();
456
1/2
✓ Branch 0 taken 691 times.
✗ Branch 1 not taken.
691 params.shapes.address = m_shapes.Address();
457 691 device::Queue& queue = device.GetQueue();
458 691 device::CommandEncoder encoder = queue.CreateEncoder();
459
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 614 times.
691 if (params.collectionRows > 0) {
460
3/3
✓ Branch 1 taken 77 times.
✓ Branch 4 taken 77 times.
✓ Branch 7 taken 77 times.
154 encoder.Dispatch(Kernels().Entry("WriteCollections"), params,
461
1/1
✓ Branch 1 taken 77 times.
77 {.x = device::GroupCount(params.collectionRows, kLightGroup)});
462 }
463
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 614 times.
691 if (params.shapeRows > 0) {
464
3/3
✓ Branch 1 taken 77 times.
✓ Branch 4 taken 77 times.
✓ Branch 7 taken 77 times.
154 encoder.Dispatch(Kernels().Entry("WriteLightShapes"), params,
465
1/1
✓ Branch 1 taken 77 times.
77 {.x = device::GroupCount(params.shapeRows, kLightGroup)});
466 }
467
2/2
✓ Branch 1 taken 691 times.
✓ Branch 4 taken 691 times.
691 queue.Submit(encoder.Finish());
468 691 }
469
470 795 device::Program& LightTable::Kernels() {
471
2/2
✓ Branch 0 taken 353 times.
✓ Branch 1 taken 442 times.
795 if (!m_program) {
472
2/2
✓ Branch 2 taken 353 times.
✓ Branch 5 taken 353 times.
1059 m_program = m_structure.GetColumnStore().GetDevice().CreateProgram(
473 {.modules = {"chrono_batch_render.scene.tables.kernels.lights"},
474 .library = &kSceneKernels,
475 .entries = {"WriteDomeMaps", "WriteDomeRows", "WriteDomeMarginals", "WriteLights",
476 "WriteLightCdf", "WriteMinimalLights", "WriteCollections",
477 "WriteLightShapes"},
478
2/3
✓ Branch 1 taken 353 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 353 times.
706 .label = "lights"});
479 }
480 795 return *m_program;
481 706 }
482
483 }
484