在交换链中为每个 renderTarget 创建一个分配器是否有意义?
Does it make sense to create an allocator per renderTarget in the swapchain?
The HelloWorld examples from Microsoft 大多使用单个 CommandAllocator,然后等待上一帧完全完成。然而,他们也说(全部大写)这不是应该做的。
所以我的想法是在交换链中为每帧创建一个分配器,并在循环缓冲区中保留要等待的栅栏值:
struct frame_resources{
ID3D12Resource* renderTarget;
ID3D12CommandAllocator* allocator;
uint64 fenceValue;
} resources[FRAME_COUNT];
uint frameIndex = swapChain->GetCurrentBackBufferIndex();
UINT64 lastFence;
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (fence->GetCompletedValue() < resources[frameIndex].fenceValue)
{
fence->SetEventOnCompletion(resources[frameIndex].fenceValue, fenceEvent);
DWORD result = MsgWaitForMultipleObjects(1, &fenceEvent, FALSE, INFINITE, QS_ALLEVENTS);
if(result == WAIT_OBJECT_0 + 1)
continue; //message in the queue
}
resources[frameIndex].allocator->Reset();
commandList->Reset(resources[frameIndex].allocator, 0);
//...
commandList->Close();
commandQueue->ExecuteCommandLists(1, &CommandList);
lastFence++;
resources[frameIndex].fenceValue = lastFence;
commandQueue->Signal(fence, lastFence);
swapChain->Present(0, DXGI_PRESENT_RESTART);
frameIndex = swapChain->GetCurrentBackBufferIndex();
}
这是明智的做法吗?或者有更好的方法吗?
你现在可能已经找到了答案,但我会回答以防万一。当 GPU 可能正在执行存储在与命令分配器关联的内存中的命令列表时,您无法重置命令分配器,因此您的方法是正确的,您需要为每个帧缓冲区设置一个单独的命令分配器。
另一方面,命令列表可以在调用 ExecuteCommandLists() 后立即重置。这意味着虽然每帧必须有一个命令分配器,但每个 "thread".
只需要一个命令列表
命令列表一次只能由一个线程填充,这意味着您需要每个线程有一个命令列表来填充一个命令列表。
因此,您需要有 numFrames*numThreads 个命令分配器和 numThreads 个命令列表
The HelloWorld examples from Microsoft 大多使用单个 CommandAllocator,然后等待上一帧完全完成。然而,他们也说(全部大写)这不是应该做的。
所以我的想法是在交换链中为每帧创建一个分配器,并在循环缓冲区中保留要等待的栅栏值:
struct frame_resources{
ID3D12Resource* renderTarget;
ID3D12CommandAllocator* allocator;
uint64 fenceValue;
} resources[FRAME_COUNT];
uint frameIndex = swapChain->GetCurrentBackBufferIndex();
UINT64 lastFence;
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (fence->GetCompletedValue() < resources[frameIndex].fenceValue)
{
fence->SetEventOnCompletion(resources[frameIndex].fenceValue, fenceEvent);
DWORD result = MsgWaitForMultipleObjects(1, &fenceEvent, FALSE, INFINITE, QS_ALLEVENTS);
if(result == WAIT_OBJECT_0 + 1)
continue; //message in the queue
}
resources[frameIndex].allocator->Reset();
commandList->Reset(resources[frameIndex].allocator, 0);
//...
commandList->Close();
commandQueue->ExecuteCommandLists(1, &CommandList);
lastFence++;
resources[frameIndex].fenceValue = lastFence;
commandQueue->Signal(fence, lastFence);
swapChain->Present(0, DXGI_PRESENT_RESTART);
frameIndex = swapChain->GetCurrentBackBufferIndex();
}
这是明智的做法吗?或者有更好的方法吗?
你现在可能已经找到了答案,但我会回答以防万一。当 GPU 可能正在执行存储在与命令分配器关联的内存中的命令列表时,您无法重置命令分配器,因此您的方法是正确的,您需要为每个帧缓冲区设置一个单独的命令分配器。
另一方面,命令列表可以在调用 ExecuteCommandLists() 后立即重置。这意味着虽然每帧必须有一个命令分配器,但每个 "thread".
只需要一个命令列表命令列表一次只能由一个线程填充,这意味着您需要每个线程有一个命令列表来填充一个命令列表。
因此,您需要有 numFrames*numThreads 个命令分配器和 numThreads 个命令列表