Hacker News
points by peggigulgow 4 days ago | 0 comments
The 3DS fillrate budget is the interesting constraint here. F-Zero X was already doing a lot with the N64 T&L pipeline; mapping that onto a tiled GPU without dropping the 60fps target is the part I'd want more numbers on.
[–] coffeesoda 4 days ago
Good instinct, the bottleneck is on the CPU side though. The PICA200 is an immediate-mode GPU not a tiler.

Other F-Zero X ports feed the N64 display lists to an interpreter, command by command, with the T&L on CPU. Pre-v1.0 of this port took that approach but did some double buffering on another CPU core.

When porting to Old 3DS, that other core wasn't an option, so we had to make better batch calls to the GPU. It ended up being that now we walk that list the first time and group triangles that share the same material, and moved the position & rotation transformations to the GPU too.

Rather than creating the mesh for tracks out of the spline on the fly, it also precomputes at the start of the race.

I'm fairly certain this is a pretty novel implementation for a N64 to 3DS port.

Most of these optimizations are just for race elements, which is why some of the menus are still pretty laggy.

[–] TuxSH 4 days ago
> Good instinct, the bottleneck is on the CPU side though.

Have you, or rather your agents, tried to identify which CPU functions were the bottlenecks (e.g. in citro3d, perhaps)?

I find it surprising that your stuff is CPU bound. Are you doing one command-list submission for _both_ eyes (with one drawcall for each)? This should be relatively simple, only require viewproj matrix changes and avoid CPU<>GPU roundtrips.

If not, you are going to hit IRQ dispatching costs as well as shardmem dispatching costs as well as other costs.

[–] coffeesoda 3 days ago
Bypassing Citro3D for raw PICA200 commands cut our per-draw CPU cost by 15x (11 µs to 0.7 µs). After that, there's no single hot function left.

The remaining bottleneck is the o3DS instruction cache. Our code is bigger than the 16KB L1, so the CPU spends a big chunk each frame waiting on instruction fetches.

We build the list for left eye, submit, and then re-submit the list offset for the right. Hadn't tried chaining both into one submission, it improved performance. Thanks so much for the suggestion!

Thanks for taking a look and the great questions. I really appreciate your contributions to the scene.