2017-03-02 23 views
0

インスタンスを描画するためにExecuteIndirectを使用しようとしています。ここで間接コマンドバッファを拡張すると、AMD GPUでExecuteIndirectがクラッシュする

は私のコードです:

間接コマンド・バッファを追加は
struct IndirectCommand 
{ 
    D3D12_GPU_VIRTUAL_ADDRESS materialBufferAddress; 
    D3D12_GPU_VIRTUAL_ADDRESS instanceBufferAddress; 
    D3D12_DRAW_INDEXED_ARGUMENTS drawArguments; 
}; // byte stride: 40 

// code for initializing command signature 
void InstanceManager::InitIndirectBuffer() 
{ 
    D3D12_INDIRECT_ARGUMENT_DESC indirectDescs[3] = {}; 
    indirectDescs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW; 
    indirectDescs[0].ConstantBufferView.RootParameterIndex = cMaterialPass; 
    indirectDescs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW; 
    indirectDescs[1].ShaderResourceView.RootParameterIndex = cInstancePass; 
    indirectDescs[2].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; 

    D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc = {}; 
    commandSignatureDesc.pArgumentDescs = indirectDescs; 
    commandSignatureDesc.NumArgumentDescs = _countof(indirectDescs); 
    commandSignatureDesc.ByteStride = sizeof(IndirectCommand); 

    ThrowIfFailed(Engine::GetApp()->GetDevice()->CreateCommandSignature(&commandSignatureDesc, Engine::GetApp()->GetRootSignature(), IID_PPV_ARGS(&mCommandSignature))); 
} 

void AppendIndirectCommandBuffer() 
{ 
    // wait for gpu 
    Engine::GetApp()->ResetCommandList(); 
    Engine::GetApp()->ExecuteCommand(); 
    Engine::GetApp()->FlushCommandQueue(); 

    for (int i = 0; i < gNumFrameResources; i++) 
    { 
     // alloc upload heap 
     Engine::GetApp()->GetFrameManager().GetFrameResource(i)->AppendUploadBuffer<IndirectCommand>(mIndirectBufferUpload[i] 
      , mLastIndirectUploadCount[i] 
      , mIndirectCount 
      , false); 

     // alloc default heap 
     Engine::GetApp()->GetFrameManager().GetFrameResource(i)->AppendDefaultBuffer<IndirectCommand>(mIndirectBufferDefault[i] 
      , mLastIndirectDefaultCount[i] 
      , mIndirectCount++ 
      , false); 
    } 
    UpdateIndirectData(_obj); 
    // code for appending indirect command buffer 
} 

更新間接コマンド・バッファのデータ:

void UpdateIndirectData(GameObject _obj) 
{ 
    UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialData)); 
    UINT insCBByteSize = sizeof(InstanceData); 

    for (int i = 0; i < gNumFrameResources; i++) 
    { 
     if (Engine::GetApp()->GetFrameManager().GetFrameResource(i) != NULL) 
     { 
      string _matName = _obj->GetComponent<RenderObject>()->GetMaterialName(); 
      string _geoName = _obj->GetComponent<RenderObject>()->GetGeometryName(); 
      Material *mat = Engine::GetApp()->GetMaterialManager().GetMaterial(_matName); 

      if (mat != nullptr) 
      { 
       IndirectCommand data; 

       data.materialBufferAddress = Engine::GetApp()->GetMaterialManager().GetMaterialBuffer(i)->Resource()->GetGPUVirtualAddress() 
       + matCBByteSize*mat->GetMatBufferIndex(); 

       data.instanceBufferAddress = mInstanceBuffer[i]->Resource()->GetGPUVirtualAddress() + mInstanceIndex[_obj->GetID()] * insCBByteSize; 

       data.drawArguments.BaseVertexLocation = mDrawArgs[_geoName].BaseVertexLocation; 
       data.drawArguments.IndexCountPerInstance = mDrawArgs[_geoName].IndexCount; 
       data.drawArguments.StartIndexLocation = mDrawArgs[_geoName].StartIndexLocation; 
       data.drawArguments.StartInstanceLocation = 0; 
       data.drawArguments.InstanceCount = 1; 

       int indirectIndex = mIndirectIndex[_obj->GetID()]; 
       mIndirectCommand[indirectIndex] = data; // an array of indirect command, size is set to 1000 temporarily 

       // copy to default heap 
       D3D12_SUBRESOURCE_DATA commandData = {}; 
       commandData.pData = reinterpret_cast<UINT8*>(&mIndirectCommand[0]); 
       commandData.RowPitch = sizeof(IndirectCommand) * mIndirectCount; 
       commandData.SlicePitch = commandData.RowPitch; 
       UpdateSubresources<1U>(Engine::GetApp()->GetCommandList(), mIndirectBufferDefault[i]->Resource(), mIndirectBufferUpload[i]->Resource(), 0, 0, 1, &commandData); 
      } 
     } 
    } 
} 

最終、executeindirect

void DrawIndirectInstance() 
{ 
    Engine::GetApp()->GetCommandList()->IASetVertexBuffers(0, 1, &mGeometry->VertexBufferView()); 
    Engine::GetApp()->GetCommandList()->IASetIndexBuffer(&mGeometry->IndexBufferView16()); 
    Engine::GetApp()->GetCommandList()->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 

    // just set a pso for testing, I haven't group my instances by material yet 
    ID3D12PipelineState *pso = Engine::GetApp()->GetMaterialManager().GetMaterialPSO("test"); 
    Engine::GetApp()->GetCommandList()->SetPipelineState(pso); 

    int frameIndex = Engine::GetApp()->GetFrameManager().GetCurrFrameIndex(); 
    auto indirectBuffer = mIndirectBufferUpload[frameIndex].get(); 

    auto materialBuffer = Engine::GetApp()->GetMaterialManager().GetMaterialBuffer(frameIndex); 
    Engine::GetApp()->GetCommandList()->SetGraphicsRootConstantBufferView(cMaterialPass, materialBuffer->Resource()->GetGPUVirtualAddress()); 
    Engine::GetApp()->GetCommandList()->SetGraphicsRootShaderResourceView(cInstancePass, mInstanceBuffer[frameIndex]->Resource()->GetGPUVirtualAddress()); 

    Engine::GetApp()->GetCommandList()->ResourceBarrier(1 
    , &CD3DX12_RESOURCE_BARRIER::Transition(indirectBuffer->Resource(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT)); 

    Engine::GetApp()->GetCommandList()->ExecuteIndirect(mCommandSignature.Get() 
    , mIndirectCount 
    , indirectBuffer->Resource() 
    , 0 
    , nullptr 
    , 0); 

    Engine::GetApp()->GetCommandList()->ResourceBarrier(1 
    , &CD3DX12_RESOURCE_BARRIER::Transition(indirectBuffer->Resource(), D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT, D3D12_RESOURCE_STATE_COPY_DEST)); 
} 

SceneManagerを使用してシーンを読み込みます。ゲームオブジェクトがレンダーオブジェクトの場合 私のシステムはAppendIndirectCommandBuffer()を呼び出し、間接コマンドバッファにデータをコピーします。

シーンの初期化後に私のゲームオブジェクトをクローンしないと、ExecuteIndirect()がうまくいくでしょう。

私は実行時に自分のgameobjectをクローンしようとしました(私のUpdate())。

私のシステムは、間接コマンドバッファのサイズを変更するために再度AppendIndirectCommandBuffer()を呼び出し、新しいデータをバッファにコピーします。

数秒のためのゲームオブジェクトをクローニングした後、私のシステムは、私のR9 380

にグリッチとTDRをもたらすために起動しますが、WARPとIntelのGPUの両方で正常に動作します。

そして私はなぜ:(を知らない。この問題を解決する方法

?私は本当に間接的な描画を有効に利用することにしたい。

ありがとう!

更新

アップロードヒープリソースがD3D12_RESOURCE_STATE_INDIRECT_ARGUMENTに転送できません。

既定の型ヒープ、およびアップロードヒープを使用してデータをコピーします。

デバッグレイヤーを試しましたが、エラーは返されません。 私はGBVを試してみましたが、唯一の2つのエラーを得た:

D3D12 ERROR: GPU-BASED VALIDATION: Draw, Uninitialized root argument accessed. Shader Stage: VERTEX, Root Parameter Index: [2], Draw Index: [0], Shader Code: Forward.hlsl(21,2-42), Asm Instruction Range: [0x114-0x13b], Asm Operand Index: [3], Command List: 0x00000134BB3C1EE0:'Unnamed ID3D12GraphicsCommandList Object', SRV/UAV/CBV Descriptor Heap: 0x00000134AE6DD020:'Unnamed ID3D12DescriptorHeap Object', Sampler Descriptor Heap: <not set>, Pipeline State: 0x00000134BB5CB540:'Unnamed ID3D12PipelineState Object', [ EXECUTION ERROR #935: GPU_BASED_VALIDATION_ROOT_ARGUMENT_UNINITIALIZED] 
D3D12 ERROR: GPU-BASED VALIDATION: Draw, Uninitialized root argument accessed. Shader Stage: VERTEX, Root Parameter Index: [1], Draw Index: [0], Shader Code: Forward.hlsl(37,2-41), Asm Instruction Range: [0x8c0-0x8e3], Asm Operand Index: [2], Command List: 0x000001D0D7B70860:'Unnamed ID3D12GraphicsCommandList Object', SRV/UAV/CBV Descriptor Heap: 0x000001D0D7AC6C80:'Unnamed ID3D12DescriptorHeap Object', Sampler Descriptor Heap: <not set>, Pipeline State: 0x000001D0D7BBF450:'Unnamed ID3D12PipelineState Object', [ EXECUTION ERROR #935: GPU_BASED_VALIDATION_ROOT_ARGUMENT_UNINITIALIZED] 

そして警告:私は次の関数呼び出し

D3D12 WARNING: ID3D12CommandList::ExecuteIndirect: GPU-based validation is not supported for ExecuteIndirect that changes root bindings. All further GPU-based validation output may not be reliable. [ EXECUTION WARNING #1000: GPU_BASED_VALIDATION_UNSUPPORTED] 

した後、これら2つのエラーがなくなっています。

Engine::GetApp()->GetCommandList()->SetGraphicsRootConstantBufferView(cMaterialPass, materialBuffer->Resource()->GetGPUVirtualAddress()); 
Engine::GetApp()->GetCommandList()->SetGraphicsRootShaderResourceView(cInstancePass, mInstanceBuffer[frameIndex]->Resource()->GetGPUVirtualAddress()); 

これらの変更を行っても、それでも正常に動作しません。

+0

デバッグレイヤーとgpuベースの検証を試したことがありますか? GCNハードウェアのキャッシュフラッシュに必要な、間接的な引数の状態遷移がコード内に表示されません。 – galop1n

+0

これは、DirectX 12が提供する低レベルの露出のレベルに伴うコストです。ハードウェアスイート全体の特定のアプリケーションのトラブルシューティングと検証が可能である必要があります。 Direct3Dのデバッグ層は、WARP12を試しているように、常に良いスタート地点ですが、問題がドライバかアプリかどうかを診断してから、ハードウェアベンダーに手を差し伸べるために、数多くの異なるマシンを用意する必要がありますベータドライバーを試してみてください。 [Direct3D 12デバイスの作成](https://blogs.msdn.microsoft.com/chuckw/2016/08/16/anatomy-of-direct3d-12-create-device/)を参照してください。 –

+0

また、大きな違いを生む可能性のあるハードウェア機能の層が混在していることを確認してください。私はTier 1リソースバインディングシステムのみを再解析するが、Tier 2以上で正常に動作する[DirectX 12用のDirectX Tool Kit](https://github.com/Microsoft/DirectXTK12)でいくつかの問題にぶつかった。これは主に、DirectX 11の実装を制限する前にDirectX 12を使用することが、プロジェクトの時間を生産的に使用しないことがある理由の大きな原因です。もちろん、それが学習のエクササイズであれば、あなたがバックグラウンドを持っている限り、今では良いレッスンを学んでいます。 –

答えて

1

最後に、私は理由を見つける!

バグは私のインスタンスデータバッファからです。

Engine::GetApp()->GetFrameManager().GetFrameResource(i)->AppendUploadBuffer<InstanceData>(mInstanceBuffer[i] 
      , mLastInstanceCount[i] 
      , mInstanceCount 
      , false); 

これを呼び出した後、メモリアドレスがに変更されます。 次のコードで間接コマンドバッファデータを設定すると、GPUがクラッシュします。

data.instanceBufferAddress = mInstanceBuffer[i]->Resource()->GetGPUVirtualAddress() + mInstanceIndex[_obj->GetID()] * insCBByteSize; 

は、だから私は、初期化時に固定サイズのインスタンスのバッファを作成します(アドレスは変更されません)または(パフォーマンスを殺す)私のゲームオブジェクトのクローンを作成した後、以前のすべての間接コマンド・データを更新するのいずれかが必要です。

愚かな質問を申し訳ありません:$。

+0

d3d12の削除されたリソースを使用することは、セーフガードの不足のためにその1つです。間接的なバッファにアドレスをやり直すことはできません。予約済みのリソースを使用する場合は、最悪の場合に十分な大きさのインスタンスデータリソースを作成し、インスタンスを追加するときにページをコミットできます。そうすれば、gpu仮想アドレスは一定のままです。 – galop1n

関連する問題