F-Zero X 디컴파일 프로젝트 G-Diffuser를 닌텐도 3DS로 포팅한 v1.0.0의 개발 회고다. New 3DS에서 3D로 60fps를 구현한 첫 단계에 이어 Old 3DS 지원, 네이티브 렌더러, 64DD Expansion Kit를 더해 두 기종의 기본 게임과 확장판을 포함하는 세 가지 콘솔 빌드를 만들었다.
첫 단계는 2026-08-11부터 09-03까지 24일 동안 진행됐고, 두 번째 단계는 2026-09-07부터 10-19까지 43일 동안 이어졌다. 한 사람이 전체 방향을 정했고, 장기 실행된 Claude 세션 하나가 작업을 조율했다. 첫 단계에는 하위 에이전트 147명이 참여했으며 두 번째 단계에는 더 많은 에이전트가 참여했다.
첫 단계 마지막에 New 3DS 실기기에서 그랑프리 모드의 중앙 프레임 속도는 59.6fps였다. 첫 에뮬레이터 레이스 때의 12~20fps에서 올라간 수치다. 30대의 머신이 몰린 상황에서 10백분위 프레임 속도는 51.4fps였으며, 프레임의 53%가 60fps 상한에 도달했다. 일주일 전에는 상한에 도달한 프레임이 14%였다. 첫 단계의 24일 중 실제 작업일은 15일이었고, 주간 사용량 한도가 소진돼 세 차례 작업이 중단됐다.
첫 단계에만 해당하는 집계로는 모든 세션과 에이전트가 사용한 토큰이 3.17B, 공개 API 목록 가격 기준 비용이 4,974달러였다. 비용 계산은 Fable의 MTok당 10달러·50달러 요금과 1시간 캐시 쓰기 요금을 적용했다. 3DS 포트에 손댄 커밋은 250개다. 이는 v0.9.0 문서에서 2026-10-08에 동결한 수치로, 최종 이력을 다시 확인한 값은 아니다. 첫 단계 당시 port/3ds에는 15,039줄이 있었고, 순수 델타 패치 48개가 추가로 있었다.
v1.0.0 두 번째 단계에서는 콘솔 빌드 세 가지가 하나의 소스 트리에서 나왔다. Old 3DS용, New 3DS용, 64DD Expansion Kit를 포함한 New 3DS용 빌드다. 진행 상황을 기록한 내부 노트는 199개다. 첫 단계의 하드웨어 성능과 토큰·비용 수치는 2026-09-03까지 측정한 값이며 v1.0.0에서 다시 측정하지 않았다. 에이전트 워크플로에는 두 번째 단계의 진행 방식이, 비용에는 어떤 비용을 계산했고 계산하지 않았는지가 정리돼 있다.
실기기 화면과 빌드 구성
v1.0 New 3DS 화면에는 Expansion Kit의 선택 모드(COURSE EDIT, CREATE MACHINE)가 표시된다. 아래 화면은 DASH의 대기 화면이다. 레이스 중에는 아래 화면에서 에너지, 순위, 랩 타임과 코스 지도를 확인할 수 있다.
아래 영상과 사진은 v0.9(2026-09) 버전에서 촬영했다. 이 버전에서는 아래 화면의 디버그 콘솔을 DASH가 대체하기 전이었다.
*레이스 영상: New 3DS에서 그랑프리를 진행하는 v0.9 화면. 아래 화면에는 포트의 디버그 메뉴가 표시되며, 59.8fps와 힙, 빌드 ID를 확인할 수 있다.
*휴대 모드 영상: 레이스 도중 촬영한 v0.9 화면. 보간 없이 네이티브 60Hz로 화면을 갱신한다.
타이틀 화면은 Homebrew Launcher에서 .3dsx로 실행한 모습이며, 이어지는 사진에는 선택 모드와 머신 선택 화면, Blue Falcon이 담겼다. 사진과 영상은 각각 v1.0 선택 화면, v1.0 레이스 화면, 타이틀 화면, 선택 모드, 머신 선택 화면, Blue Falcon에서 볼 수 있다.
한 소스 트리에서 만든 세 가지 콘솔 빌드는 모두 HOME 메뉴의 .cia 또는 홈브루 런처의 .3dsx로 실행된다. 기본 게임은 Old 3DS·2DS와 New 3DS·New 2DS XL에서 실행되며, 별도로 64DD Expansion Kit를 포함한 New 3DS 빌드가 있다. 이 확장판에는 코스 편집기와 머신 제작기가 들어가며, 사용자가 제공한 디스크 이미지가 있어야 플레이할 수 있다. 모든 빌드는 미리 만들어 둔 에셋 아카이브를 SD 카드에서 읽는다. 게임에 ROM이나 디스크 이미지는 포함되지 않는다.
그랑프리, 타임 트라이얼, 연습, 데스 레이스와 머신 편집 화면을 플레이할 수 있다. 실제 DSP에서 음악과 효과음을 재생하고, 3D 슬라이더로 입체 3D를 표시한다. 아래 화면 대시보드에는 세 가지 HUD 배치와 레이스 밖의 대기 화면이 있다. HOME 메뉴로 나갔다 돌아오기, 종료하기, 덮개를 닫아 절전하기와 전원 끄기도 지원한다.
New 3DS 빌드는 첫 단계에서 확보한 네이티브 60fps 화면 갱신을 유지한다. Old 3DS 빌드는 다른 경로로 비슷한 결과를 낸다. v1.0.0에서는 ini 파일이 없을 때 두 빌드 모두 네이티브 렌더러를 기본으로 선택한다( [perf] preset = auto에서 공백 없이 설정 이름은 [perf] preset = auto다). New 3DS의 첫 단계 렌더 스레드·그리기별 스테레오 경로도 빌드에 남아 있으며, ini를 명시하면 사용할 수 있다. 다만 기본 설정은 아니다. 두 빌드의 비교는 경계와 한계 밀어붙이기에서 볼 수 있다.
기반 구성은 다음과 같다.
decomp: F-Zero X 디컴파일 프로젝트(inspectredc/fzerox)다. 상류 저장소는 수정하지 않고 패치 스택을 적용했다.libultraship: N64 런타임(Kenix3)이다. 상류 저장소는 수정하지 않았다. devkitARM에서 빌드되도록 하는 13줄짜리 newlib 수정이 포함됐으며, 메뉴와 레이스가 아닌 모든 화면을 계속 그린다.port/3ds: 첫 단계 기준 15,039줄이며 이후에도 늘었다. citro3d 렌더링 백엔드, 스테레오, 오디오, 입력, 메뉴, 수명 주기 처리, 렌더 스레드, 프로파일러와 패키징을 포함한다.- 네이티브 렌더러는 두 번째 단계에서 추가됐다. 레이스 지오메트리의 디스플레이 리스트를 매 프레임 순회하는 대신 건너뛰는 자체 인터프리터다. v1.0.0에서 두 기종의 기본 렌더러가 됐다. Old 3DS가 성능을 유지할 수 있었던 이유와 구현 방식은 경계에 설명돼 있다.
첫 단계의 New 3DS 성능 기록
아래 수치는 첫 단계에서 New 3DS 하드웨어로 측정한 결과다. ‘상한 도달’은 60fps 상한에 도달한 프레임의 비율이다.
| 시점·시험 | 중앙값 | 10백분위 | 상한 도달 |
|---|---|---|---|
| 08-14 첫 레이스(에뮬레이터) | 12~20 | — | — |
| 08-21 첫 하드웨어 실행 | 48~50 | — | — |
| 08-28 출시 수준 빌드 | 약 51 | 약 40(군중, MINIMAL) | — |
| 09-02 1차: 캠페인 전 메인라인 | 51.3 | 39.2 | 9% |
| 09-02 2차: 브리지 메모(brfast) | 57.2 | 46.6 | 29% |
| 09-02 3차: HUD 아틀라스·삼각형 메모·TMEM·오디오 | 56.0 | 48.0 | 32% |
| 09-02 4차: 코어 2의 렌더 스레드(pipe) | 57.6 | 44.6 | 14% |
| 09-03 5차: 선행 모드·메인 스레드 브리지·자동 라이벌 디테일 | 59.6 | 51.4 | 53% |
첫 단계 진행 과정
- 08-11~08-14에는 조사에서 첫 레이스까지 진행했다. 타당성 조사 자료와 에이전트 팀 계획을 만들고, 기반 작업 다섯 갈래를 병렬로 진행했다. 부팅 오류 여섯 개를 해결한 뒤 에뮬레이터에서 12~20fps로 첫 레이스를 실행했다.
- 08-20~08-22에는 분홍색으로 보이던 화면을 플레이 가능한 상태로 만들고 실제 콘솔에서 실행했다. 안개, HUD, 도색, 그림자와 하늘을 수정했다. 로드블록에 관한 발견으로 메뉴 성능이 27fps에서 60fps로 올라갔다. 08-21 첫 하드웨어 실행 뒤 “와, 정말 잘 돌아간다”는 반응이 나왔고, 같은 날 저녁 오디오를 추가했다.
- 08-27~08-28에는 제품 수준의 빌드를 만들었다. 에이전트 다섯 명이 한꺼번에 작업을 반영했고, 스테레오, 터치 메뉴, 라이벌 디테일을 추가했다. GPU 정점 변환을 이용한 대형 시도는 구현했지만 채택하지 않았다. 법적 고지를 담은 README와 출시 패키지도 만들었다.
- 09-01~09-02에는 수명 주기 오류를 고치고 마지막 주요 성능 개선을 시도했다. HOME 화면에서 발생하던 충돌과 HOME에서 닫을 때 멈추는 문제를 수정했다. 브리지 출력 캐시는 성능 개선에 적합하지 않다는 결론을 내렸고, 매 프레임 다시 검사하는 대신 각 하위 디스플레이 리스트의 분류 결과를 메모하는 방식으로 바꿨다. LOCKED-60 캠페인을 시작해 네 가지 개선 경로를 병렬로 진행했다.
- 09-02~09-03에는 멀티코어를 활용했다. 코어 2에서 렌더 스레드를 실행하고, 한 프레임 앞서 처리하는 모드와 메인 스레드 브리지, 자동 LOD를 적용했다. 중앙값 59.6fps, 60fps 상한 도달 프레임 53%를 기록했다. 충돌과 뷰포트 배치를 수정하고 스테레오 마커의 위치도 고정했다.
두 번째 단계 진행 과정
두 번째 단계는 처음부터 계획한 작업이 아니었다. 09-07부터 10-19까지 43일 동안 진행됐다.
- 09-07~09-29에는 범위를 정한 뒤 Old 3DS에 맞게 빌드를 줄였다. 기존에 포기했던 Old 3DS 목표를 다시 시작했고, 병렬 작업으로 빌드를 기기의 64MB 앱 메모리 영역에 맞췄다. RDRAM 영역을 절반으로 줄이고, 오디오를 메모리에 상주시킨 대신 스트리밍했으며, 텍스처 업로드에 상한을 뒀다. 2026-09-29 실제 Old 3DS에서 처음 시험했을 때 New 3DS 시대의 16MiB RDRAM 빌드는 부팅 중 멈췄다. 반면 기기의 메모리 할당량에 맞춰
-DGDX_3DS_O3DS=ON프로파일로 빌드한 버전은 같은 시험에서 부팅해 레이스를 실행했지만 약 10fps를 기록했다. - 09-29~09-30에는 실제 비용이 큰 부분을 찾았다. 오디오 잠금 범위를 좁히자 Old 3DS의 레이스 대기 시간이 프레임당 약 20ms 줄었다. 프레임 건너뛰기를 적용해 게임이 의도치 않게 느려지는 현상을 없앴다. 처음 만든 유지 모드 렌더러는 에뮬레이터에서는 큰 개선을 보였지만 실기기 수치에는 거의 영향을 주지 않았다.
- 09-30~10-01에는 계획을 바꾼 프로파일링 결과를 얻었다. 하드웨어 성능 카운터는 실제 한계가 명령어 수가 아니라 명령어 캐시 미스임을 보여줬다. 포즈 재생 방식의 대체 경로를 만들어 작동시켰지만, 사용자의 요청에 따라 보류했다. 사용자는 “진짜 60을 노려야 한다. 아직 가능하다고 믿는다”고 말했다.
- 10-01~10-02에는 명령어 수가 아닌 캐시를 기준으로 네이티브 렌더러를 다시 구성했다. 레이스 종류마다 작은 루프 하나를 두고 16KB 명령어 캐시에 들어가도록 크기를 조절했다. 2D 그랑프리 레이스의 중앙 프레임 시간은 16.5ms가 됐다.
- 10-03~10-08에는 Old 3DS에서도 3D 60fps를 추진했다. 각 눈에 따로 다시 제출하고 그에 맞는 화면 교체 동기화 모드를 적용해, 대부분의 그랑프리 코스에서 3D로 59~60fps를 기록했다. 가장 부하가 큰 Silence와 Sand Ocean에서는 레이스 중 프레임 건너뛰기 안전장치가 작동해 30fps로 고정될 수 있다.
- 10-08~10-19에는 Expansion Kit와 대시보드를 더하고 출시를 준비했다. 네이티브 렌더러에서 64DD Expansion Kit가 틱 단위로 완전히 동일하게 작동하는 것을 확인했고 Old 3DS에서도 부팅했지만, 해당 기기의 속도가 출시 기준에는 미치지 못했다. 아래 화면 DASH를 출시 빌드에 넣었고, 병합 결과를 지속적으로 대립적 관점에서 검토한 뒤 v1.0.0을 출시했다.
두 번째 단계의 진행 방식은 에이전트 워크플로, Old 3DS 작업의 상세 기록은 Old 3DS에서 확인할 수 있다.
더 읽을 자료
- 작성자 노트: 사람이 작성한 한 페이지다.
- 전체 진행 기록: New 3DS부터 v1.0.0까지의 연대기다.
- 60fps를 향한 과정: New 3DS 성능 개선을 단계별로 정리했다.
- 네이티브 포크: 포크를 만든 이유와 변경 사항을 설명한다.
- Old 3DS: 268MHz 기기에서 실제 60fps를 목표로 한 과정을 다룬다.
- 한계 밀어붙이기: New 3DS 빌드 및 다른 결과와 비교한다.
- 어려움: 작업 중 맞닥뜨린 문제와 해결 과정을 정리했다.
- 경계: 이 포트가 비슷한 조건의 다른 포트와 다른 점을 설명한다.
- 에이전트 워크플로: 에이전트 팀을 운영하고 작업을 이끈 방법을 다룬다.
- 비용: 토큰, 비용과 하위 에이전트 수를 정리했다.
각 페이지의 수치에는 근거 자료가 있다. Git 이력, docs/research/ 아래의 조사 문서, 하드웨어 로그 또는 비용 페이지에서 집계한 세션 기록이다. 정확한 토큰 수에 공개 API 목록 가격을 적용한 달러 비용처럼 추정치인 경우에는 적용한 가정을 함께 밝힌다.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요