From 7b356ee3dc5d7e54d9dc06c413f84380d1044441 Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 10 Jun 2007 18:08:15 +0000 Subject: [PATCH] perfect vsync, bugfixes git-svn-id: file:///home/notaz/opt/svn/fceu@160 be3aeb3a-fb24-0410-a615-afba39da0efa --- Makefile.gp2x | 2 +- drivers/gp2x/cpuctrl.c | 136 ++++++++++++++++++++++++++++++------ drivers/gp2x/cpuctrl.h | 13 +++- drivers/gp2x/dface.h | 7 +- drivers/gp2x/gp2x-video.c | 18 +++-- drivers/gp2x/gp2x.c | 24 +++++-- drivers/gp2x/gp2x.h | 3 +- drivers/gp2x/input.c | 12 ++-- drivers/gp2x/main.c | 25 ++++--- drivers/gp2x/main.h | 1 + drivers/gp2x/menu.c | 77 ++++++++++---------- drivers/gp2x/minimal.c | 33 ++++----- drivers/gp2x/minimal.h | 4 +- drivers/gp2x/throttle.c | 101 ++++++++++++++++++-------- drivers/gp2x_test/minimal.c | 2 +- out_gp2x/readme.txt | 3 + sound.c | 13 ++-- 17 files changed, 336 insertions(+), 138 deletions(-) diff --git a/Makefile.gp2x b/Makefile.gp2x index eb80b17..05908ae 100644 --- a/Makefile.gp2x +++ b/Makefile.gp2x @@ -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)),) diff --git a/drivers/gp2x/cpuctrl.c b/drivers/gp2x/cpuctrl.c index 7bbdb67..b75cc66 100644 --- a/drivers/gp2x/cpuctrl.c +++ b/drivers/gp2x/cpuctrl.c @@ -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 @@ -20,52 +20,62 @@ */ -#include +#include #include #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; diff --git a/drivers/gp2x/cpuctrl.h b/drivers/gp2x/cpuctrl.h index 5b482a5..d537f4e 100644 --- a/drivers/gp2x/cpuctrl.h +++ b/drivers/gp2x/cpuctrl.h @@ -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 diff --git a/drivers/gp2x/dface.h b/drivers/gp2x/dface.h index efbdab1..cb66b5c 100644 --- a/drivers/gp2x/dface.h +++ b/drivers/gp2x/dface.h @@ -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(); diff --git a/drivers/gp2x/gp2x-video.c b/drivers/gp2x/gp2x-video.c index 198222d..d8524b6 100644 --- a/drivers/gp2x/gp2x-video.c +++ b/drivers/gp2x/gp2x-video.c @@ -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; + } } diff --git a/drivers/gp2x/gp2x.c b/drivers/gp2x/gp2x.c index a4834b3..92103c0 100644 --- a/drivers/gp2x/gp2x.c +++ b/drivers/gp2x/gp2x.c @@ -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; + } } diff --git a/drivers/gp2x/gp2x.h b/drivers/gp2x/gp2x.h index 3e31af3..20cadd5 100644 --- a/drivers/gp2x/gp2x.h +++ b/drivers/gp2x/gp2x.h @@ -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); diff --git a/drivers/gp2x/input.c b/drivers/gp2x/input.c index c2f88f6..34bae72 100644 --- a/drivers/gp2x/input.c +++ b/drivers/gp2x/input.c @@ -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)) diff --git a/drivers/gp2x/main.c b/drivers/gp2x/main.c index ac48a2d..5926da7 100644 --- a/drivers/gp2x/main.c +++ b/drivers/gp2x/main.c @@ -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; } diff --git a/drivers/gp2x/main.h b/drivers/gp2x/main.h index be5ae19..79cc231 100644 --- a/drivers/gp2x/main.h +++ b/drivers/gp2x/main.h @@ -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; diff --git a/drivers/gp2x/menu.c b/drivers/gp2x/menu.c index 6abe009..11cca13 100644 --- a/drivers/gp2x/menu.c +++ b/drivers/gp2x/menu.c @@ -48,7 +48,13 @@ static int txt_xmin, txt_xmax, txt_ymin, txt_ymax; char menuErrorMsg[40] = {0, }; -static void gp2x_fceu_darken_reset(void) +static void menu_flip(void) +{ + gp2x_video_flush_cache(); + gp2x_video_flip(); +} + +static void menu_darken_reset(void) { txt_xmin = 320; txt_xmax = 0; txt_ymin = 240; txt_ymax = 0; @@ -59,10 +65,10 @@ static void gp2x_fceu_copy_bg(void) if (menu_bg) memcpy(gp2x_screen, menu_bg, 320*240*2); else memset(gp2x_screen, 0, 320*240*2); - gp2x_fceu_darken_reset(); + menu_darken_reset(); } -static void gp2x_fceu_darken_text_bg(void) +static void menu_darken_text_bg(void) { int x, y, xmin, xmax, ymax; unsigned short *screen = gp2x_screen; @@ -317,7 +323,7 @@ static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel) } } gp2x_text_out15(5, 120, ">"); - gp2x_video_flip(); + menu_flip(); } static int scandir_cmp(const void *p1, const void *p2) @@ -506,7 +512,7 @@ static void draw_patchlist(int sel) if (pos < 24) gp2x_smalltext16_lim(14, pos*10, "done", 4); gp2x_text_out15(5, 120, ">"); - gp2x_video_flip(); + menu_flip(); } void patches_menu_loop(void) @@ -631,7 +637,7 @@ static void draw_savestate_menu(int menu_sel, int is_loading) // draw cursor gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">"); - gp2x_video_flip(); + menu_flip(); } static int savestate_menu_loop(int is_loading) @@ -768,8 +774,8 @@ static void draw_key_config(const bind_action_t *opts, int opt_cnt, int player_i // draw cursor gp2x_text_out15(x - 16, tl_y + sel*10, ">"); - gp2x_fceu_darken_text_bg(); - gp2x_fceu_darken_reset(); + menu_darken_text_bg(); + menu_darken_reset(); if (sel < opt_cnt) { gp2x_text_out15(30, 190, "Press a button to bind/unbind"); @@ -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"); gp2x_text_out15(30, 220, "Press B or X to exit"); } - gp2x_fceu_darken_text_bg(); - gp2x_video_flip(); + menu_darken_text_bg(); + menu_flip(); } static void key_config_loop(const bind_action_t *opts, int opt_cnt, int player_idx) @@ -861,8 +867,8 @@ static void draw_kc_sel(int menu_sel) gp2x_text_out15(tl_x, (y+=10), "none"); } - gp2x_fceu_darken_text_bg(); - gp2x_video_flip(); + menu_darken_text_bg(); + menu_flip(); } // b_turbo,a_turbo RLDU SEBA @@ -969,15 +975,15 @@ static void draw_fcemenu_options(int menu_sel) gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">"); if (menu_sel == 0) { - gp2x_fceu_darken_text_bg(); - gp2x_fceu_darken_reset(); + menu_darken_text_bg(); + menu_darken_reset(); gp2x_text_out15(30, 210, "Press B to browse,"); gp2x_text_out15(30, 220, "START to use default"); } - gp2x_fceu_darken_text_bg(); - gp2x_video_flip(); + menu_darken_text_bg(); + menu_flip(); } static void fcemenu_loop_options(void) @@ -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"); gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s", mms, Settings.mmuhack?"ON":"OFF"); // 10 gp2x_text_out15(tl_x, (y+=10), "Gamma correction %i.%02i", Settings.gamma / 100, Settings.gamma%100); - gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock %iMhz", Settings.cpuclock); // 12 + gp2x_text_out15(tl_x, (y+=10), "Perfect VSYNC %s", Settings.perfect_vsync?"ON":"OFF"); + gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock %iMhz", Settings.cpuclock); // 13 gp2x_text_out15(tl_x, (y+=10), "[FCE Ultra options]"); - gp2x_text_out15(tl_x, (y+=10), "Save cfg as default"); + gp2x_text_out15(tl_x, (y+=10), "Save cfg as default"); // 15 if (fceugi) gp2x_text_out15(tl_x, (y+=10), "Save cfg for current game only"); // draw cursor gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">"); - gp2x_fceu_darken_text_bg(); - gp2x_video_flip(); + menu_darken_text_bg(); + menu_flip(); } static int sndrate_prevnext(int rate, int dir) @@ -1116,7 +1123,6 @@ static int sndrate_prevnext(int rate, int dir) static void config_commit(void) { - gp2x_cpuclock_gamma_update(); if (Settings.region_force) FCEUI_SetVidSystem(Settings.region_force - 1); } @@ -1124,7 +1130,7 @@ static void config_commit(void) static int menu_loop_options(void) { static int menu_sel = 0; - int menu_sel_max = 14; + int menu_sel_max = 15; unsigned long inp = 0; if (fceugi) menu_sel_max++; @@ -1138,15 +1144,16 @@ static int menu_loop_options(void) if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options switch (menu_sel) { case 1: Settings.showfps = !Settings.showfps; break; - case 3: soundvol = soundvol ? 0 : 100; break; + case 3: soundvol = soundvol ? 0 : 50; break; case 9: Settings.ramtimings = !Settings.ramtimings; break; case 10: Settings.mmuhack = !Settings.mmuhack; break; - case 13: fcemenu_loop_options(); break; - case 14: // done (update and write) + case 12: Settings.perfect_vsync = !Settings.perfect_vsync; break; + case 14: fcemenu_loop_options(); break; + case 15: // done (update and write) config_commit(); SaveConfig(NULL); return 1; - case 15: // done (update and write for current game) + case 16: // done (update and write for current game) config_commit(); if (lastLoadedGameName[0]) SaveConfig(lastLoadedGameName); @@ -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; case 8: int_incdec(&CurrentState, (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break; case 11: int_incdec(&Settings.gamma, (inp & GP2X_LEFT) ? -1 : 1, 0, 300); break; - case 12: + case 13: while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) { Settings.cpuclock += (inp & GP2X_LEFT) ? -1 : 1; if (Settings.cpuclock < 0) Settings.cpuclock = 0; // 0 ~ do not change @@ -1213,8 +1220,8 @@ static void draw_menu_credits(void) gp2x_text_out15(20, 180, " cpuctrl, gamma libs"); gp2x_text_out15(20, 190, "Squidge: squidgehack"); - gp2x_fceu_darken_text_bg(); - gp2x_video_flip(); + menu_darken_text_bg(); + menu_flip(); } @@ -1246,8 +1253,8 @@ static void draw_menu_root(int menu_sel) // draw cursor gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">"); - gp2x_fceu_darken_text_bg(); - gp2x_fceu_darken_reset(); + menu_darken_text_bg(); + menu_darken_reset(); // error / version if (menuErrorMsg[0]) gp2x_text_out15(1, 229, menuErrorMsg); @@ -1256,8 +1263,8 @@ static void draw_menu_root(int menu_sel) sprintf(vstr, "v" GP2X_PORT_VERSION " r%i", GP2X_PORT_REV); gp2x_text_out15(320-strlen(vstr)*8-1, 228, vstr); } - gp2x_fceu_darken_text_bg(); - gp2x_video_flip(); + menu_darken_text_bg(); + menu_flip(); } @@ -1409,8 +1416,8 @@ static void menu_gfx_prepare(void) // switch bpp gp2x_video_changemode(16); gp2x_video_set_offs(0); - gp2x_video_RGB_setscaling(0, 320, 240); - gp2x_video_flip(); + gp2x_video_RGB_setscaling(320, 240); + menu_flip(); } diff --git a/drivers/gp2x/minimal.c b/drivers/gp2x/minimal.c index 86bfdfb..34f5ea7 100644 --- a/drivers/gp2x/minimal.c +++ b/drivers/gp2x/minimal.c @@ -54,7 +54,6 @@ void *gp2x_screen; #define FRAMEBUFF_ADDR3 (FRAMEBUFF_ADDR2+0x30000) static const int gp2x_screenaddrs[4] = { FRAMEBUFF_ADDR0, FRAMEBUFF_ADDR1, FRAMEBUFF_ADDR2, FRAMEBUFF_ADDR3 }; -static int gp2x_screenaddrs_use[4]; static unsigned short gp2x_screenaddr_old[4]; @@ -62,15 +61,10 @@ static unsigned short gp2x_screenaddr_old[4]; void gp2x_video_flip(void) { unsigned short lsw, msw; - int addr = gp2x_screenaddrs_use[screensel&3]; + int addr = gp2x_screenaddrs[screensel&3]; addr += gp2x_screen_offs; - // since we are using the mmu hack, we must flush the cache first - // (the params are most likely wrong, but they seem to work somehow) - //flushcache(addr, addr + 320*240*2, 0); - flushcache(gp2x_screen, (char *)gp2x_screen + 320*240*2, 0); - lsw = (unsigned short) addr; msw = (unsigned short)(addr >> 16); @@ -86,7 +80,7 @@ void gp2x_video_flip(void) /* doulblebuffered flip */ void gp2x_video_flip2(void) { - unsigned short msw = (unsigned short)(gp2x_screenaddrs_use[screensel&1] >> 16); + unsigned short msw = (unsigned short)(gp2x_screenaddrs[screensel&1] >> 16); gp2x_memregs[0x2910>>1] = msw; gp2x_memregs[0x2914>>1] = msw; @@ -126,18 +120,12 @@ void gp2x_video_setpalette(int *pal, int len) // TV Compatible function // -void gp2x_video_RGB_setscaling(int ln_offs, int W, int H) +void gp2x_video_RGB_setscaling(int W, int H) { float escalaw, escalah; int bpp = (gp2x_memregs[0x28DA>>1]>>9)&0x3; unsigned short scalw; - // set offset - gp2x_screenaddrs_use[0] = gp2x_screenaddrs[0] + ln_offs * 320 * bpp; - gp2x_screenaddrs_use[1] = gp2x_screenaddrs[1] + ln_offs * 320 * bpp; - gp2x_screenaddrs_use[2] = gp2x_screenaddrs[2] + ln_offs * 320 * bpp; - gp2x_screenaddrs_use[3] = gp2x_screenaddrs[3] + ln_offs * 320 * bpp; - escalaw = 1024.0; // RGB Horiz LCD escalah = 320.0; // RGB Vert LCD @@ -164,6 +152,20 @@ void gp2x_video_set_offs(int offs) gp2x_screen_offs = offs; } +void gp2x_video_wait_vsync(void) +{ + unsigned short v = gp2x_memregs[0x1182>>1]; + while (!((v ^ gp2x_memregs[0x1182>>1]) & 0x10)); +} + +void gp2x_video_flush_cache(void) +{ + // since we are using the mmu hack, we must flush the cache first + // (the params are most likely wrong, but they seem to work somehow) + //flushcache(addr, addr + 320*240*2, 0); + flushcache(gp2x_screen, (char *)gp2x_screen + 320*240*2, 0); +} + void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len) { if (buffers & (1<<0)) memcpy((char *)gp2x_screens[0] + offset, data, len); @@ -301,7 +303,6 @@ void gp2x_init(void) gp2x_screenaddr_old[2] = gp2x_memregs[0x2912>>1]; gp2x_screenaddr_old[3] = gp2x_memregs[0x2914>>1]; - memcpy(gp2x_screenaddrs_use, gp2x_screenaddrs, sizeof(gp2x_screenaddrs)); gp2x_memset_all_buffers(0, 0, 320*240*2); // snd diff --git a/drivers/gp2x/minimal.h b/drivers/gp2x/minimal.h index 3b01cad..e2a29f5 100644 --- a/drivers/gp2x/minimal.h +++ b/drivers/gp2x/minimal.h @@ -11,8 +11,10 @@ void gp2x_video_flip(void); void gp2x_video_changemode(int bpp); void gp2x_video_changemode2(int bpp); 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); void gp2x_video_set_offs(int offs); +void gp2x_video_wait_vsync(void); +void gp2x_video_flush_cache(void); void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len); void gp2x_memcpy_all_buffers(void *data, int offset, int len); void gp2x_memset_all_buffers(int offset, int byte, int len); diff --git a/drivers/gp2x/throttle.c b/drivers/gp2x/throttle.c index c52eb68..fdfc0eb 100644 --- a/drivers/gp2x/throttle.c +++ b/drivers/gp2x/throttle.c @@ -1,38 +1,68 @@ #include #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 +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; } diff --git a/drivers/gp2x_test/minimal.c b/drivers/gp2x_test/minimal.c index f753a80..d2a8982 100644 --- a/drivers/gp2x_test/minimal.c +++ b/drivers/gp2x_test/minimal.c @@ -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) { } diff --git a/out_gp2x/readme.txt b/out_gp2x/readme.txt index ab085ee..94a7e22 100644 --- a/out_gp2x/readme.txt +++ b/out_gp2x/readme.txt @@ -181,6 +181,9 @@ ver 0.4 (by notaz) - Fixed an issue of MapIRQHook getting lost after loading a savestate (glitched Akumajou Densetsu and other games after savestate load). - A bug, which prevented configuring multiple USB pads fixed. + - Fixed sound breaking bug after switching it on/off multiple times. + - Added "Perfect VSYNC" option, which changes GP2X refresh rate and + syncs emu timing to LCD vsync. rev 153 - Lots of work on the asm core. Timing fixed for some instructions. Some missing undocumented instruction handlers added. Lots of diff --git a/sound.c b/sound.c index 370664b..bb3c89d 100644 --- 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) -- 2.39.2