Clean up framerate handling

Also stop saving the framerate (it is not meaningful to persist between
sessions).
This commit is contained in:
Ilari Liusvaara 2013-02-09 16:24:31 +02:00
parent 363e7c7a3c
commit c9e05a607a
4 changed files with 70 additions and 96 deletions

View file

@ -3,6 +3,19 @@
#include <cstdint> #include <cstdint>
/**
* Set the target speed multiplier.
*
* Parameter multiplier: The multiplier target. May be INFINITE.
*/
void set_speed_multiplier(double multiplier) throw();
/**
* Get the target speed multiplier.
*
* Returns: The multiplier. May be INFINITE.
*/
double get_speed_multiplier() throw();
/** /**
* Sets the nominal frame rate. Framerate limiting tries to maintain the nominal framerate when there is no other * Sets the nominal frame rate. Framerate limiting tries to maintain the nominal framerate when there is no other
@ -11,11 +24,11 @@
void set_nominal_framerate(double fps) throw(); void set_nominal_framerate(double fps) throw();
/** /**
* Returns the current realized framerate. * Returns the current realized framerate multiplier.
* *
* returns: The framerate the system is currently archiving. * returns: The framerate multiplier the system is currently archiving.
*/ */
double get_framerate() throw(); double get_realized_multiplier() throw();
/** /**
* Freeze time. * Freeze time.

View file

@ -13,6 +13,7 @@
#include <stdexcept> #include <stdexcept>
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>
#include <limits>
#define HISTORY_FRAMES 10 #define HISTORY_FRAMES 10
@ -25,10 +26,11 @@ namespace
bool time_frozen = true; bool time_frozen = true;
uint64_t frame_number = 0; uint64_t frame_number = 0;
uint64_t frame_start_times[HISTORY_FRAMES]; uint64_t frame_start_times[HISTORY_FRAMES];
double nominal_rate = 100; //Framerate.
bool target_nominal = true; double nominal_framerate = 60;
double target_fps = 100.0; double multiplier_framerate = 1;
bool target_infinite = false; mutex_class framerate_lock;
bool turboed = false;
uint64_t get_time(uint64_t curtime, bool update) uint64_t get_time(uint64_t curtime, bool update)
{ {
@ -58,86 +60,19 @@ namespace
frame_number++; frame_number++;
} }
struct setting_targetfps : public setting std::pair<bool, double> read_fps()
{ {
setting_targetfps() throw(std::bad_alloc) double n, m;
: setting(lsnes_set, "targetfps")
{ {
umutex_class h(framerate_lock);
n = nominal_framerate;
m = multiplier_framerate;
} }
if(m == std::numeric_limits<double>::infinity())
bool blank(bool really) throw(std::bad_alloc, std::runtime_error) return std::make_pair(true, 0);
{ else
if(!really) return std::make_pair(false, n * m);
return true; }
target_nominal = true;
target_infinite = false;
target_fps = 100.0;
return true;
}
bool is_set() throw()
{
return !target_nominal;
}
virtual void set(const std::string& value) throw(std::bad_alloc, std::runtime_error)
{
double tmp;
const char* s;
char* e;
if(value == "infinite") {
target_infinite = true;
target_nominal = false;
return;
}
s = value.c_str();
tmp = strtod(s, &e);
if(*e)
throw std::runtime_error("Invalid frame rate");
if(tmp < 0.001)
throw std::runtime_error("Target frame rate must be at least 0.001fps");
target_fps = tmp;
target_infinite = false;
target_nominal = false;
}
virtual std::string get() throw(std::bad_alloc)
{
if(target_nominal)
return "";
else if(target_infinite)
return "infinite";
else {
std::ostringstream o;
o << target_fps;
return o.str();
}
}
std::pair<bool, double> read() throw()
{
lock_holder lck(this);
return std::make_pair(target_infinite, target_fps);
}
void set_nominal_framerate(double fps)
{
lock_holder(this);
nominal_rate = fps;
if(target_nominal) {
target_fps = nominal_rate;
target_infinite = false;
}
}
double get_framerate()
{
lock_holder(this);
return 100.0 * get_realized_fps() / nominal_rate;
}
} targetfps;
bool turboed = false;
function_ptr_command<> tturbo(lsnes_cmd, "toggle-turbo", "Toggle turbo", function_ptr_command<> tturbo(lsnes_cmd, "toggle-turbo", "Toggle turbo",
"Syntax: toggle-turbo\nToggle turbo mode.\n", "Syntax: toggle-turbo\nToggle turbo mode.\n",
@ -161,6 +96,21 @@ namespace
inverse_bind turbot(lsnes_mapper, "toggle-turbo", "Speed‣Turbo toggle"); inverse_bind turbot(lsnes_mapper, "toggle-turbo", "Speed‣Turbo toggle");
} }
//Set the speed multiplier. Note that INFINITE is a valid multiplier.
void set_speed_multiplier(double multiplier) throw()
{
umutex_class h(framerate_lock);
multiplier_framerate = multiplier;
}
//Get the speed multiplier. Note that this may be INFINITE.
double get_speed_multiplier() throw()
{
umutex_class h(framerate_lock);
return multiplier_framerate;
}
void freeze_time(uint64_t curtime) void freeze_time(uint64_t curtime)
{ {
get_time(curtime, true); get_time(curtime, true);
@ -176,12 +126,14 @@ void unfreeze_time(uint64_t curtime)
void set_nominal_framerate(double fps) throw() void set_nominal_framerate(double fps) throw()
{ {
targetfps.set_nominal_framerate(fps); umutex_class h(framerate_lock);
nominal_framerate = fps;
} }
double get_framerate() throw() double get_realized_multiplier() throw()
{ {
return targetfps.get_framerate(); umutex_class h(framerate_lock);
return get_realized_fps() / nominal_framerate;
} }
void ack_frame_tick(uint64_t usec) throw() void ack_frame_tick(uint64_t usec) throw()
@ -192,17 +144,17 @@ void ack_frame_tick(uint64_t usec) throw()
uint64_t to_wait_frame(uint64_t usec) throw() uint64_t to_wait_frame(uint64_t usec) throw()
{ {
auto target = targetfps.read(); auto target = read_fps();
if(!frame_number || target.first || turboed || graphics_driver_is_dummy()) if(!frame_number || target.first || turboed || graphics_driver_is_dummy())
return 0; return 0;
uint64_t lintime = get_time(usec, true); uint64_t lintime = get_time(usec, true);
uint64_t frame_lasted = lintime - frame_start_times[0]; uint64_t frame_lasted = lintime - frame_start_times[0];
uint64_t frame_should_last = 1000000 / (target.second * nominal_rate / 100); uint64_t frame_should_last = 1000000 / target.second;
if(frame_lasted >= frame_should_last) if(frame_lasted >= frame_should_last)
return 0; //We are late. return 0; //We are late.
uint64_t history_frames = min(frame_number, static_cast<uint64_t>(HISTORY_FRAMES)); uint64_t history_frames = min(frame_number, static_cast<uint64_t>(HISTORY_FRAMES));
uint64_t history_lasted = lintime - frame_start_times[history_frames - 1]; uint64_t history_lasted = lintime - frame_start_times[history_frames - 1];
uint64_t history_should_last = history_frames * 1000000 / (target.second * nominal_rate / 100); uint64_t history_should_last = history_frames * 1000000 / target.second;
if(history_lasted >= history_should_last) if(history_lasted >= history_should_last)
return 0; return 0;
return min(history_should_last - history_lasted, frame_should_last - frame_lasted); return min(history_should_last - history_lasted, frame_should_last - frame_lasted);

View file

@ -298,7 +298,7 @@ void update_movie_state()
_status.erase("Saveslot"); _status.erase("Saveslot");
{ {
std::ostringstream x; std::ostringstream x;
x << get_framerate(); x << 100 * get_realized_multiplier();
_status.set("SPD%", x.str()); _status.set("SPD%", x.str());
} }
do_watch_memory(); do_watch_memory();

View file

@ -265,11 +265,10 @@ namespace
void set_speed(double target) void set_speed(double target)
{ {
std::string v = (stringfmt() << target).str();
if(target < 0) if(target < 0)
lsnes_set.set("targetfps", "infinite"); set_speed_multiplier(std::numeric_limits<double>::infinity());
else else
lsnes_set.set("targetfps", v); set_speed_multiplier(target / 100);
} }
class autohold_menu; class autohold_menu;
@ -1165,10 +1164,20 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
} }
case wxID_SET_SPEED: { case wxID_SET_SPEED: {
bool bad = false; bool bad = false;
std::string value = lsnes_set.is_set("targetfps") ? lsnes_set.get("targetfps") : ""; std::string value = "infinite";
double val = get_speed_multiplier();
if(!(val == std::numeric_limits<double>::infinity()))
value = (stringfmt() << (100 * val)).str();
value = pick_text(this, "Set speed", "Enter percentage speed (or \"infinite\"):", value); value = pick_text(this, "Set speed", "Enter percentage speed (or \"infinite\"):", value);
try { try {
lsnes_set.set("targetfps", value); if(value == "infinite")
set_speed_multiplier(std::numeric_limits<double>::infinity());
else {
double v = parse_value<double>(value) / 100;
if(v <= 0.0001)
throw 42;
set_speed_multiplier(v);
}
} catch(...) { } catch(...) {
wxMessageBox(wxT("Invalid speed"), _T("Error"), wxICON_EXCLAMATION | wxOK, this); wxMessageBox(wxT("Invalid speed"), _T("Error"), wxICON_EXCLAMATION | wxOK, this);
} }