共用方式為


透過 DXGI 1.3 交換鏈結減少延遲

使用 DXGI 1.3 等待交換鏈結發出訊號,在適當的時間開始轉譯新畫面格,以減少有效畫面格延遲。 遊戲通常需要提供可能的最低延遲時間,也就是從接收到玩家輸入開始,到遊戲更新顯示器以回應該項輸入的時間。 本主題說明從 Direct3D 11.2 版本開始提供的技術,您可用來將遊戲中的有效畫面格延遲降到最低。

等待背景緩衝區如何減少延遲?

使用翻轉模型交換鏈結,無論您的遊戲何時呼叫 IDXGISwapChain::Present,背景緩衝區的「翻轉」都會排入佇列。 轉譯迴圈呼叫 Present() 後,系統會封鎖執行緒,直到呈現完先前的畫面格為止,這樣在實際呈現新的畫面格前,就有空間將新的畫面格排入佇列。 這會導致遊戲開始繪製畫面格到系統允許顯示該畫面格,兩者之間的時間產生額外延遲。 在許多情況下,系統會達到穩定的平衡,遊戲一律會等待幾乎完整的額外畫面格 (從轉譯到呈現每格畫面所經歷的時間)。 最好等到系統準備好接受新的畫面格,再根據目前的資料轉譯畫面格,並立即將畫面格排入佇列。

使用 DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT 旗標建立可等待的交換鏈結。 這種方式建立的交換鏈結可在系統實際準備好接受新畫面格時,通知您的轉譯迴圈。 這可讓遊戲根據目前的資料進行轉譯,然後立即將結果排入目前的佇列。

步驟 1: 建立可等候的交換鏈結

呼叫 CreateSwapChainForCoreWindow時,請指定 DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT 旗標。

swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; // Enable GetFrameLatencyWaitableObject().

注意

相較於某些旗標,此旗標無法透過 ResizeBuffers 來新增或移除。 如果這個旗標設定與建立交換鏈結時的設定不同,DXGI 會傳回錯誤碼。

// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain->ResizeBuffers(
    2, // Double-buffered swap chain.
    static_cast<UINT>(m_d3dRenderTargetSize.Width),
    static_cast<UINT>(m_d3dRenderTargetSize.Height),
    DXGI_FORMAT_B8G8R8A8_UNORM,
    DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT // Enable GetFrameLatencyWaitableObject().
    );

步驟 2。 設定畫面格延遲

使用 IDXGISwapChain2::SetMaximumFrameLatency API 設定畫面格延遲,而非呼叫 IDXGIDevice1::SetMaximumFrameLatency

根據預設,可等待交換鏈結的畫面格延遲設為 1,也就是盡可能將延遲降到最低,但這也會減少 CPU-GPU 的平行處理作業。 如果您需要將 CPU-GPU 平行處理作業提高到 60 FPS (也就是說,如果 CPU 和 GPU 各使用低於 16.7 毫秒的畫面格處理轉譯工作,但總和大於 16.7 毫秒),則將畫面格延遲設為 2。 這可讓 GPU 在前一格畫面期間處理 CPU 排入佇列的工作,同時允許 CPU 獨立提交目前畫面格的轉譯命令。

// Swapchains created with the DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT flag use their
// own per-swapchain latency setting instead of the one associated with the DXGI device. The
// default per-swapchain latency is 1, which ensures that DXGI does not queue more than one frame
// at a time. This both reduces latency and ensures that the application will only render after
// each VSync, minimizing power consumption.
//DX::ThrowIfFailed(
//    swapChain2->SetMaximumFrameLatency(1)
//    );

步驟 3: 從交換鏈結取得可等候的物件

呼叫 IDXGISwapChain2::GetFrameLatencyWaitableObject 來擷取等待控制代碼。 等待控制代碼是可等候物件的指標。 請儲存此控制代碼以供轉譯迴圈使用。

// Get the frame latency waitable object, which is used by the WaitOnSwapChain method. This
// requires that swap chain be created with the DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
// flag.
m_frameLatencyWaitableObject = swapChain2->GetFrameLatencyWaitableObject();

步驟 4. 轉譯每格畫面之前先等候

您的轉譯迴圈應等待交換鏈結透過可等待物件發出訊號,再開始轉譯每格畫面。 這包括使用交換鏈結轉譯的第一格畫面。 如果在步驟 2 中已擷取等待控制代碼,則使用 WaitForSingleObjectEx 發出訊號,指示每格畫面的開始。

下列範例顯示來自 DirectXLatency 範例的轉譯迴圈:

while (!m_windowClosed)
{
    if (m_windowVisible)
    {
        // Block this thread until the swap chain is finished presenting. Note that it is
        // important to call this before the first Present in order to minimize the latency
        // of the swap chain.
        m_deviceResources->WaitOnSwapChain();

        // Process any UI events in the queue.
        CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

        // Update app state in response to any UI events that occurred.
        m_main->Update();

        // Render the scene.
        m_main->Render();

        // Present the scene.
        m_deviceResources->Present();
    }
    else
    {
        // The window is hidden. Block until a UI event occurs.
        CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
    }
}

下列範例顯示來自 DirectXLatency 範例的 WaitForSingleObjectEx 呼叫:

// Block the current thread until the swap chain has finished presenting.
void DX::DeviceResources::WaitOnSwapChain()
{
    DWORD result = WaitForSingleObjectEx(
        m_frameLatencyWaitableObject,
        1000, // 1 second timeout (shouldn't ever occur)
        true
        );
}

遊戲等待交換鏈結呈現時應該做什麼?

如果遊戲沒有任何阻擋轉譯迴圈的工作,讓遊戲等待交換鏈結呈現也有好處,因為這樣能節省電力,對行動裝置來說特別重要。 或者,您可以在遊戲等待交換鏈結呈現時,使用多執行緒來完成工作。 以下是遊戲可完成的一些工作:

  • 處理網路事件
  • 更新 AI
  • 以 CPU 為基礎的物理
  • 延遲內容轉譯 (適用於支援的裝置)
  • 資產載入

如需有關 Windows 中的多執行緒程式設計詳細資訊,請參閱以下相關主題。