Les cartes graphiques/Les cartes accélératrices 3D

Un livre de Wikilivres.
Aller à la navigation Aller à la recherche

Le premier jeu à utiliser de la "vraie" 3D fût le jeu Quake, premier du nom. Et depuis sa sortie, la grande majorité des jeux vidéo utilisent de la 3D, même s'il existe encore quelques jeux en 2D. Face à la prolifération de ces jeux vidéo en 3D, les fabricants de cartes graphiques se sont adaptés. Ils ont inventé les cartes accélératrices 3D, des cartes vidéo capables d'accélérer les calculs effectués pour rendre une scène en 3D. Dans ce chapitre, nous allons voir comment elles fonctionnent et comment elles ont évolué dans le temps. Pour comprendre comment celles-ci fonctionnent, il faut parler rapidement de comment les jeux vidéo font pour calculer une scène en 3D. Ce rendu en 3 dimensions, aussi appelé rendu 3D, est en effet ce qui est pris en charge par les cartes accélératrices 3D, totalement ou partiellement. Nous allons donc commencer par quelques rapides rappels sur les bases du rendu 3D.

Les bases du rendu 3D[modifier | modifier le wikicode]

Une scène 3D est composée d'un espace en trois dimensions, dans laquelle le moteur d’un jeu vidéo place des objets et les fait bouger. Cette scène est, en première approche, un simple parallélogramme. Un des coins de ce parallélogramme sert d’origine à un système de coordonnées : il est à la position (0, 0, 0), et les axes partent de ce point en suivant les arêtes. Les objets seront placés à des coordonnées bien précises dans ce parallélogramme.

Les objets 3D et leur géométrie[modifier | modifier le wikicode]

Les objets placés dans la scène 3D sont composés de formes de base, combinées les unes aux autres pour former des objets complexes. En théorie, les formes géométriques en question peuvent être n'importe quoi : des triangles, des carrés, des courbes de Béziers, etc. En général, on utilise des polygones par simplicité, les autres solutions étant peu pratiques et plus complexes. Dans la quasi-totalité des jeux vidéo actuels, seuls les triangles sont utilisés. Les objets sont donc modélisés par un assemblage de triangles collés les uns aux autres. Cet assemblage de triangles/carrés/polygones est ce qu'on appelle un maillage, (mesh en anglais). Il a été tenté dans le passé d'utiliser des carrés/rectangles (rendu dit en quad) ou d'autres polygones que les triangles, mais les contraintes techniques ont fait que ces solutions n'ont pas été retenues.

Illustration d'un dauphin, représenté avec des triangles.

Les polygones sont définis par leurs sommets, aussi appelés vertices dans le domaine du rendu 3D. Dans ce qui suit, nous utiliseront indifféremment les termes vertice et sommet. Chaque sommet possède trois coordonnées, qui indiquent sa position dans la scène 3D : abscisse, ordonnée, profondeur. Un triangle est donc composé de 9 coordonnées, 3 par vertices. Ensuite, les sommets sont reliés entre eux. Le segment qui connecte une paire de sommets s'appelle une arête, comme en géométrie élémentaire. Si plusieurs arêtes délimitent une surface fermée, celle-ci est appelée une face. Concrètement, les seules face actuellement utilisées en rendu 3D sont les triangles et les carrés (quad). Quand plusieurs faces sont sur un même plan, elles forment un "polygone", bien que le terme ne soit utilisé comme en mathématique. Un assemblage de plusieurs "polygones" donne une surface.

Surface représentée par ses sommets, arêtes, triangles et polygones.

La représentation exacte d'un objet est donc une liste plus ou moins structurée de sommets, pouvant contenir une certaine redondance ou des informations en plus. La liste doit préciser les coordonnées de chaque sommet, ainsi que comment les relier. Il faut savoir quel sommet appartient à tel triangle. Pour cela, l'objet est représenté par une structure qui contient la liste des sommets, mais aussi de quoi savoir quels sont les sommets reliés entre eux par un segment. Les manières de structurer ces informations sont nombreuses, mais nous en dirons plus dans le chapitre sur le rendu de la géométrie.

Les textures[modifier | modifier le wikicode]

Tout objet à rendre en 3D est donc composé d'un assemblage de polygones, généralement des triangles. Le rendu 3D normal travaille sur des triangles, qui sont éclairés et coloriés par divers algorithmes. Une partie de ce traitement tient à gérer la lumière dans la scène, ce qui permet de colorier un triangle en nuances de gris, représentant sa luminosité. Pour rajouter de la couleur, ces objets sont recouverts par des textures, des images qui servent de papier peint à un objet. Un objet géométrique est donc éclairé, puis recouverts par une ou plusieurs textures qui permettent de le colorier ou de lui appliquer du relief.

Texture Mapping
Rendu en fil de fer d'un modèle 3D complexe.

Précisons cependant qu'il est possible de se passer des textures et du coloriage des triangles en s’arrêtant au tracé des arêtes et sommets. On obtient alors un rendu en fil de fer, (rendu wireframe en anglais). L'effet est particulier et a peu été utilisé dans les jeux vidéo.

Notons que les textures sont des images comme les autres, codées pixel par pixel. Pour faire la différence entre les pixels de l'écran et les pixels d'une texture, on appelle ces derniers des texels. Ce terme est assez important, aussi profitez-en pour le mémoriser, nous le réutiliserons dans quelques chapitres. Un autre point lié au fait que les textures sont des images est leur compression, leur format. N'allez pas croire que les textures sont stockées dans un fichier .jpg, .png ou tout autre format de ce genre. Les textures utilisent des formats spécialisés, comme le DXTC1, le S3TC ou d'autres, plus adaptés à leur rôle de texture. Mais qu'il s'agisse d'images normales (.jpg, .png ou autres) ou de textures, toutes sont compressées. Les textures sont compressées pour prendre moins de mémoire. Songez que la compression de texture est terriblement efficace, souvent capable de diviser par 6 la mémoire occupée par une texture. S'en est au point où les textures restent compressées sur le disque dur, mais aussi dans la mémoire vidéo ! Nous en reparlerons dans le chapitre sur la mémoire d'une carte graphique.

La caméra : le point de vue depuis l'écran[modifier | modifier le wikicode]

Outre les objets proprement dit, on trouve une caméra, qui représente les yeux du joueur. Cette caméra est définie par :

  • une position ;
  • par la direction du regard (un vecteur) ;
  • le champ de vision (un angle) ;
  • un plan qui représente l'écran du joueur ;
  • et un plan limite au-delà duquel on ne voit plus les objets.
Caméra.
Volume délimité par la caméra (view frustum).

Ce qui est potentiellement visible du point de vue de la caméra est localisé dans un volume, situé entre le plan de l'écran et le plan limite, appelé le view frustum. Suivant la perspective utilisée, ce volume n'a pas la même forme. Avec la perspective usuelle, le view frustum ressemble à un trapèze en trois dimensions, délimité par plusieurs faces attachées au bords de l'écran et au plan limite. Le tout est parfois appelée, bien que par abus de langage, la pyramide de vision. Avec d'autres perspectives moins utilisées, le view frustum est un pavé, mais nous n'en parlerons pas plus dans le cadre de ce cours car elles ne sont presque pas utilisés dans les jeux vidéos actuels.

Le culling et le clipping[modifier | modifier le wikicode]

Un point important du rendu 3D est que ce qui n'est pas visible depuis la caméra ne doit idéalement pas être calculé. A quoi bon calculer des choses qui ne seront pas affichées, après tout ? Ce serait gâcher de la puissance de calcul. Et pour cela, les cartes graphiques et les moteurs graphiques incorporent de nombreuses optimisations pour éliminer les calculs inutiles. Diverses techniques de clipping ou de culling existent pour cela. La différence entre culling et clipping n'est pas fixée et la terminologie n'est pas claire. Dans ce qui va suivre, nous n'utiliserons que le terme culling.

View frustum culling : les parties potentiellement visibles sont en vert, celles invisibles en rouge et celles partiellement visibles en bleu.

La première forme de culling est le view frustum culling, dont le nom indique qu'il s'agit de l'élimination de tout ce qui est situé en-dehors du view frustum. Elle fait que ce qui est en-dehors du champ de vision de la caméra n'est pas affiché à l'écran n'est pas calculé ou rendu, dans une certaine mesure. Les autres formes de culling visent à éliminer ce qui est dans le view frustum, mais qui n'est pas visible depuis la caméra. Par exemple, il se peut que certains objets situés dans le view frustum ne soient pas visibles ou alors seulement partiellement. Pensez à des objets cachés par un autre objet plus proche, par exemple. Ou encore, pensez aux faces à l'arrière d'un objet opaque qui sont cachées par l'avant. ces deux cas correspondent à deux types de culling. L'élimination des objets masqués par d'autres est appelé l'occlusion culling. L'élimination des parties arrières d'un objet est appelé le back-face culling. Enfin, certains objets qui sont trop loin ne sont tout simplement pas calculés et remplacé par du brouillard ou un autre artefact graphique, voire pas remplacé du tout.

Occlusion culling : les objets en bleu sont visibles, ceux en rouge sont masqués par les objets en bleu.

Pour résumer, les portions de la scène 3D qui ne sont pas visibles à l'écran ne doivent pas être calculées. Les cartes graphiques embarquent divers méthodes de culling pour abandonner les calculs quand elles s’aperçoivent que ceux-ci portent sur une partie non-affichée de l'image. Cela fait des économies de puissance de calcul assez appréciables et un gain en performance assez important. Précisons que le culling peut être plus ou moins précoce suivant le type de rendu 3D utilisé, mais nous verrons cela dans la suite du chapitre.

Le pipeline graphique[modifier | modifier le wikicode]

Les techniques de rendu 3D sont nombreuses, mais on peut les classer en deux grands types : le lancer de rayons et la rasterization. Sans décrire les deux techniques, sachez cependant que le lancer de rayon n'est pas beaucoup utilisé pour les jeux vidéo. Il est surtout utilisé dans la production de films d'animation, d'effets spéciaux, ou d'autres rendu spéciaux. La raison est qu'il demande beaucoup de puissance de calcul, ce qui le rend peu adapté aux jeux vidéo. De plus, le matériel pour accélérer le lancer de rayon n'est pas très efficace et n'a pas pris commercialement. Ce qui explique que depuis un bon moment, les jeux vidéo utilisent la rasterization. Celle-ci calcule une scène 3D intégralement, avant de faire des transformations pour n'afficher que ce qu'il faut à l'écran.

Il existe deux sous-types de rasterization : le rendu en mode immédiat, et le rendu en tiles. La plupart des cartes graphiques des ordinateurs de bureau ou des ordinateurs portables utilisent la première méthode. Le rendu en tiles est surtout utilisé sur les équipements mobiles ou embarqués, qui fonctionnent à basse performance et à basse consommation. Une des raisons est un avantage du rendu en tile pour le rendu en 2D, comparé aux architectures en mode immédiat. En général, les cartes graphiques utilisant le rendu en tiles consomment moins d'énergie et sont plus rapides que leur équivalent en mode immédiat pour le rendu 2D, ce qui en fait un avantage certain pour les appareils mobiles.

Le rendu en mode immédiat[modifier | modifier le wikicode]

Avec le rendu en mode immédiat, le calcul de l'image finale passe par une suite d'étapes consécutives qui doivent s'enchainer dans un ordre bien précis. L'est appelé le pipeline graphique. Précisons cependant que la succession d'étape que nous allons voir n'est pas aussi stricte que vous pouvez le penser. En fait, il n'existe pas un pipeline graphique unique : chaque API 3D fait à sa sauce, le matériel ne respecte pas forcément cette succession d'étapes, et j'en passe. Cependant, toutes les API 3D modernes sont organisée plus ou moins de la même manière, ce qui fait que le pipeline que nous allons décrire colle assez bien avec les logiciels 3D anciens et modernes, ainsi qu'avec l'organisation des cartes graphiques (anciennes ou modernes). La différence est que certaines étapes facultatives seront omises, comme la tesselation ou la gestion des primitives.

Le cas le plus simple ne demandant que trois étapes :

  • une étape purement logicielle, effectuée par le processeur, où le moteur physique calcule la géométrie de la scène 3D ;
  • une étape de traitement de la géométrie, qui gère tout ce qui a trait aux sommets et triangles ;
  • une étape de rasterization qui attribue chaque sommet/triangle à un pixel donné de l'écran.
Pipeline graphique basique.

Par la suite, l'étape de rastérisation s'est complexifiée et a été scindée en plusieurs étapes. La première est l'étape de rastérisation proprement dite, où on fait le lien entre triangle et pixels et où quelques opérations d'interpolation sont réalisées pour faire un rendu basique. La seconde étape est celle où le pipeline graphique manipule des pixels. On a donc un pipeline découpé en trois : une partie où on manipule la géométrie de la scène 3D, une étape de conversion triangle->pixels, et une étape où on traite le pixels eux-même. On a donc :

  • une étape purement logicielle ;
  • une étape de traitement de la géométrie ;
  • une étape de rasterization ;
  • une étape de traitement des pixels.

Cette séparation en trois étapes est vraiment importante. Elle est commune à tous les API 3D, en plus d'avoir une certaine logique. La séparation entre géométrie et pixels par une étape de rastérisation est au fondement même de la technique du rendu immédiat. Après, les trois étapes en question sont elles-mêmes subdivisées en plusieurs étapes distinctes, qui s'enchainent dans un ordre bien précis. Voyons cela plus en détail.

Le traitement de la géométrie[modifier | modifier le wikicode]

Le traitement de la géométrie se fait en plusieurs étapes.

La première étape est appelée étape de transformation effectue plusieurs changements de coordonnées pour chaque sommet.

  • Premièrement, elle place les objets au bon endroit dans la scène 3D, ce qui demande de mettre à jour les coordonnées de chaque sommet de chaque modèle. C'est la première étape de calcul : l'étape de transformation des modèles 3D.
  • Ensuite, elle effectue un changement de coordonnées pour centrer l'univers sur la caméra, dans la direction du regard. C'est l'étape de transformation de la caméra.
  • Ensuite, une correction de la perspective est effectuée, qui corrige la forme du view frustum : c'est l'étape de projection.

Lors de la seconde étape de traitement de la géométrie, les sommets sont éclairés dans une phase d'éclairage. Lors de cette phase, tout sommet se voit attribuer une couleur, qui définit son niveau de luminosité. Celui-ci indique si le sommet est éclairé ou est dans l'ombre.

Éventuellement, diverses opérations de culling sont ensuite effectuées à la fin de cette étape, notamment le clipping et le view frustum-culling.

Geometry pipeline.

La rastérisation[modifier | modifier le wikicode]

Illustration du principe de la rasterization. La surface correspondant à l'écran est subdivisée en pixels carrés, de coordonnées x et y. La caméra est placée au point e. Pour chaque pixel, on trace une droite qui part de la caméra et qui passe par le pixel considéré. L'intersection entre une surface et cette droite se fait en un point, appartenant à un triangle.

Vient ensuite la traduction des formes (triangles) rendues dans une scène 3D en un affichage pixelisé à l'écran. Cette étape de rasterization détermine à quoi ressemble la scène visible sur l'écran. Lors de cette étape, chaque pixel de l'écran se voit attribuer un ou plusieurs triangle(s). Pour mieux comprendre quels triangles sont associés à tel pixel, imaginez une ligne droite qui part de caméra et qui passe par un pixel sur le plan de l'écran. Cette ligne intersecte 0, 1 ou plusieurs objets dans la scène 3D. Les triangles situés ces intersections entre cette ligne et les objets rencontrés seront associé au pixel correspondant. C'est aussi lors de cette étape que sont appliquées certaines techniques de culling, qui éliminent les portions non-visibles de l'image, ainsi qu'une correction de la perspective.

L'étape de traitement des pixels[modifier | modifier le wikicode]

À la suite de la rastérisation, le pipeline ne manipule que des pixels et aucune référence à la géométrie n'est faite. Le rastériseur fait office de séparation stricte entre le pipeline géométrique et le pipeline des pixels. L'étape de traitement des pixels, après le rastériseur, effectue globalement deux à trois étapes.

Premièrement, les textures sont appliquées sur la géométrie. La carte graphique sait à quel triangle correspond chaque pixel et peut donc colorier le pixel en question en fonction de la couleur de la texture appliquée sur la géométrie. C'est la phase de placage de textures. Sur les cartes graphiques récentes, cette étape peut être gérée par le programmeur : il peut programmer les divers traitements à effectuer lui-même. En plus de cela, les pixels de l'écran peuvent subir des traitements divers et variés avant d'être enregistrés et affichés à l'écran.

Deuxièmement, après l'étape de placage de textures, la carte graphique enregistre le résultat en mémoire. Lors de cette étape, divers traitements sont effectués et divers effets peuvent être ajoutés à l'image : un effet de brouillard peut être ajouté, des tests de profondeur sont effectués pour éliminer certains pixels cachés, l'antialiasing est ajouté, on gère les effets de transparence, etc. Un chapitre entier sera dédié à ces opérations.

Les autres étapes facultatives ou moins-importantes[modifier | modifier le wikicode]

Ce qui a été dis plus haut correspond au pipeline graphique usuel, qu'on trouve dans la plupart des API 3D. Nous avons omis certaines étapes facultatives, afin de simplifier l’exposé. Par exemple, les cartes graphiques modernes supportent une étape de tesselation, qui permet de rajouter de la géométrie. Cela permet de déformer les objets ou d'augmenter leur réalisme. Cette étape est classiquement rangée dans le traitement de la géométrie. Pareil pour les geometry shaders, qui sont une nouvelle étape de traitement géométrique.

De plus, d'autres étapes nécessaires ont étés omises, pour éviter de complexifier le pipeline présenté, mais aussi car la terminologie à ce sujet est variable d'un document à l'autre. prenons les différentes opérations de culling, où les pixels/triangles/sommets non-visibles sont éliminés. Elles ne peuvent se faire qu'une fois que l'on a effectué l'étape de projection, qui centre le monde sur la caméra et se place de son point de vue. Et pour garder des performances acceptables, le culling est réalisé le plus tôt possible, donc avant l'étape de rastérisation. Formellement, le culling se place donc entre l'étape de traitement géométrique et la rastérisation. Mais certains documents/auteurs la place dans l'étape de géométrie, alors que d'autres la place dans l'étape de rastérisation. Pareil pour d'autres étapes non-mentionnées comme l'étape de primitive assembly, ou les différentes étapes de test de profondeur (censées être à la fin du pipeline dans la plupart des API, mais dont le statut en matériel et dans les API récentes est plus complexe).

Le rendu en tiles[modifier | modifier le wikicode]

Le rendu en tiles est différent sur deux points. Premièrement, l'écran est découpé en rectangles qui sont rendus séparément, là où le rendu en mode immédiat rend l'écran comme un tout qui est traité pixel par pixel. Les rectangles en question sont appelés des tiles, d'où le nom donné à la méthode. Ensuite, le rendu n'est pas composé d'une suite d'étapes consécutives. Avec le rendu en mode immédiat, les calculs se font au fil de l'eau. La carte 3D calcule une partie de la géométrie puis envoie le résultat à l'étape de rasterisation, avant d'en traiter les pixels associés. Mais avec le rendu en tiles, la géométrie est intégralement rendue avant que le traitement des pixels commence. Le résultat du calcul de la géométrie est mémorisé en mémoire vidéo, avant de démarrer la seconde étape de traitement des pixels.

La différence entre les deux est assez importante pour comprendre les avantages et inconvénients de chaque méthode. Les cartes graphiques des ordinateurs de bureau ou des ordinateurs portables sont toutes en rendu en mode immédiat. Mais les cartes graphiques des appareils mobiles, smartphones ou d'autres équipements embarqués sont de type "rendu en tiles". Les raisons à cela sont la performance. les architectures en tiles sont considérées comme moins performantes que celles en mode immédiat. Et elles sont d'autant moins performantes que la géométrie de la scène 3D est complexe. Par contre, le rendu en tiles est plus simple et plus facile à implémenter en matériel. Les architectures en tiles sont donc utilisées pour es équipements où la performance n'est pas une priorité, comme les appareils mobiles, alors que le rendu en mode immédiat est utilisé pour les ordinateurs performants (de bureau ou portable).

Le principal défaut du rendu en tiles est que le rendu se fait en deux passes, avec une mémorisation du résultat de la première passe en mémoire vidéo. Et cette mémorisation demande beaucoup de lectures et d'écritures : d'écritures pour mémoriser le résultat de la première passe, de lectures pour l'utiliser dans la seconde passe. La mémoire vidéo est donc beaucoup utilisée et doit avoir un débit suffisant. Ce qui est un désavantage pour les cartes graphiques à haute performance. L'usage de mémoires cache compense cependant encore plus le désavantage pour les architectures à tiles. Le rendu en mode immédiat et en tiles permettent tous deux l'utilisation de mémoires caches, notamment pour ce qui est des textures et des sommets. Mais le rendu en tiles permet d'utiliser des caches pour les étapes finales du traitement des pixels, là où le rendu en mode immédiat ne le peut pas vraiment. L'idée est d'utiliser un cache capable de mémoriser un tile complet, ce qui permet de finaliser le calcul du tile dans le cache et d'écrire uniquement le résultat final en mémoire vidéo. Le rendu en mode immédiat ne permet pas ce genre de facéties.

Un autre avantage des architectures en tiles est qu'elles permettent d'éliminer rapidement les portions non-affichées de la scène 3D. Le rendu en mode immédiat a certes des techniques de culling assez avancées. Mais elles sont effectuées dans l'étape de rasterization, ce qui est assez tardif comparé à ce qu'on observe sur les architectures à tiles, pour diverses raisons techniques.

Finalement, ce qui est économisé d'un côté est gaspillé de l'autre et tout est histoire de compromis. De plus, diverses optimisations spécifiques à chaque approche permettent d'éliminer des lectures/écritures "superflues", ce qui complexifie la comparaison entre les deux approches.

L'architecture d'une carte 3D en mode immédiat[modifier | modifier le wikicode]

Toute carte graphique contient obligatoirement des circuits essentiels qui ne sont pas liés au rendu 3D proprement dit, mais sont nécessaires pour qu'elle fonctionne : de la mémoire vidéo, des circuits de communication avec le bus, des circuits d’interfaçage avec l'écran, et d'autres circuits. À cela, il faut ajouter les circuits pour le rendu 3D proprement dit, qui comprennent un ensemble hétérogène de circuits aux fonctions fort différentes. Les circuits non-liés au rendu 3D sont globalement les mêmes que pour une carte d'affichage 2D, aussi nous n'en reparlerons pas ici et nous allons nous concentrer sur les circuits du pipeline graphique.

Les cartes graphiques modernes sont programmables[modifier | modifier le wikicode]

Les cartes graphiques modernes sont capables d’exécuter des programmes informatiques, comme le ferait un processeur d'ordinateur normal. Les programmes informatiques exécutés par la carte graphique sont appelés des shaders. Ils sont écrits dans un langage de haut-niveau, le HLSL pour les shaders Direct X et le GLSL pour les shaders Open Gl, puis sont ensuite traduit (compilés) en instructions machines compréhensibles par la carte graphique. Au début, ces langages et la carte graphique supportaient uniquement des opérations simples. Mais au fil du temps, les spécifications de ces langages sont devenues de plus en plus riches à chaque version de Direct X ou d'Open Gl, et le matériel en a fait autant.

Les shaders sont classifiés suivant les données qu'ils manipulent. On parle de pixel shader pour ceux qui manipulent des pixels, de vertex shaders pour ceux qui manipulent des sommets, de geometry shader pour ceux qui manipulent des triangles, de hull shaders et de domain shaders pour la tesselation, de compute shader pour des opérations sans lien avec le rendu 3D, etc. Les premiers shaders apparus étaient les vertex shaders, avec la Geforce 3 qui a rendu la gestion de la géométrie programmable. Par la suite, l'étape de traitement des pixels est elle aussi devenue programmable et les pixels shaders ont fait leur apparition. Puis d'autres formes de shaders sont apparues, pour effectuer des calculs géométriques complexes ou des calculs non-graphiques.

Les shaders sont exécutés par un ou plusieurs processeurs intégrés à la carte graphique, qui portent le nom de processeurs de shaders. Les cartes graphiques récentes contiennent un grand nombre de processeurs de shaders, plusieurs centaines.

Les unités de traitement graphique et les circuits de support[modifier | modifier le wikicode]

Toute carte graphique contient des circuits, aussi appelés unités de traitement graphiques, qui prennent en charge une étape du pipeline graphique. On trouve ainsi une unité pour le placage de textures, une unité pour l'étape de transformation, une pour la gestion de la géométrie, une unité de rasterization, une unité d'enregistrement des pixels en mémoire appelée ROP, etc. Les unités sont divisé en deux catégories : d'un côté les circuits non-programmables (dits fixes) et de l'autre les circuits programmables (les processeurs de shaders). Globalement, la gestion de la géométrie et des pixels est programmable, mais la rasterization, le placage de texture, le culling et l'enregistrement du framebuffer ne l'est pas.

Pipeline 3D : ce qui est programmable et ce qui ne l'est pas dans une carte graphique moderne.

Outre les unités du paragraphe précédent, une carte graphique contient d'autres circuits qui s'occupent de la logistique, du transfert de données ou de la répartition du travail entre les unités de traitement proprement dites. Par exemple, on trouve souvent des mémoires entre les différentes unités qui servent à mettre en attente les sommets ou les pixels, au cas où l'unité suivante est trop occupée. Divers circuits s'occupent de la gestion de ces mémoires et peuvent bloquer le démarrage de nouveau traitements si une de ces mémoires est pleine, par exemple. L'un de ces circuits de logistique les plus important est le processeur de commandes, dont nous parlerons dans quelques chapitres. Pour simplifier, il commande les différentes étapes du pipeline graphique et s'assure que les étapes s’exécutent dans le bon ordre.

Ce qu'il faut comprendre, c'est qu'une carte graphique moderne est un mélange de circuits non-programmables et de circuits programmables. L'assemblage de circuits fixes et de processeurs de shaders peut sembler contradictoire. Pourquoi ne pas tout rendre programmable ? Ou au contraire, pourquoi ne pas utiliser seulement des circuits fixes ? Le choix entre les deux parait simple. Les circuits programmables sont légèrement plus lents, mais plus flexibles, plus simples à concevoir et facilitent la vie aux programmeurs. Par contre, les circuits fixes sont plus rapides, plus économes en énergie, utilisent moins de transistors, mais sont plus compliqués à concevoir et moins flexibles. Mélanger les deux semble étrange.

La réponse rapide est qu'il s'agit d'un compromis entre flexibilité et performance qui permet d'avoir le meilleur des deux mondes. Rendre la gestion de la géométrie ou des pixels programmable est très intéressant pour le programmeur, ce qui explique qu'on a des processeurs de shader pour les vertex shaders et pixel shaders. par contre, le programmeur ne gagne pas grand chose à avoir un rastériseur programmable, mais les performances de rastérisation sont cruciales. Aussi, ce circuits est laissé non-programmable et conçu avec un circuit fixe plus rapide. Dans la fin de ce chapitre, et dans le chapitre suivant, nous allons étudier comment cette recherche du compromis a donné naissance aux cartes graphiques modernes. Nous allons voir l'évolution dans le temps des cartes graphiques à la fin de ce chapitre. Dans le chapitre suivant, nous allons voir pourquoi les vertex shaders et les pixels shaders sont apparus, en prenant l'exemple des algorithmes d'éclairage.

Un historique simplifié du hardware des cartes graphiques[modifier | modifier le wikicode]

Le hardware des cartes graphiques a fortement évolué dans le temps, ce qui n'est pas une surprise. Les évolutions de la technologie, avec l'augmentation de la miniaturisation des transistors et l'augmentation de leurs performance a permit une évolution dans laquelle les cartes graphiques ont grossit, en incorporant de plus en plus de circuits avec les années. L'évolution des cartes graphiques a suivi une évolution assez simple : elles ont acquis de plus en plus de responsabilités avec le temps. Avant l'invention des cartes graphiques, toutes les étapes du pipeline graphique étaient réalisées par le processeur : il calculait l'image à afficher, et l’envoyait à une carte d'affichage 2D. Au fil du temps, de nombreux circuits furent ajoutés, afin de déporter un maximum de calculs vers la carte vidéo. Les GPU actuels s'occupent de tous les traitements liés au moteur graphique.

Dès le début de la 3D, le choix entre circuits fixe et circuits programmables s'est fait ressentir. Les toutes premières cartes graphiques se classaient en deux camps : d'un côté les cartes graphiques complètement non-programmables, de l'autre des GPU totalement programmables. La toute première carte 3D était du premier camp : c’était la Rendition Vérité V1000. Elle contenait un processeur MIPS cadencé à 25 MHz, 4 mébioctets de RAM, une ROM pour le BIOS, et un RAMDAC, rien de plus. C'était un vrai ordinateur complètement programmable de bout en bout. Les programmeurs ne pouvaient cependant pas utiliser cette programmabilité avec des shaders, mais elle permettait à Rnedition d'implémenter n'importe quelle API 3D, que ce soit son API propriétaire ou OpenGL, voire DirectX. Mais les performances s'en ressentaient. Réaliser la rastérisation et le placage de texture en logiciel n'est pas efficace, pareil pour les opérations de fin de pipeline comme l'antialiasing. Au final, sa programmabilité était un plus pour la compatibilité logicielle, mais qui n'était pas compensé par des performances. Le manque d'unités fixes très rapides pour la rastérisation, le placage de texture ou les opérations de fin de pipeline était clairement un gros défaut.

Le second camp, celui des cartes graphiques totalement non-programmables et ne contenant que des circuits fixe, regroupe les Voodoo de 3dfx, les Riva TNT de NVIDIA, les Rage/3D d'ATI, la Virge/3D de S3, et la Matrox Mystique. Elles contenaient des circuits pour gérer les textures, quelques effets graphiques (brouillard) et l'étape d'enregistrement des pixels en mémoire. Par la suite, ces cartes s’améliorèrent en ajoutant plusieurs circuits de gestion des textures, pour colorier plusieurs pixels à la fois. Cela permettait aussi d'utiliser plusieurs textures pour colorier un seul pixel : c'est ce qu'on appelle du multitexturing. Les performances avec ces cartes étaient nettement meilleures que pour la Rendition V1000. Le fait d'avoir des circuits câblés rapides pour certaines tâches bien choisie donnait de bonnes performances, et personne n'avait la moindre utilité pour des circuits programmables à l'époque.

Carte 3D sans rasterization matérielle.

Les cartes suivantes ajoutèrent une gestion des étapes de rasterization directement en matériel. Les cartes ATI rage 2, les Invention de chez Rendition, et d'autres cartes graphiques supportaient ces étapes en hardware. De nos jours, ce genre d'architecture est commun chez certaines cartes graphiques intégrées dans les processeurs ou les cartes mères.

Carte 3D avec gestion de la géométrie.

La première carte graphique capable de gérer la géométrie fût la Geforce 256, la toute première Geforce. Son unité de gestion de la géométrie n'est autre que la bien connue T&L (Transform And Lighting). Elle implémentait des algorithmes d'éclairage de la scène 3D assez simples, comme un éclairage de Phong, qui étaient directement câblés dans ses circuits. Mais le défaut de cette approche était que ces cartes graphiques incorporaient des algorithmes d'éclairage très spécifiques, alors qu'il existe de très nombreux algorithmes d'éclairage, au point où on ne peut pas tous les mettre dans une carte graphique. Les programmeurs avaient donc le choix entre programmer les algorithmes d’éclairage qu'ils voulaient ou utiliser ceux de la carte graphique.

Carte 3D avec gestion de la géométrie.

À partir de la Geforce 3 de Nvidia, les unités de traitement de la géométrie sont devenues programmables. L'avantage était que les programmeurs n'étaient pas limités aux algorithmes implémentés dans la carte 3D pour obtenir de bonnes performances. Ils pouvaient programmer l'algorithme d'éclairage qu'ils voulaient et pouvaient le faire exécuter directement sur la carte graphique. Les unités de traitement de la géométrie deviennent donc des processeurs indépendants, capables d’exécuter des programmes appelés Vertex Shaders. Ces shaders sont écrits dans un langage de haut-niveau, le HLSL ou le GLSL, et sont traduits (compilés) par les pilotes de la carte graphique avant leur exécution. Au fil du temps, les spécifications de ces langages sont devenues de plus en plus riches et le matériel en a fait autant. D'autres types de shaders ont été inventés : pixels shaders pour le traitement de pixels, shaders de géométrie, shaders génériques, etc. Les premiers à faire leur apparition furent les pixel shaders, suivis par les geometry shaders et les shaders pour la tesselation.

Pour résumer, l'évolution des cartes 3D s'est faite d'une manière assez complexe. Le compromis entre circuits fixes et programmables a été difficile à trouver. Les concepteurs ont procédé par essais et erreurs, jusqu'à trouver le compromis actuel. Les premières cartes graphiques sont parties sur deux pistes totalement opposées : d'un côté une carte totalement programmable, de l'autre des cartes avec des circuits fixes non-programmables. L'échec de la Rendition Vérité 1000, totalement programmable mais avec de trop faibles performances, a orienté le marché dans la seconde direction. Les cartes 3D ont alors incorporé des circuits de rastérisation et de placage/filtrage de texture, qui sont toujours là de nos jours. Elles ont ensuite intégré des circuits de calculs géométrique, avant de revenir en arrière pour les remplacer par des circuits programmables. Leur programmabilité s'est ensuite accrue, en incorporant des processeurs capables d’exécuter n'importe quel algorithme, mais sans revenir sur les circuits fixes établis. Expliquer pourquoi demande cependant d'y passer un chapitre entier, ce qui est le sujet du chapitre suivant.