LCOV - code coverage report
Current view: top level - xenolith/core - XLCoreFrameHandle.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 197 247 79.8 %
Date: 2024-05-12 00:16:13 Functions: 42 55 76.4 %

          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 "XLCoreFrameHandle.h"
      24             : #include "XLCorePlatform.h"
      25             : #include "XLCoreLoop.h"
      26             : #include "XLCoreFrameRequest.h"
      27             : #include "XLCoreFrameQueue.h"
      28             : 
      29             : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
      30             : 
      31             : static constexpr ClockType FrameClockType = ClockType::Monotonic;
      32             : 
      33             : #ifdef XL_FRAME_LOG
      34             : #define XL_FRAME_LOG_INFO _request->getEmitter() ? "[Emitted] " : "", \
      35             :         "[", _order, "] [", s_frameCount.load(), \
      36             :         "] [", platform::clock(FrameClockType) - _timeStart, "] "
      37             : #else
      38             : #define XL_FRAME_LOG_INFO
      39             : #define XL_FRAME_LOG(...)
      40             : #endif
      41             : 
      42             : #ifndef XL_FRAME_PROFILE
      43             : #define XL_FRAME_PROFILE(fn, tag, max) \
      44             :         do { } while (0);
      45             : #endif
      46             : 
      47             : static std::atomic<uint32_t> s_frameCount = 0;
      48             : 
      49             : static Mutex s_frameMutex;
      50             : static std::set<FrameHandle *> s_activeFrames;
      51             : 
      52          16 : uint32_t FrameHandle::GetActiveFramesCount() {
      53          16 :         return s_frameCount.load();
      54             : }
      55             : 
      56           0 : void FrameHandle::DescribeActiveFrames() {
      57           0 :         s_frameMutex.lock();
      58             : #if SP_REF_DEBUG
      59             :         auto hasFailed = false;
      60             :         for (auto &it : s_activeFrames) {
      61             :                 if (!it->isValidFlag()) {
      62             :                         hasFailed = true;
      63             :                         break;
      64             :                 }
      65             :         }
      66             : 
      67             :         if (hasFailed) {
      68             :                 StringStream stream;
      69             :                 stream << "\n";
      70             :                 for (auto &it : s_activeFrames) {
      71             :                         stream << "\tFrame: " << it->getOrder() << " refcount: " << it->getReferenceCount() << "; success: " << it->isValidFlag() << "; backtrace:\n";
      72             :                         it->foreachBacktrace([&] (uint64_t id, Time time, const std::vector<std::string> &vec) {
      73             :                                 stream << "[" << id << ":" << time.toHttp<Interface>() << "]:\n";
      74             :                                 for (auto &it : vec) {
      75             :                                         stream << "\t" << it << "\n";
      76             :                                 }
      77             :                         });
      78             :                 }
      79             :                 stappler::log::debug("FrameHandle", stream.str());
      80             :         }
      81             : #endif
      82             : 
      83           0 :         s_frameMutex.unlock();
      84           0 : }
      85             : 
      86       28435 : FrameHandle::~FrameHandle() {
      87             :         XL_FRAME_LOG(XL_FRAME_LOG_INFO, "Destroy");
      88             : 
      89       28435 :         s_frameMutex.lock();
      90       28435 :         -- s_frameCount;
      91       28435 :         s_activeFrames.erase(this);
      92       28435 :         s_frameMutex.unlock();
      93             : 
      94       28435 :         if (_request) {
      95       28435 :                 _request->detachFrame();
      96       28435 :                 _request = nullptr;
      97             :         }
      98       28435 :         _pool = nullptr;
      99       28435 : }
     100             : 
     101       28435 : bool FrameHandle::init(Loop &loop, Device &dev, Rc<FrameRequest> &&req, uint64_t gen) {
     102       28435 :         s_frameMutex.lock();
     103       28435 :         s_activeFrames.emplace(this);
     104       28435 :         ++ s_frameCount;
     105       28435 :         s_frameMutex.unlock();
     106             : 
     107       28435 :         _loop = &loop;
     108       28435 :         _device = &dev;
     109       28435 :         _request = move(req);
     110       28435 :         _pool = _request->getPool();
     111       28435 :         _timeStart = platform::clock(FrameClockType);
     112       28435 :         if (!_request || !_request->getQueue()) {
     113           0 :                 return false;
     114             :         }
     115             : 
     116       28435 :         _gen = gen;
     117       28435 :         _order = _request->getQueue()->incrementOrder();
     118             : 
     119             :         XL_FRAME_LOG(XL_FRAME_LOG_INFO, "Init; ready: ", _request->isReadyForSubmit());
     120       28435 :         return setup();
     121             : }
     122             : 
     123       98022 : void FrameHandle::update(bool init) {
     124       98022 :         if (!_valid) {
     125           2 :                 return;
     126             :         }
     127             : 
     128             :         XL_FRAME_LOG(XL_FRAME_LOG_INFO, "update");
     129             : 
     130      196040 :         for (auto &it : _queues) {
     131       98020 :                 it->update();
     132             :         }
     133             : }
     134             : 
     135       28419 : const Rc<FrameEmitter> &FrameHandle::getEmitter() const {
     136       28419 :         return _request->getEmitter();
     137             : }
     138             : 
     139           0 : const Rc<Queue> &FrameHandle::getQueue() const {
     140           0 :         return _request->getQueue();
     141             : }
     142             : 
     143      562581 : const FrameContraints &FrameHandle::getFrameConstraints() const {
     144      562581 :         return _request->getFrameConstraints();
     145             : }
     146             : 
     147       21998 : const ImageInfoData *FrameHandle::getImageSpecialization(const ImageAttachment *a) const {
     148       21998 :         return _request->getImageSpecialization(a);
     149             : }
     150             : 
     151       31440 : const FrameOutputBinding *FrameHandle::getOutputBinding(const Attachment *a) const {
     152       31440 :         return _request->getOutputBinding(a->getData());
     153             : }
     154             : 
     155           0 : const FrameOutputBinding *FrameHandle::getOutputBinding(const AttachmentData *a) const {
     156           0 :         return _request->getOutputBinding(a);
     157             : }
     158             : 
     159       29304 : Rc<ImageStorage> FrameHandle::getRenderTarget(const Attachment *a) const {
     160       29304 :         return _request->getRenderTarget(a->getData());
     161             : }
     162             : 
     163           0 : Rc<ImageStorage> FrameHandle::getRenderTarget(const AttachmentData *a) const {
     164           0 :         return _request->getRenderTarget(a);
     165             : }
     166             : 
     167         812 : const Vector<Rc<DependencyEvent>> &FrameHandle::getSignalDependencies() const {
     168         812 :         return _request->getSignalDependencies();
     169             : }
     170             : 
     171      208424 : FrameQueue *FrameHandle::getFrameQueue(Queue *queue) const {
     172      208424 :         for (auto &it : _queues) {
     173      208423 :                 if (it->getQueue() == queue) {
     174      208423 :                         return it;
     175             :                 }
     176             :         }
     177           0 :         return nullptr;
     178             : }
     179             : 
     180           0 : void FrameHandle::schedule(Function<bool(FrameHandle &)> &&cb, StringView tag) {
     181           0 :         auto linkId = retain();
     182           0 :         _loop->schedule([this, cb = move(cb), linkId] (Loop &ctx) {
     183           0 :                 if (!isValid()) {
     184           0 :                         release(linkId);
     185           0 :                         return true;
     186             :                 }
     187           0 :                 if (cb(*this)) {
     188           0 :                         release(linkId);
     189           0 :                         return true; // end
     190             :                 }
     191           0 :                 return false;
     192             :         }, tag);
     193           0 : }
     194             : 
     195      132441 : void FrameHandle::performInQueue(Function<void(FrameHandle &)> &&cb, Ref *ref, StringView tag) {
     196      132441 :         auto linkId = retain();
     197      132441 :         _loop->performInQueue(Rc<thread::Task>::create([this, cb = move(cb)] (const thread::Task &) -> bool {
     198      132436 :                 cb(*this);
     199      132441 :                 return true;
     200      132441 :         }, [=, this] (const thread::Task &, bool) {
     201             :                 XL_FRAME_LOG(XL_FRAME_LOG_INFO, "thread performed: '", tag, "'");
     202      132441 :                 release(linkId);
     203      132441 :         }, ref));
     204      132441 : }
     205             : 
     206      276183 : void FrameHandle::performInQueue(Function<bool(FrameHandle &)> &&perform, Function<void(FrameHandle &, bool)> &&complete,
     207             :                 Ref *ref, StringView tag) {
     208      276183 :         auto linkId = retain();
     209      276183 :         _loop->performInQueue(Rc<thread::Task>::create([this, perform = move(perform)] (const thread::Task &) -> bool {
     210      274342 :                 return perform(*this);
     211      276183 :         }, [=, this, complete = move(complete)] (const thread::Task &, bool success) {
     212      276183 :                 XL_FRAME_PROFILE(complete(*this, success), tag, 1000);
     213             :                 XL_FRAME_LOG(XL_FRAME_LOG_INFO, "thread performed: '", tag, "'");
     214      276183 :                 release(linkId);
     215      276183 :         }, ref));
     216      276183 : }
     217             : 
     218      134493 : void FrameHandle::performOnGlThread(Function<void(FrameHandle &)> &&cb, Ref *ref, bool immediate, StringView tag) {
     219      134493 :         if (immediate && _loop->isOnGlThread()) {
     220        1021 :                 XL_FRAME_PROFILE(cb(*this), tag, 1000);
     221             :         } else {
     222      133472 :                 auto linkId = retain();
     223      133476 :                 _loop->performOnGlThread([=, this, cb = move(cb)] () {
     224      133478 :                         XL_FRAME_PROFILE(cb(*this);, tag, 1000);
     225             :                         XL_FRAME_LOG(XL_FRAME_LOG_INFO, "thread performed: '", tag, "'");
     226      133478 :                         release(linkId);
     227      133478 :                 }, ref);
     228             :         }
     229      134499 : }
     230             : 
     231        3597 : void FrameHandle::performRequiredTask(Function<bool(FrameHandle &)> &&cb, Ref *ref, StringView tag) {
     232        3597 :         ++ _tasksRequired;
     233        3597 :         auto linkId = retain();
     234        3597 :         _loop->performInQueue(Rc<thread::Task>::create([this, cb = move(cb)] (const thread::Task &) -> bool {
     235        3596 :                 return cb(*this);
     236       10791 :         }, [this, linkId, tag] (const thread::Task &, bool success) {
     237             :                 XL_FRAME_LOG(XL_FRAME_LOG_INFO, "thread performed: '", tag, "'");
     238        3597 :                 if (success) {
     239        3597 :                         onRequiredTaskCompleted(tag);
     240             :                 } else {
     241           0 :                         invalidate();
     242             :                 }
     243        3597 :                 release(linkId);
     244        3597 :         }, ref));
     245        3597 : }
     246             : 
     247           0 : void FrameHandle::performRequiredTask(Function<bool(FrameHandle &)> &&perform, Function<void(FrameHandle &, bool)> &&complete,
     248             :                 Ref *ref, StringView tag) {
     249           0 :         ++ _tasksRequired;
     250           0 :         auto linkId = retain();
     251           0 :         _loop->performInQueue(Rc<thread::Task>::create([this, perform = move(perform)] (const thread::Task &) -> bool {
     252           0 :                 return perform(*this);
     253           0 :         }, [this, complete = move(complete), linkId, tag] (const thread::Task &, bool success) {
     254           0 :                 XL_FRAME_PROFILE(complete(*this, success), tag, 1000);
     255             :                 XL_FRAME_LOG(XL_FRAME_LOG_INFO, "thread performed: '", tag, "'");
     256           0 :                 if (success) {
     257           0 :                         onRequiredTaskCompleted(tag);
     258             :                 } else {
     259           0 :                         invalidate();
     260             :                 }
     261           0 :                 release(linkId);
     262           0 :         }, ref));
     263           0 : }
     264             : 
     265        8295 : bool FrameHandle::isValid() const {
     266        8295 :         return _valid && (!_request->getEmitter() || _request->getEmitter()->isFrameValid(*this));
     267             : }
     268             : 
     269       27046 : bool FrameHandle::isPersistentMapping() const {
     270       27046 :         return _request->isPersistentMapping();
     271             : }
     272             : 
     273       69649 : Rc<AttachmentInputData> FrameHandle::getInputData(const AttachmentData *attachment) {
     274       69649 :         return _request->getInputData(attachment);
     275             : }
     276             : 
     277      138935 : bool FrameHandle::isReadyForSubmit() const {
     278      138935 :         return _request->isReadyForSubmit();
     279             : }
     280             : 
     281           0 : void FrameHandle::setReadyForSubmit(bool value) {
     282           0 :         if (!isValid()) {
     283             :                 XL_FRAME_LOG(XL_FRAME_LOG_INFO, "[invalid] frame ready to submit");
     284           0 :                 return;
     285             :         }
     286             : 
     287             :         XL_FRAME_LOG(XL_FRAME_LOG_INFO, "frame ready to submit");
     288           0 :         _request->setReadyForSubmit(value);
     289           0 :         if (_request->isReadyForSubmit()) {
     290           0 :                 _loop->performOnGlThread([this] {
     291           0 :                         update();
     292           0 :                 }, this);
     293             :         }
     294             : }
     295             : 
     296          32 : void FrameHandle::invalidate() {
     297          32 :         if (_loop->isOnGlThread()) {
     298          32 :                 if (_valid) {
     299          16 :                         if (!_timeEnd) {
     300          16 :                                 _timeEnd = platform::clock(FrameClockType);
     301             :                         }
     302             : 
     303          16 :                         if (auto e = _request->getEmitter()) {
     304             :                                 XL_FRAME_LOG(XL_FRAME_LOG_INFO, "complete: ", e->getFrameTime());
     305          16 :                         }
     306             : 
     307          16 :                         _valid = false;
     308          16 :                         _completed = true;
     309             : 
     310          16 :                         HashMap<const AttachmentData *, FrameAttachmentData *> attachments;
     311          32 :                         for (auto &it : _queues) {
     312         160 :                                 for (auto &iit : it->getAttachments()) {
     313         144 :                                         if (iit.second.handle->isOutput()) {
     314          16 :                                                 attachments.emplace(iit.first, (FrameAttachmentData *)&iit.second);
     315             :                                         }
     316             :                                 }
     317          16 :                                 it->invalidate();
     318             :                         }
     319             : 
     320          16 :                         if (!_submitted) {
     321          16 :                                 _submitted = true;
     322          16 :                                 if (_request->getEmitter()) {
     323          16 :                                         _request->getEmitter()->setFrameSubmitted(*this);
     324             :                                 }
     325             :                         }
     326             : 
     327          16 :                         if (_complete) {
     328          16 :                                 _complete(*this);
     329             :                         }
     330             : 
     331          16 :                         if (_request) {
     332          16 :                                 _request->finalize(*_loop, attachments, _valid);
     333          32 :                                 for (auto &it : _queues) {
     334          16 :                                         _request->signalDependencies(*_loop, it->getQueue(), _valid);
     335             :                                 }
     336             :                         }
     337          16 :                 }
     338             :         } else {
     339           0 :                 _loop->performOnGlThread([this] {
     340           0 :                         invalidate();
     341           0 :                 }, this);
     342             :         }
     343          32 : }
     344             : 
     345        9203 : void FrameHandle::setCompleteCallback(Function<void(FrameHandle &)> &&cb) {
     346        9203 :         _complete = move(cb);
     347        9203 : }
     348             : 
     349       28435 : bool FrameHandle::setup() {
     350       28435 :         _pool->perform([&, this] {
     351       28435 :                 auto q = Rc<FrameQueue>::create(_pool, _request->getQueue(), *this);
     352       28435 :                 q->setup();
     353             : 
     354       28435 :                 _queues.emplace_back(move(q));
     355       28435 :         });
     356             : 
     357       28435 :         if (!_valid) {
     358           0 :                 for (auto &it : _queues) {
     359           0 :                         it->invalidate();
     360             :                 }
     361             :         }
     362             : 
     363       28435 :         if (_request) {
     364       28435 :                 _request->attachFrame(this);
     365             :         }
     366             : 
     367       28435 :         return true;
     368             : }
     369             : 
     370       28419 : void FrameHandle::onQueueSubmitted(FrameQueue &queue) {
     371       28419 :         ++ _queuesSubmitted;
     372       28419 :         if (_queuesSubmitted == _queues.size()) {
     373       28419 :                 _submitted = true;
     374       28419 :                 if (_request->getEmitter()) {
     375        7322 :                         _request->getEmitter()->setFrameSubmitted(*this);
     376             :                 }
     377             :         }
     378       28419 : }
     379             : 
     380       28419 : void FrameHandle::onQueueComplete(FrameQueue &queue) {
     381       28419 :         _submissionTime += queue.getSubmissionTime();
     382       28419 :         ++ _queuesCompleted;
     383       28419 :         tryComplete();
     384       28419 : }
     385             : 
     386        3597 : void FrameHandle::onRequiredTaskCompleted(StringView tag) {
     387        3597 :         ++ _tasksCompleted;
     388        3597 :         tryComplete();
     389        3597 : }
     390             : 
     391       28419 : void FrameHandle::onOutputAttachment(FrameAttachmentData &data) {
     392       28419 :         if (_request->onOutputReady(*_loop, data)) {
     393       19232 :                 data.image = nullptr;
     394       19232 :                 data.state = FrameAttachmentState::Detached;
     395             :         }
     396       28419 : }
     397             : 
     398          16 : void FrameHandle::onOutputAttachmentInvalidated(FrameAttachmentData &data) {
     399          16 :         _request->onOutputInvalidated(*_loop, data);
     400          16 : }
     401             : 
     402       31173 : void FrameHandle::waitForDependencies(const Vector<Rc<DependencyEvent>> &events, Function<void(FrameHandle &, bool)> &&cb) {
     403       31173 :         auto linkId = retain();
     404       31173 :         _loop->waitForDependencies(events, [this, cb = move(cb), linkId] (bool success) {
     405       31173 :                 cb(*this, success);
     406       31173 :                 release(linkId);
     407       31173 :         });
     408       31173 : }
     409             : 
     410       29352 : void FrameHandle::waitForInput(FrameQueue &queue, const Rc<AttachmentHandle> &a, Function<void(bool)> &&cb) {
     411       29352 :         _request->waitForInput(queue, a, move(cb));
     412       29352 : }
     413             : 
     414        1721 : void FrameHandle::signalDependencies(bool success) {
     415        3442 :         for (auto &it : _queues) {
     416        1721 :                 _request->signalDependencies(*_loop, it->getQueue(), _valid);
     417             :         }
     418        1721 : }
     419             : 
     420          16 : void FrameHandle::onQueueInvalidated(FrameQueue &) {
     421          16 :         ++ _queuesCompleted;
     422          16 :         invalidate();
     423          16 : }
     424             : 
     425       32016 : void FrameHandle::tryComplete() {
     426       64032 :         if (_tasksCompleted == _tasksRequired.load() && _queuesCompleted == _queues.size()) {
     427       28419 :                 onComplete();
     428             :         }
     429       32016 : }
     430             : 
     431       28419 : void FrameHandle::onComplete() {
     432       28419 :         if (!_completed && _valid) {
     433       28419 :                 _timeEnd = platform::clock(FrameClockType);
     434       28419 :                 if (auto e = getEmitter()) {
     435             :                         XL_FRAME_LOG(XL_FRAME_LOG_INFO, "complete: ", e->getFrameTime());
     436       28419 :                 }
     437       28419 :                 _completed = true;
     438             : 
     439       28419 :                 HashMap<const AttachmentData *, FrameAttachmentData *> attachments;
     440       56838 :                 for (auto &it : _queues) {
     441      422630 :                         for (auto &iit : it->getAttachments()) {
     442      394211 :                                 if (iit.second.handle->isOutput()) {
     443       28419 :                                         attachments.emplace(iit.first, (FrameAttachmentData *)&iit.second);
     444             :                                 }
     445             :                         }
     446             :                 }
     447             : 
     448       28419 :                 if (_complete) {
     449        9187 :                         _complete(*this);
     450             :                 }
     451             : 
     452       28419 :                 _request->finalize(*_loop, attachments, _valid);
     453             : 
     454       56838 :                 for (auto &it : _queues) {
     455       28419 :                         _request->signalDependencies(*_loop, it->getQueue(), _valid);
     456             :                 }
     457       28419 :         }
     458       28419 : }
     459             : 
     460             : }

Generated by: LCOV version 1.14