> ## 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.

# Planification des images et présentation sur XBOX One

> Planification des images et présentation sur XBOX One

* [Remplacement des chaînes d'échange par la présentation directe et la planification des images](#ID4SwapChainsRIP)
  * [Migration à partir de Windows et de l'ERA ](#ID4Migration)
  * [Flux de travail général](#ID4WorkflowPrimer)
  * [Exemple de code](#ID4ExampleCode)

<a id="ID4SwapChainsRIP" />

## Remplacement des chaînes d'échange par la présentation directe et la planification des images

Game OS a remanié le processus de présentation graphique. Les objectifs sont les suivants.

* Offrir un contrôle plus direct sur la création et la gestion des ressources affichables
* Réduire la latence de bout en bout, de l'échantillonnage du périphérique d'entrée jusqu'au balayage de la ressource d'image présentée
* Accroître la souplesse de la configuration dynamique des plans et des paramètres d'affichage
* Accroître la liberté de choix de la file d'attente de commandes pour la soumission des présentations
* Établir un mécanisme explicite de limitation du processeur pour un contrôle précis de l'exécution du pipeline de simulation et de rendu
* Améliorer la tenue à jour et la production de rapports des statistiques du pipeline d'images

Voici quelques-unes des fonctionnalités les plus notables offertes par cette nouvelle approche.

* La présentation directe d'objets ID3D12Resource affichables offre une grande polyvalence dans la disposition et la sélection des ressources d'échange, puisque la chaîne devient un groupe géré par l'utilisateur.
* La possibilité d'effectuer la présentation sur n'importe quelle file d'attente de commandes graphiques ou de calcul peut éliminer un blocage de la file d'attente graphique en attente d'une clôture de présentation signalée par une file d'attente de calcul après le traitement d'une ressource d'échange (prise en charge dans un proche avenir).
* L'introduction d'une méthode d'identification formelle des images sous la forme d'un jeton de pipeline. Le jeton de pipeline d'image permet de corréler la limitation des images, l'échantillonnage des entrées, les événements d'enregistrement des listes de commandes du processeur, les événements de rendu du GPU et les événements du pipeline d'affichage pour les images dont la durée dans le pipeline s'étend sur plusieurs intervalles de synchronisation verticale. Des statistiques cohérentes pour chaque image peuvent ensuite être interrogées par jeton et affichées dans PIX. La connaissance qu'a le système de la durée de vie d'une image, y compris de tous les événements notables qui s'y produisent, est également bénéfique pour la surveillance et le réglage du service XBOX Game Streaming.
* Une planification de la production de nouvelles images à afficher, fondée sur les événements et pilotée par les interruptions, qui permet de spécifier des heures d'origine dans le pipeline d'images à la cadence de l'intervalle de présentation, avec un déphasage automatique en réponse aux images manquées. La planification permet de spécifier, de façon facultative, des événements créés par l'utilisateur pour une signalisation étendue.
* Un système d'interrogation ou de blocage sur les événements d'origine du pipeline d'images en tant que mécanisme de limitation formel. Le système permet de spécifier, de façon facultative, des événements créés par l'utilisateur comme conditions supplémentaires d'une attente.
* Une expression plus abstraite de la fréquence de rendu et de présentation, l'intervalle de présentation étant spécifié sous forme de durée plutôt que sous forme d'intervalle en nombre entier de suppressions verticales. Ce changement permet de préserver un rendu d'images constant sur le matériel fixe de la console malgré des fréquences de sortie d'affichage variables (par exemple, un rendu à 60 Hz sur un écran à 60 Hz ou à 120 Hz), et permet de prendre en charge facilement à l'avenir le rendu natif à des fréquences supérieures à 60 Hz (par exemple, 120 Hz en natif).
* L'élargissement des statistiques d'images suivies, avec un mécanisme de production de rapports filtrable et extensible pour de futurs ajouts.
* L'identification des heures d'origine des images, conjuguée à l'ajout futur d'horloges synchronisées pour l'affichage et les périphériques d'entrée (afin d'éviter une dérive continue), permet à la plateforme de demander au micrologiciel de la manette (ou d'un autre périphérique) de recueillir des échantillons d'entrée et de les rendre disponibles juste à temps pour les requêtes du jeu, afin de contribuer à réduire au minimum la latence globale.

<a id="ID4Migration" />

## Migration à partir de Windows et de l'ERA

Les API liées aux chaînes d'échange, à la présentation et à la planification qui ne sont pas prises en charge sur Game OS ont des équivalents comparables. Pour vous aider à vous orienter, un ensemble d'API et de paramètres hérités couramment utilisés est présenté dans le tableau suivant, avec leurs remplacements correspondants dans la colonne adjacente.

| Hérité | Game OS |
| - | - |
| IDXGIFactory::CreateSwapChain, <br />IDXGIFactory2::CreateSwapChainForCoreWindow et <br />IDXGIFactory2::CreateSwapChainForComposition<br /><br />    - *DXGIX\_SWAP\_CHAIN\_FLAG\_QUANTIZATION\_RGB\_FULL*<br />    - *DXGIX\_SWAP\_CHAIN\_FLAG\_COLORIMETRY\_*<br />*RGB\_BT2020\_ST2084*<br />    - *DXGIX\_SWAP\_CHAIN\_MATCH\_XBOX360\_AND\_PC*<br /><br />     - *DXGIX\_SWAP\_CHAIN\_MATCH\_OTHER\_CONSOLES*<br />    - *DXGIX\_SWAP\_CHAIN\_FLAG\_*<br />*QUANTIZATION\_RGB\_LIMITED*<br />    - *DXGIX\_SWAP\_CHAIN\_FLAG\_*<br />*COLORIMETRY\_sRGB\_TO\_REC709*<br /><br />    - *DXGIX\_SWAP\_CHAIN\_FLAG\_*<br />*AUTOMATIC\_GAMEDVR\_TONEMAP* | [ID3D12Device::CreateCommittedResource](https://learn.microsoft.com/windows/desktop/api/d3d12/nf-d3d12-id3d12device-createcommittedresource) avec <br />*HeapFlags* incluant [D3D12\_HEAP\_FLAG\_ALLOW\_DISPLAY](https://learn.microsoft.com/windows/desktop/api/d3d12/ne-d3d12-d3d12_heap_flags)<br /><br /> <br />    - [ColorSpace](/fr-CA/reference/graphics/d3d12_x/structs/d3d12xbox_present_plane_parameters) [DXGI\_COLOR\_SPACE\_RGB\_FULL\_G22\_NONE\_P709](https://learn.microsoft.com/windows/desktop/api/dxgicommon/ne-dxgicommon-dxgi_color_space_type)<br />   - [ColorSpace](/fr-CA/reference/graphics/d3d12_x/structs/d3d12xbox_present_plane_parameters) [DXGI\_COLOR\_SPACE\_RGB\_STUDIO\_G22\_NONE\_P2020](https://learn.microsoft.com/windows/desktop/api/dxgicommon/ne-dxgicommon-dxgi_color_space_type)<br /> <br />    - Non pris en charge ([DXGI\_COLOR\_SPACE\_RGB\_FULL\_G22\_NONE\_P709](https://learn.microsoft.com/windows/desktop/api/dxgicommon/ne-dxgicommon-dxgi_color_space_type)<br />  sans *sRGB\_TO\_REC709*)<br />    - [ColorSpace](/fr-CA/reference/graphics/d3d12_x/structs/d3d12xbox_present_plane_parameters) [DXGI\_COLOR\_SPACE\_RGB\_FULL\_G22\_NONE\_P709](https://learn.microsoft.com/windows/desktop/api/dxgicommon/ne-dxgicommon-dxgi_color_space_type)<br />    - Non pris en charge<br /><br />    - Non pris en charge<br /><br /> <br />   - [D3D12XBOX\_RESOURCE\_FLAG\_ALLOW\_](/fr-CA/reference/graphics/d3d12_x/enums/d3d12_resource_flags)<br />[AUTOMATIC\_GAMEDVR\_TONE\_MAP](/fr-CA/reference/graphics/d3d12_x/enums/d3d12_resource_flags) |
| IDXGISwapChain1::SetHDRToneMapper | [ID3D12CommandQueue::SetHDRToneMapperX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_sethdrtonemapperx) |
| IDXGISwapChain::Present et DXGIXPresentArray<br /><br />   - *SyncInterval* 1 - 4<br />    - *SyncInterval* 0<br />    - *PresentImmediateThreshold*<br /><br />    - *DXGI\_PRESENT\_DO\_NOT\_WAIT*<br />    - *DXGIX\_PRESENT\_DISABLE\_VARIABLE\_REFRESH\_RATE*<br />    - *DXGIX\_PRESENT\_PRESERVE\_FRAMEBUFFER*<br />    - *DXGIX\_PRESENT\_UPSCALE\_FILTER\_* \* | [ID3D12CommandQueue::PresentX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_presentx)<br /><br />   - [ID3D12Device::SetFrameIntervalX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_setframeintervalx)(..., *LengthInMicroseconds*, ...);<br />   - [D3D12XBOX\_PRESENT\_FLAG\_IMMEDIATE](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags) (substitution de PresentX)<br />    - [ImmediateThresholdPercent](/fr-CA/reference/graphics/d3d12_x/structs/d3d12xbox_present_parameters)<br /><br />    - [D3D12XBOX\_PRESENT\_FLAG\_DO\_NOT\_WAIT](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags)<br />    - [D3D12XBOX\_PRESENT\_FLAG\_DISABLE\_VARIABLE\_REFRESH\_RATE](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags)<br />    - [D3D12XBOX\_PRESENT\_FLAG\_PERSIST](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags)<br />    - [D3D12XBOX\_PRESENT\_PLANE\_SCALE\_FILTER](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_present_plane_scale_filter) |
| IDXGISwapChain::GetFrameStatistics et DXGIXGetFrameStatistics | [ID3D12Device::GetFrameStatisticsX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_getframestatisticsx) |
| DXGIX\_FRAME\_STATISTICS<br /><br />    - *GPUCountTitleUsed*<br /><br /><br /> | [D3D12XBOX\_RENDER\_STATISTICS](/fr-CA/reference/graphics/d3d12_x/structs/d3d12xbox_render_statistics)<br /><br />    - *GPUBusyDuration* x [GetTimeStampFrequency](https://learn.microsoft.com/windows/desktop/api/d3d12/nf-d3d12-id3d12commandqueue-gettimestampfrequency)() / <br />QueryPerformanceFrequency().QuadPart <br />(couvrant l'intervalle d'image) |
| DXGIX\_FRAME\_STATISTICS<br /><br />    - *CPUTimePresentCalled*<br />    - *CPUTimeAddedToQueue*<br />    - *CPUTimeFrameComplete*<br />    - *QueueLengthAddedToQueue*<br /> | [D3D12XBOX\_PRESENT\_STATISTICS](/fr-CA/reference/graphics/d3d12_x/structs/d3d12xbox_present_statistics)<br /><br />    - *PresentCallTime*<br />    - *PresentQueueTime*<br />    - *GPUProcessTime*<br />    - *QueuedFrameCount* |
| DXGIX\_FRAME\_STATISTICS<br /><br />    - *CPUTimeVSync*<br />    - *CPUTimeFlip*<br />    - *PercentScanned*<br />    - *VSyncCount* | [D3D12XBOX\_DISPLAY\_STATISTICS](/fr-CA/reference/graphics/d3d12_x/structs/d3d12xbox_display_statistics)<br /><br />    - *VSyncTime*<br />    - *FlipTime*<br />    - *PercentScanned*<br />    - Non pris en charge |
| DXGIX\_FRAME\_STATISTICS<br /><br />    - *Cookie*<br /><br /><br /><br />    - *VSyncCount* | <br /><br />    - [D3D12XBOX\_FRAME\_PIPELINE\_TOKEN](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_pipeline_token) sert <br />d'identificateur d'image (l'association avec un <br />Cookie personnalisé doit être effectuée manuellement)<br /><br />    - Non pris en charge |
| DXGIXSetVLineNotification<br /><br />   - VLINECOUNTER0<br />   - VLINECOUNTER1 | [ID3D12Device::ScheduleFrameEventX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx)<br /><br />   - [D3D12XBOX\_FRAME\_EVENT\_DISPLAY\_VBLANK](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type)<br />   - [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) |
| DXGIXSetFrameNotification<br /><br />   - FRAME\_NOTIFICATION\_FLIPPED | ID3D12Device::ScheduleFrameEventX<br /><br />   - [D3D12XBOX\_FRAME\_EVENT\_DISPLAY\_FLIP](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) |
| DXGIXSetVLineNotification (ou Present) comme mécanisme de limitation | [ID3D12Device::ScheduleFrameEventX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx) et [ID3D12Device::WaitFrameEventX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_waitframeeventx) avec [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) |

<a id="ID4WorkflowPrimer" />

## Flux de travail général

L'approche générale pour créer un groupe de ressources affichables, planifier les images en tant que mécanisme de limitation explicite et présenter les ressources d'image à l'écran comprend quelques étapes d'initialisation, suivies d'une séquence d'opérations dans la boucle de jeu. Pour plus d'informations sur chaque étape (descriptions détaillées, incidences et utilisation suggérée), consultez les pages de référence.

**Initialisation**

* Appelez [ID3D12Device::CreateCommittedResource](https://learn.microsoft.com/windows/desktop/api/d3d12/nf-d3d12-id3d12device-createcommittedresource) avec des *HeapFlags* qui incluent [D3D12\_HEAP\_FLAG\_ALLOW\_DISPLAY](https://learn.microsoft.com/windows/desktop/api/d3d12/ne-d3d12-d3d12_heap_flags) pour créer une collection d'objets [ID3D12Resource](https://learn.microsoft.com/windows/desktop/api/d3d12/nn-d3d12-id3d12resource) servant de groupe de ressources échangeables prenant en charge la présentation à l'écran (c'est-à-dire une « chaîne d'échange »).
* Appelez [ID3D12Device::SetFrameIntervalX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_setframeintervalx) pour établir une fréquence d'actualisation des images et une période. *LengthInMicroseconds* définit l'intervalle de temps entre les présentations d'images à l'écran (retournements). *PeriodInIntervals* définit l'avance que le processeur est autorisé à prendre sur le GPU, en nombre entier d'intervalles d'image. Le processeur est autorisé à prendre *PeriodInIntervals* - 1 images d'avance sur le GPU avant d'être limité (par exemple, une valeur *PeriodInIntervals* de 2 permet au processeur d'enregistrer et de soumettre les commandes de rendu de l'image *n* + 1 pendant que le GPU traite les commandes soumises pour l'image *n*).
* Appelez [ID3D12Device::ScheduleFrameEventX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx) pour établir le moment, au sein d'un intervalle d'image, où le processeur est limité. Spécifiez un Type [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) et un décalage temporel *IntervalOffsetInMicroseconds* pour planifier l'événement d'origine des images. Le processeur est limité jusqu'à ce que la durée *IntervalOffsetInMicroseconds* spécifiée au sein de l'intervalle se soit écoulée.

**Boucle de jeu**

* Appelez [ID3D12Device::WaitFrameEventX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_waitframeeventx) avec un Type [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) pour effectuer la limitation du processeur. Spécifiez une valeur *TimeOutInMs* de **D3D12XBOX\_WAIT\_FRAME\_EVENT\_INFINITE** pour bloquer jusqu'à l'arrivée de l'origine, ou un délai fixe en millisecondes pour interroger l'événement d'origine (**S\_FALSE** est retourné si l'origine n'est pas encore arrivée). Spécifiez pour *pToken* un pointeur vers un [D3D12XBOX\_FRAME\_PIPELINE\_TOKEN](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_pipeline_token) qui, au retour lors de l'arrivée de l'origine, est défini sur une valeur de jeton qui identifie l'image de façon unique. Ce jeton doit être suivi pour l'image et fourni au moment de sa présentation à l'écran.
* Interrogez l'entrée de la manette et effectuez le rendu de l'image dans les objets [ID3D12Resource](https://learn.microsoft.com/windows/desktop/api/d3d12/nn-d3d12-id3d12resource) créés avec la prise en charge de l'affichage.
* Appelez [ID3D12CommandQueue::PresentX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_presentx) pour mettre en file d'attente les ressources de l'image rendue en vue de leur présentation à l'écran. Les ressources et les jetons d'image sont fournis dans le tableau *pPlaneParameters*.
* Appelez [ID3D12Device::GetFrameStatisticsX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_getframestatisticsx) en utilisant le jeton de la dernière image censée avoir atteint l'écran (ou effectuez plusieurs appels sur différentes images d'intérêt). Analysez les statistiques d'images retournées afin d'orienter les mises à jour du point de limitation des images établi, dans le but de réduire au minimum la latence entre l'entrée de la manette et l'affichage. Appelez [ID3D12Device::ScheduleFrameEventX](/fr-CA/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx) avec le type [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr-CA/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) pour effectuer les mises à jour, qui seront appliquées lorsque la prochaine image à présenter après l'appel sera retournée à l'écran.
* Effectuez tout travail indépendant des entrées sur le processeur ou le GPU avant de passer à l'attente de la prochaine origine d'image (ou pendant que vous l'interrogez).

<a id="ID4ExampleCode" />

## Exemple de code

L'exemple de code suivant illustre le flux de travail général pour un rendu 1080p à 60 images par seconde, avec un seul plan d'arrière-plan et un groupe d'échange de 2 ressources.

```cpp theme={null}
    // Game initialization.

    HRESULT hr;

    D3D12_HEAP_PROPERTIES heapProperties = {};
    heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
    heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
    heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
    heapProperties.CreationNodeMask = D3D12XBOX_NODE_MASK;
    heapProperties.VisibleNodeMask = D3D12XBOX_NODE_MASK;

    D3D12_RESOURCE_DESC swapResourceDesc = {};
    swapResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    swapResourceDesc.Alignment = 0;
    swapResourceDesc.Width = 1920;
    swapResourceDesc.Height = 1080;
    swapResourceDesc.DepthOrArraySize = 1;
    swapResourceDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
    swapResourceDesc.MipLevels = 1;
    swapResourceDesc.SampleDesc.Count = 1;
    swapResourceDesc.SampleDesc.Quality = 0;
    swapResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    swapResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;

    // Create a swap pool of two displayable resources.

    ID3D12Resource* pSwapResources[2];

    for (UINT i = 0; i < 2; ++i)
    {
        hr = pd3dDevice->CreateCommittedResource(
            &heapProperties,
            D3D12_HEAP_FLAG_ALLOW_DISPLAY,
            &swapResourceDesc,
            D3D12_RESOURCE_STATE_PRESENT,
            nullptr,
            __uuidof(ID3D12Resource),
            (void**)&pSwapResources[i]);

        if (FAILED(hr))
        {
            return hr;
        }
    }

    // Establish a 60 Hz frame-rate interval and a frame period spanning two intervals, which permits the
    // CPU to begin recording and submitting commands for one frame while the GPU is still processing
    // commands submitted on the previous frame (if the CPU attempts to begin work on frame n + 2 before
    // the GPU has completed frame n and flipped it to the display, it will be throttled until the interval
    // following the flip).

    hr = pd3dDevice->SetFrameIntervalX(
        nullptr,
        D3D12XBOX_FRAME_INTERVAL_60_HZ,         // 16,667 microseconds between flips (60 flips per second).
        2,                                      // Frame period of 2 intervals (frame started during one
                                                // interval and finished on the next).
        D3D12XBOX_FRAME_INTERVAL_FLAG_NONE);

    if (FAILED(hr))
    {
        return hr;
    }

    // Schedule a frame origin event to establish the CPU throttle point for the game. The frame
    // origin is the time that a new frame is generated, and is generally expected to be the
    // moment when input is queried and directly used in the construction of the frame. The
    // origin should be scheduled as near to the time of frame display as possible to minimize latency,
    // based on expected frame duration (and informed by statistics feedback). In this example,
    // the game anticipates an initial end-to-end frame duration (from input query, to CPU rendering,
    // to GPU processing, to presentation for display) of 27,778 microseconds (1.66 frame intervals).
    // This translates into a frame period of 2 intervals and an interval offset of 5,556 microseconds.

    hr = pd3dDevice->ScheduleFrameEventX(
        D3D12XBOX_FRAME_EVENT_ORIGIN,              // Origin event type.
        5556,                                      // Begin the frame after one-third of the interval has passed.
        nullptr,                                   // Don't signal any additional game events at the origin.
        D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE);

    if (FAILED(hr))
    {
        return hr;
    }

    {...}

    // Game loop.

    D3D12XBOX_FRAME_PIPELINE_TOKEN frameToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL;

    do
    {
        // Perform a modest, measured amount of CPU/GPU processing not directly dependent on user input
        // (for example, texture streaming).
        {...}

        // Poll on the origin event for the frame, throttling the CPU as necessary.

        hr = pd3dDevice->WaitFrameEventX(
            D3D12XBOX_FRAME_EVENT_ORIGIN,
            0,                                    // Poll with an immediate timeout.
            nullptr,                              // Don't wait on additional game events in
                                                  // conjunction with origin.
            D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE,
            &token);                              // Obtain the frame's identifying token.

        if (hr == D3DERR_DEVICEREMOVED)
        {
            // The GPU may have stopped responding, preventing it from reaching the present submitted for
            // a previous frame and flipping it to the display. This would in turn prevent
            // the new frame origin event from being signaled due to the throttle. Alternatively,
            // another thread responsible for processing suspend events may have called
            // SuspendX during the origin wait, causing it to fail. Test and handle these
            // conditions as appropriate.
            {...}
        }

    } while (hr == S_FALSE);

    ++m_FrameIndex;

    // Store the frame token for later statistics retrieval.

    m_FrameToken[m_FrameIndex % 16] = token;

    // Query user input from the gamepad.

    IGameInputReading* pReading;

    pGameInput->GetCurrentReading(
        GameInputKindGamepad,
        pGamepadDevice,
        &pReading);

    // Render the frame based on the input reading to pSwapResources[m_FrameIndex % 2].

    {...}

    pReading->Release();

    // Queue the rendered frame for presentation to the display. Effective frame scheduling
    // will contrive to minimize the amount of time the swap resource remains in the queue
    // before being flipped and scanned out.

    D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParameters = {};

    planeParameters.Token = token;                          // Identify the frame being presented.
    planeParameters.ResourceCount = 1;
    planeParameters.ppResources = &pSwapResources[m_FrameIndex % 2]; // Present the associated swap resource.
    planeParameters.pSrcViewRects = nullptr;                // Display the entire resource (no dynamic scaling
                                                            // or split-screen multiplayer).
    planeParameters.pDestPlacementBase = nullptr;           // Full coverage of the display.
    planeParameters.ColorSpace = DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 // HDR color space.
    planeParameters.ScaleFilter = D3D12XBOX_PRESENT_PLANE_SCALE_FILTER_DEFAULT;
    planeParameters.Flags = D3D12XBOX_PRESENT_PLANE_FLAG_NONE;

    D3D12XBOX_PRESENT_PARAMETERS presentParameters = {};

    presentParameters.ImmediateThresholdPercent = 5.0f;     // Allow tearing in the top 5 percent of the frame.
    presentParameters.ViewCount = 1;                        // No split-screen multiplayer.
    presentParameters.Flags = D3D12XBOX_PRESENT_FLAG_NONE;

    pd3dCommandQueue->PresentX(
        1,
        &planeParameters,

    // Collect statistics for the most recently flipped frame.

    D3D12XBOX_FRAME_STATISTICS statisticsList[4];
    UINT statisticsCount = _countof(statisticsList);

    hr = pd3dDevice->GetFrameStatisticsX(
        m_FrameToken[(m_FrameIndex + 14) % 16],             // Query the frame originating 2 intervals in the past
                                                            // (display flip guaranteed).
        D3D12XBOX_FRAME_STATISTICS_TYPE_FRAME_EVENT |
            D3D12XBOX_FRAME_STATISTICS_TYPE_RENDER |
            D3D12XBOX_FRAME_STATISTICS_TYPE_PRESENT |
            D3D12XBOX_FRAME_STATISTICS_TYPE_DISPLAY,        // Query statistics relevant to latency analysis.
        &statisticsCount,                                   // Four entries is sufficient given no overlay and
        statisticsList);                                    // a single frame event type scheduled.

    if (SUCCEEDED(hr) &&
        (statisticsCount != 0))
    {
        bool originUpdate = false;
        UINT intervalOffsetInUs;

        // Analyze the returned statistics list to determine such things as frame length from origin to GPU
        // completion and display. Use the information to inform updates to frame scheduling with the goals
        // of minimizing latency while avoiding missed vblanks due to processing spikes.

        // Some possible considerations:
        //   Is D3D12XBOX_PRESENT_STATISTICS::GPUProcessTime too far from D3D12XBOX_DISPLAY_STATISTICS::VSyncTime?
        //     (Wasted latency from early frame completion.)
        //   Is D3D12XBOX_PRESENT_STATISTICS::GPUProcessTime too near to D3D12XBOX_DISPLAY_STATISTICS::VSyncTime?
        //     (Risk of frame drop from late frame completion.)
        //   Is D3D12XBOX_PRESENT_STATISTICS::GPUProcessTime not arriving soon after D3D12XBOX_RENDER_STATISTICS::
        //     GPUWriteCompleteTime? (Frame independent work done between swap resource completion and present
        //     instead of after present.)
        //   Is D3D12XBOX_FRAME_EVENT_STATISTICS::WaitCallTime too far from D3D12XBOX_FRAME_EVENT_STATISTICS::
        //     SignalTime? (Wait thread blocked on origin signal.)

        // When frame latency conditions have changed beyond some threshold margin, update the frame origin to
        // move it nearer to the target vblank (reduce latency) or further fom the vblank (avoid vblank miss).  
        // The frame origin update will be applied when the swap resource of the subsequent frame
        // (m_FrameIndex + 1) has been flipped to the display.

        if (originUpdate)
        {
            pd3dDevice->ScheduleFrameEventX(
                D3D12XBOX_FRAME_EVENT_ORIGIN,
                intervalOffsetInUs,
                nullptr,
                D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE);
        }
    }
```

<a id="ID4EABAC" />


## Related topics

- [Index des rubriques NDA pour le développement sur console avec XBOX GDK](/fr-CA/nda/nda-overview.md)
- [Planification des SKU](/fr-CA/publishing/game-publishing/publishing-processes/managed-creators/publishing-processes-sku-planning.md)
- [Xfest2022](/fr-CA/build/core-features/graphics/overviews/presentations/xfest2022/index.md)
- [Répertoire des rubriques NDA : liens actifs vers Microsoft Learn](/fr-CA/nda/nda-topic-directory.md)
- [Trousse d'atelier sur l'accessibilité des jeux](/fr-CA/build/game-principles/accessibility/accessibility-workshop-toolkit.md)
