DXCで使えるHLSLの文法について個人的にまとめたものです。内容には間違いが含まれている場合があります。
変数
- 参考:
[Storage_Class] [Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset [: Register]; [Annotations] [= Initial_Value]
Storage_Class(記憶域クラス指定子)
- extern:グローバル変数がアプリケーション側から入力を受け入れる
- 通常のグローバル変数では既定で有効
- precise:近似による算術命令の最適化を禁止する
- addとmulをmadにまとめる、など
- shared:エフェクト間で変数を共有していることを示すヒント
- techniqueやpassがあったころの名残?
- static:変数が永続化する
- グローバル変数ではアプリケーション側から見えなくなる
- uniform:変数の値が実行中に一意に定まる
- グローバル変数では既定で有効
- volatile:(予約済み)
頂点シェーダ出力およびピクセルシェーダ入力に指定できるもの
- linear:線形補間
- 指定なしの場合に既定で有効
- centroid:ピクセル位置がプリミティブ範囲内に納まるようにする
- マルチサンプリングでピクセル位置がプリミティブ範囲外に出てしまうときのエラーを回避できる
- 参考:GLSLにおける補間に関する修飾子
- nointerpolation:補間しない
- noperspective:perspective-correctionを行わない
- sample:サンプリング位置を使う
- シェーダーモデル4.1から利用できる
- ピクセルシェーダがサンプルごとに走るようになる
コンピュートシェーダで指定できるもの
- groupshared:変数がスレッドグループで共有されるメモリに置かれる
Type_Modifier(型修飾子)
- const:値を変更できない
- グローバル変数では既定で有効
- row_major/column_major:変数が行優先/列優先で格納される
- 既定ではcolumn_majorが有効
Type(型)
参考:https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-data-types
- スカラ
- bool:true or false
- int:32ビット符号あり整数
- uint:32ビット符号なし整数
- dword:32ビット符号なし整数
- half:16ビット浮動小数点数(相当)
- 互換性のために通常はfloatにマップされる
-enable-16bit-typesオプションを有効にすると、実際に16ビットになる
- float:32ビット浮動小数点数
- double:64ビット浮動小数点数
- min16float:最低限16ビットの浮動小数点数
- min10float:最低限10ビットの浮動小数点数
- min16int:最低限16ビットの符号あり整数
- min12int:最低限12ビットの符号あり整数
- min16uint:最低限16ビットの符号なし整数
- snorm float:の範囲に正規化されるfloat
- unorm float:の範囲に正規化されるfloat
- string:文字列
- HLSL 2018以降では、int16_t、uint32_t、float64_tなどのビット数指定型も利用できる
- 64ビット整数はシェーダーモデル6.0から利用できる
- 16ビット型はシェーダーモデル6.2から利用できる
-enable-16bit-typesオブションが追加で必要
- 参考:https://github.com/microsoft/DirectXShaderCompiler/wiki/16-Bit-Scalar-Types
- ベクトル
- スカラ型の後ろに要素数をつける:int1、float3、など
vector<Type, NumComponents>でも可
- 行列
- スカラ型の後ろに”行数x列数”をつける:int1x1、float4x3、など
matrix<Type, NumRows, NumColumns>でも可
- サンプラ
- SamplerStateやSamplerComparisonStateを使う
- sampler、sampler1D、sampler2D、sampler3D、samplerCUBEはテクスチャと紐づいていたDirectX9時代の名残なので、現在は不要
- Static samplerはRoot signatureで定義する
- 初期化構文も古い時代の名残なので、現在は不要
- SamplerStateやSamplerComparisonStateを使う
- テクスチャ
- Texture1D、Texture1DArray、Texture2D、Texture2DArray、Texture3D、TextureCubeを使う
- textureは古い時代の名残なので、現在は不要
- 取得する値の型は
Texture2D<T>の形で指定する
- RWTexture系は書き込みができる
- Texture1D、Texture1DArray、Texture2D、Texture2DArray、Texture3D、TextureCubeを使う
- バッファ
ConstantBuffer<T>:定数バッファBuffer<T>:いわゆる配列だが、古いやつ- 1D Textureに相当
- Textureしかランダムアクセスできなかった時代の名残
- 2022/02/06現在、ベクトルで第1要素しか取れない不具合?に遭遇
- float3がfloat.xxxに化ける
- StructuredBufferなら問題なく動作する
- 参考:https://forum.unity.com/threads/compute-shader-buffer-rwbuffer-vs-structuredbuffer-rwstructuredbuffer.755672/
StructuredBuffer<T>:いわゆる配列で、新しいやつ- T型の値を読み出す
- AppendStructuredBufferはpush_backができる
- ConsumeStructuredBufferはpop_backができる
- ByteAddressBuffer:いわゆるバイト列
- StructuredBufferのような型指定はできないが、DXCならLoadメソッドに出力の型を指定できる
Name[Index]
変数名および配列要素数
- 通常、配列のインデックスは定数である(ドローコール内で変化しない)必要がある
- 定数でないことをコンパイラに伝えるためには
NonUniformResourceIndex(index)を使う
- 定数でないことをコンパイラに伝えるためには
Semantic
- 参考:
- 入出力を一致させるためにユーザーが任意に付ける
- システムに値を入出力するには、
SV_*のSemanticを指定する- SV_Position:スクリーン空間での頂点位置
- 頂点シェーダの出力、または、ピクセルシェーダの入力
- SV_Position:スクリーン空間での頂点位置
Packoffset
Register
- register(t0, space0)の形
- 第一引数は対応するデスクリプタを指定する
- tはSRV、bはCBV、uはUAV、sはサンプラを示す
- 後ろには0以上の番号をつける
- 第二引数は識別用番号を示す
- spaceが異なれば第一引数は重複しても良い
- 省略すればspace0とみなす
- 第一引数は対応するデスクリプタを指定する
Annotations
フロー制御
- C言語のものをそのままの形で利用できる
- discard文:出力を行わない。ピクセルシェーダで利用できる。
- forやwhileで使える属性:
[unroll(X)]:ループを展開する。Xは打ち切る回数、省略可。[loop]:ループを展開しない。[fastopt]:コンパイル時間を減らすように最適化を抑制する。[allow_uav_condition]:UAVから読み出した値を条件式に使えるようにする。
ifやswitchで使える属性
[branch]:CPUと同等の分岐処理。条件式によっていずれかのブロックのみを実行する。[flatten]:両方のブロックを実行して、計算結果を条件式によって選択する。
switchで使える属性
[forcecase]:Force a switch statement in the hardware.- 意味がわからん
[call]:各caseをサブルーチンにする
関数
参考:https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/d3d11-graphics-reference-sm5-attributes
属性
- earlydepthstencil:シェーダ実行前にデプスステンシルテストを行う
- ピクセルシェーダ。SM5.0から
- RootSignature(string):stringで定義されるRoot Signatureを組み込む
クラス
- クラスというより集成体とった趣のもの
T v = {...}で宣言時に中身を初期化する- メンバー関数は問題なく定義できる
- 2022/05/11時点のコンパイラでは以下は使用できなかった
- コンストラクタやデストラクタ
- publicやprivate
DXCで使える機能
- HLSL 2017から
- enumおよびenum class
- HLSL 2018から
- ビット数指定型
- HLSL 2021から
- template関数
- templateクラス
- ビットフィールド
- 演算子オーバーロード
- C++相当の関数オーバーロード
Root Signatureの記法
[RootSignature(”string”)]属性を関数にアタッチする- コンパイラオプションによって、シェーダバイナリに含めたり、単体のバイナリにしたりできる
- シェーダバイナリに含まれる場合、そのBlobはシェーダとしてもRootSigとしても渡すことができる
- Root Signatureの構成はコンマ区切りの文字列として定義される
RootFlags(flags)- フラグを指定する。省略可
- flagsには
0またはD3D12_ROOT_SIGNATURE_FLAGSの値をOR演算子で連結して指定するD3D12_ROOT_SIGNATURE_FLAG_以降を使う
RootConstants(num32BitConstants=#, b# [, space=0, visibility=SHADER_VISIBILITY_ALL])- ルート定数
visibilityはD3D12_SHADER_VISIBILITYの値を指定するD3D12_以降を使う
CBV(b# [, space=0, visibility=SHADER_VISIBILITY_ALL, flags=DATA_VOLATILE])- ルートレベルCBV
SRV(t# [, space=0, visibility=SHADER_VISIBILITY_ALL, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE])- ルートレベルSRV
UAV(u# [, space=0, visibility=SHADER_VISIBILITY_ALL, flags=DATA_VOLATILE])- ルートレベルUAV
DescriptorTable(... [, visibility=SHADER_VISIBILITY_ALL])...には以下が記述できるCBV(b# [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE])SRV(t# [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE])UAV(u# [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, flags=DATA_VOLATILE])Sampler(s# [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, flags=0])
numDescriptors=unboundedで要素数を不問にできるが、範囲外チェックが省略される
StaticSampler(s# [, filter=, addressU=, addressV=, addressW=, mipLODBias=0.f, maxAnisotropy=16, comparisonFunc=, borderColor=, minLOD=0.f, maxLOD=, space=0, visibility=SHADER_VISIBILITY_ALL])- 静的サンプラ