Emporte Une Vache !!!

dimanche, septembre 18, 2005

OpenGL, la 3D

Je viens d'arrêter mon job d'été (SVG/ASP je bloguerai sûrement un jour là-dessus) pour commencer un autre stage.

Il s'agit d'un stage plutôt technique où je dois refaire un système d'affichage un peu vieillot en utilisant OpenGL et le dernières techniques d'affichage. Par dernières techniques, disons depuis la 2ème génération de cartes 3D Geforce, depuis l'apparition des vrais GPU.


Expériences avec la programmation 3D

Personnellement mon expérience avec OpenGL se limitait à des bidouilles peu optimisées, où j'avais des milliers de vertices que j'envoyais un par un (j'avais quand même une idée de ce qu'étaient les displaylists) et que je faisais transformer par les fonctions OpenGL que tout le monde utilisait... En gros, ma connaissance d'OpenGL devait s'arrêter à la version 1.1. Pas bien fameux.

J'ai essayé Direct3D ensuite aussi, à l'époque de DirectX7 je crois... Une expérience sympa. Même si j'ai des mauvais souvenirs avec C++/COM...

J'ai découvert Java3D ensuite, dans le cadre d'un projet Java de 2ème année à la FIIFO. Très enthousiasmant, à la première approche. En un week-end j'avais construit un package de classes pour la manipulation d'un personnage composé de sphères "rotatées, scalées, et translatées" =o). Tout allait très vite. Je découvrais Eclipse en même temps. Je n'avais jamais pris autant de plaisir à coder (je devrais bloguer sur Eclipse un jour...). Les performances étaient bien pauvres mais suffisantes pour animer une vingtaine de sphères texturées. Le projet s'est bien passé et j'ai eu un bon résultat.

Ensuite j'ai acheté un bouquin sur OpenGL 1.4, et j'ai découvert les vertex arrays, me suis un peu amusé avec les fonctionnalités de textures avancées (le bus AGP s'améliorant toutes les 2 semaines :-)). Rien de bien fameux. Le problème était toujours le même. Dès que j'essayais de faire la moindre chose un peu sympa la masse de modifications à appliquer sur un code déjà pas terrible me décourageait très, très vite. Et évidemment, chaque modification rendait l'application horriblement lente... Bref, j'ai laissé tomber.

Et pendant 2 ans j'ai vu les nouveaux jeux, les nouvelles cartes, entendu les nouveaux buzzwords "pixel/vertex shaders", "tesselation", "HLSL", "Cg", "Vertex unit"... On aurait dit que les performances brutes avaient explosé, que les CPU des machines avaient aussi explosé. En voyant la complexité des scènes des jeux vidéos récents, je me suis dit qu'ils avaient multiplié par 150 les capacités d'affichage de génération en génération...

C'est bien ce qu'il s'est passé =o) (quoique 150 c'est peut-être un peu en-dessous de la réalité). Mais cela ne suffit pas. Si la carte vidéo peut transformer 150 milliards de vertices à la seconde, il faut bien les produire quelque part ces vertices. Je ne comprenais pas le "progrès" et l'enthousiasme pour les cartes 3D...

La programmabilité du GPU

Le sujet de mon stage concerne l'utilisation de "shaders OpenGL". J'avais une vague idée ce que c'était. Quand je dis vague, je pensais C'est une fonctionnalité *moderne* qui trouve plein d'enthousiastes et peut-être qu'on pourra gagner 2% de performances avec ça... J'étais, comme d'habitude, bien loin de m'imaginer l'intérêt de cette fonctionnalité.

  • Première illumination : un vrai langage C-like pour les shaders
le langage de shading OpenGL est en fait un langage exécuté par le GPU. On programme le GPU par ce langage. On lui fait effectuer des opérations par vertex et par fragment (on dit par pixel sous DirectX).

Donc, à chaque appel à glVertex, on définit soi-même les opérations qui seront effectuées sur le vertex. Transformation, illumination, calcul de normal, coloration... Et on définit aussi les opérations effectuées sur les pixels interpolés (fragments). Texturage, coloration, illumination per-fragment... Tout le code OpenGL qu'on aurait placé en amont dans le glBegin / glEnd avec les 300 changements d'états (si on a mal regroupé les éléments de ses modèles =o)), on le déporte dans 2 fichiers sources .vert et .frag et on se contente de lier nos objets à ces programmes...

Bien sûr, ce n'est pas aussi simple. Il y a toute une procédure à respecter. Lecture du source, compilation par OpenGL (en ligne !), link des programmes, instanciation, binding, et ensuite définition des paramètres.

Les paramètres ! Grâce à eux, on peut paramétrer (!) les opérations effectuées dans un shader. L'exemple le plus attrayant est l'animation de particules. Supposons que vous voulez calculez la trajectoire des particules avec une fonction (du genre les bonnes vieilles fonctions de physique de Terminale S).

Vous construisez un shader qui prend comme paramètre une variable temps. Vous placez vos 4000 vertices sur une grille. Vous bindez votre shader à cette grille de vertices. Ensuite, quand vous le souhaitez, incrémentez le paramètre temps et réaffichez. Chaque vertex va être transformé en fonction de ses coordonnées de départ, et du temps courant. Plus besoin de parcourir soi-même des listes sans-fin de vertices, de leur appliquer une transformation "à la main"...

On dispose maintenant d'un moyen d'effectuer des traitement pour chaque vertex ET pour chaque fragment !

Sans parler des possibilités offertes : faire faire des calculs très lourds au GPU pour alléger le CPU. Le GPU est très fort en calcul de matrices par exemple... Il est capable par exemple d'exécuter un calcul de matrice 4x4 floats aussi vite que la multiplication 1x1 float... Il ne s'agit pas que d'une révolution dans le graphisme...

  • Deuxième illumination : les zones en mémoire vidéo/serveur enfin utilisables
Il y a eu beaucoup de travail effectué chez NVidia pour réduire les goulets d'étranglement CPU et bus AGP. Ayant déjà essayé à une époque lointaine d'utiliser des vertex arrays, j'en gardais un mauvais souvenir. Envoyer beaucoup de vertices (des centaines de milliers) avec même très peu de calcul à faire derrière (pas d'illumination, pas de texture...) à la carte la mettait très vite à genoux. Le phénomène est simple à comprendre et la solution était "évidente". La lenteur appraissait (entre autres) parce que les tableaux de vertices étaient stockés dans la mémoire application, chez le client (OpenGL est très orienté Client/Serveur). A chaque dessin il fallait renvoyer tout le tableau de vertices au serveur (la carte vidéo) pour lui faire faire le transform & lightning... Quelle efficacité !

J'ai appris la suite de l'histoire récemment. NVidia a créé un extension appelée VAR ou NVAR (pour NVidia Vertex Array Range). Cette extension permettait de réserver des zones en mémoire vidéo, AGP, ou application... Ainsi on évitait les aller-retour... Si simple ? Pas vraiment.

D'une part, cette extension avait une limitation au début, au niveau du nombre de vertices : 64K vertices au maximum... peu intéressant. Cette limitation a été levée avec le Geforce3. Mais surtout cette approche cassait le modèle client/serveur d'OpenGL, puisqu'un client avait accès à une zone mémoire serveur comme si elle était chez lui, et celle-ci n'était absolument pas verrouillée. En plus, il fallait que les développeurs codent leurs propres procédures d'allocation (comment savoir si j'ai déjà réservé cette place, en ai-je toujours besoin) ce qui rendait la programmation avec NVAR peu agréable et fiable.

NVidia (ou un autre constructeur...) a donc créé les VBO/PBO. Il s'agit des Vertex Buffer Object (et Pixel BO...). Il s'agit de permettre de réserver des buffers simplement, de dire où l'on souhaite qu'ils se trouvent (client, serveur). On peut les mapper (les bloquer en lecture/écriture), et l'allocation est gérée par le driver.

Vraiment je ne peux pas attendre lundi/mardi pour "jouer" avec les VBO et voir les différences de performances... Peut-être le million de vertices/frame. C'est le premier but.

From the bottom-up

-- digression
J'ai lu mon premier jour de stage les 5 premiers chapitres du svn handbook. Et il y a une introduction d'un chapitre qui dit à peu près ceci (traduction anglaise plus qu'approximative) : certaines personnes apprennent plus efficacement en partant du bas.

Je suis de ces gens-là. Je comprends mieux si je vois d'abord un bon exemple qu'en 2 jours de cours abstraits sur le pourquoi du comment. Je commence par un exemple. Et rapidement je comprends comment fonctionne X. Ensuite, je peux mieux comprendre le pourquoi du comment parce que j'ai une idée de comment ça fonctionne. Je n'ai peut-être pas toutes les subtilités, et mon esprit est sûrement "corrompu" par ce cambouis sur les mains et par une expérience concrète trop précipitée =o).
-- fin digression

J'ai lu le livre d'introduction "OpenGL Shading Language" rapidement, en une journée, et reparcouru rapidement le red book OpenGL pour me remettre dans le bain... C'était même plus qu'idéal : mon tuteur m'avait laissé un exemple de code qui fonctionnait : une application utilisant Glut (fenêtrage et la théïère) et les "derniers" drivers NVidia sous linux.

Je me suis lancé dans la lecture du code. Qui fait quoi ? Pourquoi ? si j'enlève ça qu'est-ce qu'il se passe ? si je fais ça avant est-ce que ça marche toujours ? Si je demande 1000 fois plus de vertices, est-ce que c'est toujours utilisable ?

Et en 2 heures j'avais déjà un premier résultat sympathique. J'ai vite compris comment ça fonctionnait et j'ai repris le livre sur les shaders pour mieux le comprendre. En 3 jours j'avais déjà de quoi faire une toute petite démonstration où j'affichais, en utilisant un shader, 200000 vertices/frame à quelques dizaines de fps.

Conclusion, et ensuite ?

Mon premier contact avec les dernières technologies 3D est vraiment enthousiasmant et je commence à comprendre l'engouement général. Je me demande d'ailleurs pourquoi il n'est pas plus important.

J'ai des souvenirs d'application de calcul qui auraient grandement bénéficié d'une utilisation intensive du GPU. Je pense à des applications de cartographie/géodésie qui demandent des calculs assez lourds (projection conique, cylindrique, interpolation linéaire, changement de système géodésique à 7 paramètres...) et qui en général faisaient s'effondrer un Athlon 2400+... Je pense aussi au projet SETI ou encore à ce projet de dépliage de protéines... Je pense aussi à POV... Augmenter la puissance d'un cluster en rajoutant des cartes graphiques ?

Une bonne semaine. En plus d'un nouvel environnement de travail, de nouveaux collègues, de nouvelles technos, un bon langage (Ada), une mise en selle rapide, et un bonheur de vendredi soir : "J'ai bien bossé"

Et maintenant j'ai envie de m'acheter un Geforce 6800 :-).

1 Comments:

  • ...une application utilisant Glut (fenêtrage et la théïère) et les "derniers" drivers NVidia sous linux.
    Je me suis lancé dans la lecture du code. Qui fait quoi ? Pourquoi ? si j'enlève ça qu'est-ce qu'il se passe ? si je fais ça avant est-ce que ça marche toujours ? Si je demande 1000 fois plus de vertices, est-ce que c'est toujours utilisable ?


    Hé hé, ça pourrait être un exemple de How To Become A Hacker. Ça fait vraiment plaisir d'arriver à apprendre de cette manière, et encore plus de travailler avec des gens qui apprécient cette façon de penser.
    Dommage que si peu de personnes aient cette mentalité dans la promo, de ce que j'en ai vu.

    So far so goude, tes posts sont de bonne qualité, sans trop de Touisteur-OMG!!111 et avec du Lionel inside, et sans mode MAVIE.
    J'attendais ça depuis un moment, en espérant que ça continue...

    By Blogger Yogi, at 15/10/05 02:44  

Enregistrer un commentaire

<< Home