2017-03-02 22 views
0

내 인스턴스를 그리기 위해 ExecuteIndirect를 사용하려고합니다. ,간접 명령 버퍼를 확장 할 때 AMD GPU에서 ExecuteIndirect가 충돌했습니다.

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 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 
} 

업데이트 간접 명령 버퍼 데이터 : 간접 명령 버퍼를 덧붙이

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))); 
} 

: 여기

내 코드입니다

씬을로드하기 위해 씬 관리자를 사용합니다. gameObject가 렌더링 객체 인 경우 내 시스템에서 AppendIndirectCommandBuffer()를 호출하고 데이터를 간접 명령 버퍼로 복사합니다.

내 장면을 초기화 한 후 내 gameobject를 복제하지 않으면 ExecuteIndirect()가 잘 작동합니다.

그리고 런타임 (내 Update())에서 내 gameobject를 복제하려고합니다.

내 시스템은 AppendIndirectCommandBuffer()를 다시 호출하여 간접 명령 버퍼의 크기를 조정하고 버퍼에 새 데이터를 복사합니다.

몇 초 동안 게임 오브젝트를 복제 한 후 내 시스템 내 R9 380

에 TDR에있는 결함과 결과를하기 시작하지만 모두 WARP와 인텔 GPU에서 제대로 작동합니다.

그리고

이 문제를 해결하는 방법? 난 정말 간접 도면을 잘 활용하고 싶은 이유 :(. 모르겠어요.

감사합니다!

업데이트

업로드 힙 자원 수 없습니다 D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT에 교통. 내가 만들

기본 유형 힙 및 업로드 힙을 사용하여 데이터를 복사합니다.

디버그 레이어를 시도했지만 오류가 반환되지 않았습니다. 나는 GBV 시도 만이 오류를 가지고 :

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] 

나는 다음과 같은 함수를 호출 한 후,이 두 가지 오류가 사라합니다.

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

또한 큰 차이를 만들 수있는 하드웨어 기능 티어가 있어야합니다. DirectX 12 용 DirectX Tool Kit (https://github.com/Microsoft/DirectXTK12)에서 Tier 1 리소스 바인딩 시스템에서만 재 작성했지만 Tier 2 이상에서는 제대로 작동하는 여러 가지 문제가 발생했습니다. 이것이 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에서 삭제 된 리소스를 사용하면 보호 장치가 없기 때문에 그 중 하나입니다. 간접 버퍼에서 주소를 다시하지 않을 수 있습니다. 예약 된 자원을 사용하는 경우, 최악의 경우에 충분히 큰 인스턴스 데이터 자원을 작성하고 인스턴스를 추가 할 때 페이지를 확약 할 수 있습니다. 그러면 gpu 가상 주소는 계속 유지됩니다. – galop1n