07 · Pushing the boundaries

Pushing the boundaries

Two comparisons. First against this port's own New 3DS build: what the Old 3DS forced that the New 3DS never needed, and what comes back the other way. Then against other N64 projects on the 3DS, from their own READMEs and press, each claim linked. Where we could not check something, the page says so.

Against our own New 3DS build

The first phase (2026-08-11 to 09-03) shipped the New 3DS build on a render-thread approach: libultraship's display-list interpreter, moved to its own CPU core so it runs a frame ahead of the game. The Old 3DS has no second core to give that interpreter, so the second phase (09-07 to 10-19) built a different route: a native renderer that skips the per-frame display-list walk for the geometry a race spends its time on. At v1.0.0, with no gdiffuser.ini, that native renderer is the default on both consoles: [perf] preset = auto resolves the New 3DS to the same n60 lever set as the Old 3DS, render thread off. The render-thread path is still built in and reachable with an explicit ini. The table below compares the two approaches on their own terms.

New 3DS buildOld 3DS build
Race rendererlibultraship's display-list interpreter (Fast3D) on its own CPU core, one frame ahead of the game — the first-phase architecture, still built in and reachable with an explicit ini, but not the v1.0.0 default (see note above)The native renderer: one small loop per race category over a game-state snapshot, writing PICA200 command words directly; the interpreter remains for menus and the long tail of other screens
What limits the frameCPU instruction count in the interpreter and the bridge that feeds it (the GPU itself was not the bottleneck: about 0.4 ms per frame in the emulator)Instruction-cache misses, not instruction count: at 268 MHz with no L2 cache, the render path ran at 4.34 cycles per instruction with 43.6% of cycles stalled on instruction fetch, so the interpreter's own code did not reliably fit the 16 KB L1 instruction cache
CoresA render thread on the second core, one frame ahead of the game, when that path is selected; core 2 backs the audio threads under the v1.0.0 default (native renderer, render thread off)No second core. One core does everything but audio, which gets a 60% share of the other (raised from an initial 30% default after a hardware A/B showed 30% caused heavy audio padding)
Memory124 MB app-mode budget, 16 MiB RDRAM arena64 MB app-mode budget (half the console's 128 MB FCRAM is reserved for the system); RDRAM arena halved to 8 MiB plus a 16 MiB linear-heap pin, 38.9 MB of heap left for the game
AudioHeadroom to spare in the synthesis budgetSynthesis' CPU share was tight enough against that grant that it was raised from an initial 30% to 60% during the port: narrowing the audio lock (−20 ms of race-wall waiting per frame) and hand-tuned ARMv6 SIMD decode kernels (2.2× cheaper) closed the gap
Stereo 3DPer draw: the packed vertex buffers replayed with a second matrix for the right eye — the first-phase mechanism, used when the render-thread path is selected; the v1.0.0 default uses the Old 3DS's per-frame mechanism instead (next column)Per frame: the recorded command stream resubmitted for the right eye with a per-eye uniform, interleaved in chunks, with its own swap-pacing mode
Hardware resultFull Grand Prix, end of the first phase: median 59.6 fps, p10 51.4, 53% of frames at the 60 cap16.5 ms median frame time on a full 2D Grand Prix race, 0 hitches; 59–60 fps in 3D on most Grand Prix courses, with the heaviest courses (Silence, Sand Ocean) able to trip the frame-skip safety net to a steady 30 fps mid-race — see Old 3DS for the full campaign. Measured with a different harness (frame time and a vblank-hold share, not the fps/p10/cap-% stats above), so not directly stacked against the New 3DS row
Correctness gateExact parity with the interpreter checked for every performance lever, on and offThe game's own per-tick state hash must match exactly; pixels are checked within a tolerance; an on-console verify mode re-checks every GPU command word the native path writes

What the Old 3DS forced that the New 3DS never needed

What carries back to the New 3DS

ChangeStatus on the New 3DS
A fix for a freeze when backlight/HOME handling toggled the screen offApplies to both models. The New 3DS build never showed the freeze in practice, because no New 3DS HOME test happened to run with the bottom screen off
A save-persistence fix for a rare corrupted save on power lossThe underlying cause is in how the SD card's filesystem handles a file rename, not anything model-specific, so the New 3DS build is believed to carry the same fix; not separately confirmed on a New 3DS log
A never-blocking file log and hitch-detection receiptsModel-independent; applies to both
The native renderer, NRR, the per-eye stereo resubmit, and the end-of-frame pacing/frame-skip stack built for the Old 3DSCarried back as the v1.0.0 default: with no ini, preset = auto resolves the New 3DS to the same n60 lever set, render thread off. An explicit ini can still select the old render-thread/per-draw-stereo path instead
The two audio tuning levers added for the Old 3DS's tighter CPU-share budget (audio_ctx_narrow, audio_simd)Also on by default for the New 3DS now, bundled into the same n60 preset, even though the New 3DS was never short on audio headroom
The Old 3DS's reduced-memory build profileOff for the New 3DS build, which is otherwise unchanged by the Old 3DS work

Against the field

Searched on 2026-10-08, with results still current at release. Every row is what the project or the press says about itself; none of these figures were measured by us, and the games differ in load, so this is not a benchmark. Our own figures come from our hardware logs.

ProjectSourceApproachWhat it says about Old / New 3DS performanceStereo 3D
Super Mario 64 3DS port (mkst)mkst/sm64-port, branch 3ds-portDecomp PC port; renderer details not in the READMEREADME: "Naïve frame-skip if frame takes longer than 33.3ms"; a 60 FPS enhancement patch is listed. Press (2020): "a solid 30fps", model not stated (VGC)Yes (README)
Ocarina of Time 64 3DS portAndresac90/OOT-64-3DS-Portzeldaret/oot decomp; renderer started from the SM64 PC port's Fast3D rendererREADME: New 3DS "60 in 2D and 3D" by interpolation (measured on hardware). Old 3DS: "about 15–17 in the biggest scene (Kokiri Forest), around 45 in interiors" (measured at simulated Old 3DS speed); "60 everywhere is still being worked on"Yes
Majora's Mask 64 3DS portAndresac90/MM-64-3DS-Portdecomp"Nothing runs on the 3DS yet"–
Smash 64 for New 3DS2gifts/smash64-3dsdecomp; credits the SM64 3DS graphics backend, citro3d; renders on the New 3DS's third core"Original 3DS/2DS models are not supported"; "a locked 60 FPS is not guaranteed in every situation"Yes
Mario Kart 64 3DSEstebanPdN/mario-kart-64-3dsSpaghettiKart (libultraship) based; Fast3D vertex/texture ranges, combiner plans compiled once per material"retains its original 30 Hz game simulation"; an adaptive interpolated midpoint frame on Old and New 3DS, "not a promise of a fixed or sustained 60 FPS mode"Not mentioned
Ship of Harkinian 3DS999sian/soh-3dslibultraship (SoH); PICA200 renderer on citro3d, built for F3DEX2New 3DS is the main target; "Old 3DS uses native 20 FPS presentation"; "Physical Old 3DS gameplay is not yet verified"Not mentioned
rt64-3dsoneup03/rt64-3dsRenderer for N64ModernRuntime static recompilations: F3DEX2 interpreter, CPU vertex transform and lighting, per-eye replay"Under construction. First target is Donkey Kong 64 (New 3DS only)"; no frame ratesYes
sm64coopdx New 3DSPR #26citro3dNot yet called playable; "30 FPS stability" listed as a next gate–
DaedalusX64-3DS (emulator)GameBrew, Wololo 2020HLE emulator, ARMv6 dynarec"Tested on N3DS, runs about at 20-30FPS on average" (v1.0, 2022-10-16)Not verified
Ocarina of Time 3D (Nintendo/Grezzo, 2011)Nintendo LifeRemake, native 3DS engineMiyamoto: "It ran at 20fps on the Nintendo64, but on the 3DS, it runs at 30fps"Yes
Star Fox 64 3D (2011)Nintendo Life reviewRemakeNumeric frame rate: not foundYes

What we can and cannot say