Les cartes graphiques/Annexe : le mode texte
Les toutes premières cartes d'affichage portaient le nom de cartes d'affichage en mode texte. Comme leur nom l'indique, elles sont spécifiquement conçues pour afficher du texte, pas des images. Elles étaient utilisées sur les ordinateurs personnels ou professionnels, qui n'avaient pas besoin d'afficher des graphismes, seulement des lignes de commandes, tableurs, traitements de textes rudimentaires, etc. Elles ont rapidement été remplacées par des cartes graphiques avec un framebuffer. Il s'agit d'une avancée énorme, qui permet beaucoup plus de flexibilité dans l'affichage.
L'existence de telles cartes en mode texte tient au fait que la mémoire vidéo était chère et qu'on ne pouvait pas en mettre beaucoup dans une carte d'affichage ou dans une console de jeu. Aussi, les fabricants de cartes graphiques devaient ruser. La petitesse de la mémoire faisait qu'il n'y avait pas de framebuffer proprement dit. On a vu au chapitre précédent qu'il existe des techniques de rendu 2D qui se passent de framebuffer, hé bien les premières cartes d'affichage les utilisaient sous une forme détournée.
Le mode texte
[modifier | modifier le wikicode]En mode texte, l'écran était découpé en carré ou en rectangles de taille fixe, contenant chacun un caractère. Les caractères affichables sont des lettres, des chiffres, ou des symboles courants, même si des caractères spéciaux sont disponibles. La carte d'affichage traitait les caractères comme un tout et il était impossible de modifier des pixels individuellement. Ceux-ci sont encodés dans un jeu de caractère spécifique (ASCII, ISO-8859, etc.), qui est généralement l'ASCII.
Tous les caractères sont des images de taille fixe, que ce soit en largeur ou en hauteur. Par exemple, un caractère peut faire 8 pixels de haut et 8 pixels de large, sur les écrans cathodiques. Sur les écrans LCD, les pixels sont carrés et les caractères font 16 pixels de haut par 8 de large pour avoir un aspect rectangulaire.
Les attributs des caractères sont des informations qui indiquent si le caractère clignote, sa couleur, sa luminosité, si le caractère doit être souligné, etc. Une gestion minimale de la couleur est parfois présente. Le tout est mémorisé dans un octet, à la suite du code ASCII du caractère.
Le mode texte est toujours présent dans nos cartes graphiques actuelles et est encore utilisé par le BIOS, ce qui lui donne cet aspect désuet et moche des plus inimitables.
Pour faire une comparaison, les caractères des cartes en mode texte sont équivalents aux tiles des cartes 2D. Une carte en mode texte peut être vue comme une carte 2D dont chaque caractère est une tile, et où il n'y a qu'un arrière-plan correspondant au texte à afficher et pas de sprite. Là encore, le but de ces architectures est d'économiser de la mémoire, très limitée et très chère pour l'époque. D'ailleurs, le hardware de ces deux types de carte se ressemble beaucoup, attendez-vous à voir quelques ressemblances.
A ce propos, il est possible d'émuler un rendu graphique à parti du mode texte, en trichant un petit peu. L'idée est de remplacer les caractères par des dessins équivalents à des tiles. C'est possible sur les cartes en mode texte sur lesquelles les caractères sont configurables, c’est-à-dire qu'on peut préciser à quoi ressemblent les caractères. Sur de telles cartes en mode texte, on peut fournir un dessin rectangulaire de quelques pixels de côté à la carte graphique et lui dire : ceci est le caractère numéro 40. On a alors un mode de rendu appelé mode semi-graphique.
L'architecture d'une carte d'affichage en mode texte
[modifier | modifier le wikicode]Paradoxalement, les cartes d'affichage en mode texte sont de loin les moins intuitives et elles sont plus complexes que les cartes d'affichage en mode graphique. Les limitations de la technologie de l'époque rendaient plus adaptées les cartes en mode texte, notamment les limitations en termes de mémoire vidéo. La faible taille de la mémoire rendait impossible l'usage d'un framebuffer proprement dit, ce qui fait que les ingénieurs ont utilisé un moyen de contournement, qui a donné naissance aux cartes graphiques en mode texte. Par la suite, avec l'amélioration de la technologie des mémoires, les cartes d'affichage avec un framebuffer sont apparues et ont remplacé les complexes cartes d'affichage en mode texte.
Les cartes d'affichage en mode texte et avec framebuffer ont une architecture assez similaire. Pour rappel, une carte graphique avec un framebuffer est composée de plusieurs composants : un circuit d’interfaçage avec le bus, un circuit de contrôle appelé le CRTC, une mémoire vidéo, un DAC qui convertit les pixels en signal analogique, et quelques circuits annexes.
Une carte en mode texte a les mêmes composants, avec quelques modifications. Le tampon de texte (text buffer) est la mémoire vidéo. Dans celle-ci, les caractères à afficher sont placés les uns à la suite des autres. Chaque caractère est stocké en mémoire avec deux octets : un octet pour le code ASCII, suivi d'un octet pour les attributs. L'avantage du mode texte est qu'il utilise très peu de mémoire vidéo : on ne code que les caractères et non des pixels indépendants, et un caractère correspond à beaucoup de pixels.
Le CRTC est modifié de manière tenir compte de l'organisation du tampon de texte. De plus, quelques circuits sont ensuite utilisés pour faire la conversion texte-image, comme on le verra plus bas. Le circuit de conversion texte-pixel est une petite mémoire ROM appelée la mémoire de caractère, qui mémorise, pour chaque caractère, sa représentation sous forme de pixels. La carte graphique contient aussi un circuit chargé de gérer les attributs des caractères : l'ATC (Attribute Controller), aussi appelé le contrôleur d'attributs. Il est situé juste en aval du tampon de texte.
La table des caractères
[modifier | modifier le wikicode]Les images de chaque caractère sont mémorisées dans une mémoire : la table des caractères, aussi appelée mémoire des caractères dans les schémas au-dessus. Dans cette mémoire, chaque caractère est représenté par une matrice de pixels, avec un bit par pixel. Certaines cartes graphiques permettent à l'utilisateur de créer ses propres caractères en modifiant cette table, ce qui en fait une mémoire ROM/EEPROM ou RAM.
On pourrait croire que la table des caractères telle que si l'on envoie le code ASCII sur l'entrée d'adresse, on récupère en sortie l'image du caractère associé. Mais cette solution simple est irréaliste : un simple caractère monochrome de 8 pixels de large et de 8 pixels de haut demanderait près de 64 pixels en sortie, soit facilement plusieurs centaines de bits, ce qui est impraticable, surtout pour les mémoires de l'époque. En réalité, la mémoire de caractère a une sortie de 1 pixel, le pixel en question étant pris dans l'image du caractère sélectionné. L'entrée d'adresse s'obtient alors en concaténant trois informations : le code ASCII pour sélectionner le caractère, le numéro de la ligne et le numéro de la colonne pour sélectionner le bit dans l'image du caractère. Les deux numéros sont fournis par le CRTC, comme on le verra plus bas.
La table des caractères ressemble, sur le principe, à la tilemap des cartes à rendu 2D sans framebuffer. Les deux convertissent un caractère/tile en pixels. La méthode d'adressage est fortement similaire, l'utilisation l'est aussi. La seule différence est leur contenu, la table des caractères stockant des caractères, la tilemap stockant des tiles graphiques.
Le CRTC sur une carte en mode texte
[modifier | modifier le wikicode]Le mode texte impose de modifier le CRTC de manière à ce qu'il adresse le tampon de texte correctement. Il contient toujours deux compteurs, pour localiser la ligne et la colonne du pixel à afficher, mais doit transformer cela en adresse de caractère. Le CRTC doit sélectionner le caractère à afficher, puis sélectionner le pixel dans celui-ci, ce qui demande la collaboration de la mémoire de caractères et le tampon de texte. Le CRTC va déduire à quel caractère correspond le pixel choisit, et le récupérer dans le tampon de texte. Là, le code du caractère est envoyé à la mémoire de caractère, et le CRTC fournit de quoi sélectionner le numéro de ligne et le numéro de colonne. Le pixel récupéré dans la mémoire de caractère est alors envoyé à l'écran.
Concrètement, les calculs à faire pour déterminer le caractère et pour trouver les numéros de ligne/colonne sont très simples, sans compter que les deux sont liés. Prenons par exemple un écran dont les caractères font tous 12 pixels de large et 8 pixels de haut. Le pixel de coordonnées X (largeur) et Y (hauteur) correspond au caractère de position X/12 et Y/8. Le reste de la première division donne la position de la colonne pour la mémoire de caractère, alors que le reste de la seconde division donne le numéro de ligne.
Si les caractères ont une largeur et une hauteur qui sont des puissances de deux, les divisions se simplifient : la position du caractère dans la mémoire se calcule alors à partir des bits de poids forts des compteurs X et Y, alors que les bits de poids faible permettent de donner le numéro de ligne et de colonne pour la mémoire de caractère. Dans le diagramme ci-dessus, les 3 bits de poids faible des registres X et Y de balayage des pixels servent à adresser le pixel parmi les 8x8 du bloc correspondant au caractère à afficher. L'index de ce caractère est lu dans le tampon de texte, adressé par les bits restant des registres X et Y.
Un exemple de CRTC est le Motorola 6845. Ce VDP génère l'adresse à lire dans la mémoire vidéo, ainsi que les signaux de synchronisation horizontale et verticale, mais ne fait pas grand-chose d'autre. Lire la mémoire vidéo, extraire les pixels et envoyer le tout à l'écran n'est pas de son ressort.
Il gère le mode texte uniquement, mais on peut supporter le mode graphique en trichant. Il supporte le mode entrelacé et le mode non-entrelacé, et est compatible aussi bien avec les moniteurs en PAL qu'en NTSC. Il contient 18 registres dont le contenu permet de configurer le VDP, pour configurer la résolution, la fréquence d'affichage, et d'autres choses encore.
D'autres CRTC plus évolués gèrent à la fois le mode texte et le mode graphique, on peut les configurer de manière à choisir lequel utiliser. Il est ainsi possible de prendre un VDP CRTC pour le mettre avec une mémoire assez petite pour gérer uniquement des graphiques en mode texte. Ou au contraire, de prendre un VDP CRTC et de le combiner avec une mémoire importante pour l'utiliser comme framebuffer.
Le défilement du texte
[modifier | modifier le wikicode]Faire défiler du texte est une opération très courante en mode texte. Concrètement, cela revient à descendre de quelques lignes dans le texte, ce qui demande de bouger tout le texte à l'écran. Et il est très utile, car défiler du texte vers le bas ou le haut est une opération très courante ! Et il s'agit d'une optimisation très couteuse. Aussi, même les premières cartes graphiques pour PC disposaient de techniques similaires pour accélérer le défilement vertical. Les toutes premières cartes graphiques MBA (monochromes) et CGA n'incorporaient pas de défilement vertical optimisé, mais les cartes suivantes, EGA et VGA, le faisaient. Les optimisations en question sont nombreuses, mais nous allons en voir deux.
Les optimisations du défilement basées sur un viewport
[modifier | modifier le wikicode]La première optimisation que nous allons voir réutilise les techniques vues dans le chapitre sur le rendu 2D. Précisément, il s'agit de l'optimisation du défilement vertical. En effet, le texte est généralement défilé de haut en bas, verticalement, le défilement horizontal étant plus rare. Même sur les écrans de l'époque, qui avaient des colonnes limitées à 80/100 caractères, le texte était conçu de manière à ce que les lignes de texte ne débordent pas de l'écran. Aussi, les optimisations qui nous intéressent sont surtout les optimisations du défilement vertical.
L'idée pour un rendu en pixels est d'avoir un framebuffer organisé en lignes et colonnes, avec plus de lignes que ce que prévoit l'écran. Ce qui est visible à l'écran est une protion du framebuffer, appelée le viewport. Ainsi, les lignes à afficher au-dessus ou en dessous du viewport sont déjà en mémoire vidéo. Il y a juste à fournir un registre qui point vers la position du viewport dans la carte graphique, ce qui permet de faire bouger le viewport à volonté. Le tout est complété avec un warp-around des adresses, à savoir que si le viewport arrive à la toute fin du framebuffer et descend encore, il reprend au tout début du framebuffer.
Le défilement en mode texte se base sur le même principe, sauf qu'on saute d'une ligne de caractère à une autre directement. Le défilement ne se fait pas ligne de pixel par ligne de pixel, mais par paquets de plusieurs lignes. Par exemple, si un caractère de texte fait 8 pixels de haut, alors on saute les lignes par paquets de 8.
L'usage d'une display list
[modifier | modifier le wikicode]Une autre solution, plus économe en RAM, fait usage d'un VDC à co-processeur. Pour rappel, ce sont des VDC qui incorporent un processeur qui exécute un programme d'affichage. Le programme, appelé la display list, afficher une image à l'écran, ou du texte, ou tout ce qu'il faut afficher. Chaque instruction de la display list dit quoi afficher sur une ligne à l'écran. Ici, elle dit quoi afficher sur une ligne de texte, une ligne de caractère, et non une ligne de pixels comme dans les chapitres précédents.
Un exemple de VDC à co-processeur en mode texte est celui des ordinateurs Amstrad PCW. Il s'agissait d'ordinateurs qui ne géraient que le mode texte, ils ne pouvaient pas afficher d'image pixel par pixel, ils n'avaient pas de framebuffer. Le texte à afficher à l'écran n'était pas stocké dans un tableau unique, ligne par ligne, dans l'ordre de rendu, comme c'est le cas sur les autres cartes en mode texte. A la place, chaque ligne était stocké en mémoire séparément les unes des autres, ou presque.
L'affichage était gouverné par une display list qui disait quelle ligne afficher, et dans quel ordre. La display list était une liste d'adresses, chacun pointant vers le début d'une ligne en mémoire vidéo. Toutes les lignes faisaient la même taille, ce qui fait que la display list avait juste à encoder l'adresse de départ de la ligne pour l'afficher correctement. Le processeur du VDC lisait la display list adresse par adresse et rendait les lignes dans l'ordre précisé par la display list.
Le défilement était alors simple à implémenter : il suffisait de modifier le contenu de la display list. Par exemple, pour défiler d'une ligne vers le cas, on décalait son contenu de la display list d'un cran et on modifiait la ligne la plus en haut. L'avantage est que modifier une display list est plus rapide que de faire défiler l'ensemble du text buffer.
La display list était stockée dans une mémoire RAM spécialisée de 512 octets, ce qui permettait de stocker 256 adresses de 16 bits chacune. La display list avait 256 lignes, ce qui collait exactement à la résolution de 720 par 256 pixels de l'Amstrad PCW. LA RAM qui mémorisait la display list s'appelait la roller RAM. Elle était utilisée par le processeur 280 de la machine pour gérer le rendu de l'affichage. Le VDC utilisé était en effet très simple et se résumait sans doute à un vulgaire CRTC en mode texte.