Exploring Space Harrier and Afterburner 32x
Moderator: BigEvilCorporation
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
Exploring Space Harrier and Afterburner 32x
After failing to be able to get any kind of decent performance out of my attempts at a super-scalar type engine, I decided to investigate what Space Harrier and Afterburner do to get their very reasonable 30fps performance. This is where I'll put my findings.
I originally wanted to focus on Afterburner because it has the largest number of sprites on screen, but there are no emulators that I could find that both run the game and can display diagnostic information like registers or dump raw vdp data. Gens/GenKmod has the features I need but can't actually run the game. But since it runs Space Harrier, I decided to concentrate on that instead. According to MobyGames, Space Harrier 32x and Afterburner 32x were done by the same company, with both projects sharing the same programmers. This leads me to believe that both games must be using similar techniques. So learning one should help with the other.
Because GensKmod has source code and has a pre-made Visual Studio solution, I could easily build, run, and debug it. It also lets me modify it to perform deeper investigations, like tracking memory writes to vram. I hooked myself into vram writes so I could see how sprites and other elements were being drawn. I also added a feature to take a screenshot after every write to see the progression of drawing a frame. Yes, this created a LOT of screen shots. One frame generated over 32 thousand images, meaning the game writes at least that many pixels on screen per frame.
Here are some of my findings. They might be completely wrong so any corrections will be appreciated!
Space Harrier's opening zooming Sega logo is rendered in the RLE video mode. Didn't expect that at all. I wonder if they did it for performance when the logo takes the whole screen. It's the only object on screen, so converting the scaled logo to RLE format should be pretty straightforward.
The Space Harrier title screen isn't one fixed image. It draws a row of trees and then the monsters, the player and logo one after the other. Lots of overdraw but the performance is not that important.
The video mode during gameplay is 16 bit. I didn't expect this either. My first super scalar experiments worked in 8 bit mode. Rendering 70 32x32 sprites gave me performance in the single digits fps. The idea was that working with 8 bit pixels would be "faster" because there's less data to copy around. But after seeing Space Harrier reach 30fps drawing in 16 bit mode, it made me realize that's not the case at all. There's a definite penalty to writing 8 bits to vram. I switched over my experiments to use 16 bit and I can now easily reach 30 fps with the 70 32x32 sprites. With 100 sprites I got around 20fps. Way better performance now and gives me more confidence that I'll be able to each something similar.
- Space Harrier has a max number of objects of around 30 to 35 on screen. This includes the player, monsters, world objects, shadows and projectiles. If I can reach 30fps with 70 objects, it sounds reasonable that I can get similiar performance. Space Harrier also renders the checkerboard ground, which can take up to maybe 2/3 of the screen.
- Space Harrier doesn't minimize overdraw at all. It just draws everything on top of each other, back to front.
- UI elements and text is drawn to the screen using longs.
- Every frame, the drawing goes like this: the screen gets cleared from the top of the screen to the horizon. Then it draws the ground one pixel at a time, until the last 10 rows or so, just above the "STAGE" text. That remaining part gets filled using a different technique. Then the objects are drawn front to back, and finally the UI elements.
- Space Harrier doesn't do any byte writes to vram.
- The part where it clears the top of the screen to the horizon doesn't trigger my hooks into VDP ram. I wonder if it's being cleared with the FIll function and it just doesn't trigger the same kind of writes. Or maybe DMA? I haven't hooked into any DMA routines (or even know where they are) to see if they're getting triggered.
- The part where the game fills the bottom 20 rows of the checker board ground may be doing the same thing. It doesn't write into vram like the rest of the ground, which is odd. I wonder what's so special about that part. And I wonder where the graphics information is coming from. Is the slave CPU rendering it? No idea at the moment.
- The city scape/mountains/whatever above the horizon is an MD plane.
- The top scores list is also on an MD plane. When it appears on screen, the game seems to stop rendering the 32x side.
- Because the game is running in 16bit and can't fit a full 320x224 frame it has a shorter vertical resolution. I think it's 204. The 32x still renders 224 rows so the line table is used to make the first and last 10 rows black. It does make me wonder where that black line is coming from since there's no more room in video ram. Maybe the game is rendering in 203 rows and using 11 black lines.
- Game sprites are drawn one pixel at a time, and processes even transparent pixels. You can see this when it draws the top part of the large explosion which has lots of empty space (see video below). I imagine a fair bit of drawing time could be saved by removing the leading/ending transparent pixels and even large empty areas.
- As for Afterburner, while I can't run it in Gens, I can run it in Kega and it doesn't have the top/bottom bars that Space Harrier has. This leads me to believe that it's not running in 16 bit mode. Most likely in 8bpp mode. RLE is of course possible but computing it might be too complicated.
- I think it's in 8 bit because it needs to write a lot more data for a lot more sprites and writing in words is a lot more efficient. Write two pixels for every word. Scaling a sprite row in words prevents perfect per-pixel scaling and indeed the scaling doesn't appear to be as nice as Space Harrier. The game looks like it's "scaling in two's" as guessed by Sik.
- If the game is truly drawing sprites by word, then it has to handle cases where the sprite lands on odd addresses. From what I remember from the SH2 docs, the CPU doesn't like (or even doesn't let you) write words to odd addresses. So there'd be cases where the first and last column of a sprite will be draw one pixel at a time. But that means that the source address might be odd as well. I don't know yet if the game handles all those cases or avoids that problem completely somehow. The same problem appears in the case of clipping a sprite against a side edge, the source might begin at an odd address. You could avoid the problem I think if you had two versions of the same sprite, with one offset by one pixel. But that of course doubles your sprite ram usage which makes it seem silly. But right now I can't prove what it's doing either way.
- in either game, I have no idea yet how it's using the slave CPU. It would make sense that it's helping somehow.
That's all I got so far!
I originally wanted to focus on Afterburner because it has the largest number of sprites on screen, but there are no emulators that I could find that both run the game and can display diagnostic information like registers or dump raw vdp data. Gens/GenKmod has the features I need but can't actually run the game. But since it runs Space Harrier, I decided to concentrate on that instead. According to MobyGames, Space Harrier 32x and Afterburner 32x were done by the same company, with both projects sharing the same programmers. This leads me to believe that both games must be using similar techniques. So learning one should help with the other.
Because GensKmod has source code and has a pre-made Visual Studio solution, I could easily build, run, and debug it. It also lets me modify it to perform deeper investigations, like tracking memory writes to vram. I hooked myself into vram writes so I could see how sprites and other elements were being drawn. I also added a feature to take a screenshot after every write to see the progression of drawing a frame. Yes, this created a LOT of screen shots. One frame generated over 32 thousand images, meaning the game writes at least that many pixels on screen per frame.
Here are some of my findings. They might be completely wrong so any corrections will be appreciated!
Space Harrier's opening zooming Sega logo is rendered in the RLE video mode. Didn't expect that at all. I wonder if they did it for performance when the logo takes the whole screen. It's the only object on screen, so converting the scaled logo to RLE format should be pretty straightforward.
The Space Harrier title screen isn't one fixed image. It draws a row of trees and then the monsters, the player and logo one after the other. Lots of overdraw but the performance is not that important.
The video mode during gameplay is 16 bit. I didn't expect this either. My first super scalar experiments worked in 8 bit mode. Rendering 70 32x32 sprites gave me performance in the single digits fps. The idea was that working with 8 bit pixels would be "faster" because there's less data to copy around. But after seeing Space Harrier reach 30fps drawing in 16 bit mode, it made me realize that's not the case at all. There's a definite penalty to writing 8 bits to vram. I switched over my experiments to use 16 bit and I can now easily reach 30 fps with the 70 32x32 sprites. With 100 sprites I got around 20fps. Way better performance now and gives me more confidence that I'll be able to each something similar.
- Space Harrier has a max number of objects of around 30 to 35 on screen. This includes the player, monsters, world objects, shadows and projectiles. If I can reach 30fps with 70 objects, it sounds reasonable that I can get similiar performance. Space Harrier also renders the checkerboard ground, which can take up to maybe 2/3 of the screen.
- Space Harrier doesn't minimize overdraw at all. It just draws everything on top of each other, back to front.
- UI elements and text is drawn to the screen using longs.
- Every frame, the drawing goes like this: the screen gets cleared from the top of the screen to the horizon. Then it draws the ground one pixel at a time, until the last 10 rows or so, just above the "STAGE" text. That remaining part gets filled using a different technique. Then the objects are drawn front to back, and finally the UI elements.
- Space Harrier doesn't do any byte writes to vram.
- The part where it clears the top of the screen to the horizon doesn't trigger my hooks into VDP ram. I wonder if it's being cleared with the FIll function and it just doesn't trigger the same kind of writes. Or maybe DMA? I haven't hooked into any DMA routines (or even know where they are) to see if they're getting triggered.
- The part where the game fills the bottom 20 rows of the checker board ground may be doing the same thing. It doesn't write into vram like the rest of the ground, which is odd. I wonder what's so special about that part. And I wonder where the graphics information is coming from. Is the slave CPU rendering it? No idea at the moment.
- The city scape/mountains/whatever above the horizon is an MD plane.
- The top scores list is also on an MD plane. When it appears on screen, the game seems to stop rendering the 32x side.
- Because the game is running in 16bit and can't fit a full 320x224 frame it has a shorter vertical resolution. I think it's 204. The 32x still renders 224 rows so the line table is used to make the first and last 10 rows black. It does make me wonder where that black line is coming from since there's no more room in video ram. Maybe the game is rendering in 203 rows and using 11 black lines.
- Game sprites are drawn one pixel at a time, and processes even transparent pixels. You can see this when it draws the top part of the large explosion which has lots of empty space (see video below). I imagine a fair bit of drawing time could be saved by removing the leading/ending transparent pixels and even large empty areas.
- As for Afterburner, while I can't run it in Gens, I can run it in Kega and it doesn't have the top/bottom bars that Space Harrier has. This leads me to believe that it's not running in 16 bit mode. Most likely in 8bpp mode. RLE is of course possible but computing it might be too complicated.
- I think it's in 8 bit because it needs to write a lot more data for a lot more sprites and writing in words is a lot more efficient. Write two pixels for every word. Scaling a sprite row in words prevents perfect per-pixel scaling and indeed the scaling doesn't appear to be as nice as Space Harrier. The game looks like it's "scaling in two's" as guessed by Sik.
- If the game is truly drawing sprites by word, then it has to handle cases where the sprite lands on odd addresses. From what I remember from the SH2 docs, the CPU doesn't like (or even doesn't let you) write words to odd addresses. So there'd be cases where the first and last column of a sprite will be draw one pixel at a time. But that means that the source address might be odd as well. I don't know yet if the game handles all those cases or avoids that problem completely somehow. The same problem appears in the case of clipping a sprite against a side edge, the source might begin at an odd address. You could avoid the problem I think if you had two versions of the same sprite, with one offset by one pixel. But that of course doubles your sprite ram usage which makes it seem silly. But right now I can't prove what it's doing either way.
- in either game, I have no idea yet how it's using the slave CPU. It would make sense that it's helping somehow.
That's all I got so far!
Last edited by djcouchycouch on Fri May 28, 2021 9:11 pm, edited 3 times in total.
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
Re: Exploring Space Harrier and Afterburner 32x
Here's a video of one frame of Space Harrier being drawn, pixel by pixel. You'll notice that it starts from the horizon and the jump when it finishes drawing the bottom of the grid. These are the parts where I think maybe the game is using the FILL function or DMA somehow.
https://www.dropbox.com/s/vfmxcxbxbys75 ... g.mp4?dl=0
https://www.dropbox.com/s/vfmxcxbxbys75 ... g.mp4?dl=0
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
Re: Exploring Space Harrier and Afterburner 32x
I've managed to prove that Space Harrier uses the Fill function to clear the top part of the screen and to fill the bottom of the ground.
I've also looked at Shadow Squadron and it uses the Fill function to draw polygon rows, and drawing single pixels for odd addresses, just as expected. The weird thing is that it seems to render to a window half of the width in vram yet displays almost full with (with 16 pixels of empty space on each side).
I've also looked at Shadow Squadron and it uses the Fill function to draw polygon rows, and drawing single pixels for odd addresses, just as expected. The weird thing is that it seems to render to a window half of the width in vram yet displays almost full with (with 16 pixels of empty space on each side).
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
Re: Exploring Space Harrier and Afterburner 32x
Figured out how to properly view Shadow Squadron's VRAM dump. False color (pixels are actually 8bit palette indexes but here interpreted as RGB8) image of Shadow Squadron video ram dump. Orange border is actually black in-game, showing how the game is rendered smaller than 320x224. The top part is framebuffer 0, the bottom framebuffer 1.
![Image](https://i.imgur.com/K5lLZUQ.png)
Here's an image that highlights the byte pixels being draw on odd addresses. The rest of the rows in the image is drawn using the FILL function. I think it's pretty clever how they made dithered polygons by having both bytes in the word given to the FILL function slightly different.
![Image](https://i.imgur.com/Y3OFbO9.png)
Here's me forcing the FILL function to a set color, showing where Space Harrier is using it when rendering a frame. It shows that it's being used to clear above the horizon and the bottom of the terrain. Also, using an 8x8 grid it shows that the black border is 10 rows high on top, and 11 rows high at the bottom. That matches my hypothesis but there's still 200 bytes for the line table unaccounted for.
![Image](https://i.imgur.com/0wmTfFa.png)
![Image](https://i.imgur.com/K5lLZUQ.png)
Here's an image that highlights the byte pixels being draw on odd addresses. The rest of the rows in the image is drawn using the FILL function. I think it's pretty clever how they made dithered polygons by having both bytes in the word given to the FILL function slightly different.
![Image](https://i.imgur.com/Y3OFbO9.png)
Here's me forcing the FILL function to a set color, showing where Space Harrier is using it when rendering a frame. It shows that it's being used to clear above the horizon and the bottom of the terrain. Also, using an 8x8 grid it shows that the black border is 10 rows high on top, and 11 rows high at the bottom. That matches my hypothesis but there's still 200 bytes for the line table unaccounted for.
![Image](https://i.imgur.com/0wmTfFa.png)
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
Re: Exploring Space Harrier and Afterburner 32x
Looking at Afterburner's ram again. Even in it's frozen state I've found two pairs of smoke sprites. They're basically identical except one side's empty space is different. I don't think my hypothesis of the game storing two sets of sprites with one set stored offset by one column is panning out.
![Image](https://i.imgur.com/Ga7w2Tj.png)
As I mentioned before, the game doesn't work correctly in Gens so who knows if it meant to store the smoke effects like that.
![Image](https://i.imgur.com/Ga7w2Tj.png)
As I mentioned before, the game doesn't work correctly in Gens so who knows if it meant to store the smoke effects like that.
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
Re: Exploring Space Harrier and Afterburner 32x
Yeah, I think I know what Afterburner is doing for odd addresses: it completely avoids writing to them. Looking at individual frames of the intro swirling balls animation, there never seems to be a one pixel space. Every time there is space between spheres, it's always a multiple two pixels. And following the motion of a sphere across multiple frames shows that it always jumps two pixels. Being so small and so close together they'd certainly be closer than two pixels, but they aren't. So yeah, I think that's a mystery solved.
![Image](https://i.imgur.com/OC6PEig.png)
![Image](https://i.imgur.com/ZXPT8gA.png)
![Image](https://i.imgur.com/Xln6Zi0.png)
![Image](https://i.imgur.com/OC6PEig.png)
![Image](https://i.imgur.com/ZXPT8gA.png)
![Image](https://i.imgur.com/Xln6Zi0.png)
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
Re: Exploring Space Harrier and Afterburner 32x
So it looks like Space Harrier and Afterburner are each taking opposite trade-offs. Space Harrier is high-quality scaling, low object count and Afterburner is low-quality scaling, high object count.
Re: Exploring Space Harrier and Afterburner 32x
This topic, and everything you have discovered so far, is nothing short of amazing!!!
Congratulations to you!!!
Congratulations to you!!!