目次
はじめに
DirectX向けにHLSL言語で書かれたシェーダプログラムを、WebGPUで使えるWGSLへと変換してみる記事です。
いわゆるトランスパイルというやつです。
実験してみたものの、すぐに忘れそうなので備忘録を兼ねて記事にしておきます。
SPIR-VとTintを使います。(詳細は後述)
余談ですが、WebGPUについて、C++でブラウザ向けに使う入門記事を先日書いたので、試してみたい方はぜひご参照ください。
また、今回はWindows環境で解説します。
そのほかの環境は以下の通りです。
DirectX Shader Compiler(dxcompiler.dll: 1.7 - 1.7.2212.40 (e043f4a12); dxil.dll: 1.7(101.7.2212.36)) Tint (mainブランチ、 コミット 4ed79e689a0632837d3d956038ef7d78206dc22d(2023年4月上旬ごろ)) ninja 1.11.1 CMake 3.24.0
変換の流れ
HLSL→WGSLの直接変換する手段は、私が知る限り存在しません。
しかし、世の中には「 SPIR-V 」という便利な中間言語があります。
SPIR-Vは、シェーディング言語に特化した中間言語で、多くの環境に向けて使うことができます。
HLSLやWGSLも、SPIR-V形式での入出力に対応しています。
こちらのSPIR-Vを中継して、変換していきます。
つまり、 HLSL→SPIR-V→WGSL という流れでの変換になります。
HLSL→SPIR-V
DirectX Shader Compiler(DXC)を使います。
Microsoftが提供するオープンソースのHLSLコンパイラです。
ShaderModel 6.0以降にも対応しています。
SPIR-Vへ変換する機能もあるため、こちらを使います。
ちなみに、HLSL→SPIR-Vの変換ができるソフトウェアは、
UnityTechnologiesの HLSLcc (HLSLCrossCompiler のFork)や、
GoogleのShaderc などもあります。
SPIR-V→WGSL
Tint を使います。
Tintは、Googleによって、Chromium向けのWebGPUの実装「Dawn」とともに開発されている、シェーダーコンパイラです。
スタンドアロンで、exe形式として使ったり、ライブラリとして組み込むなどの使いかたもできます。
環境構築
DirectX Shader Compiler(DXC)
GitHubにビルドされた状態でReleaseされてるので dxc_xxxxxxxx.zip
をDLしてきます。
https://github.com/microsoft/DirectXShaderCompiler/releases
DLできたら、適当なところに解凍します。
あとは、環境に合ったdxc.exe
のある場所にPATHを通してください。
(比較的基礎的な部分なので、PATHの通し方は本記事では触れません)
私はx64環境なので、[DXCを解凍したディレクトリ]\bin\x64
にPATHを通しました。
任意のディレクトリで、
dxc --version
を実行して正常に動作すればOKです。
Tint
Tintはバイナリ形式では配布されていないので、自力でビルドする必要があります。
depot-toolsのインストール
Chromiumの開発で必要なツール群です。
公式のドキュメント(https://dawn.googlesource.com/tint/+/refs/heads/main#building)いわく、Chromiumの依存関係管理まわりが必要だそうなので、入れておきます。
公式のセットアップページ(http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up)
にアクセスして、
WINDOWS
Download the depot_tools bundle and extract it somewhere.
と書いているあたりのリンクから、Windows用のzipファイル(depot_tools.zip
)をDLしてきてください。
DLできたら、解凍、適当な場所に配置します。
こちらも同様にPATHを通しておきます。
Tintのビルド
copy standalone.gclient .gclient gclient sync # 出力先ディレクトリを作る md out\Debug\ cd out\Debug\
cmakeとninjaを使ってビルドをします。
SPIR-Vを読み込みできるように、 TINT_BUILD_SPV_READER
オプションを指定しておきます。
(ninjaをインストールしていない場合は、ninjaをダウンロードしてきて、PATHを通してください。
https://github.com/ninja-build/ninja/releases )
cmake -GNinja ../.. TINT_BUILD_SPV_READER # ビルド ninja
ついでなので、ninjaを使わずに、CMakeとmakeでビルドする方法も書いておきます。
cmake ../.. TINT_BUILD_SPV_READER # ビルド make
Tintのインストール
ビルドに成功すると、
out/Debugにtint.exeファイルなどが沢山できているので、
これらを適当なディレクトリに配置し、これにもPATHを通しておきます。
任意のディレクトリで、
tint --help
を実行して正常に動作すればOKです。
変換をする
変換前のHLSL形式のShaderはこちらです。
ごくシンプルな、頂点カラーそのままを出力するFragmentShader(PixelShader)です。
struct VSOut { float4 Pos : SV_Position; float3 Color : TEXCOORD0; }; float4 main(VSOut In) : SV_Target0 { return float4(In.Color, 1.0f);; }
HLSL→SPIR-V(DXCを使用)
dxc.exe
を使います。
dxc -spirv -T ps_6_0 -E main FragmentTest.hlsl -Fo FragmentTest.spv
指定しているオプションについては、下表のとおりです。
dxcのオプションの詳細は、公式ドキュメント か dxc --help
コマンドから確認してください。
オプション | 説明 |
---|---|
-spirv |
SPIR-V形式に出力 |
-T ps_6_0 |
ターゲット。 シェーダーステージ( vs /ps /cs など)や、シェーダーモデル( 6_0 など)を指定。 ここでは、PixelShaderとShaderModel 6.0を指定しています。 |
-E main |
エントリポイントの関数名を指定します。 |
FragmentTest.hlsl |
コンパイル元のhlslファイル。 |
-Fo FragmentTest.spv |
出力先のSPIR-V形式のファイル。 |
成功すれば、FragmentTest.spv
が出力されます。
SPIR-V→WGSL(Tintを使用)
tint.exe
を使います。
tint FragmentTest.spv -o FragmentTest.wgsl
無事、WGSL形式のシェーダーが出力されました。
var<private> in_var_TEXCOORD0 : vec3<f32>; var<private> out_var_SV_Target0 : vec4<f32>; fn main_1() { let x_13 : vec3<f32> = in_var_TEXCOORD0; out_var_SV_Target0 = vec4<f32>(x_13.x, x_13.y, x_13.z, 1.0f); return; } struct main_out { @location(0) out_var_SV_Target0_1 : vec4<f32>, } @fragment fn main(@location(0) in_var_TEXCOORD0_param : vec3<f32>) -> main_out { in_var_TEXCOORD0 = in_var_TEXCOORD0_param; main_1(); return main_out(out_var_SV_Target0); }
おわりに
HLSL→SPIR-V→WGSLの変換をやりました。
エンジン開発などでのクロスプラットフォーム対応や、HLSLのincludeなどのプリプロセッサ機能を使いたい場合などに活きそうな技術です。
あと、ゲームコンソールでもSDKとかにトランスパイル出来る仕組みってあるのかなぁってふと疑問を抱いたりしてます。NDAに触れちゃうであろう事項なので、いまのただの学生という身分では知りようがないのですが。
これからも、WebGPUなど色々と調査・研究していきます。
参考にしたもの
HLSL を SPIR-V 経由で GLSL に変換してみた - Qiita
SPIR‐V CodeGen · microsoft/DirectXShaderCompiler Wiki · GitHub