Frame pacing

Discuss ADFFS development versions and upcoming additions
JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Frame pacing

Post by JonAbbott » Wed Jan 01, 2014 3:23 am

Whilst developing the JIT, one thing that's been playing on my mind is frame pacing.

The method ADFFS currently employs is to check the time between each frame swap and stall if it's not at the correct FPS. For Zarch, that means it will run at 50FPS regardless of the monitor refresh rate. What you end up with is something along the lines of film pull-down with an extra frame inserted every n frames, hopefully it's regular enough that you don't notice it.

The obvious flaw in this method is that it requires the game to employ frame swapping and quite a few don't. Pac-mania, Terramex and Jet Fighter are three that don't which is why I've been pondering the issue over the past two weeks. Those four games have been my main test games for the JIT, as none touch VIDC or IOC which would only complicate tracking down issues. Having run them hundreds of times, the fact they're not being paced correctly has been bugging me.

What I could do is switch the frame pacing code from OS_Byte 113 (display screen bank) to OS_Byte 19 (wait for V-sync), which will keep the current method working (OS_Byte 113 forces at least one V-Sync wait), but will allow frame pacing in more games. Whilst I'm at it, I can abstract OS_Byte 19 from the hardware, so it's paced at 50Hz to match the original Archimedes, in the process avoiding the lack of V-Sync on various RO5 machines.

Now, I've not checked to see if Pac-mania, Terramex or Jet Fighter do actually call OS_Byte 19. They obviously use something to pace themselves and V-Sync seems the obvious choice. It's obviously not an IOC timer, as I've not implemented them yet and it's not TickerV as I've had reports of games running at the wrong rate on the Pi.

I did compare Zarch and Pac-mania to an original Arc. Zarch is spot on and Pac-mania looks right but is hard to tell. If my Pi is generating V-Sync at 60Hz as my monitor reports, it's not easy to spot unless there's regular feedback. On Zarch, you simply sit on the launch pad and get a regular beep off the radar, which you can time. Not so easy on Pac-mania where you die every five seconds if you don't keep moving!

Anyhow, I'll code it up and see if any of the games are affected. This still leaves the issue of games that don't use V-Sync being too fast, possible ones I've already noted but haven't checked yet are:

Alien Invasion
Champions: World Class Leader Board
Ego: Repton 4
F.R.E.D.
HoverBod
Ibix the Viking
Play It Again Sam 3: Letrouve
Manchester United (just the menu)
Populous

Some of those should work under the JIT as-is, I can also check on RO3.71 as most already work or are fixed by ADFFS to work on a Risc PC.

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Wed Jan 01, 2014 6:13 pm

JonAbbott wrote:...switch the frame pacing code from OS_Byte 113 (display screen bank) to OS_Byte 19 (wait for V-sync)
I coded this earlier and sure enough, you can now slow Pac-mania down. Testing on the A440/1 on RO3.11, I noticed two completely separate issues:

1. The music is stuttering, with or without frame pacing. This has been reported on the Pi as well, although oddly it works okay on my Pi. Anyhow, need to investigate why Pac-mania isn't working correct...need to check against my trusty original A310 and an A4000.

2. LCDGameModes doesn't seem to be working anymore. It's enabled, but not doing anything on a MODE change, so need to investigate that as well.

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Wed Jan 01, 2014 11:07 pm

JonAbbott wrote:2. LCDGameModes doesn't seem to be working anymore. It's enabled, but not doing anything on a MODE change, so need to investigate that as well.
This was a combination of bugs in the VIDC20 detection code and the two ADFFS loader scripts: !Run and !Loader

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Thu Jan 02, 2014 12:29 am

Neither Manchester United or Terramex call OS_Byte 19 or 113, so they can't be slowed down currently.

Pac-mania does run at the right speed on RPC and Arc's, when set at 50 fps, but for some unknown reason doesn't call OS_Byte 19 when running on the Pi. The title screen does, but when the game is playing it doesn't - that has me completely stumped.

What I now need to do is abstract/hypervise various other things that are related to the V-Sync, including:

Device 3 (PRM1-121)
Event 4 (PRM1-147)
OS_Byte 176 (PRM1-415)

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Thu Jan 02, 2014 1:41 am

JonAbbott wrote:Pac-mania does run at the right speed on RPC and Arc's, when set at 50 fps, but for some unknown reason doesn't call OS_Byte 19 when running on the Pi.
I've debugged the code and it is calling OS_Byte 19, so something odd is going on. Its also using Event 4 for the music, which will explain why its stuttering on some machines.

To fix the music, ADFFS needs to take over event enable/disable and prevent event 4:
OS_Byte 13 (PRM1-150)
OS_Byte 14 (PRM1-152)

When event 4 is enabled, it needs to generate it's own VSync events via OS_CallAVector (PRM1-70)

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Thu Jan 02, 2014 11:55 pm

JonAbbott wrote:Event 4 (PRM1-147)
OS_Byte 176 (PRM1-415)
This is now implemented
JonAbbott wrote:To fix the music, ADFFS needs to take over event enable/disable and prevent event 4:
OS_Byte 13 (PRM1-150)
OS_Byte 14 (PRM1-152)

When event 4 is enabled, it needs to generate it's own VSync events via OS_CallAVector (PRM1-70)
As is this.

The good news is that the Pac-mania music is now correct on RO3.1 thru RO3.71 (haven't tested RO4.x) as is Terramex. It's also fixed the game speed in Terramex.

The bad news is Pac-mania locks the Pi solid before it starts and Terramex has a corrupt palette - suspiciously like a compiler issue, so I recompiled (is that the right word with assembler?) with the fast option and sure enough its doing something completely different. So...just need to get the compiler to work properly and I'll be able to release it.

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Fri Jan 03, 2014 2:29 am

JonAbbott wrote:The bad news is Pac-mania locks the Pi solid before it starts and Terramex has a corrupt palette - suspiciously like a compiler issue, so I recompiled (is that the right word with assembler?) with the fast option and sure enough its doing something completely different. So...just need to get the compiler to work properly and I'll be able to release it.
It's not a compiler issue, it seems to be an issue on RO5. My best guess is that EventV 4 is used by the OS somewhere.

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Wed Jan 29, 2014 4:44 pm

This is now working nicely on the Pi (the EventV 4 issues were resolved by using GraphicsV to generate the VSync)

I need to decide what to do for RO3.1 - RO4.x though. Options include:
  1. Turn off frame pacing and run the game at the monitor refresh rate
  2. Force frame swapping
  3. Abstract DA2 (the screen) and implement VIDC frame swapping independently of the game
Pros/Cons:
  1. The game will run fast. Where music code hangs off Event 4, the music will be wrong
  2. Entails remapping the screen memory every VSync - probably the best option. It does however rely on the game redrawing the screen from scratch
  3. Won't work for ARM3 as there's not enough CPU or memory bandwidth, but will work for ARM610 / SA and is how it's implemented on the Pi. Quite complicated to code though

steve3000
Posts: 198
Joined: Thu May 02, 2013 9:25 pm

Re: Frame pacing

Post by steve3000 » Thu Jan 30, 2014 2:19 am

HI Jon, this makes interesting reading.

I dabbled in this with LCDgamemodes (do you have the test version which reduces VSync?).

I tried a couple of methods, from memory:

1) trapping the VSync at the IOC interrupt trigger, before RISC OS issues vysnc event (4), and only allowing through 50 vsync events per second - this worked for music and for a few demos, but it doesn't solve OS_Byte 19, which is used by many/most games, as OS_Byte 19 looks directly at the IRQ register (IRQA I think...) and waits for the VSync trigger.

2) I trapped OS_Byte 19, as well as the above. This was more successful, and aligned correctly with actual VSyncs, so should avoid flicker. This seems to be what you're doing?

3) What I didn't do, but had planned... Was to trap the keyboard scan OS_Byte(s). Assumption being, the games which do not call OS_Byte 19 or issue frame swaps, are written for the oldest Archimedes - and probably skipped these things because they caused some level of slow down or just weren't necessary as the game was maxed out on the 8MHz processor... But all games need to gain user input and would tend to do a keyboard scan, following completion of the screen redraw - which would be at some multiple of the frame rate, ie. 50Hz or 25Hz. I suspect with a bit of thought you could force a delay through a trapped keyboard scan OS_Bye to line itself up with your VSync 50Hz code... This would need some thought where games scan for multiple keys, but pick a common key, eg. Esc is a good one - as most games would look for it - and force a delay whenever that key is scanned...

JonAbbott
Posts: 1737
Joined: Thu Apr 11, 2013 12:13 pm
Location: Essex

Re: Frame pacing

Post by JonAbbott » Thu Jan 30, 2014 11:31 am

steve3000 wrote:I dabbled in this with LCDgamemodes (do you have the test version which reduces VSync?).
I've not seen that version - not that I recall anyhow. That last version you put on the dev site is 0.21b, from which I based 0.22d to botch VIDC20 support.
steve3000 wrote:1) trapping the VSync at the IOC interrupt trigger, before RISC OS issues vysnc event (4), and only allowing through 50 vsync events per second - this worked for music and for a few demos, but it doesn't solve OS_Byte 19, which is used by many/most games, as OS_Byte 19 looks directly at the IRQ register (IRQA I think...) and waits for the VSync trigger.
I didn't go quite so low level. The IOC / IOMD versions of ADFFS supress OS_Byte 13, 4 (enable VSync event) and simply generate EventV 4 at 50Hz. This fixes the speed of most games, Terramex / Pac-mania for example.
steve3000 wrote:2) I trapped OS_Byte 19, as well as the above. This was more successful, and aligned correctly with actual VSyncs, so should avoid flicker. This seems to be what you're doing?
It traps both OS_Byte 19 and OS_Byte 113 (change screen bank). OS_Byte 113 checks to see if OS_Byte 19 has been seen since the last swap, if not it forces one.
OS_Byte 19 simply waits for n centiseconds. On IOC/IOMD it then waits for an actual VSync, on the Pi it immediately blits DA2 to the GPU back-buffer.
steve3000 wrote:3) What I didn't do, but had planned... Was to trap the keyboard scan OS_Byte(s).
That's a very good idea, I can add that to ADFFS quite easily. As with OS_Byte 113 - OS_Byte 121 (Keyboard scan), 122 (Keyboard scan from 16 decimal) and 129 (Scan a for a particular key) can all be made to check if OS_Byte 19 has been seen, if not force one.
The Manchester United title page will be a good test of it working.


How does frame pacing work...

IOC / IOMD:
  • OS_Byte 13 / 14, 4 (generate VSync events) are suppressed
  • Event 4 is generated at 50Hz via OS_CallEvery
  • OS_Byte 176 (50Hz counter) returns a true 50Hz counter
  • OS_Byte 19 waits for actual VSyncs until n centiseconds have passed
  • OS_Byte 113 forces OS_Byte 19 if one hasn't been seen since the last call
32-bit:
  • GraphicsV 1 (VSync occurred), as raised by the GPU, is suppressed from the OS and triggers a GPU bank swap if the back-buffer is dirty. If the back-buffer isn't marked as dirty within 8 VSync, DA2 is blitted at 50Hz to the back-buffer and then swapped
  • GraphicsV 1 is generated at 50Hz via OS_CallEvery
  • OS_Byte 176 (50Hz counter) returns a true 50Hz counter
  • OS_Byte 19 waits for n centiseconds
  • OS_Byte 113 forces OS_Byte 19 if one hasn't been seen since the last call
The issue with IOC/IOMD is where games use Event 4 to update the display and don't frame swap (eg Chuck Rock, Heimdall), as Event 4 is no longer VSync aligned you see the display update.

Post Reply