perfect vsync, bugfixes
authornotaz <notasas@gmail.com>
Sun, 10 Jun 2007 18:08:15 +0000 (18:08 +0000)
committernotaz <notasas@gmail.com>
Sun, 10 Jun 2007 18:08:15 +0000 (18:08 +0000)
git-svn-id: file:///home/notaz/opt/svn/fceu@160 be3aeb3a-fb24-0410-a615-afba39da0efa

17 files changed:
Makefile.gp2x
drivers/gp2x/cpuctrl.c
drivers/gp2x/cpuctrl.h
drivers/gp2x/dface.h
drivers/gp2x/gp2x-video.c
drivers/gp2x/gp2x.c
drivers/gp2x/gp2x.h
drivers/gp2x/input.c
drivers/gp2x/main.c
drivers/gp2x/main.h
drivers/gp2x/menu.c
drivers/gp2x/minimal.c
drivers/gp2x/minimal.h
drivers/gp2x/throttle.c
drivers/gp2x_test/minimal.c
out_gp2x/readme.txt
sound.c

index eb80b17..05908ae 100644 (file)
@@ -71,7 +71,7 @@ ${B}rev.h: FORCE
 include Makefile.common
 
 up: fceu
-       cp -v fceu /mnt/gp2x/mnt/sd/emus/gpfce/gpfce
+       cp -v fceu /mnt/gp2x/mnt/sd/emus/gpfce/gpfce.gpe
 
 # ----------- release -----------
 ifneq ($(findstring rel,$(MAKECMDGOALS)),)
index 7bbdb67..b75cc66 100644 (file)
@@ -1,7 +1,7 @@
 /*  cpuctrl for GP2X
-    Copyright (C) 2005  Hermes/PS2Reality 
+    Copyright (C) 2005  Hermes/PS2Reality
        the gamma-routine was provided by theoddbot
-       parts (c) Rlyehs Work & (C) 2006 god_at_hell 
+       parts (c) Rlyehs Work & (C) 2006 god_at_hell
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 */
 
 
-#include <sys/mman.h>
+#include <stdio.h>
 #include <math.h>
 #include "cpuctrl.h"
 
 
 /* system registers */
-static struct 
+static struct
 {
-       unsigned short SYSCLKENREG,SYSCSETREG,FPLLVSETREG,DUALINT920,DUALINT940,DUALCTRL940,MEMTIMEX0,MEMTIMEX1;
+       unsigned short SYSCLKENREG,SYSCSETREG,UPLLVSETREG,FPLLVSETREG,
+               DUALINT920,DUALINT940,DUALCTRL940,MEMTIMEX0,MEMTIMEX1,DISPCSETREG,
+               DPC_HS_WIDTH,DPC_HS_STR,DPC_HS_END,DPC_VS_END,DPC_DE;
 }
 system_reg;
 
-static unsigned short dispclockdiv;
-
 static volatile unsigned short *MEM_REG;
 
 #define SYS_CLK_FREQ 7372800
 
+// Fout = (m * Fin) / (p * 2^s)
+// m = MDIV+8, p = PDIV+2, s = SDIV
+
+// m = (Fout * p * 2^s) / Fin
 
 void cpuctrl_init(void)
 {
        extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */
        MEM_REG=&gp2x_memregs[0];
-       system_reg.SYSCSETREG=MEM_REG[0x91c>>1];
+       system_reg.DISPCSETREG=MEM_REG[0x924>>1];
+       system_reg.UPLLVSETREG=MEM_REG[0x916>>1];
        system_reg.FPLLVSETREG=MEM_REG[0x912>>1];
+       system_reg.SYSCSETREG=MEM_REG[0x91c>>1];
        system_reg.SYSCLKENREG=MEM_REG[0x904>>1];
        system_reg.DUALINT920=MEM_REG[0x3B40>>1];
        system_reg.DUALINT940=MEM_REG[0x3B42>>1];
        system_reg.DUALCTRL940=MEM_REG[0x3B48>>1];
        system_reg.MEMTIMEX0=MEM_REG[0x3802>>1];
        system_reg.MEMTIMEX1=MEM_REG[0x3804>>1];
-       dispclockdiv=MEM_REG[0x924>>1];
+       system_reg.DPC_HS_WIDTH=MEM_REG[0x281A>>1];
+       system_reg.DPC_HS_STR=MEM_REG[0x281C>>1];
+       system_reg.DPC_HS_END=MEM_REG[0x281E>>1];
+       system_reg.DPC_VS_END=MEM_REG[0x2822>>1];
+       system_reg.DPC_DE=MEM_REG[0x2826>>1];
 }
 
 
 void cpuctrl_deinit(void)
 {
-       MEM_REG[0x91c>>1]=system_reg.SYSCSETREG;
        MEM_REG[0x910>>1]=system_reg.FPLLVSETREG;
+       MEM_REG[0x91c>>1]=system_reg.SYSCSETREG;
        MEM_REG[0x3B40>>1]=system_reg.DUALINT920;
        MEM_REG[0x3B42>>1]=system_reg.DUALINT940;
        MEM_REG[0x3B48>>1]=system_reg.DUALCTRL940;
        MEM_REG[0x904>>1]=system_reg.SYSCLKENREG;
-       MEM_REG[0x924>>1]=dispclockdiv;
        MEM_REG[0x3802>>1]=system_reg.MEMTIMEX0;
        MEM_REG[0x3804>>1]=system_reg.MEMTIMEX1 /*| 0x9000*/;
+       unset_LCD_custom_rate();
 }
 
 
@@ -94,7 +104,7 @@ void set_920_Div(unsigned short div)
 {
        unsigned short v;
        v = MEM_REG[0x91c>>1] & (~0x3);
-       MEM_REG[0x91c>>1] = (div & 0x7) | v; 
+       MEM_REG[0x91c>>1] = (div & 0x7) | v;
 }
 
 
@@ -102,7 +112,7 @@ void set_DCLK_Div( unsigned short div )
 {
        unsigned short v;
        v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6)) );
-       MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v; 
+       MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v;
 }
 
 /*
@@ -110,12 +120,102 @@ void Disable_940(void)
 {
        MEM_REG[0x3B42>>1];
        MEM_REG[0x3B42>>1]=0;
-       MEM_REG[0x3B46>>1]=0xffff;      
+       MEM_REG[0x3B46>>1]=0xffff;
        MEM_REG[0x3B48>>1]|= (1 << 7);
        MEM_REG[0x904>>1]&=0xfffe;
 }
 */
 
+
+typedef struct
+{
+       unsigned short reg, valmask, val;
+}
+reg_setting;
+
+// ~59.998, couldn't figure closer values
+static reg_setting rate_almost60[] =
+{
+       { 0x0914, 0xffff, (212<<8)|(2<<2)|1 },  /* UPLLSETVREG */
+       { 0x0924, 0xff00, (2<<14)|(36<<8) },    /* DISPCSETREG */
+       { 0x281A, 0x00ff, 1 },                  /* .HSWID(T2) */
+       { 0x281C, 0x00ff, 0 },                  /* .HSSTR(T8) */
+       { 0x281E, 0x00ff, 2 },                  /* .HSEND(T7) */
+       { 0x2822, 0x01ff, 12 },                 /* .VSEND (T9) */
+       { 0x2826, 0x0ff0, 34<<4 },              /* .DESTR(T3) */
+       { 0, 0, 0 }
+};
+
+// perfect 50Hz?
+static reg_setting rate_50[] =
+{
+       { 0x0914, 0xffff, (39<<8)|(0<<2)|2 },   /* UPLLSETVREG */
+       { 0x0924, 0xff00, (2<<14)|(7<<8) },     /* DISPCSETREG */
+       { 0x281A, 0x00ff, 31 },                 /* .HSWID(T2) */
+       { 0x281C, 0x00ff, 16 },                 /* .HSSTR(T8) */
+       { 0x281E, 0x00ff, 15 },                 /* .HSEND(T7) */
+       { 0x2822, 0x01ff, 15 },                 /* .VSEND (T9) */
+       { 0x2826, 0x0ff0, 37<<4 },              /* .DESTR(T3) */
+       { 0, 0, 0 }
+};
+
+// 16639/2 ~120.20
+static reg_setting rate_120_20[] =
+{
+       { 0x0914, 0xffff, (203<<8)|(2<<2)|1 },  /* UPLLSETVREG */
+       { 0x0924, 0xff00, (2<<14)|(14<<8) },    /* DISPCSETREG */
+       { 0x281A, 0x00ff, 29 },                 /* .HSWID(T2) */
+       { 0x281C, 0x00ff, 19 },                 /* .HSSTR(T8) */
+       { 0x281E, 0x00ff, 19 },                 /* .HSEND(T7) */
+       { 0x2822, 0x01ff, 11 },                 /* .VSEND (T9) */
+       { 0x2826, 0x0ff0, 37<<4 },              /* .DESTR(T3) */
+       { 0, 0, 0 }
+};
+
+// 19997/2 ~100.02
+static reg_setting rate_100_02[] =
+{
+       { 0x0914, 0xffff, (63<<8)|(1<<2)|1 },   /* UPLLSETVREG */
+       { 0x0924, 0xff00, (2<<14)|(7<<8) },     /* DISPCSETREG */
+       { 0x281A, 0x00ff, 29 },                 /* .HSWID(T2) */
+       { 0x281C, 0x00ff, 21 },                 /* .HSSTR(T8) */
+       { 0x281E, 0x00ff, 20 },                 /* .HSEND(T7) */
+       { 0x2822, 0x01ff, 12 },                 /* .VSEND (T9) */
+       { 0x2826, 0x0ff0, 37<<4 },              /* .DESTR(T3) */
+       { 0, 0, 0 }
+};
+
+
+
+static reg_setting *possible_rates[] = { rate_almost60, rate_50, rate_120_20, rate_100_02 };
+
+void set_LCD_custom_rate(lcd_rate_t rate)
+{
+       reg_setting *set;
+
+       printf("setting custom LCD refresh, mode=%i... ", rate); fflush(stdout);
+       for (set = possible_rates[rate]; set->reg; set++)
+       {
+               unsigned short val = MEM_REG[set->reg >> 1];
+               val &= ~set->valmask;
+               val |= set->val;
+               MEM_REG[set->reg >> 1] = val;
+       }
+       printf("done.\n");
+}
+
+void unset_LCD_custom_rate(void)
+{
+       printf("reset to prev LCD refresh.\n");
+       MEM_REG[0x914>>1]=system_reg.UPLLVSETREG;
+       MEM_REG[0x924>>1]=system_reg.DISPCSETREG;
+       MEM_REG[0x281A>>1]=system_reg.DPC_HS_WIDTH;
+       MEM_REG[0x281C>>1]=system_reg.DPC_HS_STR;
+       MEM_REG[0x281E>>1]=system_reg.DPC_HS_END;
+       MEM_REG[0x2822>>1]=system_reg.DPC_VS_END;
+       MEM_REG[0x2826>>1]=system_reg.DPC_DE;
+}
+
 void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD)
 {
        tRC -= 1; tRAS -= 1; tWR -= 1; tMRD -= 1; tRFC -= 1; tRP -= 1; tRCD -= 1; // ???
@@ -124,14 +224,6 @@ void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, in
 }
 
 
-/*
-void gp2x_video_wait_vsync(void)
-{
-       MEM_REG[0x2846>>1]=(MEM_REG[0x2846>>1] | 0x20) & ~2;
-       while(!(MEM_REG[0x2846>>1] & 2));
-}
-*/
-
 void set_gamma(int g100)
 {
        float gamma = (float) g100 / 100;
index 5b482a5..d537f4e 100644 (file)
@@ -9,8 +9,19 @@ extern void set_FCLK(unsigned MHZ); /* adjust the clock frequency (in Mhz units)
 extern void set_920_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
 extern void set_DCLK_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
 //extern void Disable_940(void); /* 940t down */
-//extern void gp2x_video_wait_vsync(void);
+
 extern void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD);
 extern void set_gamma(int g100);
 
+typedef enum
+{
+       LCDR_60 = 0,    /* as close as possible to 60.00Hz, currently only managed to set to ~59.998Hz, has interlacing problems */
+       LCDR_50,        /* 50Hz, has interlacing problems */
+       LCDR_120_20,    /* ~60.10*2Hz, used by FCE Ultra */
+       LCDR_100_02,    /* ~50.01*2Hz, used by FCE Ultra */
+} lcd_rate_t;
+
+extern void set_LCD_custom_rate(lcd_rate_t rate);
+extern void unset_LCD_custom_rate(void);
+
 #endif
index efbdab1..cb66b5c 100644 (file)
@@ -9,12 +9,13 @@ int InitSound(void);
 void WriteSound(int16 *Buffer, int Count);
 
 void KillSound(void);
-void SilenceSound(int s); /* DOS and SDL */
+void SilenceSound(int s);
 
 
 int InitVideo(void);
 void KillVideo(void);
-void BlitScreen(uint8 *buf);
+void BlitPrepare(int skip);
+void BlitScreen(int skip);
 void LockConsole(void);
 void UnlockConsole(void);
-void ToggleFS();               /* SDL */
+void ToggleFS();
index 198222d..d8524b6 100644 (file)
@@ -156,11 +156,11 @@ static INLINE void printFps(uint8 *screen)
 }
 
 
-void BlitScreen(uint8 *buf)
+void BlitPrepare(int skip)
 {
        framesEmulated++;
 
-       if (!buf) {
+       if (skip) {
                printFps(0);
                return;
        }
@@ -185,8 +185,18 @@ void BlitScreen(uint8 *buf)
                        memset32((int *)((char *)gp2x_screen + 32), 0, srendline*320*2/4);
        }
 
-       gp2x_video_flip();
-       XBuf = gp2x_screen;
+       /* at this point we should be done with the frame */
+       gp2x_video_flush_cache();
+}
+
+
+void BlitScreen(int skip)
+{
+       if (!skip)
+       {
+               gp2x_video_flip();
+               XBuf = gp2x_screen;
+       }
 }
 
 
index a4834b3..92103c0 100644 (file)
@@ -19,6 +19,8 @@ int GP2X_PORT_REV =
 #include "rev.h"
 ;
 
+extern uint8 PAL;
+
 int CLImain(int argc, char *argv[]);
 
 DSETTINGS Settings;
@@ -144,8 +146,8 @@ int main(int argc, char *argv[])
 
         ret = CLImain(argc,argv);
 
-        // unscale the screen, in case this is bad.
-        gp2x_video_RGB_setscaling(0, 320, 240);
+        // unscale the screen, in case it is bad.
+        gp2x_video_RGB_setscaling(320, 240);
 
        if (mmuhack_status > 0)
                mmuunhack();
@@ -175,9 +177,9 @@ void gp2x_opt_setup(void)
        }
 }
 
-void gp2x_cpuclock_gamma_update(void)
+void gp2x_opt_update(void)
 {
-       static int prev_cpuclock = 200, prev_gamma = 100;
+       static int prev_cpuclock = 200, prev_gamma = 100, prev_vsync = 0, prev_pal = 0;
        if (Settings.cpuclock != 0 && Settings.cpuclock != prev_cpuclock)
        {
                set_FCLK(Settings.cpuclock);
@@ -189,6 +191,20 @@ void gp2x_cpuclock_gamma_update(void)
                set_gamma(Settings.gamma);
                prev_gamma = Settings.gamma;
        }
+
+       if (Settings.perfect_vsync != prev_vsync || (Settings.perfect_vsync && prev_pal != PAL))
+       {
+               if (Settings.perfect_vsync)
+               {
+                       set_LCD_custom_rate(PAL ? LCDR_100_02 : LCDR_120_20);
+                       prev_pal = PAL;
+               }
+               else
+               {
+                       unset_LCD_custom_rate();
+               }
+               prev_vsync = Settings.perfect_vsync;
+       }
 }
 
 
index 3e31af3..20cadd5 100644 (file)
@@ -15,10 +15,11 @@ typedef struct {
        int mmuhack;
        int ramtimings;
        int gamma;
+       int perfect_vsync;
 } DSETTINGS;
 
 extern DSETTINGS Settings;
 
 void gp2x_opt_setup(void);
-void gp2x_cpuclock_gamma_update(void);
+void gp2x_opt_update(void);
 
index c2f88f6..34bae72 100644 (file)
@@ -22,8 +22,6 @@
 #include "../../video.h"
 #include "usbjoy.h"
 
-extern int FSkip;
-
 /* UsrInputType[] is user-specified.  InputType[] is current
        (game loading can override user settings)
 */
@@ -49,6 +47,13 @@ static void setsoundvol(int soundvolume)
 {
        int soundvolIndex;
        static char soundvolmeter[24];
+       static int prev_snd_on = 0;
+
+       if ((!!soundvolume) ^ prev_snd_on)
+       {
+               FCEUI_Sound(Settings.sound_rate);
+               prev_snd_on = !!soundvolume;
+       }
 
        // draw on screen :D
        gp2x_sound_volume(soundvolume, soundvolume);
@@ -194,10 +199,9 @@ static void FCEUD_UpdateInput(void)
        uint32 all_acts[2] = {0,0};
        int i;
 
-       if ((down(VOL_DOWN) && down(VOL_UP)) || (keys & (GP2X_L|GP2X_L|GP2X_START)) == (GP2X_L|GP2X_L|GP2X_START))
+       if ((down(VOL_DOWN) && down(VOL_UP)) || (keys & (GP2X_L|GP2X_START)) == (GP2X_L|GP2X_START))
        {
                Exit = 1;
-               FSkip = 0;      /* force rendering the last frame for menu */
                return;
        }
        else if (down(VOL_UP))
index ac48a2d..5926da7 100644 (file)
@@ -49,6 +49,7 @@ void CleanSurface(void);
 // internals
 extern char lastLoadedGameName[2048];
 extern uint8 Exit; // exit emu loop flag
+extern int FSkip;
 void CloseGame(void);
 
 FCEUGI *fceugi = NULL;
@@ -166,7 +167,7 @@ static void LoadLLGN(void)
 static void SaveLLGN(void)
 {
  // save last loaded game name
- if (lastLoadedGameName[0])
+ if (lastLoadedGameName[0] && !(eoptions&EO_NOAUTOWRITE))
  {
   char tdir[2048];
   FILE *f;
@@ -256,6 +257,7 @@ static int DoArgs(int argc, char *argv[])
         {"-nofs",0,&eoptions,0x8000|EO_NOFOURSCORE},
          {"-clipsides",0,&eoptions,0x8000|EO_CLIPSIDES},
         {"-nothrottle",0,&eoptions,0x8000|EO_NOTHROTTLE},
+        {"-noautowrite",0,&eoptions,0x8000|EO_NOAUTOWRITE},
          {"-slstart",0,&srendlinev[0],0},{"-slend",0,&erendlinev[0],0},
          {"-slstartp",0,&srendlinev[1],0},{"-slendp",0,&erendlinev[1],0},
         {0,(void *)DriverArgs,0,0},
@@ -286,7 +288,7 @@ static int DoArgs(int argc, char *argv[])
        }
 
         FCEUI_SetRenderedLines(srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]);
-        FCEUI_SetSoundVolume(soundvol);
+        FCEUI_SetSoundVolume(80);
        DoDriverArgs();
 
        if(fcexp)
@@ -353,7 +355,6 @@ int CLImain(int argc, char *argv[])
         LoadConfig(NULL);
         last_arg_parsed=DoArgs(argc-1,&argv[1]);
        gp2x_opt_setup();
-       gp2x_cpuclock_gamma_update();
        LoadLLGN();
        FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);
        if(cpalette)
@@ -417,18 +418,19 @@ int CLImain(int argc, char *argv[])
          }
          }
 
+        gp2x_opt_update();
         PrepareOtherInput();
-        RefreshThrottleFPS();
         FCEUI_GetCurrentVidSystem(&srendline,&erendline);
         gp2x_video_changemode(Settings.scaling == 3 ? 15 : 8);
         switch (Settings.scaling & 3) {
-                case 0: gp2x_video_set_offs(0);  gp2x_video_RGB_setscaling(0, 320, 240); break;
-                case 1: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(0, 256, 240); break;
-                case 2: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(srendline, 256, erendline-srendline); break;
-                case 3: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(0, 320, 240); break;
+                case 0: gp2x_video_set_offs(0);  gp2x_video_RGB_setscaling(320, 240); break;
+                case 1: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(256, 240); break;
+                case 2: gp2x_video_set_offs(32+srendline*320); gp2x_video_RGB_setscaling(256, erendline-srendline); break;
+                case 3: gp2x_video_set_offs(32); gp2x_video_RGB_setscaling(320, 240); break;
         }
         CleanSurface();
         gp2x_start_sound(Settings.sound_rate, 16, 0);
+        RefreshThrottleFPS();
         FCEUI_Emulate();
        }
 
@@ -466,13 +468,16 @@ static void DriverKill(void)
 
 void FCEUD_Update(uint8 *xbuf, int16 *Buffer, int Count)
 {
+ FCEUD_UpdateInput();  // must update input before blitting because of save confirmation stuff
+ BlitPrepare(xbuf == NULL);
  if(!(eoptions&EO_NOTHROTTLE))
  {
   if(Count)
    WriteSound(Buffer,Count);
   SpeedThrottle();
  }
- FCEUD_UpdateInput();  // must update input before blitting because of save confirmation stuff
- BlitScreen(xbuf);
+ BlitScreen(xbuf == NULL);
+ // make sure last frame won't get skipped, because we need it for menu bg
+ if (Exit) FSkip=0;
 }
 
index be5ae19..79cc231 100644 (file)
@@ -27,6 +27,7 @@ extern int eoptions;
 #define EO_NOFOURSCORE 32
 #define EO_NOTHROTTLE  64
 #define EO_GG          128
+#define EO_NOAUTOWRITE 256
 extern int srendline,erendline,srendlinev[2],erendlinev[2];
 extern int NoWaiting;
 
index 6abe009..11cca13 100644 (file)
@@ -48,7 +48,13 @@ static int txt_xmin, txt_xmax, txt_ymin, txt_ymax;
 \r
 char menuErrorMsg[40] = {0, };\r
 \r
-static void gp2x_fceu_darken_reset(void)\r
+static void menu_flip(void)\r
+{\r
+       gp2x_video_flush_cache();\r
+       gp2x_video_flip();\r
+}\r
+\r
+static void menu_darken_reset(void)\r
 {\r
        txt_xmin = 320; txt_xmax = 0;\r
        txt_ymin = 240; txt_ymax = 0;\r
@@ -59,10 +65,10 @@ static void gp2x_fceu_copy_bg(void)
        if (menu_bg)\r
             memcpy(gp2x_screen, menu_bg, 320*240*2);\r
        else memset(gp2x_screen, 0, 320*240*2);\r
-       gp2x_fceu_darken_reset();\r
+       menu_darken_reset();\r
 }\r
 \r
-static void gp2x_fceu_darken_text_bg(void)\r
+static void menu_darken_text_bg(void)\r
 {\r
        int x, y, xmin, xmax, ymax;\r
        unsigned short *screen = gp2x_screen;\r
@@ -317,7 +323,7 @@ static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)
                }\r
        }\r
        gp2x_text_out15(5, 120, ">");\r
-       gp2x_video_flip();\r
+       menu_flip();\r
 }\r
 \r
 static int scandir_cmp(const void *p1, const void *p2)\r
@@ -506,7 +512,7 @@ static void draw_patchlist(int sel)
        if (pos < 24) gp2x_smalltext16_lim(14, pos*10, "done", 4);\r
 \r
        gp2x_text_out15(5, 120, ">");\r
-       gp2x_video_flip();\r
+       menu_flip();\r
 }\r
 \r
 void patches_menu_loop(void)\r
@@ -631,7 +637,7 @@ static void draw_savestate_menu(int menu_sel, int is_loading)
        // draw cursor\r
        gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
 \r
-       gp2x_video_flip();\r
+       menu_flip();\r
 }\r
 \r
 static int savestate_menu_loop(int is_loading)\r
@@ -768,8 +774,8 @@ static void draw_key_config(const bind_action_t *opts, int opt_cnt, int player_i
        // draw cursor\r
        gp2x_text_out15(x - 16, tl_y + sel*10, ">");\r
 \r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_fceu_darken_reset();\r
+       menu_darken_text_bg();\r
+       menu_darken_reset();\r
 \r
        if (sel < opt_cnt) {\r
                gp2x_text_out15(30, 190, "Press a button to bind/unbind");\r
@@ -781,8 +787,8 @@ static void draw_key_config(const bind_action_t *opts, int opt_cnt, int player_i
                gp2x_text_out15(30, 210, "to save controls");\r
                gp2x_text_out15(30, 220, "Press B or X to exit");\r
        }\r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_video_flip();\r
+       menu_darken_text_bg();\r
+       menu_flip();\r
 }\r
 \r
 static void key_config_loop(const bind_action_t *opts, int opt_cnt, int player_idx)\r
@@ -861,8 +867,8 @@ static void draw_kc_sel(int menu_sel)
                gp2x_text_out15(tl_x, (y+=10), "none");\r
        }\r
 \r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_video_flip();\r
+       menu_darken_text_bg();\r
+       menu_flip();\r
 }\r
 \r
 // b_turbo,a_turbo  RLDU SEBA\r
@@ -969,15 +975,15 @@ static void draw_fcemenu_options(int menu_sel)
        gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
 \r
        if (menu_sel == 0) {\r
-               gp2x_fceu_darken_text_bg();\r
-               gp2x_fceu_darken_reset();\r
+               menu_darken_text_bg();\r
+               menu_darken_reset();\r
 \r
                gp2x_text_out15(30, 210, "Press B to browse,");\r
                gp2x_text_out15(30, 220, "START to use default");\r
        }\r
 \r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_video_flip();\r
+       menu_darken_text_bg();\r
+       menu_flip();\r
 }\r
 \r
 static void fcemenu_loop_options(void)\r
@@ -1088,17 +1094,18 @@ static void draw_menu_options(int menu_sel)
        gp2x_text_out15(tl_x, (y+=10), "Faster RAM timings         %s", Settings.ramtimings?"ON":"OFF");\r
        gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s",   mms, Settings.mmuhack?"ON":"OFF");   // 10\r
        gp2x_text_out15(tl_x, (y+=10), "Gamma correction           %i.%02i", Settings.gamma / 100, Settings.gamma%100);\r
-       gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock             %iMhz", Settings.cpuclock);          // 12\r
+       gp2x_text_out15(tl_x, (y+=10), "Perfect VSYNC              %s", Settings.perfect_vsync?"ON":"OFF");\r
+       gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock             %iMhz", Settings.cpuclock);          // 13\r
        gp2x_text_out15(tl_x, (y+=10), "[FCE Ultra options]");\r
-       gp2x_text_out15(tl_x, (y+=10), "Save cfg as default");\r
+       gp2x_text_out15(tl_x, (y+=10), "Save cfg as default");                                          // 15\r
        if (fceugi)\r
                gp2x_text_out15(tl_x, (y+=10), "Save cfg for current game only");\r
 \r
        // draw cursor\r
        gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
 \r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_video_flip();\r
+       menu_darken_text_bg();\r
+       menu_flip();\r
 }\r
 \r
 static int sndrate_prevnext(int rate, int dir)\r
@@ -1116,7 +1123,6 @@ static int sndrate_prevnext(int rate, int dir)
 \r
 static void config_commit(void)\r
 {\r
-       gp2x_cpuclock_gamma_update();\r
        if (Settings.region_force)\r
                FCEUI_SetVidSystem(Settings.region_force - 1);\r
 }\r
@@ -1124,7 +1130,7 @@ static void config_commit(void)
 static int menu_loop_options(void)\r
 {\r
        static int menu_sel = 0;\r
-       int menu_sel_max = 14;\r
+       int menu_sel_max = 15;\r
        unsigned long inp = 0;\r
 \r
        if (fceugi) menu_sel_max++;\r
@@ -1138,15 +1144,16 @@ static int menu_loop_options(void)
                if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
                        switch (menu_sel) {\r
                                case  1: Settings.showfps    = !Settings.showfps; break;\r
-                               case  3: soundvol = soundvol ? 0 : 100; break;\r
+                               case  3: soundvol = soundvol ? 0 : 50; break;\r
                                case  9: Settings.ramtimings = !Settings.ramtimings; break;\r
                                case 10: Settings.mmuhack    = !Settings.mmuhack; break;\r
-                               case 13: fcemenu_loop_options(); break;\r
-                               case 14: // done (update and write)\r
+                               case 12: Settings.perfect_vsync = !Settings.perfect_vsync; break;\r
+                               case 14: fcemenu_loop_options(); break;\r
+                               case 15: // done (update and write)\r
                                        config_commit();\r
                                        SaveConfig(NULL);\r
                                        return 1;\r
-                               case 15: // done (update and write for current game)\r
+                               case 16: // done (update and write for current game)\r
                                        config_commit();\r
                                        if (lastLoadedGameName[0])\r
                                                SaveConfig(lastLoadedGameName);\r
@@ -1175,7 +1182,7 @@ static int menu_loop_options(void)
                                case  7: int_incdec(&Settings.sstate_confirm, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break;\r
                                case  8: int_incdec(&CurrentState,            (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break;\r
                                case 11: int_incdec(&Settings.gamma,          (inp & GP2X_LEFT) ? -1 : 1, 0, 300); break;\r
-                               case 12:\r
+                               case 13:\r
                                        while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
                                                Settings.cpuclock += (inp & GP2X_LEFT) ? -1 : 1;\r
                                                if (Settings.cpuclock < 0) Settings.cpuclock = 0; // 0 ~ do not change\r
@@ -1213,8 +1220,8 @@ static void draw_menu_credits(void)
        gp2x_text_out15(20, 180, "  cpuctrl, gamma libs");\r
        gp2x_text_out15(20, 190, "Squidge: squidgehack");\r
 \r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_video_flip();\r
+       menu_darken_text_bg();\r
+       menu_flip();\r
 }\r
 \r
 \r
@@ -1246,8 +1253,8 @@ static void draw_menu_root(int menu_sel)
        // draw cursor\r
        gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
 \r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_fceu_darken_reset();\r
+       menu_darken_text_bg();\r
+       menu_darken_reset();\r
 \r
        // error / version\r
        if (menuErrorMsg[0]) gp2x_text_out15(1, 229, menuErrorMsg);\r
@@ -1256,8 +1263,8 @@ static void draw_menu_root(int menu_sel)
                sprintf(vstr, "v" GP2X_PORT_VERSION " r%i", GP2X_PORT_REV);\r
                gp2x_text_out15(320-strlen(vstr)*8-1, 228, vstr);\r
        }\r
-       gp2x_fceu_darken_text_bg();\r
-       gp2x_video_flip();\r
+       menu_darken_text_bg();\r
+       menu_flip();\r
 }\r
 \r
 \r
@@ -1409,8 +1416,8 @@ static void menu_gfx_prepare(void)
        // switch bpp\r
        gp2x_video_changemode(16);\r
        gp2x_video_set_offs(0);\r
-       gp2x_video_RGB_setscaling(0, 320, 240);\r
-       gp2x_video_flip();\r
+       gp2x_video_RGB_setscaling(320, 240);\r
+       menu_flip();\r
 }\r
 \r
 \r
index 86bfdfb..34f5ea7 100644 (file)
@@ -54,7 +54,6 @@ void *gp2x_screen;
 #define FRAMEBUFF_ADDR3 (FRAMEBUFF_ADDR2+0x30000)\r
 \r
 static const int gp2x_screenaddrs[4] = { FRAMEBUFF_ADDR0, FRAMEBUFF_ADDR1, FRAMEBUFF_ADDR2, FRAMEBUFF_ADDR3 };\r
-static int gp2x_screenaddrs_use[4];\r
 static unsigned short gp2x_screenaddr_old[4];\r
 \r
 \r
@@ -62,15 +61,10 @@ static unsigned short gp2x_screenaddr_old[4];
 void gp2x_video_flip(void)\r
 {\r
        unsigned short lsw, msw;\r
-       int addr = gp2x_screenaddrs_use[screensel&3];\r
+       int addr = gp2x_screenaddrs[screensel&3];\r
 \r
        addr += gp2x_screen_offs;\r
 \r
-       // since we are using the mmu hack, we must flush the cache first\r
-       // (the params are most likely wrong, but they seem to work somehow)\r
-       //flushcache(addr, addr + 320*240*2, 0);\r
-       flushcache(gp2x_screen, (char *)gp2x_screen + 320*240*2, 0);\r
-\r
        lsw = (unsigned short) addr;\r
        msw = (unsigned short)(addr >> 16);\r
 \r
@@ -86,7 +80,7 @@ void gp2x_video_flip(void)
 /* doulblebuffered flip */\r
 void gp2x_video_flip2(void)\r
 {\r
-       unsigned short msw = (unsigned short)(gp2x_screenaddrs_use[screensel&1] >> 16);\r
+       unsigned short msw = (unsigned short)(gp2x_screenaddrs[screensel&1] >> 16);\r
 \r
        gp2x_memregs[0x2910>>1] = msw;\r
        gp2x_memregs[0x2914>>1] = msw;\r
@@ -126,18 +120,12 @@ void gp2x_video_setpalette(int *pal, int len)
 \r
 \r
 // TV Compatible function //\r
-void gp2x_video_RGB_setscaling(int ln_offs, int W, int H)\r
+void gp2x_video_RGB_setscaling(int W, int H)\r
 {\r
        float escalaw, escalah;\r
        int bpp = (gp2x_memregs[0x28DA>>1]>>9)&0x3;\r
        unsigned short scalw;\r
 \r
-       // set offset\r
-       gp2x_screenaddrs_use[0] = gp2x_screenaddrs[0] + ln_offs * 320 * bpp;\r
-       gp2x_screenaddrs_use[1] = gp2x_screenaddrs[1] + ln_offs * 320 * bpp;\r
-       gp2x_screenaddrs_use[2] = gp2x_screenaddrs[2] + ln_offs * 320 * bpp;\r
-       gp2x_screenaddrs_use[3] = gp2x_screenaddrs[3] + ln_offs * 320 * bpp;\r
-\r
        escalaw = 1024.0; // RGB Horiz LCD\r
        escalah = 320.0; // RGB Vert LCD\r
 \r
@@ -164,6 +152,20 @@ void gp2x_video_set_offs(int offs)
        gp2x_screen_offs = offs;\r
 }\r
 \r
+void gp2x_video_wait_vsync(void)\r
+{\r
+       unsigned short v = gp2x_memregs[0x1182>>1];\r
+       while (!((v ^ gp2x_memregs[0x1182>>1]) & 0x10));\r
+}\r
+\r
+void gp2x_video_flush_cache(void)\r
+{\r
+       // since we are using the mmu hack, we must flush the cache first\r
+       // (the params are most likely wrong, but they seem to work somehow)\r
+       //flushcache(addr, addr + 320*240*2, 0);\r
+       flushcache(gp2x_screen, (char *)gp2x_screen + 320*240*2, 0);\r
+}\r
+\r
 void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len)\r
 {\r
        if (buffers & (1<<0)) memcpy((char *)gp2x_screens[0] + offset, data, len);\r
@@ -301,7 +303,6 @@ void gp2x_init(void)
        gp2x_screenaddr_old[2] = gp2x_memregs[0x2912>>1];\r
        gp2x_screenaddr_old[3] = gp2x_memregs[0x2914>>1];\r
 \r
-       memcpy(gp2x_screenaddrs_use, gp2x_screenaddrs, sizeof(gp2x_screenaddrs));\r
        gp2x_memset_all_buffers(0, 0, 320*240*2);\r
 \r
        // snd\r
index 3b01cad..e2a29f5 100644 (file)
@@ -11,8 +11,10 @@ void gp2x_video_flip(void);
 void gp2x_video_changemode(int bpp);\r
 void gp2x_video_changemode2(int bpp);\r
 void gp2x_video_setpalette(int *pal, int len);\r
-void gp2x_video_RGB_setscaling(int ln_offs, int W, int H);\r
+void gp2x_video_RGB_setscaling(int W, int H);\r
 void gp2x_video_set_offs(int offs);\r
+void gp2x_video_wait_vsync(void);\r
+void gp2x_video_flush_cache(void);\r
 void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len);\r
 void gp2x_memcpy_all_buffers(void *data, int offset, int len);\r
 void gp2x_memset_all_buffers(int offset, int byte, int len);\r
index c52eb68..fdfc0eb 100644 (file)
@@ -1,38 +1,68 @@
 #include <sys/time.h>
 #include "main.h"
 #include "gp2x.h"
+#include "minimal.h"
 #include "throttle.h"
 
 
 extern uint8 PAL;
 extern int FSkip;
-static int usec_aim = 0, usec_done = 0;
 static int skip_count = 0;
+static struct timeval tv_prev;
 
 void RefreshThrottleFPS(void)
 {
-       usec_aim = usec_done = skip_count = 0;
+       skip_count = 0;
+       if (Settings.perfect_vsync)
+       {
+               gp2x_video_wait_vsync();
+       }
+       gettimeofday(&tv_prev, 0);
 }
 
-void SpeedThrottle(void)
+#define tvdiff(tv1, tv2) \
+       ((tv1.tv_sec - tv2.tv_sec) * 1000000 + tv1.tv_usec - tv2.tv_usec)
+
+#define tvadd(tv, usec) { \
+       tv.tv_usec += usec; \
+       if (tv.tv_usec >= 1000000) { \
+               tv.tv_sec += 1; \
+               tv.tv_usec -= 1000000; \
+       } \
+}
+
+#define tvsub(tv, usec) { \
+       tv.tv_usec -= usec; \
+       if (tv.tv_usec < 0) { \
+               tv.tv_sec -= 1; \
+               tv.tv_usec += 1000000; \
+       } \
+}
+
+static void wait_to(struct timeval *tv_aim)
 {
-       static struct timeval tv_prev;
        struct timeval tv_now;
-       int delta_nom = PAL ? 19997 : 16639; // ~50.007, 19.997 ms/frame : ~60.1, 16.639 ms/frame
+       int diff;
 
-
-       if (usec_done == 0) { // first time
-               usec_done = 1;
-               gettimeofday(&tv_prev, 0);
-               return;
+       do
+       {
+               gettimeofday(&tv_now, 0);
+               diff = tvdiff((*tv_aim), tv_now);
        }
+       while (diff > 0);
+}
 
-       gettimeofday(&tv_now, 0);
+#include <stdio.h>
+void SpeedThrottle(void)
+{
+       struct timeval tv_now, tv_aim;
+       int tdiff;
+
+       tv_aim = tv_prev;
+       tvadd(tv_aim, PAL ? 19997 : 16639); // ~50.007, 19.997 ms/frame : ~60.1, 16.639 ms/frame
 
-       usec_aim += delta_nom;
-       if (tv_now.tv_sec != tv_prev.tv_sec)
-               usec_done += 1000000;
-       usec_done += tv_now.tv_usec - tv_prev.tv_usec;
+       gettimeofday(&tv_now, 0);
+       tdiff = tvdiff(tv_now, tv_aim);
 
 #ifdef FRAMESKIP
        if (Settings.frameskip >= 0)
@@ -44,29 +74,40 @@ void SpeedThrottle(void)
                        FSkip = 1;
                }
        }
-       else if (usec_done > usec_aim + 1024*4)
+       else if (tdiff > 0)
        {
                /* auto frameskip */
-               if (usec_done - usec_aim > 1024*32)
-                       usec_done = usec_aim = 1; // too much behind, try to recover..
-               else
-                       FSkip = 1;
                tv_prev = tv_now;
+               if (tdiff < 1024*16)    // limit frameskip
+               {
+                       FSkip = 1;
+                       tvsub(tv_prev, tdiff);
+               }
                return;
        }
 #endif
 
-       tv_prev = tv_now;
-       while (usec_done < usec_aim)
+       /* throttle */
+       if (tdiff < 0)
        {
-               gettimeofday(&tv_now, 0);
-
-               if (tv_now.tv_sec != tv_prev.tv_sec)
-                       usec_done += 1000000;
-               usec_done += tv_now.tv_usec - tv_prev.tv_usec;
-               tv_prev = tv_now;
+               if (Settings.perfect_vsync)
+               {
+                       if (tdiff <= (PAL ? 19997/2 : 16639/2))
+                       {
+                               struct timeval tv_tmp = tv_aim;
+                               tvsub(tv_tmp, 5000);
+                               wait_to(&tv_tmp);
+                       }
+                       gp2x_video_wait_vsync();
+                       gettimeofday(&tv_prev, 0);
+                       return;
+               }
+               else
+               {
+                       wait_to(&tv_aim);
+               }
        }
-       usec_done = usec_done - usec_aim + 1; // reset to prevent overflows
-       usec_aim = 0;
+
+       tv_prev = tv_aim;
 }
 
index f753a80..d2a8982 100644 (file)
@@ -84,7 +84,7 @@ void gp2x_video_setpalette(int *pal, int len)
 }
 
 
-void gp2x_video_RGB_setscaling(int ln_offs, int W, int H)
+void gp2x_video_RGB_setscaling(int W, int H)
 {
 }
 
index ab085ee..94a7e22 100644 (file)
@@ -181,6 +181,9 @@ ver 0.4 (by notaz)
           - Fixed an issue of MapIRQHook getting lost after loading a savestate\r
             (glitched Akumajou Densetsu and other games after savestate load).\r
           - A bug, which prevented configuring multiple USB pads fixed.\r
+          - Fixed sound breaking bug after switching it on/off multiple times.\r
+          - Added "Perfect VSYNC" option, which changes GP2X refresh rate and\r
+            syncs emu timing to LCD vsync.\r
   rev 153\r
           - Lots of work on the asm core. Timing fixed for some instructions.\r
             Some missing undocumented instruction handlers added. Lots of\r
diff --git a/sound.c b/sound.c
index 370664b..bb3c89d 100644 (file)
--- a/sound.c
+++ b/sound.c
@@ -873,22 +873,23 @@ int32 highp;                   // 0 through 65536, 0 = no high pass, 65536 = max
 
 int32 lowp;                    // 0 through 65536, 65536 = max low pass(total attenuation)
                                // 65536 = no low pass
+static int32 flt_acc=0, flt_acc2=0;
+
 static void FilterSound(uint32 *in, int16 *outMono, int count)
 {
- static int32 acc=0, acc2=0;
 // static int min=0, max=0;
 
  for(;count;count--,in++,outMono++)
  {
   int32 diff;
 
-  diff = *in - acc;
+  diff = *in - flt_acc;
 
-  acc += (diff*highp)>>16;
-  acc2+= (int32) (((int64)((diff-acc2)*lowp))>>16);
+  flt_acc += (diff*highp)>>16;
+  flt_acc2+= (int32) (((int64)((diff-flt_acc2)*lowp))>>16);
   *in=0;
 
-  *outMono = acc2*7 >> 2; // * 1.75
+  *outMono = flt_acc2*7 >> 2; // * 1.75
 //  if (acc2 < min) { printf("min: %i %04x\n", acc2, acc2); min = acc2; }
 //  if (acc2 > max) { printf("max: %i %04x\n", acc2, acc2); max = acc2; }
  }
@@ -1016,6 +1017,8 @@ void SetSoundVariables(void)
 
   if(highp>(1<<16)) highp=1<<16;
   if(lowp>(1<<16)) lowp=1<<16;
+
+  flt_acc=flt_acc2=0;
 }
 
 void FixOldSaveStateSFreq(void)