1 #include "core/command.hpp"
2 #include "core/framerate.hpp"
3 #include "core/keymapper.hpp"
4 #include "core/settings.hpp"
5 #include "core/moviedata.hpp"
6 #include "core/moviefile.hpp"
7 #include "library/minmax.hpp"
18 #define HISTORY_FRAMES 10
20 bool graphics_driver_is_dummy();
24 uint64_t last_time_update
= 0;
25 uint64_t time_at_last_update
= 0;
26 bool time_frozen
= true;
27 uint64_t frame_number
= 0;
28 uint64_t frame_start_times
[HISTORY_FRAMES
];
30 double nominal_framerate
= 60;
31 double multiplier_framerate
= 1;
32 mutex_class framerate_lock
;
35 uint64_t get_time(uint64_t curtime
, bool update
)
37 if(curtime
< last_time_update
|| time_frozen
)
38 return time_at_last_update
;
40 time_at_last_update
+= (curtime
- last_time_update
);
41 last_time_update
= curtime
;
42 return time_at_last_update
;
44 return time_at_last_update
+ (curtime
- last_time_update
);
47 double get_realized_fps()
51 unsigned loadidx
= min(frame_number
- 1, static_cast<uint64_t>(HISTORY_FRAMES
) - 1);
52 return (1000000.0 * loadidx
) / (frame_start_times
[0] - frame_start_times
[loadidx
] + 1);
55 void add_frame(uint64_t linear_time
)
57 for(size_t i
= HISTORY_FRAMES
- 2; i
< HISTORY_FRAMES
; i
--)
58 frame_start_times
[i
+ 1] = frame_start_times
[i
];
59 frame_start_times
[0] = linear_time
;
63 std::pair
<bool, double> read_fps()
67 umutex_class
h(framerate_lock
);
68 n
= nominal_framerate
;
69 m
= multiplier_framerate
;
71 if(m
== std::numeric_limits
<double>::infinity())
72 return std::make_pair(true, 0);
74 return std::make_pair(false, n
* m
);
77 command::fnptr
<> tturbo(lsnes_cmd
, "toggle-turbo", "Toggle turbo",
78 "Syntax: toggle-turbo\nToggle turbo mode.\n",
79 []() throw(std::bad_alloc
, std::runtime_error
) {
83 command::fnptr
<> pturbo(lsnes_cmd
, "+turbo", "Activate turbo",
84 "Syntax: +turbo\nActivate turbo mode.\n",
85 []() throw(std::bad_alloc
, std::runtime_error
) {
89 command::fnptr
<> nturbo(lsnes_cmd
, "-turbo", "Deactivate turbo",
90 "Syntax: -turbo\nDeactivate turbo mode.\n",
91 []() throw(std::bad_alloc
, std::runtime_error
) {
95 keyboard::invbind
turboh(lsnes_mapper
, "+turbo", "Speed‣Turbo hold");
96 keyboard::invbind
turbot(lsnes_mapper
, "toggle-turbo", "Speed‣Turbo toggle");
100 //Set the speed multiplier. Note that INFINITE is a valid multiplier.
101 void set_speed_multiplier(double multiplier
) throw()
103 umutex_class
h(framerate_lock
);
104 multiplier_framerate
= multiplier
;
107 //Get the speed multiplier. Note that this may be INFINITE.
108 double get_speed_multiplier() throw()
110 umutex_class
h(framerate_lock
);
111 return multiplier_framerate
;
114 void freeze_time(uint64_t curtime
)
116 get_time(curtime
, true);
120 void unfreeze_time(uint64_t curtime
)
123 last_time_update
= curtime
;
127 void set_nominal_framerate(double fps
) throw()
129 umutex_class
h(framerate_lock
);
130 nominal_framerate
= fps
;
133 double get_realized_multiplier() throw()
135 umutex_class
h(framerate_lock
);
136 return get_realized_fps() / nominal_framerate
;
139 void ack_frame_tick(uint64_t usec
) throw()
142 add_frame(get_time(usec
, true));
145 uint64_t to_wait_frame(uint64_t usec
) throw()
147 auto target
= read_fps();
148 if(!frame_number
|| target
.first
|| turboed
|| graphics_driver_is_dummy())
150 uint64_t lintime
= get_time(usec
, true);
151 uint64_t frame_lasted
= lintime
- frame_start_times
[0];
152 uint64_t frame_should_last
= 1000000 / target
.second
;
153 if(frame_lasted
>= frame_should_last
)
154 return 0; //We are late.
155 uint64_t history_frames
= min(frame_number
, static_cast<uint64_t>(HISTORY_FRAMES
));
156 uint64_t history_lasted
= lintime
- frame_start_times
[history_frames
- 1];
157 uint64_t history_should_last
= history_frames
* 1000000 / target
.second
;
158 if(history_lasted
>= history_should_last
)
160 return min(history_should_last
- history_lasted
, frame_should_last
- frame_lasted
);
166 gettimeofday(&tv
, NULL
);
167 return static_cast<uint64_t>(tv
.tv_sec
) * 1000000 + tv
.tv_usec
;
170 #define MAXSLEEP 500000
172 void wait_usec(uint64_t usec
)
174 uint64_t sleep_end
= get_utime() + usec
;
176 uint64_t time_now
= get_utime();
177 if(time_now
>= sleep_end
)
179 if(sleep_end
< time_now
+ MAXSLEEP
)
180 usleep(sleep_end
- time_now
);