GTK+: Clean up speed throttling.

No more frameskip selection, only 4 options:

* Timer throttling to Settings.FrameRate
* Same, but skips frames when late
* Wait on sound buffer
* Don't throttle.

Dynamic rate control is automatically disabled for option 3.
This commit is contained in:
Brandon Wright 2018-10-28 16:55:33 -05:00
parent 7dcf6a0ce4
commit 79b1ab0250
9 changed files with 168 additions and 294 deletions

View File

@ -204,7 +204,7 @@ else
fi fi
PKG_CHECK_MODULES([GTK], ["$GTK_VERSION"]) PKG_CHECK_MODULES([GTK], ["$GTK_VERSION"])
PKG_CHECK_MODULES([GLIB], [gthread-2.0 >= 2.6 gobject-2.0 >= 2.6]) PKG_CHECK_MODULES([GLIB], [glib-2.0 > 2.28 gthread-2.0 >= 2.6 gobject-2.0 >= 2.6])
PKG_CHECK_MODULES([LIBXML], [libxml-2.0 >= 2.0]) PKG_CHECK_MODULES([LIBXML], [libxml-2.0 >= 2.0])
PKG_CHECK_MODULES([XRANDR], [xrandr]) PKG_CHECK_MODULES([XRANDR], [xrandr])

View File

@ -413,7 +413,6 @@ Snes9xConfig::save_config_file (void)
xml_out_int (xml, "sound_buffer_size", sound_buffer_size); xml_out_int (xml, "sound_buffer_size", sound_buffer_size);
xml_out_int (xml, "sound_driver", sound_driver); xml_out_int (xml, "sound_driver", sound_driver);
xml_out_int (xml, "sound_input_rate", sound_input_rate); xml_out_int (xml, "sound_input_rate", sound_input_rate);
xml_out_int (xml, "sound_sync", Settings.SoundSync);
xml_out_int (xml, "dynamic_rate_control", Settings.DynamicRateControl); xml_out_int (xml, "dynamic_rate_control", Settings.DynamicRateControl);
xml_out_int (xml, "dynamic_rate_limit", Settings.DynamicRateLimit); xml_out_int (xml, "dynamic_rate_limit", Settings.DynamicRateLimit);
xml_out_int (xml, "auto_input_rate", auto_input_rate); xml_out_int (xml, "auto_input_rate", auto_input_rate);
@ -653,6 +652,8 @@ Snes9xConfig::set_option (const char *name, const char *value)
else if (!strcasecmp (name, "frameskip")) else if (!strcasecmp (name, "frameskip"))
{ {
Settings.SkipFrames = atoi (value); Settings.SkipFrames = atoi (value);
if (Settings.SkipFrames == THROTTLE_SOUND_SYNC)
Settings.SoundSync = 1;
} }
else if (!strcasecmp (name, "sound_emulation")) else if (!strcasecmp (name, "sound_emulation"))
{ {
@ -918,10 +919,6 @@ Snes9xConfig::set_option (const char *name, const char *value)
{ {
Settings.UpAndDown = CLAMP (atoi (value), 0, 1); Settings.UpAndDown = CLAMP (atoi (value), 0, 1);
} }
else if (!strcasecmp (name, "sound_sync"))
{
Settings.SoundSync = atoi (value) ? 1 : 0;
}
else if (!strcasecmp (name, "rewind_buffer_size")) else if (!strcasecmp (name, "rewind_buffer_size"))
{ {
rewind_buffer_size = CLAMP (atoi (value), 0, 2000); rewind_buffer_size = CLAMP (atoi (value), 0, 2000);

View File

@ -1,7 +1,6 @@
#ifndef __GTK_CONFIG_H #ifndef __GTK_CONFIG_H
#define __GTK_CONFIG_H #define __GTK_CONFIG_H
#include <sys/time.h>
#include <libxml/parser.h> #include <libxml/parser.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h> #include <X11/extensions/Xrandr.h>
@ -9,17 +8,30 @@
#include "gtk_control.h" #include "gtk_control.h"
#include "snes_ntsc.h" #include "snes_ntsc.h"
#define HWA_NONE 0 enum {
#define HWA_OPENGL 1 HWA_NONE = 0,
#define HWA_XV 2 HWA_OPENGL = 1,
HWA_XV = 2
};
#define HIRES_MERGE 0 enum {
#define HIRES_NORMAL 1 HIRES_MERGE = 0,
#define HIRES_SCALE 2 HIRES_NORMAL = 1,
HIRES_SCALE = 2
};
#define ESC_TOGGLE_MENUBAR 0 enum {
#define ESC_EXIT_FULLSCREEN 1 ESC_TOGGLE_MENUBAR = 0,
#define ESC_EXIT_SNES9X 2 ESC_EXIT_FULLSCREEN = 1,
ESC_EXIT_SNES9X = 2
};
enum {
THROTTLE_TIMER = 0,
THROTTLE_TIMER_FRAMESKIP = 1,
THROTTLE_SOUND_SYNC = 2,
THROTTLE_NONE = 3
};
class Snes9xConfig class Snes9xConfig
{ {
@ -128,11 +140,11 @@ class Snes9xConfig
unsigned char screensaver_needs_reset; unsigned char screensaver_needs_reset;
int modal_dialogs; int modal_dialogs;
int pointer_is_visible; int pointer_is_visible;
struct timeval pointer_timestamp; gint64 pointer_timestamp;
unsigned int rewind_granularity; unsigned int rewind_granularity;
unsigned int rewind_buffer_size; unsigned int rewind_buffer_size;
XRRScreenResources *xrr_screen_resources; XRRScreenResources *xrr_screen_resources;
XRRCrtcInfo *xrr_crtc_info; XRRCrtcInfo *xrr_crtc_info;

View File

@ -1,6 +1,4 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>

View File

@ -361,6 +361,23 @@ event_hw_accel_changed (GtkComboBox *widget, gpointer data)
return; return;
} }
static void
event_frameskip_combo_changed (GtkComboBox *widget, gpointer user_data)
{
Snes9xPreferences *window = (Snes9xPreferences *) user_data;
if (window->get_combo ("frameskip_combo") == THROTTLE_SOUND_SYNC)
{
window->set_check ("dynamic_rate_control", 0);
window->enable_widget ("dynamic_rate_control", 0);
}
else
{
window->enable_widget ("dynamic_rate_control", 1);
}
}
static void static void
event_scale_method_changed (GtkComboBox *widget, gpointer user_data) event_scale_method_changed (GtkComboBox *widget, gpointer user_data)
{ {
@ -584,6 +601,7 @@ Snes9xPreferences::Snes9xPreferences (Snes9xConfig *config) :
{ "game_data_clear", G_CALLBACK (event_game_data_clear) }, { "game_data_clear", G_CALLBACK (event_game_data_clear) },
{ "about_clicked", G_CALLBACK (event_about_clicked) }, { "about_clicked", G_CALLBACK (event_about_clicked) },
{ "auto_input_rate_toggled", G_CALLBACK (event_auto_input_rate_toggled) }, { "auto_input_rate_toggled", G_CALLBACK (event_auto_input_rate_toggled) },
{ "frameskip_combo_changed", G_CALLBACK (event_frameskip_combo_changed) },
#ifdef USE_JOYSTICK #ifdef USE_JOYSTICK
{ "calibrate", G_CALLBACK (event_calibrate) }, { "calibrate", G_CALLBACK (event_calibrate) },
#endif #endif
@ -711,7 +729,8 @@ Snes9xPreferences::move_settings_to_dialog (void)
config->auto_input_rate ? FALSE : TRUE); config->auto_input_rate ? FALSE : TRUE);
set_spin ("sound_buffer_size", config->sound_buffer_size); set_spin ("sound_buffer_size", config->sound_buffer_size);
set_check ("sync_sound", Settings.SoundSync); if (Settings.SkipFrames == THROTTLE_SOUND_SYNC)
Settings.DynamicRateControl = 0;
set_check ("dynamic_rate_control", Settings.DynamicRateControl); set_check ("dynamic_rate_control", Settings.DynamicRateControl);
set_spin ("dynamic_rate_limit", Settings.DynamicRateLimit / 1000.0); set_spin ("dynamic_rate_limit", Settings.DynamicRateLimit / 1000.0);
set_spin ("rewind_buffer_size", config->rewind_buffer_size); set_spin ("rewind_buffer_size", config->rewind_buffer_size);
@ -762,9 +781,8 @@ Snes9xPreferences::move_settings_to_dialog (void)
set_combo ("ntsc_scanline_intensity", config->ntsc_scanline_intensity); set_combo ("ntsc_scanline_intensity", config->ntsc_scanline_intensity);
set_combo ("scanline_filter_intensity", config->scanline_filter_intensity); set_combo ("scanline_filter_intensity", config->scanline_filter_intensity);
set_combo ("frameskip_combo", set_combo ("frameskip_combo", Settings.SkipFrames);
Settings.SkipFrames == AUTO_FRAMERATE ? enable_widget ("dynamic_rate_control", Settings.SkipFrames != THROTTLE_SOUND_SYNC);
0 : Settings.SkipFrames + 1);
set_check ("bilinear_filter", Settings.BilinearFilter); set_check ("bilinear_filter", Settings.BilinearFilter);
#ifdef USE_OPENGL #ifdef USE_OPENGL
@ -806,6 +824,11 @@ Snes9xPreferences::get_settings_from_dialog (void)
{ {
int sound_needs_restart = 0; int sound_needs_restart = 0;
int gfx_needs_restart = 0; int gfx_needs_restart = 0;
int sound_sync = 0;
Settings.SkipFrames = get_combo ("frameskip_combo");
if (Settings.SkipFrames == THROTTLE_SOUND_SYNC)
sound_sync = 1;
if ((config->sound_driver != get_combo ("sound_driver")) || if ((config->sound_driver != get_combo ("sound_driver")) ||
(config->mute_sound != get_check ("mute_sound_check")) || (config->mute_sound != get_check ("mute_sound_check")) ||
@ -814,7 +837,7 @@ Snes9xPreferences::get_settings_from_dialog (void)
(config->sound_playback_rate != (7 - (get_combo ("playback_combo")))) || (config->sound_playback_rate != (7 - (get_combo ("playback_combo")))) ||
(config->sound_input_rate != get_slider ("sound_input_rate")) || (config->sound_input_rate != get_slider ("sound_input_rate")) ||
(config->auto_input_rate != get_check ("auto_input_rate")) || (config->auto_input_rate != get_check ("auto_input_rate")) ||
(Settings.SoundSync != get_check ("sync_sound")) || (Settings.SoundSync != sound_sync) ||
(Settings.DynamicRateControl != get_check ("dynamic_rate_control"))) (Settings.DynamicRateControl != get_check ("dynamic_rate_control")))
{ {
sound_needs_restart = 1; sound_needs_restart = 1;
@ -858,7 +881,6 @@ Snes9xPreferences::get_settings_from_dialog (void)
Settings.AutoSaveDelay = get_entry_value ("save_sram_after_sec"); Settings.AutoSaveDelay = get_entry_value ("save_sram_after_sec");
config->multithreading = get_check ("multithreading"); config->multithreading = get_check ("multithreading");
config->pause_emulation_on_switch = get_check ("pause_emulation_on_switch"); config->pause_emulation_on_switch = get_check ("pause_emulation_on_switch");
Settings.SkipFrames = get_combo ("frameskip_combo");
Settings.BlockInvalidVRAMAccessMaster = get_check ("block_invalid_vram_access"); Settings.BlockInvalidVRAMAccessMaster = get_check ("block_invalid_vram_access");
Settings.UpAndDown = get_check ("upanddown"); Settings.UpAndDown = get_check ("upanddown");
Settings.SuperFXClockMultiplier = get_spin ("superfx_multiplier"); Settings.SuperFXClockMultiplier = get_spin ("superfx_multiplier");
@ -868,7 +890,7 @@ Snes9xPreferences::get_settings_from_dialog (void)
config->sound_buffer_size = get_spin ("sound_buffer_size"); config->sound_buffer_size = get_spin ("sound_buffer_size");
config->sound_input_rate = get_slider ("sound_input_rate"); config->sound_input_rate = get_slider ("sound_input_rate");
config->auto_input_rate = get_check ("auto_input_rate"); config->auto_input_rate = get_check ("auto_input_rate");
Settings.SoundSync = get_check ("sync_sound"); Settings.SoundSync = sound_sync;
config->mute_sound = get_check ("mute_sound_check"); config->mute_sound = get_check ("mute_sound_check");
config->mute_sound_turbo = get_check ("mute_sound_turbo_check"); config->mute_sound_turbo = get_check ("mute_sound_turbo_check");
Settings.DynamicRateControl = get_check ("dynamic_rate_control"); Settings.DynamicRateControl = get_check ("dynamic_rate_control");
@ -988,11 +1010,6 @@ Snes9xPreferences::get_settings_from_dialog (void)
strncpy (config->sram_directory, safety_sram_directory, PATH_MAX); strncpy (config->sram_directory, safety_sram_directory, PATH_MAX);
} }
if (Settings.SkipFrames == 0)
Settings.SkipFrames = AUTO_FRAMERATE;
else
Settings.SkipFrames--;
memcpy (config->pad, pad, (sizeof (JoypadBinding)) * NUM_JOYPADS); memcpy (config->pad, pad, (sizeof (JoypadBinding)) * NUM_JOYPADS);
memcpy (config->shortcut, shortcut, (sizeof (Binding)) * NUM_EMU_LINKS); memcpy (config->shortcut, shortcut, (sizeof (Binding)) * NUM_EMU_LINKS);

View File

@ -1,5 +1,4 @@
#include <stdio.h> #include <stdio.h>
#include <sys/time.h>
#include <signal.h> #include <signal.h>
#include <gdk/gdk.h> #include <gdk/gdk.h>
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
@ -17,33 +16,26 @@
#include "gtk_netplay.h" #include "gtk_netplay.h"
#endif #endif
#define IDLE_FUNC_PRIORITY (G_PRIORITY_DEFAULT_IDLE) void S9xPostRomInit ();
static void S9xThrottle ();
void S9xPostRomInit (void); static void S9xCheckPointerTimer ();
void S9xSyncSpeedFinish (void);
static void S9xCheckPointerTimer (void);
static gboolean S9xIdleFunc (gpointer data); static gboolean S9xIdleFunc (gpointer data);
static gboolean S9xScreenSaverCheckFunc (gpointer data); static gboolean S9xScreenSaverCheckFunc (gpointer data);
Snes9xWindow *top_level; Snes9xWindow *top_level;
Snes9xConfig *gui_config; Snes9xConfig *gui_config;
StateManager stateMan; StateManager state_manager;
static struct timeval next_frame_time = { 0, 0 }; static int needs_fullscreening = FALSE;
static struct timeval now; guint idle_func_id;
static int needs_fullscreening = FALSE; gint64 frame_clock = -1;
int syncing; gint64 pointer_timestamp = -1;
guint idle_func_id;
void void S9xTerm (int signal)
S9xTerm (int signal)
{ {
S9xExit (); S9xExit ();
return;
} }
int int main (int argc, char *argv[])
main (int argc, char *argv[])
{ {
struct sigaction sig_callback; struct sigaction sig_callback;
@ -118,8 +110,7 @@ main (int argc, char *argv[])
top_level->update_accels (); top_level->update_accels ();
Settings.Paused = TRUE; Settings.Paused = TRUE;
syncing = 0; idle_func_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
idle_func_id = g_idle_add_full (IDLE_FUNC_PRIORITY,
S9xIdleFunc, S9xIdleFunc,
NULL, NULL,
NULL); NULL);
@ -160,8 +151,7 @@ main (int argc, char *argv[])
return 0; return 0;
} }
int int S9xOpenROM (const char *rom_filename)
S9xOpenROM (const char *rom_filename)
{ {
uint32 flags; uint32 flags;
bool8 loaded; bool8 loaded;
@ -237,7 +227,7 @@ S9xOpenROM (const char *rom_filename)
CPU.Flags = flags; CPU.Flags = flags;
if (stateMan.init (gui_config->rewind_buffer_size * 1024 * 1024)) if (state_manager.init (gui_config->rewind_buffer_size * 1024 * 1024))
{ {
printf ("Using rewind buffer of %uMB\n", gui_config->rewind_buffer_size); printf ("Using rewind buffer of %uMB\n", gui_config->rewind_buffer_size);
} }
@ -247,8 +237,7 @@ S9xOpenROM (const char *rom_filename)
return 0; return 0;
} }
void void S9xROMLoaded ()
S9xROMLoaded (void)
{ {
gui_config->rom_loaded = TRUE; gui_config->rom_loaded = TRUE;
top_level->configure_widgets (); top_level->configure_widgets ();
@ -260,40 +249,18 @@ S9xROMLoaded (void)
} }
S9xSoundStart (); S9xSoundStart ();
return;
} }
void void S9xNoROMLoaded ()
S9xNoROMLoaded (void)
{ {
S9xSoundStop (); S9xSoundStop ();
gui_config->rom_loaded = FALSE; gui_config->rom_loaded = FALSE;
S9xDisplayRefresh (-1, -1); S9xDisplayRefresh (-1, -1);
top_level->configure_widgets (); top_level->configure_widgets ();
top_level->update_statusbar (); top_level->update_statusbar ();
return;
} }
/* gboolean S9xPauseFunc (gpointer data)
static inline void check_messages (void)
{
static unsigned int current_timeout = 0;
if (GFX.InfoStringTimeout > current_timeout)
{
top_level->show_status_message (GFX.InfoString);
}
current_timeout = GFX.InfoStringTimeout;
return;
}
*/
gboolean
S9xPauseFunc (gpointer data)
{ {
S9xProcessEvents (TRUE); S9xProcessEvents (TRUE);
@ -325,7 +292,7 @@ S9xPauseFunc (gpointer data)
#endif #endif
/* Resume high-performance callback */ /* Resume high-performance callback */
idle_func_id = g_idle_add_full (IDLE_FUNC_PRIORITY, idle_func_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
S9xIdleFunc, S9xIdleFunc,
NULL, NULL,
NULL); NULL);
@ -336,8 +303,7 @@ S9xPauseFunc (gpointer data)
return TRUE; return TRUE;
} }
gboolean gboolean S9xIdleFunc (gpointer data)
S9xIdleFunc (gpointer data)
{ {
if (needs_fullscreening) if (needs_fullscreening)
{ {
@ -367,11 +333,8 @@ S9xIdleFunc (gpointer data)
return FALSE; return FALSE;
} }
if (syncing)
S9xSyncSpeedFinish ();
S9xCheckPointerTimer (); S9xCheckPointerTimer ();
S9xThrottle ();
S9xProcessEvents (TRUE); S9xProcessEvents (TRUE);
#ifdef NETPLAY_SUPPORT #ifdef NETPLAY_SUPPORT
@ -385,13 +348,13 @@ S9xIdleFunc (gpointer data)
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
joypads[i] = MovieGetJoypad(i); joypads[i] = MovieGetJoypad(i);
Settings.Rewinding = stateMan.pop(); Settings.Rewinding = state_manager.pop();
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
MovieSetJoypad (i, joypads[i]); MovieSetJoypad (i, joypads[i]);
} }
else if(IPPU.TotalEmulatedFrames % gui_config->rewind_granularity == 0) else if(IPPU.TotalEmulatedFrames % gui_config->rewind_granularity == 0)
stateMan.push(); state_manager.push();
static int muted_from_turbo = FALSE; static int muted_from_turbo = FALSE;
static int mute_saved_state = FALSE; static int mute_saved_state = FALSE;
@ -419,8 +382,7 @@ S9xIdleFunc (gpointer data)
return TRUE; return TRUE;
} }
gboolean gboolean S9xScreenSaverCheckFunc (gpointer data)
S9xScreenSaverCheckFunc (gpointer data)
{ {
if (!Settings.Paused && if (!Settings.Paused &&
@ -432,18 +394,12 @@ S9xScreenSaverCheckFunc (gpointer data)
} }
/* Snes9x core hooks */ /* Snes9x core hooks */
void void S9xMessage (int type, int number, const char *message)
S9xMessage (int type, int number, const char *message)
{ {
/*
fprintf (stderr, "%s\n", message);
*/
return;
} }
/* Varies from ParseArgs because this one is for the OS port to handle */ /* Varies from ParseArgs because this one is for the OS port to handle */
void void S9xParseArg (char **argv, int &i, int argc)
S9xParseArg (char **argv, int &i, int argc)
{ {
if (!strcasecmp (argv[i], "-filter")) if (!strcasecmp (argv[i], "-filter"))
{ {
@ -511,106 +467,33 @@ S9xParseArg (char **argv, int &i, int argc)
{ {
gui_config->mute_sound = TRUE; gui_config->mute_sound = TRUE;
} }
return;
} }
#undef TIMER_DIFF static void S9xThrottle ()
#define TIMER_DIFF(a, b) ((((a).tv_sec - (b).tv_sec) * 1000000) + (a).tv_usec - (b).tv_usec)
/* Finishes syncing by using more accurate system sleep functions*/
void
S9xSyncSpeedFinish (void)
{ {
if (!syncing) gint64 now;
return;
gettimeofday (&now, NULL);
if (Settings.SoundSync && !Settings.DynamicRateControl)
{
while (!S9xSyncSound ())
{
usleep (100);
gettimeofday (&next_frame_time, NULL);
/* If we can't sync sound within a second, we're probably deadlocked */
if (TIMER_DIFF (next_frame_time, now) > 1000000)
{
/* Flush out our sample buffer and give up. */
S9xClearSamples ();
break;
}
}
next_frame_time = now;
return;
}
if (TIMER_DIFF (next_frame_time, now) < -500000)
{
next_frame_time = now;
}
while (timercmp (&next_frame_time, &now, >))
{
int time_left = TIMER_DIFF (next_frame_time, now);
if (time_left > 500000)
{
next_frame_time = now;
break;
}
usleep (time_left);
gettimeofday (&now, NULL);
}
next_frame_time.tv_usec += Settings.FrameTime;
if (next_frame_time.tv_usec >= 1000000)
{
next_frame_time.tv_sec += next_frame_time.tv_usec / 1000000;
next_frame_time.tv_usec %= 1000000;
}
syncing = 0;
return;
}
/* SyncSpeed Handles delays between frames, similar to unix.cpp version,
* cleaned up for clarity, adjusted for GUI event loop */
void
S9xSyncSpeed (void)
{
unsigned int limit;
int lag;
#ifdef NETPLAY_SUPPORT #ifdef NETPLAY_SUPPORT
if (S9xNetplaySyncSpeed ()) if (S9xNetplaySyncSpeed ())
return; return;
#endif #endif
now = g_get_monotonic_time ();
if (Settings.HighSpeedSeek > 0) if (Settings.HighSpeedSeek > 0)
{ {
Settings.HighSpeedSeek--; Settings.HighSpeedSeek--;
IPPU.RenderThisFrame = FALSE; IPPU.RenderThisFrame = FALSE;
IPPU.SkippedFrames = 0; IPPU.SkippedFrames = 0;
frame_clock = now;
gettimeofday (&now, NULL);
next_frame_time = now;
syncing = 0;
return; return;
} }
else if (Settings.TurboMode) if (Settings.TurboMode)
{ {
if ((++IPPU.FrameSkip >= Settings.TurboSkipFrames) IPPU.FrameSkip++;
if ((IPPU.FrameSkip >= Settings.TurboSkipFrames)
&& !Settings.HighSpeedSeek) && !Settings.HighSpeedSeek)
{ {
IPPU.FrameSkip = 0; IPPU.FrameSkip = 0;
@ -623,84 +506,93 @@ S9xSyncSpeed (void)
IPPU.RenderThisFrame = FALSE; IPPU.RenderThisFrame = FALSE;
} }
frame_clock = now;
return; return;
} }
gettimeofday (&now, NULL); IPPU.RenderThisFrame = TRUE;
if (next_frame_time.tv_sec == 0) if (now - frame_clock > 500000)
{ {
next_frame_time = now; frame_clock = now;
++next_frame_time.tv_usec;
} }
if (Settings.SkipFrames == AUTO_FRAMERATE && (!Settings.SoundSync || Settings.DynamicRateControl)) if (Settings.SkipFrames == THROTTLE_SOUND_SYNC &&
!Settings.DynamicRateControl)
{ {
lag = TIMER_DIFF (now, next_frame_time); while (!S9xSyncSound ())
/* We compensate for the frame time by a frame in case it's just a CPU
* discrepancy. We can recover lost time in the next frame anyway. */
if (lag > (int) (Settings.FrameTime))
{ {
if (lag > (int) Settings.FrameTime * 10) usleep (100);
/* If we can't sync sound within a half-second, we're probably deadlocked */
if (g_get_monotonic_time () - now > 500000)
{ {
/* Running way too slowly */ S9xClearSamples ();
next_frame_time = now; break;
IPPU.RenderThisFrame = 1;
IPPU.SkippedFrames = 0;
} }
else }
frame_clock = now;
IPPU.SkippedFrames = 0;
return;
}
else if (Settings.SkipFrames == THROTTLE_NONE)
{
frame_clock = now;
}
else // THROTTLE_TIMER or THROTTLE_TIMER_FRAMESKIP
{
if (Settings.SkipFrames == THROTTLE_TIMER_FRAMESKIP)
{
if (now - frame_clock > Settings.FrameTime)
{ {
IPPU.RenderThisFrame = 0;
IPPU.SkippedFrames++; IPPU.SkippedFrames++;
if (IPPU.SkippedFrames < 8)
{
IPPU.RenderThisFrame = FALSE;
frame_clock += Settings.FrameTime;
return;
}
else
{
frame_clock = now - Settings.FrameTime;
}
} }
} }
else while (now - frame_clock < Settings.FrameTime)
{ {
IPPU.RenderThisFrame = 1; usleep (100);
IPPU.SkippedFrames = 0; now = g_get_monotonic_time ();
} }
frame_clock += Settings.FrameTime;
IPPU.FrameSkip = 0;
IPPU.SkippedFrames = 0;
} }
else
{
limit = (Settings.SoundSync && !Settings.DynamicRateControl) ? 1 : Settings.SkipFrames + 1;
IPPU.SkippedFrames++;
IPPU.RenderThisFrame = 0;
if (IPPU.SkippedFrames >= limit)
{
IPPU.RenderThisFrame = 1;
IPPU.SkippedFrames = 0;
}
}
syncing = 1;
return;
} }
static void void S9xSyncSpeed ()
S9xCheckPointerTimer (void) {
}
static void S9xCheckPointerTimer ()
{ {
if (!gui_config->pointer_is_visible) if (!gui_config->pointer_is_visible)
return; return;
gettimeofday (&now, NULL); if (g_get_monotonic_time () - gui_config->pointer_timestamp > 1000000)
if (TIMER_DIFF (now, gui_config->pointer_timestamp) > 1000000)
{ {
top_level->hide_mouse_cursor (); top_level->hide_mouse_cursor ();
gui_config->pointer_is_visible = FALSE; gui_config->pointer_is_visible = FALSE;
} }
return;
} }
/* Final exit point, issues exit (0) */ /* Final exit point, issues exit (0) */
void void S9xExit ()
S9xExit (void)
{ {
gui_config->save_config_file (); gui_config->save_config_file ();
@ -726,8 +618,6 @@ S9xExit (void)
delete gui_config; delete gui_config;
exit (0); exit (0);
return;
} }
void void
@ -808,18 +698,14 @@ S9xPostRomInit (void)
case 0x0A: break; //Barcode Battler case 0x0A: break; //Barcode Battler
} }
} }
return;
} }
const char * const char *S9xStringInput(const char *message)
S9xStringInput(const char *message)
{ {
return NULL; return NULL;
} }
void void S9xExtraUsage ()
S9xExtraUsage (void)
{ {
printf ("GTK port options:\n" printf ("GTK port options:\n"
"-filter [option] Use a filter to scale the image.\n" "-filter [option] Use a filter to scale the image.\n"
@ -827,5 +713,4 @@ S9xExtraUsage (void)
" super2xsai hq2x hq3x hq4x 2xbrz 3xbrz 4xbrz epx ntsc\n" " super2xsai hq2x hq3x hq4x 2xbrz 3xbrz 4xbrz epx ntsc\n"
"\n" "\n"
"-mutesound Disables sound output.\n"); "-mutesound Disables sound output.\n");
return;
} }

View File

@ -30,8 +30,8 @@
#define bind_textdomain_codeset(Domain,Codeset) (Codeset) #define bind_textdomain_codeset(Domain,Codeset) (Codeset)
#endif /* ENABLE_NLS */ #endif /* ENABLE_NLS */
#define SNES9X_GTK_AUTHORS "(c) 2007 - 2017 Brandon Wright (bearoso@gmail.com)" #define SNES9X_GTK_AUTHORS "(c) 2007 - 2018 Brandon Wright (bearoso@gmail.com)"
#define SNES9X_GTK_VERSION "85" #define SNES9X_GTK_VERSION "86"
extern Snes9xWindow *top_level; extern Snes9xWindow *top_level;
extern Snes9xConfig *gui_config; extern Snes9xConfig *gui_config;
@ -46,7 +46,7 @@ extern Snes9xConfig *gui_config;
#endif #endif
int S9xOpenROM (const char *filename); int S9xOpenROM (const char *filename);
void S9xNoROMLoaded (void); void S9xNoROMLoaded ();
void S9xROMLoaded (void); void S9xROMLoaded ();
#endif /* __GTK_S9X_H */ #endif /* __GTK_S9X_H */

View File

@ -259,7 +259,7 @@ event_motion_notify (GtkWidget *widget,
window->show_mouse_cursor (); window->show_mouse_cursor ();
} }
gettimeofday (&(window->config->pointer_timestamp), NULL); window->config->pointer_timestamp = g_get_monotonic_time ();
return FALSE; return FALSE;
} }

View File

@ -1052,37 +1052,16 @@
</columns> </columns>
<data> <data>
<row> <row>
<col id="0" translatable="yes">Automatic</col> <col id="0" translatable="yes">Timer-based</col>
</row> </row>
<row> <row>
<col id="0" translatable="yes">0</col> <col id="0" translatable="yes">Timer-based with automatic frame-skipping</col>
</row> </row>
<row> <row>
<col id="0" translatable="yes">1</col> <col id="0" translatable="yes">Sound buffer synchronization</col>
</row> </row>
<row> <row>
<col id="0" translatable="yes">2</col> <col id="0" translatable="yes">No throttling, but can use vsync to control speed</col>
</row>
<row>
<col id="0" translatable="yes">3</col>
</row>
<row>
<col id="0" translatable="yes">4</col>
</row>
<row>
<col id="0" translatable="yes">5</col>
</row>
<row>
<col id="0" translatable="yes">6</col>
</row>
<row>
<col id="0" translatable="yes">7</col>
</row>
<row>
<col id="0" translatable="yes">8</col>
</row>
<row>
<col id="0" translatable="yes">9</col>
</row> </row>
</data> </data>
</object> </object>
@ -4135,21 +4114,6 @@
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkCheckButton" id="sync_sound">
<property name="label" translatable="yes">Synchronize with sound</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Base emulation speed on the rate sound is output</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child> <child>
<object class="GtkCheckButton" id="auto_input_rate"> <object class="GtkCheckButton" id="auto_input_rate">
<property name="label" translatable="yes">Automatically adjust input rate to display</property> <property name="label" translatable="yes">Automatically adjust input rate to display</property>
@ -4163,7 +4127,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">2</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -4172,13 +4136,13 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Smoothes out slight hiccups in sound input rate</property> <property name="tooltip_text" translatable="yes">Smoothes out slight hiccups in sound input rate (can't be used with sound buffer synchronization)</property>
<property name="draw_indicator">True</property> <property name="draw_indicator">True</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">3</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
@ -4195,7 +4159,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">4</property> <property name="position">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -4211,7 +4175,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">5</property> <property name="position">4</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -4227,7 +4191,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">6</property> <property name="position">5</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -4447,7 +4411,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">7</property> <property name="position">6</property>
</packing> </packing>
</child> </child>
</object> </object>
@ -4550,7 +4514,7 @@
<object class="GtkLabel" id="label45"> <object class="GtkLabel" id="label45">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label" translatable="yes">Frameskip:</property> <property name="label" translatable="yes">Speed throttle:</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -4563,6 +4527,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="model">liststore5</property> <property name="model">liststore5</property>
<signal name="changed" handler="frameskip_combo_changed" swapped="no"/>
<child> <child>
<object class="GtkCellRendererText" id="cellrenderertext5"/> <object class="GtkCellRendererText" id="cellrenderertext5"/>
<attributes> <attributes>