scenario-godot-performance-export について
Godot 4.7.2 プロジェクトの性能分析とリリース向けスキルです。開発者によるプロファイリング、ボトルネック分類、変更の実測、エクスポート済みビルドの検証を支援します。
主な機能
- 01CPU・GPU・描画データの取得
- 02性能ボトルネックの分類
- 03最適化の適用と比較
- 04ロードやシェーダーの停止調査
- 05各プラットフォームの成果物検証
- 06リリース設定とビルドの監査
活用シーン
- 01フレームレートの CPU・GPU 制約を特定
- 02シーン変更の前後で性能を比較
- 03初回ロードや実行中の停止を調査
- 04リリース前にエクスポートビルドを確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-godot-performance-exportインストール後、Claude Code で/scenario-godot-performance-exportを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/gd_perf.pyscripts/agentkit/perf/mobile_touch.gdperf_audit.gdperf_bench.gdperf_fixes.gdperf_logger.gdperf_stress.gdship_boot.gdweb_bridge.gd詳細
Godot のパフォーマンスとリリース
対象:Godot 4.7.2.stable、macOS Apple Silicon。Android ヘルパーは Windows と Linux でも動作します。
ここでいうエキスパートレベルとは、速度に関する主張すべてに同じハーネスで測定した変更前後の数値が添えられ、出荷と呼ぶ前にすべてのビルドがファイルとして検証され、Godot が誤って報告する数値をエージェントが把握していることです。基本方針:測定し、ボトルネックを分類し、最もコストの大きい要因を修正し、再測定し、画像を比較してから、実際に開いて実行し、一覧に記載したビルドを出荷します。ここで名前を挙げた兄弟スキルが利用可能なスキルにない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人で進める場合は、ツールのスキーマに基づいて作業し、不足している点を明記してください。
必須の背景知識: scenario-godot-expert(チャンネル、レビューの反復、ツールキット、4.7 の落とし穴)。
基本方針(エキスパートとしての違い)
- 修正する前に分類します。 フレーム時間は CPU と GPU の遅いほうで決まるため、反対側を修正しても効果はありません(最適化に関する一般ドキュメント)。実例:ドローコールを 2,501 から 2 に減らすと、CPU 時間は 2.7 ms から 0.35 ms に低下しましたが、GPU 時間は 6.2 ms のままでした。GPU 時間を動かしたのはシャドウの予算だけでした(1.7 ms まで低下)。半解像度のパスを実行します。GPU 時間が低下しない場合、解像度は問題ではありません[追加]。まず
RenderingServer.get_video_adapter_name()を記録します。ハイブリッドノート PC では内蔵 GPU で実行されている場合があります。--gpu-index Nで別の GPU を選択できます[追加]。 - ピクセルより先にノードがコストになります。 ノードごとの
_process、何千ものノード、冗長な物理オブジェクトが、Godot の CPU コストの一般的な要因です(Firebelley 1PnG3r1rKcs:RenderingServer アイテムを使用して 115 ms から約 8 ms に短縮。DwMoEdAhtYQ、O5a4AKemkiQ)。繰り返しの処理は MultiMesh とシェーダーに置き換え、ティック処理を一元化します。実例:2,000 個の MeshInstance3D を 2.3 ms で作成。RenderingServer.instance_create2では 0.6 ms でした。 - 定期処理を分散させます。 ポーラーごとにランダムな位相を設定し、無効化された RayCast に対して
force_raycast_update()を実行します(Dan Does Dev、s2C2RO_WMh0 [00:05:34])。実例:エージェント 600 体で、最悪のティック時間は 1.93 から 0.64 ms に、スパイクフレームは 62 から 16 に減少しました。 - 手のひらサイズのオクルーダーを使い、描画オブジェクト数で評価します。 大きな壁ごとにボックスオクルーダーを設置する方法は、シーン全体をベイクする方法より優れています(Zenva、VBiBZBVxu1s:ベイクでは約 300 から 80 FPS、ボックスでは 350 FPS)。オクルージョンは CPU によるラスタライズです。複数のカメラ位置から描画オブジェクト数を基準に評価します。
- ヒッチの原因は読み込み、パイプライン、実行時のベイクです。 メインスレッド外で読み込みとインスタンス化の両方を行い、ウォーム状態のパイプラインキャッシュを同梱し(Shader Baker のエクスポートオプション、4.5)、フレームごとの
PIPELINE_COMPILATIONS_*の差分を記録して、各ヒッチが読み込みによるものかコンパイルによるものかを分類します。ナビメッシュのベイクや、エリア境界で Always に設定された ReflectionProbes も別の容疑者です[追加]。実例:最悪フレームは、同期処理のコールド状態で 453 ms、スレッドを使った読み込みとインスタンス化ではコールド状態で 230 ms、ウォーム状態で 9.6 ms でした。 - 実際のターゲットで、十分な時間テストします。 Export With Debug でゲームが遅くなることはありません。スロットリングは長時間実行して初めて現れます(Ian Bolton、Arm、WrjaUNAXYqk [00:05:20, 00:09:35])。最も負荷の高いエリアでスマートフォンを 30 分間連続稼働させ、20 分目から 30 分目までをゲート条件にします[期間を追加]。パフォーマンスレポートごとにクリーンビルドを使用します。古いキャッシュが原因で、パフォーマンスの不具合が数週間見逃されました(Claire Blackshaw、grdqHJOL5F4 [00:16:15])。
- エクスポートの失敗原因は環境や認証情報であり、Godot ではありません。 正確なバージョンに対応したテンプレート、JDK と SDK のパス、ETC2/ASTC のインポート、バンドル ID、署名 ID、サーバーヘッダーを確認します。認証情報は
GODOT_*環境変数に設定し、export_presets.cfgには決して記載しません(エクスポートのドキュメント;Nihamkin _n9l15CANag [00:25:38])。 - Web はデフォルトで Compatibility のみ、シングルスレッドです。 スレッドを使用するには、HTTPS 経由で COOP
same-originと COEPrequire-corpが必要です(Web のドキュメント)。実例:ヘッダーなしのスレッド版ビルドは起動しません。 - 書面の計画は、このツールキットなしでも実行できる必要があります。 各
gd_perf呼び出しの横に、それがラップしているエンジンのコードまたは CLI を記載します。たとえば、以下のロガー、godot --headless --export-release、環境変数、bundletool、xcodebuildです。第 1 ラウンドのブラインド評価では、読者が実行できない計画は評価を下げられました。
最初に確認すること
| 入力 | 計画に影響する理由 | 不明な場合のデフォルト |
|---|---|---|
| 対象ハードウェアとフレーム予算 | 60 fps では 16.67 ms、30 fps では 33.33 ms、90 fps(VR)では 11.11 ms、120 fps では 8.33 ms | 名前が挙がった中で最も低性能なデバイスで 60 fps |
| プラットフォームごとのレンダラー | 自動インスタンス化、オクルージョン、機能が異なり、ウェブでは Compatibility が必須です | デスクトップでは Forward+、スマートフォンでは Mobile、ウェブでは Compatibility |
| どこで遅くなるか | 持続的な低 fps なのか、読み込み時や向きを変えたときの一時的なカクつきなのか | 両方をプロファイリングする |
| プラットフォームとストア | 署名、ID、サイズ制限、AAB と APK の違い | 確認する。各ストアでアカウントの手順が必要です |
| ダウンロード予算 | wasm、pck、APK のサイズ | ホストが実際に配信するバイト数 |
| 認証情報の保有者 | キーストア、Apple のチーム、Steam のビルダー | エージェントはシークレットを捏造したり、保存したりしません |
ワークフロー
- クリーンなプロジェクトコピーを基準にします。
gd_env.base_projectでクローンし、gd_perf.install(P)を実行して、application/config/nameの名前を変更します(Base3D のクローンは同じuser://とシェーダーキャッシュを共有するためです)。project.godotを読み返し、3D には Jolt、意図したレンダラーが設定されていることを確認します。重いシーンでgd_perf.scene_auditを実行します。ゲート:監査 JSON を保存し、物理エンジンとレンダラーを確認済みであること。 - ウィンドウ表示で、変数ごとに測定します。
gd_perf.profile_variant(P, scene, size=(1280, 720), driver="vulkan"):フレームごとの CSV、表示およびシャドウのドローコール数、センチネルノードから取得したシーンの_process時間を記録します。gd_perf.install(P)の実行後にsettings、toggles、rendering_methodの各バリエーションを比較します。一方、変更のないシーンに対する単一の判定には、リードのgd_run.profile_scene(driver="vulkan")だけで十分です。フレームごとの測定にPerformance.TIME_PROCESSは使わないでください。約 1 秒間、同じ値を保持します。macOS では Metal が GPU 0 を報告するため、Vulkan を使用します。ウィンドウ表示ではフレーム時間がリフレッシュレートで制限されるため、gpu_ms と cpu_ms で判断します。さらに詳しく調べるには、--gpu-profile、Visual Profiler、スクリプトプロファイラー(Inclusive ではなく Self を確認します。C# は対象外です)、RenderDoc、または 1 フレーム用のベンダーツールを使用します。ゲート:2 回の実行結果の差が 10%以内であること [追加]。 - 分類します。
gd_perf.classify(full, half_res)を実行します。ゲート:数値に裏付けられた判定(CPU スクリプト、CPU レンダリング、GPU フィル、GPU ジオメトリ、またはシャドウ)を文書に記録すること。 - 1 つ修正して再測定し、見た目を確認します。
gd_perf.apply_fix(P, scene, out, fix)は新しいシーンを書き出します。share_materials、multimesh、shadow_budget、box_occluders、visibility_range、strip_process(ラボ専用:シェーダーが処理を担うようになった後で_processスクリプトを削除します)。gd_perf.compare(before, after)は、5%および 0.1 ms のノイズしきい値を適用します。変更前と変更後のキャプチャを取得し、コンタクトシートを作成して開きます。合意した下限値(0.67)を下回る解像度スケールには承認が必要です [追加]。ゲート:指標がノイズしきい値を超えて改善し、悪化した項目がなく、平均輝度差が 0.02 未満であること、または変更が承認されていること。 - ヒッチを確認します。 新しい
private_home(home_envとともに実行)を使ってperf_bench.gd:hitchを実行し、シェーダーキャッシュが空の状態を確認します。ゲート:キャッシュが温まった状態で最悪フレームが予算の 2 倍未満であり、パイプラインコンパイルがゲームプレイ中のフレームに発生しないこと。 - 出荷用ビルドを作成します。
gd_run.ensure_presetとgd_perf.preset_fieldsを使ってプリセットを設定します。home = gd_perf.private_home(...)として、gd_perf.export_env(**gd_perf.home_env(home))の下でエクスポートします。 通常の CLI:godot --headless --path . --export-release "<preset>" <out>。各成果物を検証します:verify_macos、verify_apk、verify_xcode_project、pck_listing、size_report、web_smoke。 ゲート:以下のプラットフォーム別要件を満たすこと。 - エクスポートしたものを実行します。
perf_logger.gdを使ってgd_perf.run_exported(exe, ["--headless", "--", "--perf-log", "--perf-quit"])を実行します。Web はヘッドレス Chrome で実行します。ゲート:SHIP_BOOTに期待されるタグとレンダラーが表示され、PERF_SUMMARYの p95 が予算内で、エラーがないこと。 - リリース監査と引き継ぎを行います。
gd_perf.release_audit(P)を実行し、アカウントを管理する担当者向けに署名、公証、アップロードの手順を記載します(notarize_plan、steam_vdf)。ゲート:重大なフラグがなく、アカウント関連の手順は理由を添えて「未実行」と記載されていること。 スマートフォン。 モバイルレンダラー、またはローエンド端末への幅広い対応には Compatibility を使用します(Ray Hayes, KWhVVMpihsc [00:06:03])。fallback_to_opengl3はデフォルトで有効になっており、見た目が変わるため、フォールバック後の表示もキャプチャしてください [00:05:12]。低性能端末では、scaling_3d_scaleを 0.67~0.8、Engine.max_fps = 30、物理演算のティックレートを 30 に設定し、補間を有効にします(O5a4AKemkiQ [00:03:43])。Android にもセーフエリアを適用してください。実測では 4.7.2 の APK は SDK 36 を対象としているため、Android 15 以降では画面の端まで描画されます[追加]。Android ビルド:--install-android-build-templateはエクスポートコマンドと併用する場合に限り有効です(実測では--quitを付けても何もインストールされません)。キーストアはGODOT_ANDROID_KEYSTORE_RELEASE_{PATH,USER,PASSWORD}に設定し、サイズはbundletool build-apks --connected-deviceの後にget-size totalで確認します[未実行]。サーマル負荷テストでは、10 秒ごとにadb shell dumpsys thermalserviceを記録します。CI では Streamline のリージョンマーカーと Performance Advisor を使用し(WrjaUNAXYqk [00:14:43])、デバイス上のゲーム指標にはPerformance.add_custom_monitorを使います。クラッシュレポーターを組み込み、リリース前に次の OS ベータ版でテストしてください(8zqjiRuhQLE [00:03:40, 00:09:11])。iOS: エクスポートすると Xcode プロジェクトが生成されます。その後、xcodebuild archiveと-exportArchiveを実行します。初回アップロードの前に App Store Connect のレコードを作成し、毎回ビルド番号を増やしてください。Vulkan レンダラーはシミュレーターで使用できません。エクスポート時に「xcodebuild requires Xcode」と表示された場合は、sudo xcode-select -s /Applications/Xcode.app/Contents/Developerを実行します(x_ZFAV2id3I [00:14:41, 00:17:04, 00:40:34])。IAP:ストアのプラグインとアカウントを使い、偽装しないでください。
Web。 スレッドが重要だと実測で確認できた場合を除き、シングルスレッドにします。itch.io はアップロードされたファイルをそのまま配信するため(オンザフライ圧縮なし)、送信されるバイト数を考慮してください。バックグラウンドタブでは _process が一時停止し、ネットワーク対応ゲームが停止します。HTTPRequest はチャンク形式のレスポンスに対応せず、進捗はフレームごとに 1 段階しか更新されません。古いサービスワーカーによって別のプロジェクトが表示されることがあります(Web ドキュメント)。分離後は、クロスオリジンのフェッチに CORS または CORP が必要です[追加]。C# プロジェクトは Web 向けにエクスポートできません(バージョン差分 16)。ブラウザーでのリーダーボードは読み取り専用です。
エンジンのみのフレームロガー(ツールキットなし、2026-10-02 に実行)
extends Node # autoload "Bench"; run the game with: -- --bench
var ai_ms := 0.0
var _vp: RID
var _rows := PackedStringArray(["frame_ms,render_cpu_ms,gpu_ms,draw_calls,pipelines_total"])
func _ready() -> void:
if not "--bench" in OS.get_cmdline_user_args():
set_process(false)
return
_vp = get_viewport().get_viewport_rid()
RenderingServer.viewport_set_measure_render_time(_vp, true)
Performance.add_custom_monitor("game/ai_ms", _get_ai_ms) # a method, never a lambda
print("BENCH adapter=", RenderingServer.get_video_adapter_name())
func _get_ai_ms() -> float:
return ai_ms
func _process(delta: float) -> void:
var pipes := Performance.get_monitor(Performance.PIPELINE_COMPILATIONS_SURFACE) \
+ Performance.get_monitor(Performance.PIPELINE_COMPILATIONS_SPECIALIZATION)
_rows.append("%.2f,%.3f,%.3f,%d,%d" % [delta * 1000.0,
RenderingServer.viewport_get_measured_render_time_cpu(_vp),
RenderingServer.viewport_get_measured_render_time_gpu(_vp),
Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME), pipes])
func _exit_tree() -> void:
if is_processing():
Performance.remove_custom_monitor("game/ai_ms")
FileAccess.open("user://bench.csv", FileAccess.WRITE).store_string("\n".join(_rows))
パイプラインカウンターは累積値です。合計が増加したヒッチ行はコンパイルを示します。最初の数フレームでは GPU 時間は 0 と表示されます。
数値
| 値 | 比較対象 | 出典 |
|---|---|---|
| hitch = median の 2 倍を超えるフレーム | 実行ごと | toolkit [追加] |
| 2,501 から 33 draw calls | 2,500 cubes、共有マテリアル 8 個、Forward+ | 実機、オートインスタンシング |
| 2,501 から 2,501 | Mobile で同条件 | 実機:オートインスタンシングなし |
| 400 個の透明な cube:1 draw、交互に使うマテリアル 2 個:117(不透明:2) | Forward+ | 実機:深度ソートによりバッチが分割 |
| 400 Label3D:800 draws、共有 TextMesh 1 個:1 | Forward+ | 実機:アウトラインとテキストはインスタンス化されない |
| omni shadow:Cube(デフォルト)19 draws、Dual Paraboloid 2 | Forward+、キャスター 400 個 | 実機、Mobile では逆(124 対 220) |
| GPU 6.6 から 1.7 ms | シャドウ付き omni light 16 個から 4 個 | 実機 |
| オブジェクト 1,260 個から 90 個 | ボックス型オクルーダー 1 個 | 実機、3 種類すべてのレンダラー |
| 生データ 38.1 MB、gzip で 9.7、brotli で 7.8 | 4.7.2 の Web エクスポート、小規模な 3D シーン | 実機:wasm が大半を占める |
| 26.5 から 28.3 MB | Android arm64 APK、release / debug | 実機:エンジンライブラリ 24 MB |
品質ゲート
- 測定値: 対象クラスで p95 フレーム時間または GPU 時間が予算内であること。エリア読み込み時の最悪フレームも確認します。
compareで意図したメトリクスが改善し、悪化したメトリクスがないことを確認します。scene_auditに high フラグがないことを確認します。 - 視覚: 変更前後のコンタクトシート(最大 1600 px)を開きます。オクルーダーのデバッグキャプチャと Web キャンバスのスクリーンショットも確認します。
- macOS:
codesign --verify --deep --strictが成功し、Debugging entitlement がオフで、両方のアーキテクチャに対応していること。Gatekeeper が受け入れるのは公証後のみです。 - Android:
apksignerで検証でき、署名者の SHA-256 がキーストアと一致し、versionCode が引き上げられ、release がデバッグ不可で、予定した ABI に対応し、プリセットにパスワードが含まれていないこと。 - iOS: scheme、bundle id、team が設定された Xcode プロジェクトがあること。iOS プラットフォームのインストール後に、署名なしの
xcodebuildが通ること。 - Web: 配信された状態でヘッドレス Chrome から起動できること。スレッドを使う場合は
crossOriginIsolatedが true であること。ページエラーがなく、配信サイズが予算内であること。 - パック: base pck に除外対象のコンテンツが含まれていないこと。DLC が
replace_files=falseで読み込まれること。demo タグがデモにのみ含まれること。
よくある間違い
| 間違い | 発生すること | 修正方法 |
|---|---|---|
モニター CSV の process_ms の p95 | 120 行すべてで同じ値になる | センチネル計測 |
| Metal での GPU 数値 | gpu_ms が 0 になる | --rendering-driver vulkan |
| ヘッドレス時のフレーム時間 | 描画されていないのに「60 fps」と表示される | ウィンドウ表示で実行 |
| ヘッドレスジョブでの MultiMesh の構築 | 保存されたシーンにインスタンスがない | MultiMesh.buffer に書き込む |
| モバイルでの共有マテリアル | ドローコール数が変わらない | MultiMesh |
| 同じ領域内での透明マテリアルの混在 | オブジェクト数に応じてドローコール数が増加する | 透明マテリアルを減らす。不透明面とアルファ面が混在する場合は分割する(3D doc) |
| ネームプレートやダメージ数値に Label3D を使用 | ラベルごとに 2 回描画される | 共有 TextMesh またはテキストノードを 1 つ使用する(grdqHJOL5F4 [00:09:33]) |
| LightmapGI の隣にライトを Dynamic のまま配置 | ベイク済みエリアで動的ライトのコストが発生する | ベイクモードを Static にする。DirectionalLight3D は Dynamic のままにする(3D doc) |
| ラムダとしてのカスタムモニター | 初期値のまま変わらない。終了時に 4.7.2 がクラッシュした(シグナル 11) | メソッドをバインドする。終了時に remove_custom_monitor を呼び出す |
| オクルージョンを有効にしているが、オクルーダーがない | 描画されるオブジェクトが変わらない | OccluderInstance3D のボックスを使用する |
| ヘッダーなしで itch にスレッド対応 Web ビルドを配置 | 「Cross-Origin Isolation missing」と表示される | シングルスレッドにする、ヘッダーを追加する、または PWA で回避する |
| Android パスを一度だけ設定する | 「A valid Java SDK path is required」と表示される | 非公開のエディター設定ファイルでパスを設定する |
| replace_files true で DLC をマウントする | 古いスクリプトが新しいスクリプトを上書きする | load_resource_pack(path, false) |
export_presets.cfg にパスワードを記載する | シークレットが git に含まれる | GODOT_ANDROID_KEYSTORE_*、GODOT_MACOS_* 環境変数を使用する |
引き継ぎ
scenario-godot-rendering-lighting(シャドウ予算、ベイクモード、品質ティア)、
scenario-godot-shaders(MultiMesh の頂点アニメーション、Shader Baker)、scenario-godot-3d-world(LOD、
可視範囲、オクルーダー、Jolt、大規模マップ向けの Large World Coordinates または原点シフト)、
scenario-godot-gameplay および scenario-godot-architecture(マネージャー、プーリング、間隔をずらしたタイマー、
スレッド化された読み込み)、scenario-godot-ui(タッチレイアウト、安全領域)、scenario-godot-multiplayer(Web
トランスポート、専用サーバー、信頼できるリーダーボードへの書き込み)、scenario-godot-pipeline-automation(CI
エクスポート、クリーンビルド)、scenario-godot-audio(Web での Sample 再生)。人による作業:Apple Developer ID、
App Store Connect、Play Console、Steamworks、コンソール、IAP 製品。監査フラグには担当者が記録されます
(perf_audit.gd)。
Godot 4.7 に関する注意事項
OS.get_thermal_stateは 4.7.2 には存在しません。負荷試験中のフレーム時間と、adb または Instruments から取得した OS の温度状態を記録してください。- 確認済みのデフォルト設定:
rendering_method.mobile="mobile"、rendering_method.web="gl_compatibility"、オクルージョンカリングは無効、手書きのプロジェクトではimport_etc2_astcは false、物理補間は無効、物理演算は 60 Hz、fallback_to_opengl3は true、OmniLight3D.omni_shadow_modeは Cube、light_bake_modeは Dynamic、Web オーディオは Sample。 - Pck 形式 4(
pck_listingで読み取れます)。4.6 以降、新しい 3D プロジェクトでは Jolt がデフォルトです。手書きのproject.godotでは設定が必要です。 - Android:JDK 17。Godot はエディター設定を作成するときに限り、JAVA_HOME と ANDROID_HOME から JDK と SDK のパスを設定します。4.3 以降、権限は自動で要求されません。
- iOS エクスポートでは、署名チームがない場合は
application/export_project_onlyが必要です。.ipaが存在しないため、gd_run.exportは失敗を報告します。 - 物理補間(2D は 4.3、3D は 4.4)により、物理演算の更新頻度を下げても実用的になります。
参考資料
references/procedures.md:コード、実行時の結果、実行しなかった内容を含む手順 1~16。references/expert-notes.md:専門家による主張とタイムスタンプ、および実際のテスト結果との相違点。references/critique.md、references/gui-paths.md、references/sources.md。scripts/gd_perf.pyとscripts/agentkit/perf/(perf_stress、perf_fixes、perf_audit、perf_bench、perf_logger、ship_boot、web_bridge、mobile_touch)。