Line data Source code
1 : /**
2 : Copyright (c) 2022 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 "XLVkLoop.h"
25 : #include "XLVkInstance.h"
26 : #include "XLVkDevice.h"
27 : #include "XLVkTextureSet.h"
28 : #include "XLVkConfig.h"
29 : #include "XLCoreFrameCache.h"
30 :
31 : #include "XLVkTransferQueue.h"
32 : #include "XLVkRenderQueueCompiler.h"
33 : #include "XLVkMeshCompiler.h"
34 : #include "XLVkMaterialCompiler.h"
35 :
36 : #define XL_VK_DEPS_DEBUG 0
37 :
38 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
39 :
40 : struct DependencyRequest : public Ref {
41 : Vector<Rc<core::DependencyEvent>> events;
42 : Function<void(bool)> callback;
43 : uint64_t initial = 0;
44 : uint32_t signaled = 0;
45 : bool success = true;
46 : };
47 :
48 : struct PresentationData {
49 42 : PresentationData() { }
50 :
51 : uint64_t getLastUpdateInterval() {
52 : auto tmp = lastUpdate;
53 : lastUpdate = platform::clock(core::ClockType::Monotonic);
54 : return lastUpdate - tmp;
55 : }
56 :
57 : uint64_t now = platform::clock(core::ClockType::Monotonic);
58 : uint64_t last = 0;
59 : uint64_t updateInterval = config::PresentationSchedulerInterval;
60 : uint64_t lastUpdate = 0;
61 : };
62 :
63 : struct Loop::Internal final : memory::AllocPool {
64 42 : Internal(memory::pool_t *pool, Loop *l) : pool(pool), loop(l) {
65 42 : timers = new (pool) memory::vector<Timer>(); timers->reserve(8);
66 42 : reschedule = new (pool) memory::vector<Timer>(); reschedule->reserve(8);
67 42 : autorelease = new (pool) memory::vector<Rc<Ref>>(); autorelease->reserve(8);
68 42 : }
69 :
70 42 : void setDevice(Rc<Device> &&dev) {
71 42 : requiredTasks += 3;
72 :
73 42 : device = move(dev);
74 :
75 42 : device->begin(*loop, *queue, [this] (bool success) {
76 42 : if (info->onDeviceStarted) {
77 42 : info->onDeviceStarted(*loop, *device);
78 : }
79 :
80 42 : onInitTaskPerformed(success, "DeviceResources");
81 42 : });
82 :
83 42 : transferQueue = Rc<TransferQueue>::create();
84 42 : materialQueue = Rc<MaterialCompiler>::create();
85 42 : renderQueueCompiler = Rc<RenderQueueCompiler>::create(*device, transferQueue, materialQueue);
86 :
87 42 : compileQueue(transferQueue, [this] (bool success) {
88 42 : onInitTaskPerformed(success, "TransferQueue");
89 42 : });
90 42 : compileQueue(materialQueue, [this] (bool success) {
91 42 : onInitTaskPerformed(success, "MaterialCompiler");
92 42 : });
93 42 : }
94 :
95 42 : void endDevice() {
96 42 : if (!device) {
97 0 : return;
98 : }
99 :
100 42 : fences.clear();
101 42 : transferQueue = nullptr;
102 42 : renderQueueCompiler = nullptr;
103 42 : device->end();
104 :
105 42 : if (info->onDeviceFinalized) {
106 42 : info->onDeviceFinalized(*loop, *device);
107 : }
108 :
109 42 : device = nullptr;
110 : }
111 :
112 42 : void waitIdle() {
113 42 : auto r = running->exchange(false);
114 :
115 42 : queue->lock(); // lock to prevent new tasks
116 :
117 : // wait for all pending tasks on fences
118 42 : for (auto &it : scheduledFences) {
119 0 : it->check(*loop, false);
120 : }
121 42 : scheduledFences.clear();
122 :
123 42 : if (device) {
124 : // wait for device
125 42 : device->waitIdle();
126 : }
127 :
128 42 : queue->unlock();
129 :
130 : // wait for all CPU tasks
131 42 : queue->waitForAll();
132 :
133 : // after this, there should be no CPU or GPU tasks pending or executing
134 :
135 42 : if (r) {
136 0 : running->exchange(true);
137 : }
138 42 : }
139 :
140 21 : void compileResource(Rc<TransferResource> &&req) {
141 21 : auto h = loop->makeFrame(transferQueue->makeRequest(move(req)), 0);
142 21 : h->update(true);
143 21 : }
144 :
145 189 : void compileQueue(const Rc<core::Queue> &req, Function<void(bool)> &&cb) {
146 189 : auto input = Rc<RenderQueueInput>::alloc();
147 189 : input->queue = req;
148 :
149 189 : auto h = Rc<DeviceFrameHandle>::create(*loop, *device, renderQueueCompiler->makeRequest(move(input)), 0);
150 189 : if (cb) {
151 189 : h->setCompleteCallback([cb = move(cb), req] (FrameHandle &handle) {
152 189 : cb(handle.isValid());
153 189 : });
154 : }
155 :
156 189 : h->update(true);
157 189 : }
158 :
159 1193 : void compileMaterials(Rc<core::MaterialInputData> &&req, Vector<Rc<DependencyEvent>> &&deps) {
160 1193 : if (materialQueue->inProgress(req->attachment)) {
161 0 : materialQueue->appendRequest(req->attachment, move(req), move(deps));
162 : } else {
163 1193 : auto attachment = req->attachment;
164 1193 : materialQueue->setInProgress(attachment);
165 1193 : materialQueue->runMaterialCompilationFrame(*loop, move(req), move(deps));
166 : }
167 1193 : }
168 :
169 126 : void onInitTaskPerformed(bool success, StringView view) {
170 126 : if (success) {
171 126 : -- requiredTasks;
172 126 : if (requiredTasks == 0 && signalInit) {
173 42 : signalInit();
174 : }
175 : } else {
176 0 : log::error("Loop", "Fail to initalize: ", view);
177 : }
178 126 : }
179 :
180 4392 : void signalDependencies(const Vector<Rc<DependencyEvent>> &events, Queue *queue, bool success) {
181 8784 : for (auto &it : events) {
182 4392 : if (it->signal(queue, success)) {
183 2302 : auto iit = dependencyRequests.equal_range(it.get());
184 2302 : auto tmp = iit;
185 6906 : while (iit.first != iit.second) {
186 4604 : auto &v = iit.first->second;
187 4604 : if (!success) {
188 0 : v->success = false;
189 : }
190 4604 : ++ v->signaled;
191 4604 : if (v->signaled == v->events.size()) {
192 : #if XL_VK_DEPS_DEBUG
193 : StringStream str; str << "signalDependencies:";
194 : for (auto &it : v->events) {
195 : str << " " << it->getId();
196 : }
197 : str << "\n";
198 : log::debug("vk::Loop", "Signal: ", str.str());
199 : #endif
200 4352 : v->callback(iit.first->second->success);
201 : }
202 4604 : ++ iit.first;
203 : }
204 :
205 2302 : dependencyRequests.erase(tmp.first, tmp.second);
206 : }
207 : }
208 4392 : }
209 :
210 4352 : void waitForDependencies(Vector<Rc<DependencyEvent>> &&events, Function<void(bool)> &&cb) {
211 : #if XL_VK_DEPS_DEBUG
212 : StringStream str; str << "waitForDependencies:";
213 : for (auto &it : events) {
214 : str << " " << it->getId();
215 : }
216 : log::debug("vk::Loop", "Wait: ", str.str());
217 : #endif
218 :
219 4352 : auto req = Rc<DependencyRequest>::alloc();
220 4352 : req->events = move(events);
221 4352 : req->callback = move(cb);
222 4352 : req->initial = platform::clock(core::ClockType::Monotonic);
223 :
224 8956 : for (auto &it : req->events) {
225 4604 : if (it->isSignaled()) {
226 0 : if (!it->isSuccessful()) {
227 0 : req->success = false;
228 : }
229 0 : ++ req->signaled;
230 : } else {
231 4604 : dependencyRequests.emplace(it.get(), req);
232 : }
233 : }
234 :
235 4352 : if (req->signaled == req->events.size()) {
236 : #if XL_VK_DEPS_DEBUG
237 : log::debug("vk::Loop", "Run: ", str.str());
238 : #endif
239 0 : req->callback(req->success);
240 : }
241 4352 : }
242 :
243 0 : void wakeup() { }
244 :
245 : memory::pool_t *pool = nullptr;
246 : Loop *loop = nullptr;
247 : const core::LoopInfo *info = nullptr;
248 :
249 : memory::vector<Timer> *timers;
250 : memory::vector<Timer> *reschedule;
251 : memory::vector<Rc<Ref>> *autorelease;
252 :
253 : std::multimap<DependencyEvent *, Rc<DependencyRequest>, std::less<void>> dependencyRequests;
254 :
255 : Mutex resourceMutex;
256 :
257 : Rc<Device> device;
258 : Rc<thread::TaskQueue> queue;
259 : Vector<Rc<Fence>> fences;
260 : Set<Rc<Fence>> scheduledFences;
261 :
262 : Rc<RenderQueueCompiler> renderQueueCompiler;
263 : Rc<TransferQueue> transferQueue;
264 : Rc<MaterialCompiler> materialQueue;
265 : Rc<MeshCompiler> meshQueue;
266 : std::atomic<bool> *running = nullptr;
267 : uint32_t requiredTasks = 0;
268 :
269 : Function<void()> signalInit;
270 : };
271 :
272 : struct Loop::Timer final {
273 0 : Timer(uint64_t interval, Function<bool(Loop &)> &&cb, StringView t)
274 0 : : interval(interval), callback(move(cb)), tag(t) { }
275 :
276 : uint64_t interval;
277 : uint64_t value = 0;
278 : Function<bool(Loop &)> callback; // return true if timer is complete and should be removed
279 : StringView tag;
280 : };
281 :
282 84 : Loop::~Loop() { }
283 :
284 42 : Loop::Loop() { }
285 :
286 42 : bool Loop::init(Rc<Instance> &&instance, LoopInfo &&info) {
287 42 : if (!core::Loop::init(instance, move(info))) {
288 0 : return false;
289 : }
290 :
291 42 : _vkInstance = move(instance);
292 42 : _thread = std::thread(Loop::workerThread, this, nullptr);
293 42 : return true;
294 : }
295 :
296 42 : void Loop::waitRinning() {
297 42 : std::unique_lock<std::mutex> lock(_mutex);
298 42 : if (_running.load()) {
299 0 : lock.unlock();
300 0 : return;
301 : }
302 :
303 42 : _cond.wait(lock);
304 42 : lock.unlock();
305 42 : }
306 :
307 42 : void Loop::threadInit() {
308 42 : thread::ThreadInfo::setThreadInfo("Gl::Loop");
309 42 : _threadId = std::this_thread::get_id();
310 42 : _shouldExit.test_and_set();
311 :
312 42 : memory::pool::initialize();
313 42 : auto pool = memory::pool::createTagged("Gl::Loop", mempool::custom::PoolFlags::ThreadSafeAllocator);
314 :
315 42 : memory::pool::push(pool);
316 :
317 42 : _internal = new (pool) vk::Loop::Internal(pool, this);
318 42 : _internal->pool = pool;
319 42 : _internal->running = &_running;
320 42 : _internal->info = &_info;
321 :
322 210 : _internal->signalInit = [this] {
323 : // signal to main thread
324 42 : _mutex.lock();
325 42 : _running.store(true);
326 42 : _cond.notify_all();
327 42 : _mutex.unlock();
328 42 : };
329 :
330 42 : _internal->queue = Rc<thread::TaskQueue>::alloc("Vk::Loop::Queue");
331 84 : _internal->queue->spawnWorkers(thread::TaskQueue::Flags::Cancelable | thread::TaskQueue::Flags::Waitable, LoopThreadId,
332 42 : _internal->info->threadsCount);
333 :
334 42 : if (auto dev = _vkInstance->makeDevice(_info)) {
335 42 : _internal->setDevice(move(dev));
336 42 : _frameCache = Rc<FrameCache>::create(*this, *_internal->device);
337 0 : } else if (_info.deviceIdx != core::Instance::DefaultDevice) {
338 0 : log::warn("vk::Loop", "Unable to create device with index: ", _info.deviceIdx, ", fallback to default");
339 0 : _info.deviceIdx = core::Instance::DefaultDevice;
340 0 : if (auto dev = _vkInstance->makeDevice(_info)) {
341 0 : _internal->setDevice(move(dev));
342 0 : _frameCache = Rc<FrameCache>::create(*this, *_internal->device);
343 : } else {
344 0 : log::error("vk::Loop", "Unable to create device");
345 0 : }
346 : } else {
347 0 : log::error("vk::Loop", "Unable to create device");
348 42 : }
349 :
350 42 : memory::pool::pop();
351 42 : }
352 :
353 42 : void Loop::threadDispose() {
354 42 : auto pool = _internal->pool;
355 :
356 42 : memory::pool::push(pool);
357 :
358 42 : if (_frameCache) {
359 42 : _frameCache->invalidate();
360 : }
361 :
362 42 : _internal->waitIdle();
363 :
364 42 : _internal->queue->waitForAll();
365 :
366 42 : _internal->queue->lock();
367 42 : _internal->timers->clear();
368 42 : _internal->reschedule->clear();
369 42 : _internal->autorelease->clear();
370 42 : _internal->queue->unlock();
371 :
372 42 : _internal->queue->cancelWorkers();
373 42 : _internal->queue = nullptr;
374 :
375 42 : _internal->endDevice();
376 :
377 42 : delete _internal;
378 42 : _internal = nullptr;
379 :
380 42 : memory::pool::pop();
381 42 : memory::pool::destroy(pool);
382 42 : }
383 :
384 796765 : static bool Loop_pollEvents(Loop::Internal *internal, PresentationData &data) {
385 796765 : bool timeoutPassed = false;
386 796765 : auto counter = internal->queue->getOutputCounter();
387 796765 : if (counter > 0) {
388 : XL_PROFILE_BEGIN(queue, "gl::Loop::Queue", "queue", 500);
389 400471 : internal->queue->update();
390 : XL_PROFILE_END(queue)
391 :
392 400471 : data.now = platform::clock(core::ClockType::Monotonic);
393 400471 : if (data.now - data.last > data.updateInterval) {
394 79270 : timeoutPassed = true;
395 : }
396 : } else {
397 396294 : data.now = platform::clock(core::ClockType::Monotonic);
398 396294 : if (data.now - data.last > data.updateInterval) {
399 34300 : timeoutPassed = true;
400 : } else {
401 361994 : if (internal->timers->empty() && internal->scheduledFences.empty()) {
402 : // no timers - just wait for events with 60FPS wakeups
403 361994 : auto t = std::max(data.updateInterval, uint64_t(1'000'000 / 60));
404 361994 : internal->queue->wait(TimeInterval::microseconds(t));
405 : } else {
406 0 : if (!internal->queue->wait(TimeInterval::microseconds(data.updateInterval - (data.now - data.last)))) {
407 0 : data.now = platform::clock(core::ClockType::Monotonic);
408 0 : timeoutPassed = true;
409 : }
410 : }
411 : }
412 : }
413 796765 : return timeoutPassed;
414 : }
415 :
416 796765 : static void Loop_runFences(Loop::Internal *internal) {
417 796765 : auto it = internal->scheduledFences.begin();
418 107860748 : while (it != internal->scheduledFences.end()) {
419 107063983 : if ((*it)->check(*internal->loop, true)) {
420 101210 : it = internal->scheduledFences.erase(it);
421 : }
422 : }
423 796765 : }
424 :
425 113570 : static void Loop_runTimers(Loop::Internal *internal, uint64_t dt) {
426 113570 : auto timers = internal->timers;
427 113570 : internal->timers = internal->reschedule;
428 :
429 113570 : auto it = timers->begin();
430 113570 : while (it != timers->end()) {
431 0 : if (it->interval) {
432 0 : it->value += dt;
433 0 : if (it->value > it->interval) {
434 :
435 : XL_PROFILE_BEGIN(timers, "gl::Loop::Timers", it->tag, 1000);
436 :
437 0 : auto ret = it->callback(*internal->loop);
438 :
439 : XL_PROFILE_END(timers);
440 :
441 0 : if (!ret) {
442 0 : it->value -= it->interval;
443 : } else {
444 0 : it = timers->erase(it);
445 0 : continue;
446 : }
447 : }
448 0 : ++ it;
449 : } else {
450 : XL_PROFILE_BEGIN(timers, "gl::Loop::Timers", it->tag, 1000);
451 :
452 0 : auto ret = it->callback(*internal->loop);
453 :
454 : XL_PROFILE_END(timers);
455 :
456 0 : if (ret) {
457 0 : it = timers->erase(it);
458 : } else {
459 0 : ++ it;
460 : }
461 : }
462 : }
463 :
464 113570 : if (!internal->timers->empty()) {
465 0 : for (auto &it : *internal->timers) {
466 0 : timers->emplace_back(std::move(it));
467 : }
468 0 : internal->timers->clear();
469 : }
470 113570 : internal->timers = timers;
471 113570 : }
472 :
473 42 : bool Loop::worker() {
474 42 : if (!_internal->device) {
475 0 : _running.store(false);
476 0 : return false;
477 : }
478 :
479 42 : PresentationData data;
480 :
481 42 : auto pool = memory::pool::create(_internal->pool);
482 :
483 1593614 : while (_shouldExit.test_and_set()) {
484 796765 : bool timeoutPassed = false;
485 :
486 796765 : ++ _clock;
487 :
488 : XL_PROFILE_BEGIN(loop, "vk::Loop", "loop", 1000);
489 :
490 : XL_PROFILE_BEGIN(poll, "vk::Loop::Poll", "poll", 500);
491 796765 : timeoutPassed = Loop_pollEvents(_internal, data);
492 : XL_PROFILE_END(poll)
493 :
494 796765 : Loop_runFences(_internal);
495 :
496 796765 : if (timeoutPassed) {
497 113570 : auto dt = data.now - data.last;
498 : XL_PROFILE_BEGIN(timers, "vk::Loop::Timers", "timers", 500);
499 113570 : Loop_runTimers(_internal, dt);
500 : XL_PROFILE_END(timers)
501 113570 : data.last = data.now;
502 : }
503 :
504 : XL_PROFILE_BEGIN(autorelease, "vk::Loop::Autorelease", "autorelease", 500);
505 796765 : _internal->autorelease->clear();
506 : XL_PROFILE_END(autorelease)
507 :
508 796765 : _frameCache->clear();
509 :
510 : XL_PROFILE_END(loop)
511 796765 : memory::pool::clear(pool);
512 : }
513 :
514 42 : memory::pool::destroy(pool);
515 :
516 42 : _running.store(false);
517 42 : return false;
518 : }
519 :
520 42 : void Loop::cancel() {
521 42 : _shouldExit.clear();
522 42 : _thread.join();
523 42 : }
524 :
525 21 : void Loop::compileResource(Rc<core::Resource> &&req, Function<void(bool)> &&cb, bool preload) const {
526 21 : auto res = Rc<TransferResource>::create(_internal->device->getAllocator(), move(req), move(cb));
527 21 : if (preload) {
528 0 : res->initialize();
529 : }
530 21 : performOnGlThread([this, res = move(res)] () mutable {
531 21 : _internal->compileResource(move(res));
532 21 : }, const_cast<Loop *>(this), true);
533 21 : }
534 :
535 105 : void Loop::compileQueue(const Rc<Queue> &req, Function<void(bool)> &&callback) const {
536 105 : performOnGlThread([this, req, callback = move(callback)]() mutable {
537 105 : _internal->compileQueue(req, move(callback));
538 105 : }, const_cast<Loop *>(this), true);
539 105 : }
540 :
541 1193 : void Loop::compileMaterials(Rc<core::MaterialInputData> &&req, const Vector<Rc<DependencyEvent>> &deps) const {
542 1193 : performOnGlThread([this, req = move(req), deps = deps] () mutable {
543 1193 : _internal->compileMaterials(move(req), move(deps));
544 1193 : }, const_cast<Loop *>(this), true);
545 1193 : }
546 :
547 42 : void Loop::compileImage(const Rc<core::DynamicImage> &img, Function<void(bool)> &&callback) const {
548 42 : performOnGlThread([this, img, callback = move(callback)]() mutable {
549 42 : _internal->device->compileImage(*this, img, move(callback));
550 42 : }, const_cast<Loop *>(this), true);
551 42 : }
552 :
553 26287 : void Loop::runRenderQueue(Rc<FrameRequest> &&req, uint64_t gen, Function<void(bool)> &&callback) {
554 26287 : performOnGlThread([this, req = move(req), gen, callback = move(callback)]() mutable {
555 26287 : auto frame = makeFrame(move(req), gen);
556 26287 : if (frame && callback) {
557 1066 : frame->setCompleteCallback([callback = move(callback)] (FrameHandle &handle) {
558 1066 : callback(handle.isValid());
559 1066 : });
560 : }
561 26287 : frame->update(true);
562 26287 : }, this, true);
563 26287 : }
564 :
565 0 : void Loop::schedule(Function<bool(core::Loop &)> &&cb, StringView tag) {
566 0 : if (isOnGlThread()) {
567 0 : _internal->timers->emplace_back(0, move(cb), tag);
568 : } else {
569 0 : performOnGlThread([this, cb = move(cb), tag] () mutable {
570 0 : _internal->timers->emplace_back(0, move(cb), tag);
571 0 : });
572 : }
573 0 : }
574 :
575 0 : void Loop::schedule(Function<bool(core::Loop &)> &&cb, uint64_t delay, StringView tag) {
576 0 : if (isOnGlThread()) {
577 0 : _internal->timers->emplace_back(delay, move(cb), tag);
578 : } else {
579 0 : performOnGlThread([this, cb = move(cb), delay, tag] () mutable {
580 0 : _internal->timers->emplace_back(delay, move(cb), tag);
581 0 : });
582 : }
583 0 : }
584 :
585 970873 : void Loop::performInQueue(Rc<thread::Task> &&task) const {
586 970873 : if (!_internal || !_internal->queue) {
587 0 : auto &tasks = task->getCompleteTasks();
588 0 : for (auto &it : tasks) {
589 0 : it(*task, false);
590 : }
591 0 : return;
592 : }
593 :
594 970873 : _internal->queue->perform(move(task));
595 : }
596 :
597 42 : void Loop::performInQueue(Function<void()> &&func, Ref *target) const {
598 42 : if (!_internal || !_internal->queue) {
599 0 : return;
600 : }
601 :
602 42 : _internal->queue->perform(move(func), target);
603 : }
604 :
605 1032689 : void Loop::performOnGlThread(Function<void()> &&func, Ref *target, bool immediate) const {
606 1032689 : if (!_internal || !_internal->queue) {
607 84 : return;
608 : }
609 :
610 1032618 : if (immediate) {
611 729665 : if (isOnGlThread()) {
612 693545 : func();
613 693545 : return;
614 : }
615 : }
616 339073 : _internal->queue->onMainThread(move(func), target);
617 : }
618 :
619 1064377 : bool Loop::isOnGlThread() const {
620 1064377 : return _threadId == std::this_thread::get_id();
621 : }
622 :
623 37039 : auto Loop::makeFrame(Rc<FrameRequest> &&req, uint64_t gen) -> Rc<FrameHandle> {
624 37039 : if (_running.load()) {
625 74078 : return Rc<DeviceFrameHandle>::create(*this, *_internal->device, move(req), gen);
626 : }
627 0 : return nullptr;
628 : }
629 :
630 9517 : Rc<core::Framebuffer> Loop::acquireFramebuffer(const PassData *data, SpanView<Rc<core::ImageView>> views) {
631 9517 : if (!_running.load()) {
632 0 : return nullptr;
633 : }
634 :
635 9517 : return _frameCache->acquireFramebuffer(data, views);
636 : }
637 :
638 9517 : void Loop::releaseFramebuffer(Rc<core::Framebuffer> &&fb) {
639 9517 : _frameCache->releaseFramebuffer(move(fb));
640 9517 : }
641 :
642 28593 : auto Loop::acquireImage(const ImageAttachment *a, const AttachmentHandle *h, const core::ImageInfoData &i) -> Rc<ImageStorage> {
643 28593 : if (!_running.load()) {
644 0 : return nullptr;
645 : }
646 :
647 28593 : core::ImageInfoData info(i);
648 28593 : if (a->isTransient()) {
649 19034 : if ((info.usage & (core::ImageUsage::ColorAttachment | core::ImageUsage::DepthStencilAttachment | core::ImageUsage::InputAttachment))
650 19034 : != core::ImageUsage::None) {
651 19034 : info.usage |= core::ImageUsage::TransientAttachment;
652 : }
653 : }
654 :
655 28593 : auto views = a->getImageViews(info);
656 28593 : return _frameCache->acquireImage(a->getId(), info, views);
657 28593 : }
658 :
659 28572 : void Loop::releaseImage(Rc<ImageStorage> &&image) {
660 28572 : performOnGlThread([this, image = move(image)] () mutable {
661 28572 : _frameCache->releaseImage(move(image));
662 28572 : }, this, true);
663 28572 : }
664 :
665 126189 : Rc<core::Semaphore> Loop::makeSemaphore() {
666 126189 : return _internal->device->makeSemaphore();
667 : }
668 :
669 21 : const Vector<core::ImageFormat> &Loop::getSupportedDepthStencilFormat() const {
670 21 : return _internal->device->getSupportedDepthStencilFormat();
671 : }
672 :
673 207420 : Rc<Fence> Loop::acquireFence(uint32_t v, bool init) {
674 207420 : auto initFence = [&] (const Rc<Fence> &fence) {
675 207420 : if (!init) {
676 21 : return;
677 : }
678 :
679 414798 : fence->setFrame([this, fence] () mutable {
680 101210 : if (isOnGlThread()) {
681 : // schedule fence
682 101210 : _internal->scheduledFences.emplace(move(fence));
683 101210 : return true;
684 : } else {
685 0 : performOnGlThread([this, fence = move(fence)] () mutable {
686 0 : if (!fence->check(*this, true)) {
687 0 : return;
688 : }
689 :
690 0 : _internal->scheduledFences.emplace(move(fence));
691 : }, this, true);
692 0 : return true;
693 : }
694 622197 : }, [this, fence] () mutable {
695 207399 : fence->clear();
696 207399 : std::unique_lock<Mutex> lock(_internal->resourceMutex);
697 207399 : _internal->fences.emplace_back(move(fence));
698 414798 : }, v);
699 207420 : };
700 :
701 207420 : std::unique_lock<Mutex> lock(_internal->resourceMutex);
702 207420 : if (!_internal->fences.empty()) {
703 207274 : auto ref = move(_internal->fences.back());
704 207274 : _internal->fences.pop_back();
705 207274 : initFence(ref);
706 207274 : return ref;
707 207274 : }
708 146 : lock.unlock();
709 146 : auto ref = Rc<Fence>::create(*_internal->device);
710 146 : initFence(ref);
711 146 : return ref;
712 207420 : }
713 :
714 4392 : void Loop::signalDependencies(const Vector<Rc<DependencyEvent>> &events, Queue *q, bool success) {
715 4392 : if (!events.empty()) {
716 4392 : if (isOnGlThread() && _internal) {
717 4392 : _internal->signalDependencies(events, q, success);
718 4392 : return;
719 : }
720 :
721 0 : performOnGlThread([this, events, success, q = Rc<Queue>(q)] () {
722 0 : _internal->signalDependencies(events, q, success);
723 0 : }, this, false);
724 : }
725 : }
726 :
727 40541 : void Loop::waitForDependencies(const Vector<Rc<DependencyEvent>> &events, Function<void(bool)> &&cb) {
728 40541 : if (events.empty()) {
729 36189 : cb(true);
730 : } else {
731 4352 : performOnGlThread([this, events = events, cb = move(cb)] () mutable {
732 4352 : _internal->waitForDependencies(move(events), move(cb));
733 4352 : }, this, true);
734 : }
735 40541 : }
736 :
737 0 : void Loop::wakeup() {
738 0 : if (_internal) {
739 0 : _internal->wakeup();
740 : }
741 0 : }
742 :
743 0 : void Loop::waitIdle() {
744 0 : if (_internal) {
745 0 : _internal->waitIdle();
746 : }
747 0 : }
748 :
749 21 : void Loop::captureImage(Function<void(const ImageInfoData &info, BytesView view)> &&cb, const Rc<core::ImageObject> &image, core::AttachmentLayout l) {
750 21 : performOnGlThread([this, cb = move(cb), image, l] () mutable {
751 21 : _internal->device->getTextureSetLayout()->readImage(*_internal->device, *this, image.cast<Image>(), l, move(cb));
752 21 : }, this, true);
753 21 : }
754 :
755 25200 : void Loop::captureBuffer(Function<void(const BufferInfo &info, BytesView view)> &&cb, const Rc<core::BufferObject> &buf) {
756 25200 : if ((buf->getInfo().usage & core::BufferUsage::TransferSrc) != core::BufferUsage::TransferSrc) {
757 0 : log::error("vk::Loop::captureBuffer", "Buffer '", buf->getName(), "' has no BufferUsage::TransferSrc flag to being captured");
758 : }
759 :
760 25200 : performOnGlThread([this, cb = move(cb), buf] () mutable {
761 25200 : _internal->device->getTextureSetLayout()->readBuffer(*_internal->device, *this, buf.cast<Buffer>(), move(cb));
762 25200 : }, this, true);
763 25200 : }
764 :
765 : }
|