Rendering on the Spectrum sucks


The biggest problem for anyone writing games on the ZX Spectrum is not the CPU speed - the Z80 was actually pretty quick for the time - it is the total absence of hardware for drawing sprites, tiled backgrounds and so forth.  Unlike many other contemporaneous machines,  all that was available in the Speccy was an area of memory mapped to the display, from address 16384 (4000h) onwards.  If you want to draw to the screen, you have to write numbers into that area of memory which match the pixels you want to see.  Drawing a 16x16 pixel sprite involves writing 32 bytes for the bitmap (8 pixels = 1 byte), and 4 bytes for the colour attributes. These operations become way more costly when you need to 'blend' with the background, or apply a mask, or when sprites do not fall on nice 8 pixel boundaries.  Costly equals slow, and slow equals crappy frame rates.

Given this, it was extremely fortunate that the Z80 was relatively fast for the time. It had to be fast, because most of its time had to be spent writing lots of numbers to the display memory. If it hadn't been as fast, the Speccy simply wouldn't have been a feasible platform for any games worth mentioning, and history would have been completely different.

I wanted my game to run at 50fps.  It mostly does, although the frame-rate drops in some rooms with a lot of moving sprites.  To achieve this, I targeted the 128K model only.   The reason for this is that the 128K model has RAM banks which can be switched in and out, and more specifically of interest to me, there are two RAM banks that can be switched into the display memory area - the 'normal' and 'shadow' banks.  My rendering pipeline uses both banks to create double-buffering, i.e. one frame is drawn to one of the banks, and the next frame is drawn to the other bank, and finally the banks are switched.  This eliminates the 'tearing' you may have seen in many Speccy games.

The pipeline works like this:

- On entering a room, the tiles of the room are drawn to BOTH banks.

- Each frame, sprites are drawn to the 'back-buffer' bank, and the bounding box of each sprite is recorded in that bank

- The back-buffer is switched in after a vertical sync (becoming what is shown on the screen)

- In the new back-buffer (the screen that has just been switched out), we go through all the bounding boxes that were previously recorded, and redraw the background tiles in those areas. This erases the sprites drawn in a previous frame to this particular buffer.

This system means that we only write to the display RAM when absolutely necessary, the least amount of writes possible.  The player sprite is by far the most expensive operation due to it having a background mask and need to be drawn at any pixel location, whereas all other sprites are very quick to draw, especially sprites with vertical movement.

It took a real long time to get this system working properly, but when it did it left me with on average half a frame's time to update the game, play audio etc.  This also meant that the player could move very smoothly, and not jittery and slowly as in many classic Spectrum games.

I would hazard a guess that most games that were written for 48K and 128K Spectrums in the 80's did not have a system like this - the cost of writing a custom system for the 128K would not have been feasible.  The major difference back then between 48/128 was that you could load the whole game at once for the 128 instead of multi-loading on the 48 (oh, and loudspeaker beeps vs 3 channel audio!). You're shooting yourself in the foot financially by targeting the 128K only.  I didn't have these concerns, so I could experiment as much as I liked.

Get Octavius Kitten (The Game!)

Leave a comment

Log in with itch.io to leave a comment.