d3d:d3d12:indirect
目次
Indirect Drawing と CommandSignature
Direct3D 12 の Indirect Draw command では、Shader に渡すパラメータも定義することができます。 定義可能なのは Buffer のアドレスと CBV の内容 (RootConstant) です。 Command 内で Texture や Sampler を変更することはできません。
Command (Argument Buffer) で渡せるもの
- Draw 命令のパラメータ (Index 数, Vertex数, Instance 数、それぞれの offset 等)
- Dispatch 命令のパラメータ
- VertexBuffer の GPU Address
- RootSignature Parameter の更新
- RootDescriptor CBV の GPU Address
- RootDescriptor SRV (Buffer) の GPU Address
- RootDescriptor UAV (Buffer) の GPU Address
- Root32bitConstant の値
どのようなパラメータを渡すのか、予めフォーマットを定義しておく必要があります。
- 2015/09/21 現在判明している問題
- RADEON GCN 15.8 で Root32bitConstant/RootDescriptor が反映されない問題があります。
- GeForce Kepler/Maxwell では Driver 355.82 以降が必要です。それ以前だと RootDescriptor が反映されません。
- Intel HD Graphics では RootSignature に 32bitConstant が複数存在する場合 CommandSignature で最初の constant しか反映されません。
Type | Argument Data |
---|---|
D3D12_INDIRECT_ARGUMENT_TYPE_DRAW | D3D12_DRAW_ARGUMENTS |
D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED | D3D12_DRAW_INDEXED_ARGUMENTS |
D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH | D3D12_DISPATCH_ARGUMENTS |
D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW | D3D12_VERTEX_BUFFER_VIEW |
D3D12_INDIRECT_ARGUMENT_TYPE_INDEX_BUFFER_VIEW | D3D12_INDEX_BUFFER_VIEW |
D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT | 32bit Constant Data |
D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW | D3D12_GPU_VIRTUAL_ADDRESS |
D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW | D3D12_GPU_VIRTUAL_ADDRESS |
D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW | D3D12_GPU_VIRTUAL_ADDRESS |
CommandSignature
Root 32bit Constant
CommandSignature は Argument Buffer のフォーマットを定義します。 下記の例では、ArgumentBuffer に直接 Matrix を埋め込んでいます。 描画のたびに RootSignature の Parameter Slot 0 が置き換わるわけです。
struct DrawArgument { math::Matrix44 WorldMatrix; D3D12_DRAW_INDEXED_ARGUMENTS Draw; }; D3D12_INDIRECT_ARGUMENT_DESC arg[2]; memset( arg, 0, sizeof(arg) ); arg[0].Type= D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT; arg[0].Constant.RootParameterIndex= 0; arg[0].Constant.DestOffsetIn32BitValues= 0; arg[0].Constant.Num32BitValuesToSet= sizeof(math::Matrix44)/sizeof(float); // 16 arg[1].Type= D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; D3D12_COMMAND_SIGNATURE_DESC desc; memset( &desc, 0, sizeof(desc) ); desc.ByteStride= sizeof(DrawArugment); desc.pArgumentDescs= arg; desc.NumArgumentDescs= 2; iD3DDevice->CreateCommandSignature( &desc, iRootSignature, IID_PPV_ARGS(&iCommandSignature) );
バッファ内のパラメータ配置例。CPU で書き込んでいますが、もちろん ComputeShader を用いて動的に作成することも可能。
void* ptr= nullptr; iArgumentBuffer->Map( 0, nullptr, &ptr ); auto arg= reinterpret_cast<DrawArgument*>( ptr ); for( int i= 0 ; i< OBJECT_COUNT ; i++, arg++ ){ arg->WorldMatrix= matrix; arg->Draw.IndexCountPerInstance= index_count; arg->Draw.InstanceCount= 1; arg->Draw.StartIndexLocation= 0; arg->Draw.BaseVertexLocation= 0; arg->Draw.StartInstanceLocation= 0; }
実行
iCommandList->ExecuteIndirect( iCommandSignature, OBJECT_COUNT, iArgumentBuffer, 0, nullptr, 0 );
Root Descriptor
RootDescriptor は GPU Address を直接格納します。
struct DrawArgument { // 32byte D3D12_GPU_VIRTUAL_ADDRESS Geometry; // 8byte D3D12_DRAW_INDEXED_ARGUMENTS Draw; // 20byte unsigned int Padding; // 4byte }; D3D12_INDIRECT_ARGUMENT_DESC arg[2]; memset( arg, 0, sizeof(arg) ); arg[0].Type= D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW; arg[0].ConstantBufferView.RootParameterIndex= 0; arg[1].Type= D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; D3D12_COMMAND_SIGNATURE_DESC desc; memset( &desc, 0, sizeof(desc) ); desc.ByteStride= sizeof(DrawArugment); desc.pArgumentDescs= arg; desc.NumArgumentDescs= 2; iD3DDevice->CreateCommandSignature( &desc, iRootSignature, IID_PPV_ARGS(&iCommandSignature) );
参照するバッファの作成
D3D12_RESOURCE_DESC desc; memset( &desc, 0, sizeof(desc) ); desc.Dimension= D3D12_RESOURCE_DIMENSION_BUFFER; desc.Width= OBJECT_COUNT * AlignedGeometryBufferSize; // 256byte alignment desc.Height= 1; desc.DepthOrArraySize= 1; desc.MipLevels= 1; desc.SamleDesc.Count= 1; desc.Layout= D3D12_TEXTURE_LAYOUT_ROW_MAJOR; D3D12_HEAP_PROPERTIES heap; memset( &heap, 0, sizeof(heap) ); heap.Type= D3D12_HEAP_TYPE_UPLOAD; ID3D12Resource* iGeometryBuffer= nullptr; iD3DDevice->CreateCommittedResource( &heap, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&iGeometryBuffer) );
Command を作成します。
D3D12_GPU_VIRTUAL_ADDRESS addr= iGeometryBuffer->GetGPUVirtualAddress(); void* ptr= nullptr; iArgumentBuffer->Map( 0, nullptr, &ptr ); auto arg= reinterpret_cast<DrawArgument*>( ptr ); for( int i= 0 ; i< OBJECT_COUNT ; i++, arg++ ){ arg->Geometry= addr + AlignedGeometryBufferSize * i; arg->Draw.IndexCountPerInstance= index_count; arg->Draw.InstanceCount= 1; arg->Draw.StartIndexLocation= 0; arg->Draw.BaseVertexLocation= 0; arg->Draw.StartInstanceLocation= 0; }
d3d/d3d12/indirect.txt · 最終更新: 2015/09/22 20:27 by oga