1 | /**************************************************************************/ |
2 | /* main_timer_sync.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "main_timer_sync.h" |
32 | |
33 | #include "core/os/os.h" |
34 | #include "servers/display_server.h" |
35 | |
36 | void MainFrameTime::clamp_process_step(double min_process_step, double max_process_step) { |
37 | if (process_step < min_process_step) { |
38 | process_step = min_process_step; |
39 | } else if (process_step > max_process_step) { |
40 | process_step = max_process_step; |
41 | } |
42 | } |
43 | |
44 | ///////////////////////////////// |
45 | |
46 | void MainTimerSync::DeltaSmoother::update_refresh_rate_estimator(int64_t p_delta) { |
47 | // the calling code should prevent 0 or negative values of delta |
48 | // (preventing divide by zero) |
49 | |
50 | // note that if the estimate gets locked, and something external changes this |
51 | // (e.g. user changes to non-vsync in the OS), then the results may be less than ideal, |
52 | // but usually it will detect this via the FPS measurement and not attempt smoothing. |
53 | // This should be a rare occurrence anyway, and will be cured next time user restarts game. |
54 | if (_estimate_locked) { |
55 | return; |
56 | } |
57 | |
58 | // First average the delta over NUM_READINGS |
59 | _estimator_total_delta += p_delta; |
60 | _estimator_delta_readings++; |
61 | |
62 | const int NUM_READINGS = 60; |
63 | |
64 | if (_estimator_delta_readings < NUM_READINGS) { |
65 | return; |
66 | } |
67 | |
68 | // use average |
69 | p_delta = _estimator_total_delta / NUM_READINGS; |
70 | |
71 | // reset the averager for next time |
72 | _estimator_delta_readings = 0; |
73 | _estimator_total_delta = 0; |
74 | |
75 | /////////////////////////////// |
76 | |
77 | int fps = Math::round(1000000.0 / p_delta); |
78 | |
79 | // initial estimation, to speed up converging, special case we will estimate the refresh rate |
80 | // from the first average FPS reading |
81 | if (_estimated_fps == 0) { |
82 | // below 50 might be chugging loading stuff, or else |
83 | // dropping loads of frames, so the estimate will be inaccurate |
84 | if (fps >= 50) { |
85 | _estimated_fps = fps; |
86 | #ifdef GODOT_DEBUG_DELTA_SMOOTHER |
87 | print_line("initial guess (average measured) refresh rate: " + itos(fps)); |
88 | #endif |
89 | } else { |
90 | // can't get started until above 50 |
91 | return; |
92 | } |
93 | } |
94 | |
95 | // we hit our exact estimated refresh rate. |
96 | // increase our confidence in the estimate. |
97 | if (fps == _estimated_fps) { |
98 | // note that each hit is an average of NUM_READINGS frames |
99 | _hits_at_estimated++; |
100 | |
101 | if (_estimate_complete && _hits_at_estimated == 20) { |
102 | _estimate_locked = true; |
103 | #ifdef GODOT_DEBUG_DELTA_SMOOTHER |
104 | print_line("estimate LOCKED at " + itos(_estimated_fps) + " fps" ); |
105 | #endif |
106 | return; |
107 | } |
108 | |
109 | // if we are getting pretty confident in this estimate, decide it is complete |
110 | // (it can still be increased later, and possibly lowered but only for a short time) |
111 | if ((!_estimate_complete) && (_hits_at_estimated > 2)) { |
112 | // when the estimate is complete we turn on smoothing |
113 | if (_estimated_fps) { |
114 | _estimate_complete = true; |
115 | _vsync_delta = 1000000 / _estimated_fps; |
116 | |
117 | #ifdef GODOT_DEBUG_DELTA_SMOOTHER |
118 | print_line("estimate complete. vsync_delta " + itos(_vsync_delta) + ", fps " + itos(_estimated_fps)); |
119 | #endif |
120 | } |
121 | } |
122 | |
123 | #ifdef GODOT_DEBUG_DELTA_SMOOTHER |
124 | if ((_hits_at_estimated % (400 / NUM_READINGS)) == 0) { |
125 | String sz = "hits at estimated : " + itos(_hits_at_estimated) + ", above : " + itos(_hits_above_estimated) + "( " + itos(_hits_one_above_estimated) + " ), below : " + itos(_hits_below_estimated) + " (" + itos(_hits_one_below_estimated) + " )" ; |
126 | |
127 | print_line(sz); |
128 | } |
129 | #endif |
130 | |
131 | return; |
132 | } |
133 | |
134 | const int SIGNIFICANCE_UP = 1; |
135 | const int SIGNIFICANCE_DOWN = 2; |
136 | |
137 | // we are not usually interested in slowing the estimate |
138 | // but we may have overshot, so make it possible to reduce |
139 | if (fps < _estimated_fps) { |
140 | // micro changes |
141 | if (fps == (_estimated_fps - 1)) { |
142 | _hits_one_below_estimated++; |
143 | |
144 | if ((_hits_one_below_estimated > _hits_at_estimated) && (_hits_one_below_estimated > SIGNIFICANCE_DOWN)) { |
145 | _estimated_fps--; |
146 | made_new_estimate(); |
147 | } |
148 | |
149 | return; |
150 | } else { |
151 | _hits_below_estimated++; |
152 | |
153 | // don't allow large lowering if we are established at a refresh rate, as it will probably be dropped frames |
154 | bool established = _estimate_complete && (_hits_at_estimated > 10); |
155 | |
156 | // macro changes |
157 | // note there is a large barrier to macro lowering. That is because it is more likely to be dropped frames |
158 | // than mis-estimation of the refresh rate. |
159 | if (!established) { |
160 | if (((_hits_below_estimated / 8) > _hits_at_estimated) && (_hits_below_estimated > SIGNIFICANCE_DOWN)) { |
161 | // decrease the estimate |
162 | _estimated_fps--; |
163 | made_new_estimate(); |
164 | } |
165 | } |
166 | |
167 | return; |
168 | } |
169 | } |
170 | |
171 | // Changes increasing the estimate. |
172 | // micro changes |
173 | if (fps == (_estimated_fps + 1)) { |
174 | _hits_one_above_estimated++; |
175 | |
176 | if ((_hits_one_above_estimated > _hits_at_estimated) && (_hits_one_above_estimated > SIGNIFICANCE_UP)) { |
177 | _estimated_fps++; |
178 | made_new_estimate(); |
179 | } |
180 | return; |
181 | } else { |
182 | _hits_above_estimated++; |
183 | |
184 | // macro changes |
185 | if ((_hits_above_estimated > _hits_at_estimated) && (_hits_above_estimated > SIGNIFICANCE_UP)) { |
186 | // increase the estimate |
187 | int change = fps - _estimated_fps; |
188 | change /= 2; |
189 | change = MAX(1, change); |
190 | |
191 | _estimated_fps += change; |
192 | made_new_estimate(); |
193 | } |
194 | return; |
195 | } |
196 | } |
197 | |
198 | bool MainTimerSync::DeltaSmoother::fps_allows_smoothing(int64_t p_delta) { |
199 | _measurement_time += p_delta; |
200 | _measurement_frame_count++; |
201 | |
202 | if (_measurement_frame_count == _measurement_end_frame) { |
203 | // only switch on or off if the estimate is complete |
204 | if (_estimate_complete) { |
205 | int64_t time_passed = _measurement_time - _measurement_start_time; |
206 | |
207 | // average delta |
208 | time_passed /= MEASURE_FPS_OVER_NUM_FRAMES; |
209 | |
210 | // estimate fps |
211 | if (time_passed) { |
212 | double fps = 1000000.0 / time_passed; |
213 | double ratio = fps / (double)_estimated_fps; |
214 | |
215 | //print_line("ratio : " + String(Variant(ratio))); |
216 | |
217 | if ((ratio > 0.95) && (ratio < 1.05)) { |
218 | _measurement_allows_smoothing = true; |
219 | } else { |
220 | _measurement_allows_smoothing = false; |
221 | } |
222 | } |
223 | } // estimate complete |
224 | |
225 | // new start time for next iteration |
226 | _measurement_start_time = _measurement_time; |
227 | _measurement_end_frame += MEASURE_FPS_OVER_NUM_FRAMES; |
228 | } |
229 | |
230 | return _measurement_allows_smoothing; |
231 | } |
232 | |
233 | int64_t MainTimerSync::DeltaSmoother::smooth_delta(int64_t p_delta) { |
234 | // Conditions to disable smoothing. |
235 | // Note that vsync is a request, it cannot be relied on, the OS may override this. |
236 | // If the OS turns vsync on without vsync in the app, smoothing will not be enabled. |
237 | // If the OS turns vsync off with sync enabled in the app, the smoothing must detect this |
238 | // via the error metric and switch off. |
239 | // Also only try smoothing if vsync is enabled (classical vsync, not new types) .. |
240 | // This condition is currently checked before calling smooth_delta(). |
241 | if (!OS::get_singleton()->is_delta_smoothing_enabled() || Engine::get_singleton()->is_editor_hint()) { |
242 | return p_delta; |
243 | } |
244 | |
245 | // only attempt smoothing if vsync is selected |
246 | DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID); |
247 | if (vsync_mode != DisplayServer::VSYNC_ENABLED) { |
248 | return p_delta; |
249 | } |
250 | |
251 | // Very important, ignore long deltas and pass them back unmodified. |
252 | // This is to deal with resuming after suspend for long periods. |
253 | if (p_delta > 1000000) { |
254 | return p_delta; |
255 | } |
256 | |
257 | // keep a running guesstimate of the FPS, and turn off smoothing if |
258 | // conditions not close to the estimated FPS |
259 | if (!fps_allows_smoothing(p_delta)) { |
260 | return p_delta; |
261 | } |
262 | |
263 | // we can't cope with negative deltas .. OS bug on some hardware |
264 | // and also very small deltas caused by vsync being off. |
265 | // This could possibly be part of a hiccup, this value isn't fixed in stone... |
266 | if (p_delta < 1000) { |
267 | return p_delta; |
268 | } |
269 | |
270 | // note still some vsync off will still get through to this point... |
271 | // and we need to cope with it by not converging the estimator / and / or not smoothing |
272 | update_refresh_rate_estimator(p_delta); |
273 | |
274 | // no smoothing until we know what the refresh rate is |
275 | if (!_estimate_complete) { |
276 | return p_delta; |
277 | } |
278 | |
279 | // accumulate the time we have available to use |
280 | _leftover_time += p_delta; |
281 | |
282 | // how many vsyncs units can we fit? |
283 | int64_t units = _leftover_time / _vsync_delta; |
284 | |
285 | // a delta must include minimum 1 vsync |
286 | // (if it is less than that, it is either random error or we are no longer running at the vsync rate, |
287 | // in which case we should switch off delta smoothing, or re-estimate the refresh rate) |
288 | units = MAX(units, 1); |
289 | |
290 | _leftover_time -= units * _vsync_delta; |
291 | // print_line("units " + itos(units) + ", leftover " + itos(_leftover_time/1000) + " ms"); |
292 | |
293 | return units * _vsync_delta; |
294 | } |
295 | |
296 | ///////////////////////////////////// |
297 | |
298 | // returns the fraction of p_physics_step required for the timer to overshoot |
299 | // before advance_core considers changing the physics_steps return from |
300 | // the typical values as defined by typical_physics_steps |
301 | double MainTimerSync::get_physics_jitter_fix() { |
302 | return Engine::get_singleton()->get_physics_jitter_fix(); |
303 | } |
304 | |
305 | // gets our best bet for the average number of physics steps per render frame |
306 | // return value: number of frames back this data is consistent |
307 | int MainTimerSync::get_average_physics_steps(double &p_min, double &p_max) { |
308 | p_min = typical_physics_steps[0]; |
309 | p_max = p_min + 1; |
310 | |
311 | for (int i = 1; i < CONTROL_STEPS; ++i) { |
312 | const double typical_lower = typical_physics_steps[i]; |
313 | const double current_min = typical_lower / (i + 1); |
314 | if (current_min > p_max) { |
315 | return i; // bail out if further restrictions would void the interval |
316 | } else if (current_min > p_min) { |
317 | p_min = current_min; |
318 | } |
319 | const double current_max = (typical_lower + 1) / (i + 1); |
320 | if (current_max < p_min) { |
321 | return i; |
322 | } else if (current_max < p_max) { |
323 | p_max = current_max; |
324 | } |
325 | } |
326 | |
327 | return CONTROL_STEPS; |
328 | } |
329 | |
330 | // advance physics clock by p_process_step, return appropriate number of steps to simulate |
331 | MainFrameTime MainTimerSync::advance_core(double p_physics_step, int p_physics_ticks_per_second, double p_process_step) { |
332 | MainFrameTime ret; |
333 | |
334 | ret.process_step = p_process_step; |
335 | |
336 | // simple determination of number of physics iteration |
337 | time_accum += ret.process_step; |
338 | ret.physics_steps = floor(time_accum * p_physics_ticks_per_second); |
339 | |
340 | int min_typical_steps = typical_physics_steps[0]; |
341 | int max_typical_steps = min_typical_steps + 1; |
342 | |
343 | // given the past recorded steps and typical steps to match, calculate bounds for this |
344 | // step to be typical |
345 | bool update_typical = false; |
346 | |
347 | for (int i = 0; i < CONTROL_STEPS - 1; ++i) { |
348 | int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i]; |
349 | if (steps_left_to_match_typical > max_typical_steps || |
350 | steps_left_to_match_typical + 1 < min_typical_steps) { |
351 | update_typical = true; |
352 | break; |
353 | } |
354 | |
355 | if (steps_left_to_match_typical > min_typical_steps) { |
356 | min_typical_steps = steps_left_to_match_typical; |
357 | } |
358 | if (steps_left_to_match_typical + 1 < max_typical_steps) { |
359 | max_typical_steps = steps_left_to_match_typical + 1; |
360 | } |
361 | } |
362 | |
363 | #ifdef DEBUG_ENABLED |
364 | if (max_typical_steps < 0) { |
365 | WARN_PRINT_ONCE("`max_typical_steps` is negative. This could hint at an engine bug or system timer misconfiguration." ); |
366 | } |
367 | #endif |
368 | |
369 | // try to keep it consistent with previous iterations |
370 | if (ret.physics_steps < min_typical_steps) { |
371 | const int max_possible_steps = floor((time_accum)*p_physics_ticks_per_second + get_physics_jitter_fix()); |
372 | if (max_possible_steps < min_typical_steps) { |
373 | ret.physics_steps = max_possible_steps; |
374 | update_typical = true; |
375 | } else { |
376 | ret.physics_steps = min_typical_steps; |
377 | } |
378 | } else if (ret.physics_steps > max_typical_steps) { |
379 | const int min_possible_steps = floor((time_accum)*p_physics_ticks_per_second - get_physics_jitter_fix()); |
380 | if (min_possible_steps > max_typical_steps) { |
381 | ret.physics_steps = min_possible_steps; |
382 | update_typical = true; |
383 | } else { |
384 | ret.physics_steps = max_typical_steps; |
385 | } |
386 | } |
387 | |
388 | if (ret.physics_steps < 0) { |
389 | ret.physics_steps = 0; |
390 | } |
391 | |
392 | time_accum -= ret.physics_steps * p_physics_step; |
393 | |
394 | // keep track of accumulated step counts |
395 | for (int i = CONTROL_STEPS - 2; i >= 0; --i) { |
396 | accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps; |
397 | } |
398 | accumulated_physics_steps[0] = ret.physics_steps; |
399 | |
400 | if (update_typical) { |
401 | for (int i = CONTROL_STEPS - 1; i >= 0; --i) { |
402 | if (typical_physics_steps[i] > accumulated_physics_steps[i]) { |
403 | typical_physics_steps[i] = accumulated_physics_steps[i]; |
404 | } else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) { |
405 | typical_physics_steps[i] = accumulated_physics_steps[i] - 1; |
406 | } |
407 | } |
408 | } |
409 | |
410 | return ret; |
411 | } |
412 | |
413 | // calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero |
414 | MainFrameTime MainTimerSync::advance_checked(double p_physics_step, int p_physics_ticks_per_second, double p_process_step) { |
415 | if (fixed_fps != -1) { |
416 | p_process_step = 1.0 / fixed_fps; |
417 | } |
418 | |
419 | float min_output_step = p_process_step / 8; |
420 | min_output_step = MAX(min_output_step, 1E-6); |
421 | |
422 | // compensate for last deficit |
423 | p_process_step += time_deficit; |
424 | |
425 | MainFrameTime ret = advance_core(p_physics_step, p_physics_ticks_per_second, p_process_step); |
426 | |
427 | // we will do some clamping on ret.process_step and need to sync those changes to time_accum, |
428 | // that's easiest if we just remember their fixed difference now |
429 | const double process_minus_accum = ret.process_step - time_accum; |
430 | |
431 | // first, least important clamping: keep ret.process_step consistent with typical_physics_steps. |
432 | // this smoothes out the process steps and culls small but quick variations. |
433 | { |
434 | double min_average_physics_steps, max_average_physics_steps; |
435 | int consistent_steps = get_average_physics_steps(min_average_physics_steps, max_average_physics_steps); |
436 | if (consistent_steps > 3) { |
437 | ret.clamp_process_step(min_average_physics_steps * p_physics_step, max_average_physics_steps * p_physics_step); |
438 | } |
439 | } |
440 | |
441 | // second clamping: keep abs(time_deficit) < jitter_fix * frame_slise |
442 | double max_clock_deviation = get_physics_jitter_fix() * p_physics_step; |
443 | ret.clamp_process_step(p_process_step - max_clock_deviation, p_process_step + max_clock_deviation); |
444 | |
445 | // last clamping: make sure time_accum is between 0 and p_physics_step for consistency between physics and process |
446 | ret.clamp_process_step(process_minus_accum, process_minus_accum + p_physics_step); |
447 | |
448 | // all the operations above may have turned ret.p_process_step negative or zero, keep a minimal value |
449 | if (ret.process_step < min_output_step) { |
450 | ret.process_step = min_output_step; |
451 | } |
452 | |
453 | // restore time_accum |
454 | time_accum = ret.process_step - process_minus_accum; |
455 | |
456 | // forcing ret.process_step to be positive may trigger a violation of the |
457 | // promise that time_accum is between 0 and p_physics_step |
458 | #ifdef DEBUG_ENABLED |
459 | if (time_accum < -1E-7) { |
460 | WARN_PRINT_ONCE("Intermediate value of `time_accum` is negative. This could hint at an engine bug or system timer misconfiguration." ); |
461 | } |
462 | #endif |
463 | |
464 | if (time_accum > p_physics_step) { |
465 | const int = floor(time_accum * p_physics_ticks_per_second); |
466 | time_accum -= extra_physics_steps * p_physics_step; |
467 | ret.physics_steps += extra_physics_steps; |
468 | } |
469 | |
470 | #ifdef DEBUG_ENABLED |
471 | if (time_accum < -1E-7) { |
472 | WARN_PRINT_ONCE("Final value of `time_accum` is negative. It should always be between 0 and `p_physics_step`. This hints at an engine bug." ); |
473 | } |
474 | if (time_accum > p_physics_step + 1E-7) { |
475 | WARN_PRINT_ONCE("Final value of `time_accum` is larger than `p_physics_step`. It should always be between 0 and `p_physics_step`. This hints at an engine bug." ); |
476 | } |
477 | #endif |
478 | |
479 | // track deficit |
480 | time_deficit = p_process_step - ret.process_step; |
481 | |
482 | // p_physics_step is 1.0 / iterations_per_sec |
483 | // i.e. the time in seconds taken by a physics tick |
484 | ret.interpolation_fraction = time_accum / p_physics_step; |
485 | |
486 | return ret; |
487 | } |
488 | |
489 | // determine wall clock step since last iteration |
490 | double MainTimerSync::get_cpu_process_step() { |
491 | uint64_t cpu_ticks_elapsed = current_cpu_ticks_usec - last_cpu_ticks_usec; |
492 | last_cpu_ticks_usec = current_cpu_ticks_usec; |
493 | |
494 | cpu_ticks_elapsed = _delta_smoother.smooth_delta(cpu_ticks_elapsed); |
495 | |
496 | return cpu_ticks_elapsed / 1000000.0; |
497 | } |
498 | |
499 | MainTimerSync::MainTimerSync() { |
500 | for (int i = CONTROL_STEPS - 1; i >= 0; --i) { |
501 | typical_physics_steps[i] = i; |
502 | accumulated_physics_steps[i] = i; |
503 | } |
504 | } |
505 | |
506 | // start the clock |
507 | void MainTimerSync::init(uint64_t p_cpu_ticks_usec) { |
508 | current_cpu_ticks_usec = last_cpu_ticks_usec = p_cpu_ticks_usec; |
509 | } |
510 | |
511 | // set measured wall clock time |
512 | void MainTimerSync::set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec) { |
513 | current_cpu_ticks_usec = p_cpu_ticks_usec; |
514 | } |
515 | |
516 | void MainTimerSync::set_fixed_fps(int p_fixed_fps) { |
517 | fixed_fps = p_fixed_fps; |
518 | } |
519 | |
520 | // advance one physics frame, return timesteps to take |
521 | MainFrameTime MainTimerSync::advance(double p_physics_step, int p_physics_ticks_per_second) { |
522 | double cpu_process_step = get_cpu_process_step(); |
523 | |
524 | return advance_checked(p_physics_step, p_physics_ticks_per_second, cpu_process_step); |
525 | } |
526 | |