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

# Résolution dynamique sur XBOX One

> Résolution dynamique sur XBOX One

Ce document présente le matériel, les API et les meilleures pratiques de la XBOX One permettant d'ajuster dynamiquement la résolution d'un titre afin d'obtenir une fréquence d'images fluide tout en gérant les variations de complexité du rendu des scènes. Cette technique, appelée *résolution dynamique*, permet à un titre d'afficher de vastes panoramas sous leur meilleur jour tout en restant capable de prendre en charge un nombre potentiellement important d'objets dynamiques.

<a id="introduction" />

## Introduction

Peu de choses gâchent autant l'expérience d'un joueur qu'une fréquence d'images saccadée. Bien que des défauts mineurs, comme un crénelage indésirable ou la main d'un joueur traversant occasionnellement un mur, soient gênants, ils ne perturbent pas l'ensemble du champ de vision du joueur et affectent rarement le gameplay.

Les techniques traditionnelles permettant de maintenir une fréquence d'images fluide comprennent les ajustements du *niveau de détail* (LOD) appliqués à la géométrie, aux shaders et aux textures, ainsi que la limitation des budgets artistiques des scènes de sorte que l'image la plus défavorable puisse être rendue de manière fluide. Chacune de ces techniques présente des inconvénients.

Les LOD de shaders et de géométrie sont certainement appropriés dans certains cas, mais ces techniques demandent un travail supplémentaire au développeur et à l'artiste. De plus, il est souvent difficile de masquer la transition d'un LOD au suivant lorsque des objets se trouvent au premier plan dans le champ de vision du joueur.

Limiter le budget artistique d'un titre pour maintenir l'image la plus défavorable dans le budget peut finir par placer la barre très bas pour ce qui peut être affiché dans une image moyenne. Prenons par exemple la scène de la figure 1. Limiter le budget artistique de la scène pour tenir compte de la possibilité que plusieurs personnages occupent le panorama lors d'une phase très interactive du jeu pourrait restreindre inutilement la vue du vaste panorama lorsque peu de personnages, voire aucun, sont présents.

**Figure 1.  Un scénario LOD typique** <img src="https://mintcdn.com/microsoft-4404708b/8SF8ae--p4IJyDi1/images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_01.png?fit=max&auto=format&n=8SF8ae--p4IJyDi1&q=85&s=b880ea068fd7a974fba35f9e498accc9" alt="Un scénario LOD typique" width="622" height="183" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_01.png" />

Ce livre blanc examine une troisième façon de gérer les variations typiques de complexité du rendu des scènes sur XBOX One, appelée *résolution dynamique.* Cette technique, qui peut être utilisée conjointement avec les ajustements de LOD et les restrictions artistiques des scènes, tire parti du fait que le rendu moderne est souvent fortement limité par le pixel shading. Lorsque des temps d'image excessifs sont anticipés ou constatés, un titre peut abaisser dynamiquement sa résolution, ce qui réduit la quantité totale de travail du GPU pour une même scène. Faire varier la résolution de manière dynamique pendant le jeu permet au titre d'afficher de vastes panoramas sous leur meilleur jour tout en restant capable de prendre en charge un nombre potentiellement important d'objets dynamiques.

<a id="dxgix_frame_statistics_and_the_anatomy_of_a_frame" />

## DXGIX\_FRAME\_STATISTICS et l'anatomie d'une image

Les figures suivantes présentent un exemple d'image typique représentée sur les chronologies du CPU, du GPU et de l'affichage.

**Figure 2.  Une image unique sur trois chronologies** <img src="https://mintcdn.com/microsoft-4404708b/8SF8ae--p4IJyDi1/images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_02.png?fit=max&auto=format&n=8SF8ae--p4IJyDi1&q=85&s=184adb8104929a8a3680dc93a03ebe74" alt="Une image unique sur trois chronologies" width="628" height="361" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_02.png" />

Le XDK XBOX One de février 2015 apporte des améliorations importantes à la structure **DXGIX\_FRAME\_STATISTICS**. Ces améliorations sont propres à la plateforme XBOX One et sont reflétées dans l'ensemble de ce document. Le code suivant présente les membres de la structure **DXGIX\_FRAME\_STATISTICS**, ainsi que quelques définitions utiles.

**C++**

```cpp theme={null}
typedef struct _DXGIX_FRAME_STATISTICS
{
    // CPU timeline
    UINT64 CPUTimePresentCalled;
    UINT64 CPUTimeAddedToQueue;
    UINT32 QueueLengthAddedToQueue;
      
    // GPU timeline
    UINT64 CPUTimeFrameComplete;
    UINT64 GPUTimeFrameComplete;
    UINT64 GPUCountTitleUsed;
    UINT64 GPUCountSystemUsed;

    // Display timeline
    UINT64 CPUTimeVSync;
    UINT64 GPUTimeVSync
    UINT64 CPUTimeFlip;
    UINT64 GPUTimeFlip;
    UINT64 VSyncCount;
    FLOAT  PercentScanned;
  
    VOID*  Cookie[2];
} DXGIX_FRAME_STATISTICS;

#define D3D11X_XBOX_GPU_TIMESTAMP_FREQUENCY ( 99750000 ) // 100 MHz * .9975
#define D3D11X_XBOX_VIRTUAL_REFRESH ( 59.94f )           // 59.94 MHz  
```

<a id="a_note_on_clock_rates_and_counts" />

### Remarque sur les fréquences d'horloge et les compteurs

De nombreux noms de membres de la structure **DXGIX\_FRAME\_STATISTICS** commencent par « GPUTime » ou « CPUTime ». *Ces préfixes n'indiquent pas la chronologie à partir de laquelle les données sont collectées.* Ils indiquent plutôt le domaine d'horloge échantillonné pour la statistique concernée. En fait, pour de nombreuses statistiques, nous renvoyons par commodité le temps échantillonné à la fois dans les domaines d'horloge du CPU et du GPU. Les préfixes « CPUTime » et « GPUTime » ont été volontairement omis dans la figure 2, car l'un ou l'autre domaine d'horloge peut être utilisé dans les calculs.

La console XBOX One fait varier dynamiquement ses fréquences d'horloge afin d'économiser de l'énergie, mais lorsqu'un titre est en cours d'exécution, les fréquences d'horloge sont réglées au maximum afin de garantir les meilleures performances et la meilleure réactivité. La fréquence d'horloge maximale du CPU est de 1750 MHz, et la fréquence d'horloge de référence maximale du GPU (la fréquence de l'horloge d'*horodatage*) est de 100 MHz. Notez que l'horloge du cœur du GPU de la XBOX One fonctionne à 853 MHz, mais que la valeur de temps renvoyée par les statistiques d'image utilise le compteur à 100 MHz du GPU.

Il est intéressant de noter que les horloges ne fonctionnent pas exactement à 1750 MHz ou 100 MHz. En effet, des organismes de réglementation, comme la Federal Communications Commission (FCC) aux États-Unis, exigent que les appareils n'émettent pas certaines fréquences. Pour que la console soit conforme à ces réglementations, une faible gigue doit être introduite. La fréquence exacte du CPU s'obtient facilement en appelant la fonction [QueryPerformanceFrequency](https://msdn.microsoft.com/library/windows/desktop/ms644905\(v=vs.85\).aspx), et la fréquence exacte du compteur d'horodatage du GPU est définie par `#define D3D11X_XBOX_GPU_TIMESTAMP_FREQUENCY`.

Les statistiques d'image dont le nom de variable contient « Count » désignent soit un nombre de cycles d'horloge, soit le nombre d'occurrences d'un événement tel que la synchronisation verticale, par opposition à une valeur « Time » sur une chronologie.

Le Cookie (un pour chaque plan activé) est simplement transmis par le titre au moment de la présentation, ce qui permet d'associer une statistique donnée à un appel spécifique de la fonction **DXGIXPresentArray**.

<a id="cpu_timeline" />

### Chronologie du CPU

Les commandes utilisées pour rendre une image sont générées sur le CPU. **TimePresentCalled** indique le moment où un titre a appelé **DXGIXPresentArray** sur le CPU, et **copy** indique le moment où l'image est ajoutée à la file d'attente de présentation interne.

Vous pouvez soustraire la valeur **TimeAddedToQueue** d'une image de sa valeur **TimePresentCalled** pour obtenir la durée pendant laquelle Direct3D a limité le CPU. **QueueLengthAddedToQueue** indique à quel point la file d'attente de présentation était encombrée ou vide lorsque **DXGIXPresentArray** a été appelé. Ce membre enregistre le temps *après* l'attente (le cas échéant), et non avant.

Le nombre total de cycles d'horloge du CPU consacrés à la construction d'une image (sans compter le temps de limitation par Direct3D) peut être calculé en soustrayant la valeur **TimeAddedToQueue** de l'image précédente de la valeur **TimePresentCalled** de l'image actuelle ; la valeur obtenue peut être convertie en secondes en la divisant par la fréquence du CPU.

<a id="gpu_timeline" />

### Chronologie du GPU

La chronologie du GPU représente la durée entre le moment où le GPU consomme les commandes envoyées par le CPU et le moment où il produit une image rendue. **TimeFrameComplete** indique le moment où le GPU termine l'image complète à permuter. Le temps total consacré au rendu de l'image (y compris le temps GPU passé à attendre la chaîne de permutation) peut être calculé en soustrayant **TimeFrameComplete** de la valeur correspondante de l'image précédente. La valeur obtenue peut être convertie en secondes en la divisant par la fréquence d'horodatage du GPU.

**GPUCountTitleUsed** représente le nombre de cycles d'horloge du GPU utilisés par le titre au cours d'une image donnée. **GPUCountSystemUsed** représente le nombre de cycles d'horloge du GPU utilisés par le système au cours d'une image donnée pour les applications partagées ou les charges de travail NUI (interface utilisateur naturelle). Ces deux valeurs se comprennent mieux dans le contexte de la chronologie de l'affichage, en particulier la façon dont les charges de travail des applications partagées et NUI sont réparties en tranches de temps avec la charge de travail du titre.

<a id="display_timeline" />

### Chronologie de l'affichage

La dernière chronologie est celle de l'affichage. Quelles que soient la résolution et la fréquence de rafraîchissement réelles du téléviseur du joueur, le titre présente toujours sur un affichage virtuel 1080p (1920×1080 pixels à 59,94 Hz). Au début de chaque image se produit une synchronisation verticale, au cours de laquelle l'image suivante est envoyée à l'appareil ; **TimeVSync** indique le moment de cet événement. Le pointeur vers une image donnée est permuté pendant l'intervalle de suppression, sauf si un rendu en mode immédiat est effectué ; **TimeFlip** indique ce moment. **VSyncCount** représente l'« identifiant » de la synchronisation verticale sur laquelle l'image a été présentée. Il s'incrémente de un pour un rendu à 60 Hz, de deux pour un rendu à 30 Hz, et ainsi de suite, si aucune image n'est perdue.

Enfin, une valeur **PercentScanned** est renvoyée ; elle indique le pourcentage de l'image qui avait été balayé lorsque le pilote a basculé vers l'image actuelle. Pour un rendu fixe à 30 Hz ou 60 Hz, cette valeur est toujours nulle, car aucun déchirement n'est autorisé. Pour un rendu en mode immédiat, ou pour un rendu avec une valeur **PresentImmediateThreshold** non nulle, cette valeur peut être non nulle.

<a id="a_note_on_time_slices" />

##### Remarque sur les tranches de temps

Au début de chaque image affichée, jusqu'à 8,5 % du GPU peut être réservé à l'usage du système. Notez qu'il s'agit d'une réduction par rapport aux 10 % réservés à l'usage du système lors du lancement de la XBOX One.

Il existe quatre tranches de temps : NUI, Système exclusif, Système et titre partagés, et Titre exclusif.

* Si la réservation GPU NUI est activée, 4,5 % fixes du GPU sont réservés à la charge de travail GPU NUI dans la tranche de temps NUI. Si la propriété système **DisableKinectGpuReservation** a la valeur **true**, la tranche de temps NUI est désactivée.
* Si l'indicateur de manifeste **GpuAvailability** est défini sur fixed, la tranche de temps Système exclusif est activée et 4 % fixes du GPU sont réservés ; la tranche de temps Système et titre partagés est alors désactivée.
* Si l'indicateur de manifeste **GpuAvailability** est défini sur **variable**, le titre doit répondre aux notifications d'événement **ResourceAvailabilityChanged**. Lorsque l'énumération **ResourceAvailability** est définie sur **ResourceAvailability.FullWithExtendedSystemReserve** en raison de la présence d'une application ancrée, la tranche de temps Système exclusif est fixée à 4 % et la tranche de temps Système et titre partagés est désactivée. Lorsque **ResourceAvailability** a la valeur **ResourceAvailability.Full**, la tranche de temps Système exclusif est désactivée, mais le système peut utiliser jusqu'à 3 % de la tranche de temps Système et titre partagés pour des notifications ou d'autres tâches.
* La tranche de temps Titre exclusif est utilisée uniquement pour le rendu du titre.
* Les tranches de temps NUI et Système exclusif commencent toutes les 60 Hz, au moment du VBlank. La tranche de temps NUI facultative vient en premier, suivie de la tranche de temps Système exclusif ou Système et titre partagés, puis enfin de la tranche de temps Titre exclusif. Par conséquent, une image GPU courte du titre qui commence peu après le début de la tranche de temps Titre exclusif ne peut être interrompue par aucun travail système ou NUI. En revanche, une image GPU plus longue (pour un rendu à 30 Hz), commençant juste avant le VBlank, peut potentiellement être interrompue par l'une des tranches de temps Système ou par la tranche de temps NUI, à deux moments distincts.

<a id="title_used_and_system_used_counters" />

### Compteurs d'utilisation par le titre et par le système

Voyons maintenant comment fonctionnent les compteurs de pourcentage d'utilisation. Le compteur **GPUCountTitleUsed** indique toujours, pour une image GPU donnée sur la chronologie du GPU, le nombre de cycles d'horloge du GPU consommés pendant le rendu de l'image du titre. Le compteur **GPUCountSystemUsed** indique, pour une image GPU donnée sur la chronologie du GPU, le nombre de cycles d'horloge du GPU réservés ou utilisés par le système ou NUI.

Notez également que les compteurs de pourcentage d'utilisation ne sont pas identiques au compteur « % occupé » affiché dans [PIX](/fr/tools/tools-console/pix/pix). Le compteur d'occupation du GPU dans PIX ne comptabilise pas le temps pendant lequel le GPU est bloqué en attente d'une barrière (fence). **GPUCountTitleUsed** et **GPUCountSystemUsed** incluent bien les temps de blocage, car nous mesurons le temps réellement consommé ou « utilisé », par opposition au temps pendant lequel le GPU est « occupé » à effectuer un travail utile.

<a id="using_the_frame_statistics_for_dynamic_scaling" />

### Utilisation des statistiques d'image pour la mise à l'échelle dynamique

Le code suivant présente quelques calculs simples utilisant les statistiques d'image, qui renvoient plusieurs valeurs intéressantes et utiles pour la résolution dynamique.

**C++**

```cpp theme={null}
struct DERIVED_FRAME_STATISTICS
{
    double IdealFrameTimeInMs;

    double PercentCPUUsed;
    double CPUFrameTimeInMs;
    double CPUTimeLeftInMs;
    double PresentLatencyInMs;

    double PercentGPUUsedBySystem;
    double PercentGPUUsedByTitle;
    double PercentGPUUsedTotal;
    double GPUFrameTimeInMs;
    double GPUTimeLeftInMs;
    double FrameCompleteLatencyInMs;

    bool FrameDropped;
};

void CalculateDerivedFrameStats(
    const DXGIX_FRAME_STATISTICS& Current, 
    const DXGIX_FRAME_STATISTICS& Last, 
    const UINT PresentInterval, 
    DERIVED_FRAME_STATISTICS& DerivedStats)
{
    ZeroMemory(&DerivedStats, sizeof(DerivedStats));

    LARGE_INTEGER CpuFreq;
    QueryPerformanceFrequency( &CpuFreq );

    // assume interval 1 "target" for immediate mode rendering
    UINT32 Intervals = PresentInterval == 0 ? 1 : PresentInterval; 

    double CPUCountIdealFrame =
        double(CpuFreq.QuadPart) / D3D11X_XBOX_VIRTUAL_REFRESH * Intervals;

    double GPUCountIdealFrame =
        double(D3D11X_XBOX_GPU_TIMESTAMP_FREQUENCY) / D3D11X_XBOX_VIRTUAL_REFRESH * Intervals;

    DerivedStats.IdealFrameTimeInMs =
        CPUCountIdealFrame / CpuFreq.QuadPart * 1000;

    if(Last.GPUTimeFrameComplete != 0 && Current.GPUTimeFrameComplete != 0)
    {
        DerivedStats.CPUFrameTimeInMs =
            double(Current.CPUTimePresentCalled - Last.CPUTimePresentCalled) /
            CpuFreq.QuadPart * 1000.0;

        DerivedStats.PercentCPUUsed =
            double(Current.CPUTimePresentCalled - Last.CPUTimeAddedToQueue) /
            CPUCountIdealFrame * 100.0;

        DerivedStats.GPUFrameTimeInMs =
            double(Current.GPUTimeFrameComplete - Last.GPUTimeFrameComplete) /
            D3D11X_XBOX_GPU_TIMESTAMP_FREQUENCY * 1000.0;

        DerivedStats.PercentGPUUsedBySystem =
            Current.GPUCountSystemUsed / GPUCountIdealFrame * 100.0;

        DerivedStats.PercentGPUUsedByTitle =
            Current.GPUCountTitleUsed / GPUCountIdealFrame * 100.0;

        DerivedStats.PercentGPUUsedTotal =
            DerivedStats.PercentGPUUsedBySystem + DerivedStats.PercentGPUUsedByTitle;

        if(Last.VSyncCount != 0 && PresentInterval != 0)
        {
            DerivedStats.CPUTimeLeftInMs =
               ((Last.CPUTimeAddedToQueue + CPUCountIdealFrame) - double(Current.CPUTimePresentCalled)) 
                / CpuFreq.QuadPart * 1000.0;

            DerivedStats.GPUTimeLeftInMs =
                ((Last.GPUTimeVSync + GPUCountIdealFrame) - double(Current.GPUTimeFrameComplete)) 
                / D3D11X_XBOX_GPU_TIMESTAMP_FREQUENCY * 1000.0;
        }
    }
    if( Current.VSyncCount != 0 )
    {   
        DerivedStats.PresentLatencyInMs =
            double(Current.CPUTimeFlip - Current.CPUTimePresentCalled) /
            CpuFreq.QuadPart * 1000.0;

        DerivedStats.FrameCompleteLatencyInMs =
            double(Current.CPUTimeFlip - Current.CPUTimeFrameComplete) /
            CpuFreq.QuadPart * 1000.0;
        DerivedStats.FrameDropped = 
            (Current.VSyncCount - Last.VSyncCount) > Intervals;
    }
}  
```

Pour un rendu à 60 Hz (intervalle de présentation 1), les valeurs de **CPUCountIdealFrame** et de **GPUCountIdealFrame** correspondent à environ 16,67 millisecondes, exprimées respectivement en cycles d'horloge du CPU ou du GPU. Pour un rendu à 30 Hz (intervalle de présentation 2), elles sont deux fois plus élevées. Lorsque l'intervalle de présentation est immédiat, le code définit l'intervalle sur un pour une cible idéale de 60 Hz.

Si le titre passe trop de temps à construire des commandes sur le CPU (comme illustré dans la [figure 3](#figure_3)), le résultat du calcul de **PercentCPUUsed** dépasse 100 % et la valeur de **CPUTimeLeftInMs** devient négative. Dans ce cas, abaisser la résolution GPU ne servira à rien et le titre doit prendre des mesures pour réduire la quantité de travail CPU qu'il effectue. L'utilisation de la sémantique rapide (Fast Semantics) de Direct3D 11.x aide considérablement à la construction des tampons de commandes sur le CPU, et Direct3D 12.x sera encore plus rapide.

Notez que le calcul de **PercentCPUUsed** suppose une limitation automatique par Direct3D lors de la présentation. Il devra être modifié si le titre effectue une limitation ailleurs, soit manuellement (par exemple en attendant une barrière), soit implicitement (par exemple en attendant une requête). De plus, **PercentCPUUsed** ne détecte pas si le titre est limité par le CPU sur un cœur autre que celui où réside le contexte immédiat.

**Figure 3.  Le titre ne soumet pas les images assez rapidement depuis le CPU**

<a id="figure_3" />

<img src="https://mintcdn.com/microsoft-4404708b/8SF8ae--p4IJyDi1/images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_05.png?fit=max&auto=format&n=8SF8ae--p4IJyDi1&q=85&s=2f97d7cb774155e747b6505572ce4cae" alt="Le titre ne soumet pas les images assez rapidement depuis le CPU" width="627" height="259" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_05.png" />

Si le titre passe trop de temps sur le GPU (comme illustré dans la [figure 4](#figure_4)), une image peut être manquée, ce que signale l'indicateur **FrameDropped** dans **DERIVED\_FRAME\_STATISTICS**. Le résultat du calcul de **PercentGPUUsedTotal** dépasse alors 100 %, et la valeur de **GPUTimeLeftInMs** devient négative.

**Figure 4.  Le titre est limité par la charge de travail du GPU**

<a id="figure_4" />

<img src="https://mintcdn.com/microsoft-4404708b/8SF8ae--p4IJyDi1/images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_06.png?fit=max&auto=format&n=8SF8ae--p4IJyDi1&q=85&s=65693a17d05079b878392672af89c205" alt="Le titre est limité par la charge de travail du GPU" width="611" height="266" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_06.png" />

À mesure que la charge de travail GPU du titre augmente, **PercentGPUTotal** augmente et **GPUTimeLeftinMs** diminue, car **GPUTimeFrameComplete** se rapproche de plus en plus de TimeVSync.

Le calcul de **GPUTimeLeftinMs** est sans doute le plus utile pour maintenir une fréquence d'images constante tout en ajustant dynamiquement la résolution. Si le résultat de ce calcul est supérieur à zéro plus une certaine marge de sécurité, le titre peut rendre davantage d'éléments ou augmenter la résolution de l'image. S'il est proche de zéro ou inférieur, le titre peut rendre moins d'éléments ou diminuer la résolution de l'image. Notez qu'en pratique, des marges sont utilisées afin de gérer les pics de charge de travail et d'éviter les artefacts visuels de mise à l'échelle. Pour plus d'informations, consultez la section [Quand et comment mettre à l'échelle, meilleures pratiques et conseils issus du terrain](#when_and_how_to_scale_best_practices_and_hints_from_the_field) de ce document.

<a id="scaling_the_image" />

## Mise à l'échelle de l'image

Une fois la mémoire tampon d'arrière-plan réduite, il reste à déterminer comment l'agrandir jusqu'à la résolution native 1080p que nous prévoyons de présenter.

Nous recommandons de rendre l'interface utilisateur du titre sur un plan distinct en pleine résolution, qui est fusionné avec le rendu agrandi de la scène principale. Le rendu de l'interface utilisateur contient souvent du texte et d'autres éléments qui ne se mettent pas naturellement à l'échelle, et il est rarement coûteux en cycles d'horloge du GPU. L'utilisation d'un plan d'interface utilisateur entièrement distinct entraîne toutefois le coût de l'effacement de ce plan avant le rendu, ou au moins de l'effacement des sections du plan d'interface utilisateur qui changent d'une image à l'autre.

Une autre façon de mettre à l'échelle l'image de la scène principale consiste simplement à utiliser un shader implémentant un agrandissement rapide et de haute qualité. Cette méthode a l'avantage de fonctionner sur toutes les plateformes, et elle permet le rendu recommandé des éléments d'interface utilisateur en pleine résolution après l'agrandissement, une fois le post-traitement ou l'anticrénelage de la scène principale terminé.

Sur XBOX One, une façon potentiellement plus rapide et plus efficace de mettre à l'échelle l'image de la scène principale consiste à tirer parti du matériel personnalisé de la plateforme.

<a id="taking_advantage_of_xbox_one_upscale_hardware" />

### Tirer parti du matériel d'agrandissement de la XBOX One

La XBOX One dispose d'un matériel spécifique à fonction fixe qui met à l'échelle et fusionne dynamiquement jusqu'à deux plans soumis par le titre. Ce matériel a été conçu intentionnellement pour ce scénario. Il prend en charge un agrandissement matériel entièrement programmable à dix prises horizontales et six prises verticales, ainsi que la fusion des deux plans présentés dans le matériel à fonction fixe. Deux plans de permutation sont présentés à l'aide de la fonction **DXGIXPresentArray**. De nombreuses options de filtrage sont disponibles, notamment des variantes de filtres sinc et Lanczos de haute qualité.

Notez que plusieurs modifications ont été apportées au XDK XBOX One de février 2015 afin d'améliorer la qualité du scaler matériel. Plus précisément, une erreur de décalage d'un pixel a été corrigée, et des ajustements de filtre appropriés pour les décalages de pixels fractionnaires sont désormais effectués lors du redimensionnement de l'image.

<a id="pre_multiplied_alpha_with_multiple_present_planes" />

### Alpha prémultiplié avec plusieurs plans de présentation

Dans un rendu à plan unique, les éléments de l'interface utilisateur utilisant la fusion alpha sont rendus de l'arrière vers l'avant avec une fusion alpha standard, comme le montre la [figure 5](#fig_5). <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_01.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=edfdfc34b2d0a61d59f1a96bd1a8a67d" alt="Image de la formule de calcul de DST_COLOR indice n dans un rendu à plan unique" width="428" height="39" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_01.png" />

**Figure 5.  Composition de la scène principale et des éléments d'interface utilisateur dans un rendu traditionnel à mémoire tampon d'arrière-plan unique**

<a id="fig_5" />

<img src="https://mintcdn.com/microsoft-4404708b/8SF8ae--p4IJyDi1/images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_07.png?fit=max&auto=format&n=8SF8ae--p4IJyDi1&q=85&s=adb7af0c341636d5c642ddbeb11af21a" alt="Image de la scène principale derrière l'élément d'interface utilisateur le plus éloigné, lui-même derrière l'élément d'interface utilisateur le plus proche" width="433" height="281" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_07.png" />

Cependant, comme les composants d'interface utilisateur d'un titre sont placés sur un plan distinct sur XBOX One, la fusion alpha doit être effectuée d'une manière légèrement différente qui donne néanmoins les mêmes résultats. Le plan de la scène principale est rendu en premier, puis le plan de l'interface utilisateur est rendu séparément. Les deux plans sont ensuite composés.

**Figure 6.  Composition de plans distincts pour l'interface utilisateur et la scène** <img src="https://mintcdn.com/microsoft-4404708b/8SF8ae--p4IJyDi1/images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_08.png?fit=max&auto=format&n=8SF8ae--p4IJyDi1&q=85&s=c5e8b7ed1aa7f22275b7889eb0a6a000" alt="Composition de plans distincts pour l'interface utilisateur et la scène" width="609" height="457" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_08.png" />

Un peu de mathématiques permet de montrer comment séparer le rendu du plan de la scène principale de celui du plan de l'interface utilisateur, et comment composer les deux à l'aide du matériel à fonction fixe de mise à l'échelle et de fusion des plans de sortie de la XBOX One. Les concepts mathématiques qui sous-tendent ce rendu par plans sont présentés dans la section [Dérivation](#derivation) de ce document.

<Note>
  **DXGIXPresentArray** utilise le plan matériel un pour désigner l'arrière-plan et le plan matériel zéro pour désigner le premier plan.
</Note>

La dérivation de la section suivante intéressera particulièrement les développeurs qui effectuent une fusion alpha non traditionnelle sur le plan de l'interface utilisateur et qui souhaitent mieux comprendre les calculs afin d'adapter correctement leurs propres solutions.

<a id="derivation" />

##### Dérivation

Considérons d'abord deux itérations de l'équation standard de fusion alpha et refactorisons-la sous une forme adaptée au nouveau plan d'interface utilisateur et au plan de la scène principale : <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_02.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=dfb14ba061b3fdab44c4768076dcbf56" alt="Image de la formule de DST_COLOR indice n" width="520" height="191" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_02.png" />

Le premier terme entre crochets est indépendant de la couleur de destination. Pour les besoins de cette discussion, ce terme est défini comme *`UI_COLOR`* à l'aide de la relation récursive correspondante suivante : <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_03.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=217cf3e597e4d774cc85318a3d9c5372" alt="Image de la formule de UI_COLOR indice n" width="405" height="69" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_03.png" />

Le second terme entre crochets peut être développé encore et encore, sans nécessiter de couleurs sources, à l'aide de la relation de produit suivante : <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_04.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=6064cb06b6fe1a4148a6c0a205def20a" alt="Image de la formule de BLENDED_SCENE_COLOR indice n" width="461" height="44" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_04.png" />

De plus, la scène principale rendue *`(DST_COLOR<sub>0</sub>)`* est considérée comme déjà terminée, et *`(DST_COLOR<sub>0</sub>)`* est considérée comme l'image finale :

<img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_05.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=00a8b33ed71bfea524f683fe51685228" alt="Image montrant que DST_COLOR indice 0 est égal à SCENE_COLOR et que DST_COLOR indice n est égal à FINAL_IMAGE" width="214" height="49" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_05.png" />

En remplaçant *`UI_COLOR<sub>n</sub>`*, *`SCENE_COLOR`*, *`FINAL_IMAGE`* et *`BLENDED_SCENE_COLOR<sub>n</sub>`* dans l'équation de fusion alpha d'origine, on obtient la solution suivante pour *`FINAL_IMAGE`* :

<img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_06.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=71e861f49a16750c549c229611d490ba" alt="Image montrant la formule de FINAL_IMAGE" width="512" height="183" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_06.png" />

Le matériel de fusion de la XBOX One utilise le calcul suivant et suppose un alpha prémultiplié : <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_07.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=b195ec14e29af7c87fd1c6f6f981bad5" alt="Image montrant la formule de COMPOSITE_IMAGE" width="518" height="37" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_07.png" />

Pour cet exemple, le plan de la scène principale est défini sur le plan un et le plan de l'interface utilisateur sur le plan zéro. De plus, le canal alpha du plan de l'interface utilisateur est défini sur le canal alpha du plan zéro (appelé *`UI_ALPHA<sub>n</sub>`* ci-dessous). <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_08.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=0c85e228a2f47a01efefabff76a579da" alt="Image montrant les formules de calcul de COMPOSITE_IMAGE" width="484" height="111" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_08.png" />

Ensuite, *`FINAL_IMAGE`* est défini comme égal à *`COMPOSITE_IMAGE`*. La résolution pour *`UI_ALPHA<sub>n</sub>`* donne le résultat suivant : <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_09.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=1bb808b99be808bb6edb432cbe99a73d" alt="Image montrant le résultat de la résolution pour UI_ALPHA indice n" width="430" height="163" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_09.png" />

Après quelques itérations, la relation récursive est dérivée. Elle montre comment accumuler correctement les valeurs alpha du plan de l'interface utilisateur afin que celui-ci soit correctement fusionné avec le plan de la scène principale : <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_10.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=08397ab06a0cad74576d2d3313e7380b" alt="Montre la formule de fusion du plan de l'interface utilisateur avec le plan de la scène principale" width="435" height="235" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_10.png" />

<a id="procedure" />

##### Procédure

En rassemblant quelques résultats, on obtient la solution et la procédure finales :

1. Rendez la scène principale sur le plan matériel un de la manière habituelle.  <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_11.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=6b6bb8f3ea34ce5ce270ecdbdb3decac" alt="Image de la formule de SCENE_COLOR indice m" width="441" height="59" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_11.png" />
2. Effacez le plan matériel zéro en noir. Notez que vous devez effacer uniquement les parties du plan qui contiennent des éléments d'interface utilisateur dans chaque image. Ensuite, rendez les éléments d'interface utilisateur de la manière habituelle. <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_12.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=db6b4f2e2ab373cd3ddb0215e6728a64" alt="Image de la formule de rendu des éléments d'interface utilisateur" width="405" height="39" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_12.png" /> Accumulez les valeurs alpha de l'interface utilisateur dans le canal alpha du plan matériel un. <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_13.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=5a38c3d372ee529bac15400b20ab11e6" alt="Image de la formule de UI_ALPHA indice n" width="435" height="19" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_13.png" /> Le code suivant montre comment rendre le plan de l'interface utilisateur. **C++**

```cpp theme={null}
      D3D11_RENDER_TARGET_BLEND_DESC RTUIDesc = {0};
      RTUIDesc.BlendEnable = TRUE;
          
      // DST_COLOR = SRC_COLOR*SRC_ALPHA + DST_COLOR*(1-SRC_ALPHA)
      RTUIDesc.BlendOp = D3D11_BLEND_OP_ADD;
      RTUIDesc.SrcBlend = D3D11_BLEND_SRC_ALPHA;
      RTUIDesc.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
          
      // DST_ALPHA = DST_ALPHA + (1- DST_ALPHA)(SRC_ALPHA)
      RTUIDesc.BlendOpAlpha = D3D11_BLEND_OP_ADD;
      RTUIDesc.SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; 
      RTUIDesc.DestBlendAlpha = D3D11_BLEND_ONE; 
      
      RTUIDesc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;  
```

1. Présentez les deux plans à l'aide du paramètre *PresentImmediateThreshold* de la fonction **DXGIPresentArray**. Le matériel gère la fusion finale lorsqu'il est configuré pour l'alpha prémultiplié à l'aide de l'indicateur **DXGI\_ALPHA\_MODE.DXGI\_ALPHA\_MODE\_PREMULTIPLIED**. <img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_14.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=685fadb32e752fab75b2575da11a29af" alt="Image montrant le calcul de FINAL_IMAGE" width="446" height="19" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_eq_14.png" />

<a id="a_note_on_immediate_and_maximum_threshold_rendering_when_using_the_scaler" />

##### Remarque sur le rendu immédiat et à seuil maximal lors de l'utilisation du scaler

Le matériel ne peut pas modifier les paramètres du scaler tant que l'affichage ne se trouve pas dans une zone de suppression verticale. En effet, les tampons de lignes et la configuration matérielle doivent rester cohérents au sein d'une image. Par conséquent, le rendu en mode immédiat revient par défaut à l'intervalle de présentation un et la valeur du paramètre *PresentImmediateThreshold* de la fonction **DXGIPresentArray** revient par défaut à zéro chaque fois que les paramètres du scaler (comme le type de filtre ou la taille de la mémoire tampon d'entrée) sont modifiés. Autrement dit, *le rendu d'un titre ne peut pas présenter de déchirement sur l'image où une nouvelle taille d'entrée ou un nouveau type de filtre est sélectionné*.

<a id="when_and_how_to_scale_best_practices_and_hints_from_the_field" />

## Quand et comment mettre à l'échelle, meilleures pratiques et conseils issus du terrain

Les remarques et meilleures pratiques suivantes sont issues de l'implémentation de la résolution dynamique dans des exemples de code et dans des titres commercialisés.

<a id="preferred_horizontal_scaling" />

### Mise à l'échelle horizontale à privilégier

Nous recommandons d'effectuer la mise à l'échelle uniquement dans le sens horizontal, pour plusieurs raisons. Tout d'abord, le scaler matériel de la XBOX One prend en charge davantage de prises dans le sens horizontal que dans le sens vertical, ce qui offre une mise à l'échelle horizontale de meilleure qualité. Ensuite, dans la plupart des titres, le mouvement naturel de la caméra varie surtout dans le sens horizontal, lorsque les joueurs balaient l'horizon du regard ; les changements horizontaux sont donc moins perceptibles.

<a id="when_not_to_scale" />

### Quand ne pas mettre à l'échelle

Afin de réduire au minimum les artefacts visibles, nous recommandons de lier les mises à jour de la taille de la scène d'entrée aux moments où la scène est en mouvement. Cela inclut les moments où la caméra se déplace ou ceux où l'activité de la scène est intense.

Nous recommandons également que les titres ne mettent pas continuellement leur résolution à l'échelle. Une fois qu'une résolution cible a été choisie et appliquée, une petite marge de performances doit être conservée afin que le titre puisse maintenir la résolution cible pendant une durée déterminée, pour éviter des visuels instables ou des changements de résolution excessifs.

<a id="preemptive_tuning_of_the_scaling_parameters" />

### Réglage préventif des paramètres de mise à l'échelle

Toute logique du moteur de jeu servant à prédire la complexité de la scène peut être fournie à l'avance à la fonction qui détermine « l'ampleur de la mise à l'échelle ». Par exemple, si l'on sait que la solution de rendu est sur le point d'être sollicitée par l'apparition d'une grosse explosion ou d'un grand nombre de personnages, la résolution peut être abaissée de manière proactive.

Un titre peut également prendre en compte la notification d'événement **ResourceAvailabilityChanged** dans sa décision de mise à l'échelle.

<a id="different_ui_and_main_scene_refresh_rates" />

### Fréquences de rafraîchissement différentes pour l'interface utilisateur et la scène principale

Un titre à 60 Hz peut rendre le plan de l'interface utilisateur à 30 Hz afin d'économiser du temps GPU. Pour cela, il suffit de définir le champ **UsePreviousBuffer** sur **true** dans la structure **DXGIX\_PRESENTARRAY\_PARAMETERS** du plan de l'interface utilisateur, puis de ne remplir la mémoire tampon d'arrière-plan de l'interface utilisateur qu'une image sur deux.

Un titre à 30 Hz peut également rendre le plan de l'interface utilisateur à 60 Hz si des mises à jour fluides de l'interface utilisateur sont nécessaires. Pour cela, il suffit de définir le champ **UsePreviousBuffer** sur **true** dans la structure **DXGIX\_PRESENTARRAY\_PARAMETERS** du plan de la scène principale.

<a id="missed_frame_safety_margins" />

### Marges de sécurité contre les images manquées

Un équilibre délicat doit être maintenu entre la part du GPU conservée en réserve pour gérer les pics inattendus d'utilisation et la part disponible pour l'utilisation moyenne globale. Si une trop grande part du GPU est réservée aux pics, la complexité moyenne des scènes en pâtit. Si la réserve est trop faible, davantage d'images seront perdues. Cet équilibre délicat est très spécifique à chaque jeu et peut même varier selon les scènes et les niveaux d'un même titre.

Notez qu'en cas d'images perdues, il peut être préférable d'autoriser le déchirement de l'image suivante (à l'aide du paramètre *PresentImmediateThreshold* de la fonction **DXGIPresentArray**) plutôt que de bloquer. De plus, il peut être judicieux d'abaisser la résolution de plusieurs crans dès que possible en cas d'image perdue.

**Figure 7.  Marge de sécurité de la charge de travail du GPU** <img src="https://mintcdn.com/microsoft-4404708b/8SF8ae--p4IJyDi1/images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_10.png?fit=max&auto=format&n=8SF8ae--p4IJyDi1&q=85&s=0401b9d761a2427fa38d0a3dff15ace5" alt="Marge de sécurité de la charge de travail du GPU" width="627" height="261" data-path="images/gdk/features/graphics/xbox_one_dynamic_resolution_fig_10.png" />

<a id="using_dxgixsetframenotification_with_dxgix_frame_statistics" />

### Utilisation de DXGIXSetFrameNotification avec DXGIX\_FRAME\_STATISTICS

Plus tôt vous pouvez diagnostiquer votre fréquence d'images réelle, plus tôt vous pouvez agir et éviter les images perdues. Il est possible d'interroger les statistiques d'image à l'aide de la fonction **DXGIXGetFrameStatistics** avant que l'image ne soit entièrement balayée.

Les titres peuvent également interroger les résultats à l'aide de **DXGIGetFrameStatistics**. Les données de chronologie sont valides lorsque les critères répertoriés dans le tableau suivant sont remplis.

| Chronologie | Les résultats sont valides... |
| - | - |
| CPU | Immédiatement après l'appel de la présentation. |
| GPU | Lorsque la valeur de <b>CPUTimeFrameComplete</b> ou de <b>GPUTimeFrameComplete</b> devient non nulle. |
| Affichage | Lorsque la valeur de <b>CPUTimeVsync</b> ou de <b>GPUTimeVsync</b> devient non nulle. |

Les titres peuvent utiliser la fonction **DXGIXSetFrameNotification** pour recevoir des notifications pour les événements répertoriés dans le tableau suivant.

| Valeur de <i>NotificationType</i> | Description |
| - | - |
| FRAME\_NOTIFICATION\_QUEUED | La notification de mise en file d'attente est signalée lorsqu'une image est mise en file d'attente après la présentation et après l'introduction d'éventuels blocages du CPU. La partie chronologie du CPU de la structure <b>DXGIX\_FRAME\_STATISTICS</b> de l'image est garantie valide une fois cet événement de mise en file d'attente signalé. |
| FRAME\_NOTIFICATION\_COMPLETED | La notification d'achèvement est signalée lorsque le GPU a terminé le rendu d'une image. La partie chronologie du GPU de la structure <b>DXGIX\_FRAME\_STATISTICS</b> de l'image est garantie valide une fois l'événement d'achèvement signalé. |
| FRAME\_NOTIFICATION\_FLIPPED | La notification de basculement est signalée lorsqu'une image est basculée pour être affichée. La partie chronologie de l'affichage de la structure <b>DXGIX\_FRAME\_STATISTICS</b> de l'image est garantie valide une fois l'événement de basculement signalé. |

En bref, il n'est pas nécessaire que l'image entière soit balayée pour que des données utiles à son sujet soient disponibles. Appeler la fonction **DXGIXGetFrameStatistics** tôt permet de réduire la marge de sécurité et de maximiser le nombre de pixels rendus pour une image moyenne.

<a id="summary" />

## Résumé

Ce document vous a présenté des détails essentiels sur la façon dont les images sont rendues sur XBOX One, ainsi que sur le fonctionnement du matériel et des API de mise à l'échelle de la XBOX One. Vous avez également vu comment interroger les informations relatives à l'utilisation du GPU et aux latences de votre titre afin de déterminer quand mettre à l'échelle dynamiquement la résolution de rendu. Plusieurs titres XBOX One ont déjà été commercialisés en utilisant des formes précoces de résolution dynamique ; les principes et techniques exposés dans ce livre blanc ont donc largement fait leurs preuves.


## Related topics

- [Répertoire des rubriques NDA : liens actifs vers Microsoft Learn](/fr/nda/nda-topic-directory.md)
- [Résolution des problèmes de connexion aux services XBOX](/fr/services/xbox-services/fundamentals/identity/auth/live-troubleshooting-sign-in.md)
- [L'architecture audio de XBOX One](/fr/build/console-features/audio/overviews/xbox-one-audio-architecture.md)
- [FAQ et résolution des problèmes multijoueurs](/fr/services/xbox-services/multiplayer/mpsd/concepts/live-multiplayer-2015-faq.md)
- [Vue d'ensemble des études de cas sur la durabilité](/fr/build/game-principles/sustainability/case-studies/case-studies-overview.md)
