You are not logged in.

Read the FAQ and Knowledge Base before posting.
We won't make a 3DS/2DS emulator.



#1 2013-10-20 23:54:46

rmartins
Member
Registered: 2013-10-20
Posts: 5

patch: new limiter for gtk

Hello! This is my first time posting, so just to set the background: thank you all very much for this emulator, I'm having a blast with all the cool games on the NDS collection.

Now, I made a patch for the gtk frontend to change the FPS limiter. I was getting 64 fps instead of 60, and it was not very smooth (ok it's a small difference, but anyway). It's based on the glade limiter and the patch is below. Now I'm getting 60 fps and it also solved many of my problems with the dual asynchronous sound.

Hope it helps!

Index: main.cpp
===================================================================
--- main.cpp	(revision 4806)
+++ main.cpp	(working copy)
@@ -80,8 +80,8 @@
 #define SCREEN_BYTES_PER_PIXEL 3
 #define GAP_SIZE 50
 
-#define FPS_LIMITER_FRAME_PERIOD 8
-static SDL_sem *fps_limiter_semaphore;
+#define TICKS_PER_FRAME 17
+Uint32 ticksPrevFrame = 0;
 static int gtk_fps_limiter_disabled;
 extern int _scanline_filter_a, _scanline_filter_b, _scanline_filter_c, _scanline_filter_d;
 VideoFilter video(256, 384, VideoFilterTypeID_HQ2XS, 4);
@@ -1936,7 +1936,6 @@
 gboolean EmuLoop(gpointer data)
 {
     static Uint32 fps_SecStart, next_fps_SecStart, fps_FrameCount, skipped_frames; 
-    static int limiter_frame_counter;
     unsigned int i;
     gchar Title[20];
 
@@ -1983,41 +1982,15 @@
     _updateDTools();
     gtk_widget_queue_draw( pDrawingArea );
     osd->clear();
+		
+    if(!gtk_fps_limiter_disabled)
+      while((SDL_GetTicks() - ticksPrevFrame) < TICKS_PER_FRAME);
+    ticksPrevFrame = SDL_GetTicks();
 
-    if (!gtk_fps_limiter_disabled) {
-        limiter_frame_counter += 1;
-        if (limiter_frame_counter >= FPS_LIMITER_FRAME_PERIOD) {
-            limiter_frame_counter = 0;
-            /* wait for the timer to expire */
-            SDL_SemWait( fps_limiter_semaphore);
-        }
-    }
-
     return TRUE;
 }
 
 
-/** 
- * A SDL timer callback function. Signals the supplied SDL semaphore
- * if its value is small.
- * 
- * @param interval The interval since the last call (in ms)
- * @param param The pointer to the semaphore.
- * 
- * @return The interval to the next call (required by SDL)
- */
-static Uint32 fps_limiter_fn(Uint32 interval, void *param)
-{
-  SDL_sem *sdl_semaphore = (SDL_sem *)param;
-
-  /* signal the semaphore if it is getting low */
-  if ( SDL_SemValue( sdl_semaphore) < 4) {
-    SDL_SemPost( sdl_semaphore);
-  }
-
-  return interval;
-}
-
 static void desmume_try_adding_ui(GtkUIManager *self, const char *ui_descr){
     GError *error;
     error = NULL;
@@ -2131,8 +2104,6 @@
 {
     driver = new GtkDriver();
 
-    SDL_TimerID limiter_timer = NULL;
-
     GtkAccelGroup * accel_group;
     GtkWidget *pVBox;
     GtkWidget *pMenuBar;
@@ -2358,21 +2329,8 @@
     gtk_box_pack_end(GTK_BOX(pVBox), pStatusBar, FALSE, FALSE, 0);
 
     gtk_widget_show_all(pWindow);
-
     gtk_fps_limiter_disabled = my_config->disable_limiter;
-    if ( !gtk_fps_limiter_disabled) {
-        /* create the semaphore used for fps limiting */
-        fps_limiter_semaphore = SDL_CreateSemaphore( 1);
 
-        /* start a SDL timer for every FPS_LIMITER_FRAME_PERIOD frames to keep us at 60 fps */
-        limiter_timer = SDL_AddTimer( 16 * FPS_LIMITER_FRAME_PERIOD, fps_limiter_fn, fps_limiter_semaphore);
-        if ( limiter_timer == NULL) {
-            g_printerr("Error trying to start FPS limiter timer: %s\n",
-                     SDL_GetError());
-            return 1;
-        }
-    }
-
     //Set the 3D emulation to use
     unsigned core = my_config->engine_3d;
     // setup the gdk 3D emulation;
@@ -2428,12 +2386,6 @@
 
     desmume_free();
 
-    if ( !gtk_fps_limiter_disabled) {
-        /* tidy up the FPS limiter timer and semaphore */
-        SDL_RemoveTimer( limiter_timer);
-        SDL_DestroySemaphore( fps_limiter_semaphore);
-    }
-
     /* Unload joystick */
     uninit_joy();

Dell System Vostro 3450 / Linux 3.10-2-amd64 Debian 3.10.7-1 x86_64
Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz (4 cores)
MemTotal: 6022396 kB

Offline

#2 2013-10-31 17:43:49

rmartins
Member
Registered: 2013-10-20
Posts: 5

Re: patch: new limiter for gtk

Hello again. I wasn't satisfied with using a while loop to limit framerate (seems really brute) so I made this new limiter. It is not portable, of course, but it's incredibly accurate. The 16800 value is what works best on my system, currently, but it could be anything >= 16667.

Hope it helps!

Index: src/gtk/main.cpp
===================================================================
--- src/gtk/main.cpp	(revision 4810)
+++ src/gtk/main.cpp	(working copy)
@@ -26,6 +26,8 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #include <SDL.h>
@@ -80,8 +82,6 @@
 #define SCREEN_BYTES_PER_PIXEL 3
 #define GAP_SIZE 50
 
-#define FPS_LIMITER_FRAME_PERIOD 8
-static SDL_sem *fps_limiter_semaphore;
 static int gtk_fps_limiter_disabled;
 extern int _scanline_filter_a, _scanline_filter_b, _scanline_filter_c, _scanline_filter_d;
 VideoFilter video(256, 384, VideoFilterTypeID_HQ2XS, 4);
@@ -1932,11 +1932,12 @@
     gtk_main_quit();
 }
 
+timespec frame_start_time, frame_end_time;
+useconds_t microsec_to_wait;
 
 gboolean EmuLoop(gpointer data)
 {
     static Uint32 fps_SecStart, next_fps_SecStart, fps_FrameCount, skipped_frames; 
-    static int limiter_frame_counter;
     unsigned int i;
     gchar Title[20];
 
@@ -1984,40 +1985,18 @@
     gtk_widget_queue_draw( pDrawingArea );
     osd->clear();
 
-    if (!gtk_fps_limiter_disabled) {
-        limiter_frame_counter += 1;
-        if (limiter_frame_counter >= FPS_LIMITER_FRAME_PERIOD) {
-            limiter_frame_counter = 0;
-            /* wait for the timer to expire */
-            SDL_SemWait( fps_limiter_semaphore);
-        }
+    if (!gtk_fps_limiter_disabled && frame_start_time.tv_nsec > 0) {
+      clock_gettime(CLOCK_REALTIME, &frame_end_time);
+      microsec_to_wait = 16800 - (frame_end_time.tv_nsec - frame_start_time.tv_nsec) / 1000;
+      if (microsec_to_wait > 0 && microsec_to_wait < 16800) {
+        usleep(microsec_to_wait);
+      }
     }
+    clock_gettime(CLOCK_REALTIME, &frame_start_time);
 
     return TRUE;
 }
 
-
-/** 
- * A SDL timer callback function. Signals the supplied SDL semaphore
- * if its value is small.
- * 
- * @param interval The interval since the last call (in ms)
- * @param param The pointer to the semaphore.
- * 
- * @return The interval to the next call (required by SDL)
- */
-static Uint32 fps_limiter_fn(Uint32 interval, void *param)
-{
-  SDL_sem *sdl_semaphore = (SDL_sem *)param;
-
-  /* signal the semaphore if it is getting low */
-  if ( SDL_SemValue( sdl_semaphore) < 4) {
-    SDL_SemPost( sdl_semaphore);
-  }
-
-  return interval;
-}
-
 static void desmume_try_adding_ui(GtkUIManager *self, const char *ui_descr){
     GError *error;
     error = NULL;
@@ -2131,8 +2110,6 @@
 {
     driver = new GtkDriver();
 
-    SDL_TimerID limiter_timer = NULL;
-
     GtkAccelGroup * accel_group;
     GtkWidget *pVBox;
     GtkWidget *pMenuBar;
@@ -2360,19 +2337,7 @@
     gtk_widget_show_all(pWindow);
 
     gtk_fps_limiter_disabled = my_config->disable_limiter;
-    if ( !gtk_fps_limiter_disabled) {
-        /* create the semaphore used for fps limiting */
-        fps_limiter_semaphore = SDL_CreateSemaphore( 1);
 
-        /* start a SDL timer for every FPS_LIMITER_FRAME_PERIOD frames to keep us at 60 fps */
-        limiter_timer = SDL_AddTimer( 16 * FPS_LIMITER_FRAME_PERIOD, fps_limiter_fn, fps_limiter_semaphore);
-        if ( limiter_timer == NULL) {
-            g_printerr("Error trying to start FPS limiter timer: %s\n",
-                     SDL_GetError());
-            return 1;
-        }
-    }
-
     //Set the 3D emulation to use
     unsigned core = my_config->engine_3d;
     // setup the gdk 3D emulation;
@@ -2428,12 +2393,6 @@
 
     desmume_free();
 
-    if ( !gtk_fps_limiter_disabled) {
-        /* tidy up the FPS limiter timer and semaphore */
-        SDL_RemoveTimer( limiter_timer);
-        SDL_DestroySemaphore( fps_limiter_semaphore);
-    }
-
     /* Unload joystick */
     uninit_joy();

Dell System Vostro 3450 / Linux 3.10-2-amd64 Debian 3.10.7-1 x86_64
Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz (4 cores)
MemTotal: 6022396 kB

Offline

#3 2014-02-07 09:39:54

alvinhochun
Member
Registered: 2014-02-07
Posts: 61

Re: patch: new limiter for gtk

Just for your information, I committed my very own new fps limiter and frameskip code here: https://sourceforge.net/p/desmume/code/4977/

You can download the latest svn code to try it out.

Thanks for your patch anyway. smile

Offline

Board footer

Powered by FluxBB