In my quest to make a sidescrolling platformer in mode 15 I have been trying to optimize sprite rendering. It quickly became apparent that drawing tiles is the bottleneck, so this is the first area I tried to improve.
The test consist of a simple program with uncapped FPS that draws a 14x11 tilemap of 16x16 tiles on screen each frame. Basically it draws a full screen image, but drawing a tilemap is more realistic in my particular use case. There are two versions of the test: One that draws the tilemap on an even position, another that draws the tilemap on an odd position. This is because routines are quite different depending on the pixel placement.
The idea behind this post is to discuss those techniques and see what can eventually make its way to PokittoLib. But first the numbers…
This uses the drawBitmapData from PokittoLib.
- Even: 18 FPS
- Odd: 21 FPS
Not much difference between odd and even pixel placement. Surprisingly odd pixel placement is faster which looking at the code shouldn’t. I guess this is due to some obscure O3 optimization.
Optimization 1: Disabling transparency
The first, obvious thing, is to disable transparency as most of the time this is not needed for tiles. So I just disabled the transparency check on the Pokitto routines.
- Even: 35 FPS
- Odd: 25 FPS
The odd frame rate could still be optimzed. My current code simply don’t check for transparency but still performs read on the screen buffer, which could be prevented.
Optimization 2: Even pixel placement
Even pixel placement is much faster and easier to work with (when writing blitting routines). So I decided to rewrite a routine that can only display sprites on an even pixel position, also it only support sprites with even width so that there is no ‘x clip’.
- Even: 42 FPS
This first version is simply a loop that reads byte from the bitmap and put them in the screen buffer. I had a private discussion with @Pharap about the Pokitto CPU and it occurred this is a 32bit CPU so why push 8bit bytes instead of 32bit words? Here is the result with another version that use memcpy to copy the bitmap content to the screen buffer.
- Even with memcpy: 47 FPS
Using even pixel placement
I have been thinking how to use even pixel placement. There could be some ticks such as doubling assets with a normal version and a ‘shifted by 4 bit version’. Or using a screen buffer that is bigger by 1 byte, and perform the shifting when sending data to the LCD. But this all seems overly complicated and somehow still limited.
So I used a much simpler trick which consists of making use of even pixel position as much as possible. This is rather simple: The players moves by 2 pixel each frame, the camera follows the player so it also move by 2 pixels. This insure the background tilemap is always drawn on even position.
Putting it all together
To prove my points and show it works I put together a small demo platformer were you can move, jump and shoot.
Without capping the FPS the game runs between 45-47 FPS. I decided to cap it to 30 FPS so that there is still room for entities and sound, and that the games run at a constant speed. Also 30 FPS is good for porting the game to PC which has a 60Hz vsync.
In this sort demo there are 3 layers:
- parralax background. Only the clouds are drawn, blue is the background color. This layer doesn’t use even pixel placement, it uses optimization 1.
- background. Follows the player so use optimization 2.
- foreground. Same as background put drawn over the player.
dg_0_1.bin (57.6 KB)
This game uses the DeadGunner sprites from Surt of OpenGameArt. By the way I recommend checking other works by Surt, lots of NES style stuffs that could be great Pokitto games!
Note that this is version 0.1 of DeadGunner. I’m planning to continue work on it, hopefully turning it into a full game. But let’s not discuss this here, if there is interest I will create a separated thread.