내 인스턴스를 그리기 위해 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());
이러한 수정을 했음에도 불구하고 여전히 제대로 작동하지 않습니다.
디버그 레이어 및 GPU 기반 유효성 검사를 해 보셨습니까? GCN 하드웨어의 일부 캐시 플러시에 필요한 코드의 간접 인수로의 상태 전환이 표시되지 않습니다. – galop1n
이것은 DirectX 12가 제공하는 낮은 수준의 노출 수준과 함께 제공되는 비용입니다. 일련의 하드웨어에서 특정 응용 프로그램의 문제를 해결하고 유효성을 검사 할 수 있어야합니다. Direct3D 디버그 레이어는 항상 WARP12를 시도하는 것처럼 좋은 출발점이지만 문제가 드라이버 또는 앱인 경우 진단을 위해 여러 대의 컴퓨터가 있어야합니다. 그런 다음 하드웨어 공급 업체에 연락하십시오. 베타 드라이버를 사용해보십시오. [Direct3D 12 장치 생성 분석] (https://blogs.msdn.microsoft.com/chuckw/2016/08/16/anatomy-of-direct3d-12-create-device/)을 참조하십시오. –
또한 큰 차이를 만들 수있는 하드웨어 기능 티어가 있어야합니다. DirectX 12 용 DirectX Tool Kit (https://github.com/Microsoft/DirectXTK12)에서 Tier 1 리소스 바인딩 시스템에서만 재 작성했지만 Tier 2 이상에서는 제대로 작동하는 여러 가지 문제가 발생했습니다. 이것이 DirectX 11을 실제로 사용하기 전에 DirectX 12를 사용하는 것이 프로젝트에 생산적인 시간을 사용하지 않는 이유입니다. 물론, 그것이 학습 운동이라면, 당신이 배경을 가지고있는 한 당신은 지금 좋은 교훈을 배우고 있습니다. –