1 #include "core/command.hpp"
2 #include "core/framerate.hpp"
3 #include "cmdhelp/turbo.hpp"
4 #include "core/instance.hpp"
5 #include "core/keymapper.hpp"
6 #include "core/moviedata.hpp"
7 #include "library/minmax.hpp"
18 bool graphics_driver_is_dummy();
20 framerate_regulator::framerate_regulator(command::group
& _cmd
)
22 turbo_p(cmd
, CTURBO::p
, [this]() { this->turboed
= true; }),
23 turbo_r(cmd
, CTURBO::r
, [this]() { this->turboed
= false; }),
24 turbo_t(cmd
, CTURBO::t
, [this]() { this->turboed
= !this->turboed
; })
27 time_at_last_update
= 0;
30 for(unsigned i
= 0; i
< FRAMERATE_HISTORY_FRAMES
; i
++)
31 frame_start_times
[i
] = 0;
32 nominal_framerate
= 60;
33 multiplier_framerate
= 1;
37 //Set the speed multiplier. Note that INFINITE is a valid multiplier.
38 void framerate_regulator::set_speed_multiplier(double multiplier
) throw()
40 threads::alock
h(framerate_lock
);
41 multiplier_framerate
= multiplier
;
44 //Get the speed multiplier. Note that this may be INFINITE.
45 double framerate_regulator::get_speed_multiplier() throw()
47 threads::alock
h(framerate_lock
);
48 return multiplier_framerate
;
51 void framerate_regulator::freeze_time(uint64_t curtime
)
53 get_time(curtime
, true);
57 void framerate_regulator::unfreeze_time(uint64_t curtime
)
60 last_time_update
= curtime
;
64 void framerate_regulator::set_nominal_framerate(double fps
) throw()
66 threads::alock
h(framerate_lock
);
67 nominal_framerate
= fps
;
70 double framerate_regulator::get_realized_multiplier() throw()
72 threads::alock
h(framerate_lock
);
73 return get_realized_fps() / nominal_framerate
;
76 void framerate_regulator::ack_frame_tick(uint64_t usec
) throw()
79 add_frame(get_time(usec
, true));
82 uint64_t framerate_regulator::to_wait_frame(uint64_t usec
) throw()
84 auto target
= read_fps();
85 if(!frame_number
|| target
.first
|| turboed
|| graphics_driver_is_dummy())
87 uint64_t lintime
= get_time(usec
, true);
88 uint64_t frame_lasted
= lintime
- frame_start_times
[0];
89 uint64_t frame_should_last
= 1000000 / target
.second
;
90 if(frame_lasted
>= frame_should_last
)
91 return 0; //We are late.
92 uint64_t history_frames
= min(frame_number
, static_cast<uint64_t>(FRAMERATE_HISTORY_FRAMES
));
93 uint64_t history_lasted
= lintime
- frame_start_times
[history_frames
- 1];
94 uint64_t history_should_last
= history_frames
* 1000000 / target
.second
;
95 if(history_lasted
>= history_should_last
)
97 return min(history_should_last
- history_lasted
, frame_should_last
- frame_lasted
);
100 uint64_t framerate_regulator::get_utime()
103 gettimeofday(&tv
, NULL
);
104 return static_cast<uint64_t>(tv
.tv_sec
) * 1000000 + tv
.tv_usec
;
107 #define MAXSLEEP 500000
109 void framerate_regulator::wait_usec(uint64_t usec
)
111 uint64_t sleep_end
= get_utime() + usec
;
113 uint64_t time_now
= get_utime();
114 if(time_now
>= sleep_end
)
116 if(sleep_end
< time_now
+ MAXSLEEP
)
117 usleep(sleep_end
- time_now
);
123 uint64_t framerate_regulator::get_time(uint64_t curtime
, bool update
)
125 if(curtime
< last_time_update
|| time_frozen
)
126 return time_at_last_update
;
128 time_at_last_update
+= (curtime
- last_time_update
);
129 last_time_update
= curtime
;
130 return time_at_last_update
;
132 return time_at_last_update
+ (curtime
- last_time_update
);
135 double framerate_regulator::get_realized_fps()
139 unsigned loadidx
= min(frame_number
- 1, static_cast<uint64_t>(FRAMERATE_HISTORY_FRAMES
) - 1);
140 return (1000000.0 * loadidx
) / (frame_start_times
[0] - frame_start_times
[loadidx
] + 1);
143 void framerate_regulator::add_frame(uint64_t linear_time
)
145 for(size_t i
= FRAMERATE_HISTORY_FRAMES
- 2; i
< FRAMERATE_HISTORY_FRAMES
; i
--)
146 frame_start_times
[i
+ 1] = frame_start_times
[i
];
147 frame_start_times
[0] = linear_time
;
151 std::pair
<bool, double> framerate_regulator::read_fps()
155 threads::alock
h(framerate_lock
);
156 n
= nominal_framerate
;
157 m
= multiplier_framerate
;
159 if(m
== std::numeric_limits
<double>::infinity())
160 return std::make_pair(true, 0);
162 return std::make_pair(false, n
* m
);