コンピュータープログラミング

HLSL関連メモ(コンピュートシェーダ)

このメモの目的

公式ドキュメントを読んでいてこんがらがってきたので、なんとか利用できるようにシェーダ周りの内容でメモっていた分をテキスト化しておく試行。
前回端折ったコンピュートシェーダ関連のまとめを追加しました。

グラフィックスパイプライン関連のまとめは こちら(HLSL関連メモ) に。

パイプライン?

  1. CS : コンピュートシェーダ
    (それぞれの単位で分割可能なデータに対する)計算を、GPUの大量のスレッド(処理の最小単位)を並走させて高速演算処理する。

パイプラインらしいパイプラインが存在しないっぽい。上流下流の概念が見当たらない。

GPU内に、計算に必要な入力情報と計算結果を書き込むための出力情報用のレジスタを定義しておき、必要に応じて読み書きすることで、プログラム上で結果を得る仕組み。

関連の概念

[グループ(group)]
ディスパッチ単位。計算はディスパッチ単位に分割されグループとして処理される。
グループは複数のスレッドを束ねる。

[スレッド(thread)]
処理の最小単位。グループ毎に束ねられ同時並走処理される。

[グループ共有(groupshared)]
同一グループ内で同時並走中の別スレッドが、データを共有できるように管理するキーワード。
スレッドで共有データを書き込んだ際、 GroupMemoryBarrierWithGroupSync(); で別スレッドが同一処理を完了するまで待機する必要がある。

[ウェーブ(Wave)] HLSL6.0 以降
ピクセルシェーダとコンピュートシェーダで利用可能な概念。
複数スレッドをまとめて扱う単位。グラフィックスカードによって 32 または 64 のいずれかが採用されているらしい。

  • [レーン(Lane)]
    ウェーブにまとめられた個別のスレッドを呼称する用語。
  • [アクティブレーン(ActiveLane)]
    現在命令実行の対象となっている(処理中の)スレッドのこと。
  • [非アクティブレーン(InactiveLane)]
    同ウェーブ内で、処理不要と判定され命令実行の対象になっていないスレッドのこと。
    同ウェーブ内の ActiveLane が完走するまで停止状態。
  • [ヘルパーレーン(HelperLane)]
    ピクセルシェーダで、ピクセルの出力を行わない補助的なスレッドを指す。
  • [Quad]
    4レーンを 1単位とする スレッドグループ。
    ┏━━━→ X
    ┃[0] [1]
    ┃[2] [3]

    Y
  • Wave を導入すると、同一Wave内の Active/Inactive の調査や、現在のカレントレーンが何番目かなどの調査ができるっぽい。
  • Wave を導入すると、同一Wave内の特定のレーンについてちょっかいがかけられるっぽい。
  • Wave を導入すると、同一Wave内の アクティブレーンの情報を統括して利用することができるっぽい。
  • Wave を導入すると、Quad の 左右上下データの参照とかができるっぽい。

CS

入力

Dispacth() 命令によって分割されたスレッドグループ を基準として、
それぞれのグループを numthredas 指定数で分割して同時並走スレッドとし、
スレッド毎にメソッドが呼び出される。

以下のシステム生成値を引数として利用可能

SV_GroupID

  • スレッドグループID
  • プログラム側から指定する
  • 3次元
  • commandlist.Dispatch( DispatchX, DispatchY, DispatchZ )
    x : 0 ~ DispatchX-1 の範囲のインデックス
    y : 0 ~ DispatchY-1 の範囲のインデックス
    z : 0 ~ DispatchZ-1 の範囲のインデックス

SV_GroupThreadID

  • 1スレッドグループに対して動作するスレッドのID
  • HLSL で メインメソッドの属性として指定する
  • 3次元
  • [ numthread( ThreadX, ThreadY, ThreadZ) ]
    x : 0 ~ ThreadX-1 の範囲のインデックス
    y : 0 ~ ThreadY-1 の範囲のインデックス
    z : 0 ~ ThreadZ-1 の範囲のインデックス

SV_GroupIndex

  • 1スレッドグループに対する スレッドの貫通番号
  • スレッドグループ毎に共有したいデータのインデックスアクセスに利用
  • groupshared キーワードのついた一次元データ配列とセットで使う模様
// グループ共有用のデータ変数
groupshard float data[ ThreadX * ThreadY * ThreadZ ];


[numthread( ThreadX, ThreadY, ThreadZ )]
void CS_Main( uint index: SV_GroupIndex ){
        // todo : 計算処理
        float value = 0;

        // グループ共有メモリに対する書き込み処理
        data[index] = value;
        // 待機命令
        GroupMemoryBarrierWithGroupSync();

        //  すべてのグループで 計算が終わるまで、ここでスレッドは待機される

        // todo: グループ共有データを使用した計算
       if( data[index] == 0 ){ ... }

}
  • 1次元
  • 0 ~ ((ThreadX-1) * ThreadY * ThreadZ) +
    ((ThreadY-1) * ThreadZ) +
    (ThreadZ-1)
    の範囲のインデックス
  • 現在スレッドが (x,y,z) を処理中の場合、
    (x * ThreadY * ThreadZ) +(y * ThreadZ) + (z)

SV_DispatchThreadID

  • スレッドグループとスレッドを総合した状態でのデータ座標
  • Dispatch する前のオリジナルデータに対する位置や座標のインデックスに相当
  • 3次元
  • commandlist.Dispatch( DispatchX, DispatchY, DispatchZ )
    [ numthread( ThreadX, ThreadY, ThreadZ) ]
    x : 0 ~ ( DispatchX * (ThreadX-1) ) の範囲のインデックス
    y : 0 ~ ( DispatchY * (ThreadY-1) ) の範囲のインデックス
    z : 0 ~ ( DispatchZ * (ThreadZ-1) ) の範囲のインデックス

出力

なし

計算結果を書き込むためのレジスタを予め設定しておく必要がある

レジスタ

TypeName<datatype> ParamName : register(x0) ;
各種類ごとにレジスタ番号は基本的に連番。
重複して問題ない設計(Read用/Write用等で別名アクセスするなど)ならば被り番号もあり。

  • u
    RW…
    UAVレジスタ (読み書き可能)
    例) RWTexture2D<float4> Dst : register(u0);

以下、UAV以外のレジスタも使用する場合の書式例

  • t
    テクスチャ用レジスタ(読み取り専用)
    例) Texture2D<float4> Src : register(t0);
  • s
    SamplerState
    サンプラステート(サンプリング用設定値)
    例) SamplerState Smp : register(s0);
  • b
    定数バッファ
    cbuffer CONST_DATA : resigter( b0 ){ type vaule; … }

関数制御属性

[ numthreads(X, Y, Z) ]
1グループ当たりの並走スレッド数
1グループ ごとに、この属性で指定された分割のスレッドが同時に演算処理を行う

利用可能なType

以下の型はピクセルシェーダとコンピュートシェーダで利用可能

  • AppendStructuredBuffer
    追記可能なユーザ定義構造体バッファ
    DXGI_FORMAT_UNKNOWN
    BUFFER_UAV_FLAG_APPEND
  • ConsumeStructuredBuffer
    読み取り用ユーザ定義構造体バッファ
    DXGI_FORMAT_UNKNOWN
    BUFFER_UAV_FLAG_APPEND
  • RWBuffer
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load
  • RWByteAddressBuffer
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load, Store, Interlocked
  • RWStructuredBuffer
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load
    Rawデータとして使用可能
  • RWTexture1D
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load, 配列アクセス
    ※ PixcelShader で同一メモリをTexture1Dとして使用する
  • RWTexture1DArray
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load, 配列アクセス
    ※ PixcelShader で同一メモリをTexture1DArrayとして使用する
  • RWTexture2D
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load, 配列アクセス
    ※ PixcelShader で同一メモリをTexture2Dとして使用する
  • RWTexture2DArray
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load, 配列アクセス
    ※ PixcelShader で同一メモリをTexture2DArrayとして使用する
  • RWTexture3D
    グローバルで共有されるリード/ライトバッファ
    読み書きには同期用のバリアが必要
    Load, 配列アクセス
    ※ PixcelShader で同一メモリをRWTexture3Dとして使用する