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