目次
RootSignature と Descriptor
Descriptor
リソースの情報を格納した構造体です。 GPU メモリに確保され、GPU が直接リソースを参照するために用いられます。
Descriptor を格納するメモリは DescriptorHeap から確保されます。 DescriptorHeap は GPU Memory に確保すると同時に System Memory にもミラーが作られ、CPU と GPU 両方からアクセスできるようになっています。
- Descriptor の作成時 : CreateShaderResourceView 等 (CPU の Descriptor Address)
- 描画時 : SetGraphicsRootDescriptorTable (GPU の Descriptor Address)
Descriptor が必要なリソースは下記の通り
- ConstantBufferView
- ShaderResourceView (Texture)
- UnorderedAccessView
- Sampler
- RenderTargetView
- DepthStencilView
Descriptor が消費する Heap のメモリ量は GPU によって異なります。下記の表の単位は byte です。
GPU | FeatureLevel | CBV_SRV_UAV | SAMPLER | RTV | DSV |
---|---|---|---|---|---|
RADEON GCN 1.0 | 11_1 | 32 | 16 | 32 | 144 |
RADEON GCN 1.1 | 12_0 | 32 | 16 | 32 | 144 |
GeForce Kepler | 11_0 | 32 | 32 | 32 | 8 |
GeForce Maxwell GM1 | 11_0 | 32 | 32 | 32 | 8 |
GeForce Maxwell GM2 | 12_1 | 32 | 32 | 32 | 8 |
Intel HD Graphics Gen7.5 | 11_1 | 32 | 16 | 32 | 96 |
Intel HD Graphcis Gen8 | 11_1 | 64 | 16 | 32 | 128 |
古い D3D11 世代の GPU では Descriptor Handle が仮想的な実装になっている可能性があります。
Descriptor Heap
CBV, SRV, UAV の Descriptor Heap は共有されています。
Descriptor HeapType | Descriptor |
---|---|
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV | ConstantBufferView, ShaderResourceView, UnorderedAccessView |
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER | Sampler |
D3D12_DESCRIPTOR_HEAP_TYPE_RTV | RenderTargetView |
D3D12_DESCRIPTOR_HEAP_TYPE_DSV | DepthStencilView |
つまり Shader に渡すパラメータ CBV, SRV, UAV は同じ Heap (Table) 上に並べてまとめて管理することができます。描画時に API に渡す場合一度に設定することができます。 一度の描画で参照できる DescriptorHeap は、HeapType 毎に 1 つだけなので注意が必要です。
ID3D12RootSignature
リソースとシェーダーの対応付けを行うための API である Parameter Slot を定義します。 また Slot に指定した Descriptor と Shader Register の対応付けも行います。
パラメータのレイアウトはアプリケーション側で自由に設計することが可能です。 RootSignature はいわばシェーダーに渡すパラメータ API がプログラマブルになったものと言えます。
初期の Shader Program と同じように、RootSignature には Slot サイズの上限があります。 現状では最大 64エントリ のみとなります。 なお Descriptor 自体はテーブルとして先頭アドレスを Slot に設定するだけなので、Descriptor の最大数には上限がありません。
RootSignature の各 Slot は下記のように Type に応じた Cost が設けられています。
- Cost 1 : DescriptorTable
- Cost 2 : Root Descriptor 直接
- Cost 1 : Root 32bit Constant (32bit 単位で1、float4 なら Cost4 になる)
例えば RootSignature を ConstantBuffer の 32bit 直値だけで埋めるなら最大で 64個まで入ります。つまり float4x4 を 4つ分。
RootSignature は PipelineState 作成時に必要で、また描画時にも CommandList に設定します。 RootSignature は定義内容が一致していれば同一とみなされます。 PipelineState と CommandList に異なる Object を与えても問題ありません。
RootSignature は Shader と同じように hlsl に記述することが可能で、fxc を使ってバイナリ化できます。
RootSignature と API
Shader にパラメータを渡す方法は複数存在しています。 下記はそのまとめです。
Type | Descriptor Heap | 設定 API | 描画時に設定する内容 | Reg | 設定個数 | 消費Cost | ||
---|---|---|---|---|---|---|---|---|
CBV | CBV_SRV_UAV | Descriptor Table | CommandList::SetGraphicsRootDescriptorTable() | 先頭の GPU Descriptor Handle | b | 複数 | 1 | |
CBV | - | Root Descriptor | CommandList::SetGraphicsRootConstantBufferView() | Resource GPU Address | b | 1 | 2 | |
CBV | - | Root Constants | CommandList::SetGraphicsRoot32BitConstants() | Constant Value | b | 1 | 1x個数 | |
SRV | CBV_SRV_UAV | Descriptor Table | CommandList::SetGraphicsRootDescriptorTable() | 先頭の GPU Descriptor Handle | t | 複数 | 1 | |
SRV | - | Root Descriptor | CommandList::SetGraphicsRootShaderResourceView() | Resource GPU Address | t | 1 | 2 | Raw/Structured のみ |
UAV | CBV_SRV_UAV | Descriptor Table | CommandList::SetGraphicsRootDescriptorTable() | 先頭の GPU Descriptor Handle | u | 複数 | 1 | |
UAV | - | Root Descriptor | CommandList::SetGraphicsRootUnorderedAccessView() | Resource GPU ADdress | u | 1 | 2 | Raw/Structured のみ |
Sampler | SAMPLER | Descriptor Table | CommandList::SetGraphicsRootDescriptorTable() | 先頭の GPU Descriptor Handle | s | 複数 | 1 | |
Sampler | - | Static Sampler | Device::CreateRootSignature() | s | 複数 | - | 動的に変更できない | |
RTV | RTV | Descriptor Table | CommandList::OMSetRenderTargets() | CPU Descriptor Handle | 複数 | - | ||
DSV | DSV | Descriptor Table | CommandList::OMSetRenderTargets() | CPU Descriptor Handle | 1 | - |
CBV, SRV, UAV, Sampler いずれも Descriptor Table を使う方法、使わない方法両方用意されています。 ただし SRV, UAV は Root Descriptor の場合 Sampler を使うことができません。 よって事実上 Texture Map として用いる場合は Descriptor Table を使う必要があります。
CBV は上記のように、DescriptorTable を使う場合、直接 Root Descriptor に設定する場合、値を RootSignature (Root 32bit Constant) に直接格納する場合の 3通りの手段があります。どの方法を用いても構いません。
API による速度の違い
RootSignature を使って Shader にパラメータを渡す方法は複数存在しています。 実際に RootSignature の設計によってどの程度パフォーマンスに差が生じるか調べてみました。
Core i7-4790K | Jaguar | N3150 | |||||
---|---|---|---|---|---|---|---|
Intel | GCN 1.0 | Kepler | Maxwell1 | Maxwell2 | GCN1.1 | Gen8 | |
const32bit | 18.33 | 9.88 | 11.26 | 8.25 | 13.35 | 14.80 | 36.61 |
root desc | 18.24 | 14.39 | 10.00 | 7.48 | 13.40 | 17.45 | 36.74 |
global handle | 18.44 | 11.70 | 9.00 | 8.06 | 12.80 | 15.48 | 33.74 |
buf shared | 18.25 | 11.69 | 9.90 | 7.44 | 13.31 | 14.72 | 35.53 |
cached | 10.76 | 11.70 | 13.50 | 12.60 | 12.51 | 10.48 | 21.20 |
Dynamic Heap | 25.66 | 35.54 | 15.96 | 15.00 | 15.18 | 133.73 | 79.77 |
Shared RS | 17.45 | 11.72 | 14.88 | 14.87 | 14.88 | 13.08 | 33.14 |
Separate RS | 18.25 | 11.70 | 10.25 | 9.50 | 12.20 | 13.25 | 33.66 |
Bundle const32bit | 18.67 | – | 9.00 | 8.75 | 9.87 | – | 35.50 |
Bundle root desc | 20.55 | – | 9.66 | 9.66 | 9.90 | – | 36.96 |
Bundle copy | 42.62 | – | 34.47 | 17.11 | 15.00 | – | 67.93 |
Bundle cached | 20.35 | – | 8.23 | 8.41 | 9.90 | – | 35.22 |
Bundle2 | 21.26 | 28.28 | 15.36 | 15.28 | 15.50 | 90.24 | 66.38 |