Screen Banking - Eliminating Graphics Flicker
Angel Perez (2908) 84 posts |
I have had so far enormous fun with the BASIC interpreter and the StrongED text editor on my Raspberry Pi 2 in RISC OS. But new challenges await as I tread further and deeper into gaming. Graphics displayed on the screen alone isn’t enough in BASIC on the Pi 2 in RISC OS. There is something else to conquer: screen flickering. From the Archimedes Gamemaker’s Manual I checked out the ARMsprite program and the sprites do move across the screen as smooth as lubricant and virtually no flicker. The trouble is, although the programs work, I need a better undestanding of the process of screen banking for my own work. One of the things needed to be done during graphics rendering at runtime is to update the screen for every draw on it. Sure, operating system SWI call &06 (OS_Byte) with Register 0 at values of &70 and &71 do take part in screen banking but the &13 value given to OS_Byte as the reason is a less known figure in the coding. In BASIC we often use a set of statements within a PROCedure, such as: DEF PROCSome_Procedure In the ARMsprite program I tested, in the listing there is a part of the code% where there is an OS_Byte call to #19 (&13) as the reason for the call. Apparently it is used to update the screen. But that program was written with assembly code linked branching, which I don’t wish to use at this time and the list of variables there, from work = 0 to link = 14 apparently refer to the registers R0 to R14. I don’t yet really know what is the SWI call &10C for but it is said that it clears the screen. In all an interesting part of graphics drawing for gaming. |
Chris Johnson (125) 825 posts |
The series of SWI calls &100 to &1FF simply write the ‘char’ in the bottom byte of the SWI number, using OS_WriteC. In this case the ‘char’ being written is &0C, which is #12. VDU 12 does indeed clear the screen. |
David Pitt (102) 743 posts |
See SWI OS_WriteI and VDU codes HTH. |
Chris Johnson (125) 825 posts |
OS_Byte with reason code &13 is ‘wait for vertical sync’. This means the screen can be updated or switched during the blank period, hence reducing tearing or jitter. |
Angel Perez (2908) 84 posts |
To Chris Johnson (125) But Chris, though, while the reason &13 for the OS_Byte call does indeed reduce the jitters and tearing, I still have noticeable flickering at the top third part of the screen. Generally the screen bank value at bk% is initialised at 1 but even though this can eliminate the flickering completely, you can’t see what is happening on the screen except for a brief spurt every 4 seconds. |
Angel Perez (2908) 84 posts |
Hereby, Chris, I am drawing graphics on the screen inside a REPEAT…UNTIL loop. But I discovered the solution… under my nose! What would be a looping ARM routine in the ARMsprite program from the Archimedes Gamemakers’ Manual, for the REPEAT…UNTIL loop in my games, the routine for blanking the screen and selecting the screen bank is split into two parts with the lines of code for the graphics between them. Example: bk% = bk% EOR &03 The average speed of BASIC inside a REPEAT…UNTIL loop, in my current experience, is clocked at over 200 frames per second! But the OS_Byte call to reason &13, which causes the graphics interface to wait for the V-sync, slows down the program execution inside the loop to well over 60 frames per second. (But it sure eliminates the graphics flickering completely!) As far as it is of concern of the ARMsprite program in BASIC, even 60 fps should still be adequate for most any classic games. But the tinkering I worked up when I clocked the BASIC interpreter inside a loop at 200 fps (without screen V-sync) can be useful to measure out how many sprites on the screen and how big a scrolling screen scenery can RISC OS handle in BASIC (with assembly code routines, of course!) |
Neil Fazakerley (464) 124 posts |
Hi Angel. What mode and colour depth are you running in? Risc OS screen banking on the Pi will only work in certain modes/colour depths. E.g. banking will work in 1280 × 1024 × 64k colours, but not in 16 million colours. Unlike most other Risc OS platforms, the Pi assigns a fixed amount of screen memory (8MB) which can’t be altered or added to by Risc OS. So whatever byte count your mode is it must fit twice into 8MB for banking to succeed. 64k colours require 3 bytes per pixel. 1280 × 1024 × 3 = 3,932,160 bytes. Multiply that by 2 banks and it just squeezes into the Pi’s 8MB screen memory. Likewise, the widescreen version of the same monitor: 1440 × 900 × 3 = 3,888,000 bytes. However 16 million colours (requiring 4 bytes per pixel) obviously won’t fit twice so the Pi ignores your banking code completely – which is what sounds like is happening in your case. |
Angel Perez (2908) 84 posts |
In the BASIC routines, including assembly code, Neil Fazakerley (464), I am using Acorn’s native graphics 256-colour modes (e.g., MODE 13), not 16-bit or 24-bit colours. (I would be doing programmes under WIMP, typically, if I used 16-bit or 24-bit colours.) That the OS_Byte &13 call may not prevent flicker altogether will depend on the screen mode, the visual resolution and colour depth. I decided to stick to 256-colour modes and a visual resolution of no more than 320 × 256. With internal graphic resolution of 1280 × 1024, each pixel in the 320 × 256 mode (MODE 13 for example) is worth 4 pixels in both the X and Y axes. This translates into the visuals on the screen moving across as smooth as baby skin! Notice that when you make an OS_ColourTrans graphics call, &4075E, which is SetColour, to change the colour of the graphics “pen” in VDU 5 sub-mode, the documentation only lists R0 as the colour reason in the code for use and R3 and R4 for determination whether it is a foreground or background color and GCOL action. The colour reasons R1 and R2, respectively, only apply to usage of colour modes 16-bit and 24-bit, respectively 64K and 16M colours. But a 256-colour graphics mode, like MODE 13, is already adequate for my work. Sure, Neil, there is MAME available in the !PackMan listing for those who are into gaming who are too lazy to learn to code programmes in RISC OS… and unless you played Prince Of Persia or Wolfenstein 3D on an IBM PC, no arcade game I ever played in the past was ever rendered with any colour palettes beyond a content of 256 colours. Nintendo’s Donkey Kong may rank as the world’s very first video game in the arcade to ever render graphics in a 256-colour mode like the later Acorn computers descended from the original BBC Micro. So far, I believe I am all set to write my very first home-brew game on my Raspberry Pi in RISC OS! |
Jon Abbott (1421) 2651 posts |
You’re seeing tearing on the Pi, because of the order of the VSync wait and Bank switch. Due to the way the GPU actions data packets, you need to update the back buffer, switch screen banks and then wait for VSync. You may also find you need triple buffering, due to delays in packets being actioned. Alternatively, update the front buffer instead. There’s a few GPU’s that need this method, its implementation defined unfortunately, hence why folk tend to use triple buffering. With triple buffering, your last two buffers are both considered as being front buffers and the third can safely be assumed to always be a back buffer. |
Neil Fazakerley (464) 124 posts |
Out of interest, how much of this Pi screen banking and Vsync peculiarity would apply to a BB-xM (or ARMini)? I’m thinking of dusting off my BB-xM to test some game/graphics code I’m writing that doesn’t run well on the Pi, but there won’t be much point unless the BB-xM uses more predictable/traditional Risc OS buffering. |
Jon Abbott (1421) 2651 posts |
Just about every GPU based machine requires the bank switch to occur before the VSync. |