Search Unity

新しい実験版機能 Caching Shader Preprocessor によるビルドの高速化

, 5月 6, 2020

シェーダーのコンパイルは複数のステップからなる長いプロセスです。最初のステップの 1 つは、シェーダーソースの前処理です。Unity 2020.1 ベータ版では、このコンパイルステップを実行するための新しいカスタムソリューションである「Caching Shader Preprocessor」が導入されています。これは、プラットフォームコンパイラーのプリプロセッサーよりも最大 25% 高速で、C 標準に忠実に追従しつつ、新しい機能を提供します。

Unity を使用する人なら誰でも、直接的あるいは間接的にシェーダーを扱うことになります。シェーダーは GPU 上で実行されるプログラムであり、オブジェクトがどのように画面にレンダリングされるかを決定します。例えば、ポイントライトがシーンに追加された場合、それに反応する必要のあるオブジェクトは、ポイントライトの扱い方を定義する別のシェーダーバリアントを使用します。

まだ出現していない新しいシェーダーバリアントが使われている場合はいつでも、Unity エディターはそれをコンパイルしなければなりません。また、ターゲットデバイス上で動作するようにアプリケーションをビルドする時も、エディターは必要なシェーダーをすべてコンパイルする必要があります。

Caching Shader Preprocessor をオン/オフするチェックボックスは、エディター設定の Shader Compilation セクションにあります。

このブログ記事の残りの部分では、シェーダーを書いている場合に役立つと思われる技術的な詳細をカバーします。

速さを追求した作り

新しいプリプロセッサーは、中間的な前処理データをキャッシュして、シェーダーのインポートとコンパイル時間を短縮します。このキャッシュにより、エディタはインクルードファイルの内容が変更されるまでインクルードファイルを解析する必要がなくなり、同じシェーダーの複数のバリアントをより効率的にコンパイルできるようになります。新しいプリプロセッサーを有効にすると、プロジェクト内のシェーダーがインクルードファイルの大部分を共有している場合に最も顕著な効果を発揮します。

一体化

異なるシェーダーコンパイラーのバックエンドには、それぞれ独自のプリプロセッサーが付属しています。コンパイラーが実行される前に標準化されたカスタムプリプロセッサーを実行することで、現在または将来使用されるどのコンパイラーバックエンドに対してもシェーダーコードの互換性が確保され、Unity のバージョン間でのプロジェクトのアップグレードが容易になります。

シェーダーのインポート時に同じプリプロセッサーが使用されるようになり、シェーダーのコンパイルパラメータ(#pragma ディレクティブ)をチェックするために以前採用されていたプレーンテキスト解析ソリューションを置き換えることができるようになりました。これにより、条件付きの#pragma ディレクティブの選択や、それらのディレクティブをインクルードファイルに入れることができるなど、追加の新機能を提供できるようになりました。

新機能

前処理されたソースを表示
シェーダーのインスペクターに「Preprocess only」チェックボックスが追加され、コンパイル済みのシェーダーコードと前処理済みのシェーダーのソースの表示を切り替えることができるようになりました。この機能は、シェーダーを開発している人にとって非常に便利で、シェーダーのデバッグを容易にします。

インクルードファイルのシェーダーコンパイルパラメーター
新しく「#include_with_pragmas」プリプロセッサーディレクティブを導入しました。これは、シェーダーの開発者がコンパイル設定を制御する #pragma ディレクティブをインクルードファイルに記述できるようにするものです。これらは通常の #include ディレクティブと同じように動作しますが、シェーダーのインポート時に無視されません。

この違いがシェーダーのインポート時間を最小化します。この機能がなければ、シェーダーに含まれるすべてのファイルに対してプリプロセッサーを実行する必要が出てきます。

古いシェーダーのインポートパスは新しいディレクティブを無視します。

条件付きシェーダーコンパイルディレクティブの選択
シェーダーのインポート中にプリプロセッサーを実行すると、シェーダーのコンパイルを制御する#pragma ディレクティブをプリプロセッサーの条件式でラップすることができます。

すべての条件式が #pragma の選択に影響を与えるわけではありません。プリプロセッサーは、条件式の引数がどこから来るかを検出します。これにより、再帰を防ぎ、シェーダーのコンパイルパイプラインへの影響を最小限に抑えます。条件式が #pragma ディレクティブのレポートに影響を与えるのは、一般的なマクロ定義(Unity バージョンまたは UNITY_OLD_PROPROCESSOR マクロ)、ユーザーマクロ定義、またはビルドターゲットに依存し、他の手段で設定できないプラットフォームキーワードに依存している場合に限られます。最後のものには、SHADER_API_DESKTOP、SHADER_API_MOBILE、UNITY_NO_CUBEMAP_ARRAY、UNITY_FRAMEBUFFER_FETCH_AVAILABLE、UNITY_USE_NATIVE_HDR、UNITY_NO_RGBMのほか、コンソール用のSHADER_API_キーワードが含まれます。ここで述べたユーザーマクロ定義には、#pragma multi_compile や#pragma shader_feature ディレクティブで指定されたユーザーキーワードは含まれないことに注意してください。

正しい使用例:

正しくない使用例:


前処理動作の変更
新しいシェーダー前処理ソリューションについて注目すべき動作の変更点は以下のとおりです。

  • #pragma 警告がサポートされるようになりました。
  • #include ディレクティブのパラメーターが通常のフォーマット(#include <インクルードファイル名> または #include “インクルードファイル名”)にマッチしない場合、マクロ展開されるようになりました。
  • #line ディレクティブのパラメーターが通常のフォーマット(”#line “の後に符号なし整数、オプションでファイル名)にマッチしない場合、マクロ展開されるようになりました。
  • マクロを再定義したとき、新しい定義が前の定義と異なる場合に警告が表示されます。
  • マクロ展開は C 言語の標準に完全準拠しています。
  • 最初の引数が識別子である場合、正しくない形式の #undef ディレクティブが無視されなくなりました。
  • 文字列化が完全にサポートされるようになりました。
  • 引数なしのマクロで連結が動作するようになりました。
  • 無効な連結に対して警告を出すようになりました。
  • 文字列化や連結に使用した場合、マクロパラメーターは展開されません
  • シフト演算子が条件式でサポートされるようになりました。
  • プリプロセッサーが、パラメーターを持つべきなのにパラメーターを持たないマクロ名に遭遇した場合、エラーは発生せず、マクロ展開も発生しません。
  • 「\\\n」(バックスラッシュとそれに続く改行)は、スペースとして扱われなくなりました。

古いシェーダーのインポートパイプラインでは、UNITY_OLD_PREPROCESSOR マクロが定義されるようになりました。これは、2 種類のプリプロセッサーを区別するために使うことができます。

ご意見をお聞かせください

Caching Shader Preprocessor は新しい機能です。Unity 2020.1 では実験版機能とマークされ、すべてのプラットフォームとレンダーパイプラインに適用されます。

2020 年のバージョンサイクルの終わりまでに完全に利用できるようにする予定ですので、Unity 2020.1 ベータ版でこの機能をぜひお試しいただき、フォーラムにフィードバックをお寄せください