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éos utilisent de la 3D, même s'il existe encore quelques jeux en 2D. Face à la prolifération de ces jeux vidéos 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éos 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 physique du 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 de 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éos 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, amis aussi 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.

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

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. 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éos.

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 frustrum).

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. Il porte le nom de view frustrum. Suivant la perspective utilisée, ce volume n'a pas la même forme. Avec la perspective usuelle, le view frustrum 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 frustrum est un pavé, mais nous n'en parlerons pas plus dans le cadre de ce cours.

Un point important du rendu 3D est que ce qui est en-dehors du view frustrum n'est pas affiché à l'écran et ne doit pas être calculé ou rendu. Mais il se peut que certains objets situés dans le view frustrum 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. Toujours est-il que ce qui n'est pas affiché ne doit pas être calculé ou rendu et 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.

Il existe plusieurs grands types de culling. Le premier est le view frustrum culling, dont le nom indique qu'il s'agit de l'élimination de tout ce qui est situé en-dehors du view frustrum, ce qui n'est pas dans le champ de vision de la caméra. Le second type est l'élimination des objets masqués par d'autres, appelé l'occlusion culling. Le troisième type est l'élimination des parties arrières d'un objet. Ne pas calculer la géométrie de ces faces n'est pas possible, mais on peut abandonner les calculs d'éclairage ou de placage de texture.

View frustum culling : les parties potentiellement visibles sont en vert, celles invisibles en rouge et celles partiellement visibles en bleu.
Occlusion culling : les objets en bleu sont visibles, ceux en rouge sont masqués par les objets en bleu.

Pour le view frustrum culling, un soin particulier doit être pris pour les triangles dont une partie seulement est dans le champ de vision. Ils doivent être découpés en plusieurs triangles, tous présents intégralement dans le champ de vision. Les algorithmes pour ce faire sont assez nombreux et il serait compliqué d'en faire une liste exhaustive, aussi nous laissons le sujet de coté pour le moment.

Clipping/View frustrum culling dans le cadre d'un écran de forme carrée (en gris).

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]

Le 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éos. 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éos. 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éos 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 dy 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, l'ensemble étant appelé le pipeline graphique. Le cas le plus simple ne demandant que trois étapes :

  • 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 détermine quelle partie de l'image 3D s'affiche à l'écran, et qui attribue chaque sommet/triangle à un pixel donné de l'écran ;
  • une étape de traitement des pixels, classiquement divisée en une étape de placage de textures et une étape d'enregistrement des pixels en mémoire.

Dans certains cas, des traitements supplémentaires sont ajoutés. Mais ces étapes rajoutées peuvent être vues comme des subdivisions des trois étapes précédentes. 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. Tout cela pour dire que l'organisation en trois étapes est très pédagogique, en plus d'être terriblement efficace.

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

  • La première étape place les objets au bon endroit dans la scène 3D. Lors de la modélisation d'un objet, celui-ci est encastré dans un cube : un sommet du cube possède la coordonnée (0, 0, 0), et les vertices de l'objet sont définies à partir de celui-ci. Pour placer l'objet dans la scène, il faut tenir compte de sa localisation, calculée par le moteur physique : si le moteur physique a décrété que l'objet est à l'endroit de coordonnées (50, 250, 500), toutes les coordonnées des vertices de l'objet doivent être modifiées. Pendant cette étape, l'objet peut subir une translation, une rotation, ou un gonflement/dégonflement (on peut augmenter ou diminuer sa taille). C'est la première étape de calcul : l'étape de transformation.
  • Ensuite, les vertices sont éclairées dans une phase d'éclairage. Chaque vertice se voit attribuer une couleur, qui définit son niveau de luminosité : est-ce que la vertice est fortement éclairée ou est-elle dans l'ombre ?
  • Vient ensuite une phase de traitement de la géométrie, où les vertices sont assemblées en triangles, points, ou lignes, voire en polygones. Ces formes géométriques de base sont ensuite traitées telles quelles par la carte graphique. 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.
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.

À la suite de cela, 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. 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 visibilité sont effectués pour éliminer certains pixels cachés, l'antialiasing est ajouté, etc.

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 tile 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 tile est plus simple et plus facile à implémenter en matériel. Les architectures en tile 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 à tile. Le rendu en mode immédiat et en tile permettent tous deux l'utilisation de mémoires caches, notamment pour ce qui est des textures et des sommets. Mais le rendu en tile 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 une tile complète, ce qui permet de finaliser le calcul de la 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 tile 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 coté 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]

Avant l'invention des cartes graphiques, toutes ces é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 circuits d'une carte graphique varie grandement selon son degré de sophistacation. Les premières cartes graphiques ne faisaient pas grand chose et le processeur ne leur déléguait que peu de calculs. Mais avec l'évolution des technologies, de plus en plus de calculs de rendu ont été délégués à la carte graphique. Cela s'en ressent sur l'organisation des circuits des cartes graphiques. Si certains circuits sont toujours présents sur toutes les cartes graphiques, d'autres ont étés ajoutés progressivement, au fil des années.

Répartition du travail entre processeur et GPU, sur les cartes graphiques récentes. On voit que le GPU s'occupe des traitements liés au moteur graphique, tandis que les autres traitements (son, physique) sont pris en charge par le processeur.

Toute carte graphique contient obligatoirement 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. A cela, il faut ajouter les circuits pour le rendu 3D proprement dit. Ces derniers sont regroupés dans un ensemble hétérogène de circuits aux fonctions forts différentes. Il est composé de circuits non-programmables (dits fixes) et de circuits programmables. Conceptuellement, on sépare les circuits fixes et programmables dans deux sous-pipelines séparés, ce qui permet de faire la distinction entre pipeline programmable qui regroupe les circuits programmables et le pipeline fixe pour le reste. Mais cette distinction est purement conceptuelle et ne correspond pas vraiment à la manière dont les circuits sont organisés réellement. Le pipeline graphique est secondé par des circuits qui s'occupent de lire/écrire des textures et vertices depuis la mémoire vidéo. Ces deux circuits portent le nom d'unité de texture et d'input assembler.

Architecture de base d'une carte 3D - 1

Les circuits essentiels[modifier | modifier le wikicode]

La mémoire vidéo est nécessaire pour stocker l'image à afficher à l'écran, mais aussi pour mémoriser temporairement des informations importantes. Dans le cas le plus simple, elle sert simplement de Framebuffer : elle stocke l'image à afficher à l'écran. Au fil du temps, elle s'est vu ajouter d'autres fonctions, comme stocker les textures et les vertices de l'image à calculer, ainsi que divers résultats temporaires. Elle est très proche des mémoires RAM qu'on trouve sous forme de barrettes dans nos PC, à quelques différences près. En premier lieu, la mémoire vidéo peut supporter un grand nombre d'accès mémoire simultanés. Ensuite, elle est optimisée pour accéder à des données proches en mémoire.

La carte graphique communique via un bus, un vulgaire tas de fils qui connectent la carte graphique à la carte mère. Les premières cartes graphiques utilisaient un bus nommé ISA, qui fût rapidement remplacé par le bus PCI, plus rapide. Viennent ensuite le bus AGP, puis le bus PCI-Express. Ce bus est géré par un contrôleur de bus, un circuit qui se charge d'envoyer ou de réceptionner les données sur le bus. Les circuits de communication avec le bus permettent à l'ordinateur de communiquer avec la carte graphique, via le bus PCI-Express, AGP, PCI ou autre. Il contient quelques registres dans lesquels le processeur pourra écrire ou lire, afin de lui envoyer des ordres du style : j'envoie une donnée, transmission terminée, je ne suis pas prêt à recevoir les données que tu veux m'envoyer, etc.

Le circuit d’interfaçage avec l'écran permet à la carte graphique d'envoyer à l'écran une image à afficher. Enfin, on trouve naturellement des circuits qui s'occupent des rendus 2D et 3D proprement dit.

Les circuits du pipeline fixe[modifier | modifier le wikicode]

Toute carte graphique contient des circuits, aussi appelés unités, qui prennent en charge une étape du pipeline graphique. Entre les différentes unités, on trouve souvent des mémoires pour mettre en attente les vertices ou les pixels, au cas où une unité est trop occupée. Pour plus d'efficacité, ces cartes graphiques possédaient parfois plusieurs unités de traitement des vertices et des pixels, ou plusieurs ROP. Dans ce cas, ces unités multiples sont précédées par un circuit qui se charge de répartir les vertex ou pixels sur chaque unités. Généralement, ces unités sont alimentées en vertex/pixels les unes après les autres (principe du round-robin).

Tout les traitements que la carte graphique doit effectuer, qu'il s'agisse de rendu 2D, de calculs 2D, du décodage matérielle d'un flux vidéo, ou de calculs généralistes, sont envoyés par le pilote de la carte graphique, sous la forme de commandes. 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 file (une zone de mémoire dans laquelle on stocke des données dans l'ordre d'ajout) : le tampon de commandes. Ensuite, ces commandes sont interprétées par un circuit spécialisé : le processeur de commandes. Celui-ci est chargé de piloter les circuits de la carte graphique.

Les toutes premières cartes graphiques contenaient simplement des circuits pour gérer les textures, en plus de la mémoire RAM vidéo. Seules l'étape de texturing, quelques effets graphiques (brouillard) et l'étape d'enregistrement des pixels en mémoire étaient prises en charge par la carte graphique. 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 cartes graphiques construites sur cette architecture sont très anciennes. On parle des cartes graphiques ATI rage, 3DFX Voodoo, Nvidia TNT, etc.

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 commune 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 simples, comme un éclairage de Phong, qui étaient directement câblés dans ses circuits. Nous étudierons d'ailleurs cette unité et les algorithmes qu'elle utilise dans quelques chapitres.

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

Les circuits du pipeline programmable : vertex et pixels shaders[modifier | modifier le wikicode]

A partir de la Geforce 3 de Nvidia, les unités de traitement de la géométrie sont devenues programmables. Cela permet une grande flexibilité, à savoir que changer le comportement ne nécessite pas de re-câbler tout le circuit. 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. Par la suite, l'étape de traitement des pixels est elle aussi devenue programmable et les pixels shaders (programmes de traitement de pixels) ont fait leur apparition. Par la suite, d'autres types de shaders ont été inventés : shaders de géométrie, shaders génériques, etc. 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.

Les premières cartes graphiques avaient des jeux d'instructions séparés pour les unités de vertex shader et les unités de pixel shader, et les processeurs étaient séparés. Pour donner un exemple, c'était le cas de la Geforce 6800. Cette séparation entre unités de texture et de vertices était motivée par le fait que les unités de vertice n’accédaient jamais à la mémoire, contrairement aux unités de traitement de pixels qui doivent accéder aux textures.

Carte 3D avec pixels et vertex shaders non-unifiés.

Depuis DirectX 10, ce n'est plus le cas : le jeu d'instructions a été unifié entre les vertex shaders et les pixels shaders, ce qui fait qu'il n'y a plus de distinction entre processeurs de vertex shaders et de pixels shaders, chaque processeur pouvant traiter indifféremment l'un ou l'autre. Cela a un avantage considérable, car tous les jeux vidéo n'ont pas les mêmes besoins. Certains vont avoir une géométrie très développées mais peu de besoin en termes de textures ou d'effets de post-processing. Ceux là gagnent à avoir beaucoup d'unités de gestion de la géométrie et peu d'unités de traitement des pixels. A l'inverse, d'autres jeux vidéos ont besoin de beaucoup de puissance de calcul pour traiter les pixels, mais arrivent à économiser énormément sur la géométrie. L'usage de shaders unifiés permet d'adapter la répartition entre vertex shaders et pixels shaders suivant les besoins de l'application, là où la séparation entre unités de vertex et de pixel ne le permettait pas.

Carte 3D avec pixels et vertex shaders unfifiés.