Les cartes graphiques

Chapitre 1.2 : Cartes accélératrices 2D

Guy Grave

Avec l'arrivée des jeux vidéo, les performances commencèrent à poser quelques problèmes. Les premiers jeux vidéo étaient tous des jeux 2D qui donnaient l'illusion de la 3D. Le processeur avait en charge tous les calculs et coloriait les pixels un par un, avant de tout envoyer à la carte graphique.

Commentez

- Titre : Les cartes graphiques

- Auteur : Guy Grave

- Parution : 20 mars 2014

- Mise à jour : 23 novembre 2019

- Licence : Le contenu de cet article est rédigé par Guy Grave et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Pas de Modification 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Sommaire

- Navigation

- I. Introduction

- II. Blitter

- III. Sprites et accélération matérielle du curseur de souris

- III-A. Sprites

- III-B. Curseur de souris matériel

- Navigation

Navigation

Tutoriel précédent : cartes d'affichages

Sommaire

Tutoriel suivant : les cartes accélératrices 3D

I - Introduction

Avec l'arrivée des jeux vidéo, les performances commencèrent à poser quelques problèmes. Les premiers jeux vidéo étaient tous des jeux 2D qui donnaient l'illusion de la 3D. Le processeur avait en charge tous les calculs et coloriait les pixels un par un, avant de tout envoyer à la carte graphique.

Les premières cartes accélératrices furent un grand pas en avant : au lieu de laisser tout le boulot au processeur, ces cartes graphiques faisaient une partie des calculs. À l'époque, ces calculs étaient assez simples : tracé de segments, tracé de lignes, et autres. Les cartes graphiques 2D ont d'abord commencé par accélérer le traitement de figures géométriques simples : segments, cercles, ellipses, etc. Dans certains cas, elles pouvaient colorier une de ces figures : remplir un disque de rouge, remplir un rectangle en orange, etc. Ces fonctions permettaient d'accélérer les premières interfaces graphiques des systèmes d'exploitation.

Les cartes graphiques actuelles supportent aussi d'autres technologies, comme des techniques d'accélération du rendu des polices d'écriture, une accélération du scrolling, des accélérateurs d'affichage pour les bibliothèques GDI (utilisées sous Windows), ou encore un support matériel du curseur de souris. Si vous ne me croyez pas, lancer Windows ou Linux sans les pilotes de la carte graphique…

II - Blitter

Un peu plus tard, elles ont introduit un composant très utile pour l'époque : le blitter. Dans sa version la plus simple, ce blitter sert à accélérer les copies de blocs de données d'un endroit de la mémoire vidéo à un autre. Ce genre de copie arrive souvent lorsqu'on doit faire un défilement, ou qu'un objet 2D se déplace sur l'écran. Déplacer une fenêtre sur votre bureau est un bon exemple : le contenu de ce qui était présent sur l'écran doit être déplacé vers le haut ou vers le bas. Dans la mémoire vidéo, cela équivaut à une copie des pixels correspondants de leur ancienne position vers la nouvelle.

Cela a aussi des applications dans les jeux en 2D. La base d'un rendu en 2D, c'est simplement de superposer des images les unes au-dessus des autres. Par exemple, dans tout jeu 2D, presque toutes les entités du jeu sont représentées par une image 2D. On peut avoir une image pour l'arrière-plan (le décor), une image pour le monstre qui vous fonce dessus, une image pour le dessin de votre personnage, etc.

Ces images sont alors placées au bon endroit sur l'écran, et peuvent subir quelques transformations : zoom, rotation, etc. Elles sont alors superposées sur l'arrière-plan. Ce qui se traduit par une copie des pixels de l'image aux bons endroits dans la mémoire.

Créer un circuit juste pour faire des copies en mémoire et quelques opérations bit à bit peut sembler bizarre. Mais il y a de bonnes raisons à cela. Lorsque ce circuit a été inventé, le screen buffer des cartes graphiques était accessible par le processeur, qui pouvait lire et écrire directement dedans. Ces copies étaient donc à la charge du processeur, qui devait déplacer lui-même les données en mémoire. Pour ce faire, un petit morceau de programme s'en chargeait. Ce morceau de programme répétait une série d'instructions en boucle pour copier les données pixel par pixel.

Répéter ces instructions nécessitait de recharger celles-ci depuis la mémoire à chaque utilisation, ce qui prenait du temps. A contrario, un blitter n'a pas ce genre de problèmes. Il s'agit d'un circuit qui était conçu pour ce genre de tâche : il n'accédait à la mémoire que pour transférer des données, sans besoin de charger la moindre instruction. Le gain en performance était assez appréciable.

Notre blitter se compose simplement d'un circuit auquel sont interfacés quelques registres. Ces registres permettent de configurer notre blitter, afin de lui indiquer :

- la position en mémoire du bloc de données à copier ;

- la destination ;

- la longueur du bloc ;

- et quelques autres paramètres.

Ceci dit, un blitter possède d'autres fonctionnalités. Il peut effectuer une opération bit à bit entre le bloc de données à copier et le bloc de destination. Le résultat de cette opération est ensuite enregistré en mémoire. Généralement, le blitter peut effectuer des négations, des ET bit à bit, des OU bit à bit, parfois des XOR bit à bit.

Pour voir à quoi cela peut servir, reprenons notre exemple du jeu 2D, basé sur une superposition d'images. Les images des différents personnages sont souvent des images rectangulaires. Par exemple, l'image correspondant à notre bon vieux pacman ressemblerait à celle-ci.

Évidemment, cette image s'interface très mal avec l'arrière-plan. Imaginez que l'arrière-plan soit de couleur blanche. Les bords en noir sur l'image de notre bon vieux pacman se verraient à l'écran. L'idéal, ce serait de ne pas toucher à l'arrière-plan sur les pixels noirs de notre pacman, et de ne modifier l'arrière-plan que pour les pixels jaunes. Cela est possible en fournissant une information qu'on appelle le masque. Il s'agit d'une image qui indique quels sont les pixels à modifier lors d'un transfert, et quels sont ceux qui ne doivent pas changer. Par exemple, le masque de notre pacman est celui-ci :

Grâce à ce masque, le blitter peut décider quels sont les pixels à ne pas modifier. Pour cela, il suffit de lui fournir le masque en plus. Il prend donc en entrée l'image de notre pacman, le morceau de l'arrière-plan auquel on superpose pacman, et le masque. Pour chaque pixel, il effectue l'opération suivante : ((arrière-plan) AND (masque)) OR (image de pacman). Finalement, l'image résultante est bel et bien celle qu'on attend.

III - Sprites et accélération matérielle du curseur de souris

Le blitter était concurrencé par une autre technique en vigueur : les sprites matériels. Avec cette technique, nul besoin de blitter pour superposer une image sur une autre. Ces sprites ne sont ni plus ni moins que les images à superposer à l'arrière-plan. Ceux-ci sont stockés dans de petites mémoires RAM intégrées dans la carte graphique.

III-A - Sprites

Avec la technique des sprites, ces sprites ne sont pas ajoutés sur l'arrière-plan : celui-ci n'est pas modifié. À la place, c'est la carte graphique qui décidera d'afficher les pixels de l'arrière-plan ou du sprite lors de l'envoi des pixels à l'écran, lors du balayage effectué par le CRTC.

Notre carte contient donc des RAM pour stocker les sprites, plus une grosse RAM pour l'arrière-plan. Toutes ces RAM sont connectées au RAMDAC ou au tampon d'images via un bus, un ensemble de fils électriques sur lequel un seul composant peut envoyer plusieurs données à la fois.

Pour chacune des RAM associée au sprite, on trouve deux registres permettant de mémoriser la position du sprite à l'écran : un pour sa coordonnée X, et un autre pour sa coordonnée Y. Lorsque le CRTC demande à afficher le pixel à la position (X, Y), chacun des registres de position est alors comparé à la position envoyée par le CRTC. Si aucun sprite ne correspond, les mémoires des sprites sont déconnectées du bus. Le pixel affiché est celui de l'arrière-plan. Dans le cas contraire, la RAM du sprite est connectée sur le bus, et son contenu est envoyé au tampon d'images ou au RAMDAC.

Si plusieurs sprites doivent s'afficher en même temps, alors le bus décide de choisir un des sprites, et déconnecte tous les autres du bus. Pour cela, divers mécanismes d'arbitrage sont implantés dans le bus (une simple daisy chain peut suffire). Grosso modo, certains registres seront prioritaires sur les autres, et ces priorités sont fixées une fois pour toutes dans le matériel qui gère le bus. La gestion de recouvrements est donc gérée par le programmeur, qui décide dans quels registres placer les images à afficher suivant leurs priorités.

III-B - Curseur de souris matériel

Cette technique des sprites est présente dans notre carte graphique, mais dans un cadre particulièrement spécialisé. Elle sert à afficher le curseur de la souris !

Notre carte graphique contient en effet un ou plusieurs sprites, qui représentent chacun un curseur de souris. La carte graphique permet de configurer la position de ce sprite grâce à deux registres, qui stockent les coordonnées x et y du curseur.

Ainsi, pas besoin de redessiner l'image à envoyer à l'écran à chaque fois que l'on bouge la souris, comme on aurait dû le faire avec un blitter. À la place, il suffit de modifier le contenu des deux registres, et la carte graphique s'occupe de placer le curseur sur l'écran automatiquement, lors de l'affichage de l'image. Cette technique d'accélération matérielle du curseur de souris est présente dans toutes les cartes graphiques actuelles. Pour en avoir la preuve, testez une nouvelle machine sur laquelle les drivers ne sont pas installés, et bougez le curseur. Effet lag garanti !

Navigation

Tutoriel précédent : cartes d'affichages

Sommaire

Tutoriel suivant : les cartes accélératrices 3D