Skip to main content
Cette rubrique décrit les API de cadencement des images du Microsoft Game Development Kit avec extensions XBOX (GDKX) pour la planification des images. Elle couvre les objectifs, les capacités et les pièges de ces API. Vous apprendrez à utiliser ces API pour équilibrer la stabilité du jeu et la latence.
Ces renseignements étaient à jour en avril 2022. Plusieurs fonctionnalités pourraient avoir changé ou avoir été mises à jour depuis.

API de cadencement des images

Les nouvelles API de cadencement des images ont remanié le processus de présentation graphique. Elles visent à :
  • 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 flexibilité de la configuration dynamique des plans d’affichage et des paramètres
  • Accroître la liberté dans le choix de la file d’attente de commandes pour la soumission de la présentation
  • É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 et la production de rapports des statistiques du pipeline d’images
Elles sont disponibles depuis plusieurs années, mais n’ont pas été beaucoup abordées dans la documentation du GDKX. Figure 1. API de cadencement des images avec un changement cassant. API de cadencement des images À la figure 1, l’exemple de code comporte du texte noir et du texte magenta. Un changement cassant historique est devenu obligatoire en avril 2019. Les API à gauche, en noir, sont des extensions Direct3D ou XDK standard. Si vous utilisiez l’API Present, vous appeliez les API en noir à gauche. Les deux autres à gauche étaient des extensions ajoutées à l’époque de l’ERA. Les API à droite, en magenta, sont les nouvelles API; par exemple, PresentX. Comme il s’agissait d’un changement cassant, des modifications de code étaient nécessaires lors du passage au GDKX. Ce passage est devenu obligatoire il y a trois ans. Vous les utilisez déjà si vous avez créé un jeu au cours des trois dernières années.

L’ancienne méthode - initialisation

Figure 2. L’ancienne méthode - initialisation. L'ancienne méthode - initialisation La figure 2 représente votre utilisation antérieure de l’API Present. Auparavant, pendant la période d’initialisation au début de votre jeu, vous créiez ce qu’on appelait une chaîne d’échange (swap chain). Elles ne sont plus utilisées dans le même sens. Notez que le système allouait les mémoires tampons de la chaîne d’échange.

L’ancienne méthode - boucle d’images

Figure 3. L’ancienne méthode - boucle d’images. L'ancienne méthode - boucle d'images Auparavant, pour chaque image, vous utilisiez le processus suivant.
  1. Demander une mémoire tampon à la chaîne d’échange.
  2. Effectuer le rendu de l’image dans la mémoire tampon de la chaîne d’échange.
  3. Appeler Present.
Present était une API simple qui n’avait que quelques paramètres. La figure 3 montre Present et le paramètre frameInterval. Sa valeur de un signifiait 60 hertz (Hz). Notez qu’il n’y a aucun contrôle du minutage. Le système progresse aussi loin qu’il le peut, tant que c’est correct. Cependant, dans certains cas, Present peut se bloquer.

La nouvelle méthode - initialisation

Figure 4. La nouvelle méthode - initialisation. La nouvelle méthode - initialisation La figure 4 montre l’initialisation de la présentation. Lorsque vous démarrez votre jeu, vous devez appeler davantage de code, car votre titre a plus de contrôle qu’auparavant. Le titre crée ses propres mémoires tampons de chaîne d’échange, spécifie la fréquence d’images à l’avance, puis crée un événement d’origine d’image. Comme le montre la figure 4, au lieu de créer une interface de chaîne d’échange, vous créez vos propres mémoires tampons de chaîne d’échange une à la fois, comme des ressources ordinaires. L’indicateur HEAP_ALLOW_DISPLAY indique que vous comptez utiliser ces mémoires tampons pour l’affichage. Vous appelez ensuite plusieurs nouvelles API. Une nouvelle API, SetFrameIntervalX, spécifie à l’avance votre fréquence d’images cible, plutôt que d’attendre que l’image soit présentée. Dans ce cas, la fréquence d’images cible est de 60 Hz. Pour terminer l’initialisation, planifiez un événement ORIGIN. Il servira à bien des choses, y compris pour déterminer le moment où vous voulez que votre image commence. Voilà ce que vous faites à l’initialisation. Pour la boucle d’images, vous faites maintenant ce qui suit une fois par image.

La nouvelle méthode - boucle d’images

Figure 5. La nouvelle méthode - boucle d’images. La nouvelle méthode - boucle d'images Comme le montre la figure 5, au lieu d’appeler simplement Present, appelez d’abord WaitFrameEventX. Il attend l’événement ORIGIN que vous avez planifié comme le montre la figure 4. Les images ne peuvent plus être démarrées quand vous le voulez. Vous devez les attendre. Ensuite, effectuez le rendu de votre image dans la mémoire tampon de chaîne d’échange que vous avez créée. Enfin, appelez PresentX, la nouvelle version de Present. PresentX comporte de nombreux paramètres. Ce n’est plus une API simple.

Motivation des nouvelles API

Cette section énumère une série de problèmes rencontrés avec les anciennes API et la façon dont les nouvelles API sont censées les résoudre. Des exemples de code sont fournis, et les figures utilisent du texte magenta pour le code de la solution.

Thème principal : la latence

Le thème principal de la nouvelle API est le contrôle de la latence, qui est un concept important. Si vous consultez souvent Digital Foundry, vous verrez que leurs critiques tentent de mesurer exactement la latence. Grâce à XBOX Game Streaming, les joueurs peuvent jouer à des jeux dans le nuage. La latence est également importante pour le jeu dans le nuage. Les anciennes API Present ne fonctionnaient pas très bien en matière de latence. Par exemple, lorsque vous appeliez Present, le pilote se bloquait aussi longtemps que nécessaire. Ce blocage pouvait durer longtemps. Vous n’aviez aucun contrôle sur celui-ci. La latence à ce moment-là avait tendance à être un multiple entier de l’intervalle d’image. Si vous étiez limité par le GPU, vous aviez tendance à obtenir la latence la plus élevée possible, même lorsque vous n’en aviez pas besoin. Les nouvelles API ont une latence explicite. Le titre peut demander une latence exacte en microsecondes plutôt qu’un nombre entier d’images. Vous pouvez faire augmenter et diminuer cette latence au besoin. En période de stress, vous pouvez avoir une latence plus élevée et éviter de perdre des images. En période sans stress, vous pouvez réduire la latence et avoir un jeu plus réactif.

Problème 1/10 : Aucune extensibilité pour plusieurs plans d’affichage

La XBOX One a été la première à introduire le second plan d’affichage. Il était exposé aux titres, mais n’était pas extensible.

Solution : Extensibilité pour plusieurs plans d’affichage

Figure 6. Extensibilité pour plusieurs plans d’affichage. Extensibilité pour plusieurs plans d'affichage La figure 6 montre du codage en dur en magenta, mais pas pour les deux plans d’affichage. Lorsque vous appelez Present maintenant, vous passez un nombre arbitraire de plans, et chacun d’eux contient un nombre arbitraire de vues. Ce codage prend en charge tout matériel pouvant avoir plus de deux plans ou plus d’un affichage par plan. Vous pouvez avoir un plan d’affichage où une vue est RGBE avec un exposant partagé, et une seconde vue contient votre canal alpha. D’autres scénarios pourraient être possibles, comme l’utilisation de deux vues pour l’écran partagé ou de deux vues pour le mode spectateur. Ces scénarios ne sont pas pris en charge actuellement, mais l’API les prend en charge implicitement.

Problème 2/10 : Aucun moyen de découpler la fréquence de rendu des plans d’affichage

Ce problème est lié à l’extensibilité des plans d’affichage. Par le passé, il n’y avait aucun moyen de découpler la fréquence de rendu des plans d’affichage. Par exemple, un plan d’affichage pourrait effectuer le rendu à 60 images par seconde (FPS) et l’autre à 30 FPS. Le matériel le prend en charge, mais l’API ne le faisait pas. L’extensibilité des plans d’affichage est maintenant importante pour les jeux à 120 Hz, qui deviennent plus courants. Il n’est pas nécessaire d’effectuer le rendu de l’interface utilisateur à 120 Hz. À 120 Hz, vous ne disposez que de peu de temps pour une image.

Solution : Moyen de découpler la fréquence de rendu des plans d’affichage

Figure 7. Découpler la fréquence de rendu des plans d’affichage. Découpler la fréquence de rendu des plans d'affichage Comme le montre la figure 7, le découplage des fréquences de rendu est implicite dans la nouvelle API, car vous passez les ressources qui seront affichées. Par conséquent, vous pouvez passer la même ressource pour le plan de l’interface utilisateur deux fois de suite.

Problème 3/10 : Aucun PresentationThreshold pour prendre en charge un déchirement limité

Le problème suivant est PresentationThreshold, de l’époque de la XBOX 360. C’est un moyen de faire un compromis entre le déchirement et les pertes d’images. PresentationThreshold était exposé par une extension sur XBOX 360. Il s’agit d’un pourcentage de déchirement de 0 à 100. Zéro pour cent est la valeur par défaut et signifie qu’il n’y a jamais de déchirement. Cinquante pour cent signifie que si le budget d’image est dépassé et que l’image est terminée alors que seuls les 50 premiers pour cent de l’image ont été balayés, vous utilisiez Present immédiatement, puis le déchirement se produisait. Si plus de 50 pour cent est utilisé, le déchirement n’est pas nécessaire, et vous voudriez attendre le prochain Vblank. L’autre extrême est 100 pour cent, ce qui signifie que tant que la fréquence d’images est respectée, il n’y a pas de déchirement. Cependant, lorsque la cible d’image est manquée, le déchirement peut se produire.

Solution : Utiliser PresentationThreshold pour prendre en charge un déchirement limité

Figure 8. PresentationThreshold pour prendre en charge un déchirement limité. Solution : PresentationThreshold pour prendre en charge un déchirement limité La figure 8 montre l’utilisation de ImmediateThresholdPercent de la nouvelle API. PresentationThreshold prend en charge un déchirement limité. Vous pouvez l’utiliser dès maintenant. De nombreux titres utilisent le mode 100 pour cent, qui est probablement l’utilisation la plus courante.

Problème 4/10 : Aucune prise en charge des fréquences d’images supérieures à 60 FPS

L’ancienne API ne prenait pas en charge les fréquences d’images supérieures à 60 FPS. Elles ne pouvaient pas être exprimées, car l’intervalle d’image était un UINT. Un signifiait 60 FPS. On ne peut pas avoir la moitié de 1 : la moitié n’est pas un entier. Il n’y avait aucun moyen d’indiquer que vous vouliez 120 Hz avec l’ancienne API. Une nouvelle API était nécessaire. La nouvelle API prend en charge 120 Hz. Elle prend implicitement en charge tout ce qui est un multiple de cette durée d’image. Ainsi, vous obtenez 40 FPS, ou encore, depuis peu, 24 FPS pour les cinématiques.

Solution : Prise en charge des fréquences d’images supérieures à 60 FPS

Figure 9. Prise en charge des fréquences d’images supérieures à 60 FPS. Prise en charge des fréquences d'images supérieures à 60 FPS Comme le montre la figure 9, la solution consiste à utiliser le paramètre LengthInMicroseconds. Il s’agit toujours d’un entier non signé, mais il est maintenant exprimé en microsecondes. N’importe quelle fréquence d’images peut être exprimée ici. Passez la durée en microsecondes que vous voulez et, si cette durée est prise en charge, l’API réussit. Si un jour il faut prendre en charge 240 FPS, l’API n’aura pas besoin de changer. Lorsque la prise en charge de 24 FPS a été ajoutée récemment, l’API n’a pas changé.
La bonne façon de détecter la prise en charge de 120 FPS est d’utiliser GetDisplayModeListX. Elle n’appelle pas SetFrameIntervalX et ne vérifie pas le code de retour.

Problème 5/10 : Aucun moyen de terminer l’image sur la file d’attente de calcul

L’ancienne API appelait Present, qui était un membre de l’interface de chaîne d’échange. La chaîne d’échange faisait implicitement partie de la file d’attente graphique. Il est courant que le dernier travail d’une image soit entièrement basé sur le calcul. Il serait utile d’effectuer ce travail, d’appeler Present, puis d’avoir déjà commencé le travail graphique de l’image suivante. Les graphiques et le calcul se chevauchent un peu et sont sous-pipelinés. Un exemple était disponible pour vous montrer comment terminer l’image sur une file d’attente de calcul avec l’ancienne API. Cependant, c’était compliqué en raison de cette omission.

Solution : Moyen de terminer l’image sur la file d’attente de calcul

Figure 10. Moyen de terminer l’image sur la file d’attente de calcul. Moyen de terminer l'image sur la file d'attente de calcul La figure 10 montre qu’avec la nouvelle API, il n’y a plus d’interface de chaîne d’échange. Present a été déplacé vers la file d’attente de commandes afin que l’API puisse exprimer que l’image peut être terminée sur n’importe quelle file d’attente de commandes. PresentX est une méthode de ID3D12CommandQueue (classe de base) plutôt que de IDXGISwapChain, qui n’existe plus. Jusqu’à présent, cela est pris en charge sur les graphiques et sur le calcul asynchrone. S’il fallait un jour le prendre en charge sur un nouveau type de file d’attente ou sur une file d’attente existante comme l’accès direct à la mémoire (DMA), cela pourrait se faire sans modifier l’API.

Problème 6/10 : La limitation n’offre aucun contrôle précis

L’ancienne API n’offrait aucun contrôle précis sur la limitation. Il s’agit d’un blocage intentionnel visant à empêcher la latence de croître sans limite. C’est la latence de rendu. Elle avait tendance à prendre par défaut un multiple entier de l’intervalle d’image. Les titres contournaient ce problème en ajoutant une troisième mémoire tampon de chaîne d’échange, en signalant une clôture (fence) à un certain point du milieu de l’image, puis en attendant cette clôture sur le processeur. Essentiellement, les titres effectuent une limitation manuelle avant que le pilote puisse le faire automatiquement. Cependant, c’est imprécis. Vous pouvez limiter d’une image plus une prépasse de profondeur, mais pas d’une image et 4 ms.

Solution : Contrôle précis de la limitation

Figure 11. Contrôle précis de la limitation. Contrôle précis de la limitation La figure 11 montre la façon dont la nouvelle API est contrôlée. Ce contrôle s’effectue au moyen des deux paramètres en texte magenta. (Ils seront abordés plus en détail plus loin dans cette rubrique.) Le premier paramètre est PeriodInIntervals. Il indique combien d’intervalles de la fréquence d’images sont nécessaires pour terminer une image du début à la fin. Par exemple, si la fréquence d’images est de 60 FPS, l’intervalle de la fréquence d’images est de 16,7 ms. Plus d’un de ces intervalles pourrait être nécessaire du début de l’image jusqu’à sa fin. Le second paramètre est IntervalOffsetInMicroseconds. Utilisez-le pour une fraction d’image de latence. Peut-être que la période en intervalles était de deux, mais qu’en réalité, une valeur entre un et deux était nécessaire. Une valeur appropriée du décalage d’intervalle peut être trouvée pour y parvenir.

Problème 7/10 : L’entrée de la manette n’a aucune synchronisation explicite

L’ancienne API ne vous permettait pas de vous synchroniser avec la manette. Il s’agit d’un facteur important de latence, en particulier pour les manettes sans fil. Lorsqu’un bouton est enfoncé, le jeu ne réagit pas immédiatement. Pour économiser la pile, les manettes sans fil n’envoient des mises à jour que de temps à autre. Un joueur pourrait appuyer sur un bouton juste avant une mise à jour et obtenir cette mise à jour immédiatement. Cependant, si un joueur appuie sur un bouton juste après la mise à jour, il doit attendre la prochaine mise à jour pour que l’appui sur le bouton soit reconnu. C’est de la latence. D’une certaine façon, c’est le pire type de latence, car elle n’est pas la même à chaque image. Les joueurs peuvent compenser un peu la latence s’ils savent ce qu’elle sera et qu’elle est toujours la même. Sinon, il devient difficile de faire des choses comme appuyer sur le bouton exactement au bon moment dans un jeu nécessitant des réflexes rapides.

Solution : Synchronisation explicite avec l’entrée de la manette

Figure 12. Synchronisation explicite avec l’entrée de la manette. Synchronisation explicite avec l'entrée de la manette La figure 12 montre l’une des choses pour lesquelles l’événement ORIGIN est utile si vous le planifiez de façon prévisible. Une manette sans fil peut envoyer une mise à jour juste à temps, peut-être une ms avant que le titre en ait besoin. Cela réduit la latence, et c’est la même latence pour chaque image.

Problème 8/10 : Les événements importants n’ont aucune notification

L’ancienne API ne permettait pas la notification des événements importants, à l’exception du Vblank. Il est important pour les titres de savoir quand l’interruption Vblank s’est produite. Une partie de cette fonctionnalité a été supprimée. Cependant, il existe encore des moyens d’obtenir des notifications d’événements importants.

Solution : Notification des événements importants

Figure 13. Notification des événements importants. Notification des événements importants Comme le montre la figure 13, la nouvelle API prend en charge deux événements par défaut : la notification Vblank et la notification Flip. L’événement Flip se produit lorsqu’une nouvelle mémoire tampon de chaîne d’échange devient visible, et il est extensible. La notification Flip est un moyen pratique de savoir quand il est sécuritaire de réutiliser une mémoire tampon d’échange. D’autres éléments pourraient être ajoutés à Flip sans modifier l’API.

Problème 9/10 : PIX ne peut pas afficher une image

Par le passé, les captures de minutage PIX (Timing Captures) ne pouvaient pas afficher (suivre) une image entière. La seule information dont PIX disposait au sujet d’une image était le moment où vous appeliez Present avec l’ancienne API. Il n’y avait aucune information sur ce qui avait contribué à cet appel Present ni sur le moment où cette image avait commencé.

Solution : Moyen pour PIX d’afficher une image

Figure 14. Moyen pour PIX d’afficher une image. Moyen pour PIX d'afficher une image La figure 14 montre un jeton de pipeline d’image. Lorsque vous attendez l’événement ORIGIN, vous recevez un jeton de pipeline d’image comme valeur de retour. Conservez-le, car vous en aurez besoin plus tard. Lorsque vous appelez Present, vous passez le même jeton. PIX reconnaît maintenant :
  • Le début d’une image et la fin correspondante de cette image.
  • Que d’autres événements faisaient partie de la même image lorsque vous passez le même jeton.

Problème 10/10 : Le titre ne peut pas récupérer de données de minutage détaillées

L’ancienne API ne peut pas récupérer de données de minutage détaillées. Pour votre titre, vous pourriez vouloir savoir combien de temps les choses ont pris ou quand elles se sont produites. Par exemple :
  • Pendant combien de temps le GPU a-t-il été occupé au cours d’une image?
  • Quand l’image a-t-elle commencé?
  • Quand l’événement ORIGIN a-t-il eu lieu?
  • Quand l’image a-t-elle été présentée?
  • Quand l’appel Present a-t-il atteint le GPU?
Un titre peut régler lui-même certains de ces problèmes au moyen de requêtes. Cependant, il serait préférable que le pilote fournisse tous ces renseignements à un seul endroit.

Solution : Moyen pour un titre de récupérer des données de minutage détaillées

Figure 15. Moyen pour un titre de récupérer des données de minutage détaillées. Moyen pour un titre de récupérer des données de minutage détaillées La figure 15 montre que la nouvelle API récupère des données de minutage détaillées au moyen de GetFrameStatisticsX. Elle fournit de nombreuses statistiques. Elle est également extensible de la même façon que les autres API. De nouveaux types de statistiques peuvent être ajoutés sans modifier la signature de l’API.

Utilisation recommandée des API de cadencement des images

Cette section vous montre comment moduler la latence : découvrir la latence que vous avez, décider de ce qu’elle devrait être, puis la modifier au moyen des API de cadencement des images.

Moduler la latence

Figure 16. Moduler la latence : trois étapes faciles. Moduler la latence : trois étapes faciles La figure 16 montre les trois étapes recommandées pour moduler la latence.
  1. Utiliser les statistiques d’image pour mesurer la latence idéale de votre titre.
  2. Ajouter une marge pour la variabilité.
  3. Calculer vos paramètres.
À la première étape, deux statistiques sont importantes : le SignalTime de l’événement ORIGIN, qui signale le début de l’image, et GPUProcessTime, qui signale la fin de l’image lorsque `Present’ est appelé et atteint le GPU. La mémoire tampon d’image que vous voulez afficher est terminée, et la différence entre les deux statistiques correspond à la latence idéale de votre titre. À la deuxième étape, il est préférable d’avoir une marge lorsque la latence idéale n’est pas tout à fait exacte. Si votre estimation de la marge est trop basse et que votre latence suivante est plus élevée, vous perdrez des images. Si votre estimation est trop élevée, votre latence sera plus élevée que nécessaire. La troisième étape consiste à utiliser tous ces renseignements pour calculer les deux paramètres, PeriodInIntervals et IntervalOffsetInMicroseconds. Ils doivent être fournis au pilote. Ces changements sont pipelinés; ils prennent donc effet en quelques images. Vous pourriez vouloir que votre titre réagisse immédiatement aux hausses de latence, mais lentement aux baisses de latence.

Exemple de modulation de la latence

Figure 17. Exemple de modulation de la latence. Exemple de modulation de la latence La figure 17 montre un exemple de modulation de la latence. Cet exemple suppose un titre à 60 Hz avec un intervalle d’image de 16,7 ms. La latence mesurée est de 30 ms, selon la différence entre SignalTime et GPUProcessTime. Par exemple, vous décidez que la marge de sécurité est d’une demi-image, soit 8,3 ms. Cela donne une latence totale demandée de 38,3 ms. Pour calculer les deux paramètres, PeriodInIntervals et IntervalOffsetInMicroseconds, examinez le graphique de la figure 17. Du côté droit du graphique se trouve le Vblank cible. C’est le moment où l’image doit être prête pour Present. En reculant de la marge de sécurité de 8,3 ms, on arrive au moment où l’image devrait se terminer. À partir de là, reculez de la latence mesurée de 30 ms. C’est votre point ORIGIN. La figure 17 calcule PeriodInIntervals, la période de l’image en intervalles, en divisant 38,3 ms (38300) par l’intervalle d’image de 16,7 ms (16667). Le résultat est arrondi à trois intervalles. IntervalOffsetInMicroseconds indique à quel point dans ce premier intervalle l’image commencera. Le calcul de la figure 17 vous indique qu’il s’agit de 11,7 ms. Au total, cela signifie que le Vblank cible est le troisième Vblank après le point ORIGIN. Il se situe au milieu d’un intervalle d’image (11,7 ms). Ce processus n’est pas si compliqué, mais il pourrait l’être. Il le sera probablement dans les titres où d’autres choses se font en même temps. Si votre titre utilise une résolution dynamique, vous devez en tenir compte dans le résultat. Si votre latence est très élevée, vous pourriez y remédier en réduisant la résolution. Certains titres modulent dynamiquement leur fréquence d’images, ce qui signifie qu’ils sont parfois des titres à 60 hertz et parfois des titres à 120 hertz. D’autres titres utilisent ImmediateThreshold pour permettre le déchirement lorsqu’ils dépassent leur budget d’image. Vous pouvez créer un algorithme très compliqué pour prévoir toutes vos éventualités.

Utilisation non recommandée des API de cadencement des images

Cette section couvre les utilisations des API de cadencement des images que nous ne recommandons pas.

La mémoire tampon d’arrière-plan n’est pas présentée dans le délai convenu

Les questions abordées jusqu’ici dans cette rubrique s’apparentent à un contrat. Vous convenez qu’une image sera terminée dans un certain délai. Si vous ne terminez pas une image dans le délai convenu, des problèmes comme des pertes d’images peuvent survenir. Auparavant, vous ne perdiez des images que si votre processeur ou votre GPU dépassait son budget. Maintenant, vous pouvez faire une prédiction de latence, ne pas la respecter et perdre des images même si votre processeur et votre GPU respectent votre budget de temps.

Le titre utilise une chaîne d’échange trop courte

Lorsqu’un titre utilise une chaîne d’échange trop courte, des problèmes, comme des blocages, peuvent survenir. La taille idéale de la chaîne d’échange est PeriodInIntervals plus un. Par exemple, si vous utilisez PeriodInIntervals égal à deux et que IntervalOffsetInMicroseconds est zéro, vous avez besoin d’une chaîne d’échange de taille trois. En effet, une image est affichée, une autre image se trouve dans le deuxième intervalle de son calcul et une troisième image se trouve dans le premier intervalle de son calcul. Cela fait trois images, toutes en même temps. Techniquement, elles doivent avoir des mémoires tampons de chaîne d’échange différentes; sinon, elles pourraient entrer en collision. Dans certains cas, une chaîne d’échange courte n’entraîne aucune pénalité. Rien ne se passe. Cependant, dans d’autres cas, le processeur se bloque dans PresentX ou le GPU se bloque dans ResourceBarrier. Parfois, vous obtenez des blocages qui n’affectent pas votre fréquence d’images. D’autres fois, les blocages affectent votre fréquence d’images. Vous pouvez créer des exemples de chacun de ces scénarios. Celui que vous choisissez dépend du fonctionnement de votre titre.

Le titre définit PeriodInIntervals et IntervalOffsetInMicroseconds une seule fois au démarrage

Des problèmes peuvent survenir si votre titre définit les nouveaux paramètres, PeriodInIntervals et IntervalOffsetInMicroseconds, au démarrage et n’en fait rien d’autre par la suite. Cela ressemble à l’ancienne façon de faire, où vous définissiez une latence cible à l’avance et conserviez les mêmes choix, peu importe ce qui se passait pendant le jeu. Des pénalités peuvent survenir si vous êtes trop agressif ou trop prudent dans votre choix de latence. Trop agressif, et vous perdez des images sans raison, même lorsque vous respectez votre budget. Trop prudent, et votre latence est toujours plus élevée que nécessaire.

Le titre commence à calculer une image avant que l’événement ORIGIN soit signalé

Ce problème survient lorsque vous planifiez votre événement ORIGIN et l’attendez, mais que le titre commence ses calculs d’image. Dans ce cas, les calculs n’ont pas commencé au moment prévu, de sorte que votre latence fluctue dans un sens et dans l’autre et devient indéterminée. Il en résulte une absence de synchronisation de l’entrée de la manette et aucune possibilité de suivi des images dans PIX.
Parmi les problèmes présentés dans cette rubrique, c’est le plus important. On ignore pourquoi cela ne fonctionne que parfois, lorsque vous planifiez votre événement ORIGIN, puis l’attendez.

Démos

Cadencement des images dans PIX System Monitor

Figure 19. Cadencement des images dans PIX System Monitor. Cadencement des images dans PIX System Monitor La figure 19 met en évidence la section D3D (Direct3D) de PIX System Monitor. La section D3D suit les événements importants pour le calcul de la latence d’image de bout en bout. La démo décrit les éléments suivants.
  • Frames per Second : Aucune explication nécessaire.
  • Total Frame Latency : Temps écoulé entre l’événement ORIGIN et le moment où l’image a été basculée et est devenue la mémoire tampon avant.
  • Frame Origin : Combien de temps après le Vblank l’événement ORIGIN s’est-il produit (IntervalOffsetInMicroseconds)?
  • Present to Flip : Combien de temps à l’avance l’image était-elle prête (PresentX a atteint le GPU) avant d’être basculée?
  • Wait for Signal : Pendant combien de temps WaitFrameEventX(ORIGIN) a-t-il bloqué?

Exemple Frame Pacing

Figure 20. Interface utilisateur de l’exemple Frame Pacing. Exemple Frame Pacing La figure 20 montre l’interface utilisateur de l’exemple Frame Pacing. L’exemple n’a pas été publié. Il crée artificiellement des durées d’image sur le processeur et le GPU, puis affiche les résultats dans l’interface utilisateur. L’interface utilisateur est divisée en plusieurs parties.
  • Menu :
    • Situé dans le coin supérieur droit.
    • Divisé en deux sections :
      • Paramètres de charge d’image.
      • Paramètres de cadencement des images.
    • Les charges d’image sont imposées par des minuteries.
  • Graphiques :
    • Trois graphiques linéaires situés dans le coin supérieur gauche.
      • Durée/fréquence d’image.
      • Latence idéale.
      • Marge de latence (marge de sécurité).
    • Une marge négative indique une image en retard.
  • Chronologie :
    • Ressemble à une capture de minutage PIX simplifiée.
    • Affiche les renseignements suivants.
      • Mise à jour du processeur.
      • Rendu du processeur.
      • File d’attente graphique du GPU.
      • File d’attente de calcul du GPU.
      • Flip.
    • Flip vous indique quelle mémoire tampon de chaîne d’échange est affichée.
    • Le graphique de chronologie utilise un code de couleur selon la mémoire tampon de chaîne d’échange.
    • L’exemple de la figure 20 comporte trois mémoires tampons de chaîne d’échange représentées par des couleurs : violet, vert et jaune.

Fraction d’image de latence

L’ancienne API ne permettait pas une fraction d’image de latence. Cependant, la nouvelle API le permet, ce qui permet au titre de spécifier des décalages fractionnaires en microsecondes. Figure 21. Fraction d’image de latence 1/2. Fraction d'image de latence 1 de 2 La figure 21 montre l’exemple sans fraction d’image de latence. Remarquez que Frame Offset (ms) est à zéro. La mise à jour du processeur (événement ORIGIN) se produit au Vblank. Cela signifie que la latence est un nombre entier d’images. Figure 22. Fraction d’image de latence 2/2. Fraction d'image de latence 2 de 2 La figure 22 montre l’exemple où Frame Offset (ms) est réglé à trois. Ce décalage est le plus élevé qui puisse être défini sans perdre d’images. Il laisse une marge de latence presque nulle, ce qui est dangereusement bas. Remarquez que les événements ORIGIN, où commencent les mises à jour du processeur, ne sont plus synchronisés avec les Vblank où se termine le Flip.

Latence découplée de la taille de la chaîne d’échange

Figure 23. Latence découplée de la taille de la chaîne d’échange 1/2. Avec la nouvelle API, la latence ne dépend plus de la longueur de la chaîne d’échange. Cette démo montre ce qui se passe lorsque :
  • La taille de la chaîne d’échange est celle que nous recommandons.
  • La taille de la chaîne d’échange est inférieure à celle que nous recommandons.
Latence découplée de la taille de la chaîne d'échange 1 de 2 La figure 23 montre l’exemple où Frame Period est réglé à deux. Cela nécessite habituellement trois mémoires tampons d’image. Remarquez qu’il y a trois couleurs dans les barres de minutage en bas : violet, vert et jaune. Chaque couleur représente une mémoire tampon de chaîne d’échange. Figure 24. Latence découplée de la taille de la chaîne d’échange 2/2. Latence découplée de la taille de la chaîne d'échange 2 de 2 La figure 24 montre l’exemple où le nombre de mémoires tampons d’image a été changé à deux. Remarquez qu’il y a maintenant deux couleurs dans les barres de minutage en bas : vert et jaune. Remarquez également que cela ressemble à la figure 23. À la figure 24, la latence idéale dans le graphique linéaire est de 30,2. La marge de latence est de 3,1. Si une autre mémoire tampon d’image est ajoutée (figure 23), il n’y a aucun changement. La latence d’image reste la même. La mémoire tampon d’image supplémentaire n’augmente pas la latence, bien qu’elle entraîne un coût supplémentaire en mémoire. Cette démo montre également que la fréquence d’images n’a pas changé, même si le Flip vert de l’image N chevauche les barres vertes de l’image N+2. La fréquence d’images est demeurée stable à 59,0 FPS. Des blocages peuvent tout de même survenir. Par exemple, des blocages peuvent survenir sur BlockOnFence_SwapThrottle sur le processeur si la mémoire tampon est encore affichée lorsqu’elle est passée à Present. Un blocage peut également survenir sur WaitOnSwapChainSurface sur le GPU si la mémoire tampon est encore affichée lorsqu’elle quitte l’état PRESENT pour passer à un état accessible en écriture. Plus vous pouvez reporter ces opérations, moins vous avez besoin de mise en mémoire tampon. Vous pouvez provoquer ces blocages dans l’exemple Frame Pacing en diminuant les durées de CPU Update et de CPU Render.

Modulation de la latence

Figure 25. Modulation de la latence 1/4. Modulation de la latence 1 de 4 La figure 25 montre l’exemple avec CPU Update augmenté à 14 ms. Remarquez que la marge de latence est négative. Le titre manque ses échéances d’image, et des images sont perdues. Selon la Frame load du menu, aucune des étapes de traitement ne coûte moins d’un intervalle d’image (16,7 ms). C’est ce qui se produit lorsque votre prédiction de latence est trop agressive. Figure 26. Modulation de la latence 2/4. Modulation de la latence 2 de 4 La figure 26 montre l’exemple avec le mode de cadencement automatique des images activé. Il a corrigé les images perdues en faisant passer Frame Period de deux à trois. Remarquez que Frame Offset est passé de 0,00 à 7,45 ms, et que Legacy margin affiche maintenant 8,3 ms. Figure 27. Modulation de la latence 3/4. Modulation de la latence 3 de 4 La figure 27 montre Auto Frame Load activé et un scénario où une image dépasse le budget chaque seconde. Ce problème ponctuel du GPU entraîne la perte de l’image suivante. Cela apparaît dans le graphique Frame time et dans les espaces de la chronologie. Il y a un problème ponctuel chaque seconde, car la marge de latence est trop basse. Figure 28. Modulation de la latence 4/4. Modulation de la latence 4 de 4 La figure 28 montre le même scénario avec le mode Auto Frame Pacing de nouveau activé. L’algorithme corrige ce problème en étant moins agressif dans ses prédictions de latence. La marge de latence passe à 8,3 ms et évite les pertes d’images. Le graphique de la marge de latence ne descendra pas sous 0.

Étapes suivantes

Si vous souhaitez consulter les renseignements des documents de présentation liés à cette vue d’ensemble, téléchargez les fichiers suivants à partir de XBOX Developer Download Secure Data Storage (SDS).
  • Diaporama : GR03_Understanding Frame Pacing and Latency with the GDKX Presentation APIs.pptx dans Xfest 2022 Graphics Track PowerPoints (Xfest2022GfxPPTs.ZIP)
  • Présentation vidéo : GR03.mp4 dans Xfest 2022 Graphics Track Videos (Xfest2022GfxVids.ZIP)

Télécharger les présentations Microsoft PowerPoint et les vidéos

  1. Accédez à Téléchargements du Game Development Kit (GDK).
  2. Sous Select file type, sélectionnez Conference Materials, puis sélectionnez Confirm.
  3. Sous Select build/version number, choisissez l’une des présentations graphiques suivantes.
    • Xfest 2022 Graphics Track PowerPoints
    • Xfest 2022 Graphics Track Videos
  4. Sélectionnez Download Now, puis attendez la fin du téléchargement du fichier .zip.
  5. Accédez à votre dossier Téléchargements local, puis décompressez (extrayez) les fichiers du dossier compressé.

Télécharger les exemples pour console du Microsoft Game Development Kit mentionnés dans cet article

  1. Accédez à Téléchargements du Game Development Kit (GDK).
  2. Sous Select file type, sélectionnez GDK, puis sélectionnez Confirm.
  3. Sous Select build/version number, choisissez l’option Microsoft GDKX (Sample only) la plus récente.
  4. Sélectionnez Download Now, puis attendez la fin du téléchargement du fichier .zip.
  5. Accédez à votre dossier Téléchargements local, puis décompressez (extrayez) les fichiers du dossier compressé.
  6. Sélectionnez GDKSamples > Graphics, puis recherchez l’exemple.

Voir aussi

Présentation de la diffusion en continu de jeux Vue d’ensemble de la compensation de la latence de la diffusion en continu de jeux Analyse approfondie de la compensation de la latence de la diffusion en continu de jeux
Last modified on October 6, 2026