我开始学习Direct3D 12,对CPU-GPU同步理解有困难。据我所知,fence(ID3D12Fence)不过是一个用作计数器的UINT64(unsigned long long)值。但它的方法使我感到困惑。以下是D3D12示例源代码的一部分。(https://github.com/d3dcoder/d3d12book)
void D3DApp::FlushCommandQueue()
{
// Advance the fence value to mark commands up to this fence point.
mCurrentFence++;
// Add an instruction to the command queue to set a new fence point. Because we
// are on the GPU timeline, the new fence point won't be set until the GPU finishes
// processing all the commands prior to this Signal().
ThrowIfFailed(mCommandQueue->Signal(mFence.Get(), mCurrentFence));
// Wait until the GPU has completed commands up to this fence point.
if(mFence->GetCompletedValue() < mCurrentFence)
{
HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
// Fire event when GPU hits current fence.
ThrowIfFailed(mFence->SetEventOnCompletion(mCurrentFence, eventHandle));
// Wait until the GPU hits current fence event is fired.
WaitForSingleObject(eventHandle, INFINITE);
CloseHandle(eventHandle);
}
}
据我理解,这部分的目的是要“Flush”命令队列,即使CPU等待GPU直到它达到给定的“Fence值”,以便CPU和GPU具有相同的Fence值。
问:如果Signal()是一个函数,让GPU更新给定ID3D12Fence内的Fence值,为什么需要mCurrentFence值?
根据Microsoft文档,它说“将一个Fence更新为指定的值。”是什么指定的值?我需要的是“获取最后已完成的命令列表值”,而不是设置或指定。这个指定的值是什么?
在我看来,它似乎必须像这样:
// Suppose mCurrentFence is 1 after submitting 1 command list (Index 0), and the thread reached to here for the FIRST time
ThrowIfFailed(mCommandQueue->Signal(mFence.Get()));
// At this point Fence value inside mFence is updated
if (m_Fence->GetCompletedValue() < mCurrentFence)
{
...
}
如果m_Fence->GetCompletedValue()等于0,
如果(0 < 1)
GPU尚未执行命令列表(索引0),则CPU必须等待GPU跟进。然后才有意义调用SetEventOnCompletion,WaitForSingleObject等方法。
如果(1 < 1)
GPU已完成命令列表(索引0),因此CPU不需要等待。
在执行命令列表的某个位置增加mCurrentFence。
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
mCurrentFence++;
ThrowIfFailed(mFence->SetEventOnCompletion(m_nextFence, eventHandle)); WaitForSingleObject(eventHandle, INFINITE); CloseHandle(eventHandle); } } - YoonSeok OH