Nightmare in viewport street
And another bug bites the dust... a quite old one, by the way.

Namely, it was reported two months ago in issue #18: missing character models in Homie Rollerz's character select screen. Actually, if you look closely, you can see they were there, but they got compressed to one scanline at the top, which was caused by a bug in the viewport transform.

In 3D graphics terms, the viewport defines how normalized device coordinates of polygons are transformed to screen coordinates, which can be used to render the polygons.

Most games specify a standard fullscreen viewport, but there are games that pull tricks. Homie Rollerz is one of them, the character select screen uses a 'bad' viewport. But, unlike high-level graphics APIs, the DS has no concept of bad viewport. You can input whatever viewport coordinates, it doesn't reject them or correct them.

So how does it behave? Well, if you've been following this, you surely know that the DS looks normal and friendly on the surface, but if you look deeper, you find out that everything is weird and quirky. Viewports are no exception.

That's why the bug stayed unfixed for so long. GBAtek doesn't document these cases, so it's a matter of running hardware tests, observing results, and doing it again and again until you figure out the logic.

For example, here's a test: the viewport is set to range from 64,0 to 128,192. Nothing special there.

shitty triangle

Now, we change the viewport to range from 192,0 to 128,192, which results in a width of -64 (which, by the way, OpenGL would reject). One would say that such a viewport results in graphics getting mirrored, like this:

shitty triangle but mirrored

It looks correct, but that's not what the hardware outputs. In reality, it looks more like this:

shitty triangle stretched

The GPU doesn't support negative screen coordinates or viewport sizes, so they wrap around to large positive values. The range for X coordinates is 0-511, so for example trying to specify a viewport width of -1 results in a 511 pixel wide viewport. Such values are likely to cause the viewport transform calculations to overflow, causing coordinates to wrap around in a similar fashion. This is what happens in the example above -- the green vertex actually goes above 511.

Y coordinates work in the same way but with a range of 0-255. However, one has to take into account the fact that they're reversed -- the Y axis for 3D graphics goes upwards, but the 3D scene is rendered from top to bottom. The viewport is also specified upside-down. Different ways of reversing the screen coordinates give slightly different results, so I had to take a while to figure out the proper way. Y coordinates are reversed before the viewport transform, by inverting their sign. Viewport Y coordinates are reversed too, as such:

finalY0 = 191 - Y1;
finalY1 = 191 - Y0;

Past that, there are no special cases -- the viewport transform is the same, no matter the viewport coordinates and vertices. The only special case is that polygons with any Y coordinate greater than 192 aren't rendered (but they are still stored in vertex/polygon RAM). This is probably because the hardware can't figure out whether the coordinate should have been negative (as said before, it doesn't support negative screen coordinates), and thus can't guess what the correct result should be, so it's taking the easy way out. But this is a bit odd considering it has no problem with X coordinates going beyond 256.

With that, I'm not sure how coordinates should be scaled should 3D upscaling be implemented. But, I have a few ideas. We'll see.

But regardless, after revising viewport handling according to these findings, the Homie Rollerz character select screen Just Works™, and I haven't observed any regression, so it's all good.

Also, release 0.4 is for very soon.
StarTrekVoyager says:
Jul 5th 2017
Actually, that's the first time I reas one of the most technical blogs "in depth", and god, no wonder why Higan needs a 3 GHz CPU. Nintendo consoles seem to have always been a mess with weird hardware and math (this is an example of that) and other hacky things, and the DS is no exception. I hope you manage to get through that though :P
StapleButter says:
Jul 6th 2017
Definitely. Also, getting Y coordinates perfectly right is important -- polygons are sorted by their Y bounds. So a difference of one pixel can change ordering and break layouts that rely on it.
telon22 says:
Jul 9th 2017
"Also, release 0.4 is for very soon."
Can't wait for this :D
huckleberrypie says:
Jul 19th 2017
I can confirm this with Kit Mystery Challenge, as it also suffered from the same fucked-up viewport issue that plagued Homie Rollerz. Same symptoms, i.e. character doesn't show up on screen. In Kit, this can be reproduced by going to the upstairs attic, and clicking on the maroon trunk to access the outfit selection screen. On 0.3 and earlier, Kit doesn't show up, but now she does on 0.4 as expected. Exo fixed this issue some time ago in Drastic, so I'm glad this got remedied here as well.
Post a comment