libretro / beetle-psx-libretro

Standalone port/fork of Mednafen PSX to the Libretro API.
GNU General Public License v2.0
311 stars 131 forks source link

[Beetle PSX HW] Correct Refresh Rates (game speed) #509

Closed Dogway closed 4 years ago

Dogway commented 5 years ago

Description

The hard-coded console refresh rates are incorrect for both NTSC and PAL regions, leading to incorrect game speed with libretro's default time-stretch settings.

Expected behavior

hunterk merged a commit under a fork . I did some calculations on this post, but I believe hunterk's PAL values are more correct (accounted for correct PAL width)

Papermanzero commented 5 years ago

Can those refresh rates be used to speed up the PAL versions of certain games

Dogway commented 5 years ago

You can already speed up PAL games using RA's timing_skew option, the problem is the core is reporting a wrong frame rate for both NTSC and PAL so you won't play either region games at their original speed (or extrapolated speed in case of PAL unoptimized games) if you wanted, unless you want to do some hackish maths to compensate.

To add to this ticket, hunterk's commit should be adapted to a static variable fed from Core options, since only 1.40% of PSX library is fully interlaced (480i) link. Remaining 98.60% might have mixed modes if menus render at 480i, but constant display modeline switching would be undesirable. Maybe round the 2 optional static variables to 59.826 and 59.940 (49.842 and 49.764 for PAL). Due to lack of experience I don't feel comfortable doing a PR of this so anyone willing is welcome.

Dogway commented 5 years ago

Does the maintainer accept bounties? Edit: Link to Bountysource

inactive123 commented 5 years ago

Of course.

On Thu, 22 Aug 2019, 19:22 Dogway, notifications@github.com wrote:

Does the maintainer accept bounties?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/libretro/beetle-psx-libretro/issues/509?email_source=notifications&email_token=AAIGQSX7UTKJBXYMFCPNBUDQF3DO5A5CNFSM4HSCR2YKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD45ZLIY#issuecomment-523998627, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIGQSXDCDW7R5XHPEXJ2TTQF3DO5ANCNFSM4HSCR2YA .

hizzlekizzle commented 5 years ago

Ok, the main reason I hadn't PRed this myself is that it wasn't automatically switching for interlaced content, but you're saying that's not desirable anyway, right? So how should the option be named/worded? Which speeds do we need to expose?

Dogway commented 5 years ago

For CRT I guess it should switch.

For now I would set them to the correct progressive rates that matches with most of the content and open a ticket for the switch on interlaced content, because among other things I'm not sure how the switch will affect those with modelines. For instance if it boots in interlaced refresh rate the modeline won't be triggered. Not sure if libretro can know what kind of display (EDID?) is being used, or at worst add a core option as "Allow Interlaced Rate" or else because there might be someone who feeds native resolution to an LCD as well.

ggrtk commented 4 years ago

Currently the way to report the proper frame rate to the frontend is through RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO. RetroArch won't perform a driver reinit on fps changes anymore after https://github.com/libretro/RetroArch/commit/e8c027cbc3194a666f2285cae1f64601427f0179 but the libretro API has no guarantees for this. We could implement the fps switching pretty easily but without any guarantees this might result in bad behavior for some frontends, especially for many games that switch between non-interlaced and interlaced frequently. @hizzlekizzle Any thoughts?

The values calculated out in the matching content and clocks section below should be what we use in pretty much all cases since the Beetle core doesn't currently allow the video mode of a game to be set to something different from the disc region. Hopefully the calculations below put some of the discussion from this issue thread and the forum thread to rest.

Nominal values

NTSC GPU clock is nominally 53.693175 MHz PAL GPU clock is nominally 53.203425 MHz

PS1 outputs 263 scanlines per field for NTSC non-interlaced PS1 outputs 262.5 scanlines per field for NTSC interlaced

PS1 outputs 314 scanlines per field for PAL non-interlaced PS1 outputs 312.5 scanlines per field for PAL interlaced

NTSC line rate (horizontal frequency) is 9/572 MHz ~= 15.734266 kHz (~63.555554 us per line) PAL line rate (horizontal frequency) is 15.625 kHz (64 us per line)

Field rate calculations

Matching content and console clocks

I'm working backwards from nominal values listed above rather than via primitives like oscillators. The PS1 NTSC/PAL line timings are fairly standard and empirically measured values should lie within some small tolerance of the nominal values.

Field rate = (Line rate)/(Lines per field)

NTSC non-interlaced w/ NTSC clock (9/572 MHz)/263 ~= 59.826 Hz

NTSC interlaced w/ NTSC clock (9/572 MHz)/262.5 ~= 59.940 Hz

PAL non-interlaced w/ PAL clock (15.625 kHz)/314 ~= 49.761 Hz

PAL interlaced w/ PAL clock (15.625 kHz)/312.5 ~= 50.00 Hz

Non-matching content and console clocks

This is where things get kind of messy. I'm not very confident about these calculations and it seems like results might even wildly differ depending on console revision. This all gets thrown out if a console is specifically modded so I'll ignore that specific case for now.

Disclaimer: calculated values in this section are liable to be inaccurate and I make no guarantees for their accuracy.

NTSC GPU cycles in an NTSC line: (53.693175 MHz)/(9/572 MHz) ~= 3412.4996 cycles per line PAL GPU cycles in a PAL line: (53.203425 MHz)/(15.625 kHz) ~= 3405.0192 cycles per line

Field rate = (GPU clock)/(Lines per field * GPU cycles per line)

Assumptions: GPU clock is determined by specific console region (ignore possibility of mods for additional oscillators) Lines per field and GPU cycles per line seems to be a constant that is determined by the content (assumption taken from Nocash)

PAL non-interlaced w/ NTSC clock (53.693175 MHz)/(314 * 3405.0192) ~= 50.219 Hz

PAL interlaced w/ NTSC clock (53.693175 MHz)/(312.5 * 3405.0192) ~= 50.460 Hz

Horizontal frequency for PAL content on NTSC clock is higher than PAL content on PAL clock.

NTSC non-interlaced w/ PAL clock (53.203425 MHz)/(263 * 3412.4996) ~= 59.280 Hz

NTSC interlaced w/ PAL clock (53.203425 MHz)/(262.5 * 3412.4996) ~= 59.393 Hz

Horizontal frequency for NTSC content on PAL clock is lower than NTSC content on NTSC clock.

Some other things to address

Nocash uses 53.2224 MHz as the GPU clock in some instances, claiming this comes from the PSOne PAL console. I'm unable to find much information about this so it's probably best to stick with the nominal 53.203425 MHz PAL value.

In GPU_FillVideoParams() in gpu.cpp, Mednafen provides the fps as 1005643085 (NTSC) or 836203078 (PAL) and has this comment in git.h: uint32_t fps; // frames per second * 65536 * 256, truncated. This gives ~59.941 for NTSC and ~49.842 for PAL. The NTSC value is approximately the nominal field rate for colored NTSC, but the PAL value doesn't seem to correspond to any of the values calculated above. Perhaps the PAL value is a rough estimate of non-interlaced PAL content on PAL clock? This doesn't seem to affect anything in the Beetle core so it's not a big deal either way.

Some users have OSSC reporting 50.1Hz for non-interlaced PAL content on NTSC consoles. I'm not sure if this means that the calculated values above are wrong or if it's just one of those hardware revision differences. https://shmups.system11.org/viewtopic.php?f=6&t=63612 https://www.cybdyn-systems.com.au/forum/viewtopic.php?t=1840

Sources

https://assemblergames.com/threads/playing-ntsc-games-on-pal-ps1-ps2-and-vice-versa.68051/ http://www.kolumbus.fi/pami1/video/pal_ntsc.html https://www.maximintegrated.com/en/design/technical-documents/tutorials/7/734.html https://forum.fobby.net/index.php?t=msg&goto=3434& https://problemkaputt.de/psx-spx.htm (not particularly helpful for GPU timings in some areas, but was cross-referenced with nevertheless)

hizzlekizzle commented 4 years ago

but the libretro API has no guarantees for this. We could implement the fps switching pretty easily but without any guarantees this might result in bad behavior for some frontends, especially for many games that switch between non-interlaced and interlaced frequently

While undefined behavior sucks, if it doesn't explicitly say we shouldn't do it... The normal RA/LR way is to just put it behind an option (preferably with an inscrutable name lol)

ggrtk commented 4 years ago

I've pushed commit 60f5ff84 that makes the frame rate reporting accurate, but this heavily relies on frontend behavior so it's not something I want to merge into main yet. The audio momentarily cuts out in RetroArch whenever the timing is changed which @realnc and @fr500 confirmed is because the audio driver is still being reinited on SET_SYSTEM_AV_INFO.

ggrtk commented 4 years ago

@hizzlekizzle @twinaphex

I'd like to start merging the accurate refresh rate reporting into main. To avoid the possible issues with frontend driver reinits, we could just put an experimental core option that when toggled on, allows the refresh rate reporting to toggle between 240p and 480i rates (59.826 Hz and 59.940 Hz for NTSC, 49.761 Hz and 50.000 Hz for PAL) and locks to either the progressive rates or interlaced rates when the option is toggled off, which is the current behavior.

A couple of things though -- I have no idea how this will interact with the PSX modelines listed here https://github.com/libretro/RetroArch/blob/51964eee20a1fc3ed4882b5cfbfd58a007c7fd77/README.md and it looks like the PSX resolutions listed there are incomplete and a couple have timings that are off.

Secondly, any preferences as to what the default timings we should use are? Currently the core uses the PAL progressive rate and NTSC interlaced rate. We should probably use either the progressive rate for both or interlaced for both for the default behavior.

hizzlekizzle commented 4 years ago

I think the option idea is good. That'll give people a chance to test out the modelines, etc. before making it mandatory. Seems to me that we would want to use the progressive rate as default, since most games are running in that mode most of the time.

ggrtk commented 4 years ago

Sorry for the delay, this feature is now available as of 6e90f45.

ggrtk commented 4 years ago

@Dogway Can you let us know if the core option is sufficient for this issue? If so then we can close the issue and bounty.

Dogway commented 4 years ago

@ggdrt Sure, thanks a lot. I didn't have time to test it thoroughly (only progressive mode) but I did see the option and was already in line with your valuable posts.

ggrtk commented 4 years ago

@twinaphex I think we can go ahead and close the bounty on this as well. I'm not sure if there's much else we can do at this point since the libretro API is based on fixed rates.