記事一覧
56件の問題:エンジン全体のレビューで見つかったこと
機能を追加する前に、エンジンとエディタの約6,000行すべてをレビューしました。6件の重大なバグ、スワップチェーンの分割、そしてすべてのVulkanリソースのRAII化。
2026年10月にHydroを再開したとき、物理、パーティクル、3Dレンダラーなど、多くの機能を素早く追加したいと考えていました。何年も見ていなかった土台の上にそれを積むのは危険に感じたので、新機能の前にエンジンとエディタ全体、約6,000行をレビューしました。見つかった問題は56件です。
6件の重大なバグ
- リサイズでレンダラーの半分がリークしていた。スワップチェーンの再作成が、レンダーパス、コマンドプール、コマンドバッファ、セマフォ、フェンス、サンプラーを古いものを破棄せずに作り直し、イメージビューとフレームバッファを2回作っていました。今はサイズに依存するオブジェクトだけを作り直します。
- バリデーションが黙って無効になっていた。GLFWの拡張機能リストがdebug-utils拡張を上書きしていたため、デバッグメッセンジャーが一度も作られていませんでした。さらにReleaseでもレイヤーが有効でした。何年もの「バリデーションエラーなし」には意味がなかったのです。
- イメージのフラグが間違っていた。レイアウトの定数がusageとaspectのフラグとして渡され、ファイルからの画像読み込みではピクセルが実際にはコピーされていませんでした。
- 処理中の複数フレームがデータを共有していた。2Dレンダラーは、同時に処理中のフレーム間で1つの頂点バッファと1つのオフスクリーンイメージを同期なしで使い、インデックスバッファを半分のサイズでアップロードしていました。
- スクリプトがダングリングポインタを保持していた。ネイティブスクリプトが、ストレージを移動させるEnTTのプール内の
thisや、スタック変数のアドレスを保存していました。 - コピペのバグ。
PushOverlayがPopOverlayを呼んでいました。
一番考えさせられるのは2つ目です。他のバグを見つけるための道具そのものが壊れていて、すべてが正常に見えていました。
構造の修正
- スワップチェーンは表示だけを担当。フレームごとのオブジェクトはフレームコンテキストへ、サーフェスはレンダラーコンテキストへ、フレームループはレンダラーへ移しました。
- すべてをRAIIに。すべてのVulkanラッパーはデストラクタで自分を解放します。所有者は
Scope(単独所有)を持ち、利用側は参照を受け取ります。所有するGPUオブジェクトを共有ポインタで持つことはなくなりました。 - 削除キュー。デストラクタはGPUメモリをすぐには解放せず、処理中のフレームが使い終わってから解放するキューに送ります。これでホットリロードとリサイズから
WaitIdleがすべてなくなり、エディタが止まらなくなりました。
そこから生まれたルール
レビューからは独自のスタイルも生まれました。すべてnamespace Hydroの中、!の代わりに== false、すべての本体に波括弧、リソースは仕様の構造体から作成。これらはドキュメントとAIエージェント用の設計スキルに書かれ、のちに規約チェッカーにもなり、同じバグが黙って戻ってくることはありません。
学び:拡大する前にレビューする。その後の数週間で作ったすべての機能は、このレビューでの修正の上に立っています。