LCOV - code coverage report
Current view: top level - xenolith/scene/director - XLFrameContext.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 152 163 93.3 %
Date: 2024-05-12 00:16:13 Functions: 19 20 95.0 %

          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 "XLFrameContext.h"
      24             : #include "XLFrameInfo.h"
      25             : #include "XLDirector.h"
      26             : #include "XLScene.h"
      27             : 
      28             : namespace STAPPLER_VERSIONIZED stappler::xenolith {
      29             : 
      30          21 : FrameContext::~FrameContext() { }
      31             : 
      32          21 : bool FrameContext::init() {
      33          21 :         return true;
      34             : }
      35             : 
      36          21 : void FrameContext::onEnter(Scene *scene) {
      37          21 :         _scene = scene;
      38          21 :         _queue = _scene->getQueue();
      39          21 : }
      40             : 
      41          21 : void FrameContext::onExit() {
      42          21 :         _queue = nullptr;
      43          21 :         _scene = nullptr;
      44          21 : }
      45             : 
      46             : SP_COVERAGE_TRIVIAL
      47             : Rc<FrameContextHandle> FrameContext::makeHandle(FrameInfo &) {
      48             :         return nullptr;
      49             : }
      50             : 
      51        9538 : void FrameContext::submitHandle(FrameInfo &info, FrameContextHandle *handle) {
      52        9538 :         submitMaterials(info);
      53             : 
      54        9538 :         if (!handle->waitDependencies.empty()) {
      55        1088 :                 info.director->getApplication()->wakeup();
      56             :         }
      57        9538 : }
      58             : 
      59       42202 : uint64_t FrameContext::getMaterial(const MaterialInfo &info) const {
      60       42202 :         auto hash = info.hash();
      61       42202 :         auto it = _materials.find(hash);
      62       42202 :         if (it != _materials.end()) {
      63       42070 :                 for (auto &m : it->second) {
      64       42070 :                         if (m.info == info) {
      65       42070 :                                 return m.id;
      66             :                         }
      67             :                 }
      68             :         }
      69         132 :         return 0;
      70             : }
      71             : 
      72         132 : uint64_t FrameContext::acquireMaterial(const MaterialInfo &info, Vector<core::MaterialImage> &&images, Ref *data, bool revokable) {
      73         132 :         auto pipeline = getPipelineForMaterial(info);
      74         132 :         if (!pipeline) {
      75           0 :                 return 0;
      76             :         }
      77             : 
      78         264 :         for (uint32_t idx = 0; idx < uint32_t(images.size()); ++ idx) {
      79         132 :                 if (images[idx].image != nullptr) {
      80         132 :                         auto &image = images[idx];
      81         132 :                         image.info = getImageViewForMaterial(info, idx, images[idx].image);
      82         132 :                         image.view = nullptr;
      83         132 :                         image.sampler = info.samplers[idx];
      84             :                 }
      85             :         }
      86             : 
      87         132 :         core::MaterialId newId = 0;
      88         132 :         if (revokable) {
      89          27 :                 if (!_revokedIds.empty()) {
      90           0 :                         newId = _revokedIds.back();
      91           0 :                         _revokedIds.pop_back();
      92             :                 }
      93             :         }
      94             : 
      95         132 :         if (newId == 0) {
      96         132 :                 newId = _materialAttachment->getNextMaterialId();
      97             :         }
      98             : 
      99         132 :         if (auto m = Rc<core::Material>::create(newId, pipeline, move(images), data)) {
     100         132 :                 auto id = m->getId();
     101         132 :                 addPendingMaterial(move(m));
     102         132 :                 addMaterial(info, id, revokable);
     103         132 :                 return id;
     104         132 :         }
     105           0 :         return 0;
     106             : }
     107             : 
     108          21 : void FrameContext::readMaterials(core::MaterialAttachment *a) {
     109          21 :         _materialAttachment = a;
     110             : 
     111          21 :         auto renderPass = a->getLastRenderPass();
     112          42 :         while (renderPass) {
     113          21 :                 auto &layouts = renderPass->pipelineLayouts;
     114          42 :                 for (auto &layout : layouts) {
     115          21 :                         bool isUsable = false;
     116          42 :                         for (auto &set : layout->sets) {
     117          42 :                                 for (auto &desc : set->descriptors) {
     118          42 :                                         if (desc->attachment->attachment->attachment == a) {
     119          21 :                                                 isUsable = true;
     120          21 :                                                 break;
     121             :                                         }
     122             :                                 }
     123             :                         }
     124             : 
     125          21 :                         if (!isUsable) {
     126           0 :                                 break;
     127             :                         }
     128             : 
     129          21 :                         auto &sp = _layouts.emplace_back(PipelineLayoutData({layout}));
     130             : 
     131         105 :                         for (auto &pipeline : layout->graphicPipelines) {
     132          84 :                                 auto hash = pipeline->material.hash();
     133          84 :                                 auto it = sp.pipelines.find(hash);
     134          84 :                                 if (it == sp.pipelines.end()) {
     135          84 :                                         it = sp.pipelines.emplace(hash, Vector<const core::GraphicPipelineData *>()).first;
     136             :                                 }
     137          84 :                                 it->second.emplace_back(pipeline);
     138             :                         }
     139             :                 }
     140             : 
     141          21 :                 renderPass = a->getPrevRenderPass(renderPass);
     142             :         }
     143         105 :         for (auto &m : a->getPredefinedMaterials()) {
     144          84 :                 addMaterial(getMaterialInfo(m), m->getId(), false);
     145             :         }
     146          21 : }
     147             : 
     148          84 : MaterialInfo FrameContext::getMaterialInfo(const Rc<core::Material> &material) const {
     149          84 :         MaterialInfo ret;
     150             : 
     151          84 :         size_t idx = 0;
     152         168 :         for (auto &it : material->getImages()) {
     153          84 :                 if (idx < config::MaxMaterialImages) {
     154          84 :                         ret.images[idx] = it.image->image->getIndex();
     155          84 :                         ret.samplers[idx] = it.sampler;
     156          84 :                         ret.colorModes[idx] = it.info.getColorMode();
     157             :                 }
     158          84 :                 ++ idx;
     159             :         }
     160             : 
     161          84 :         ret.pipeline = material->getPipeline()->material;
     162          84 :         return ret;
     163             : }
     164             : 
     165         132 : void FrameContext::addPendingMaterial(Rc<core::Material> &&material) {
     166         132 :         _pendingMaterialsToAdd.emplace_back(move(material));
     167         132 :         if (!_materialDependency) {
     168         424 :                 _materialDependency = Rc<core::DependencyEvent>::alloc(core::DependencyEvent::QueueSet{
     169         212 :                         Rc<core::Queue>(_materialAttachment->getCompiler())
     170         318 :                 });
     171             :         }
     172         132 : }
     173             : 
     174         216 : void FrameContext::addMaterial(const MaterialInfo &info, core::MaterialId id, bool revokable) {
     175         216 :         auto materialHash = info.hash();
     176         216 :         auto it = _materials.find(info.hash());
     177         216 :         if (it != _materials.end()) {
     178           0 :                 it->second.emplace_back(ContextMaterialInfo{info, id, revokable});
     179             :         } else {
     180         216 :                 Vector<ContextMaterialInfo> ids({ContextMaterialInfo{info, id, revokable}});
     181         216 :                 _materials.emplace(materialHash, move(ids));
     182         216 :         }
     183         216 : }
     184             : 
     185          21 : String FrameContext::listMaterials() const {
     186          21 :         StringStream out;
     187         237 :         for (auto &it : _materials) {
     188         216 :                 out << it.first << ":\n";
     189         432 :                 for (auto &iit : it.second) {
     190         216 :                         out << "\t" << iit.info.description() << " -> " << iit.id << "\n";
     191             :                 }
     192             :         }
     193          42 :         return out.str();
     194          21 : }
     195             : 
     196         132 : core::ImageViewInfo FrameContext::getImageViewForMaterial(const MaterialInfo &info, uint32_t idx, const core::ImageData *image) const {
     197         132 :         return core::ImageViewInfo(image->format, info.colorModes[idx]);
     198             : }
     199             : 
     200         132 : auto FrameContext::getPipelineForMaterial(const MaterialInfo &info) const -> const core::GraphicPipelineData * {
     201         132 :         auto hash = info.pipeline.hash();
     202         132 :         for (auto &it : _layouts) {
     203         132 :                 auto hashIt = it.pipelines.find(hash);
     204         132 :                 if (hashIt != it.pipelines.end()) {
     205         132 :                         for (auto &pipeline : hashIt->second) {
     206         132 :                                 if (pipeline->material == info.pipeline && isPipelineMatch(pipeline, info)) {
     207         132 :                                         return pipeline;
     208             :                                 }
     209             :                         }
     210             :                 }
     211             :         }
     212           0 :         log::warn("Scene", "No pipeline for attachment '", _materialAttachment->getName(), "': ",
     213           0 :                         info.pipeline.description(), " : ", info.pipeline.data());
     214           0 :         return nullptr;
     215             : }
     216             : 
     217         132 : bool FrameContext::isPipelineMatch(const core::GraphicPipelineData *data, const MaterialInfo &info) const {
     218         132 :         return true; // TODO: true match
     219             : }
     220             : 
     221        9538 : void FrameContext::submitMaterials(const FrameInfo &info) {
     222             :         // submit material updates
     223        9538 :         if (!_pendingMaterialsToAdd.empty() || !_pendingMaterialsToRemove.empty()) {
     224         127 :                 Vector<Rc<core::DependencyEvent>> events;
     225         127 :                 if (_materialDependency) {
     226         106 :                         events.emplace_back(_materialDependency);
     227             :                 }
     228             : 
     229         127 :                 if (!_pendingMaterialsToAdd.empty() || !_pendingMaterialsToRemove.empty()) {
     230         127 :                         auto req = Rc<core::MaterialInputData>::alloc();
     231         127 :                         req->attachment = _materialAttachment;
     232         127 :                         req->materialsToAddOrUpdate = move(_pendingMaterialsToAdd);
     233         127 :                         req->materialsToRemove = move(_pendingMaterialsToRemove);
     234         254 :                         req->callback = [app = Rc<Application>(info.director->getApplication())] {
     235         127 :                                 app->wakeup();
     236         254 :                         };
     237             : 
     238         154 :                         for (auto &it : req->materialsToRemove) {
     239          27 :                                 emplace_ordered(_revokedIds, it);
     240             :                         }
     241             : 
     242         127 :                         info.director->getGlLoop()->compileMaterials(move(req), events);
     243         127 :                 }
     244             : 
     245         127 :                 _pendingMaterialsToAdd.clear();
     246         127 :                 _pendingMaterialsToRemove.clear();
     247         127 :                 _materialDependency = nullptr;
     248         127 :         }
     249        9538 : }
     250             : 
     251          21 : void FrameContext::revokeImages(SpanView<uint64_t> vec) {
     252             : #ifdef COVERAGE
     253          21 :         listMaterials();
     254             : #endif
     255          54 :         auto shouldRevoke = [&, this] (const ContextMaterialInfo &iit) {
     256          27 :                 for (auto &id : vec) {
     257          27 :                         if (iit.info.hasImage(id)) {
     258          27 :                                 emplace_ordered(_pendingMaterialsToRemove, iit.id);
     259          27 :                                 return true;
     260             :                         }
     261             :                 }
     262           0 :                 return false;
     263          21 :         };
     264             : 
     265         237 :         for (auto &it : _materials) {
     266         216 :                 auto iit = it.second.begin();
     267         432 :                 while (iit != it.second.end()) {
     268         216 :                         if (iit->revokable) {
     269          27 :                                 if (shouldRevoke(*iit)) {
     270          27 :                                         iit = it.second.erase(iit);
     271             :                                 } else {
     272           0 :                                         ++ iit;
     273             :                                 }
     274             :                         } else {
     275         189 :                                 ++ iit;
     276             :                         }
     277             :                 }
     278             :         }
     279          21 : }
     280             : 
     281             : }

Generated by: LCOV version 1.14