> ## 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 et présentation des images sur XBOX One

> Planification et présentation des images sur XBOX One

* [Remplacement des chaînes d'échange par la présentation directe et la planification des images](#ID4SwapChainsRIP)
  * [Migration depuis Windows et l'ERA ](#ID4Migration)
  * [Workflow 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 entièrement repensé 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 (scan-out) de la ressource d'image présentée
* Accroître la flexibilité de la configuration dynamique des plans d'affichage et des paramètres
* Offrir une plus grande liberté dans le choix de la file d'attente de commandes pour la soumission des présentations
* Mettre en place un mécanisme explicite de limitation du CPU permettant un contrôle précis de l'exécution du pipeline de simulation et de rendu
* Améliorer la gestion et la communication 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 souplesse dans l'organisation et la sélection des ressources d'échange, la chaîne évoluant vers un pool 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 le blocage de la file d'attente graphique en attente d'une barrière de présentation signalée par une file d'attente de calcul après le traitement d'une ressource d'échange (prise en charge prévue prochainement).
* 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 CPU, 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 exposées dans PIX. La connaissance par 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 en outre utile à la surveillance et au réglage du service XBOX Game Streaming.
* Une planification basée sur les événements et pilotée par interruptions de la production de nouvelles images à afficher, 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 éventuellement 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, qui sert de mécanisme formel de limitation. Le système permet de spécifier éventuellement 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'un nombre entier de périodes de suppression verticale (v-blank). Cette modification permet de conserver un rendu des images cohérent sur un matériel de console fixe malgré des fréquences de sortie d'affichage variables (par exemple, un rendu à 60 Hz sur un écran à 60 Hz ou à 120 Hz) et facilitera la prise en charge future du rendu natif à des fréquences supérieures à 60 Hz (par exemple, 120 Hz natif).
* L'extension des statistiques d'images suivies, avec un mécanisme de communication filtrable et extensible pour de futurs ajouts.
* L'identification des heures d'origine des images, combiné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), permettra à la plateforme de demander au microprogramme de la manette (ou d'un autre périphérique) de collecter des échantillons d'entrée et de les mettre à disposition juste à temps pour les requêtes du jeu, afin de réduire au minimum la latence globale.

<a id="ID4Migration" />

## Migration depuis Windows et 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 disposent d'équivalents comparables. Pour vous aider à vous orienter, le tableau suivant répertorie un ensemble d'API et de paramètres hérités couramment utilisés, 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/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/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/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/reference/graphics/d3d12_x/enums/d3d12_resource_flags)<br />[AUTOMATIC\_GAMEDVR\_TONE\_MAP](/fr/reference/graphics/d3d12_x/enums/d3d12_resource_flags) |
| IDXGISwapChain1::SetHDRToneMapper | [ID3D12CommandQueue::SetHDRToneMapperX](/fr/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/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_presentx)<br /><br />   - [ID3D12Device::SetFrameIntervalX](/fr/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_setframeintervalx)(..., *LengthInMicroseconds*, ...);<br />   - [D3D12XBOX\_PRESENT\_FLAG\_IMMEDIATE](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags) (remplacement PresentX)<br />    - [ImmediateThresholdPercent](/fr/reference/graphics/d3d12_x/structs/d3d12xbox_present_parameters)<br /><br />    - [D3D12XBOX\_PRESENT\_FLAG\_DO\_NOT\_WAIT](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags)<br />    - [D3D12XBOX\_PRESENT\_FLAG\_DISABLE\_VARIABLE\_REFRESH\_RATE](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags)<br />    - [D3D12XBOX\_PRESENT\_FLAG\_PERSIST](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_present_flags)<br />    - [D3D12XBOX\_PRESENT\_PLANE\_SCALE\_FILTER](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_present_plane_scale_filter) |
| IDXGISwapChain::GetFrameStatistics et DXGIXGetFrameStatistics | [ID3D12Device::GetFrameStatisticsX](/fr/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_getframestatisticsx) |
| DXGIX\_FRAME\_STATISTICS<br /><br />    - *GPUCountTitleUsed*<br /><br /><br /> | [D3D12XBOX\_RENDER\_STATISTICS](/fr/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/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/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/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/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx)<br /><br />   - [D3D12XBOX\_FRAME\_EVENT\_DISPLAY\_VBLANK](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type)<br />   - [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr/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/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) |
| DXGIXSetVLineNotification (ou Present) comme mécanisme de limitation | [ID3D12Device::ScheduleFrameEventX](/fr/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx) et [ID3D12Device::WaitFrameEventX](/fr/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_waitframeeventx) avec [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) |

<a id="ID4WorkflowPrimer" />

## Workflow général

L'approche générale pour créer un pool de ressources affichables, planifier les images en tant que mécanisme de limitation explicite et présenter les ressources d'image à l'écran consiste en 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, implications 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) qui servira de pool de ressources échangeables prenant en charge la présentation à l'écran (c'est-à-dire la « chaîne d'échange »).
* Appelez [ID3D12Device::SetFrameIntervalX](/fr/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_setframeintervalx) pour définir une fréquence et une période de rafraîchissement des images. *LengthInMicroseconds* définit l'intervalle de temps entre les présentations d'images à l'écran (flips). *PeriodInIntervals* définit, en nombre entier d'intervalles d'image, l'avance que le CPU est autorisé à prendre sur le GPU. Le CPU peut prendre *PeriodInIntervals* - 1 images d'avance sur le GPU avant d'être limité (par exemple, une valeur *PeriodInIntervals* de 2 permet au CPU 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/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx) pour définir le moment, au sein d'un intervalle d'image, auquel limiter le CPU. Spécifiez un type [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr/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 CPU 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/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_waitframeeventx) avec un type [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) pour effectuer la limitation du CPU. Spécifiez une valeur *TimeOutInMs* égale à **D3D12XBOX\_WAIT\_FRAME\_EVENT\_INFINITE** pour bloquer jusqu'à l'arrivée de l'origine, ou un délai d'expiration fixe en millisecondes pour interroger l'événement d'origine (**S\_FALSE** est renvoyé si l'origine n'est pas encore arrivée). Spécifiez pour *pToken* un pointeur vers un [D3D12XBOX\_FRAME\_PIPELINE\_TOKEN](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_frame_pipeline_token) qui, au retour lors de l'arrivée de l'origine, reçoit une valeur de jeton identifiant l'image de manière unique. Ce jeton doit être suivi pour l'image et fourni au moment de sa présentation à l'écran.
* Interrogez les entrées 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/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_presentx) pour placer les ressources de l'image rendue dans la file d'attente de présentation à l'écran. Les ressources et les jetons d'image sont fournis dans le tableau *pPlaneParameters*.
* Appelez [ID3D12Device::GetFrameStatisticsX](/fr/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_getframestatisticsx) avec le jeton de la dernière image censée avoir atteint l'écran (ou effectuez plusieurs appels sur différentes images pertinentes). Analysez les statistiques d'images renvoyées pour 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/reference/graphics/d3d12_x/interfaces/id3d12device/methods/id3d12device_scheduleframeeventx) avec le type [D3D12XBOX\_FRAME\_EVENT\_ORIGIN](/fr/reference/graphics/d3d12_x/enums/d3d12xbox_frame_event_type) pour effectuer les mises à jour, qui seront appliquées lorsque la prochaine image présentée après l'appel sera affichée à l'écran (flip).
* Effectuez tout travail indépendant des entrées sur le CPU/GPU avant d'attendre l'origine de l'image suivante (ou pendant son interrogation).

<a id="ID4ExampleCode" />

## Exemple de code

L'exemple de code suivant illustre le workflow général pour un rendu 1080p à 60 FPS, avec un seul plan d'arrière-plan et un pool 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

- [Répertoire des rubriques NDA : liens actifs vers Microsoft Learn](/fr-CA/nda/nda-topic-directory.md)
- [XR046 Nom d'affichage et image de joueur](/fr-CA/publishing/certification/fma/xr-046.md)
- [XR046 Nom d'affichage et image du joueur](/fr/publishing/certification/fma/xr-046.md)
- [Exigences XBOX testées lors de la certification pour les jeux sur console XBOX](/fr/publishing/certification/console-cert-tested-requirements.md)
- [Contenu complémentaire sur les exigences et politiques XBOX](/fr-CA/publishing/certification/xr/overview.md)
