LCOV - code coverage report
Current view: top level - xenolith/core - XLCoreFrameEmitter.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 87 152 57.2 %
Date: 2024-05-12 00:16:13 Functions: 19 28 67.9 %

          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 "XLCoreFrameEmitter.h"
      24             : #include "XLCoreFrameQueue.h"
      25             : #include "XLCoreFrameCache.h"
      26             : #include "XLCoreQueue.h"
      27             : #include "XLCoreLoop.h"
      28             : #include "XLCorePlatform.h"
      29             : #include "XLCoreFrameRequest.h"
      30             : 
      31             : #ifndef XL_FRAME_EMITTER_LOG
      32             : #define XL_FRAME_EMITTER_LOG(...)
      33             : #endif
      34             : 
      35             : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
      36             : 
      37          32 : FrameEmitter::~FrameEmitter() { }
      38             : 
      39          16 : bool FrameEmitter::init(const Rc<Loop> &loop, uint64_t frameInterval) {
      40          16 :         _frameInterval = frameInterval;
      41          16 :         _loop = loop;
      42             : 
      43          16 :         _avgFrameTime.reset(0);
      44          16 :         _avgFrameTimeValue = 0;
      45             : 
      46          16 :         return true;
      47             : }
      48             : 
      49          16 : void FrameEmitter::invalidate() {
      50          16 :         _valid = false;
      51          16 :         auto frames = _frames;
      52          32 :         for (auto &it : frames) {
      53          16 :                 it->invalidate();
      54             :         }
      55          16 :         _frames.clear();
      56          16 : }
      57             : 
      58        7338 : void FrameEmitter::setFrameSubmitted(FrameHandle &frame) {
      59        7338 :         if (!_loop->isOnGlThread()) {
      60           0 :                 return;
      61             :         }
      62             : 
      63             :         XL_FRAME_EMITTER_LOG("FrameTime:        ", _frame.load(), "   ", platform::clock(ClockType::Monotonic) - _frame.load(), " mks");
      64             : 
      65        7338 :         auto it = _frames.begin();
      66       14676 :         while (it != _frames.end()) {
      67        7338 :                 if ((*it) == &frame) {
      68        7338 :                         if (frame.isValid()) {
      69        7322 :                                 _framesPending.emplace_back(&frame);
      70             :                         }
      71        7338 :                         it = _frames.erase(it);
      72             :                 } else {
      73           0 :                         ++ it;
      74             :                 }
      75             :         }
      76             : 
      77             :         XL_PROFILE_BEGIN(success, "FrameEmitter::setFrameSubmitted", "success", 500);
      78             :         XL_PROFILE_BEGIN(onFrameSubmitted, "FrameEmitter::setFrameSubmitted", "onFrameSubmitted", 500);
      79        7338 :         onFrameSubmitted(frame);
      80             :         XL_PROFILE_END(onFrameSubmitted)
      81             : 
      82        7338 :         ++ _submitted;
      83             :         XL_PROFILE_BEGIN(onFrameRequest, "FrameEmitter::setFrameSubmitted", "onFrameRequest", 500);
      84        7338 :         if (!_onDemand) {
      85           0 :                 onFrameRequest(false);
      86             :         }
      87             :         XL_PROFILE_END(onFrameRequest)
      88             :         XL_PROFILE_END(success)
      89             : }
      90             : 
      91        7323 : bool FrameEmitter::isFrameValid(const FrameHandle &frame) {
      92        7323 :         if (_valid && frame.getGen() == _gen && std::find(_frames.begin(), _frames.end(), &frame) != _frames.end()) {
      93        7323 :                 return true;
      94             :         }
      95           0 :         return false;
      96             : }
      97             : 
      98           0 : void FrameEmitter::acquireNextFrame() { }
      99             : 
     100           0 : void FrameEmitter::dropFrameTimeout() {
     101           0 :         _loop->performOnGlThread([this] {
     102           0 :                 if (!_frameTimeoutPassed) {
     103           0 :                         ++ _order; // increment timeout timeline
     104           0 :                         onFrameTimeout(_order);
     105             :                 }
     106           0 :         }, this, true);
     107           0 : }
     108             : 
     109          16 : void FrameEmitter::dropFrames() {
     110          16 :         if (!_loop->isOnGlThread()) {
     111           0 :                 return;
     112             :         }
     113             : 
     114          16 :         for (auto &it : _frames) {
     115           0 :                 it->invalidate();
     116             :         }
     117          16 :         _frames.clear();
     118          16 :         _framesPending.clear();
     119             : }
     120             : 
     121        7338 : uint64_t FrameEmitter::getLastFrameTime() const {
     122        7338 :         return _lastFrameTime;
     123             : }
     124          16 : uint64_t FrameEmitter::getAvgFrameTime() const {
     125          16 :         return _avgFrameTimeValue;
     126             : }
     127        7338 : uint64_t FrameEmitter::getAvgFenceTime() const {
     128        7338 :         return _avgFenceIntervalValue;
     129             : }
     130             : 
     131          16 : bool FrameEmitter::isReadyForSubmit() const {
     132          16 :         return _frames.empty() && _framesPending.empty();
     133             : }
     134             : 
     135        7322 : void FrameEmitter::setEnableBarrier(bool value) {
     136        7322 :         _enableBarrier = value;
     137        7322 : }
     138             : 
     139        7338 : void FrameEmitter::onFrameEmitted(FrameHandle &) { }
     140             : 
     141        7338 : void FrameEmitter::onFrameSubmitted(FrameHandle &) { }
     142             : 
     143        7338 : void FrameEmitter::onFrameComplete(FrameHandle &frame) {
     144        7338 :         if (!_loop->isOnGlThread()) {
     145           0 :                 return;
     146             :         }
     147             : 
     148        7338 :         _lastFrameTime = frame.getTimeEnd() - frame.getTimeStart();
     149        7338 :         _avgFrameTime.addValue(frame.getTimeEnd() - frame.getTimeStart());
     150        7338 :         _avgFrameTimeValue = _avgFrameTime.getAverage();
     151             : 
     152        7338 :         if (auto t = frame.getSubmissionTime()) {
     153        7322 :                 _avgFenceInterval.addValue(t);
     154        7322 :                 _avgFenceIntervalValue = _avgFenceInterval.getAverage();
     155             :         }
     156             : 
     157        7338 :         auto it = _framesPending.begin();
     158       14660 :         while (it != _framesPending.end()) {
     159        7322 :                 if ((*it) == &frame) {
     160        7322 :                         it = _framesPending.erase(it);
     161             :                 } else {
     162           0 :                         ++ it;
     163             :                 }
     164             :         }
     165             : 
     166        7338 :         if (_framesPending.size() <= 1 && _frames.empty() && !_onDemand) {
     167           0 :                 onFrameRequest(false);
     168             :         }
     169             : 
     170        7338 :         if (_framesPending.empty()) {
     171        7338 :                 for (auto &it : _frames) {
     172           0 :                         if (!it->isReadyForSubmit()) {
     173           0 :                                 it->setReadyForSubmit(true);
     174           0 :                                 break;
     175             :                         }
     176             :                 }
     177             :         }
     178             : }
     179             : 
     180           0 : void FrameEmitter::onFrameTimeout(uint64_t order) {
     181           0 :         if (order == _order) {
     182           0 :                 _frameTimeoutPassed = true;
     183           0 :                 onFrameRequest(true);
     184             :         }
     185           0 : }
     186             : 
     187           0 : void FrameEmitter::onFrameRequest(bool timeout) {
     188           0 :         if (canStartFrame()) {
     189           0 :                 auto next = platform::clock();
     190             : 
     191           0 :                 if (_nextFrameRequest) {
     192           0 :                         scheduleFrameTimeout();
     193           0 :                         submitNextFrame(move(_nextFrameRequest));
     194           0 :                 } else if (!_nextFrameAcquired) {
     195           0 :                         if (_frame.load()) {
     196             :                                 XL_FRAME_EMITTER_LOG(timeout ? "FrameRequest [T]: " : "FrameRequest [S]: ", _frame.load(), "   ",
     197             :                                                 next - _frame.load(), " mks");
     198             :                         }
     199           0 :                         _frame = next;
     200           0 :                         _nextFrameAcquired = true;
     201           0 :                         scheduleFrameTimeout();
     202           0 :                         acquireNextFrame();
     203             :                 }
     204             :         }
     205           0 : }
     206             : 
     207        7338 : Rc<FrameHandle> FrameEmitter::makeFrame(Rc<FrameRequest> &&req, bool readyForSubmit) {
     208        7338 :         if (!_valid) {
     209           0 :                 return nullptr;
     210             :         }
     211             : 
     212        7338 :         req->setReadyForSubmit(readyForSubmit);
     213        7338 :         return _loop->makeFrame(move(req), _gen);
     214             : }
     215             : 
     216           0 : bool FrameEmitter::canStartFrame() const {
     217           0 :         if (!_valid || !_frameTimeoutPassed) {
     218           0 :                 return false;
     219             :         }
     220             : 
     221           0 :         if (_frames.empty()) {
     222           0 :                 return _framesPending.size() <= 1;
     223             :         }
     224             : 
     225           0 :         for (auto &it : _frames) {
     226           0 :                 if (!it->isSubmitted()) {
     227           0 :                         return false;
     228             :                 }
     229             :         }
     230             : 
     231           0 :         return _framesPending.size() <= 1;
     232             : }
     233             : 
     234           0 : void FrameEmitter::scheduleNextFrame(Rc<FrameRequest> &&req) {
     235           0 :         _nextFrameRequest = move(req);
     236           0 : }
     237             : 
     238           0 : void FrameEmitter::scheduleFrameTimeout() {
     239           0 :         if (_valid && _frameInterval && _frameTimeoutPassed && !_onDemand) {
     240           0 :                 _frameTimeoutPassed = false;
     241           0 :                 ++ _order;
     242           0 :                 [[maybe_unused]] auto t = platform::clock();
     243           0 :                 _loop->schedule([=, guard = Rc<FrameEmitter>(this), idx = _order] (Loop &ctx) {
     244             :                         XL_FRAME_EMITTER_LOG("TimeoutPassed:    ", _frame.load(), "   ", platform::clock() - _frame.load(), " (",
     245             :                                         platform::clock(ClockType::Monotonic) - t, ") mks");
     246           0 :                         guard->onFrameTimeout(idx);
     247           0 :                         return true; // end spinning
     248           0 :                 }, _frameInterval - config::FrameIntervalSafeOffset, "FrameEmitter::scheduleFrameTimeout");
     249             :         }
     250           0 : }
     251             : 
     252        7322 : Rc<FrameRequest> FrameEmitter::makeRequest(const FrameContraints &constraints) {
     253        7322 :         _frame = platform::clock();
     254       14644 :         return Rc<FrameRequest>::create(this, constraints);
     255             : }
     256             : 
     257        7338 : Rc<FrameHandle> FrameEmitter::submitNextFrame(Rc<FrameRequest> &&req) {
     258        7338 :         if (!_valid) {
     259           0 :                 return nullptr;
     260             :         }
     261             : 
     262        7338 :         bool readyForSubmit = !_enableBarrier || (_frames.empty() && _framesPending.empty());
     263        7338 :         auto frame = makeFrame(move(req), readyForSubmit);
     264        7338 :         _nextFrameRequest = nullptr;
     265        7338 :         if (frame && frame->isValidFlag()) {
     266        7338 :                 auto now = platform::clock();
     267        7338 :                 _lastSubmit = now;
     268             : 
     269        7338 :                 frame->setCompleteCallback([this] (FrameHandle &frame) {
     270        7338 :                         onFrameComplete(frame);
     271        7338 :                 });
     272             : 
     273             :                 XL_FRAME_EMITTER_LOG("SubmitNextFrame:  ", _frame.load(), "   ", platform::clock(ClockType::Monotonic) - _frame.load(), " mks ", readyForSubmit);
     274             : 
     275        7338 :                 _nextFrameAcquired = false;
     276        7338 :                 onFrameEmitted(*frame);
     277        7338 :                 frame->update(true);
     278        7338 :                 if (frame->isValidFlag()) {
     279        7338 :                         if (_frames.empty() && _framesPending.empty() && !frame->isReadyForSubmit()) {
     280           0 :                                 _frames.push_back(frame);
     281           0 :                                 frame->setReadyForSubmit(true);
     282             :                         } else {
     283        7338 :                                 _frames.push_back(frame);
     284             :                         }
     285             :                 }
     286        7338 :                 return frame;
     287             :         }
     288           0 :         return nullptr;
     289        7338 : }
     290             : 
     291             : }

Generated by: LCOV version 1.14