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 : }
|