ユーザ用ツール

サイト用ツール


d3d:d3d12:query

Direct3D 12 Query

Query の使い方

  1. ID3D12Device CreateQueryHeap (複数まとめて確保可能)
  2. ID3D12Device CreateResource (Resolve バッファ) D3D12_HEAP_TYPE_READBACK
  3. ID3D12CommandList BeginQuery, EndQuery
  4. ID3D12CommandList ResolveQueryData
  5. 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