> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct3D 對暫停與繼續的支援

> Direct3D 對暫停與繼續的支援

本主題說明暫停與繼續 Game OS 遊戲之 Direct3D 圖形轉譯的程序。

* [暫停與繼續事件](#ID4EN)
* [對畫面排程與統計資料的影響](#ID4FrameSchedulingResume)
* [呼叫模式](#ID4EEC)
* [測試](#ID4EBF)

<a id="ID4EN" />

## 暫停與繼續事件

在 XBOX One 上，Game OS 應用程式可由程序生命週期管理 (PLM) 暫停與繼續。在暫停狀態下，應用程式的記憶體會保持不變，但應用程式沒有任何 CPU 或 GPU 資源。Game OS 應用程式實作暫停與繼續是 XBOX One 的 XBOX 需求 (XR) 之一。

如果應用程式收到 **Suspending** 事件，應用程式必須呼叫 **SuspendX**。否則，應用程式將會被終止。**SuspendX** 與 **ResumeX** 呼叫都必須在遊戲的轉譯執行緒上執行，以確保 **SuspendX** 呼叫能正確儲存 GPU 狀態。

遊戲暫停時，在 GPU 繼續之前無法轉譯任何內容。在 Direct3D **SuspendX** 與 **ResumeX** 呼叫之間呼叫任何 Direct3D API (例如呼叫 **ID3D12GraphicsCommandList::DrawInstanced** 或 **ID3D12CommandQueue::ExecuteCommandLists** 方法) 會擲回例外狀況。

以下是 XBOX One 上 Direct3D 的暫停與繼續方法。

* [ID3D12CommandQueue::SuspendX](/zh-TW/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_suspendx)
* [ID3D12CommandQueue::ResumeX](/zh-TW/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_resumex)

這些方法應在圖形命令佇列上叫用，因為運算與複製佇列不支援這些方法。

<a id="ID4FrameSchedulingResume" />

## 對畫面排程與統計資料的影響

暫停應用程式會對其已建立的畫面排程造成不確定性的中斷。由於暫停事件發生的時間無法預測，系統無法在後續的繼續事件之後安全地還原已建立的排程及其時間狀態。為了提供穩健且可預測的行為，系統會在處理 **SuspendX** 呼叫期間清除應用程式的畫面排程。呈現佇列會排清到顯示器，而任何由 **WaitFrameEventX** 開始但尚未透過 **PresentX** 傳送到顯示器的畫面都會被捨棄。

因此，從 **ResumeX** 呼叫傳回後，應用程式必須先透過呼叫 **ID3D12Device::SetFrameIntervalX** 與 **ID3D12Device::ScheduleFrameEventX** 重新建立所需的畫面排程，才能繼續等待下一個畫面起始時間。應用程式在繼續之後應假設畫面管線是空的。

<Note>
  應用程式在呼叫 **ID3D12Device::WaitFrameEventX** 期間等待畫面起始時間 (或其他畫面事件) 發出訊號時收到暫停事件，可能是很常見的情況。如果負責在圖形命令佇列上呼叫 **SuspendX** 的應用程式執行緒與用來等待畫面事件的執行緒不同，則 **ID3D12Device::WaitFrameEventX** 呼叫 (即使在 **SuspendX** 呼叫之前就已開始) 可能會失敗並傳回 D3DERR\_DEVICEREMOVED。
</Note>

畫面統計資料不會跨暫停/繼續邊界保留。在暫停之前產生的任何畫面權杖在繼續之後都會被視為無效，而參考這些權杖以取得相關統計資訊的 **ID3D12Device::GetFrameStatisticsX** 呼叫將會失敗。

<a id="ID4EEC" />

## 呼叫模式

Game OS 應用程式透過已註冊的回呼接收通知。只有暫停與繼續事件，不再有明確的啟用階段。一個簡單的實作方式是透過張貼 WM\_USER 訊息來處理暫停與繼續。

```cpp theme={null}
#include <appnotify.h>

PAPPSTATE_REGISTRATION hPLM = {};
HANDLE plmSuspendComplete = nullptr;
HANDLE plmSignalResume = nullptr;

// Create a window.

plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
plmSignalResume = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
if (!plmSuspendComplete || !plmSignalResume)
    return 1;

if (RegisterAppStateChangeNotification([](BOOLEAN quiesced, PVOID context)
{
    if (quiesced)
    {
        ResetEvent(plmSuspendComplete);
        ResetEvent(plmSignalResume);

        // To ensure we use the main UI thread to process the notification, we self-post a message.
        PostMessage(reinterpret_cast<HWND>(context), WM_USER, 0, 0);

        // To defer suspension, we must wait to exit this callback.
        (void)WaitForSingleObject(plmSuspendComplete, INFINITE);
    }
    else
    {
        SetEvent(plmSignalResume);
    }
}, hwnd, &hPLM))
    return 1;

// Message loop

UnregisterAppStateChangeNotification(hPLM);

CloseHandle(plmSuspendComplete);
CloseHandle(plmSignalResume);
```

如果訊息幫浦是在對圖形命令佇列具有獨佔存取權的轉譯執行緒上執行，就可以在 WM\_USER 訊息處理常式中直接呼叫 Direct3D **SuspendX** 與 **ResumeX**。任何將工作發給非同步運算或複製命令佇列的個別執行緒，都必須在呼叫 **SuspendX** 之前被指示停止佇列作業。

```cpp theme={null}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
...
    switch (message)
    {
    case WM_USER:
        // Notify any threads using other command queues to halt operations and wait for acknowledgement.

        // Call SuspendX(0) on the graphics command queue, and cease all GPU submissions. This API is asynchronous so
        // that the game can continue doing work below.
        pGraphicsQueue->SuspendX(0);

        // Complete deferral.
        SetEvent(plmSuspendComplete);

        (void)WaitForSingleObject(plmSignalResume, INFINITE);

        // Before picking up rendering again, call ResumeX on the graphics command queue.
        pGraphicsQueue->ResumeX();

        // Notify any threads using other command queues that it's safe to resume operations.

        // Register again for frame events via SetFrameIntervalX and ScheduleFrameEventX.
        break;
    }
```

如果訊息幫浦執行所在的執行緒，與一或多個具有圖形命令佇列存取權的執行緒不同，則必須指示轉譯執行緒進行 **SuspendX** 呼叫並停止使用佇列 (並以類似方式處理 **ResumeX** 及相關作業)。

進行 **SuspendX** 呼叫時，Direct3D 執行階段會儲存內容暫存器、CE RAM、ESRAM、全域資料存放區 (GDS)、索引緩衝區、部分 GPU 暫存器 (並非所有 GPU 暫存器都可讀取) 以及 CP 內部記憶體的狀態。此狀態會在 **ResumeX** 呼叫時還原。

PLM 系統定義了應用程式可能處於的四種狀態：**Unconstrained** (不受限)、**Constrained** (受限)、**Suspended** (已暫停) 與 **Terminated** (已終止)。

如需詳細資訊，請參閱[程序生命週期管理 (開發人員教育資料，所有 NDA 白皮書)](https://aka.ms/xgddl)。

<a id="ID4EBF" />

## 測試

為了能夠實際測試暫停與繼續，遠端命令 [應用程式管理 (xbapp.exe)](/zh-TW/tools/tools-console/commandlinetools/xbapp) 提供了相關選項。請參閱該主題中有關 **xbapp suspend** 的章節，並留意範例批次檔。

<a id="ID4EOF" />


## Related topics

- [NDA 主題目錄 - Microsoft Learn 線上連結](/zh-TW/nda/nda-topic-directory.md)
- [XBOX Series X|S 總覽](/zh-TW/paths/series-xs/overview.md)
- [PlayFab Multiplayer C++ SDK 版本資訊](/zh-TW/services/playfab/multiplayer/lobby/lobby-matchmaking-sdks/lobby-and-matchmaking-release-notes.md)
- [XR112 在初次啟用與繼續時建立使用者和控制器](/zh-TW/publishing/certification/fma/xr-112.md)
- [XBOX 主機遊戲的認證測試 XBOX 需求](/zh-TW/publishing/certification/console-cert-tested-requirements.md)
