2025/12/04 0:30
Why are my headphones buzzing whenever I run my game?
RSS: https://news.ycombinator.com/rss
要約▶
要約(≈280文字)
本プロジェクトは Rust と wgpu‑rs を使ったアイソメトリックゲームで、起動時にヘッドホンがビープ音を発する問題が発生。GPU の負荷は低いものの、ピッキングテクスチャ全体を毎フレーム GPU→CPU にコピーすると USB オーディオと干渉しバズりが出ることが判明。外部電源に切替で消失したため、PC 内部電力供給が原因と結論付けられた。最終的に「カーソル下の小領域のみをコピー」する選択的ダウンロードを実装し、ノイズは完全に解消されパフォーマンスも向上した。
本文
背景
私は Rust で書かれた自前の簡易エンジン(wgpu‑rs を使用)を使い、Gnomoria、RimWorld、Dwarf Fortress などに触発されたアイソメトリックゲームを開発しています。ゲームを起動するとヘッドホンがビープ音を発します。同じヘッドセットは Fortnite、Overwatch など他のゲームでは問題なく使用できるため、私のゲームだけで発生するバズりです。
環境は以下の通りです:CPU、3090 RTX GPU、32 GB RAM、USB 経由で MODI 2 DAC を接続。MODI デバイスへの電源は PC の USB ポートから供給しており、ポートを変えても同じ結果でした。最初は古い PSU などの電源問題だと考えましたが、軽量なゲームでより大きなノイズが発生する理由が説明できません。
レンダリングを無効にするとバズりがなくなるため、CPU 負荷ではありません。ゲーム中も GPU 使用率は低く抑えられています。
パイプライン
グラフィックパイプラインは WebGPU(wgpu‑rs)で構築しています。まずコンピュートパスで可視エンティティを選択し、次にそれらのエンティティに対して間接描画を行います。レンダーパイプラインでは以下二つを出力します。
- 画面に表示されるフレームバッファ
- “ピッキングテクスチャ”
ピッキングテクスチャはマウスピッキングの簡易手法です:各オブジェクトが自身の EntityID を対応するピクセルへ書き込みます。プレイヤーがクリックしたとき、カーソル下のピクセルを読み取り、選択されたエンティティを判定します。
フレーム毎にそのピッキングテクスチャ全体を GPU メモリからシステム RAM にコピーし、クリック時にマウス位置と比較できるようにしています。GPU と CPU 間で大量のデータ転送はコストが高いですが、この手法は実装とデバッグが容易だったため採用しました。
レンダリングがヘッドホンバズりを引き起こす理由
問題がレンダリングに関連していることから、GPU 作業の何かが USB オーディオ信号と干渉しているはずです。GPU の負荷は低いので、単なる電力消費の問題ではありません。
原因を特定するためにパイプラインの各部分を段階的に無効化しました:
- まずコンピュートパスを削除
- 次にレンダリングパスを削除
- 最後にピッキングテクスチャを RAM にコピーする処理を停止
ピッキングテクスチャのダウンロード全体を完全に省略したとき、バズりは完全に消えました。再度有効化すると低音量でバズりが戻りました。250 ms 毎に転送を繰り返すとほぼノイズが消え、頻度を上げると再びバズりが増加しました。
したがって、ピッキングテクスチャ全体のダウンロードが干渉源であるようです。他のグラフィックスエンジニアからは「GPU がワークブースト後にデータ転送を待つ間、一時停止し、次フレームで再び負荷をかける」ための “stutter” が USB オーディオ信号に干渉する可能性があるという仮説があります。
この仮説を検証するために MODI デバイスへの電源を PC ではなく外部供給に切り替えました。結果、バズりは止まりました。これは GPU 活動とデータ転送中の PC の電力供給が干渉源であることを示唆しています。
解決策
最も簡単な修正は「毎フレーム全体を転送する」のではなく、カーソル下にある小さな領域だけをコピーすることです。選択的ダウンロードを実装した結果、バズりは完全に消えました。GPU トレースを見ると、そのテクスチャの転送が全く行われていないことが確認できます。
この変更により、干渉問題の解決だけでなく、不要なデータ移動を削減してパフォーマンスも向上しました。