Skip to content

Commit

Permalink
introduce fractional framerates
Browse files Browse the repository at this point in the history
  • Loading branch information
notaz committed Apr 14, 2024
1 parent 98c5462 commit 2f326fa
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 22 deletions.
26 changes: 23 additions & 3 deletions frontend/libretro.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ static unsigned previous_width = 0;
static unsigned previous_height = 0;

static int plugins_opened;
static int is_pal_mode;

#define is_pal_mode Config.PsxType

/* memory card data */
extern char Mcd1Data[MCD_SIZE];
Expand Down Expand Up @@ -586,7 +587,6 @@ void pl_frame_limit(void)

void pl_timing_prepare(int is_pal)
{
is_pal_mode = is_pal;
}

void plat_trigger_vibrate(int pad, int low, int high)
Expand Down Expand Up @@ -1002,7 +1002,7 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
unsigned geom_width = vout_width;

memset(info, 0, sizeof(*info));
info->timing.fps = is_pal_mode ? 50.0 : 60.0;
info->timing.fps = psxGetFps();
info->timing.sample_rate = 44100.0;
info->geometry.base_width = geom_width;
info->geometry.base_height = geom_height;
Expand Down Expand Up @@ -2265,6 +2265,7 @@ static void update_variables(bool in_flight)
int gpu_peops_fix = GPU_PEOPS_OLD_FRAME_SKIP;
#endif
frameskip_type_t prev_frameskip_type;
double old_fps = psxGetFps();

var.value = NULL;
var.key = "pcsx_rearmed_frameskip_type";
Expand Down Expand Up @@ -2706,6 +2707,18 @@ static void update_variables(bool in_flight)
Config.GpuListWalking = -1;
}

var.value = NULL;
var.key = "pcsx_rearmed_fractional_framerate";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if (strcmp(var.value, "disabled") == 0)
Config.FractionalFramerate = 0;
else if (strcmp(var.value, "enabled") == 0)
Config.FractionalFramerate = 1;
else // auto
Config.FractionalFramerate = -1;
}

var.value = NULL;
var.key = "pcsx_rearmed_screen_centering";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
Expand Down Expand Up @@ -3005,6 +3018,13 @@ static void update_variables(bool in_flight)
}

update_option_visibility();

if (old_fps != psxGetFps())
{
struct retro_system_av_info info;
retro_get_system_av_info(&info);
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info);
}
}

// Taken from beetle-psx-libretro
Expand Down
17 changes: 16 additions & 1 deletion frontend/libretro_core_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,21 @@ struct retro_core_option_v2_definition option_defs_us[] = {
},
"disabled",
},
{
"pcsx_rearmed_fractional_framerate",
"Use fractional frame rate",
NULL,
"Instead of the exact 50 or 60 (maximum) fps for PAL/NTSC the real console runs closer to something like 49.75 and 59.81fps (varies slightly between hw versions). PCSX-ReARMed uses the former \"round\" framerates to better match modern displays, however that may cause audio/video desync in games like DDR and Spyro 2 (intro). With this option you can try to use fractional framerates.",
NULL,
"video",
{
{ "auto", "Auto" },
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
},
"auto",
},
{
"pcsx_rearmed_gpu_slow_llists",
"(GPU) Slow linked list processing",
Expand All @@ -433,7 +448,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
NULL,
"video",
{
{ "auto", NULL },
{ "auto", "Auto" },
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
Expand Down
1 change: 1 addition & 0 deletions frontend/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ void emu_set_default_config(void)
Config.PsxAuto = 1;
Config.cycle_multiplier = CYCLE_MULT_DEFAULT;
Config.GpuListWalking = -1;
Config.FractionalFramerate = -1;

pl_rearmed_cbs.gpu_neon.allow_interlace = 2; // auto
pl_rearmed_cbs.gpu_neon.enhancement_enable =
Expand Down
12 changes: 9 additions & 3 deletions frontend/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ static const struct {
CE_CONFIG_VAL(DisableStalls),
CE_CONFIG_VAL(Cpu),
CE_CONFIG_VAL(GpuListWalking),
CE_CONFIG_VAL(FractionalFramerate),
CE_CONFIG_VAL(PreciseExceptions),
CE_INTVAL(region),
CE_INTVAL_V(g_scaler, 3),
Expand Down Expand Up @@ -1638,7 +1639,7 @@ static int menu_loop_speed_hacks(int id, int keys)
return 0;
}

static const char *men_gpul[] = { "Auto", "Off", "On", NULL };
static const char *men_autooo[] = { "Auto", "Off", "On", NULL };

static const char h_cfg_cpul[] = "Shows CPU usage in %";
static const char h_cfg_spu[] = "Shows active SPU channels\n"
Expand All @@ -1657,10 +1658,12 @@ static const char h_cfg_exc[] = "Emulate some PSX's debug hw like breakpoints
"and exceptions (slow, interpreter only, keep off)";
static const char h_cfg_gpul[] = "Try enabling this if the game misses some graphics\n"
"causes a performance hit";
static const char h_cfg_ffps[] = "Instead of 50/60fps for PAL/NTSC use ~49.75/59.81\n"
"Closer to real hw but doesn't match modern displays.";
static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
"(adjust this if the game is too slow/too fast/hangs)";

enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_BP, AMO_CPU, AMO_GPUL };
enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_BP, AMO_CPU, AMO_GPUL, AMO_FFPS };

static menu_entry e_menu_adv_options[] =
{
Expand All @@ -1671,7 +1674,8 @@ static menu_entry e_menu_adv_options[] =
mee_onoff_h ("Disable CD Audio", 0, menu_iopts[AMO_CDDA], 1, h_cfg_cdda),
mee_onoff_h ("ICache emulation", 0, menu_iopts[AMO_IC], 1, h_cfg_icache),
mee_onoff_h ("BP exception emulation", 0, menu_iopts[AMO_BP], 1, h_cfg_exc),
mee_enum_h ("GPU l-list slow walking",0, menu_iopts[AMO_GPUL], men_gpul, h_cfg_gpul),
mee_enum_h ("GPU l-list slow walking",0, menu_iopts[AMO_GPUL], men_autooo, h_cfg_gpul),
mee_enum_h ("Fractional framerate", 0, menu_iopts[AMO_FFPS], men_autooo, h_cfg_ffps),
#if !defined(DRC_DISABLE) || defined(LIGHTREC)
mee_onoff_h ("Disable dynarec (slow!)",0, menu_iopts[AMO_CPU], 1, h_cfg_nodrc),
#endif
Expand All @@ -1697,12 +1701,14 @@ static int menu_loop_adv_options(int id, int keys)
for (i = 0; i < ARRAY_SIZE(opts); i++)
*opts[i].mopt = *opts[i].opt;
menu_iopts[AMO_GPUL] = Config.GpuListWalking + 1;
menu_iopts[AMO_FFPS] = Config.FractionalFramerate + 1;

me_loop(e_menu_adv_options, &sel);

for (i = 0; i < ARRAY_SIZE(opts); i++)
*opts[i].opt = *opts[i].mopt;
Config.GpuListWalking = menu_iopts[AMO_GPUL] - 1;
Config.FractionalFramerate = menu_iopts[AMO_FFPS] - 1;

return 0;
}
Expand Down
11 changes: 7 additions & 4 deletions frontend/plugin_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "../libpcsxcore/psxmem_map.h"
#include "../libpcsxcore/gpu.h"
#include "../libpcsxcore/r3000a.h"
#include "../libpcsxcore/psxcounters.h"

#define HUD_HEIGHT 10

Expand Down Expand Up @@ -778,18 +779,20 @@ void pl_frame_limit(void)

void pl_timing_prepare(int is_pal_)
{
double fps;
pl_rearmed_cbs.fskip_advice = 0;
pl_rearmed_cbs.flips_per_sec = 0;
pl_rearmed_cbs.cpu_usage = 0;

is_pal = is_pal_;
frame_interval = is_pal ? 20000 : 16667;
frame_interval1024 = is_pal ? 20000*1024 : 17066667;
fps = psxGetFps();
frame_interval = (int)(1000000.0 / fps);
frame_interval1024 = (int)(1000000.0 * 1024.0 / fps);

// used by P.E.Op.S. frameskip code
pl_rearmed_cbs.gpu_peops.fFrameRateHz = is_pal ? 50.0f : 59.94f;
pl_rearmed_cbs.gpu_peops.fFrameRateHz = (float)fps;
pl_rearmed_cbs.gpu_peops.dwFrameRateTicks =
(100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
(100000*100 / (int)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
}

static void pl_get_layer_pos(int *x, int *y, int *w, int *h)
Expand Down
10 changes: 3 additions & 7 deletions libpcsxcore/cdrom.c
Original file line number Diff line number Diff line change
Expand Up @@ -583,19 +583,15 @@ static int cdrSeekTime(unsigned char *target)
int cyclesSinceRS = psxRegs.cycle - cdr.LastReadSeekCycles;
seekTime = MAX_VALUE(seekTime, 20000);

// need this stupidly long penalty or else Spyro2 intro desyncs
// note: if misapplied this breaks MGS cutscenes among other things
if (cdr.DriveState == DRIVESTATE_PAUSED && cyclesSinceRS > cdReadTime * 50)
seekTime += cdReadTime * 25;
// Transformers Beast Wars Transmetals does Setloc(x),SeekL,Setloc(x),ReadN
// and then wants some slack time
else if (cdr.DriveState == DRIVESTATE_PAUSED || cyclesSinceRS < cdReadTime *3/2)
if (cdr.DriveState == DRIVESTATE_PAUSED || cyclesSinceRS < cdReadTime *3/2)
seekTime += cdReadTime;

seekTime = MIN_VALUE(seekTime, PSXCLK * 2 / 3);
CDR_LOG("seek: %.2f %.2f (%.2f) st %d\n", (float)seekTime / PSXCLK,
CDR_LOG("seek: %.2f %.2f (%.2f) st %d di %d\n", (float)seekTime / PSXCLK,
(float)seekTime / cdReadTime, (float)cyclesSinceRS / cdReadTime,
cdr.DriveState);
cdr.DriveState, diff);
return seekTime;
}

Expand Down
17 changes: 17 additions & 0 deletions libpcsxcore/database.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ static const char * const dualshock_init_analog_hack_db[] =
"SLUS00546",
};

static const char * const fractional_Framerate_hack_db[] =
{
/* Dance Dance Revolution */
"SLPM86503", // 3rd Mix
"SLPM86752", // 4th Mix
"SLPM86266", // 4thMix: The Beat Goes On
"SLPM86831", // Extra Mix
"SLUS01446", // Konamix
/* Dancing Stage Fever */
"SLES04097",
/* Dancing Stage Fusion */
"SLES04163",
/* Spyro 2 */
"SCUS94425", "SCES02104",
};

#define HACK_ENTRY(var, list) \
{ #var, &Config.hacks.var, list, ARRAY_SIZE(list) }

Expand All @@ -82,6 +98,7 @@ hack_db[] =
HACK_ENTRY(gpu_centering, gpu_centering_hack_db),
HACK_ENTRY(gpu_timing1024, dualshock_timing1024_hack_db),
HACK_ENTRY(dualshock_init_analog, dualshock_init_analog_hack_db),
HACK_ENTRY(fractional_Framerate, fractional_Framerate_hack_db),
};

static const struct
Expand Down
4 changes: 3 additions & 1 deletion libpcsxcore/psxcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,10 @@ typedef struct {
boolean icache_emulation;
boolean DisableStalls;
boolean PreciseExceptions;
int GpuListWalking;
int cycle_multiplier; // 100 for 1.0
int cycle_multiplier_override;
s8 GpuListWalking;
s8 FractionalFramerate; // ~49.75 and ~59.81 instead of 50 and 60
u8 Cpu; // CPU_DYNAREC or CPU_INTERPRETER
u8 PsxType; // PSX_TYPE_NTSC or PSX_TYPE_PAL
struct {
Expand All @@ -153,6 +154,7 @@ typedef struct {
boolean gpu_centering;
boolean dualshock_init_analog;
boolean gpu_timing1024;
boolean fractional_Framerate;
} hacks;
} PcsxConfig;

Expand Down
35 changes: 33 additions & 2 deletions libpcsxcore/psxcounters.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,40 @@ u32 psxNextCounter = 0, psxNextsCounter = 0;

/******************************************************************************/

#define FPS_FRACTIONAL_PAL (53203425/314./3406) // ~49.75
#define FPS_FRACTIONAL_NTSC (53693175/263./3413) // ~59.81

static inline
u32 frameCycles(void)
{
int ff = Config.FractionalFramerate >= 0
? Config.FractionalFramerate : Config.hacks.fractional_Framerate;
if (ff)
{
if (Config.PsxType)
return (u32)(PSXCLK / FPS_FRACTIONAL_PAL);
else
return (u32)(PSXCLK / FPS_FRACTIONAL_NTSC);
}
return Config.PsxType ? (PSXCLK / 50) : (PSXCLK / 60);
}

// used to inform the frontend about the exact framerate
double psxGetFps()
{
int ff = Config.FractionalFramerate >= 0
? Config.FractionalFramerate : Config.hacks.fractional_Framerate;
if (ff)
return Config.PsxType ? FPS_FRACTIONAL_PAL : FPS_FRACTIONAL_NTSC;
else
return Config.PsxType ? 50.0 : 60.0;
}

// to inform the frontend about the exact famerate
static inline
u32 lineCycles(void)
{
// should be more like above, but our timing is already poor anyway
if (Config.PsxType)
return PSXCLK / 50 / HSyncTotal[1];
else
Expand Down Expand Up @@ -308,7 +339,7 @@ static void scheduleRcntBase(void)

if (hSyncCount + hsync_steps == HSyncTotal[Config.PsxType])
{
rcnts[3].cycle = Config.PsxType ? PSXCLK / 50 : PSXCLK / 60;
rcnts[3].cycle = frameCycles();
}
else
{
Expand Down Expand Up @@ -380,7 +411,7 @@ void psxRcntUpdate()
if( hSyncCount >= HSyncTotal[Config.PsxType] )
{
u32 status, field = 0;
rcnts[3].cycleStart += Config.PsxType ? PSXCLK / 50 : PSXCLK / 60;
rcnts[3].cycleStart += frameCycles();
hSyncCount = 0;
frame_counter++;

Expand Down
2 changes: 2 additions & 0 deletions libpcsxcore/psxcounters.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ u32 psxRcntRtarget(u32 index);

s32 psxRcntFreeze(void *f, s32 Mode);

double psxGetFps();

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion plugins/dfsound/externals.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
#define MAXCHAN 24

// note: must be even due to the way reverb works now
#define NSSIZE ((44100 / 50 + 16) & ~1)
#define NSSIZE ((44100 / 50 + 32) & ~1)

///////////////////////////////////////////////////////////
// struct defines
Expand Down

0 comments on commit 2f326fa

Please sign in to comment.