LCOV - code coverage report
Current view: top level - xenolith/backend/vk - XLVkSync.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 135 170 79.4 %
Date: 2024-05-12 00:16:13 Functions: 25 28 89.3 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2021 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 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 "XLVkSync.h"
      25             : #include "XLVkDevice.h"
      26             : 
      27             : #ifndef XL_VKAPI_LOG
      28             : #define XL_VKAPI_LOG(...)
      29             : #endif
      30             : 
      31             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      32             : 
      33      268748 : Semaphore::~Semaphore() { }
      34             : 
      35      134374 : static void Semaphore_destroy(core::Device *dev, core::ObjectType, core::ObjectHandle ptr, void *) {
      36      134374 :         auto d = ((Device *)dev);
      37      134374 :         d->getTable()->vkDestroySemaphore(d->getDevice(), (VkSemaphore)ptr.get(), nullptr);
      38      134374 : }
      39             : 
      40         146 : static void Fence_destroy(core::Device *dev, core::ObjectType, core::ObjectHandle ptr, void *) {
      41         146 :         auto d = ((Device *)dev);
      42         146 :         d->getTable()->vkDestroyFence(d->getDevice(), (VkFence)ptr.get(), nullptr);
      43         146 : }
      44             : 
      45      134374 : bool Semaphore::init(Device &dev) {
      46      134374 :         VkSemaphoreCreateInfo semaphoreInfo{};
      47      134374 :         semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
      48      134374 :         semaphoreInfo.pNext = nullptr;
      49      134374 :         semaphoreInfo.flags = 0;
      50             : 
      51      134374 :         if (dev.getTable()->vkCreateSemaphore(dev.getDevice(), &semaphoreInfo, nullptr, &_sem) == VK_SUCCESS) {
      52      134374 :                 return core::Semaphore::init(dev, Semaphore_destroy, core::ObjectType::Semaphore, core::ObjectHandle(_sem));
      53             :         }
      54             : 
      55           0 :         return false;
      56             : }
      57             : 
      58         292 : Fence::~Fence() {
      59         146 :         doRelease(false);
      60         292 : }
      61             : 
      62         146 : bool Fence::init(Device &dev) {
      63         146 :         VkFenceCreateInfo fenceInfo{};
      64         146 :         fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
      65         146 :         fenceInfo.pNext = nullptr;
      66         146 :         fenceInfo.flags = 0;
      67             : 
      68         146 :         _state = Disabled;
      69             : 
      70         146 :         if (dev.getTable()->vkCreateFence(dev.getDevice(), &fenceInfo, nullptr, &_fence) == VK_SUCCESS) {
      71         146 :                 return core::Object::init(dev, Fence_destroy, core::ObjectType::Fence, core::ObjectHandle(_fence));
      72             :         }
      73           0 :         return false;
      74             : }
      75             : 
      76      207399 : void Fence::clear() {
      77      207399 :         if (_releaseFn) {
      78           0 :                 _releaseFn = nullptr;
      79             :         }
      80      207399 :         if (_scheduleFn) {
      81        9517 :                 _scheduleFn = nullptr;
      82             :         }
      83      207399 : }
      84             : 
      85      207399 : void Fence::setFrame(Function<bool()> &&schedule, Function<void()> &&release, uint64_t f) {
      86      207399 :         _frame = f;
      87      207399 :         _scheduleFn = move(schedule);
      88      207399 :         _releaseFn = move(release);
      89      207399 : }
      90             : 
      91           0 : void Fence::setScheduleCallback(Function<bool()> &&schedule) {
      92           0 :         _scheduleFn = move(schedule);
      93           0 : }
      94             : 
      95           0 : void Fence::setReleaseCallback(Function<bool()> &&release) {
      96           0 :         _releaseFn = move(release);
      97           0 : }
      98             : 
      99      197902 : void Fence::setArmed(DeviceQueue &q) {
     100      197902 :         std::unique_lock<Mutex> lock(_mutex);
     101      197901 :         _state = Armed;
     102      197901 :         _queue = &q;
     103      197901 :         _queue->retainFence(*this);
     104      197902 :         _armedTime = platform::clock(core::ClockType::Monotonic);
     105      197900 : }
     106             : 
     107        9538 : void Fence::setArmed() {
     108        9538 :         std::unique_lock<Mutex> lock(_mutex);
     109        9538 :         _state = Armed;
     110        9538 :         _armedTime = platform::clock(core::ClockType::Monotonic);
     111        9538 : }
     112             : 
     113      182115 : void Fence::setTag(StringView tag) {
     114      182115 :         _tag = tag;
     115      182115 : }
     116             : 
     117      534485 : void Fence::addRelease(Function<void(bool)> &&cb, Ref *ref, StringView tag) {
     118      534485 :         std::unique_lock<Mutex> lock(_mutex);
     119      534485 :         _release.emplace_back(ReleaseHandle({move(cb), ref, tag}));
     120      534485 : }
     121             : 
     122      197882 : bool Fence::schedule(Loop &loop) {
     123      197882 :         std::unique_lock<Mutex> lock(_mutex);
     124      197882 :         if (_state != Armed) {
     125           0 :                 lock.unlock();
     126           0 :                 if (_releaseFn) {
     127           0 :                         loop.performOnGlThread([this] {
     128           0 :                                 doRelease(false);
     129             : 
     130           0 :                                 if (_releaseFn) {
     131           0 :                                         auto releaseFn = move(_releaseFn);
     132           0 :                                         _releaseFn = nullptr;
     133           0 :                                         _scheduleFn = nullptr;
     134           0 :                                         releaseFn();
     135           0 :                                 } else {
     136           0 :                                         _scheduleFn = nullptr;
     137             :                                 }
     138           0 :                         }, this, true);
     139             :                 } else {
     140           0 :                         doRelease(false);
     141           0 :                         _scheduleFn = nullptr;
     142             :                 }
     143           0 :                 return false;
     144             :         } else {
     145      197882 :                 lock.unlock();
     146             : 
     147      197882 :                 if (check(loop, true)) {
     148       96672 :                         _scheduleFn = nullptr;
     149       96672 :                         return false;
     150             :                 }
     151             :         }
     152             : 
     153      101210 :         if (!_scheduleFn) {
     154           0 :                 return false;
     155             :         }
     156             : 
     157      101210 :         auto scheduleFn = move(_scheduleFn);
     158      101210 :         _scheduleFn = nullptr;
     159             : 
     160      101210 :         if (lock.owns_lock()) {
     161           0 :                 lock.unlock();
     162             :         }
     163             : 
     164      101210 :         return scheduleFn();
     165      197882 : }
     166             : 
     167   107271349 : bool Fence::check(Loop &loop, bool lockfree) {
     168   107271349 :         std::unique_lock<Mutex> lock(_mutex);
     169   107271346 :         if (_state != Armed) {
     170           0 :                 return true;
     171             :         }
     172             : 
     173   107271346 :         auto dev = ((Device *)_object.device);
     174             :         enum VkResult status;
     175             : 
     176   107271346 :         dev->makeApiCall([&, this] (const DeviceTable &table, VkDevice device) {
     177   107271321 :                 if (lockfree) {
     178   107261865 :                         status = table.vkGetFenceStatus(device, _fence);
     179             :                 } else {
     180        9456 :                         status = table.vkWaitForFences(device, 1, &_fence, VK_TRUE, UINT64_MAX);
     181             :                 }
     182   107271424 :         });
     183             : 
     184   107271406 :         switch (status) {
     185      207440 :         case VK_SUCCESS:
     186      207440 :                 _state = Signaled;
     187             :                 XL_VKAPI_LOG("Fence [", _frame, "] ", _tag, ": signaled: ", platform::clock(core::ClockType::Monotonic) - _armedTime);
     188      207440 :                 lock.unlock();
     189      207439 :                 if (loop.isOnGlThread()) {
     190      197882 :                         doRelease(true);
     191      197882 :                         scheduleReset(loop);
     192             :                 } else {
     193        9558 :                         scheduleReleaseReset(loop, true);
     194             :                 }
     195      207441 :                 return true;
     196             :                 break;
     197   107063983 :         case VK_TIMEOUT:
     198             :         case VK_NOT_READY:
     199   107063983 :                 _state = Armed;
     200   107063983 :                 if (platform::clock(core::ClockType::Monotonic) - _armedTime > 1'000'000) {
     201           0 :                         lock.unlock();
     202           0 :                         if (_queue) {
     203             :                                 XL_VKAPI_LOG("Fence [", _queue->getFrameIndex(), "] Fence is possibly broken: ", _tag);
     204             :                         } else {
     205             :                                 XL_VKAPI_LOG("Fence [", _frame, "] Fence is possibly broken: ", _tag);
     206             :                         }
     207           0 :                         return check(loop, false);
     208             :                 }
     209   107063983 :                 return false;
     210           0 :         default:
     211           0 :                 break;
     212             :         }
     213           0 :         return false;
     214   107271407 : }
     215             : 
     216      328136 : void Fence::autorelease(Rc<Ref> &&ref) {
     217      328136 :         _autorelease.emplace_back(move(ref));
     218      328136 : }
     219             : 
     220      197882 : void Fence::scheduleReset(Loop &loop) {
     221      197882 :         if (_releaseFn) {
     222      197882 :                 loop.performInQueue(Rc<thread::Task>::create([this] (const thread::Task &) {
     223      197882 :                         auto dev = ((Device *)_object.device);
     224      197882 :                         dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
     225      197882 :                         return true;
     226      395764 :                 }, [this] (const thread::Task &, bool success) {
     227      197882 :                         auto releaseFn = move(_releaseFn);
     228      197882 :                         _releaseFn = nullptr;
     229      197882 :                         releaseFn();
     230      593646 :                 }, this));
     231             :         } else {
     232           0 :                 auto dev = ((Device *)_object.device);
     233           0 :                 dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
     234             :         }
     235      197882 : }
     236             : 
     237        9559 : void Fence::scheduleReleaseReset(Loop &loop, bool s) {
     238        9559 :         if (_releaseFn) {
     239        9517 :                 loop.performInQueue(Rc<thread::Task>::create([this] (const thread::Task &) {
     240        9517 :                         auto dev = ((Device *)_object.device);
     241        9517 :                         dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
     242        9517 :                         return true;
     243       28551 :                 }, [this, s] (const thread::Task &, bool success) {
     244        9517 :                         doRelease(s);
     245             : 
     246        9517 :                         auto releaseFn = move(_releaseFn);
     247        9517 :                         _releaseFn = nullptr;
     248        9517 :                         releaseFn();
     249       28551 :                 }, this));
     250             :         } else {
     251          42 :                 auto dev = ((Device *)_object.device);
     252          42 :                 dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
     253          42 :                 doRelease(s);
     254             :         }
     255        9559 : }
     256             : 
     257      207587 : void Fence::doRelease(bool success) {
     258      207587 :         if (_queue) {
     259      197903 :                 _queue->releaseFence(*this);
     260      197903 :                 _queue = nullptr;
     261             :         }
     262      207587 :         if (!_release.empty()) {
     263             :                 XL_PROFILE_BEGIN(total, "vk::Fence::reset", "total", 250);
     264      732388 :                 for (auto &it : _release) {
     265      534485 :                         if (it.callback) {
     266             :                                 XL_PROFILE_BEGIN(fence, "vk::Fence::reset", it.tag, 250);
     267      534485 :                                 it.callback(success);
     268             :                                 XL_PROFILE_END(fence);
     269             :                         }
     270             :                 }
     271             :                 XL_PROFILE_END(total);
     272      197903 :                 _release.clear();
     273             :         }
     274      207587 :         _autorelease.clear();
     275      207587 :         _tag = StringView();
     276      207587 : }
     277             : 
     278             : }

Generated by: LCOV version 1.14