Les solutions de streaming : Streaming local Steam et Nvidia GameStream en test

Publié le 26/07/2016 par
Imprimer

DXGI, Swap chain

Notre schéma page précédente reste simpliste, en pratique l'image rendue n'est pas affichée aussitôt à l'écran. Sous Windows, cette gestion des buffers est assez particulière, et s'est complexifiée ces dernières années. Pour l'exemple toujours, nous prenons le cas d'une application qui tourne en plein écran avec la synchronisation verticale activée.

Windows dispose depuis Vista d'une API baptisée DXGI  qui regroupe les tâches de bas niveau. Parmi celles-ci on retrouve le rôle essentiel de la swap chain.

L'image qui vient d'être rendue par le GPU n'est en effet pas directement affichée à l'écran. Etant donné qu'on ne peut jamais prédire réellement quand la prochaine image sera prête, il est nécessaire d'avoir un mécanisme qui permet d'avoir toujours quelque chose à afficher. Résultat, l'image qui est actuellement affichée à l'écran est stockée dans un buffer (appelé front buffer) dont le contenu n'est pas modifiable.

L'idée de la swap chain est assez simple, DXGI gère en pratique pour le jeu une "file" de buffers. A l'image d'une file d'attente, les images rendues par le GPU prennent place dans la file au fur et a mesure qu'elles sont calculées, celle qui est en tête de la file étant affichée quand vient son tour (le haut de la file est considéré comme le front buffer, les suivantes des back buffers). Le nom de swap chain (également appellée flip queue) vient du fait qu'en pratique l'ordre des buffers est changé de manière virtuelle : dans le cas de trois buffers A, B et C, le front buffer se "déplace" d'un cran à chaque fois comme vous pouvez le voir sur ce diagramme de Microsoft.


La position des buffers en mémoire sur la carte graphique ne change pas, chaque flip déplace les pointeurs

En pratique, il y a beaucoup d'avantages a avoir une file d'images prêtes à être affichées. Plus le nombre de buffers est élevé et mieux on peut parer à des ralentissement et éviter les saccades. L'inconvénient est qu'augmenter la taille de la file rajoute de la latence.

Qu'est ce que cela donne en pratique ? Voici notre diagramme (à peu près) complet, avec une swap chain de 4 images :

Nous vous montrons toujours le parcours de trois images. Ici les images sont rendues dans le dernier back buffer, en bas de la file, puis remontent la file au fur et a mesure pour arriver jusqu'au front buffer, puis d'être enfin visibles à l'écran (cf page précédente).

Vous pouvez voir qu'en pratique la latence peut paraître élevée, quasi 100 millisecondes entre le moment ou l'on appuie sur notre pad et le moment ou l'image est visible à l'écran pour cet exemple.

Le nombre de buffers joue un rôle primordial sur la latence, mais il n'y a pas de constante d'un jeu a l'autre. En effet, chaque jeu peut choisir la longueur de sa swap chain lorsqu'il démarre et selon les techniques de rendu utilisées, certains peuvent avoir besoin de chaînes plus longues que d'autres. En général on dispose toujours au minimum de 2 ou 3 buffers sous DirectX

Certains jeux permettent parfois de réduire le nombre d'images précalculées, c'est le cas de Project Cars par exemple qui dispose d'un réglage dans ses options. Les drivers peuvent aussi interférer sur le réglage, directement chez Nvidia, et via un utilitaire tiers chez AMD.

Cependant, réduire au minimum le nombre de back buffers est en pratique une fausse bonne idée. Si vous réduisez la latence théorique, en pratique tout ira bien si votre carte graphique et votre processeur sont toujours capables de fournir des images toutes les 16.6 ms. S'il y a un ralentissement quelconque, vous augmentez dramatiquement le risque que la file soit vide, et donc que la carte graphique soit obligée de renvoyer à l'écran la même image qu'au cycle précédent. Et comme le rendu du moteur CPU reste, V-Sync oblige, reste cadencée a l'écran, l'impression de saccade est très perceptible.

Et sans V-Sync ?

Si l'on désactive la synchronisation verticale, les choses se compliquent un peu. Sur le fond l'idée est simple, le moteur n'est plus synchronisé avec le taux de rafraîchissement de l'écran, il peut donc tenter de calculer un maximum d'images. Pour l'exemple nous avons pris un cas ou le CPU n'est pas limitant, et le GPU est capable de calculer 120 images par secondes :

A chaque image rendue, l'image est ajoutée à notre file, faisant remonter les autres à l'exception du front buffer qui reste lui toujours synchronisé à l'écran. Dans notre cas, seule une image sur deux calculée est affichée, notre écran reste toujours limité a 60 images par secondes.

Est ce mieux qu'avant ? Sur la latence, on peut voir qu'en moyenne elle va être plus basse, même si l'on peut se retrouver avec une variance un peu plus grande qu'auparavant entre le moment ou l'on appuie sur le bouton et le moment ou l'image est visible. Si l'on extrapole, on peut voir que plus les rendus CPU et GPU seront rapides, et plus la latence sera réduite.

Bien évidemment, calculer des images qui ne seront pas affichées ne sert à rien et fait augmenter la consommation et les nuisances sonores de sa machine.

Les choses deviennent beaucoup plus problématiques lorsque l'on considère le fait qu'en pratique, et contrairement à nos exemples, le temps de calcul n'est pas constant d'une image à l'autre. Dans notre exemple du jeu de voiture, un grand nombre de véhicules a l'écran fera baisser les performances. Ces variations peuvent faire que l'on se retrouve dans un cas ou notre file est vide ou quasiment. Plus la file est courte, et plus ce risque est important.

Les opérations de copies dans les buffers n'étant pas immédiates, on peut se retrouver avec un cas ou le GPU était entrain de copier une image dans le premier back buffer (en première position dans la file) au moment même ou l'écran réclame sa nouvelle image. Résultat ? Sous Windows en plein écran, on se retrouve avec cela :

On retrouve en bas de l'écran un bout de la nouvelle image, et en haut les restes de l'ancienne image (avec un bout d'une autre image encore plus ancienne !). Un effet de déchirement appelé tearing en anglais.

Windows et le tearing

Si la cause du tearing est connue, elle intervient avant tout parce que les API de Microsoft font le choix explicite d'afficher des images qui ne sont pas complètes, plutôt que d'attendre une nouvelle image complète a afficher. Ce choix historique de Microsoft est encore présent aujourd'hui dans les jeux lorsque l'on est en mode plein écran.

Le mode plein écran est lui même quelque chose d'ancien. Historiquement, les jeux prenaient complètement la main sur l'écran, oubliant tout le reste de Windows. Un mode explicite qui n'existe plus vraiment dans les Windows modernes. Vous le savez sûrement, depuis Windows Vista, Microsoft à introduit DWM, son nouveau bureau accéléré par la carte graphique. En pratique, chaque fenêtre dispose de son propre buffer (une surface dans le langage de Microsoft) et la carte graphique est utilisée pour "composer" l'affichage.

Or, même si vous tapez très vite dans votre traitement de texte, vous aurez remarqué qu'il n'y a jamais d'effets de déchirements à l'écran ! Pour une bonne raison : DWM n'autorise pas le tearing, seuls des buffers complets sont utilisés.

La synchronisation verticale n'est cependant pas forcée ce qui fait qu'il est possible de cumuler l'absence de tearing et l'absence de V-Sync... en utilisant quand les jeux le supportent le mode "plein écran fenêtré". Un mode très utile à ceux qui possèdent deux écrans.

Dans ce mode, on passe par DWM pour le rendu ce qui pourrait paraître pire pour la latence. En pratique il n'en est rien : sous Windows 10, nous trouvons une latence strictement identique en mode plein écran "pur" et en mode fenêtré. Historiquement ce n'était pas le cas, passer par un mode "exclusif" était préférable pour la latence.

La raison de cette non différence tient probablement dans le fait que le mode plein écran "exclusif" ne l'est plus vraiment sous Windows 10, du au fait que Microsoft veut pouvoir "composer" par dessus les jeux ses notifications qui ne sauraient attendre :


Au cas ou vous auriez oublié avoir volontairement désactivé Windows Defender 20 secondes avant, une notification bien utile vient vous le rappeler en plein jeu ! Cela change de la publicité pour Office qui est apparue juste avant !

Vos réactions

Top articles