ユーザ用ツール

サイト用ツール


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