ホーム < ゲームつくろー! < プログラマブルシェーダ編

その10 プリコンパイル済みhlslファイルを作ろう


 シェーダやfxファイルは人が読めるテキストファイルで作成しますが、リリース時にそのまま付けてしまうのはちょっと嫌な感じがします。DirectXにはテキストのシェーダファイルをバイナリファイルにコンパイルするfxc.exeというユーティリティが付属しています。この章ではこれを使ってプリコンパイル済みfxファイルを作る方法を紹介します。



@ fxc.exeユーティリティの使い方

 fxc.exeはHLSLのコンパイラでコマンドプロンプト上で使います。これはDirectXをインストールしたフォルダのUtilities\Bin\x86\fxc.exeにあります。

 使い方はとても簡単です。まずコンパイルしたいHLSLファイルを用意します。ここでは例えばTest.hlslとしておきましょう。この中には頂点シェーダ、ピクセルシェーダ、そしてテクニックを含めます。続いてコマンドプロンプトでfxc.exeを次のように実行します:

fxc.exeの使い方
fxc.exe Test.hlsl /T fx_2_0 /Fo Test.cfx

/Tオプションはprofile(プロファイル)を指定します。プロファイルとはシェーダのバージョンなどの事で、fxファイルの場合は「fx_2_0」「fx_4_0」「fx_4_1」のいずれかを指定できますが、DirectX9の場合はfx_2_0にします。
/Foオプションは出力ファイル名を指定します。上の場合ですとfxc.exeがあるフォルダに作成されてしまいますが、パス指定をすれば好きな場所に出力できます。ちなみに、拡張子は好きに付ける事ができます。

 HLSLファイルが正しければ次のような表示が出てコンパイル済みバイナリfxファイルが作成されます:

C:\Program Files\Microsoft DirectX SDK (August 2007)\Utilities\Bin\x86>fxc.exe Test.hlsl /T fx_2_0 /Fo Test.cfx
Microsoft (R) D3D10 Shader Compiler 9.19.949.1075
Copyright (C) Microsoft Corporation 2002-2006. All rights reserved.

compilation succeeded; see C:\Program Files\Microsoft DirectX SDK (August 2007)\Utilities\Bin\x86\Test.cfx


 もし間違いがあった場合は間違いを指摘してくれます:

C:\Program Files\Microsoft DirectX SDK (August 2007)\Utilities\Bin\x86>fxc.exe Test.hlsl /T fx_2_0 /Fo Test.cfx
Microsoft (R) D3D10 Shader Compiler 9.19.949.1075
Copyright (C) Microsoft Corporation 2002-2006. All rights reserved.

ID3DXEffectCompiler: There were no techniques
ID3DXEffectCompiler: Compilation failed

上の場合ですとtechniqueが無くてコンパイルに失敗したと告げてくれています。

 コンパイルに成功したバイナリエフェクトファイルはDirectX上でテキストファイルの時と同様に読み込む事ができます。



A Visual Studioにコンパイルさせるようにする

 コンパイルは以上のように簡単ですが、何か変更があるたびにコマンドプロンプトを立ち上げて再コンパイルするのは面倒です。そこで、このコンパイル作業をVisual Studioにさせるように仕込んでみます。

 Visual Studioでソースコードをコンパイルする時にfxファイルのコンパイルも一緒にしてしまいます。これを行うためには「ビルドイベント」に必要な記述をします。ビルドイベントはプロジェクトのプロパティの中にあります。

ここにはコンパイル(ビルド)する時に一緒に実行するコマンドラインを記述します。今回はプロジェクトフォルダの下に「Shaders」というフォルダを作成し、そこに格納した全hlslファイルをコンパイルします。そのために上の「コマンドライン」欄に次のように記述します:

コマンドライン
for %%1 in ($(InputDir)Shaders/*.hlsl) do fxc.exe $(InputDir)Shaders/%%~n1.hlsl /T fx_2_0 /Fo $(InputDir)Shaders/%%~n1.cfx

for文を使っています。%1という変数にShaders/*.hlslに該当するファイル名(フルパス)だけを格納し、それに対してdo以下でコンパイルコマンドを実行しています。「&(InputDir)」にはプロジェクトフォルダへのフルパスがマクロとして格納されています(これはVSがプロジェクト立ち上げ時に自動的に生成するマクロです)。見た目はややこしいのですが、%%1とマクロを注意深く戻していくと何をしているかわかると思います。このコマンドをすべての構成に対して記述します。私はビルド後イベントとして記述しました。

 これで、ビルドをするたびにfxファイルが再コンパイルされ、コンパイル済みファイルが生成されます。こうする事で、私たちはもはやテキストファイルであるhlslファイルではなくてコンパイル済みcfxファイルをプログラム内で使用できるようになります。ただし、ビルドが一度成功するとプログラムを変更しないとビルドイベントは発生しません。hlslファイルだけを変更した場合はfxc.exeを使って独立してコンパイルする必要があります。そのためのバッチファイルを作っておいても良いですね。



B プリコンパイル済みfxファイルを使う利点

 プリコンパイル済みのバイナリfxファイルを使うと、エフェクトファイルの実装を隠蔽できます。これは改ざんを防ぐのに非常に効果的です。利点はそれだけではありません。コンパイルが済んでいるのですから、プログラム上でコンパイルする手間が省けます。結果としてエフェクトファイルの読み込みと設置が高速化します。

 ID3DXEffectをD3DXCreateEffectFromFile関数で作成する時にフラグを設定する部分がありました。ちょっと宣言を見てみます:

D3DXCreateEffectFromFile関数
HRESULT D3DXCreateEffectFromFile(
   LPDIRECT3DDEVICE9 pDevice,
   LPCSTR pSrcFile,
   CONST D3DXMACRO* pDefines,
   LPD3DXINCLUDE pInclude,
   DWORD Flags,
   LPD3DXEFFECTPOOL pPool,
   LPD3DXEFFECT* ppEffect,
   LPD3DXBUFFER *ppCompilationErrors
);

上の第5引数のFlagsです。pSrcFileに入ってくるファイルをコンパイルする必要が無い場合、ここにD3DXSHADER_SKIPVALIDATIONフラグを立てます。このフラグを立てると妥当性チェック(バリデートチェック)が行われません。そのため、ファイルさえあれば問答無用でエフェクトオブジェクトが作成されます。コンパイルが入らないので高速です。

 エフェクトファイルが多くなってくると、コンパイルのための待ち時間はかなりなものになります。どうせ動くと分かっているエフェクトファイルなのですから、プリコンパイルしてしまって積極的に動作の高速化をはかりたいものです。