December Gears emulator update

Debugging a VDP is fun !

January 04, 2023

I wrote here about how I'm writing an emulator. How has it progressed ?

Fixing a rendering bug with backgrounds

In November I wrote on mastodon how I was tracking down a rendering bug.

To track down this issue with weird data on screen, there was already too many messages, so it was very hard to find anything with printf debugging. So I added a border to every bg/sprite character, and encoded the pattern number in the border color. I didn't know if it would work but it looked fun:

Screenshot of a game gear emulator showing sonic 1 game screen, with a grid of various colors for background and spriset.

I then slightly changed the encoding in border color (zoomed for visibility):

Screenshot of a game gear emulator showing sonic 1 game screen, with a grid of various colors for background and sprites.
A color tool from the gimp is measuring border color to get encoded information like pattern number, or background coordinates.

After that, I continued working on unrelated things. I took some time to play the game a bit more in the emulator, which finally gave me an epiphany. Once I had identified the issue, fixing was fairly straight forward. It was missing wrapping in x.

This is because you can imagine the background in the Game Gear VDP as a torus: on this torus, the viewport (the game visible area on the LCD) is a window showing the actual content, controlled by scroll offsets in X and Y.

Of course in memory, this "torus" is just a simple and straightforward memory buffer. So implementing it means wrapping around when the viewport reaches a border of the memory buffer.

Wrapping in Y was working already because rendering is done line-by-line and once the proper line is selected, it stays the same.

Wrapping in X simply wasn't done, so once a border was reached, instead of continuing rendering on the same line, we actually went to the next line ! And it also means that sometimes a line would be rendered that should never have been on screen, hence the weird looking data.

I'll let you compare this screenshot with the previous one:

Screenshot of a game gear emulator showing sonic 1 game screen.
It should look perfectly normal to those who played the game, and is posted to play differences with the previous one.
The difference is that the level is flat: their isn't an extraneous raise of floor level that was there before, as well as a display bug with random data being displayed.

And a final note: I was focusing entirely on the wrong thing here, only seeing the weird data, and not the other rendering bug completely shifting the background screen by 8 pixels.

In the end, the fix was relatively simple.

Implementing missing features

Off-by-one error in sprite rendering

This one was found by looking at other emulators and noticing something weird in Sonic's splash screen :


Before

After (correct render)

Can you see it ?

Here, I added a line to let you see it more easily:


Before

After (correct render)

This is due to the way the coordinates are handled for sprites. They should be offset by one pixel (compared to what I did before) ! Here is another example, zoomed in on Sonic's hand in the Press Start screen:


Before

After (correct render)

Background priority over sprites

On the Game Gear VDP, background tiles have a priority bit that allows them to be in front of sprites. This is very useful to give an impression of depth. Usually it's done so that one color from the background is not above sprites. So blending looks seamless. When rendering the background, the emulator should keep track of patterns that have the "PRIO" bit, and render them always in front of sprites (except for color code "0"). Here is a still from Sonic Triple Trouble before and after implementing background priority:

Sonic triple trouble frame: two trees, a sky background, and game status (HUD) in the upper left corner: 16 rings, 6 seconds remaining, and 1 life for Sonic.

Sonic is in ball form in the air in front of a tree.
Before
Sonic Triple Trouble frame: two trees, a sky background, and game status (HUD) in the upper left corner: 16 rings, 6 seconds remaining, and Sonic lives are hidden behind a tree.

Sonic is in ball form in the air in behind of a tree.
After (correct render)

In this frame the trees are part of the background, and have the PRIO bit set. So they should be rendered over sprites: Sonic, but also the game status in the upper left corner !

Priority between sprites

Here is Sonic 1's first frame:

Sonic is on the left of an empty white screen, facing right, hands out, and in a jumping position.
Before
Sonic is on the left of an empty white screen, facing right, hands out, and in a jumping position.

Sonic's right side is cut in a straigt line.
After (correct render)

What happens here ? Surely the first one is the correct one ? It left me just as confused as you when I looked at other emulator's rendering of this first frame. I even checked on a real Game Gear just to be sure!

The 64 sprites available on the Game Gear/SMS VDP should be rendered one by one, in the order they appear. The first sprites have priority over the later ones. This means the later ones should NOT be rendered if another sprite was rendered on a given pixel (except for transparent colors…).

So what happens on this frame ? Luckily the debug mode I developed earlier is still in the code base behind a config flag that is easy to toggle:

Sonic is on the left of a grid screen, facing right, hands out, and in a jumping position. Sonic's right side is cut in two, by a grid of other white-on-white sprites.

The game uses higher-priority blank sprites to hide the rest of Sonic ! (probably from a re-used routine). This is so that in the animation where the Sega logo appears, it looks like there's a magic line that makes everything appear. And Sonic's feet and hand would go over that line ! So they were hidden by developers by putting blank (but not transparent) sprites before Sonic.

A remaining map bug

There might be plenty of remaining bugs, but here is one I found in Sonic's map screen after I implemented background priority:

Sonic 1 map screen. Sky/sea background and clouds are scrambled.

The first level is showed with a line, and Sonic has 3 lives.
Before (bad)
Sonic 1 map screen. Sky/sea background and clouds are scrambled.
After (still bad, but worse)

The current level line and number of lives disappeared ! Why ? I don't know !

It seems the background priority are incorrectly set. I have no idea why it does this.

After I saw this I thought I caused some kind of regression, so I added a test framework to generate frames and compare them with a "good" render to prevent regressions. This is how most frames in this section where generated, and why the filenames have a weird naming. You can check how it works in the repo and the test frames.

But it's not the only issue for this frame ! Here is how this frame should actually look, if we check how the map is rendered with another emulator:

Sonic 1 map screen. Sky/sea background and clouds are scrambled.
How it looks like currently
Sonic 1 map screen how it should look like.

The first level is showed with a line, and Sonic has 3 lives.
How it should look like

I'm not sure I'll try very hard to fix this one. I'll probably go slowly and think about it in the background, waiting for the right epiphany.

Update: I wrote about how I fixed it.

Share