One bug or two? (Patreon)
Content
Hi everyone,
we will do another bug hunting session today with graphical glitches. The candidates for this episode are:
- Castrol Honda Superbike Racing
- Primal Rage
Let's have a look at the problems:
There is a motorcycle supposed to be on the right side and you can see it slightly. This may mean that the rendering is ok, but the colors are wrong.
How is Primal Rage?
Looks kind of similar: the content is there, but the colors are wrong.
Whenever colors are wrong, a possible reason is the color palette. The PSX can render using textures with full 15bit color depth or with either 4 or 8bit values mapping to a 16/256 entry color palette.
This is useful to reduce the size of the texture by 75%(4 bit palette) or 50% (8 bit palette).
The color palette is stored together with the framebuffers and the textures in VRAM. Let's see if we can find it.
Castrol Honda Superbike Racing has the same bug also in another loading screen which is not good to show in a screenshot because it's all black, but better to show with VRAM, as it's clearly visible.
You can see this is shortly after the BIOS booted, because the textures from the BIOS are still in the image. If you look very closely, you can see the color palette in the lower left edge of the image. This is 1 frame before the bug.
Now let's see the next frame:
The texture for the splash screen is now loaded to the right side and already rendered to the framebuffer on the upper left side. But the palette is gone.
What happened here is that there is a second framebuffer in the lower left side of the image. The game starts drawing there by clearing the framebuffer with black and then draws using the texture and the palette.
Which palette you may ask now?
Well, the palette is gone in VRAM, but it's still in the GPU. Having the palette referenced for every pixel drawn would be very slow, as it would require a random access in VRAM. Because of that, the palette is cached by the GPU every time a object is rendered and the palette has changed.
The game draws the same object again to the second framebuffer, so it uses the same palette. The developers probably never noticed their mistake, because on a real PS1 this is still drawing right.
There was a bug in the core, where the color palette cache was invalidated already when the palette type changed between 4bit and 8bit. However, this has no effect until the next primitive is drawn and the game switches back to the previous mode before it draws the second frame.
So this might also fix Primal Rage? Unfortunatly no. At this point it seems there are not many bugs left that hit several games, most things are very special.
Let's see what happens in Primal Rage in VRAM:
This is how it should look. You can see the two framebuffers, the textures on the right and a bunch of color palettes below the framebuffers.
What happens with the bug?
The textures on the right look the same, but the color palettes in the lower left edge look as if some of the pixels are gone. How could this happen?
It turns out, that drawing to the lower framebuffer will overwrite a color palette pixel when the drawn pixel is not black. But how is this supposed to work then?
This bug only happened about 50% of the time, so we can see what the difference is. I was very lucky this time to look for anything odd and noticed a GPU command that is very rarely used at all:
The "Get GPU Info" command can be used to read out the settings that have previously been written to the GPU. Several of these settings return the position of the framebuffer to be drawn to, called "Draw area".
Usually games know where they drawing and don't have to ask the GPU for that, but this is very useful for us, because the response differs:
When the bug happens, the returned value for the Draw area top is 256 and when the bug is not there it's 0.
This is easily explained with the language select screen that this game shows before, which also draws to different framebuffers. So does this game depend on the time when you select the language?
That makes no sense, so let's look one step further: what happens in the commands before the "Get GPU info". Maybe there is a clue?
Yes indeed, one of these commands is the softreset:
This command does reset most parts of the GPU.
What we are looking for is the "Draw area". Can you see it? Probably not and me neither. That's why i didn't implement it into the softreset.
But you need to look closer:
<code>"GP0(E1h..E6h) ;rendering attributes (0)"</code>While being cryptic, this line tells you that every parameter set with the commands E1..E6 will be reset to zero. The commands E3 and E4 will set the Draw area. My bad for not thinking enough about this line.
With the Draw Area included in the softreset, the game will always read the starting framebuffer that it depends on and not overwrite the palette anymore.
You may ask now why the palette wasn't just cached like in the Castrol Racing? The answer is very good visible in the VRAM image: there are multiple palettes used for drawing the title screen. One for the background and several for the texts and the GPU can only cache one of them. So the cache is invalidated all the time and all the palettes must still be fully there in VRAM.
That's it for today. While the first fix is already in the last release, the Primal Rage bugfix is not yet and will be included in the next release coming soon.
Have fun!