LCOV - code coverage report
Current view: top level - xenolith/core - XLCoreMaterial.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 365 459 79.5 %
Date: 2024-05-12 00:16:13 Functions: 35 40 87.5 %

          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             : }

Generated by: LCOV version 1.14