Slang は「HLSL は唯一まともな GPU 言語だが、Microsoft のコンパイラに
縛られている」に対する Khronos の答えだ。モダンなシェーディング言語で、
モジュール、ジェネリクス、インターフェース、自動微分を備え、1つの
ソースから SPIR-V(および DXIL、Metal、WGSL)へコンパイルできる。
Vulkan では .slang ファイル → slangc -target spirv →
VkShaderModule で、GLSL/HLSL と同じパイプラインだ。
なぜ GLSL ではだめか
compare.txt
GLSL: モジュールなし、ジェネリクスなし、1970年代のプリプロセッサ
インクルード、弱い型システム、クロージャなし。小さなシェーダー
には十分だが、エンジン規模のシェーディングでは苦痛。
Slang: モジュールの import、ジェネリック関数/構造体、インターフェース、
微分可能プログラミング(順/逆自動微分)、本物のリフレクション
API、1つのソース → 全バックエンド。味見
light.slang
// ジェネリックで再利用可能な関数 — 素の GLSL では不可能:
T shade<T>(T a, T b, float t) where T : IFloat
{ return a * (1 - t) + b * t; }
[shader("compute")]
[numthreads(64)]
void main(uint3 id : SV_DispatchThreadID) {
result[id.x] = shade(a[id.x], b[id.x], 0.5f);
}Vulkan 向けコンパイル
build.sh
slangc shader.slang -target spirv -o shader.spv -entry main
# マルチエントリー → エントリーごとに1モジュール:
slangc shader.slang -target spirv \
-entry vertMain -stage vertex -o vert.spv \
-entry fragMain -stage fragment -o frag.spv
# デバッグ情報を埋め込む:
slangc shader.slang -target spirv -g -o shader.spvリフレクション API(slang-reflection/libslang)は、SPIR-V を再パース
せずにディスクリプタバインディング、プッシュ定数レイアウト、
スレッドグループサイズを与えてくれる。spirv-reflect の記事で使った
のと同じツールだが、ソースレベルだ。
決定的な機能:自動微分
diff.slang
// [Differentiable] — slang が逆伝播パスを自動的に計算する:
[Differentiable]
float loss(float3 pred, float3 target) {
float3 d = pred - target;
return dot(d, d);
}
// シェーダー内:bwd_diff(loss)(…) が勾配を返す —
// 微分コードを書くのはあなたではなく自動微分機構だニューラルテクスチャ圧縮、学習 BRDF、微分可能レンダリング。勾配コードが 手で導出されるのではなく生成されるシェーディング言語は、今のところ Slang だけだ。
Vulkan 統合の落とし穴
set/bindingは[[vk::binding(N,S)]]または Slang 独自の[vk::binding]属性にマップされる。DXC の HLSL 経路と同じモデルだ。- プッシュ定数は
[[vk::push_constant]] ConstantBuffer<T>だ。HLSL の 記事と同じ仕組み。 slangcは SPIR-V を直接出力する。その SPIR-V はspirv-optとspirv-val(ツール記事参照)に通せるほどクリーンだ。- SPIRV-Reflect は Slang の出力を問題なく読める。バインディングと エントリーポイントは通常の SPIR-V デコレーションとして現れる。
実践的なルール
- エントリーポイントごとに
slangc -target spirvを使う。マルチ エントリーの.slangもVkShaderModuleごとに1つの.spvになる。 - モジュールは
#includeを置き換える。import foo;は名前空間付きで 依存関係が追跡される。古いglslangインクルードチェーンのハックは 削除する。 slangdが LSP だ。VSCode/Vim で.slangの補完とエラーが得られる。- ジェネリクスはインスタンス化ごとに単相化される。異なる
Tでの2つのshade<T>呼び出しは2つの SPIR-V 関数を生成する。巨大なジェネリック グラフでは特殊化コストを確認する。 - Vulkan 専用プロジェクトでは、Slang は自動微分 + モジュール + 本物の ツールチェーンをもたらす。すでに GLSL と小さなシェーダーに全力投入 しているなら、それは必需品ではなくツールチェーンの切り替えだ。
この記事が役に立った場合は、TechOverflow での新しい記事の調査と公開を支援するため、「Buy Me a Coffee」でのご支援、または PayPal 経由でのご寄付をご検討ください