Я начинаю изучать Direct3D 12 и с трудом понимаю синхронизацию CPU-GPU. Насколько я понимаю, забор (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);
}
}
Насколько я понимаю, эта часть пытается «сбросить» очередь команд, что в основном заставляет ЦП ждать GPU, пока он не достигнет заданного «значения Fence», чтобы ЦП и GPU имели одинаковое значение ограничения.
В. Если этот Signal() является функцией, которая позволяет графическому процессору обновлять значение границы внутри заданного ID3D12Fence, зачем нужно это значение mCurrentFence?
Согласно Microsoft Doc, он говорит: «Обновляет забор до указанного значения». Какое указанное значение? Мне нужно «Получить последнее значение списка завершенных команд», а не устанавливать или указывать. Для чего это указанное значение?
Мне кажется, так и должно быть
// 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,
if (0 < 1)
Графический процессор не обработал список команд (индекс 0), тогда ЦП должен ждать, пока ГП не выполнит его. Тогда имеет смысл вызывать SetEventOnCompletion, WaitForSingleObject и т.д.
if (1 < 1)
Графический процессор завершил список команд (индекс 0), поэтому ЦП не нужно ждать.
Увеличить значение mCurrentFence там, где выполняется список команд.
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
mCurrentFence++;