6502tinymachines

コンソールの窓を計画する

N8 の計画。作業の前に書かれた。

コードより前に書いた (2026-09-06)。スケッチ (第 3 節、N8) が言うのはこうだ: Linux のネイティブバイナリ、コンソール、窓、シェーダに入った CRT の各段 (GPU が働きに見合う唯一の場所)、コントローラ入力、音声出力。ダイのエクスプローラはブラウザに留まる。WASM ビルドは二つ目の標的として生かし続け、別に測る。N6 は壁時計による歩調合わせとドリフト方針をここへ先送りしていた。

すでにあるもの、そして一フレームの費用

picture-bench を full_palette.nes で、一コア (2026-09-06): コンソールが 1 フレーム 7.15 ms、音付きで 13.01。NES の符号化器が 4.96。3 ライン・コムの復号が 28.02。CRT の各段が 54.76。周期は 16.64 ms。つまりコンソールと符号化器は一コアに余裕で収まり、復号と各段は CPU のどこにも収まらない: 101 のうち 83 ms だ。この二つが GPU へ行く。それがスケッチの一文である。

  • ntsc-crt の復号器と各段がオラクルだ。以下のパスはすべて、絵ではなくそれに押さえられる。復号器の定数 (コムの重み、間引かれた UV のローパスとその間引き率、行列、復調のオフセット、黒と白、ガンマ) は復号器自身の公開フィールドであり、インスタンスからアップロードされる。打ち込むことは決してない。
  • ntsc-wasm の Pacing が、すでにテスト済みのドリフト方針だ。ソースは壁時計の一拍ごとに、厳密な周期のフレーム単位でまるごと進む。重複と欠落は数えられ、時間方向に再標本化されることは決してない。素の Rust であり、ネイティブにビルドできる。
  • 6502 の v6502-gpu が一族の wgpu の先例だ (wgpu 22、pollster、ヘッドレスのアダプタ。アダプタが無ければテストは SKIP する)。
  • この箱: RTX 3070 が二枚、ディスプレイのセッションは無し、ALSA と X11 と Wayland のクライアントライブラリは入っている。だから GPU のパスはここでヘッドレスに検査し、バイナリもここでビルドし、それを窓で走らせるのは机の項目になる。

手順

  1. GPU の絵 (crates/nes-shell/src/gpu.rs、WGSL はその隣)。 GpuPicture が CompositeFrame (符号化器のもの、CPU 上で 5 ms) を取り、計算パスとして次を走らせる: 3 ライン・コムと復調 (その行の位相で回した正弦の表、ボックスカーの間引き、間引かれたローパス、Catmull-Rom で戻し、輝度のスケール) を通して YUV へ。行列、クランプ、表示ガンマを通して 2048 x 240 のグリッド上の線形 RGB へ。ビーム (ガウシアンの列を 256 x scale へ)。走査線 (CPU の散らし版に対する集め版、同じ 1e-4 の打ち切り)。残光 (ピンポンする状態、励起と減衰した前回の最大)。マスクとジオメトリは、そのパラメータが Some のときに。出力は (256 x scale) x (240 x scale) の線形 RGB で、検査のために読み戻し、窓のためには blit でガンマ符号化する。

    検査 (tests/gpu.rs。アダプタが無ければ名指しで SKIP し、REQUIRE_GPU=1 が強制する): 連続する三つのコンソールフレーム (テスト用カートリッジ、描画オン) を CPU の連鎖 (Decoder::decode、CrtPipeline::process) と GPU のパスに通す。二回目の走行ではマスクとジオメトリをオンにして、すべてのパスを運動させる。許容はいま述べる: 出力画素すべての成分すべてが線形の光で 1e-3 以内、平均絶対差が 1e-5 以内 (両者は f32 で総和の順序が違い、ライブラリの exp と pow を使う。間違ったパスはこれよりはるかに大きく外れる)。MUTATE=1 は残光のパスを飛ばし、二番目と三番目のフレームは赤にならなければならない。フレーム時間はこの箱で測って記録する。押さえはしない。

  2. シェル (crates/nes-shell/src/main.rs): nes-shell rom.nes。音をオンにしたコンソールが自分のスレッドで厳密なレートで走り、Pacing が表示の一拍ごとにソースのフレームをいくつ進めるかを決める (ゼロなら前の絵をもう一度出し、二つ以上なら欠落させる。どちらも数えて終了時に印字する)。描画スレッドはフレームを符号化し、wgpu のサーフェス上の winit の窓へ GPU の絵を走らせる。整数倍のスケールは 3。音は cpal を通して 48 kHz、コンソールのスレッドが満たすリングから。アンダーランは数える。キーボードがコントローラ 1 だ (矢印、B と A に Z と X、Start と Select に Enter と右シフト、終了に Escape)。ここにあるものは自分の計数器以外の何にも照らして測らない。これはスケッチが求めているものそのものであり、その検査は画面のある机だ。

    ここで検査するもの: 窓なしのシェルの中核ループ (コンソールのスレッド、歩調合わせ、リング) を合成した時計で 120 拍走らせ、計数が算術の言うとおりに出ること (tests/pacing.rs: ちょうど周期のときは重複も欠落も無し。周期の半分では一拍おきに重複し、二倍では一拍ごとに一つ欠落する)。

  3. WASM の標的。 cargo check --target wasm32-unknown-unknown -p nes-console: コンソール、そのラング群、ntsc-crt がブラウザ向けにコンパイルできること (チップの表はビルド時にホスト側で作られる。それがこれを可能にしている)。run_frames を持つ nes-wasm の橋と、1 秒あたりのフレーム数を測る node のベンチが、別に測る二つ目の標的だ。それを載せるページは屋根の項目であり、このリポジトリのものではない。

  4. 梱包と報告。 cargo build --release -p nes-shell がバイナリだ。README が走らせ方とキーの割り当てを述べる。ROM は決してコミットしない。docs/n8-report.md: GPU の検査の数値、この箱でのフレーム時間、歩調合わせの検査、wasm の検査、そして机の項目 (窓、音声デバイス、コントローラ)。

N8 に入らないもの

ゲームパッド (winit はキーボードを与える。gilrs は別の日のためのレジストリの依存だ)。セーブステート、巻き戻し、ダイのエクスプローラ。N5 から N7 のベンチ項目が待っているもの全般。

ビルド時に nes/docs/n8-plan.md から取り込まれる。写しはリポジトリの一つだけだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。