Guide de programmation de la swapchain de composition
L’API de chaîne d’échange de composition est un successeur spirituel de la chaîne d’échange DXGI, qui permet aux applications de rendre et de présenter du contenu à l’écran. Il existe plusieurs avantages à utiliser cette API plutôt que la chaîne d’échange DXGI. Votre application bénéficie d’un contrôle plus précis sur l’état de la chaîne d’échange, ainsi que d’une plus grande liberté quant à la manière dont la chaîne d’échange est utilisée. De plus, l’API offre une meilleure gestion du timing précis de la présentation.
Qu’est-ce que la présentation ?
La présentation est le concept qui consiste à afficher les résultats des opérations de dessin à l’écran. Un présent est une instance unique de présentation, une requête pour montrer les résultats d’une opération de dessin sur un seul tampon à l’écran. Un présent peut contenir des attributs supplémentaires qui décrivent comment l’afficher à l’écran. Dans cette API, un présent peut également avoir un temps cible, qui est un horodatage relatif au système (un temps d’interruption) qui décrit le moment idéal où le présent doit être affiché. Votre application peut utiliser cela pour contrôler plus précisément le taux auquel le contenu apparaît à l’écran, et pour synchroniser les présents avec d’autres événements dans le système, tels qu’une piste audio.
Au cœur de la présentation se trouve la synchronisation. En d’autres termes, les opérations de dessin sont généralement effectuées par un GPU, plutôt que par le CPU, et, en tant que telles, elles s’exécutent sur une chronologie asynchrone par rapport à celle du CPU qui a initialement émis les opérations. La présentation est une opération soumise au GPU qui garantit que les opérations de dessin précédemment émises seront terminées avant que le tampon ne soit affiché à l’écran.
Votre application émettra généralement de nombreux présents au fil du temps, et disposera de plusieurs textures à sélectionner lors de l’émission de présents. Votre application doit utiliser les mécanismes de synchronisation que cette API fournit pour s’assurer qu’une fois que vous dessinez sur un tampon et le présentez, vous ne dessinez pas à nouveau sur ce tampon tant que ce présent n’a pas été affiché et ensuite remplacé par un nouveau tampon provenant d’un présent ultérieur. Sinon, le contenu du tampon que votre application souhaitait initialement présenter peut être écrasé au moment où ce présent est affiché à l’écran.
Modes de présentation : composition, superposition multi-plans et basculement indépendant
Les tampons présentés par votre application peuvent être affichés par le système de plusieurs manières différentes.
La manière la plus simple, qui est celle par défaut, consiste à envoyer le présent au DWM, et le DWM rendra une image basée sur le tampon qui a été présenté. C’est-à-dire qu’il y a une copie (ou plus précisément, un rendu 3D) du tampon de présentation dans le tampon arrière que le DWM envoie à l’affichage. Cette méthode d’affichage d’un présent est appelée Composition.
Un mode plus performant d’affichage d’un présent serait de scanner directement le tampon de présentation vers le matériel, et d’éliminer la copie qui a lieu. Cette méthode d’affichage d’un présent est appelée scanout direct. Lors de la gestion des présents, le DWM peut décider de programmer le matériel pour scanner directement un tampon de présentation, en assignant soit le tampon à un plan de superposition multi-plans (ou plan MPO, en abrégé), soit en basculant directement le tampon vers le matériel (connu sous le nom de basculement direct).
Une méthode encore plus performante pour afficher un présent serait que les présents soient affichés directement par le noyau graphique, en contournant complètement le DWM. Cette méthode de présentation est connue sous le nom de basculement indépendant (iflip). La superposition multi-plans et iflip sont décrits dans Pour des performances optimales, utilisez le modèle de basculement DXGI.
La composition est la méthode la plus facilement prise en charge, mais aussi la moins efficace. La surface doit être spécialement allouée pour être éligible au scanout direct ou à iflip, et ce type d’allocation spéciale a des exigences système plus strictes que la chaîne d’échange de composition. Il n’est disponible que sur le matériel WDDM 3.0 et supérieur. En conséquence, votre application peut interroger la prise en charge de l’API pour la présentation uniquement par composition, ainsi que pour la présentation qui se qualifie pour le scanout direct ou iflip.
Remarque
Pour que vos surfaces puissent bénéficier automatiquement de ces modes de présentation plus optimisés, les surfaces doivent être allouées comme étant directement affichables par le GPU. Pour les surfaces Direct3D 11, vous devez allouer vos surfaces comme affichables. Les surfaces qui ne sont pas allouées comme affichables peuvent toujours être composées par le compositeur système à l’écran, mais ne bénéficieront jamais des avantages du mode de basculement indépendant.
Fabrique de présentation, vérification des capacités et gestionnaire de présentation
Le premier objet que votre application utilisera dans l’API de chaîne d’échange de composition est la fabrique de présentation. La fabrique de présentation est créée par votre application et liée à un périphérique Direct3D que votre application transmet à l’appel de création, et, en tant que telle, elle est associée à l’adaptateur vidéo associé à ce périphérique.
La fabrique de présentation expose des méthodes permettant de vérifier si le système actuel et le périphérique graphique sont capables d’utiliser l’API de chaîne d’échange de composition. Vous pouvez utiliser des méthodes de vérification des capacités telles que IPresentationFactory::IsPresentationSupported pour vérifier la prise en charge du système. Si les méthodes de vérification des capacités indiquent que le système prend en charge l’API, vous pouvez alors utiliser la fabrique de présentation pour créer un gestionnaire de présentation. Ce gestionnaire de présentation est l’objet que vous utilisez pour exécuter des fonctions de présentation, et il est lié au même périphérique Direct3D et à l’adaptateur vidéo que la fabrique de présentation utilisée pour le créer.
Actuellement, les exigences système pour utiliser l’API de chaîne d’échange de composition sont les pilotes GPU prenant en charge WDDM (Windows Device Driver Model) 2.0 et Windows 11 (Build 10.0.22000.194) ou une version supérieure. Pour utiliser l’API de chaîne d’échange de composition de manière la plus performante (scanout direct et basculement indépendant, ou iflip), les systèmes devront disposer de pilotes GPU prenant en charge WDDM 3.0.
Si le système n’est pas capable d’utiliser l’API de chaîne d’échange de composition, votre application devra disposer d’un chemin de code distinct pour gérer la présentation en utilisant des méthodes plus anciennes, telles qu’une chaîne d’échange DXGI.
Enregistrement des tampons de présentation pour la présentation
Le gestionnaire de présentation suit les tampons qu’il peut présenter. Pour présenter une texture Direct3D, votre application doit d’abord créer cette texture avec Direct3D, puis l’enregistrer auprès du gestionnaire de présentation. Lorsqu’une texture est enregistrée auprès du gestionnaire de présentation, elle est appelée un tampon de présentation et peut, à partir de ce moment-là, être présentée à l’écran par ce gestionnaire de présentation. Votre application peut ajouter et supprimer des tampons de présentation à sa guise, bien qu’il y ait un nombre maximum de tampons de présentation pouvant être ajoutés à un seul gestionnaire de présentation (actuellement 31). Ces tampons de présentation peuvent également être de tailles et de formats variés, qui seront appliqués au moment où un tampon de présentation individuel est présenté.
Une texture peut être enregistrée auprès de plusieurs gestionnaires de présentation ; cependant, cela ne serait pas considéré comme une utilisation normale dans la plupart des cas, et cela entraînerait des scénarios de synchronisation complexes que votre application serait responsable de gérer.
Définir le contenu à présenter
En général, les tampons que nous présentons doivent être associés à un contenu dans un arbre visuel. Par conséquent, nous devons définir une sorte de liaison afin que, lorsque votre application émet des présents, il soit clair où, dans l’arbre visuel, les tampons présentés sont censés être placés. Nous appelons cette liaison contenu de présentation.
Le contenu présenté peut prendre de nombreuses formes. Votre application pourrait souhaiter présenter un seul tampon à afficher, ou elle pourrait vouloir présenter du contenu stéréo avec des tampons pour les yeux gauche et droit, et ainsi de suite. La version initiale de cette API prend en charge la présentation d’un seul tampon à l’écran.
Nous définissons une surface de présentation comme une forme de contenu de présentation à laquelle un seul tampon est présenté à la fois. Une surface de présentation peut être définie comme contenu dans un arbre visuel et peut afficher un seul tampon de présentation à la fois à l’écran. Les présents du gestionnaire de présentation mettront à jour le tampon affiché par une ou plusieurs surfaces de présentation de manière atomique.
Le gestionnaire de présentation peut être utilisé pour créer une ou plusieurs surfaces de présentation pour un handle de surface de composition donné. Chaque handle de surface de composition peut être lié à un ou plusieurs éléments visuels dans un arbre visuel (selon des stratégies décrites dans la documentation des API Windows.UI.Composition et DirectComposition) pour définir la relation entre la surface de présentation associée et l’endroit où elle apparaît dans son arbre visuel. Votre application peut mettre à jour une ou plusieurs surfaces de présentation, qui sont soumises au système et prennent effet lors de la prochaine opération de présentation.
Notez que le gestionnaire de présentation peut présenter n’importe quel tampon de présentation à un nombre quelconque de surfaces de présentation. Il n’y a pas de restrictions. Cependant, c’est à votre application de garder une trace des tampons que vous avez émis et de leur emplacement, afin de s’assurer que vous n’essayez pas d’émettre de nouvelles opérations de dessin sur ce tampon alors qu’il est encore affiché par une surface de présentation.
Application des propriétés à la surface de présentation
En plus de spécifier les tampons à afficher dans une surface de présentation, un présent peut également spécifier diverses autres propriétés à cette surface de présentation. Cela inclut des propriétés qui définissent comment la texture source sera échantillonnée, y compris le mode alpha et l’espace colorimétrique, comment la texture source sera transformée et disposée, ainsi que toute restriction d’affichage ou de lecture pour le contenu protégé. Tous ces éléments sont exposés sous forme de méthodes de définition de propriétés sur une surface de présentation, qui peuvent être modifiées par votre application et, tout comme les mises à jour des tampons, prendront effet lorsque la présentation de votre application aura lieu.
Présentation à la surface de présentation
Après que votre application a créé des surfaces de présentation, enregistré des tampons de présentation et spécifié des mises à jour à émettre lors d’un présent, vous pouvez appliquer ces propriétés en présentant. Votre application émet un présent via le gestionnaire de présentation. Lorsque ce présent est traité par le système, toutes les mises à jour sont appliquées de manière atomique. De plus, votre application peut également spécifier d’autres propriétés du présent, telles que le moment idéal auquel il devrait avoir lieu (le temps cible du présent) et d’autres propriétés plus rares, telles que le taux de contenu prévu, qui peuvent être utilisées pour activer des modes de rafraîchissement personnalisés sur le système. Étant donné que les présents peuvent être programmés à un moment donné, votre application peut émettre plusieurs présents à l’avance. Ces présents seront traités un par un à mesure que leur heure programmée est atteinte.
Synchronisation de la présentation
Votre application doit s’assurer que lorsqu’elle effectue des rendus sur des tampons et émet des présents, elle sélectionne un tampon sur lequel rendre qui n’est pas actuellement référencé par un autre présent précédent en attente, car cela pourrait écraser le contenu du tampon destiné à ces présents. De plus, si votre application effectue un rendu sur un tampon actuellement affiché par une surface de présentation dans le matériel de scanout, alors son rendu peut être bloqué indéfiniment, car Direct3D interdit le rendu sur le tampon avant.
L’API de chaîne d’échange de composition fournit plusieurs mécanismes permettant à votre application de pratiquer une synchronisation correcte des tampons qu’elle a présentés.
Un tampon est dit disponible s’il n’est référencé par aucun présent en attente, et qu’il n’est pas actuellement affiché par le système. Sinon, il est indisponible. L’API fournit un événement pour chaque tampon de présentation qui indique si le tampon est disponible ou non. C’est la méthode de synchronisation la plus simple à utiliser pour votre application. Avant de dessiner sur un tampon et de le présenter, votre application peut s’assurer que son événement disponible est déclenché. L’événement disponible pour un tampon particulier devient non déclenché dès qu’il a été lié à une surface de présentation dans l’API, et reste non déclenché jusqu’à ce que le présent soit retiré.
Deuxièmement, le gestionnaire de présentation suit une seule barrière de retrait de présent pour communiquer à votre application quels présents ont été complétés. La valeur de la barrière correspond à l’identifiant du dernier présent qui a commencé la phase de retrait de son cycle de vie, comme discuté dans la section cycle de vie ci-dessous. Une fois qu’un présent entre dans cette phase, il est sûr de supposer que tous les tampons qui ont été remplacés par des présents ultérieurs peuvent être réutilisés.
Cette méthode de synchronisation est plus avancée, mais permet un plus grand contrôle sur la limitation du flux de travail et donne plus d’informations sur l’état du système en ce qui concerne la profondeur de la file d’attente actuelle des présents. Pour un aperçu du cycle de vie d’un présent, consultez la section ci-dessous.
Cycle de vie d’un présent
Les présents du gestionnaire de présentation sont mis en file d’attente dans le système dans le cadre de sa file d’attente de présents. Le système traite les présents dans l’ordre de leur mise en file d’attente. De plus, chaque présent a un identifiant de présent unique (pour le gestionnaire de présentation), qui est une valeur incrémentale attribuée à un présent, commençant à 1 pour le premier présent, et augmentant de 1 pour chaque présent suivant. Cet identifiant de présent est utilisé dans diverses parties de l’API, telles que les primitives de synchronisation et les statistiques de présentation, pour se référer à ce présent particulier.
Chaque présent que votre application émet suit un cycle de vie spécifique, tel que décrit ici.
Une fois que votre application a configuré les modifications à apporter dans le cadre d’un présent, elle utilisera le gestionnaire de présentation pour émettre réellement le présent. À ce stade, le présent est dit en attente.
Une fois en attente, un présent restera dans la file d’attente des présents du gestionnaire de présentation, où il restera jusqu’à ce que l’un des deux événements suivants se produise.
- Le présent devient annulé. Le gestionnaire de présentation permet à votre application d’annuler les présents précédemment émis. Si cela se produit, alors le présent est dit annulé, puis il devient immédiatement mis hors service. Lors de cette transition, les événements disponible associés aux tampons pour le présent annulé seront mis à jour, cependant, la barrière de retrait de présent ne sera pas déclenchée, car le présent précédemment affiché (avant les présents qui ont été annulés) restera affiché. Pour cette raison, votre application ne peut pas utiliser la barrière de retrait de présent pour déterminer quels présents ont été annulés. Vous devez plutôt l’apprendre à partir des statistiques de statut de présent qui reviennent pour chaque présent annulé. Nous suggérons que votre application utilise les événements disponible du tampon pour trouver un tampon disponible à présenter après une annulation. Une fois que ce présent est affiché, le présent précédent commencera le processus de retrait et mettra à jour la barrière de retrait de présent.
- S’il n’est pas annulé, le présent devient finalement prêt à être traité. Pour être prêt, deux conditions majeures doivent être remplies.
- Tout le travail de dessin émis au contexte Direct3D avant l’appel du présent doit être terminé. Cela garantit que le tampon n’est pas affiché avant que le dessin de votre application ne soit terminé.
- Si un temps cible de présent a été spécifié, alors le temps actuel relatif au système auquel nous nous attendons à pouvoir afficher le présent doit correspondre au temps cible demandé que votre application a appliqué au présent.
Lorsque le système décide de trouver un présent à afficher à l’écran, il choisira le dernier présent qui est devenu prêt à être affiché. S’il y a plusieurs présents prêts, tous sauf le dernier (c’est-à-dire, le présent avec le plus grand identifiant de présent) seront ignorés et entreront immédiatement dans l’état hors service, auquel point leurs événements disponible du tampon seront déclenchés, mais la barrière de retrait de présent ne sera pas déclenchée, car le présent ignoré ne passe pas de l’état affiché.
Lorsque le présent prêt est choisi pour être affiché, le système commence à faire le travail pour l’afficher à l’écran. Cela peut signifier rendre le tampon dans le cadre d’une image DWM, puis demander au matériel d’afficher cette image à l’écran, ou cela peut signifier envoyer le tampon directement au matériel de scanout dans le cas de iflip. Une fois que cela a eu lieu, le présent est dit en file d’attente. En termes généraux, cela signifie qu’il est en cours d’affichage.
Lorsque le matériel s’occupe d’afficher le présent, ce présent est dit affiché. Il y restera, visible à l’écran, jusqu’à ce qu’un présent ultérieur arrive et le remplace.
Lorsqu’un présent ultérieur devient en file d’attente, alors nous savons que le matériel finira par cesser d’afficher le présent actuel. À ce stade, le présent est dit en cours de retrait.
Lorsque ce présent ultérieur devient affiché, alors le présent actuel est dit mis hors service.
Le gestionnaire de présentation expose une barrière de retrait de présent, qui est déclenchée pour l’identifiant de chaque présent lorsqu’il entre dans l’état mis hors service. Ce signal indique à votre application qu’il est devenu sûr d’émettre des travaux de rendu sur les tampons associés à ce présent sans corrompre un présent précédent. Si votre application émet des travaux de rendu pendant l’état de mis hors service du présent, alors ces travaux de rendu seront mis en file d’attente jusqu’à ce que le présent entre dans l’état mis hors service, auquel moment ils seront exécutés. Si les travaux de rendu sont émis après que le présent soit devenu mis hors service, alors ils seront exécutés immédiatement.
Voici un diagramme de ce changement d’état.
Diagramme des tampons, des surfaces et des présents
Voici un diagramme mettant en relation le gestionnaire de présentation, les tampons de présentation, les surfaces de présentation, les présents et les mises à jour.
Ce diagramme montre un gestionnaire de présentation, avec deux surfaces de présentation et trois tampons de présentation, qui ont eu deux présents émis jusqu’à présent—le premier présent a affiché le tampon 1 sur la surface 1, et le tampon 2 sur la surface 2. Le second présent a mis à jour la surface 2 pour afficher le tampon de présentation 3, et n’a pas changé la liaison de la surface 1. Après que le présent 2 soit affiché, la surface 1 affichera le tampon 1, et la surface 2 affichera le tampon 3, ce qui peut être vu dans l’état actuel des objets dans le gestionnaire de présentation. Chaque présent dans la file d’attente prendra effet lorsqu’il sera traité dans le système.
Remarque
Comme le présent 2 n’a pas changé le tampon pour la surface 1, la surface 1 est restée liée au tampon 1 du présent précédent. Dans ce sens, il y a une référence "implicite" au tampon 1 dans le présent 2, puisque la surface 1 restera liée au tampon 1 après l’affichage du présent 2.
Ajout de surfaces de présentation à l’arbre visuel
Les surfaces de présentation sont des contenus qui existent dans le cadre d’un arbre visuel de composition. Chaque surface de présentation est liée à un handle de surface de composition. Dans Windows.UI.Composition, un pinceau de surface peut être créé pour un handle de surface de composition préexistant et lié à un sprite visuel. Dans DirectComposition, une surface de composition peut être créée à partir d’un handle de surface de composition préexistant et liée en tant que contenu à un visuel. Veuillez consulter la documentation respective de chaque API pour plus d’informations.
Les API comme Windows Media Foundation, conçues pour utiliser cette API, exposent des handles de surface de composition qui seront pré-liés à une surface de présentation. Une application peut également créer son propre handle de surface de composition pour le lier par la suite à une surface de présentation et l’ajouter à un arbre visuel en appelant DCompositionCreateSurfaceHandle.
Lecture des statistiques de présentation
L’API de chaîne d’échange de composition expose les statistiques de présentation, qui décrivent diverses informations sur la manière dont un présent particulier a été traité. Les informations peuvent généralement décrire comment une surface de présentation a été utilisée dans une image DWM, le moment où elle est apparue, si elle a été affichée ou non, et ainsi de suite.
Il existe différents types de statistiques de présentation, et ils sont conçus pour être extensibles dans les futures versions de l’API. Une application utilise le gestionnaire de présentation pour s’inscrire afin de recevoir les types de statistiques qui l’intéressent. Ces statistiques sont ensuite transmises à la file d’attente des statistiques du gestionnaire de présentation. Le gestionnaire de présentation expose un événement de disponibilité des statistiques aux applications, qui est un handle d’événement indiquant quand la file d’attente des statistiques a des éléments de statistiques disponibles à lire. Lorsque c’est le cas, votre application peut extraire le premier élément de statistiques de la file d’attente, le lire et le traiter. Le gestionnaire de présentation réinitialisera l’événement de disponibilité des statistiques lorsque votre application aura lu toutes les statistiques actuellement dans la file d’attente. Une application lira et traitera généralement les statistiques dans une boucle jusqu’à ce que l’événement de disponibilité des statistiques soit réinitialisé. Il sera courant pour votre application de traiter cette file d’attente de statistiques dans la même boucle de travail que celle que vous utilisez pour émettre des présents. Le modèle d’utilisation suggéré est de donner la priorité au traitement des statistiques par rapport à l’émission de nouveaux présents, afin de s’assurer que la file d’attente ne déborde pas.
La file d’attente a un nombre maximum de statistiques qu’elle suivra, qui sera de l’ordre de 512-1024 statistiques. La profondeur maximale de la file d’attente devrait être suffisante pour stocker environ 5 secondes de statistiques dans des cas normaux. Si la file d’attente des statistiques devient pleine et que d’autres statistiques sont signalées, la politique est que les statistiques les plus anciennes seront retirées pour faire de la place.