Chip8 and SuperChip programs can suffer from flicker.
This is due to the issue that the standard Chip8 game processing is essentially a free running loop.
Modern 2D or 3D graphics produce moving graphics in three steps:
- They wait for the video beam refresh to restart in some way,
- They then begin processing to tidy up the screen from the last render,
- They then redraw all currently active sprites in their existing or new positions.
This processing then hopefully finishes before the next refresh is due.
The more advanced method is to draw to a hidden screen and then present this completed screen when done.
This allows any slowdown to cause a slow frame rate to occur rather than any possible flickering at times.
The Draw Instruction instruction is used to both undraw and redraw using a machine code Exclusive Or instruction which can turn on and off bits into a bit-mapped screen memory area.
There is no Chip8 instruction to cause a wait for a video refresh therefore the processing loop can move in and out of sync with the refresh screen processing.
At best, a drawn set of bytes appears half bright and flickers at a high rate.
At worse, the object is in the undraw state and effectively disappears (more likely to happen with a slow emulator refresh process).
Algorithmic Methods of Reducing Flicker
The amount of flickering can be reduced or avoided all together depending how the program is coded and on the method the real machine or the emulator refreshes it's screen.
Some sample Chip8 pseudo code:
The initial draw at x and y, Start loop, Undraw the object at x and y, Alter X or Y due to keys, Redraw the object at x and y, Repeat Loop.
This will create a constantly flickering image.
To reduce the flicker, the number of instructions between an undraw and redraw can be reduced:
The initial draw at x and y, Start loop, Store X and Y in XSaved and YSaved, Alter X or Y due to keys, Undraw the object at XSaved and YSaved, Redraw the object at x and y, Repeat Loop.
This may usually allow the undraw and redraw instructions to execute within the time allowed between a screen refresh.
The initial draw at x and y, Start loop, Store X and Y in XSaved and YSaved, Alter X or Y due to keys, if XSaved <> x or YSaved <> y then Undraw object at XSaved and YSaved, Redraw object at x and y, Endif Repeat Loop.
This only causes a little flicker when the object is moved but when there is no movement the object will not flicker at all.
Currently there is no direct way to monitor for the video refresh in Chip8.
The Megachip language implements a specialized clear screen that can wait for video beam and process a single redraw for all objects model.
So all objects are required to be draw only once before the screen is cleared again.
Megachip has an additional background image display ability that replaces the standard clear screen.
Currently it is not known how Megachip will implement backgrounds as in the online videos of that emulator running.
This could be in form of a Save Current Screen instruction which stores the screen.
The Clear Screen could then either zero the display to zero and black.
Or the Clear Screen could overwrite the current screen with the saved screen.
Modern systems can clear a screen, redraw the entire tiled screen and then overwrite the display with the actual sprites.
Chip8 may not be fast enough to do this via interpreted code and so may need assistance from the emulator to generate such a screen.
The original ROM code for real machine implementations does attempt to reduce flicker:
- When a draw instruction is executed by the Chip8 ROM, it pauses for a while, by executing an Idle instruction, this is commented as waiting for a video refresh to occur.
- When an 1802 machine is interrupted by the video chip (CDP1861 - NTSC or CDP1864 - PAL), and is required to output screen bytes to the video display, the state of the line 1 input pin to the 1802 is set on by the video chip when the non-visible part of the screen is reached.
To detect this notification when the video chip is ready, the ROM code executes a Branch if Line 1 is on to itself.
This causes the CPU to run in endless loop until the line is set on.
The ROM code for the display interrupt loads an screen byte address into the R0 which is then read by the Video Chip until the Video sets EF1 to on (indicating the scan line is before or after the visible part of a CRT screen).
It may be possible to implement an LCD after effect fade screen draw.
This was seen in a calculator computer implementation of Chip8 where the slow un-polarization of the LCD crystal left a half dark pixel.
This could be implemented as a 100% pixel reducing to a 0% pixel with a timed delay.
If the redraw of the object is quick enough it will keep the pixel lit at at less 80% or 60% of the time.
Emulator Assisted Solutions
An alternate system would be to indicate to the emulator where a Video Wait should occur.
This entails identifying the main game loop or loops in the Chip8 program and saving that address.
The address can either be placed in a list of addresses to be checked while processing each instruction.
This may slow down the emulator a little so an alternative may be to alter the binary once it is loaded into memory and replacing the existing instruction with a Video Wait instruction.
When the emulator executes that instruction, it will actually execute a real video wait graphics call.
It will then search through a list of saved addresses and when matched would move back the Program Counter by one instruction and reprocess the instruction using the original value.
This fulfills the need to have a video wait in the main game loop and most of the time improves the game's speed and smoothness.