Line data Source code
1 : /**
2 : Copyright (c) 2021-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "XLCoreMaterial.h"
25 : #include "XLCoreDynamicImage.h"
26 : #include "XLCoreLoop.h"
27 : #include "XLCoreDevice.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
30 :
31 1850 : MaterialSet::~MaterialSet() {
32 925 : clear();
33 1850 : }
34 :
35 16 : bool MaterialSet::init(const BufferInfo &info, const EncodeCallback &callback,
36 : uint32_t objectSize, uint32_t imagesInSet, uint32_t buffersInSet, const MaterialAttachment *owner) {
37 16 : _info = info;
38 16 : _encodeCallback = callback;
39 16 : _objectSize = objectSize;
40 16 : _imagesInSet = imagesInSet;
41 16 : _buffersInSet = buffersInSet;
42 16 : _info.size = 0;
43 16 : _owner = owner;
44 16 : return true;
45 : }
46 :
47 909 : bool MaterialSet::init(const Rc<MaterialSet> &other) {
48 909 : _info = other->_info;
49 909 : _encodeCallback = other->_encodeCallback;
50 909 : _generation = other->_generation + 1;
51 909 : _materials = other->_materials;
52 909 : _objectSize = other->_objectSize;
53 909 : _imagesInSet = other->_imagesInSet;
54 909 : _buffersInSet = other->_buffersInSet;
55 909 : _layouts = other->_layouts;
56 909 : _owner = other->_owner;
57 909 : _buffer = other->_buffer;
58 :
59 1818 : for (auto &it : _layouts) {
60 909 : it.set = nullptr;
61 : }
62 :
63 909 : return true;
64 : }
65 :
66 7293 : bool MaterialSet::encode(uint8_t *buf, const Material *material) {
67 7293 : if (_encodeCallback) {
68 7293 : return _encodeCallback(buf, material);
69 : }
70 0 : return false;
71 : }
72 :
73 1834 : void MaterialSet::clear() { }
74 :
75 0 : Vector<Rc<Material>> MaterialSet::updateMaterials(const Rc<MaterialInputData> &data,
76 : const Callback<Rc<ImageView>(const MaterialImage &)> &cb) {
77 0 : return updateMaterials(data->materialsToAddOrUpdate, data->dynamicMaterialsToUpdate, data->materialsToRemove, cb);
78 : }
79 :
80 925 : Vector<Rc<Material>> MaterialSet::updateMaterials(const Vector<Rc<Material>> &materials, SpanView<MaterialId> dynamicMaterials,
81 : SpanView<MaterialId> materialsToRemove, const Callback<Rc<ImageView>(const MaterialImage &)> &cb) {
82 925 : Vector<MaterialId> updatedIds; updatedIds.reserve(materials.size() + dynamicMaterials.size());
83 925 : Vector<Rc<Material>> ret; ret.reserve(materials.size());
84 :
85 947 : for (auto &it : materialsToRemove) {
86 22 : auto mIt = _materials.find(it);
87 22 : if (mIt != _materials.end()) {
88 22 : ret.emplace_back(mIt->second);
89 22 : removeMaterial(mIt->second);
90 44 : for (auto &it : mIt->second->getImages()) {
91 22 : if (it.dynamic && _owner) {
92 0 : _owner->removeDynamicTracker(mIt->second->getId(), it.dynamic->image);
93 : }
94 : }
95 22 : _materials.erase(mIt);
96 : }
97 : }
98 :
99 1091 : for (auto &material : materials) {
100 166 : bool isImagesValid = true;
101 :
102 166 : if (!materialsToRemove.empty()) {
103 0 : auto it = std::find(materialsToRemove.begin(), materialsToRemove.end(), material->getId());
104 0 : if (it != materialsToRemove.end()) {
105 0 : continue;
106 : }
107 : }
108 :
109 332 : for (auto &it : material->_images) {
110 166 : if (!it.image) {
111 0 : isImagesValid = false;
112 : }
113 166 : if (it.dynamic) {
114 : // try to actualize image
115 16 : auto current = it.dynamic->image->getInstance();
116 16 : if (current != it.dynamic) {
117 0 : if (material->_atlas == it.image->atlas) {
118 0 : material->_atlas = current->data.atlas;
119 : }
120 0 : it.dynamic = current;
121 0 : it.image = &it.dynamic->data;
122 : }
123 16 : if (_owner) {
124 16 : _owner->addDynamicTracker(material->getId(), it.dynamic->image);
125 : }
126 16 : }
127 : }
128 :
129 166 : if (!isImagesValid) {
130 0 : continue;
131 : }
132 :
133 166 : updatedIds.emplace_back(material->getId());
134 :
135 166 : auto mIt = _materials.find(material->getId());
136 166 : if (mIt != _materials.end()) {
137 0 : emplaceMaterialImages(mIt->second, material.get(), cb);
138 0 : mIt->second = move(material);
139 0 : ret.emplace_back(mIt->second.get());
140 0 : for (auto &it : mIt->second->getImages()) {
141 0 : if (it.dynamic && _owner) {
142 0 : _owner->removeDynamicTracker(material->getId(), it.dynamic->image);
143 : }
144 : }
145 : } else {
146 166 : auto it = _materials.emplace(material->getId(), move(material)).first;
147 166 : emplaceMaterialImages(nullptr, it->second.get(), cb);
148 166 : ret.emplace_back(it->second.get());
149 : }
150 : }
151 :
152 1737 : for (auto &it : dynamicMaterials) {
153 812 : if (!materialsToRemove.empty()) {
154 0 : auto iit = std::find(materialsToRemove.begin(), materialsToRemove.end(), it);
155 0 : if (iit != materialsToRemove.end()) {
156 0 : continue;
157 : }
158 : }
159 :
160 812 : auto mIt = _materials.find(it);
161 812 : if (mIt != _materials.end()) {
162 812 : auto &material = mIt->second;
163 812 : bool hasUpdates = false;
164 812 : Vector<Rc<DynamicImageInstance>> dynamics;
165 812 : dynamics.reserve(mIt->second->getImages().size());
166 :
167 1624 : for (auto &image : mIt->second->getImages()) {
168 812 : if (image.dynamic) {
169 812 : auto current = image.dynamic->image->getInstance();
170 812 : if (current != image.dynamic) {
171 812 : hasUpdates = true;
172 812 : dynamics.emplace_back(current);
173 : } else {
174 0 : dynamics.emplace_back(nullptr);
175 : }
176 812 : } else {
177 0 : dynamics.emplace_back(nullptr);
178 : }
179 : }
180 :
181 812 : if (hasUpdates) {
182 : // create new material
183 812 : Vector<MaterialImage> images = material->getImages();
184 812 : size_t i = 0;
185 1624 : for (auto &it : images) {
186 812 : if (auto v = dynamics[i]) {
187 812 : it.dynamic = v;
188 812 : it.image = &v->data;
189 812 : }
190 812 : it.view = nullptr;
191 812 : ++ i;
192 : }
193 :
194 812 : auto mat = Rc<Material>::create(material, move(images));
195 :
196 1624 : for (auto &it : mat->getImages()) {
197 812 : if (it.dynamic && _owner) {
198 812 : _owner->addDynamicTracker(mat->getId(), it.dynamic->image);
199 : }
200 : }
201 :
202 812 : emplaceMaterialImages(mIt->second, mat.get(), cb);
203 812 : mIt->second = move(mat);
204 812 : ret.emplace_back(mIt->second.get());
205 1624 : for (auto &it : mIt->second->getImages()) {
206 812 : if (it.dynamic && _owner) {
207 812 : _owner->removeDynamicTracker(material->getId(), it.dynamic->image);
208 : }
209 : }
210 812 : }
211 812 : }
212 : }
213 :
214 925 : _info.size = _objectSize * _materials.size();
215 :
216 925 : if (_info.size == 0 || ret.size() == 0) {
217 0 : return Vector<Rc<Material>>();
218 : }
219 925 : return ret;
220 925 : }
221 :
222 925 : void MaterialSet::setBuffer(Rc<BufferObject> &&buffer, std::unordered_map<MaterialId, uint32_t> &&ordering) {
223 925 : _buffer = move(buffer);
224 925 : _ordering = move(ordering);
225 925 : }
226 :
227 7322 : const MaterialLayout *MaterialSet::getLayout(uint32_t idx) const {
228 7322 : if (idx < _layouts.size()) {
229 7322 : return &_layouts[idx];
230 : }
231 0 : return nullptr;
232 : }
233 :
234 242982 : const Material * MaterialSet::getMaterialById(MaterialId idx) const {
235 242982 : auto it = _materials.find(idx);
236 242982 : if (it != _materials.end()) {
237 242982 : return it->second.get();
238 : }
239 0 : return nullptr;
240 : }
241 :
242 33679 : uint32_t MaterialSet::getMaterialOrder(MaterialId idx) const {
243 33679 : auto it = _ordering.find(idx);
244 33679 : if (it != _ordering.end()) {
245 33679 : return it->second;
246 : }
247 0 : return maxOf<uint32_t>();
248 : }
249 :
250 22 : void MaterialSet::removeMaterial(Material *oldMaterial) {
251 22 : auto &oldSet = _layouts[oldMaterial->getLayoutIndex()];
252 44 : for (auto &oIt : oldMaterial->_images) {
253 22 : -- oldSet.imageSlots[oIt.descriptor].refCount;
254 22 : if (oldSet.imageSlots[oIt.descriptor].refCount == 0) {
255 16 : oldSet.imageSlots[oIt.descriptor].image = nullptr;
256 : }
257 22 : oIt.view = nullptr;
258 : }
259 22 : }
260 :
261 978 : void MaterialSet::emplaceMaterialImages(Material *oldMaterial, Material *newMaterial,
262 : const Callback<Rc<ImageView>(const MaterialImage &)> &cb) {
263 978 : Vector<MaterialImage> *oldImages = nullptr;
264 978 : uint32_t targetSet = maxOf<uint32_t>();
265 978 : if (oldMaterial) {
266 812 : targetSet = oldMaterial->getLayoutIndex();
267 812 : oldImages = &oldMaterial->_images;
268 : }
269 :
270 978 : auto &newImages = newMaterial->_images;
271 978 : if (oldImages) {
272 812 : auto &oldSet = _layouts[targetSet];
273 : // remove non-aliased images
274 1624 : for (auto &oIt : *oldImages) {
275 812 : bool hasAlias = false;
276 1624 : for (auto &nIt : newImages) {
277 812 : if (oIt.canAlias(nIt)) {
278 0 : hasAlias = true;
279 0 : break;
280 : }
281 : }
282 812 : if (!hasAlias) {
283 812 : -- oldSet.imageSlots[oIt.descriptor].refCount;
284 812 : if (oldSet.imageSlots[oIt.descriptor].refCount == 0) {
285 812 : oldSet.imageSlots[oIt.descriptor].image = nullptr;
286 : }
287 812 : oIt.view = nullptr;
288 : }
289 812 : if (oIt.image->atlas) {
290 796 : if (auto &atlasIndex = oIt.image->atlas->getIndexBuffer()) {
291 796 : auto descIdx = atlasIndex->getDescriptor();
292 796 : if (descIdx < oldSet.bufferSlots.size()) {
293 796 : -- oldSet.bufferSlots[descIdx].refCount;
294 796 : if (oldSet.bufferSlots[descIdx].refCount == 0) {
295 796 : oldSet.bufferSlots[descIdx].buffer = nullptr;
296 : }
297 : }
298 : }
299 796 : if (auto &atlasData = oIt.image->atlas->getDataBuffer()) {
300 796 : auto descIdx = atlasData->getDescriptor();
301 796 : if (descIdx < oldSet.bufferSlots.size()) {
302 796 : -- oldSet.bufferSlots[descIdx].refCount;
303 796 : if (oldSet.bufferSlots[descIdx].refCount == 0) {
304 796 : oldSet.bufferSlots[descIdx].buffer = nullptr;
305 : }
306 : }
307 : }
308 : }
309 : }
310 : }
311 :
312 978 : Vector<Pair<const MaterialImage *, Vector<uint32_t>>> uniqueImages;
313 978 : Vector<BufferObject *> uniqueBuffers;
314 :
315 : // find unique images
316 978 : uint32_t imageIdx = 0;
317 1956 : for (auto &it : newImages) {
318 978 : it.info = it.image->getViewInfo(it.info);
319 :
320 978 : bool isAlias = false;
321 978 : for (auto &uit : uniqueImages) {
322 0 : if (uit.first->canAlias(it)) {
323 0 : uit.second.emplace_back(imageIdx);
324 0 : isAlias = true;
325 : }
326 : }
327 978 : if (!isAlias) {
328 978 : uniqueImages.emplace_back(pair(&it, Vector<uint32_t>({imageIdx})));
329 : }
330 978 : ++ imageIdx;
331 :
332 978 : if (it.image->atlas) {
333 812 : if (auto &atlasIndex = it.image->atlas->getIndexBuffer()) {
334 812 : uniqueBuffers.emplace_back(atlasIndex);
335 : }
336 812 : if (auto &atlasData = it.image->atlas->getDataBuffer()) {
337 812 : uniqueBuffers.emplace_back(atlasData);
338 : }
339 : }
340 : }
341 :
342 1790 : auto emplaceMaterial = [&, this] (uint32_t setIdx, MaterialLayout &set, Vector<uint32_t> &imageLocations, Vector<uint32_t> &bufferLocations) {
343 978 : if (imageLocations.empty()) {
344 32 : for (uint32_t imageIdx = 0; imageIdx < uniqueImages.size(); ++ imageIdx) {
345 16 : imageLocations.emplace_back(imageIdx);
346 : }
347 : }
348 :
349 978 : if (!uniqueBuffers.empty() && bufferLocations.empty()) {
350 0 : for (uint32_t bufferIdx = 0; bufferIdx < uniqueBuffers.size(); ++ bufferIdx) {
351 0 : bufferLocations.emplace_back(bufferIdx);
352 : }
353 : }
354 :
355 978 : uint32_t imageIdx = 0;
356 1956 : for (auto &it : uniqueImages) {
357 978 : auto loc = imageLocations[imageIdx];
358 978 : if (set.imageSlots[loc].image) {
359 : // increment slot refcount, if image already exists
360 38 : set.imageSlots[loc].refCount += it.second.size();
361 : } else {
362 : // fill slot with new ImageView
363 940 : set.imageSlots[loc].image = cb(*it.first);
364 940 : set.imageSlots[loc].image->setLocation(setIdx, loc);
365 940 : set.imageSlots[loc].refCount = it.second.size();
366 940 : set.usedImageSlots = std::max(set.usedImageSlots, loc + 1);
367 : }
368 :
369 : // fill refs
370 1956 : for (auto &iIt : it.second) {
371 978 : newImages[iIt].view = set.imageSlots[loc].image;
372 978 : newImages[iIt].set = setIdx;
373 978 : newImages[iIt].descriptor = loc;
374 : }
375 :
376 978 : ++ imageIdx;
377 : }
378 :
379 978 : uint32_t bufferIdx = 0;
380 2602 : for (auto &it : uniqueBuffers) {
381 1624 : auto loc = bufferLocations[bufferIdx];
382 1624 : if (set.bufferSlots[loc].buffer) {
383 0 : ++ set.bufferSlots[loc].refCount;
384 : } else {
385 : // fill slot with new ImageView
386 1624 : set.bufferSlots[loc].buffer = it;
387 1624 : set.bufferSlots[loc].buffer->setLocation(setIdx, loc);
388 1624 : ++ set.bufferSlots[loc].refCount;
389 1624 : set.usedBufferSlots = std::max(set.usedBufferSlots, loc + 1);
390 : }
391 :
392 1624 : ++ bufferIdx;
393 : }
394 :
395 978 : newMaterial->setLayoutIndex(setIdx);
396 :
397 978 : if (oldImages) {
398 812 : auto &oldSet = _layouts[targetSet];
399 : // remove non-aliased images
400 1624 : for (auto &oIt : *oldImages) {
401 812 : if (oIt.view) {
402 0 : -- oldSet.imageSlots[oIt.descriptor].refCount;
403 0 : if (oldSet.imageSlots[oIt.descriptor].refCount == 0) {
404 0 : oldSet.imageSlots[oIt.descriptor].image = nullptr;
405 : }
406 0 : oIt.view = nullptr;
407 : }
408 : }
409 : }
410 978 : };
411 :
412 962 : auto tryToEmplaceSet = [&] (uint32_t setIndex, MaterialLayout &set) -> bool {
413 962 : uint32_t emplacedImages = 0;
414 962 : uint32_t emplacedBuffers = 0;
415 962 : Vector<uint32_t> imagePositions; imagePositions.resize(uniqueImages.size(), maxOf<uint32_t>());
416 962 : Vector<uint32_t> bufferPositions; bufferPositions.resize(uniqueBuffers.size(), maxOf<uint32_t>());
417 :
418 17850 : imageIdx = 0;
419 : // for each unique image, find it's potential place in set
420 1924 : for (auto &uit : uniqueImages) {
421 962 : uint32_t location = 0;
422 7272 : for (auto &it : set.imageSlots) {
423 : // check if image can alias with existed
424 7272 : if (it.image && it.image->getImage() == uit.first->image->image && it.image->getInfo() == uit.first->info) {
425 38 : if (imagePositions[imageIdx] == maxOf<uint32_t>()) {
426 38 : ++ emplacedImages; // mark as emplaced only if not emplaced already
427 : }
428 38 : imagePositions[imageIdx] = location;
429 38 : break; // stop searching - best variant
430 7234 : } else if (!it.image || it.refCount == 0) {
431 : // only if not emplaced
432 2660 : if (imagePositions[imageIdx] == maxOf<uint32_t>()) {
433 924 : if (std::find(imagePositions.begin(), imagePositions.end(), location) == imagePositions.end()) {
434 924 : ++ emplacedImages;
435 924 : imagePositions[imageIdx] = location;
436 : }
437 : }
438 : // continue searching for possible alias
439 : }
440 7234 : ++ location;
441 7234 : if (location > set.usedImageSlots + uniqueImages.size()) {
442 924 : break;
443 : }
444 : }
445 :
446 962 : ++ imageIdx;
447 : }
448 :
449 962 : imageIdx = 0;
450 2586 : for (auto &uit : uniqueBuffers) {
451 1624 : uint32_t location = 0;
452 8056 : for (auto &it : set.bufferSlots) {
453 8056 : if (it.buffer && it.buffer == uit) {
454 0 : if (bufferPositions[imageIdx] == maxOf<uint32_t>()) {
455 0 : ++ emplacedBuffers; // mark as emplaced only if not emplaced already
456 : }
457 0 : bufferPositions[imageIdx] = location;
458 0 : break; // stop searching - best variant
459 8056 : } else if (!it.buffer || it.refCount == 0) {
460 : // only if not emplaced
461 8056 : if (bufferPositions[imageIdx] == maxOf<uint32_t>()) {
462 2436 : if (std::find(bufferPositions.begin(), bufferPositions.end(), location) == bufferPositions.end()) {
463 1624 : ++ emplacedBuffers;
464 1624 : bufferPositions[imageIdx] = location;
465 : }
466 : }
467 : // continue searching for possible alias
468 : }
469 8056 : ++ location;
470 8056 : if (location > set.usedBufferSlots + uniqueBuffers.size()) {
471 1624 : break;
472 : }
473 : }
474 1624 : ++ imageIdx;
475 : }
476 :
477 : // if all images emplaced, perform actual emplace and return
478 962 : if (emplacedImages == uniqueImages.size() && emplacedBuffers == uniqueBuffers.size()) {
479 962 : emplaceMaterial(setIndex, set, imagePositions, bufferPositions);
480 962 : return true;
481 : }
482 0 : return false;
483 962 : };
484 :
485 978 : if (targetSet != maxOf<uint32_t>()) {
486 812 : if (tryToEmplaceSet(targetSet, _layouts[targetSet])) {
487 812 : return;
488 : }
489 : }
490 :
491 : // process existed sets
492 166 : uint32_t setIndex = 0;
493 166 : for (auto &set : _layouts) {
494 150 : if (setIndex == targetSet) {
495 0 : continue;
496 : }
497 :
498 150 : if (tryToEmplaceSet(setIndex, set)) {
499 150 : return;
500 : }
501 :
502 : // or continue to search for appropriate set
503 0 : ++ setIndex;
504 : }
505 :
506 : // no available set, create new one;
507 16 : auto &nIt = _layouts.emplace_back(MaterialLayout());
508 16 : nIt.imageSlots.resize(_imagesInSet);
509 16 : nIt.bufferSlots.resize(_buffersInSet);
510 :
511 16 : Vector<uint32_t> imageLocations;
512 16 : Vector<uint32_t> bufferLocations;
513 16 : emplaceMaterial(_layouts.size() - 1, nIt, imageLocations, bufferLocations);
514 1940 : }
515 :
516 812 : bool MaterialImage::canAlias(const MaterialImage &other) const {
517 812 : return other.image == image && other.info == info;
518 : }
519 :
520 1956 : Material::~Material() {
521 978 : if (_ownedData) {
522 0 : _images.clear();
523 0 : delete _ownedData;
524 0 : _ownedData = nullptr;
525 : }
526 1956 : }
527 :
528 102 : bool Material::init(MaterialId id, const PipelineData *pipeline, Vector<MaterialImage> &&images, Rc<Ref> &&data) {
529 102 : _id = id;
530 102 : _pipeline = pipeline;
531 102 : _images = move(images);
532 102 : _data = move(data);
533 102 : return true;
534 : }
535 :
536 0 : bool Material::init(MaterialId id, const PipelineData *pipeline, const Rc<DynamicImageInstance> &image, Rc<Ref> &&data) {
537 0 : _id = id;
538 0 : _pipeline = pipeline;
539 0 : _images = Vector<MaterialImage>({
540 : MaterialImage{
541 0 : .image = &image->data,
542 : .dynamic = image
543 : }
544 0 : });
545 0 : _data = move(data);
546 0 : _atlas = image->data.atlas;
547 0 : return true;
548 : }
549 :
550 0 : bool Material::init(MaterialId id, const PipelineData *pipeline, const ImageData *image, Rc<Ref> &&data, bool ownedData) {
551 0 : _id = id;
552 0 : _pipeline = pipeline;
553 0 : _images = Vector<MaterialImage>({
554 : MaterialImage({
555 : image
556 : })
557 0 : });
558 0 : _atlas = image->atlas;
559 0 : if (ownedData) {
560 0 : _ownedData = image;
561 : }
562 0 : _data = move(data);
563 0 : return true;
564 : }
565 :
566 64 : bool Material::init(MaterialId id, const PipelineData *pipeline, const ImageData *image, ColorMode mode, Rc<Ref> &&data, bool ownedData) {
567 64 : _id = id;
568 64 : _pipeline = pipeline;
569 :
570 64 : MaterialImage img({
571 : image
572 64 : });
573 :
574 64 : img.info.setup(*image);
575 64 : img.info.setup(mode);
576 :
577 320 : _images = Vector<MaterialImage>({
578 64 : move(img)
579 192 : });
580 64 : _atlas = image->atlas;
581 64 : if (ownedData) {
582 0 : _ownedData = image;
583 : }
584 64 : _data = move(data);
585 64 : return true;
586 64 : }
587 :
588 0 : bool Material::init(const Material *master, Rc<ImageObject> &&image, Rc<DataAtlas> &&atlas, Rc<Ref> &&data) {
589 0 : _id = master->getId();
590 0 : _pipeline = master->getPipeline();
591 :
592 0 : auto otherData = master->getOwnedData();
593 0 : if (!otherData) {
594 0 : auto &images = master->getImages();
595 0 : if (images.size() > 0) {
596 0 : otherData = images[0].image;
597 : }
598 : }
599 :
600 0 : auto ownedData = new ImageData;
601 0 : static_cast<ImageInfoData &>(*ownedData) = image->getInfo();
602 0 : ownedData->image = move(image);
603 0 : ownedData->atlas = move(atlas);
604 0 : _ownedData = ownedData;
605 :
606 0 : _images = Vector<MaterialImage>({
607 : MaterialImage({
608 0 : _ownedData
609 : })
610 0 : });
611 0 : _data = move(data);
612 0 : return true;
613 : }
614 :
615 812 : bool Material::init(const Material *master, Vector<MaterialImage> &&images) {
616 812 : _id = master->getId();
617 812 : _pipeline = master->getPipeline();
618 812 : _images = move(images);
619 812 : for (auto &it : _images) {
620 812 : if (it.image->atlas) {
621 812 : _atlas = it.image->atlas;
622 812 : break;
623 : }
624 : }
625 812 : _data = master->_data;
626 812 : return true;
627 : }
628 :
629 978 : void Material::setLayoutIndex(uint32_t idx) {
630 978 : _layoutIndex = idx;
631 978 : }
632 :
633 16 : MaterialAttachment::~MaterialAttachment() { }
634 :
635 16 : bool MaterialAttachment::init(AttachmentBuilder &builder, const BufferInfo &info, MaterialSet::EncodeCallback &&cb, uint32_t size) {
636 16 : if (!BufferAttachment::init(builder, info)) {
637 0 : return false;
638 : }
639 :
640 16 : _materialObjectSize = size;
641 16 : _encodeCallback = move(cb);
642 16 : return true;
643 : }
644 :
645 16 : void MaterialAttachment::addPredefinedMaterials(Vector<Rc<Material>> &&materials) {
646 80 : for (auto &it : materials) {
647 128 : it->_id = _attachmentMaterialId.fetch_add(1);
648 : }
649 :
650 16 : if (_predefinedMaterials.empty()) {
651 16 : _predefinedMaterials = move(materials);
652 : } else {
653 0 : for (auto &it : materials) {
654 0 : _predefinedMaterials.emplace_back(move(it));
655 : }
656 : }
657 16 : }
658 :
659 8232 : const Rc<MaterialSet> &MaterialAttachment::getMaterials() const {
660 8232 : return _data;
661 : }
662 :
663 925 : void MaterialAttachment::setMaterials(const Rc<MaterialSet> &data) const {
664 925 : auto tmp = _data;
665 925 : _data = data;
666 925 : if (tmp) {
667 909 : tmp->clear();
668 : }
669 925 : }
670 :
671 16 : Rc<MaterialSet> MaterialAttachment::allocateSet(const Device &dev) const {
672 16 : return Rc<MaterialSet>::create(_info, _encodeCallback, _materialObjectSize,
673 32 : dev.getTextureLayoutImagesCount(), dev.getTextureLayoutBuffersCount(), this);
674 : }
675 :
676 909 : Rc<MaterialSet> MaterialAttachment::cloneSet(const Rc<MaterialSet> &other) const {
677 909 : return Rc<MaterialSet>::create(other);
678 : }
679 :
680 828 : void MaterialAttachment::addDynamicTracker(MaterialId id, const Rc<DynamicImage> &image) const {
681 828 : std::unique_lock<Mutex> lock(_dynamicMutex);
682 828 : auto it = _dynamicTrackers.find(image);
683 828 : if (it != _dynamicTrackers.end()) {
684 812 : ++ it->second.refCount;
685 : } else {
686 16 : it = _dynamicTrackers.emplace(image, DynamicImageTracker{1}).first;
687 16 : image->addTracker(this);
688 : }
689 :
690 828 : auto iit = it->second.materials.find(id);
691 828 : if (iit != it->second.materials.end()) {
692 812 : ++ iit->second;
693 : } else {
694 16 : it->second.materials.emplace(id, 1);
695 : }
696 828 : }
697 :
698 812 : void MaterialAttachment::removeDynamicTracker(MaterialId id, const Rc<DynamicImage> &image) const {
699 812 : std::unique_lock<Mutex> lock(_dynamicMutex);
700 812 : auto it = _dynamicTrackers.find(image);
701 812 : if (it != _dynamicTrackers.end()) {
702 812 : auto iit = it->second.materials.find(id);
703 812 : if (iit != it->second.materials.end()) {
704 812 : -- iit->second;
705 812 : if (iit->second == 0) {
706 0 : it->second.materials.erase(iit);
707 : }
708 : }
709 812 : -- it->second.refCount;
710 812 : if (it->second.refCount == 0) {
711 0 : _dynamicTrackers.erase(it);
712 0 : image->removeTracker(this);
713 : }
714 : }
715 812 : }
716 :
717 812 : void MaterialAttachment::updateDynamicImage(Loop &loop, const DynamicImage *image, const Vector<Rc<DependencyEvent>> &deps) const {
718 812 : auto input = Rc<MaterialInputData>::alloc();
719 812 : input->attachment = this;
720 812 : std::unique_lock<Mutex> lock(_dynamicMutex);
721 812 : auto it = _dynamicTrackers.find(image);
722 812 : if (it != _dynamicTrackers.end()) {
723 1624 : for (auto &materialIt : it->second.materials) {
724 812 : input->dynamicMaterialsToUpdate.emplace_back(materialIt.first);
725 : }
726 : }
727 1608 : for (auto &it : deps) {
728 796 : it->addQueue(getCompiler());
729 : }
730 812 : loop.compileMaterials(move(input), deps);
731 812 : }
732 :
733 102 : MaterialId MaterialAttachment::getNextMaterialId() const {
734 204 : return _attachmentMaterialId.fetch_add(1);
735 : }
736 :
737 16 : void MaterialAttachment::setCompiler(Queue *c) {
738 16 : _compiler = c;
739 16 : }
740 :
741 877 : Queue *MaterialAttachment::getCompiler() const {
742 877 : return _compiler;
743 : }
744 :
745 : }
|