chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
249 / 261
95.4%
Branches:
259 / 293
88.4%
Functions:
21 / 21
100.0%

scene/tables/textures.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/scene/tables/textures.h"
3
4 #include <algorithm>
5 #include <span>
6 #include <string>
7
8 #include "chrono_batch_render/io/image.h"
9 #include "chrono_batch_render/scene/records/render_tables.h"
10 #include "chrono_batch_render/scene/schema/columns.h"
11 #include "chrono_batch_render/stage/publish/change_set.h"
12 #include "chrono_batch_render/util/profiler.h"
13
14 namespace chrono::batch_render {
15 namespace {
16
17 54 TextureWrap Wrap(TextureWrapMode mode) {
18
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 2 times.
54 switch (mode) {
19 case TextureWrapMode::Black:
20 return TextureWrap::Border;
21 ✗ case TextureWrapMode::Clamp:
22 ✗ return TextureWrap::Clamp;
23 ✗ case TextureWrapMode::Mirror:
24 ✗ return TextureWrap::Mirror;
25 52 default:
26 52 return TextureWrap::Repeat;
27 }
28 }
29
30 }
31
32 namespace {
33
34 360 std::map<SchemaId, std::vector<TextureSlot>> MaterialSlots() {
35
1/1
✓ Branch 1 taken 360 times.
360 std::map<SchemaId, std::vector<TextureSlot>> materials;
36 720 materials[SchemaId::UsdUVTexture] = {
37
2/2
✓ Branch 1 taken 360 times.
✓ Branch 4 taken 360 times.
360 {.table = SchemaId::UsdUVTexture, .texture = kUsdUVTextureFile.index, .color = true}};
38 720 materials[SchemaId::DomeLight] = {
39
2/2
✓ Branch 1 taken 360 times.
✓ Branch 4 taken 360 times.
360 {.table = SchemaId::DomeLight, .texture = kDomeLightTextureFile.index, .color = true}};
40 3240 for (const SchemaId light : {SchemaId::SphereLight, SchemaId::RectLight, SchemaId::DiskLight,
41
2/2
✓ Branch 0 taken 1440 times.
✓ Branch 1 taken 360 times.
1800 SchemaId::CylinderLight}) {
42 1440 materials[light] = {{.table = SchemaId::ShapingAPI,
43 .texture = kShapingAPIShapingIesFile.index,
44
2/2
✓ Branch 1 taken 1440 times.
✓ Branch 4 taken 1440 times.
1440 .color = false}};
45 }
46
2/2
✓ Branch 1 taken 360 times.
✓ Branch 4 taken 360 times.
360 materials[SchemaId::RectLight].push_back(
47 {.table = SchemaId::RectLight, .texture = kRectLightTextureFile.index, .color = true});
48 360 return materials;
49 ✗ }
50
51 360 std::vector<ColumnRef> InputColumns(const std::map<SchemaId, std::vector<TextureSlot>>& materials) {
52 360 std::vector<ColumnRef> inputs = {kUsdUVTextureWrapS, kUsdUVTextureWrapT,
53 360 kUsdUVTextureSourceColorSpace, kCheckerboardAPICheckerboard};
54
2/2
✓ Branch 0 taken 2160 times.
✓ Branch 1 taken 360 times.
2520 for (const auto& [schema, slots] : materials) {
55
2/2
✓ Branch 0 taken 2520 times.
✓ Branch 1 taken 2160 times.
4680 for (const TextureSlot& slot : slots) {
56
1/1
✓ Branch 1 taken 2520 times.
2520 const ColumnRef column = {slot.table, &Columns(slot.table)[slot.texture], slot.texture};
57
2/2
✓ Branch 1 taken 1440 times.
✓ Branch 2 taken 1080 times.
2520 if (std::ranges::none_of(inputs,
58
2/2
✓ Branch 0 taken 13320 times.
✓ Branch 1 taken 1080 times.
14400 [&](ColumnRef c) { return c.column == column.column; })) {
59
1/1
✓ Branch 1 taken 1440 times.
1440 inputs.push_back(column);
60 }
61 }
62 }
63 360 return inputs;
64 ✗ }
65
66 }
67
68 360 TextureTable::TextureTable(Structure& structure, unsigned threads)
69 360 : m_structure(structure),
70 ✗ m_cache(
71
1/1
✓ Branch 1 taken 360 times.
360 structure.GetColumnStore().GetDevice(),
72
1/1
✓ Branch 1 taken 360 times.
382 [&structure](const std::string& path) { return structure.FindFile(path); }, threads),
73
5/5
✓ Branch 1 taken 360 times.
✓ Branch 4 taken 360 times.
✓ Branch 7 taken 360 times.
✓ Branch 10 taken 360 times.
✓ Branch 15 taken 360 times.
720 m_slots(MaterialSlots()), m_inputs(InputColumns(m_slots)) {
74
1/1
✓ Branch 1 taken 360 times.
360 UploadBindings();
75 360 }
76
77 360 TextureTable::~TextureTable() = default;
78
79 501 void TextureTable::Describe(RenderTables& tables) const {
80
1/2
✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
501 tables.textures.address = m_records.Buffer() ? m_records.Buffer()->Address() : 0;
81 501 tables.textureBindings.address = m_bindingAddress;
82 501 }
83
84 946 void TextureTable::Hold(std::vector<Ref<const RefCounted>>& held) const {
85
4/8
✓ Branch 0 taken 946 times.
✓ Branch 1 taken 946 times.
✓ Branch 2 taken 945 times.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1892 HoldBuffers(held, {m_records.Buffer()});
86 1892 }
87
88 8679 bool TextureTable::Pending() const {
89 8679 return m_cache.Pending();
90 }
91
92 692 void TextureTable::Finish() {
93 692 m_cache.Finish();
94 692 }
95
96 31 uint64_t TextureTable::Handle(uint32_t prim, std::string_view input) const {
97 31 const auto found = m_materials.find(prim);
98
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 if (found == m_materials.end()) {
99 return 0;
100 }
101
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 for (const Bound& bound : found->second.slots) {
102
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 if (Columns(bound.slot.table)[bound.slot.texture].field == input) {
103 31 return bound.binding.handle;
104 }
105 }
106 ✗ return 0;
107 }
108
109 861 void TextureTable::UploadBindings() {
110 861 const uint64_t address = m_cache.UploadBindings();
111 861 m_bindingAddress = address;
112 861 }
113
114 501 std::set<uint32_t> TextureTable::Collect() {
115 501 const std::set<TextureKey> finished = m_cache.Collect();
116 501 std::set<uint32_t> dirty;
117
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 501 times.
527 for (const TextureKey& key : finished) {
118
2/2
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 26 times.
84 for (const auto& [prim, material] : m_materials) {
119 29 if (std::ranges::any_of(material.slots,
120
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 23 times.
53 [&](const Bound& bound) { return bound.binding.key == key; }) ||
121
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
6 (material.checkered && key.first == kCheckerboardTexture)) {
122
1/1
✓ Branch 1 taken 28 times.
28 dirty.insert(prim);
123 }
124 }
125 }
126 501 return dirty;
127 501 }
128
129 22 void TextureTable::Refresh(uint32_t prim) {
130 22 Material& material = m_materials.at(prim);
131 22 bool resolved = false;
132
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 for (Bound& bound : material.slots) {
133
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (bound.binding.handle == 0) {
134 22 m_cache.Resolve(bound.binding);
135
3/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 18 times.
22 resolved = resolved || bound.binding.handle != 0;
136 }
137 }
138
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 if (!resolved) {
139 return;
140 }
141
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (material.bindings == kNoTextures) {
142 18 material.bindings = m_cache.AllocateBindings(uint32_t(material.slots.size()));
143 }
144
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 for (uint32_t index = 0; index < material.slots.size(); ++index) {
145 18 m_cache.SetBinding(material.bindings + index, material.slots[index].binding.handle);
146 }
147 18 Publish(prim, material);
148 }
149
150 142 void TextureTable::Publish(uint32_t prim, const Material& material) {
151 142 const Prims& prims = m_structure.GetPrims();
152 142 const SchemaId schema = prims.Record(prim).schema;
153 142 TextureRecord record{};
154
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 82 times.
142 if (schema == SchemaId::UsdUVTexture || schema == SchemaId::DomeLight) {
155 60 record.textures = material.bindings;
156 }
157
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 142 times.
233 for (uint32_t index = 0; index < material.slots.size(); ++index) {
158
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 71 times.
91 const SchemaId table = material.slots[index].slot.table;
159 182 const uint32_t binding =
160
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 71 times.
91 material.bindings == kNoTextures ? kNoTextures : material.bindings + index;
161
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 63 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 27 times.
91 if (table == SchemaId::ShapingAPI && prims.HasApi(prim, SchemaId::ShapingAPI)) {
162 1 record.shaping = binding;
163
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 87 times.
90 } else if (table == SchemaId::RectLight) {
164 3 record.textures = binding;
165 }
166 }
167
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 15 times.
142 if (schema == SchemaId::DomeLight && material.bindings != kNoTextures) {
168
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (const auto found = m_cache.Size(material.slots[0].binding.key)) {
169 2 record.width = found->first;
170 2 record.height = found->second;
171 }
172 }
173 142 m_records.Set(prim, record);
174 142 Rebound(prims.Record(prim).world);
175 142 }
176
177 465 void TextureTable::Rebound(uint32_t world) {
178
2/2
✓ Branch 1 taken 352 times.
✓ Branch 2 taken 113 times.
465 if (std::ranges::find(m_rebound, world) == m_rebound.end()) {
179 352 m_rebound.push_back(world);
180 }
181 465 }
182
183 266 void TextureTable::Release(uint32_t prim) {
184 266 const auto found = m_materials.find(prim);
185
2/2
✓ Branch 0 taken 254 times.
✓ Branch 1 taken 12 times.
266 if (found == m_materials.end()) {
186 254 return;
187 }
188 12 m_records.Set(prim, TextureRecord{});
189 12 const Prims& prims = m_structure.GetPrims();
190
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 1 time.
12 if (prims.Alive(prim)) {
191 11 Rebound(prims.Record(prim).world);
192 } else {
193 1 Rebound(kGlobalWorld);
194 }
195 12 const Material& material = found->second;
196
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
18 for (const Bound& bound : material.slots) {
197 6 m_cache.Unbind(bound.binding);
198 }
199
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 if (material.bindings != kNoTextures) {
200 5 m_cache.FreeBindings(material.bindings, uint32_t(material.slots.size()));
201 }
202
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
12 if (material.checkered && --m_checkerUsers == 0) {
203 4 m_cache.Unbind(m_checker);
204 4 m_checker = {};
205 4 m_cache.SetBinding(kCheckerTextureBinding, 0);
206 }
207
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (const RowKey& row : material.rows) {
208 12 m_byRow.erase(row);
209 }
210 12 m_materials.erase(found);
211 4 }
212
213 181 const std::vector<uint32_t>& TextureTable::Read(Cells& cells, SchemaId table, uint32_t column) {
214
2/2
✓ Branch 1 taken 169 times.
✓ Branch 2 taken 12 times.
181 auto [found, added] = cells.columns.try_emplace({table, column});
215
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 12 times.
181 if (added) {
216 169 ColumnTable& rows = m_structure.GetColumnStore().Schema(table);
217
1/1
✓ Branch 2 taken 169 times.
338 found->second = Items<uint32_t>(rows.Read(column, 0, rows.Rows()));
218 }
219 181 return found->second;
220 }
221
222 124 void TextureTable::Rebind(uint32_t prim, Cells& cells) {
223 124 const Prims& prims = m_structure.GetPrims();
224 124 const SchemaId schema = prims.Record(prim).schema;
225 124 Material material;
226 124 TextureWrap wrapS = TextureWrap::Clamp;
227 124 TextureWrap wrapT = TextureWrap::Clamp;
228 124 TextureColorSpace space = TextureColorSpace::Auto;
229
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 97 times.
124 if (schema == SchemaId::UsdUVTexture) {
230
1/1
✓ Branch 1 taken 27 times.
27 const uint32_t row = prims.Row(prim, SchemaId::UsdUVTexture);
231 54 wrapS = Wrap(
232
2/2
✓ Branch 1 taken 27 times.
✓ Branch 4 taken 27 times.
27 TextureWrapMode(Read(cells, SchemaId::UsdUVTexture, kUsdUVTextureWrapS.index)[row]));
233 54 wrapT = Wrap(
234
2/2
✓ Branch 1 taken 27 times.
✓ Branch 4 taken 27 times.
27 TextureWrapMode(Read(cells, SchemaId::UsdUVTexture, kUsdUVTextureWrapT.index)[row]));
235 27 space = TextureColorSpace(
236
1/1
✓ Branch 1 taken 27 times.
27 Read(cells, SchemaId::UsdUVTexture, kUsdUVTextureSourceColorSpace.index)[row]);
237 }
238
1/1
✓ Branch 1 taken 124 times.
124 TextureBinding checker;
239
3/3
✓ Branch 1 taken 124 times.
✓ Branch 3 taken 54 times.
✓ Branch 4 taken 70 times.
124 if (IsA(schema, SchemaId::Plane)) {
240
1/1
✓ Branch 1 taken 54 times.
54 const uint32_t row = prims.Row(prim, SchemaId::CheckerboardAPI);
241 108 material.checkered =
242
3/3
✓ Branch 1 taken 54 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 44 times.
54 Read(cells, SchemaId::CheckerboardAPI, kCheckerboardAPICheckerboard.index)[row] != 0;
243
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 44 times.
54 if (material.checkered) {
244
2/2
✓ Branch 1 taken 10 times.
✓ Branch 5 taken 10 times.
20 checker = m_cache.Bind({std::string(kCheckerboardTexture), false}, TextureWrap::Repeat,
245 10 TextureWrap::Repeat);
246 }
247
1/1
✓ Branch 1 taken 54 times.
54 material.rows.push_back({SchemaId::CheckerboardAPI, row});
248 }
249 124 const auto slots = m_slots.find(schema);
250
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 54 times.
124 if (slots != m_slots.end()) {
251
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 70 times.
143 for (const TextureSlot& slot : slots->second) {
252
6/6
✓ Branch 1 taken 73 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 45 times.
✓ Branch 6 taken 28 times.
✓ Branch 8 taken 27 times.
✓ Branch 9 taken 1 time.
73 if (IsApi(slot.table) && !prims.HasApi(prim, slot.table)) {
253 27 material.slots.push_back({slot, {}});
254 27 continue;
255 }
256
1/1
✓ Branch 1 taken 46 times.
46 const uint32_t row = prims.Row(prim, slot.table);
257
1/1
✓ Branch 1 taken 46 times.
46 std::string path(
258
4/5
✓ Branch 1 taken 46 times.
✓ Branch 4 taken 46 times.
✓ Branch 7 taken 46 times.
✓ Branch 9 taken 46 times.
✗ Branch 10 not taken.
46 m_structure.GetTokens().Text(Token{Read(cells, slot.table, slot.texture)[row]}));
259
3/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 2 times.
46 const bool srgb = space == TextureColorSpace::SRGB ||
260
6/6
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 1 time.
67 (space == TextureColorSpace::Auto && slot.color && !path.empty() &&
261
2/4
✓ Branch 1 taken 23 times.
✓ Branch 4 taken 23 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
46 IsPngOrJpeg(path));
262
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 31 times.
46 if (schema == SchemaId::DomeLight) {
263 15 wrapS = TextureWrap::Repeat;
264 15 wrapT = TextureWrap::Repeat;
265 }
266 46 material.slots.push_back({slot, m_cache.Bind({std::move(path), srgb}, wrapS, wrapT)});
267
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (std::ranges::find(material.rows, RowKey{slot.table, row}) == material.rows.end()) {
268
1/1
✓ Branch 1 taken 46 times.
46 material.rows.push_back({slot.table, row});
269 }
270 46 }
271 }
272
273
1/1
✓ Branch 1 taken 124 times.
124 Release(prim);
274
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 114 times.
124 if (material.checkered) {
275
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
10 if (m_checkerUsers++ == 0 || m_checker.handle == 0) {
276
1/1
✓ Branch 1 taken 9 times.
9 m_cache.Unbind(m_checker);
277
1/1
✓ Branch 1 taken 9 times.
9 m_checker = checker;
278
1/1
✓ Branch 1 taken 9 times.
9 m_cache.SetBinding(kCheckerTextureBinding, m_checker.handle);
279 } else {
280
1/1
✓ Branch 1 taken 1 time.
1 m_cache.Unbind(checker);
281 }
282 }
283
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 122 times.
124 if (std::ranges::any_of(material.slots,
284
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 2 times.
73 [](const Bound& bound) { return bound.binding.handle != 0; })) {
285
1/1
✓ Branch 1 taken 2 times.
2 material.bindings = m_cache.AllocateBindings(uint32_t(material.slots.size()));
286
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (uint32_t index = 0; index < material.slots.size(); ++index) {
287
1/1
✓ Branch 1 taken 2 times.
2 m_cache.SetBinding(material.bindings + index, material.slots[index].binding.handle);
288 }
289 }
290
1/1
✓ Branch 1 taken 124 times.
124 Publish(prim, material);
291
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 124 times.
224 for (const RowKey& row : material.rows) {
292
1/1
✓ Branch 1 taken 100 times.
100 m_byRow[row] = prim;
293 }
294
2/2
✓ Branch 1 taken 124 times.
✓ Branch 4 taken 124 times.
124 m_structure.GetColumnStore().StampWorld(prims.Record(prim).world);
295
1/1
✓ Branch 1 taken 124 times.
124 m_materials[prim] = std::move(material);
296 367 }
297
298 501 void TextureTable::Run(const ChangeSet& changes, TableVersions& versions) {
299
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 496 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
501 CHRONO_BATCH_RENDER_ZONE("Textures/Run");
300
1/1
✓ Branch 1 taken 501 times.
501 const Prims& prims = m_structure.GetPrims();
301 7737 const auto textured = [&](uint32_t prim) {
302
6/6
✓ Branch 1 taken 7220 times.
✓ Branch 2 taken 16 times.
✓ Branch 5 taken 7082 times.
✓ Branch 6 taken 138 times.
✓ Branch 7 taken 102 times.
✓ Branch 8 taken 6980 times.
14318 return prims.Alive(prim) && (m_slots.contains(prims.Record(prim).schema) ||
303 7082 IsA(prims.Record(prim).schema, SchemaId::Plane));
304 501 };
305
306
1/1
✓ Branch 1 taken 501 times.
501 const std::set<uint32_t> loaded = Collect();
307
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 220 times.
501 std::set<uint32_t> dirty;
308
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 220 times.
501 if (changes.resync) {
309
2/2
✓ Branch 0 taken 1865 times.
✓ Branch 1 taken 281 times.
2146 for (uint32_t prim = 0; prim < prims.Size(); ++prim) {
310
3/3
✓ Branch 1 taken 1865 times.
✓ Branch 3 taken 109 times.
✓ Branch 4 taken 1756 times.
1865 if (textured(prim)) {
311
1/1
✓ Branch 1 taken 109 times.
109 dirty.insert(prim);
312 }
313 }
314 } else {
315
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 220 times.
362 for (const StructureEntry& entry : changes.removed) {
316
1/1
✓ Branch 1 taken 142 times.
142 Release(entry.prim);
317 142 dirty.erase(entry.prim);
318 }
319
2/2
✓ Branch 0 taken 5247 times.
✓ Branch 1 taken 220 times.
5467 for (const StructureEntry& entry : changes.added) {
320
5/6
✓ Branch 1 taken 5247 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 5240 times.
✓ Branch 6 taken 7 times.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
5247 if (textured(entry.prim) && prims.Generation(entry.prim) == entry.generation) {
321
1/1
✓ Branch 1 taken 7 times.
7 dirty.insert(entry.prim);
322 }
323 }
324
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 220 times.
232 for (const StructureEntry& entry : changes.apis) {
325
1/5
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
12 if (entry.api == SchemaId::ShapingAPI && textured(entry.prim) &&
326
0/3
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ prims.Generation(entry.prim) == entry.generation) {
327
0/1
✗ Branch 1 not taken.
✗ dirty.insert(entry.prim);
328 }
329 }
330
2/2
✓ Branch 0 taken 1760 times.
✓ Branch 1 taken 220 times.
1980 for (const ColumnRef column : m_inputs) {
331
1/1
✓ Branch 1 taken 1760 times.
1760 const ChangedRows* rows = changes.Rows(column);
332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1760 times.
1760 if (rows == nullptr) {
333 ✗ continue;
334 }
335
3/3
✓ Branch 1 taken 1760 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 1760 times.
1786 for (const uint32_t row : rows->ToHost()) {
336
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 20 times.
26 if (const auto prim = m_byRow.find({column.schema, row}); prim != m_byRow.end()) {
337
1/1
✓ Branch 1 taken 6 times.
6 dirty.insert(prim->second);
338 }
339 1760 }
340 }
341 }
342
343
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 501 times.
529 for (const uint32_t prim : loaded) {
344 28 const auto material = m_materials.find(prim);
345
3/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 1 time.
28 if (dirty.contains(prim) || material == m_materials.end()) {
346 1 continue;
347 }
348
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 22 times.
27 if (material->second.checkered) {
349
1/1
✓ Branch 1 taken 5 times.
5 dirty.insert(prim);
350 } else {
351
1/1
✓ Branch 1 taken 22 times.
22 Refresh(prim);
352 }
353 }
354
355 501 Cells cells;
356
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 501 times.
625 for (const uint32_t prim : dirty) {
357
2/3
✓ Branch 1 taken 124 times.
✓ Branch 3 taken 124 times.
✗ Branch 4 not taken.
124 if (textured(prim)) {
358
1/1
✓ Branch 1 taken 124 times.
124 Rebind(prim, cells);
359 } else {
360
0/1
✗ Branch 1 not taken.
✗ Release(prim);
361 }
362 }
363
1/1
✓ Branch 1 taken 501 times.
501 UploadBindings();
364
1/1
✓ Branch 1 taken 501 times.
501 m_records.Reserve(prims.Size());
365
3/3
✓ Branch 1 taken 501 times.
✓ Branch 3 taken 311 times.
✓ Branch 4 taken 190 times.
501 if (m_records.Upload(m_structure.GetColumnStore().GetDevice())) {
366
1/1
✓ Branch 1 taken 311 times.
311 Rebound(kGlobalWorld);
367 }
368
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 161 times.
501 if (!m_rebound.empty()) {
369
1/1
✓ Branch 1 taken 340 times.
340 versions.Record(TableId::Textures, m_rebound);
370 }
371 501 m_rebound.clear();
372
373
1/1
✓ Branch 1 taken 501 times.
501 m_stats.images = m_cache.Images();
374
1/1
✓ Branch 1 taken 501 times.
501 m_stats.loaded = m_cache.Loaded();
375
1/1
✓ Branch 1 taken 501 times.
501 m_stats.failed = m_cache.Failed();
376
1/1
✓ Branch 1 taken 501 times.
501 m_stats.loading = m_cache.Loading();
377 501 m_stats.bound = 0;
378
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 501 times.
831 for (const auto& [prim, material] : m_materials) {
379
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 165 times.
278 for (const Bound& bound : material.slots) {
380
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 25 times.
201 m_stats.bound += bound.binding.handle != 0 ? 1 : 0;
381 }
382 }
383 501 }
384
385 }
386