Se connecter avec
S'enregistrer | Connectez-vous

NV40/R420(?) : la troisième génération

3 années d’évolution des shaders : un bilan
Par
Cette troisième version des shaders a généré beaucoup d’incompréhension en grande partie parce que c’est la première fois qu’une nouvelle version est disponible sans mise à jour du runtime de DirectX. Dans un premier temps il convient donc, je pense, d’éclaircir les choses à ce propos : oui les shaders 3.0 sont d’ores et déjà disponibles dans la version standard de DirectX 9.0. Pour l’instant, comme aucun hardware ne gère encore cette génération de shaders, elle n’est accessible qu’en mode logiciel via le Reference Rasterizer de l’API. Cependant même si l’interface assembleur des Vertex Shaders 3.0 et des Pixel Shaders 3.0 est incluse dans DirectX 9, il n’existe à l’heure actuelle aucune compile target permettant de générer des shaders 3.0 depuis le HLSL. Par conséquent Microsoft devra faire une mise à jour du SDK lors de la disponibilité des nouveaux chips 3D gérant cette version de shaders. En particulier il devra mettre à jour le compilateur contenu dans la lib D3DX. A priori ça ne change rien au niveau du runtime qui n’a, de toute façon à son niveau, aucune connaissance du HLSL mais uniquement de l’assembleur. Cependant, comme cela a été précisé par Microsoft, pour mettre un terme à beaucoup de confusions à propos d’un éventuel DirectX 9.1:

“Some of the confusion may be due to us shipping support for 3.0 shader models in the DirectX 9 runtime. This was specifically to reduce the amount of churn in the API. When some 3.0 hardware is produced we'll evaluate how close the API fits the hardware (there's always some tuning), and we may need to release an update - but remember the definitions, this would most likely be a "letter" change runtime release, not a "minor".”

Autrement dit une mise à jour du runtime aura peut être lieu pour adapter l’interface aux puces définitives mais ce ne sera pas une nouvelle révision de l’API et surtout ça n’apportera pas le support des shaders 3.0 : le support est déjà là, tout ce qu’il faut c’est au pire une phase de raffinage.

Vertex Shaders 3.0

Après ce petit éclaircissement nous pouvons maintenant nous pencher sur cette nouvelle version et, comme d’habitude, nous allons commencer par les Vertex Shaders. Si vous avez lu cet article depuis le début vous devriez déjà vous attendre à ce que je vais vous dire car l’enchaînement est logique. Une fois de plus nous avons donc droit à une nouvelle augmentation des limites de certaines ressources en particulier le nombre d’instructions qui passe de 256 à 512. Le nombre de registres temporaires connaît lui aussi une évolution, passant de 12 à 32.

Une des grandes nouveautés de cette nouvelle version est elle aussi prévisible : après le contrôle de flux statique, c’est au tour du contrôle de flux dynamique de faire son apparition. Comme nous l’avons vu le contrôle de flux statique ne peut opérer que sur des constantes, leur modification ne pouvant avoir lieu qu’entre deux appels de rendu. A l’inverse le contrôle de flux dynamique permet d’adapter le code en fonction des attributs d’un sommet. La flexibilité offerte est énorme car il est désormais possible d’effectuer des opérations de branchement au niveau du sommet (alors qu’auparavant c’était au niveau de l’ensemble des sommets partageant le même shader). Enfin un autre intérêt du branchement dynamique se situe au niveau des performances : il est dés lors possible de désactiver des portions du code en fonction des caractéristiques du sommet. Un exemple simple serait d’effectuer un test sur l’angle entre le vecteur normal et le vecteur lumière, et selon le résultat d’activer ou non les calculs d’éclairage

En pratique il convient toutefois de relativiser le gain induit par cette méthode. D’une part parce que l’instruction de branchement a un coût, et ensuite parce que les gains varieront d’une implémentation à une autre : il n’est en effet pas évident de gérer efficacement les branchements dans des architecture très fortement pipelinées. C’est le problème d’Intel avec son P4 dont le pipeline compte 20/31 étages alors imaginez avec un GPU dont le nombre d’étages se compte en centaines !

Les branchements dynamiques ne sont pas la seule nouveauté des Vertex Shaders 3.0 qui autorisent également désormais un véritable échantillonnage de texture au sein d’un programme. Le niveau de fonctionnalité et de flexibilité de l’adressage de textures rejoint donc celui des Pixels Shaders. Contrairement à la version disponible dans les Vertex Shaders 2.0 où les données de texture apparaissaient sous la forme d’un registre, il s’agit désormais d’instructions permettant d’accéder réellement et à n’importe quel endroit du programme à une texture par le biais de coordonnées. La seule restriction concerne le filtrage : il n’est pas possible d’utiliser le filtrage anisotropique, et de plus il est nécessaire de passer le niveau de MIP adressé lors de l’instruction d’échantillonnage. Mais hormis ceci tout le reste fonctionne comme dans un Pixel Shader : les coordonnées de texture peuvent être modifiées, tout comme le niveau de MIP, il peut y avoir des indirections (adressages de textures dépendants) sans aucune restriction. Mais quel est l’intérêt de lire une texture dans un Vertex Shader ? La première utilisation, c’est d’autoriser enfin un véritable Displacement Mapping un peu à la manière de celui qu’a introduit Matrox avec son Parhelia. Sauf qu’au lieu d’utiliser une unité dédiée cette fois la solution est totalement générique laissant un contrôle total de l’implémentation au programmeur. Il est également possible d’imaginer de complexes algorithmes multipasses dans lesquels un calcul serait effectué une seule fois avant d’être stocké dans une texture pour pouvoir être ensuite réutilisé. Encore une fois il faut se débarrasser du concept d’images lorsqu’on parle d’une texture et voir bien plus loin : une texture ne reste jamais qu’une fonction et peut donc servir de table de précalculs tout comme on le fait dans un Pixel Shader.