DX12 指令佇列與柵欄
在正確的時間同步 CPU 和 GPU
該部落格上撰寫的文章是出於教學目的而創建的。 另外,文章中的資訊可能不正確,請謹慎。
在 DirectX 12 中,CPU 記錄命令列表,GPU 稍後執行。 由於兩個裝置同時移動,因此它們必須同步,以便 CPU 不會覆蓋 GPU 仍在使用的資源。
命令隊列和命令列表
Command List是記錄繪圖指令的列表,Command Queue將完成的列表提交給GPU。
CPU
命令分配器初始化
命令列表歷史記錄
CommandList Close
↓
提交命令隊列
↓
GPU執行
CommandAllocator 管理錄製所需的記憶體。 當 GPU 仍在讀取前一幀的指令時,不應重置同一個分配器。
使用 Fence 檢查完成時間
void WaitForGPU()
{
const UINT64 SignalValue = ++FenceValue;
CommandQueue->Signal(Fence, SignalValue);
if (Fence->GetCompletedValue() < SignalValue)
{
Fence->SetEventOnCompletion(SignalValue, FenceEvent);
WaitForSingleObject(FenceEvent, INFINITE);
}
}
當訊號值進入佇列時,GPU 會處理先前的所有命令,然後更新 Fence 值。 只有當完成值小於目標時,CPU 才會等待事件。
如果你等待每一幀,那麼速度會很慢。
在三角形的例子中,為了更容易理解,WaitForGPU()可以調用。 但是,如果這樣做,CPU 和 GPU 就無法協同工作並在每一幀串行運行。
在實際應用中,BackBuffer的個數就有多少個Frame Resources,並且單獨記錄每幀的Fence值。
struct FrameContext
{
ComPtr<ID3D12CommandAllocator> Allocator;
UINT64 FenceValue = 0;
};
它只等待目前使用的幀資源的柵欄,並允許GPU繼續處理其他幀。
開啟調試層
在 DX12 中,開發人員對錯誤的狀態轉換或描述符的使用負有直接責任。 如果在初始化之前開啟偵錯層,您可以更快找出哪些資源狀態和命令順序錯誤。
DX12同步的目的不是無條件等待。 它允許CPU和GPU盡可能同時工作,同時精確地等待再次使用相同的資源。