av_info: report the actual SPG-derived refresh rate

retro_get_system_av_info bucketed timing.fps to 60.00 (VGA) / 59.94 (NTSC) /
50.00 (PAL) from a pixel-clock table whose constants didn't even reconcile with
those figures, and the VGA case was wrong: Dreamcast VGA runs at 59.94, not 60
(27MHz / (858*525) = 59.9401). It also missed that 240p NTSC is ~59.83, not
59.94, and NAOMI boards run faster still.

The scheduler already computes the exact frame period in CalculateSync from the
SPG registers the game programs (Line_Cycles * pvr_numscanlines). Expose it as
spg_get_refresh_rate() -- pixel_clock / ((hcount+1) * (vcount+1)) -- and report
that. timing.fps now equals the rate frames and audio are actually produced at,
per mode and per game: 59.94 for VGA/480i, ~59.83 for 240p NTSC, 50.00 for PAL
480i, ~49.92 for PAL 240p, and the correct higher rates for NAOMI. Matches the
hardware-derived values confirmed upstream (flyinghead/flycast PR #2033) and
keeps frontend frame pacing in step with the core, pairing with the per-frame
audio flush. Falls back to 60 before CalculateSync has run.
This commit is contained in:
libretroadmin authored and libretroadmin committed 2026-07-03 21:44:45 +02:00
1 parent 55aa00b1d7
commit fa34742ec0
3 files changed
+24 -22

No files matched your search

+18
View File
@@ -59,6 +59,24 @@ void CalculateSync(void)
sh4_sched_request(vblank_schid, Line_Cycles);
}
/*
* Actual emulated vertical refresh rate, derived from the same SPG timing the
* scheduler runs on: pixel_clock / ((hcount+1) * (vcount+1)), i.e.
* SH4_MAIN_CLOCK / (Line_Cycles * pvr_numscanlines). This is the rate at which
* frames (and thus audio) are actually produced, so reporting it to the
* frontend via retro_get_system_av_info keeps timing.fps in step with the core
* instead of a bucketed 60/59.94/50 guess. It naturally yields the hardware
* figures: ~59.94 for VGA and 480i, ~59.83 for 240p NTSC, 50.00 for PAL 480i,
* and the higher NAOMI rates for boards that program the SPG accordingly.
* Falls back to 60 before CalculateSync has run.
*/
double spg_get_refresh_rate(void)
{
if (Line_Cycles == 0 || pvr_numscanlines == 0)
return 60.0;
return (double)SH4_MAIN_CLOCK / ((double)Line_Cycles * (double)pvr_numscanlines);
}
//called from sh4 context , should update pvr/ta state and everything else
int spg_line_sched(int tag, int cycl, int jit)
+1
View File
@@ -6,6 +6,7 @@ void spg_Term();
void spg_Reset(bool Manual);
void CalculateSync();
double spg_get_refresh_rate();
void read_lightgun_position(int x, int y);
struct TA_context;
void SetREP(TA_context* cntx);
+5 -22
View File
@@ -2304,10 +2304,6 @@ void retro_get_system_info(struct retro_system_info *info)
void retro_get_system_av_info(struct retro_system_av_info *info)
{
/* 00=VGA 01=NTSC 10=PAL, 11=illegal/undocumented */
const int spg_clks[4] = { 26944080, 13458568, 13462800, 26944080 };
u32 pixel_clock= spg_clks[(SPG_CONTROL.full >> 6) & 3];
if (cheatManager.Reset())
{
info->geometry.aspect_ratio = 16.0 / 9.0;
@@ -2336,24 +2332,11 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
if (rotate_screen)
info->geometry.aspect_ratio = 1 / info->geometry.aspect_ratio;
switch (pixel_clock)
{
case 26944080:
info->timing.fps = 60.00; /* (VGA 480 @ 60.00) */
break;
case 26917135:
info->timing.fps = 59.94; /* (NTSC 480 @ 59.94) */
break;
case 13462800:
info->timing.fps = 50.00; /* (PAL 240 @ 50.00) */
break;
case 13458568:
info->timing.fps = 59.94; /* (NTSC 240 @ 59.94) */
break;
case 25925600:
info->timing.fps = 50.00; /* (PAL 480 @ 50.00) */
break;
}
/* Report the actual emulated refresh rate, derived from the SPG timing the
* scheduler runs on, so the frontend's frame pacing matches the rate frames
* and audio are really produced at (~59.94 VGA/480i, ~59.83 240p NTSC,
* 50.00 PAL 480i, higher for NAOMI) rather than a bucketed 60/59.94/50. */
info->timing.fps = spg_get_refresh_rate();
info->timing.sample_rate = 44100.0;
}