LCOV - code coverage report
Current view: top level - xenolith/core - XLCoreFrameCache.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 153 210 72.9 %
Date: 2024-05-12 00:16:13 Functions: 26 29 89.7 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XLCoreFrameCache.h"
      24             : #include "XLCoreDevice.h"
      25             : #include "XLCoreLoop.h"
      26             : 
      27             : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
      28             : 
      29          64 : FrameCache::~FrameCache() { }
      30             : 
      31          32 : bool FrameCache::init(Loop &loop, Device &dev) {
      32          32 :         _loop = &loop;
      33          32 :         _device = &dev;
      34          32 :         return true;
      35             : }
      36             : 
      37          32 : void FrameCache::invalidate() {
      38          32 :         _framebuffers.clear();
      39          32 :         _imageViews.clear();
      40          32 :         _renderPasses.clear();
      41          32 :         _images.clear();
      42          32 : }
      43             : 
      44        7322 : Rc<Framebuffer> FrameCache::acquireFramebuffer(const QueuePassData *data, SpanView<Rc<ImageView>> views) {
      45        7322 :         auto e = views.front()->getFramebufferExtent();
      46        7322 :         Vector<uint64_t> ids; ids.reserve(views.size() + 2);
      47        7322 :         ids.emplace_back(data->impl->getIndex());
      48        7322 :         ids.emplace_back(uint64_t(e.depth) << uint64_t(48) | uint64_t(e.height) << uint64_t(24) | uint64_t(e.width));
      49       29288 :         for (auto &it : views) {
      50       21966 :                 ids.emplace_back(it->getIndex());
      51             :         }
      52             : 
      53        7322 :         auto it = _framebuffers.find(ids);
      54        7322 :         if (it != _framebuffers.end()) {
      55        7232 :                 if (!it->second.framebuffers.empty()) {
      56        7232 :                         auto fb = it->second.framebuffers.back();
      57        7232 :                         it->second.framebuffers.pop_back();
      58        7232 :                         return fb;
      59        7232 :                 }
      60             :         }
      61             : 
      62          90 :         return _device->makeFramebuffer(data, views);
      63        7322 : }
      64             : 
      65        7322 : void FrameCache::releaseFramebuffer(Rc<Framebuffer> &&fb) {
      66        7322 :         auto e = fb->getFramebufferExtent();
      67        7322 :         Vector<uint64_t> ids; ids.reserve(fb->getViewIds().size() + 2);
      68        7322 :         ids.emplace_back(fb->getRenderPass()->getIndex());
      69        7322 :         ids.emplace_back(uint64_t(e.depth) << uint64_t(48) | uint64_t(e.height) << uint64_t(24) | uint64_t(e.width));
      70       29288 :         for (auto &it : fb->getViewIds()) {
      71       21966 :                 ids.emplace_back(it);
      72             :         }
      73             : 
      74        7322 :         if (isReachable(SpanView<uint64_t>(ids))) {
      75        7322 :                 auto it = _framebuffers.find(ids);
      76        7322 :                 if (it == _framebuffers.end()) {
      77         180 :                         _framebuffers.emplace(move(ids), FrameCacheFramebuffer{ Vector<Rc<Framebuffer>>{move(fb)}, e });
      78             :                 } else {
      79        7232 :                         it->second.framebuffers.emplace_back(move(fb));
      80             :                 }
      81             :         }
      82        7322 : }
      83             : 
      84       21998 : Rc<ImageStorage> FrameCache::acquireImage(uint64_t attachment, const ImageInfoData &info, SpanView<ImageViewInfo> v) {
      85         240 :         auto makeImage = [&, this] {
      86          80 :                 auto ret = _device->makeImage(info);
      87          80 :                 ret->rearmSemaphores(*_loop);
      88          80 :                 makeViews(ret, v);
      89          80 :                 return ret;
      90           0 :         };
      91             : 
      92       21998 :         auto aIt = _attachments.find(attachment);
      93       21998 :         if (aIt == _attachments.end() || (info.hints & core::ImageHints::DoNotCache) != core::ImageHints::None) {
      94           0 :                 return makeImage();
      95             :         }
      96             : 
      97       21998 :         if (aIt->second == nullptr) {
      98          80 :                 aIt->second = addImage(info);
      99       21918 :         } else if (*aIt->second != info) {
     100           0 :                 removeImage(*aIt->second);
     101           0 :                 aIt->second = addImage(info);
     102             :         }
     103             : 
     104       21998 :         auto imageIt = _images.find(info);
     105       21998 :         if (imageIt != _images.end()) {
     106       21998 :                 if (!imageIt->second.images.empty()) {
     107       21918 :                         auto ret = move(imageIt->second.images.back());
     108       21918 :                         imageIt->second.images.pop_back();
     109       21918 :                         ret->rearmSemaphores(*_loop);
     110       21918 :                         makeViews(ret, v);
     111       21918 :                         return ret;
     112       21918 :                 }
     113             :         }
     114             : 
     115          80 :         return makeImage();
     116             : }
     117             : 
     118       21982 : void FrameCache::releaseImage(Rc<ImageStorage> &&img) {
     119       21982 :         if (!img->isCacheable()) {
     120           0 :                 img->cleanup();
     121           0 :                 return;
     122             :         }
     123             : 
     124       21982 :         auto info = img->getInfo();
     125       21982 :         auto imageIt = _images.find(info);
     126       21982 :         if (imageIt == _images.end()) {
     127           0 :                 log::warn("FrameCache", "releaseImage: cache miss: ", img->getInfo());
     128           0 :                 return;
     129             :         }
     130             : 
     131       21982 :         imageIt->second.images.emplace_back(move(img));
     132             : }
     133             : 
     134         176 : void FrameCache::addImageView(uint64_t id) {
     135         176 :         _imageViews.emplace(id);
     136         176 : }
     137             : 
     138         176 : void FrameCache::removeImageView(uint64_t id) {
     139         176 :         auto it = _imageViews.find(id);
     140         176 :         if (it != _imageViews.end()) {
     141          48 :                 _imageViews.erase(it);
     142             : 
     143          48 :                 auto iit = _framebuffers.begin();
     144         122 :                 while (iit != _framebuffers.end()) {
     145          74 :                         if (!isReachable(SpanView<uint64_t>(iit->first))) {
     146          52 :                                 for (auto &it : iit->second.framebuffers) {
     147          26 :                                         _autorelease.emplace_back(it);
     148             :                                 }
     149          26 :                                 iit = _framebuffers.erase(iit);
     150             :                         } else {
     151          48 :                                 ++ iit;
     152             :                         }
     153             :                 }
     154             :         }
     155         176 : }
     156             : 
     157         223 : void FrameCache::addRenderPass(uint64_t id) {
     158         223 :         _renderPasses.emplace(id);
     159         223 : }
     160             : 
     161         159 : void FrameCache::removeRenderPass(uint64_t id) {
     162         159 :         auto it = _renderPasses.find(id);
     163         159 :         if (it != _renderPasses.end()) {
     164           0 :                 _renderPasses.erase(it);
     165             : 
     166           0 :                 auto iit = _framebuffers.begin();
     167           0 :                 while (iit != _framebuffers.end()) {
     168           0 :                         if (!isReachable(SpanView<uint64_t>(iit->first))) {
     169           0 :                                 for (auto &it : iit->second.framebuffers) {
     170           0 :                                         _autorelease.emplace_back(it);
     171             :                                 }
     172           0 :                                 iit = _framebuffers.erase(iit);
     173             :                         } else {
     174           0 :                                 ++ iit;
     175             :                         }
     176             :                 }
     177             :         }
     178         159 : }
     179             : 
     180          80 : void FrameCache::addAttachment(uint64_t id) {
     181          80 :         _attachments.emplace(id, nullptr);
     182          80 : }
     183             : 
     184          80 : void FrameCache::removeAttachment(uint64_t id) {
     185          80 :         auto it = _attachments.find(id);
     186          80 :         if (it == _attachments.end()) {
     187           0 :                 return;
     188             :         }
     189             : 
     190          80 :         if (it->second) {
     191          80 :                 removeImage(*it->second);
     192             :         }
     193          80 :         _attachments.erase(it);
     194             : }
     195             : 
     196          80 : void FrameCache::removeUnreachableFramebuffers() {
     197          80 :         auto fbsIt = _framebuffers.begin();
     198          80 :         while (fbsIt != _framebuffers.end()) {
     199           0 :                 auto e = fbsIt->second.extent;
     200           0 :                 bool found = false;
     201           0 :                 for (auto &it : _images) {
     202           0 :                         if (it.first.extent.width == e.width && it.first.extent.height == e.height) {
     203           0 :                                 found = true;
     204             :                         }
     205             :                 }
     206           0 :                 if (!found) {
     207           0 :                         for (auto &it : fbsIt->second.framebuffers) {
     208           0 :                                 _autorelease.emplace_back(it);
     209             :                         }
     210           0 :                         fbsIt = _framebuffers.erase(fbsIt);
     211             :                 } else {
     212           0 :                         auto fbIt = fbsIt->second.framebuffers.begin();
     213           0 :                         while (fbIt != fbsIt->second.framebuffers.end()) {
     214           0 :                                 auto e = (*fbIt)->getFramebufferExtent();
     215           0 :                                 Vector<uint64_t> ids; ids.reserve((*fbIt)->getViewIds().size() + 2);
     216           0 :                                 ids.emplace_back((*fbIt)->getRenderPass()->getIndex());
     217           0 :                                 ids.emplace_back(uint64_t(e.depth) << uint64_t(48) | uint64_t(e.height) << uint64_t(24) | uint64_t(e.width));
     218           0 :                                 for (auto &it : (*fbIt)->getViewIds()) {
     219           0 :                                         ids.emplace_back(it);
     220             :                                 }
     221             : 
     222           0 :                                 if (isReachable(SpanView<uint64_t>(ids))) {
     223           0 :                                         _autorelease.emplace_back(*fbIt);
     224           0 :                                         fbIt = fbsIt->second.framebuffers.erase(fbIt);
     225             :                                 } else {
     226           0 :                                         ++ fbIt;
     227             :                                 }
     228           0 :                         }
     229             : 
     230           0 :                         if (fbsIt->second.framebuffers.empty()) {
     231           0 :                                 fbsIt = _framebuffers.erase(fbsIt);
     232             :                         } else {
     233           0 :                                 ++ fbsIt;
     234             :                         }
     235             :                 }
     236             :         }
     237          80 : }
     238             : 
     239        7323 : size_t FrameCache::getFramebuffersCount() const {
     240        7323 :         size_t ret = 0;
     241       36361 :         for (auto &it : _framebuffers) {
     242       29038 :                 ret += it.second.framebuffers.size();
     243             :         }
     244        7323 :         return ret;
     245             : }
     246             : 
     247        7323 : size_t FrameCache::getImagesCount() const {
     248        7323 :         size_t ret = 0;
     249       36551 :         for (auto &it : _images) {
     250       29228 :                 ret += it.second.images.size();
     251             :         }
     252        7323 :         return ret;
     253             : }
     254             : 
     255        7323 : size_t FrameCache::getImageViewsCount() const {
     256        7323 :         return _imageViews.size();
     257             : }
     258             : 
     259      605226 : void FrameCache::clear() {
     260      605226 :         if (!_freezed) {
     261      605226 :                 _autorelease.clear();
     262             :         }
     263      605226 : }
     264             : 
     265           0 : void FrameCache::freeze() {
     266           0 :         _freezed = true;
     267           0 : }
     268             : 
     269           0 : void FrameCache::unfreeze() {
     270           0 :         if (_freezed) {
     271           0 :                 _autorelease.clear();
     272             :         }
     273           0 :         _freezed = false;
     274           0 : }
     275             : 
     276        7396 : bool FrameCache::isReachable(SpanView<uint64_t> ids) const {
     277        7396 :         auto fb = ids.front();
     278        7396 :         if (_renderPasses.find(fb) == _renderPasses.end()) {
     279           0 :                 return false;
     280             :         }
     281             : 
     282        7396 :         ids = ids.sub(2, ids.size() - 2);
     283       29506 :         for (auto &it : ids) {
     284       22136 :                 if (_imageViews.find(it) == _imageViews.end()) {
     285          26 :                         return false;
     286             :                 }
     287             :         }
     288        7370 :         return true;
     289             : }
     290             : 
     291           0 : bool FrameCache::isReachable(const ImageInfoData &info) const {
     292           0 :         auto it = _images.find(info);
     293           0 :         return it != _images.end();
     294             : }
     295             : 
     296          80 : const ImageInfoData *FrameCache::addImage(const ImageInfoData &info) {
     297          80 :         auto it = _images.find(info);
     298          80 :         if (it == _images.end()) {
     299          80 :                 it = _images.emplace(info, FrameCacheImageAttachment{uint32_t(1), Vector<Rc<ImageStorage>>()}).first;
     300             :         } else {
     301           0 :                 ++ it->second.refCount;
     302             :         }
     303          80 :         return &it->first;
     304             : }
     305             : 
     306          80 : void FrameCache::removeImage(const ImageInfoData &info) {
     307          80 :         auto it = _images.find(info);
     308          80 :         if (it != _images.end()) {
     309          16 :                 if (it->second.refCount == 1) {
     310          16 :                         for (auto &iit : it->second.images) {
     311           0 :                                 _autorelease.emplace_back(iit);
     312             :                         }
     313          16 :                         _images.erase(it);
     314             :                 } else {
     315           0 :                         -- it->second.refCount;
     316             :                 }
     317             :         }
     318          80 : }
     319             : 
     320       21998 : void FrameCache::makeViews(const Rc<ImageStorage> &img, SpanView<ImageViewInfo> views) {
     321       51318 :         for (auto &info : views) {
     322       29320 :                 auto v = img->getView(info);
     323       29320 :                 if (!v) {
     324          96 :                         auto v = _device->makeImageView(img->getImage(), info);
     325          96 :                         addImageView(v->getIndex());
     326          96 :                         v->setReleaseCallback([loop = Rc<Loop>(_loop), id = v->getIndex()] {
     327          96 :                                 loop->performOnGlThread([loop, id] {
     328          96 :                                         loop->getFrameCache()->removeImageView(id);
     329          96 :                                 });
     330          96 :                         });
     331          96 :                         img->addView(info, move(v));
     332          96 :                 }
     333       29320 :         }
     334       21998 : }
     335             : 
     336             : }

Generated by: LCOV version 1.14