Command Buffer et interface logicielle

Une carte graphique est un périphérique comme un autre, connecté sur la carte mère (sauf pour certaines cartes graphiques intégrées). Le processeur doit envoyer des informations à la carte graphique pour que celle-ci fasse son travail. Voyons tout ce qui se passe durant ces transferts.

Le logiciel

La carte graphique accélére les jeux vidéos, les applications de conception assistée par ordinateur (solidworks), ou de rendu d'images 3D (blender, maya, etc). Elle peut aussi accélérer le traitement de l'affichage 2D : essayez d'utiliser Windows sans pilote de carte graphique, vous verrez de quoi je parle. Bref, il y a forcément un programme, ou un logiciel qui utilise notre carte graphique et lui délègue ses calculs.

DirectX et OpenGL

Pour déléguer ses calculs à la carte 3D, l'application pourrait communiquer directement avec la carte graphique, en écrivant dans ses registres et dans sa mémoire vidéo. Seul problème : le programme ne pourra communiquer qu'avec un ou deux modèles de cartes, et la compatibilité sera presque inexistante.

Pour résoudre ce problème, les concepteurs de systèmes d'exploitations et de cartes graphiques ont inventé des API 3D, des bibliothèques qui fournissent des "sous-programmes" de base, des fonctions, que l'application pourra exécuter au besoin. De nos jours, les plus connues sont DirectX, et OpenGL.

Pilotes de carte graphique

Les fonctions de ces APIs vont préparer des données à envoyer à la carte graphique, avant que le pilote s'occupe des les communiquer à la carte graphique. Un driver de carte graphique gère la mémoire de la carte graphique : où placer les textures, les vertices, et les différents buffers de rendu. Le pilote de carte graphique est aussi chargé de traduire les shaders, écrits dans un langage de programmation comme le HLSL ou le GLSL, en code machine.

L'envoi des données à la carte graphique ne se fait pas immédiatement : il arrive que la carte graphique n'ait pas fini de traiter les données de l'envoi précédent. Il faut alors faire patienter les données tant que la carte graphique est occupée. Les pilotes de la carte graphique vont les mettre en attente dans une portion de la mémoire : le ring buffer. Ce ring buffer est ce qu'on appelle une file, une zone de mémoire dans laquelle on stocke des données dans l'ordre d'ajout.

Si le ring buffer est plein, le driver n'accepte plus de demandes en provenance des applications. Un ring buffer plein est généralement mauvais signe : cela signifie que la carte graphique est trop lente pour traiter les demandes qui lui sont faites. Par contre, il arrive que le ring buffer soit vide : dans ce cas, c'est simplement que la carte graphique est trop rapide comparé au processeur, qui n'arrive alors pas à donner assez de commandes à la carte graphique pour l'occuper suffisamment.

Command Processor

Les commandes envoyées par le pilote de la carte graphique sont gérées par le command processor.

Commandes

Certaines de ces commandes vont demander à la carte graphique d'effectuer une opération 2D, d'autres une opération 3D, et d'autres une opération concernant l'accélération vidéo. Vous vous demandez à quoi peuvent bien ressembler ces commandes. Prenons les commandes de la carte graphique AMD Radeon X1800.

Voici les commandes 2D :

Commandes 2D Fonction
PAINT Peindre des rectangle d'une certaine couleur
PAINT_MULTI Peindre des rectangles (pas les mêmes paramètres que PAINT)
BITBLT Copie d'un bloc de mémoire dans un autre
BITBLT_MULTI Plusieurs copies de blocs de mémoire dans d'autres
TRANS_BITBLT Copie de blocs de mémoire avec un masque
NEXTCHAR Afficher un caractère avec une certaine couleur
HOSTDATA_BLT Écrire une chaine de caractère à l'écran ou copier une série d'image bitmap dans la mémoire vidéo
POLYLINE Afficher des lignes reliées entre elles
POLYSCANLINES Afficher des lignes
PLY_NEXTSCAN Afficher plusieurs lignes simples
SET_SCISSORS Utiliser les scissors ?
LOAD_PALETTE Charger la palette pour affichage 2D

D'autres commandes servent à synchroniser le processeur et le GPU :

Commandes de synchronisation Fonction
NOP Ne rien faire
WAIT_SEMAPHORE Attendre la synchronisation avec un sémaphore
WAIT_MEM Attendre que la mémoire vidéo soit disponible et inoccupée par le CPU

D'autres commandes servent pour l'affichage 3D : afficher une image à partir de paquets de vertices, ou préparer le passage d'une image à une autre. Et enfin, certaines commandes servent pour l’accélération des vidéos.

Parallélisme

Sur les cartes graphiques modernes, le command processor peut démarrer une commande avant que les précédentes soient terminées. Par exemple, il est possible d’exécuter une commande ne requérant que des calculs, en même temps qu'une commande qui ne fait que faire des copies en mémoire. Toutefois, cette parallélisation du command processor a un désavantage : celui-ci doit gérer les synchronisations entre commandes.

Synchronisation CPU

Avec un command buffer, le processeur et la carte graphique ne fonctionnent pas au même rythme, et cela pose problèmes. Par exemple, Direct X et Open Gl décident d'allouer ou de libérer de la mémoire vidéo pour les textures ou les vertices. Or, Direct X et Open Gl ne savent pas quand le rendu de l'image se termine. Mais comment éviter d'enlever une texture de la mémoire tant que les commandes qui utilisent celle-ci ne sont pas terminées ? Ce problème ne se limite pas aux textures, mais vaut pour tout ce qui est placé en mémoire vidéo. De manière générale, Direct X et Open Gl doivent savoir quand une commande se termine.

Un moyen pour éviter tout problème serait d'intégrer les données nécessaire à l'exécution d'une commande dans celle-ci : par exemple, on pourrait copier les textures nécessaires dans chacune des commandes. Mais cela gâche de la mémoire, et ralentit le rendu à cause des copies de textures.

Fences

Les cartes graphiques récentes incorporent des commandes de synchronisation : les fences. Ces fences vont empêcher le démarrage d'une nouvelle commande tant que la carte graphique n'a pas fini de traiter toutes les commandes qui précèdent la fence. Pour gérer ces fences, le command buffer contient des registres, qui permettent au processeur de savoir où la carte graphique en est dans l’exécution de la commande.

Sémaphores

Un autre problème provient du fait que les commandes se partagent souvent des données, et que de nombreuses commandes différentes peuvent s'exécuter en même temps. Or, si une commande veut modifier les données utilisées par une autre commande, il faut que l'ordre des commandes soit maintenu : la commande la plus récente ne doit pas modifier les données utilisées par une commande plus ancienne. Pour éviter cela, les cartes graphiques ont introduit des instructions de sémaphore, qui permettent à une commande de bloquer tant qu'une ressource (une texture) est utilisée par une autre commande.