d3d:d3d12:query
Direct3D 12 Query
Query の使い方
- ID3D12Device CreateQueryHeap (複数まとめて確保可能)
- ID3D12Device CreateResource (Resolve バッファ) D3D12_HEAP_TYPE_READBACK
- ID3D12CommandList BeginQuery, EndQuery
- ID3D12CommandList ResolveQueryData
- ID3D12Resource Map (読み出し)
Query を使った Timestamp の例
初期化
typedef unsigned long long UI64; unsigned int Offset= 0; constexpr unsigned int FRAME_COUNT= 4; constexpr unsigned int QUERY_COUNT= 2; ID3D12QueryHeap* iQuery= nullptr; ID3D12Resource* iBuffer= nullptr; { D3D12_QUERY_HEAP_DESC desc; memset( &desc, 0, sizeof(desc) ); desc.Type= D3D12_QUERY_HEAP_TYPE_TIMESTAMP; desc.Count= QUERY_COUNT * FRAME_COUNT; iD3D12Device->CreateQueryHeap( &desc, IID_PPV_ARGS(&iQuery) ); } { D3D12_RESOURCE_DESC desc; memset( &desc, 0, sizeof(desc) ); desc.SampleDesc.Count= 1; desc.Dimension= D3D12_RESOURCE_DIMENSION_BUFFER; desc.Width= sizeof(UI64) * QUERY_COUNT * FRAME_COUNT; desc.Height= 1; desc.MipLevels= 1; desc.DepthOrArraySize= 1; desc.Layout= D3D12_TEXTURE_LAYOUT_ROW_MAJOR; D3D12_HEAP_PROPERTIES heap; memset( &heap, 0, sizeof(heap) ); heap.Type= D3D12_HEAP_TYPE_READBACK; iD3D12Device->CreateCommittedResource( &heap, 0, D3D12_RESOURCE_STATE_COPY_DEST, IID_PPV_ARGS(&iBuffer) ); } iD3D12Device->SetStablePowerState( true );
描画と計測
ID3D12GraphcisCommandList* iCommand; ~ iCommand->EndQuery( iQuery, D3D12_QUERY_TYPE_TIMESTAMP, Offset + 0 ); // BeginQuery ではなく EndQuery で正しい ~ Draw など iCommand->EndQuery( iQuery, D3D12_QUERY_TYPE_TIMESTAMP, Offset + 1 ); iCommand->ResolveQueryData( iQuery, D3D12_QUERY_TYPE_TIMESTAMP, Offset, 2, iBuffer, Offset * sizeof(UI64) ); ~ UI64 GPU_Freq= 0; iCommandQueue->GetTimestampFrequency( &GPU_Freq ); { unsigned int offset= Offset + QUERY_COUNT; if( offset >= FRAME_COUNT * QUERY_COUNT ){ offset= 0; } Offset= offset; }
読み出し
unsigned int start= (QUERY_COUNT * sizeof(UI64)) * ReadOffset; D3D12_RANGE range{ start, start + QUERY_COUNT * sizeof(UI64) }; void* ptr= nullptr; iBuffer->Map( 0, &range, &ptr ); auto data= reinterpret_cast<UI64*>( ptr ); float time_ms= (data[1] - data[0]) * 1000.0f / GPU_Freq; // 計測時間 ms iBuffer->Unmap( 0, nullptr );
同期
最近の GPU は他の描画とオーバーラップ実行されることが多く、必ずしも Command 実行時の TimeStamp が描画にかかった GPU 時間を計測しているとは限りません。単なる Command 発行間隔の計測になっている可能性があります。バッファが多ければ極端に短い結果を返す可能性があります。完了を待つには Fence が必要になるかもしれません。主に RADEON で差が出るようです。
Fence の作成
ID3D12Fence* iFence= nullptr; iD3D12Device->CreateFence( 0, 0, IID_PPV_ARGS(&iFence) ); UI64 FenceCount= 0;
Fence の挿入
iCommand->EndQuery( iQuery, D3D12_QUERY_TYPE_TIMESTAMP, Offset + 0 ); ~ Draw iCommand->Close(); { ID3D12CommandList* list[]= { iCommand }; iCommandQueue->ExecuteCommandLists( 1, list ); } iCommandQueue->Signal( iFence, FenceCount ); iCommandQueue->Wait( iFence, FenceCount ); FenceCount++; iCommand2->EndQuery( iQueue, D3D12_QUERY_TYPE_TIMESTAMP, Offset + 1 ); iCommand2->Close(); { ID3D12CommandList* list[]= { iCommand2 }; iCommandQueue->ExecuteCommandLists( 1, list ); }
d3d/d3d12/query.txt · 最終更新: 2015/09/10 03:27 by oga