Tweak format of command help files and do some further command cleanup
[lsnes.git] / src / core / framerate.cpp
blob7a5438a7339028cfd61091e450c3c01b37443d1c
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"
9 #include <cstdlib>
10 #include <string>
11 #include <sstream>
12 #include <iostream>
13 #include <stdexcept>
14 #include <sys/time.h>
15 #include <unistd.h>
16 #include <limits>
18 bool graphics_driver_is_dummy();
20 framerate_regulator::framerate_regulator(command::group& _cmd)
21 : cmd(_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; })
26 last_time_update = 0;
27 time_at_last_update = 0;
28 time_frozen = true;
29 frame_number = 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;
34 turboed = false;
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);
54 time_frozen = true;
57 void framerate_regulator::unfreeze_time(uint64_t curtime)
59 if(time_frozen)
60 last_time_update = curtime;
61 time_frozen = false;
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()
78 unfreeze_time(usec);
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())
86 return 0;
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)
96 return 0;
97 return min(history_should_last - history_lasted, frame_should_last - frame_lasted);
100 uint64_t framerate_regulator::get_utime()
102 struct timeval tv;
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;
112 while(1) {
113 uint64_t time_now = get_utime();
114 if(time_now >= sleep_end)
115 break;
116 if(sleep_end < time_now + MAXSLEEP)
117 usleep(sleep_end - time_now);
118 else
119 usleep(MAXSLEEP);
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;
127 if(update) {
128 time_at_last_update += (curtime - last_time_update);
129 last_time_update = curtime;
130 return time_at_last_update;
131 } else
132 return time_at_last_update + (curtime - last_time_update);
135 double framerate_regulator::get_realized_fps()
137 if(frame_number < 2)
138 return 0;
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;
148 frame_number++;
151 std::pair<bool, double> framerate_regulator::read_fps()
153 double n, m;
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);
161 else
162 return std::make_pair(false, n * m);