DirectX10 で大きく仕様が変わったのは、より汎用化を進めるためでした。
つまり専用の機能が無くなったということ。
ライティングのための機能、マテリアルの設定などといった目的別の API は
完全に姿を消しています。
では CPU のように完全に何にでも使える、単純でフラットな空間が得られたのかと言えば必ずしも
そうではなく、特にリソースとバッファの扱いはかえって複雑になった印象を受けます。
汎用化や何にでも使えることが、そのまま単純化に繋がるとは限らないためです。
複数の機能の要素をマージしたこと、目的別の機能の代わりにより抽象的な用語や仕様が
増えたことがその要因といえるかもしれません。
DirectX11 はさらに CompteShader が使えるようになり、書き込み可能なバッファが
追加されています。
以下 FEATURE_LEVEL 11.0、 ShaderModel 5.0 を対象としています。
●リソース
Direct3D 11 では View も ShaderObject も種類が増えており何を見て良いのか
わからなくなります。
でもリソースを作る手段は二つだけ。CreateBuffer() か CreateTexture~() です。
Constant も Buffer だし、Vertex や Index もただの Buffer です。
● View
リソースをどう扱うか、それを決めるのが View です。
同じリソースを複数の View を通して見ることが可能で、テクスチャとして参照したり
レンダリングしたり、データとして読み書きするなど流用が可能となります。
View は次の 4種類だけです。
・読み込みのための View、テクスチャやバッファなど
ShaderResourceView (SRV)
・Merger による書き込みのための View
RenderTargetView (RTV)
DepthStencilView (DSV)
・読み書きのための View
UnorderedAccessView (UAV)
VertexBuffer/IndexBuffer/ConstantBuffer は View を用いずに設定します。
●タイプとシェーダーオブジェクト
データをアクセスする方法を決定するのが、バッファ作成時の細かい指定と
DXGI フォーマットタイプです。
Texture Buffer ByteAdddressBuffer StructuredBuffer AppendSturctutedBuffer ConsumeStructuredBuffer RWTexture RWBuffer RWSturcturedBuffer RWByteAddressBuffer
これらのシェーダーオブジェクトは、シェーダーがアクセスする方法を決定しています。
シェーダー側の宣言だけではだめで、リソース生成時にもいろいろとフラグを指定
しておく必要があります。
● UnorderedAccessView
RW がついているものと AppendSturctutedBuffer/ConsumeStructuredBuffer は
書き込み可能なシェーダーオブジェクトです。
これらは UnorderedAccessView (UAV) を使います。
UAV が使えるのは PixelShader と CompteShader だけ。
Compte Shader は Output Merger が無いので、出力のために必ず何らかの UAV を
用いることになります。
実際に使ってみると、出力はすべて UnorderedAccessView に相当することがわかってきます。
つまり RenderTarget も出力先アドレスが固定された UnorderedAccessView 相当だということです。
UAV の設定 API は次の通り
CompteShader → CSSetUnorderedAccessViews() PixelShader → OMSetRenderTargetsAndUnorderedAccessViews()
OMSetRenderTargetsAndUnorderedAccessViews() で一見何のために存在する
パラメータなのかわかりにくいのが UAVStartSlot です。
これは RenderTarget との衝突を避けるためのものでした。
例えば RenderTarget を 2 枚設定した場合は、UnorderedAccessView は必ず
番号 2 から始めなければなりません。
下記のようなリソースを登録する場合
RenderTarget x2
UnorderedAccessView x3
OMSetRenderTargetsAndUnorderedAccessViews() には次のようなパラメータを
渡します。
NumViews = 2 // RTV (RenderTargetView) の個数 UAVStartSlot = 2 // UAV (UnorderedAccessView) の開始番号 == NumViews NumUAVs = 3 // UAV の個数
※ August 2009 のマニュアル OMSetRenderTargetsAndUnorderedAccessViews()
の引数は若干間違いがあります。ヘッダファイルを見た方が正しい宣言です。
シェーダーレジスタはこのように割り当てられます。
o0 = RenderTarget o1 = RenderTarget u2 = UnorderedAccessView u3 = UnorderedAccessView u4 = UnorderedAccessView
つまり o レジスタと u レジスタは同時に同じ番号を使うことが出来ず、
使用可能な View はあわせて 8 個まで。この両者ほぼ同じ扱いです。
UnorderedAccessView は読み書き可能なバッファです。
よく考えると RenderTarget や DepthBuffer と同じこと。
UAV は読み込んだあとにブレンドしたり、判定した結果をまた書き戻すことが出来るわけです。
そのパス内で更新できる OM をプログラムできるなら、いろいろ面白いことが出来そうです。
実際試してみたらエラーで、RW で読み込めるのは sngle コンポーネントに限ると言われます。
時間がなかったので、このあたりは後ほどまた詳しく調べてみます。
昔わからないと書いた CSSetUnorderedAccessViews() の最後のパラメータは
Append/Consume buffer に関するものでした。
やはり当時のサンプルの使い方が間違っていたのだと思われます。
関連エントリ
・DirectX 11 / Direct3D 11 と RADEON HD 5870 の caps
・Direct3D11/DirectX11 (7) テセレータの流れの基本部分
・その他 Direct3D 11 関連