chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
236 / 254
92.9%
Branches:
219 / 249
88.0%
Functions:
18 / 18
100.0%

material/codegen.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/material/codegen.h"
3
4 #include <algorithm>
5 #include <cstddef>
6 #include <string_view>
7
8 #include <fmt/format.h>
9
10 #include "chrono_batch_render/util/text.h"
11
12 extern "C" {
13 extern const unsigned char chrono_batch_render_material_dispatch[];
14 extern const std::size_t chrono_batch_render_material_dispatch_size;
15 extern const unsigned char chrono_batch_render_material_definition[];
16 extern const std::size_t chrono_batch_render_material_definition_size;
17 extern const unsigned char chrono_batch_render_material_surface[];
18 extern const std::size_t chrono_batch_render_material_surface_size;
19 extern const unsigned char chrono_batch_render_material_standard[];
20 extern const std::size_t chrono_batch_render_material_standard_size;
21 extern const unsigned char chrono_batch_render_material_registered[];
22 extern const std::size_t chrono_batch_render_material_registered_size;
23 }
24
25 namespace chrono::batch_render::material {
26
27 namespace {
28
29 327 std::string_view Embedded(const unsigned char* bytes, std::size_t size) {
30 327 return {reinterpret_cast<const char*>(bytes), size};
31 }
32
33 430 std::string Cases(const MaterialDefinitionSet& set, std::string_view standard,
34 std::string_view surface) {
35 430 std::string cases;
36
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 430 times.
470 for (const MaterialDefinition& definition : set.Definitions()) {
37
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 8 times.
40 const std::string_view call = definition.surface ? surface : standard;
38 40 cases += fmt::format(" }} else if (context.definition == {}) {{\n {}\n",
39
2/2
✓ Branch 1 taken 40 times.
✓ Branch 4 taken 40 times.
120 definition.id, fmt::format(fmt::runtime(call), definition.type));
40 }
41 430 return cases;
42 ✗ }
43
44 constexpr std::string_view kPlanetaryDefinitions[] = {"Hapke", "LommelSeeliger", "LunarLambert",
45 "OrenNayar"};
46
47 430 std::string PlanetaryCases(bool planetary, std::string_view call) {
48
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 420 times.
430 std::string cases;
49
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 420 times.
430 if (!planetary) {
50 return cases;
51 }
52
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 10 times.
50 for (const std::string_view name : kPlanetaryDefinitions) {
53
1/1
✓ Branch 1 taken 40 times.
40 cases +=
54
1/1
✓ Branch 1 taken 40 times.
80 fmt::format(" }} else if (context.definition == kDefinition{0}) {{\n {1}\n",
55
1/1
✓ Branch 1 taken 40 times.
120 name, fmt::format(fmt::runtime(call), name));
56 }
57 10 return cases;
58 ✗ }
59
60 215 std::string Dispatch(const MaterialDefinitionSet& set) {
61 215 std::string imports;
62 215 std::string linked;
63
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 215 times.
235 for (const MaterialDefinition& definition : set.Definitions()) {
64
1/1
✓ Branch 1 taken 20 times.
40 imports += fmt::format("import {};\n", definition.module);
65
1/1
✓ Branch 1 taken 20 times.
40 linked += fmt::format(" || definition == {}", definition.id);
66 }
67 215 const bool planetary = set.Planetary();
68 215 return FillTemplate(
69 Embedded(chrono_batch_render_material_dispatch, chrono_batch_render_material_dispatch_size),
70 {{"imports", imports},
71 {"planetaryImport",
72
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 5 times.
215 planetary ? "__exported import "
73 "chrono_batch_render.render.kernels.material.definitions.planetary;\n"
74 : ""},
75 {"planetaryLinked",
76
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 5 times.
215 planetary ? " || (definition >= kDefinitionHapke && definition <= kDefinitionOrenNayar)"
77 : ""},
78 {"planetaryShade",
79
1/1
✓ Branch 1 taken 215 times.
215 PlanetaryCases(planetary, "{}Definition<Spectrum>.Shade(context, closure);")},
80 {"planetaryAlbedo",
81
1/1
✓ Branch 1 taken 215 times.
430 PlanetaryCases(planetary, "return {}Definition<Spectrum>.Albedo(context);")},
82 {"linked", linked},
83
1/1
✓ Branch 1 taken 215 times.
430 {"shadeCases", Cases(set, "StandardDefinition<{}, Spectrum>.Shade(context, closure);",
84 "{}<Spectrum>.Shade(context, closure);")},
85
1/1
✓ Branch 1 taken 215 times.
430 {"albedoCases", Cases(set, "return StandardDefinition<{}, Spectrum>.Albedo(context);",
86
5/5
✓ Branch 4 taken 215 times.
✓ Branch 8 taken 215 times.
✓ Branch 13 taken 215 times.
✓ Branch 17 taken 215 times.
✓ Branch 21 taken 215 times.
860 "return {}<Spectrum>.Albedo(context);")}});
87 215 }
88
89 27 std::string Expression(const ShadingGraph& graph, const GraphLayout& layout, uint32_t node,
90 uint32_t input) {
91
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24 times.
27 const InputBinding& binding = graph.nodes[node].inputs[input];
92
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24 times.
27 const MaterialNodeInput& declared = graph.nodes[node].node->inputs[input];
93 27 const bool spectral = declared.type == MaterialInputType::Spectral;
94
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24 times.
27 if (binding.kind == BindingKind::Pattern) {
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 return spectral ? fmt::format("SpectralValue.Rgb(r{})", binding.source)
96 3 : fmt::format("r{}", binding.source);
97 }
98 24 const std::string cell = fmt::format("p.n{}_{}", node, declared.name);
99
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24 if (binding.kind == BindingKind::Texture) {
100 2 const std::string sampled =
101 fmt::format("texels.texels[{0}], texels.Handle({0}), &p.textures[{0}]",
102
1/1
✓ Branch 1 taken 2 times.
2 layout.textures[node][input]);
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (declared.type == MaterialInputType::Float) {
104
0/1
✗ Branch 1 not taken.
✗ return fmt::format("TexturedFloat({}, {})", cell, sampled);
105 }
106
1/1
✓ Branch 1 taken 2 times.
2 const std::string color = fmt::format("TexturedColor({}, {})", cell, sampled);
107
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
2 return spectral ? fmt::format("SpectralValue.Rgb({})", color) : color;
108 4 }
109
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 21 times.
22 if (spectral) {
110 1 return fmt::format("({0}_spectrum != kNoSpectrum ? SpectralValue.Library({0}_spectrum) : "
111 "SpectralValue.Rgb({0}.Vector()))",
112
1/1
✓ Branch 1 taken 1 time.
1 cell);
113 }
114
3/3
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 10 times.
21 switch (declared.type) {
115 4 case MaterialInputType::Bool:
116
1/1
✓ Branch 1 taken 4 times.
4 return cell + " != 0";
117 7 case MaterialInputType::Float2:
118 7 case MaterialInputType::Float3:
119 7 case MaterialInputType::Float4:
120
1/1
✓ Branch 1 taken 7 times.
7 return cell + ".Vector()";
121 10 default:
122
1/1
✓ Branch 1 taken 10 times.
10 return cell;
123 }
124 24 }
125
126 3 std::string Call(const ShadingGraph& graph, const GraphLayout& layout, uint32_t node) {
127 3 const MaterialNodeDefinition& definition = *graph.nodes[node].node;
128 3 std::vector<std::string> arguments;
129
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 for (const MaterialNodeParameter& parameter : definition.parameters) {
130
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
5 switch (parameter.source) {
131 1 case MaterialNodeParameter::Source::Context:
132
1/1
✓ Branch 1 taken 1 time.
1 arguments.emplace_back("context");
133 break;
134 ✗ case MaterialNodeParameter::Source::Point:
135
0/1
✗ Branch 1 not taken.
✗ arguments.emplace_back("context.point");
136 break;
137 4 case MaterialNodeParameter::Source::Input:
138
1/1
✓ Branch 1 taken 4 times.
8 arguments.push_back(Expression(graph, layout, node, parameter.input));
139 4 break;
140 }
141 }
142
1/1
✓ Branch 1 taken 3 times.
3 return fmt::format(" const {} r{} = {}({});\n", InputInfo(definition.result).slangType,
143
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
6 node, definition.name, Join(arguments));
144 3 }
145
146 14 std::string ParamsFields(const ShadingGraph& graph, const GraphLayout& layout) {
147
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 std::string fields;
148
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (layout.textureCount > 0) {
149
1/1
✓ Branch 1 taken 2 times.
4 fields += fmt::format(" TextureInput textures[{}];\n", layout.textureCount);
150 }
151
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (layout.mapped) {
152
1/1
✓ Branch 1 taken 2 times.
2 fields += " MappingRecord mapping;\n";
153 }
154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (layout.detailed) {
155
0/1
✗ Branch 1 not taken.
✗ fields += fmt::format(" DetailRecord detail;\n TextureInput details[{}];\n",
156 ✗ kDetailTextures);
157 }
158
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 14 times.
31 for (uint32_t node = 0; node < graph.nodes.size(); ++node) {
159
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 17 times.
44 for (const MaterialNodeInput& input : graph.nodes[node].node->inputs) {
160 27 fields +=
161
1/1
✓ Branch 1 taken 27 times.
54 fmt::format(" {} n{}_{};\n", InputInfo(input.type).cellType, node, input.name);
162
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 26 times.
27 if (input.type == MaterialInputType::Spectral) {
163
1/1
✓ Branch 1 taken 1 time.
2 fields += fmt::format(" uint n{}_{}_spectrum;\n", node, input.name);
164 }
165 }
166 }
167 14 return fields;
168 ✗ }
169
170 14 std::string AddImports(const ShadingGraph& graph, MaterialDefinition& module) {
171 14 std::string imports;
172
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 14 times.
31 for (const ShadingNode& node : graph.nodes) {
173
1/1
✓ Branch 1 taken 17 times.
17 const MaterialNodeDefinition& definition = *node.node;
174
1/1
✓ Branch 1 taken 17 times.
17 const std::string file = ModulePath(definition.module);
175
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 14 times.
17 if (module.files.contains(file)) {
176 3 continue;
177 }
178
1/1
✓ Branch 1 taken 14 times.
28 imports += fmt::format("import {};\n", definition.module);
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (definition.source.empty()) {
180 ✗ continue;
181 }
182
1/1
✓ Branch 1 taken 14 times.
14 module.files.emplace(file, definition.source);
183
1/1
✓ Branch 1 taken 14 times.
14 module.origins.emplace_back(file, definition.file);
184
2/2
✓ Branch 1 taken 14 times.
✓ Branch 4 taken 14 times.
14 module.origins.emplace_back(definition.module + ".slang", definition.file);
185 17 }
186 14 return imports;
187 ✗ }
188
189 14 std::string Body(const ShadingGraph& graph, const GraphLayout& layout) {
190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 const auto surface = uint32_t(graph.nodes.size() - 1);
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 const MaterialNodeDefinition& top = *graph.nodes[surface].node;
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 std::string body;
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (layout.detailed) {
194
0/1
✗ Branch 1 not taken.
✗ body += " SurfacePoint point = context.point;\n"
195 " const float3 overlay = MapNodeDetail(context.materials, &p.mapping, "
196 "&p.detail, &p.details[0], point);\n"
197 14 " context.point = point;\n";
198 }
199
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (layout.textureCount > 0) {
200 2 body += fmt::format(" const SurfaceTexels<{0}> texels = SampleNodeTextures<{0}>("
201 "context, &p.mapping, &p.textures[0]);\n",
202
1/1
✓ Branch 1 taken 2 times.
4 layout.textureCount);
203 }
204
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14 times.
17 for (uint32_t node = 0; node < surface; ++node) {
205
1/1
✓ Branch 1 taken 3 times.
6 body += Call(graph, layout, node);
206 }
207
1/1
✓ Branch 1 taken 14 times.
28 body += fmt::format(" {} node;\n", top.name);
208
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 14 times.
37 for (uint32_t input = 0; input < top.inputs.size(); ++input) {
209
1/1
✓ Branch 1 taken 23 times.
23 const std::string value = Expression(graph, layout, surface, input);
210
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
23 const bool overlaid = layout.detailed && top.detailAlbedo == input &&
211
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ top.inputs[input].type == MaterialInputType::Spectral;
212
1/1
✓ Branch 1 taken 23 times.
46 body += fmt::format(" node.{} = {};\n", top.inputs[input].name,
213
1/2
✗ Branch 1 not taken.
✓ Branch 4 taken 23 times.
69 overlaid ? fmt::format("DetailedAlbedo({}, overlay)", value) : value);
214 23 }
215 14 return body;
216 ✗ }
217
218 }
219
220 2 bool Texturable(MaterialInputType type) {
221
1/3
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
2 return type == MaterialInputType::Float || type == MaterialInputType::Float3 ||
222 2 type == MaterialInputType::Spectral;
223 }
224
225 29 GraphLayout LayOut(const ShadingGraph& graph) {
226 29 GraphLayout layout;
227
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 29 times.
64 for (const ShadingNode& node : graph.nodes) {
228
1/1
✓ Branch 1 taken 35 times.
35 std::vector<uint32_t>& textures = layout.textures.emplace_back();
229
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 35 times.
90 for (const InputBinding& binding : node.inputs) {
230
3/3
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 51 times.
✓ Branch 3 taken 55 times.
55 textures.push_back(binding.kind == BindingKind::Texture ? layout.textureCount++
231 : kNoTexture);
232 }
233 }
234 29 uint32_t offset = 0;
235
2/4
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 layout.detailed = !graph.nodes.empty() && graph.nodes.back().node->detail;
236
3/4
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
29 layout.mapped = layout.textureCount > 0 || layout.detailed;
237
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 25 times.
29 if (layout.mapped) {
238 4 layout.mapping = layout.textureCount * kTextureInputBytes;
239 4 offset = layout.mapping + kMappingBytes;
240 }
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (layout.detailed) {
242 ✗ layout.detail = offset;
243 ✗ layout.detailTextures = offset + kDetailBytes;
244 ✗ offset = layout.detailTextures + kDetailTextures * kTextureInputBytes;
245 }
246
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 29 times.
64 for (const ShadingNode& node : graph.nodes) {
247
1/1
✓ Branch 1 taken 35 times.
35 std::vector<uint32_t>& cells = layout.cells.emplace_back();
248
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 35 times.
90 for (const MaterialNodeInput& input : node.node->inputs) {
249
1/1
✓ Branch 1 taken 55 times.
55 cells.push_back(offset);
250 55 offset += InputInfo(input.type).bytes;
251 }
252 }
253 29 layout.bytes = offset;
254 29 return layout;
255 ✗ }
256
257 15 graph::ShapeKey MaterialDefinitionKey(const ShadingGraph& graph) {
258
1/1
✓ Branch 1 taken 15 times.
15 graph::ShapeWriter writer;
259
1/1
✓ Branch 1 taken 15 times.
15 writer.Add(uint32_t(graph.nodes.size()));
260
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 15 times.
33 for (const ShadingNode& node : graph.nodes) {
261
1/1
✓ Branch 1 taken 18 times.
18 writer.Add(node.node->module);
262
1/1
✓ Branch 1 taken 18 times.
18 writer.Add(node.node->name);
263
1/1
✓ Branch 1 taken 18 times.
18 writer.Add(uint32_t(node.inputs.size()));
264
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 18 times.
46 for (const InputBinding& binding : node.inputs) {
265
1/1
✓ Branch 1 taken 28 times.
28 writer.Add(uint32_t(binding.kind));
266
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 25 times.
28 if (binding.kind == BindingKind::Pattern) {
267
1/1
✓ Branch 1 taken 3 times.
3 writer.Add(binding.source);
268 }
269 }
270 }
271
1/1
✓ Branch 1 taken 15 times.
15 return std::move(writer).Finish();
272 15 }
273
274 14 MaterialDefinition GenerateMaterialDefinition(uint32_t id, const ShadingGraph& graph) {
275 14 const GraphLayout layout = LayOut(graph);
276
1/1
✓ Branch 1 taken 14 times.
14 const MaterialNodeDefinition& top = *graph.nodes.back().node;
277 14 MaterialDefinition module{.id = id,
278 .type = fmt::format("Definition{}", id),
279 .module =
280 fmt::format("chrono_batch_render.material.generated.d{}", id),
281 14 .words = layout.bytes / uint32_t(sizeof(uint32_t)),
282
3/3
✓ Branch 1 taken 14 times.
✓ Branch 4 taken 14 times.
✓ Branch 7 taken 14 times.
14 .surface = top.role == MaterialNodeRole::Surface};
283 14 const std::string& type = module.type;
284
1/1
✓ Branch 1 taken 14 times.
14 const std::string imports = AddImports(graph, module);
285
1/1
✓ Branch 1 taken 14 times.
14 const std::string fields = ParamsFields(graph, layout);
286
1/1
✓ Branch 1 taken 14 times.
14 const std::string body = Body(graph, layout);
287 14 const std::string definition =
288 3 FillTemplate(module.surface ? Embedded(chrono_batch_render_material_surface,
289 chrono_batch_render_material_surface_size)
290 11 : Embedded(chrono_batch_render_material_standard,
291 chrono_batch_render_material_standard_size),
292
3/3
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 11 times.
✓ Branch 5 taken 14 times.
28 {{"type", type}, {"body", body}});
293
1/1
✓ Branch 5 taken 14 times.
14 module.source = FillTemplate(Embedded(chrono_batch_render_material_definition,
294 chrono_batch_render_material_definition_size),
295 14 {{"node", top.name},
296 {"imports", imports},
297 {"type", type},
298 {"fields", fields},
299 14 {"definition", definition}});
300 14 return module;
301 28 }
302
303 std::map<std::string, std::string, std::less<>>
304 351 ClosurePrimitiveSources(std::span<const std::shared_ptr<const ClosurePrimitive>> primitives) {
305
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 267 times.
351 std::map<std::string, std::string, std::less<>> sources;
306
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 267 times.
351 if (primitives.empty()) {
307 return sources;
308 }
309 84 std::string imports;
310 84 std::string kinds;
311 84 std::string glossy;
312 84 std::string estimate;
313 84 std::string evaluate;
314 84 std::string pdf;
315 84 std::string direction;
316
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 84 times.
169 for (const std::shared_ptr<const ClosurePrimitive>& primitive : primitives) {
317
3/3
✓ Branch 1 taken 85 times.
✓ Branch 4 taken 85 times.
✓ Branch 7 taken 85 times.
170 sources[ModulePath(primitive->module)] = primitive->source;
318
1/1
✓ Branch 1 taken 85 times.
170 imports += fmt::format("import {};\n", primitive->module);
319
1/1
✓ Branch 1 taken 85 times.
170 kinds += fmt::format("static const uint kLobe{} = {};\n", primitive->name, primitive->kind);
320 510 const auto add = [&](std::string& cases, std::string_view call) {
321 850 cases += fmt::format(" case {}:\n return {}.{};\n", primitive->kind,
322 850 primitive->name, call);
323 425 };
324
1/1
✓ Branch 1 taken 85 times.
85 add(glossy, "Glossy()");
325
1/1
✓ Branch 1 taken 85 times.
85 add(estimate, "Estimate<Spectrum>(tint, alpha, params.values, outgoing)");
326
1/1
✓ Branch 1 taken 85 times.
85 add(evaluate, "Evaluate<Spectrum>(tint, alpha, params.values, outgoing, incoming)");
327
1/1
✓ Branch 1 taken 85 times.
85 add(pdf, "Pdf(alpha, params.values, outgoing, incoming)");
328
1/1
✓ Branch 1 taken 85 times.
85 add(direction, "Direction(alpha, params.values, outgoing, u)");
329 }
330
3/3
✓ Branch 9 taken 84 times.
✓ Branch 12 taken 84 times.
✓ Branch 15 taken 84 times.
252 sources[kRegisteredFile] = FillTemplate(Embedded(chrono_batch_render_material_registered,
331 chrono_batch_render_material_registered_size),
332 {{"imports", imports},
333 84 {"firstLobe", std::to_string(kFirstPrimitiveLobe)},
334 {"kinds", kinds},
335 {"glossy", glossy},
336 {"estimate", estimate},
337 {"evaluate", evaluate},
338 {"pdf", pdf},
339 84 {"direction", direction}});
340 84 return sources;
341 84 }
342
343 std::map<std::string, std::string, std::less<>>
344 215 MaterialDispatchSources(const MaterialDefinitionSet& set) {
345 215 std::map<std::string, std::string, std::less<>> sources(set.Files().begin(), set.Files().end());
346
3/3
✓ Branch 1 taken 215 times.
✓ Branch 4 taken 215 times.
✓ Branch 7 taken 215 times.
215 sources[kDispatchFile] = Dispatch(set);
347
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 210 times.
215 if (set.Planetary()) {
348
3/3
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
✓ Branch 7 taken 5 times.
5 sources[kLobesFile] = "static const bool kPhotometricLobes = true;\n";
349 }
350
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 215 times.
235 for (const MaterialDefinition& definition : set.Definitions()) {
351
3/3
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
✓ Branch 7 taken 20 times.
40 sources[ModulePath(definition.module)] = definition.source;
352
3/3
✓ Branch 1 taken 19 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 20 times.
39 for (const auto& [path, source] : definition.files) {
353
2/2
✓ Branch 1 taken 19 times.
✓ Branch 4 taken 19 times.
38 sources[path] = source;
354 }
355 }
356 215 return sources;
357 ✗ }
358
359 669 MaterialDefinitionSet::MaterialDefinitionSet(std::vector<MaterialDefinition> definitions,
360 std::map<std::string, std::string, std::less<>> files,
361 669 bool planetary)
362 669 : m_definitions(std::move(definitions)), m_files(std::move(files)), m_planetary(planetary),
363 669 m_hash(kFnvBasis) {
364
3/3
✓ Branch 0 taken 653 times.
✓ Branch 1 taken 16 times.
✓ Branch 3 taken 669 times.
1322 m_hash = Fnv1a(planetary ? "planetary" : "", m_hash);
365
3/3
✓ Branch 1 taken 142 times.
✓ Branch 3 taken 142 times.
✓ Branch 4 taken 669 times.
811 for (const auto& [path, source] : m_files) {
366
1/1
✓ Branch 1 taken 142 times.
142 m_hash = Fnv1a(path, m_hash);
367
1/1
✓ Branch 1 taken 142 times.
142 m_hash = Fnv1a(source, m_hash);
368 }
369 669 std::ranges::sort(m_definitions, {}, &MaterialDefinition::id);
370
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 669 times.
690 for (const MaterialDefinition& definition : m_definitions) {
371
1/1
✓ Branch 2 taken 21 times.
21 m_hash = Fnv1a(std::to_string(definition.id), m_hash);
372
1/1
✓ Branch 1 taken 21 times.
21 m_hash = Fnv1a(definition.type, m_hash);
373
1/1
✓ Branch 1 taken 21 times.
21 m_hash = Fnv1a(definition.source, m_hash);
374
3/3
✓ Branch 1 taken 20 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 21 times.
41 for (const auto& [path, source] : definition.files) {
375
1/1
✓ Branch 1 taken 20 times.
20 m_hash = Fnv1a(path, m_hash);
376
1/1
✓ Branch 1 taken 20 times.
20 m_hash = Fnv1a(source, m_hash);
377 }
378 }
379 669 }
380
381 8 bool MaterialDefinitionSet::Contains(uint32_t id) const {
382
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 if (id >= kFirstPlanetaryDefinition && id < kFirstGeneratedDefinition) {
383 3 return m_planetary;
384 }
385
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
8 return id < kFirstGeneratedDefinition ||
386 3 std::ranges::binary_search(m_definitions, id, {}, &MaterialDefinition::id);
387 }
388
389 }
390