High Level Shading Language

High Level Shading Languageはマイクロソフトによって開発された、Direct3D  で使われるプログラマブルシェーダーのためのプロプライエタリなシェーディング言語である。High Level Shader Language という呼び方もされている。ただしMSDNの日本語版ドキュメントでは、英語版の原文が「High Level Shader Language」となっている箇所だけでなく「High Level Shading Language」となっている箇所でも、上位レベル シェーダー言語という訳語を使用している。

HLSLはOpenGLで使われるシェーディング言語であるGLSLと類似の物である。また、NVIDIAと協力して開発されたことから、言語文法がCg言語に非常によく似ている。

1. 開発経緯
-------

Direct3D 7まではグラフィックスチップに実装された固定パイプラインおよびハードウェア機能を駆使して3Dグラフィックスシーンを構築していたが、グラフィックス表現の柔軟性を向上させるべく、Direct3D 8ではプログラマブルシェーダーが搭載された。これによって、グラフィックスアプリケーション開発者がグラフィックス描画アルゴリズムをソフトウェアによってカスタマイズすることが可能となった。しかし、Direct3D 8で使用できるシェーダー言語はアセンブリ言語であったため、開発効率やプログラムコードの再利用性に限界があった。それを解消するべく、C/C++風の宣言文や制御文などの記法を可能とした高水準言語HLSLが開発されることとなった。HLSLはDirect3D 9で初めて導入され、その後もDirect3Dとともに機能拡張が続けられている。

GDC 2016ではDirectX 12の今後の発展、そして新たな次期DirectXとシェーダーモデル6の開発に関して言及があり、HLSL言語仕様にも大きな機能追加が予定されていることが発表された。シェーダーモデル6.0では//Wave//と呼ばれるSIMTスレッドグループの概念と各グループ内でのデータ交換のための組み込み命令が導入され、NVIDIA GPUの//Warp//およびAMD GPUの//Wavefront//を標準化した。

2. プログラマブルパイプラインステージ
--------------------

HLSLによってプログラム可能なグラフィックスパイプラインステージは、対応するDirect3Dのバージョンおよびシェーダーモデルによって異なる。

Direct3D 9の場合は、頂点シェーダーおよびピクセルシェーダーの2つである。
Direct3D 10.xの場合は、頂点シェーダー、ジオメトリシェーダー、そしてピクセルシェーダーの3つである。
Direct3D 11.x/12の場合は、頂点シェーダー、ハルシェーダー、ドメインシェーダー、ジオメトリシェーダー、ピクセルシェーダー、そしてコンピュートシェーダーの6つである。ただしコンピュートシェーダーだけはグラフィックスパイプラインとは独立して動作させることができる。頂点シェーダーはアプリケーションによって提供される頂点それぞれについて実行され、主にオブジェクト空間から視空間への頂点座標変換やテクスチャ座標の生成、また頂点の接線や従法線や法線ベクトルのような光線の係数の計算などの処理を担当する。頂点シェーダーを通して頂点のグループ  が入力された時、出力座標はその領域内で画面上のピクセルを決めるために補間される。この処理はラスタライゼーションとして知られている。これらのピクセルそれぞれがピクセルシェーダーを通ることで、結果としてスクリーン上の各点の色が計算される。

また、Direct3D 10/11/12対応ハードウェアにおいてDirect3D 10/11/12インターフェイスを使うアプリケーションは、頂点シェーダーステージの後にジオメトリシェーダーを指定することもできる。ジオメトリシェーダーはラスタライズの前にプリミティブの増減や種類の変更を行なうことができる。

なお、HLSLで使用可能なパーリンノイズ生成関数であるnoiseは、テクスチャシェーダーと呼ばれる特殊なシェーダーステージでのみ利用が可能となっている。

Windows 10 October 2018 Update  では、DirectX Raytracing  と呼ばれるリアルタイムレイトレーシング技術が実装された。DXRにハードウェアレベルで対応するGPU上では、シェーダーモデル6.3のレイトレーシングパイプラインを記述するためのHLSLシェーダーが利用可能となる。

3. 言語機能
-------

HLSLの基本的な文法はC/C++に準ずるが、グラフィックスプログラムを記述するのに適した専用のベクトル・行列型や関数を備えている。数学関数の中にはC/C++標準ライブラリと同様のものも含まれる。また、Direct3D 10ではAPIの大幅な設計変更が行なわれたこともあり、Direct3D 9用のHLSLと比較して、Direct3D 10以降用のHLSLではオブジェクト指向に基づいた言語仕様の再設計がなされ、多数の仕様変更が加えられている。

Direct3D 10以降ではHLSLにてクラスを定義し、C++のようにデータと振る舞いを関連付けることが可能だが、アクセス指定子によるカプセル化や継承および仮想関数といった機能は備えていない。

Direct3D 11ではシェーダーの組み合わせ爆発問題を解消するべく、HLSLにてインターフェイスの定義と実装によるポリモーフィズムを疑似的に実現する「動的シェーダーリンク」と呼ばれる機能が追加された。

4. コード例
-------

以下にDirect3D 10/11向けHLSLを用いた、単純なHalf Lambert照明モデルおよびPhong照明モデルの頂点シェーダーおよびピクセルシェーダーのプログラムを示す。なお分岐によって照明モデルを切り替えているが、これはいわゆるウーバーシェーダーなので、実行速度効率などは考慮していないことに注意されたい。

// Shader Constants. matrix TrWorldViewProj; matrix TrWorld; float4 LightPosition; float3 EyePosition; float4 DiffuseColor; float4 SpecularColor; float SpecularPower; bool IsPhongModel;

struct BasicVSOutput { float4 Pos : SV_POSITION; float3 WPos : TEXCOORD1; float3 WNormal : NORMAL0; }; typedef BasicVSOutput BasicPSInput;

// Vertex Shader Program. BasicVSOutput BasicVS { BasicVSOutput output = 0; output.Pos = mul, TrWorldViewProj); output.WPos = mul, TrWorld).xyz; output.WNormal = mulTrWorld); return output; }

float4 CalcLambert { // Half Lambert.

float lambert = dot; lambert = lambert * 0.5f + 0.5f; lambert *= lambert; return lambert * DiffuseColor; }

float4 BasicLambert { const float3 light = normalize; const float3 normal = normalize; return CalcLambert; }

float4 BasicPhong { // Phong lighting with specular.

const float3 eye = normalize; const float3 light = normalize; const float3 halfway = normalize; const float3 normal = normalize; const float specular = pow, 0.0), SpecularPower); return CalcLambert + specular * SpecularColor; }

// Pixel Shader Program. float4 BasicPS : SV_TARGET0 { if  { return BasicPhong; } else { return BasicLambert; } }<WtXmlEndTag />

例のように、ピクセルシェーダーによってピクセル単位の正規化法線ベクトルを求めることにより、Direct3D 7以前の固定機能シェーダーでは実現が難しかったPer-Pixelライティングが容易に実装可能となっている。 もちろん、使用するシェーダーモデルおよび対応するハードウェアによっては、より複雑で長大なアルゴリズムを実装することもできる。リアルタイムグラフィックスゆえにハードウェア性能に応じたトレードオフにはなるが、単純な局所照明だけでなく、より厳密な物理ベースのレンダリング方程式に基づいた、大域照明モデルをHLSLによるプログラマブルシェーダーで実装することで、より現実に近いリアルタイム3Dコンピューターグラフィックスを実現することも可能となる。さらに、Direct3D 11  ではコンピュートシェーダーを使って、GPUにグラフィックス用途以外の汎用計算を行なわせるGPGPUプログラムをHLSLで記述することも可能となる。

なお、HLSLソースファイルには通例.hlsl拡張子が付けられ、ヘッダーファイルには.hlsli拡張子が付けられる。

5. 対応環境
-------

HLSLプログラムは主にホストとなるC++アプリケーションプログラムコードからDirect3D APIを使って入力と出力を管理する必要があるので、単体で動作させることはできない。なお、単体のコンパイラはマイクロソフトから無償提供されているDirectX SDKに付属する。プロプライエタリなHLSLコンパイラfxc.exeによって出力されるのは、グラフィックスハードウェアのベンダーに依存しない共通バイトコードであるため、一度コンパイルしておけば異なるハードウェアであっても動作させることができる。HLSLプログラムをサポートするのはDirect3D 9以降をサポートするシステムに限られるため、かつてはWindows OSおよびXbox 360以降のXboxシリーズが主な動作環境であったが、Vulkan向けのシェーダープログラムを事前コンパイルして中間表現Standard Portable Intermediate Representationを生成するコンパイラglslangValidatorがGLSLとHLSLの両方に対応したことなどもあり、クロスプラットフォームでのHLSLの活用が進んでいる。

アプリケーションの実行時にHLSLソースコードをコンパイルしてバイトコードを生成する機能を組み込むためのD3DCompilerランタイムも提供されている。

他に、ゲームエンジンのUnityでは、シェーダープログラムの記述にHLSLが使用されている。なお、Windows上でDirectComputeベース  のコンピュートシェーダーを使用することができるが、Cgはコンピュートシェーダーに対応していないため、コンピュートシェーダーの記述には当初からHLSLが使用されていた。UnityはCg/HLSLからGLSLへのトランスレーションが可能なため、OpenGL 4.3やOpenGL ES 3.1のコンピュートシェーダーを用いる場合でもGLSLではなくHLSLを使用することが推奨されていた。

LLVM/ClangベースのHLSLコンパイラdxc.exeもGitHub上で開発が進められている。こちらはDirectX Intermediate Language  と呼ばれる別の中間言語コードを生成するが、これまでのfxc.exeが生成するバイトコード  とは互換性がない。

6. エフェクト
--------

HLSL自体は、シェーダー関数および各シェーダーステージのエントリーポイントを記述するために使われるが、この複数のシェーダーステージをまとめて管理・適用する「エフェクト」と呼ばれる仕組みも存在する。つまり、例えば2つの頂点シェーダーエントリーポイントVS1, VS2と2つのピクセルシェーダーエントリーポイントPS1, PS2を単一のHLSLソースプログラムファイルに記述し、さらにVS1+PS1, VS2+PS2, VS1+PS2, VS2+PS1といったシェーダーステージの組み合わせのほか、各種レンダリングステートの設定をエフェクトファイル中に記述して関連付けることができる。エフェクトを扱うAPIはDirect3D 10のコアライブラリもしくはDirect3D 9/11のエクステンションライブラリに用意されており、レンダリングパイプラインの管理をC++コードから分離することができる。

7. WPFエフェクト
-----------

Windowsデスクトップアプリケーションフレームワークの1つであるWPFでは、グラフィックスのレンダリングにDirect3Dが使用されているが、GUIウィジェットにブラーやドロップシャドウといったエフェクトを適用することが可能となっている。さらにWPFではユーザープログラマーがHLSLで作成したピクセルシェーダーを使用してカスタムエフェクトを適用することもできる。

WPF 3.5まではシェーダーモデル2.0のピクセルシェーダーのみがサポートされていたが、WPF 4ではシェーダーモデル3.0のピクセルシェーダーも使用できるようになった 。

8. Direct2Dエフェクト
----------------

DirectXファミリーの1つ、2次元コンピュータグラフィックスAPIであるDirect2Dでは、バージョン1.1にてエフェクト機能が実装されたが、HLSLによるカスタムエフェクトを作成・利用することも可能となっている。

9. シェーダーモデル
-----------

Direct3Dプログラマブルシェーダーを実行するには、Direct3D 8以降に対応したハードウェアが必要となる。ただし、Direct3D 9までの場合、頂点シェーダーだけはソフトウェアすなわちCPUでエミュレートすることもできるため、固定機能ピクセルシェーダーと組み合わせることによりDirect3D 7以前の古いハードウェアでプログラマブルシェーダーを実行することも可能である。また、Direct3D 10.1以降では比較的高速なソフトウェアレンダリングエンジンであるWARPデバイスも実装されているため、GPUが対応していなくてもCPUにDirect3Dレンダリングを実行させることもできる。

Direct3D対応ハードウェアの世代によって、GPU上にてハードウェアレベルで実行可能なシェーダープログラムの仕様が異なる。この仕様はシェーダーモデルと呼ばれ、新しい世代のシェーダーモデルをサポートするハードウェアは基本的に古い世代のシェーダーモデルもサポートするが、ベンダーごとに拡張された2.0a/2.0bなどの例外も存在する。 なおHLSLがDirect3Dに搭載されたのはバージョン9以降だが、シェーダーモデル2.0以降でないとHLSLを使えないというようなことはなく、HLSLを使用してシェーダーモデル1.xレベルのプログラムを記述することも可能である。また、Direct3D 10では、アセンブリ言語によるシェーダープログラム開発が廃止され、シェーダーの記述にはHLSLのみが使用できるようになった。

シェーダーモデル3.0には頂点テクスチャフェッチと呼ばれる機能が存在するが、DirectX 9.0c世代で対応したのはNVIDIAのハードウェアのみで、ATIのハードウェアではサポートされなかった。逆に、浮動小数点バッファにおけるアンチエイリアス機能は、NVIDIAハードウェアではサポートされず、ATIハードウェアのみでの対応となっていた 。他にも、テッセレーション機能がATIハードウェア上のみでサポートされる など、シェーダーモデル3.0までは機能面において各社の足並みがそろわない状態にあり、これらの機能を利用するアプリケーション開発者は使用したい機能が実際にハードウェアでサポートされているかどうかをあらかじめDirect3DのCaps  取得APIを使って一つ一つ調べなければならなかった。このようにベンダーごとに各機能の対応レベルがバラバラとなっていた悲惨な状況は、次のバージョンのDirect3D 10以降で要求仕様が厳格化されたことで、ある程度解消されることになる。

なお、Direct3D 10.1 APIでは4.xプロファイルのシェーダープログラムに加えてダウンレベルの2.0プロファイルが使用可能であり、Direct3D 11/12 APIでは5.xおよび4.xプロファイルに加えてダウンレベルの2.0プロファイルが使用可能だが、いずれも3.0プロファイルに関しては使用できない 。

9.1. DirectXバージョンと各シェーダーステージ
----------------------------

以下の表はハードウェアが対応しているDirectXバージョンと、そのハードウェアがサポートする各シェーダーステージの最上位バージョン間の関係を示している。 後述するように、実行可能なシェーダープログラムの最大命令数やレジスタ数、リソーススロット数などは新しいバージョンのほうが大きくなり、より柔軟で長大なプログラムを記述することができるようになる。

なおコンピュートシェーダーはDirectX 11にて導入されたステージであり、DirectX 10 APIを経由して利用することはできないが、ドライバーが対応していればDirectX 10.x世代のハードウェア上でもDirectX 11 APIを経由してダウンレベルのコンピュートシェーダーを実行することが可能となる。

シェーダーモデル5.1はDirectX 12 APIをドライバーレベルでサポートするすべてのハードウェアで使用可能だが、Root Signatureに関する機能はDirectX 11.3では使用できず、DirectX 12専用の機能となる。また、ROV  に関するオブジェクトは、ROV対応ハードウェアでしか使用できない。

シェーダーモデル6.0の組み込み関数は機能レベル12_0の要件として追加されている。

9.2. ピクセルシェーダーの比較
-----------------


PS 2.0 = DirectX 9.0オリジナルのシェーダーモデル2.0仕様。
PS 2.0a = NVIDIA GeForce FXに最適化されたモデル。
PS 2.0b = ATI Radeon X700, X800, X850のシェーダーモデル。
PS 3.0 = シェーダーモデル3.0に含まれる。
PS 4.0 = シェーダーモデル4.0に含まれる。
PS 4.1 = シェーダーモデル4.1に含まれる。
PS 5.0 = シェーダーモデル5.0に含まれる。//実行命令数//において"32 + 64"というのは"32のテクスチャ命令と64の算術命令"を意味する。

9.3. 頂点シェーダーの比較
---------------


VS 2.0 = DirectX 9.0オリジナルのシェーダーモデル2.0仕様。
VS 2.0a = NVIDIA GeForce FXに最適化されたモデル。
VS 3.0 = シェーダーモデル3.0に含まれる。
VS 4.0 = シェーダーモデル4.0に含まれる。
VS 4.1 = シェーダーモデル4.1に含まれる。
VS 5.0 = シェーダーモデル5.0に含まれる。なおVS 2.0bは存在しない。

9.4. 対応ハードウェアの概略
----------------

以下の表はDirect3Dプログラマブルシェーダーに対応している各社グラフィックスカードの概略であり、対応するピクセルシェーダーバージョンとDirectXのバージョンを示している。グラフィックスチップは前述のとおり、一般的には上位互換性がある。例えばPS 3.0対応のチップはPS 2.0やPS 1.1にも対応している。

なお開発に専用APIやOpenGL/GLSLを使用するゲーム専用機やモバイル機器は、たとえプログラマブルシェーダー対応であってもDirect3D/HLSLに対応しているとは限らないが、グラフィックスチップの世代を示すときは便宜上シェーダーモデルを使うことがある。



9.4.1. Shader Model 1.x
-----------------------

DirectX 8.x世代。
NVIDIAとATIが際限なく機能拡張を行なった頃のモデル。1.1、1.2、1.3、1.4のマイナーバージョンが存在する。
対応GPU: AMD Radeonは8xxx、NVIDIA GeForceは3-4Tiシリーズ。
ゲーム機であるXbox用GPUはSM1.x、またはその派生版と見られる。

9.4.2. Shader Model 2.0
-----------------------

DirectX 9世代。
マイクロソフトとインテルが、両者の利点を生かして作ったスタンダードモデル。
NVIDIA拡張である2.0aと、ATI拡張である2.0bが存在する。
対応GPU: Radeonは9500-X850、GeForceはFX 5xxxシリーズ。

9.4.3. Shader Model 3.0
-----------------------

DirectX 9.0c世代。
このバージョンより、シェーダープログラム長の制限がほぼ無くなった。
対応GPU: RadeonはX1000シリーズ、GeForceは6、7シリーズ。
ゲーム機であるXbox 360、プレイステーション3用GPUは、SM3.0またはその派生版と思われる。

9.4.4. Shader Model 4.x
-----------------------

DirectX 10.x世代。
統合型シェーダーアーキテクチャの採用。なお、GPGPU用APIのCUDAやOpenCLに対応するのはSM 4.0世代以降である。
定数レジスタ容量の大幅な拡張。
ジオメトリシェーダーの追加。
追加のテクスチャ命令などをサポートするマイナーバージョン4.1が存在する。
対応GPU: RadeonはHD 2xxx-HD 4xxxシリーズ、GeForceは8xxx-GT 3xxシリーズ。
ゲーム機であるWii U用GPUは、SM4.0またはその派生版と思われる。

9.4.5. Shader Model 5.0
-----------------------

DirectX 11.x世代。
ハルシェーダー、ドメインシェーダー、固定機能テッセレータが含まれるテッセレーションステージの追加、およびGPGPU機能であるコンピュートシェーダーの対応など。
対応GPU: RadeonはHD 5xxx-HD 8xxx、Rx 2xx/3xxシリーズ、GeForceはFermi、Kepler、Maxwell第1世代。
ゲーム機であるXbox One、PlayStation 4用GPUは、SM5.0またはその派生版と思われる。

9.4.6. Shader Model 6.0
-----------------------

DirectX 12世代。
対応GPU: RadeonはGCN第2世代以降、GeForceはMaxwell第2世代以降。なおOpenGL対応レベルに関しては、ナンバリングがDirectXのバージョンやシェーダーモデルと正確に対応するわけではなく、細かい機能における差異が多数存在するが、世代としてはおおよそ下記の通りとなる。

OpenGL 2.x - Direct3D 9
OpenGL 3.x - Direct3D 10
OpenGL 4.x - Direct3D 11

10. 関連項目
--------

Microsoft DirectX
Direct3D
DirectCompute
GLSL
Cg 

11. 脚注
------

12. 外部リンク
---------

[1]
[2]
[3]
[4]