GPU - Luc Claustres
Transcription
GPU - Luc Claustres
Programmation des processeurs graphiques et langage Cg Cours de Synthèse d’Images - SUPAERO Luc Claustres - [email protected] Objectifs • Processeurs graphiques programmables • Programmation par flots • Cg – langage – API OpenGL – performances GPU programmables : objectifs • Comparaison CPU ↔ GPU • Programmable Render Pipeline • Shading Languages CPU vs GPU • Les processeurs graphiques évoluent rapidement – précision : calculs flottants sur 32 bits – performances : supérieures au CPU – programmabilité : langages haut-niveau • Performances + Flexibilité → Apparition du GPGPU – calculs génériques sur les processeurs graphiques – applications très variées • • • • rendu avancé : éclairage global, basé image calculs scientifiques : PDE, systèmes linéaires, dynamique calculs géométriques … CPU vs GPU • Les GPU possèdent des spécificités => portage délicat • Architecture massivement parallèle – sommets – fragments • Pas d’accès direct à la mémoire • Instructions vectorielles (SIMD) • Architecture très secrète CPU vs GPU Architecture NV40 les pixels pipelines sont regroupés par quatre (quads) caches de texture 6 vertex pipelines 16 pixel pipelines CPU vs GPU • Puissance de calcul – Pentium4 3 GHz théorique : 6 GFLOPS, 5.96 Go/sec peak – GeForceFX 5900 observée : 20 GFLOPs, 25.3 Go/sec peak – GeForce 6800 Ultra observée : 40 GFLOPs, 35.2 Go/sec peak • Evolution et croissance – CPU : annuelle ~ 1.5× → par décade ~ x 60 (loi de Moore) – GPU : annuelle > 2.0× → par décade > x 1000 • Explications – économique : marché du jeu (18 milliards de $ en 2003) – spécialisation : ajout de transistors + simple CPU vs GPU CPU vs GPU 10000 1000 Mpixels/s Mvertices/s Mtransistors 100 1 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 BUS mémoire API GPU : Historique • 1ère génération (…-1998) : Voodoo3, NV TNT2, ATI Rage – transformation par le CPU, opérations mathématiques limitées • 2ème génération (1999-2000) : GeForce2, Radeon 7500, Savage3D – transformation et éclairage par le GPU, configurable ≠ programmable • 3ème génération (2001) : GeForce3, GeForce4 Ti, Radeon 8500, XBox – vertex engine programmable, pixel engine configurable • 4ème génération (2002) : GeForce FX, Radeon 9700 – vertex engine programmable, pixel engine programmable GPU : Historique • • • • process : plus petite unité de traitement en micron transistors : mesure approximative de la complexité fill rate : en million de pixels RGBA par seconde polygon rate : en million de triangles par seconde OpenGL : Historique • • • • • • • • 1992 : première spécification (version 1.0) 1993 : premières implémentations (SGI) 1997 : vertex arrays/texture objects (version 1.1) 1998 : 3D textures (version 1.2) 2001 : cube maps/multi-compressed textures (version 1.3) 2002 : shadow maps/blending/mipmaps… (version 1.4) 2003 : vertex buffers/occlusion/!2n textures (version 1.5) 2004 : vertex-fragment programs (version 2.0) Evolution : OpenGL Architecture Review Board (ARB) 3Dlabs, Apple, ATI, Dell, Evans & Sutherland, Hewlett-Packard, IBM, Intel, Matrox, NVIDIA, SGI, Sun Microsystems, Microsoft, Compaq, DEC Extensions OpenGL • Objectif principal – adéquation implémentation OpenGL et capacités matérielles • Chaque extension est documentée à bas niveau pour – permettre son intégration hardware par les constructeurs – permettre son implémentation software dans le driver • Cycle de vie d’une extension 1) implémentation spécifique (NVidia, ATI, SGI, …) 2) implémentation générique (approbation consensuelle ou ARB) 3) nouvelle fonctionnalité du cœur d’OpenGL (v 1.0 → v 1.1) Extensions OpenGL • Nomenclature des extensions – Génériques • ARB : extensions officielles approuvées par l’Architectural Review Board • EXT : extensions communes à plusieurs distributeurs de matériel – Spécifiques • • • • • • • • • HP : Hewlett-Packard IBM : International Business Machines INTEL : Intel NVIDIA : NVIDIA Corporation ATI : ATI Technologies Inc. MESA : implémentation gratuite de Brian Paul (Linux) SGIX : Silicon Graphics (généralement experimental) SUN : Sun Microsystems WIN : Microsoft Corporation – Systèmes • WGL : Microsoft Windows • GLX : X Window Extensions OpenGL • Nom d’une extension – GL + préfixe de nomenclature + nom : GL_EXT_vertex_array • Obtenir les extensions disponibles glGetString(GLenum name) – GL_VERSION : version de l’implémentation (driver) – GL_RENDERER : identifiant du matériel (carte 3D) – GL_VENDOR : nom du fournisseur de l’implémentation – GL_EXTENSIONS : liste des extensions disponibles • Vérifier si une extension est présente GLboolean glCheckExtension(char *name, GLubyte *extensions) Extensions OpenGL • En pratique – obtenir un header intégrant les extensions : glext.h / wglext.h – l’existence de chaque extension est signalée par des macros #define GL_EXT_vertex_array – nouvelles fonctions suffixées par le code de nomenclature glPointParameterfEXT(), wglQueryPbufferARB() – nouvelles constantes suffixées par le code de nomenclature GL_DISTANCE_ATTENUATION_EXT, WGL_TEXTURE_RGBA_ARB – récupérer un pointeur vers les nouvelles fonctions (Windows) GPU programmables : objectifs • Comparaison CPU ↔ GPU • Programmable Render Pipeline • Shading Languages Render Pipeline états graphiques Application Application Transform Transform sommets (3D) CPU Rasterizer Rasterizer sommets transformés, attribués (2D) fragments (pré-pixels) GPU Fragment Fragment Operations Operations pixels (couleur) Mémoire Mémoire Vidéo Vidéo (Textures) (Textures) Programmable Render Pipeline états graphiques Application Application sommets (3D) Vertex Vertex Engine Engine CPU Rasterizer Rasterizer sommets transformés, attribués (2D) fragments (pré-pixels) GPU vertex program Fragment Fragment Engine Engine pixels (couleur) Mémoire Mémoire Vidéo Vidéo (Textures) (Textures) render-to-texture fragment program Programmable Render Pipeline sommets transformés et éclairés assemblage de primitives Vertex Program exécuté par le Vertex Engine une fois pour chaque sommet discrétisation interpolation et texturage Fragment Program exécuté par le Fragment Engine une fois par fragment Render Pipeline Modèle OpenGL 1.5 Programmable Render Pipeline Modèle OpenGL 2.0 Vertex Processor • Ce qui peut/doit être fait – – – – – – – projection des sommets transformation/normalisation des normales éclairage génération/transformation des coordonnées de texture calcul de la coordonnée de brouillard calcul de la taille de la primitive GL_POINT calculs des plans de clipping Vertex Processor • Ce qui ne peut pas être remplacé – – – – – évaluateurs (Bézier, NURBS) clipping par le volume de visualisation division perspective transformation de viewport élimination des faces arrières/avant • Pas d’ajout/suppression de sommet – 1 sommet en entrée = 1 sommet en sortie Vertex Processor Fragment Processor • Autorise/Contrôle – – – – la couleur finale (éclairage) l’accès aux textures et l’application de textures l’application du brouillard plus généralement : opérations sur les attributs interpolés • N’autorise/Ne contrôle pas – – – – le mélange les tests (alpha, stencil, Z) le mode d’accès aux textures (filtrage, etc.) lecture du framebuffer Fragment Processor Flot Mémoire CPU CPU Vertex Vertex program program Fragment Fragment program program Frame Frame buffer buffer CPU CPU Vertex Vertex program program Fragment Fragment program program Frame Frame buffer buffer Vertex Vertex program program Fragment Fragment program program CPU CPU Readback Copy-to-Texture Render-to-Texture Vertex Vertex program program Fragment Fragment program program Accès texture depuis le vertex program (NV40) Programmable Render Pipeline Structuration d’une application 3D nouvelle génération (NVidia) GPU programmables : objectifs • Comparaison CPU ↔ GPU • Programmable Render Pipeline • Shading Languages Shading Languages • Application, API 3D et Driver : C/C++ • Vertex/Fragment Programs : ASM, Cg, HLSL, GLSL Shading Languages • Pourquoi ? – programmer en assembleur est une tâche complexe – les processeurs actuels gèrent des programmes comportant plusieurs centaines d’instructions – avantages de la programmation haut-niveau • simplicité, portabilité, ré-utilisabilité, débogage Shading Languages Shading Languages • Assembleur – extensions ARB_vertex_program et ARB_fragment_program • GLSL – spécifique à OpenGL (>= 2.0) – portable entre les différents matériels graphiques – intégré à l’implémentation (driver) • HLSL – spécifique à DirectX (>= 9.0) • Cg – compatible HLSL – librairie RT + compilateur Shading Languages programmes GLSL / HLSL / Cg attributs de sommet attributs interpolés fragments Dans le futur il est probable que d’autres parties du pipeline graphique seront programmables via des langages de haut-niveau Shading Languages • Spécification des shaders via l’API 3D – programmes – activation/désactivation • Commandes de tracé habituelles – textures (activation, chargement, filtrage) – géométrie (immediate/retain mode) – composition • Les programmes sont automatiquement exécutés – pour chaque sommet – pour chaque fragment Shading Languages • Compilation spécifique à un matériel donnée (profil) – optimisation des performances – utilisation des fonctionnalités additionnelles – limiter les programmes pour un matériel moins performant • Exemple – vertex programs : vs_1_1, vs_2_0, vs_3_0 – fragment programs : ps_1_1, ps_2_x, ps_2_a, ps_3_0 • Actuellement les versions 3.0 sont les plus évoluées – GeForce 6 seulement Objectifs • Processeurs graphiques programmables • Programmation par flots • Cg – langage – API OpenGL – performances Programmation par flots : objectifs • Modèles de parallélisme • Programmation générique sur GPU Parallélisme • SISD : Single Instruction, Single Data – une opération sur une donnée à tout instant – machine Von Neuman séquentielle (PC) • SIMD : Single Instruction, Multiple Data – mêmes opérations en // sur un ensemble de données – exemple typique : calculs vectoriels – parallélisme de données Parallélisme • MISD : Multiple Instruction, Single Data – différentes opérations en // sur une même donnée • MIMD : Multiple Instruction, Multiple Data – programmes indépendants exécutés en // – parallélisme de tâches – mémoire partagée/distribuée Parallélisme • Loi de Amdalh, toute tâche comporte – une partie séquentielle – une partie parallélisable • Quand le nombre de processeurs augmente – le temps d’exécution de la partie parallélisable → 0 – le temps d’exécution de la partie séquentielle reste constant partie parallélisable temps d’exécution # de processeurs partie séquentielle Parallélisme • Les GPU exploitent deux approches : SIMD & MIMD – parallélisme de tâches : plusieurs pipelines – parallélisme de données (sommets, triangles, spans, fragments) SISD CPU SIMD Vertex/Fragment Engine Multithreaded SIMD GPU Parallélisme • Le problème majeur est la répartition de la charge – les triangles sont de taille variable – chaque triangle génère de nombreux spans – chaque spans génère de nombreux fragments – toute unité de traitement inactive pendant un cycle est perdue Parallélisme • Le second problème majeur est la lenteur des bus • Sur le CPU – stratégies élaborées de cache (plusieurs niveaux, etc.) – inacceptable pour de hautes performances • Sur le GPU – latence → puissance de calcul – pipes multiples avec ALU multiples – pipe GeForce3 : 800 cycles Parallélisme • Le second problème majeur est la lenteur des bus • CPU et GPU disposent pour accélérer les calculs de – registres – caches • Le GPU dispose en + de son propre espace d’adressage – – – – les données doivent être copiées avant utilisation il s’agit classiquement du goulot d’étranglement pas d’accès à la mémoire CPU pas d’accès au disque Programmation par flots : objectifs • Modèles de parallélisme • Programmation générique sur GPU GPGPU • Modèle d’architecture par flots • Flot (Stream) – ensemble de données nécessitant un même traitement – données indépendantes • Noyau (Kernel) – fonction appliquée à chaque élément d’un flot – calculs indépendants appliqués de façon FIFO – réduit les problème de latence et de cache • GPU : chaque pixel est une machine SIMD virtuelle – données d’entrée par pixel + accès à une mémoire globale – pas d’écriture aléatoire en sortie GPGPU • Exemple typique : grille de calcul – représentée par une texture • Algorithme de la simulation – composée de pas – chaque pas met à jour la grille entière – un pas doit se terminer avant de débuter le suivant • Grille ↔ Flot • Pas ↔ Noyaux (appliqués sur chaque texel) diffusion • Communication dans les grilles – les cellules voisines partagent de l’information collecte GPGPU • Flots de données sur un GPU textures sommets attribués vertex processor rasterizer fragment processor frame buffer • Ressources – processeurs parallèles programmables – textures : mémoire en lecture seule – frame buffer (render-to-texture) : mémoire en écriture seule GPGPU • Rôle du rasterizer – tracer des triangles ! OU de façon plus générale – – – – diffuser une valeur interpoler une donnée générer une adresse (coordonnée de texture) réaliser différentes opérations par sous-image GPGPU • Vertex Processor – – – – capable de diffusion mais pas de collecte possibilité de changer la position du sommet pas d’accès aux informations des sommets voisins accès aléatoire aux textures sur les derniers GPU • Fragment Processor – – – – capable de collecte mais pas de diffusion adresse de sortie fixée (pixel) accès aléatoire aux textures typiquement plus utile : + de pipes, collecte, sortie GPGPU • Analogies CPU GPU – mémoire ↔ texture – accès ↔ lecture d’un texel – noyau/pas d’algorithme ↔ fragment program CPU GPU GPGPU • Analogies – chaque pas dépend du résultat du précédent – écriture du résultat ↔ render-to-texture … grid[i][j]=x … CPU GPU GPGPU • Analogies – lancer un calcul ↔ tracer la géométrie – calcul sur tous les pixels ↔ tracer un quad couvrant l’écran 1. initialiser la vue glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 1, 0, 1, 0, 1); glViewport(0, 0, W, H); 2. pour chaque pas d’algorithme – – – – activer le p-buffer activer les textures activer les programmes tracer un quad glBegin(GL_QUADS); glVertex3f(0, 0, 0); glVertex3f(0, 1, 0); glVertex3f(1, 1, 0); glVertex3f(1, 0, 0); glEnd(); GPGPU • Exemple : calcul du mouvement des vagues résolution des équations d’onde stockage de la position des sommets modification de la position des sommets GPGPU • Créer un mesh pour représenter la surface – plan finement maillé – stocker la position des sommets dans une texture – nécessite une texture flottante (height map) • Render-to-Texture pour calculer la nouvelle altitude – intégration de Verlet • Accès à la texture pour modifier l’altitude des sommets – depuis le vertex shader GPGPU • Exemple : système de particules • Problème des N-corps – chaque particule attire toutes les autres – interactions gravitationnelles complexes • Gravitation • Répulsion GPGPU • Render-to-Texture pour la mise à jour – – – – lire l’état courant du système depuis la texture calculer la valeur des forces au pas suivant écrire le nouvel état du système dans la texture utiliser cet état pour rafraîchir la simulation • Données stockées – position – vitesse – force • 1 particule = 1 texel GPGPU • Faire interagir les N particules – ne nécessite qu’un triangle : F(a,b) = -F(b,a) – flip * -1 pour le reste du calcul • Sommer toutes les forces – mélange additif • Appliquer la force aux particules – mettre à jour la vitesse – texture Nx1 v Fdt v’ GPGPU • Structures de données : tableaux – 1D → 2D – 3D → 2D • Outrepasser les limitations de l’espace d’adressage – actuellement 4096 pixels : 4096² = 16 777 216 – texels RGBA flottants → 256Mo • Textures 3D + filtrage matériel – 512 pixels seulement à plat en coupe GPGPU • Structures de données : tableaux d’objets – stocker chaque membre dans un tableau différent (texture) – utiliser les MRT pour la mise à jour • Structures de données : pointeurs – adresses stockées dans une texture – accès texture indirect texture d’adressage texture de données GPGPU • Branchement – stratégie de prédiction sur CPU Pred A IF (C) { A P S C } ELSE { B B } Succ • MIMD : aucune pénalité – chaque processeur prend une branche différente – possible sur les vertex processors des GeForce6 GPGPU • SIMD : problème de performance – certains processeurs terminent l’exécution du noyau de calcul avant les autres suivant les branches exécutées – temps d’exécution final ~ temps des branches simultanées – efficace en cas de cohérence « spatiale » des conditions – possible sur les vertex/fragment processors des GeForce6 Pred A IF (C) { A } ELSE { B } Succ P S C B GPGPU • Sur les architectures plus vieilles – la branche exécutée et non exécutée sont évaluées – la condition est évaluée et positionne un code – chaque instruction de branche vérifie son code avant écriture éventuelle de son résultat dans un registre • Coûteux si les branches sont relativement longues • Effectuer une résolution statique si possible – trier les données par résultat de la condition – exécuter deux programmes différents par groupe GPGPU • Boucle : mêmes problèmes de performance – boucle statique (possibilité de la dérouler) – boucle dynamique (cohérence nécessaire) Pred WHILE (C) { A P } S C A Succ Pred DO { A } WHILE (C) Succ P S A C GPGPU • Langages dédiés – simplifier la programmation parallèle – axés algorithme et non implémentation – inutile de connaître OpenGL, DirectX, extensions ATI/NV • Sh – Université de Waterloo – http://libsh.sourceforge.net, http://www.cgl.uwaterloo.ca • Brook – Université de Stanford – http://brook.sourceforge.net, http://graphics.stanford.edu Objectifs • Processeurs graphiques programmables • Programmation par flots • Cg – langage – API OpenGL – performances Langage Cg : objectifs • Présentation • Types • Fonctions • Flot d’éxécution • Gestion des textures Langage Cg • NV Shading Language haut-niveau et open-source • Assembleur → Language ~ C (Cg = C for Graphics) • Développé en collaboration avec Microsoft (HLSL) • Multi-API (OpenGL/DirectX) • Multi-plateformes (Windows, Linux, Mac OS) Langage Cg • Création des shaders – from scratch – repository • Importation des shaders – applications 3D (CAO, …) – moteurs de rendu • Compilation – à la volée / pré– ciblée Langage Cg Cg intégré dans les applications standards édition et compilation directe de code Cg Langage Cg • Compilateur (cgc) • Librairie Standard • Librairies RT DirectX & OpenGL • Spécification du language • Manuel utilisateur • Shaders • Browser Langage Cg Profils • Profil = sous-ensemble de fonctionnalités Cg disponible sur une architecture donnée • DirectX – 8.0 : CG_PROFILE_{V,P}S_1_X (RT) / {v,p}s_1_x (compilateur) – 9.0 : CG_PROFILE_{V,P}S_2_X (RT) / {v,p}s_2_x (compilateur) • OpenGL – ARB : CG_PROFILE_ARB{V,F}P1 (RT) / arb{v,f}p1 (compilateur) – NV2X : CG_PROFILE_{V,F}P20 (RT) / {v,f}p20 (compilateur) – NV30 : CG_PROFILE_{V,F}P30 (RT) / {v,f}p30 (compilateur) Langage Cg : objectifs • Présentation • Types • Fonctions • Flot d’éxécution • Gestion des textures Types simples • float, 1.0f : nombres réels 32-bits IEEE (s23e8) • half, 1.0h : nombres réels 16-bits (s10e5) • fixes, 1.0x : nombres réels [-2,2) 12-bits (s1.10) • bool : booléen • int : entier 32-bits • pas de pointeurs pour l’instant Types simples • Typage implicite des calculs via constantes • En langage C la plus haute précision est utilisée half x,y; x = y * 2.0; // Calcul en float • En langage Cg la précision des variables est conservée half x,y; x = y * 2.0; // Calcul en half • Il est possible de forcer le changement de précision half x,y; x = y * 2.0f; // Calcul en float Types vectoriels • Type simple avec dimension • Vecteurs : typeN, 1 <= N <= 4 • Matrices : typeMxN, 1 <= M <= 4, 1 <= N <= 4 – organisées en colonnes d’abord – une colonne d’une matrice est un vecteur • Accès aux données – indirect : vecteur[i], matrice[i][j] – direct : constantes pré-définies r,g,b,a ou x,y,z,w ! le premier est moins efficace ! • Constructeurs à la C++ : type(…) Masking & Swizzle • Swizzle = extraction des éléments d’un vecteur • Masking = spécification des éléments assignés • V.1234 : construction syntaxique représentant l’organisation des éléments au sein du vecteur – vecteurs : chaque position = x/r, y/g, z/b, ou w/a – matrices : chaque position = _mij Masking & Swizzle • Exemple de code Types complexes • struct {…} : structures – similaire au langage C – utilisées pour les paramètres d’entrée/sortie des programmes • type …[N] : tableaux – – – – similaire au langage C ne sont pas des pointeurs ne sont pas des vecteurs : float4 ≠ float [4] l’affectation copie toutes les valeurs Types de variables • Uniforme (uniform) – identique pour chaque sommet dans un vertex program – identique pour chaque fragment dans un fragment program – exemples : couleur de la lumière, matrice de transformation, … • Variable (varying) – différente pour chaque sommet dans un vertex program – différente pour chaque fragment dans un fragment program – exemples : position, normale, coordonnées de texture, … • Locale (local) – pour calculs intermédiaire dans un vertex/fragment program Types de variables • Les paramètres uniform sont typiquement identiques – – – – entre une paire de glBegin() / glEnd() pour le tracé d’un objet pour le tracé d’un groupe d’objets pour le tracé de la scène • Les paramètres varying des sommets sont leurs attributs – possibilité de les spécifier via l’application – utilisation des vertex arrays/VBO • Les paramètres varying des fragments sont les attributs interpolés – impossible de les spécifier via l’application Attributs de sommet • Paramètres variant par sommet – – – – – – position normale couleur primaire et secondaire coordonnées de texture (8) coordonnée de brouillard attributs supplémentaires • Associés aux données application par une sémantique – POSITION, NORMAL, COLOR{0,1}, FOG, TEXCOORD{0-8} • Fonctionne avec les appels directs, vertex arrays, VBO Attributs de sommet • Lien possible via une structure d’entrée struct VertexIn { float4 position : POSITION, float3 normal : NORMAL }; void main(VertexIn vertex) { … } • Lien possible directement void main(float4 position : POSITION, float3 color : COLOR) { … } Attributs interpolés • Potentiellement tous les attributs de sommets – sorties du vertex program = entrées du fragment program • Lien possible via une structure de sortie struct VertexOut { float4 position : POSITION }; VertexOut main(VertexIn vertex_in, uniform float4x4 matrix) { VertexOut vertex_out; … vertex_out.position = mul(matrix, vertex_in.position); … return vertex_out; } Attributs de fragment • Couleur : COLOR{0,3} • Profondeur : DEPTH • Taille du point : PSIZE • Lien possible via une structure de sortie • Lien possible directement void main(out float4 color : COLOR, out float depth : DEPTH) OU float4 main(VertexOut p_FragmentIn) : COLOR Langage Cg : objectifs • Présentation • Types • Fonctions • Flot d’éxécution • Gestion des textures Fonctions • Absence de pointeurs – pas de passage par référence implicite • Spécification explicite du rôle des paramètres – entrée : in – sortie : out – entrée-sortie : inout • Surcharge possible – nombre de paramètres – type des paramètres (pratique avec autant de types de base) – type du profil Fonctions • Exemple de code function f1(in float3 color, inout float x, out float y) { x = x + 1.0; y = (color.r + color.g + color.b) / 3.0; } float f2(float3 color, inout float x) { x = x + 1.0; return (color.r + color.g + color.b) / 3.0; } function same(float a, float b) { … } function same(bool a, bool b) { … } Librairie Standard • Fonctions mathématiques – – – – – – – – – – – – abs(x) : valeur absolue ceil(x) : + petit entier ≥ x floor(x) : + grand entier ≤ x round(x) : entier le + proche de x clamp(x, a, b) : borne x dans [a,b] fmod(x, y) : reste de x/y du même signe que x frac(x) : partie fractionnaire min(a, b) , max(a , b) : calculs min/max lerp(a, b, f) : interpolation linéaire (1-f) * a + f * b exp(x), exp2(x), ldexp(x, n) : ex, 2x, x * 2n log(x), log2(x), log10(x) : logarithme naturel, en base 2, en base 10 pow(x, y) : xy Librairie Standard • Fonctions mathématiques sqrt(x), rsqrt(x) : √x, 1/ √x saturate(x) : clamp(x, 0, 1) sign(x) : signe de x smoothstep(min, max, x) : interpolation d’Hermite noise(x) : fonction de bruit de Perlin modf(x, i) : séparation partie intégrale/fractionnaire (retournée) frexp(x, e) : séparation partie fractionnaire normalisée dans [-1/2,1/2] (retournée) et une puissance de deux – isfinite(x) : vrai si la valeur de x est finie – isnan(x) : vrai si la valeur de x n’est pas un nombre – isinf(x) : vrai si la valeur de x est infinie – – – – – – – Librairie Standard • Fonctions trigonométriques – – – – – – – – – – – – cos(x) : cosinus cosh(x) : cosinus hyperbolique sin(x) : sinus sinh(x) : sinus hyperbolique tan(x) : tangente tanh(x) : tengente hyperbolique sincos(x, s, c) : calcule simultanément sin/cos (+ efficace) acos(x) : arc cosinus asin(x) : arc sinus atan(x) : arc tangente atan2(y,x) : arc tangente de y/x radians(x), degrees(x) : conversions radians ↔ degrés Librairie Standard • Fonctions vectorielles/matricielles – all(x) : vrai si tous les éléments du vecteur sont ≠ 0 – any(x) : vrai si un élément du vecteur est ≠ 0 – mul(x, y) : – transpose(x) : matrice transposée Librairie Standard • Fonctions géométriques – – – – – – – dot(a, b) : produit scalaire cross(a, b) : produit vectoriel length(x) : longueur d’un vecteur distance(a, b) : distance entre deux points normalize(x) : normalisation d’un vecteur reflect(i, n) : vecteur réfléchi de i par rapport à n refract(i, n, eta) : vecteur réfracté de i par rapport à n pour une interface d’indice de réfraction eta – faceforward(n, i, ref) : dot(ref,i) < 0 ? n : -n • Fonctions diverses – ddx(a), ddy(a) : dérivées partielles de a / coordonnées écran x et y Librairie Standard • Fonctions de packing/unpacking (profils évolués) – pack_2half : 2 réels 16/32 bits → 32 bits – unpack_2half : 32 bits → 2 réels 16 bits – pack_2ushort : 2 réels 16/32 bits → 2 entiers 16 bits – pack_2ushort : 32 bits → 2 réels 16/32 bits Librairie Standard • Fonctions de packing/unpacking (profils évolués) – pack_4byte : 4 réels 16/32 bits → 32 bits – unpack_4byte : 32 bits → 4 réels 16 bits Librairie Standard • Fonctions de packing/unpacking (profils évolués) – pack_4ubyte : 4 réels 16/32 bits → 32 bits – unpack_4ubyte : 32 bits → 4 réels 16 bits Langage Cg : objectifs • Présentation • Types • Fonctions • Flot d’éxécution • Gestion des textures Structures de contrôle • If-Then-Else – nécessite une condition booléenne – ! performances ! Structures de contrôle • For-While – similaires au C ANSI – boucles statiques/dynamiques • dépend du profil – multi-passes → passe unique Langage Cg : objectifs • Présentation • Types • Fonctions • Flot d’éxécution • Gestion des textures Textures • Types – – – – – sampler1D : texture 1D, fonction d’atténuation, rampe sampler2D : texture 2D, shadow map, normal map, etc. sampler3D : texture 3D, données volumiques, etc. samplerCUBE : cube map, normalization, environment samplerRECT : image 2D, texture 2D flottante • L’accès à une donnée nécessite – une texture – des coordonnées de texture • 1D, 2D, 3D : [0,1] • CUBE : direction 3D • RECT : [largeur, hauteur] Textures • Accès sans projection selon le type – – – – – tex1D(sampler1D tex, float coord) : texture 1D tex2D(sampler2D tex, float2 coords) : texture 2D tex3D(sampler3D tex, float3 coords) : texture 3D texCUBE(samplerCUBE tex, float3 coords) : cube map texRECT(samplerRECT tex, float2 coords) : image 2D • Accès avec projection : coordonnée supplémentaire – – – – – tex1D(sampler1D tex, float2 coord_q) : texture 1D tex2D(sampler2D tex, float3 coords_q) : texture 2D tex3D(sampler3D tex, float4 coords_q) : texture 3D texCUBE(samplerCUBE tex, float4 coords_q) : cube map texRECT(samplerRECT tex, float3 coords_q) : image 2D Textures • Shadow maps : comparaison de z – l’unité de texture doit être configurée pour – – – – – tex1D(sampler1D tex, float2 coord_z) : texture 1D tex2D(sampler2D tex, float3 coords_z) : texture 2D tex3D(sampler3D tex, float4 coords_z) : texture 3D texCUBE(samplerCUBE tex, float4 coords_z) : cube map texRECT(samplerRECT tex, float3 coords_z) : image 2D • Accès sans/avec projection et dérivée – – – – – tex1D(sampler1D tex, float coord, float dx, float dy) : texture 1D tex2D(sampler2D tex, float2 coords , float2 dx, float2 dy) : texture 2D tex3D(sampler3D tex, float3 coords , float3 dx, float3 dy) : texture 3D texCUBE(samplerCUBE tex, float3 coords , float3 dx, float3 dy) : cube map texRECT(samplerRECT tex, float2 coords , float2 dx, float2 dy) : image 2D Textures • Textures non spécifiables directement en Cg – passage depuis l’application via des paramètres uniformes void main(float2 texCoord, uniform sampler2D textureMap, uniform samplerCUBE envMap) { … } • Sémantique : unité de texture associée void main(float2 texCoord, uniform sampler2D textureMap : TEXUNIT0, uniform samplerCUBE envMap : TEXUNIT1) { … } Textures • Préparation « classique » car – filtrage non spécifiable directement en Cg – répétition non spécifiable directement en Cg Objectifs • Processeurs graphiques programmables • Programmation par flots • Cg – langage – API OpenGL – performances CgGL • Pour exécuter un programme Cg il faut – le compiler avec le profil correspondant au matériel – le lier à l’application • paramètres uniformes • paramètres variables • A cause de la large variété de profils – – – – la compilation se fait généralement au Run-Time permet de tirer partie des optimisations futures permet de fonctionner sur de futur matériels/profils plus lent qu’une pré-compilation CgGL • Cg Run-Time – Core : fonctions et structures encapsulant le RT #include <Cg/cg.h>, préfixe cg – OpenGL : fonctions spécifiques à OpenGL #include <Cg/cgGL.h>, préfixe cgGL – DirectX : fonctions spécifiques à DirectX #include <Cg/cgD3D8.h>, préfixe cgD3D8 #include <Cg/cgD3D9.h>, préfixe cgD3D9 CgGL • Contexte ↔ Containeur – de programmes – de données partagées • Création/Destruction CGcontext cgCreateContext() void cgDestroyContext(CGContext context) • Validation CGbool cgIsContext(CGcontext context) CgGL • Création/Destruction de programmes – compile aussi le programme – à partir d’un code en mémoire CGprogram cgCreateProgram(CGcontext context, CGenum type, const char *program, CGprofile profile, const char *entry, const char **args) – à partir d’un fichier contenant le code source CGprogram cgCreateProgramFromFile(…) void cgDestroyProgram(CGProgram program) CgGL • Création de programmes – – – – type : CG_SOURCE, CG_OBJECT entry : nom de la fonction principale (main) profile : profil cible pour la compilation args : liste d’arguments passés au compilateur • Obtention du meilleur profil disponible CGprofile cgGLGetLatestProfile(CG_GL_{VERTEX, FRAGMENT}) • Obtention des meilleurs options de compilation void cgGLSetOptimalOptions(CGprofile profile) CgGL • Exemple de code CgGL • Validation de programme CGbool cgIsProgram(CGprogram program) • Recompilation CGbool cgIsProgramCompiled(CGprogram program) void cgCompileProgram(CGprogram program) CGprogram cgCopyProgram(CGprogram program) • Résultat de la compilation const char *cgGetLastListing(CGcontext context) CgGL • Les programmes sont stockés séquentiellement CGprogram cgGetFirstProgram(CGcontext context) CGprogram cgGetNextProgram(CGprogram program) CGprogram program = cgGetFirstProgram(context); while (program != NULL) { // Gérer le programme … program = cgGetNextProgram(program); } CgGL • Exécution de programmes 1. chargement du programme : résultat de compilation → API void cgGLLoadProgram(CGprogram program) 2. activation/désactivation du profil void cgGLEnableProfile(CGprofile profile) void cgGLDisableProfile(CGprofile profile) 3. activation du programme : change le programme courant void cgGLBindProgram(CGprogram program) CgGL • Accès indirect aux paramètres CGparameter cgGetFirstParameter(CGprogram program, CGenum namespace) CGparameter cgGetNextParameter(CGparameter parameter) CGparameter param = cgGetFirstParameter(program, CG_PROGRAM); while (param != NULL) { // Gérer le paramètre … param = cgGetNextParameter(param); } CgGL • Accès direct aux paramètres CGparameter cgGetNamedParameter(CGprogram program, const char *name) • Utilisation de la syntaxe Cg pour les structures/tableaux CgGL • Types des paramètres CGtype cgGetParameterType(CGparameter param) – CG_STRUCT, CG_ARRAY , CG_FLOATn , CG_HALFn , CG_SAMPLER* • Noms des paramètres const char*cgGetParameterName(CGparameter param) • Sémantique des paramètres CGressource cgGetParameterRessource(CGparameter param) • Spécification de la valeur des paramètres – différenciation des paramètres vectoriels, matriciels, textures – cache : inutile de toujours mettre à jour un paramètre uniforme CgGL • Paramètres scalaires et vectoriels void cgGLSetParameter[1234]{fd}[v](CGparameter param, const type [*] xyzw) void cgGLGetParameter[1234]{fd}(CGparameter param, type * xyzw) • Paramètres matriciels void cgGLSetMatrixParameter{fd}{rc}(CGparameter param, const type [*] matrix) void cgGLGetMatrixParameter{fd}{rc}(CGparameter param, type * matrix) ordonnée en ligne ou colonne CgGL • Matrices d’états OpenGL void cgGLSetStateMatrixParameter(CGparameter parameter, GLenum matrix, GLenum transform) CG_GL_MODELVIEW_MATRIX : modélisation-vue CG_GL_PROJECTION_MATRIX : projection CG_GL_TEXTURE_MATRIX : texture CG_GL_MODELVIEW_PROJECTION_MATRIX : modélisation-vue + projection CG_GL_MATRIX_IDENTITY : pas de transformation CG_GL_MATRIX_TRANSPOSE : transposition CG_GL_MATRIX_INVERSE : inversion CG_GL_MATRIX_INVERSE_TRANSPOSE : inversion et transposition Cg vs GLSL • Modèles d’éxécution Cg GLSL Cg vs GLSL • Similarités – – – – – – – – – syntaxe C types mots clefs opérateurs identifieurs expressions variables uniformes structures de contrôle librairie standard Cg vs GLSL • Différences – entrées/sorties des programmes • structures ↔ variables – compilateur • externe à l’API ↔ interne à l’API – édition de lien en GLSL – accès aux états OpenGL • explicite ↔ implicite – Cg supporte le type half Objectifs • Processeurs graphiques programmables • Programmation par flots • Cg – langage – API OpenGL – performances Performances 1. Travailler en vectoriel le compilateur fait de son mieux pour trouver et optimiser les opérations vectorielles, mais plus le code original est vectorisé meilleure sera l’optimisation Performances 2. Utiliser le masquage le GPU peut réarranger les éléments d’un vecteur sans perte en performances, très utile lorsque les mêmes composantes ne sont pas utilisées des deux côtés d’une expression Performances 3. Utiliser la librairie standard les fonctions de la librairie standard ont été implémentées dans un souci de validité et d’efficacité, il est impossible de les optimiser car certaines sont directement compilées en instructions GPU utiliser la fonction dot() prédéfinie de la librairie standard Performances 4. Discrétiser les fonctions complexes dans des textures l’accès à une texture avec filtrage est très efficace sur les profils le supportant, si une fonction est lisse l’interpolation suffit souvent nécessite généralement une normalisation des valeurs de f Performances 5. Utiliser les types de précision minimale requise les calculs sont plus rapides en fixed qu’en half, et en half qu’en float 6. Eviter les transpositions de matrices inutiles l’inversion d’un produit vecteur-matrice peut le permettre Performances 7. Fragment processor → Vertex processor les fragments programs sont souvent beaucoup plus exécutés que les vertex programs, y transférer tout calcul de résultat qui • • • est constant par fragment varie linéairement sur un triangle (interpolation) varie quasi-linéairement sur un triangle (plausibilité) 8. Effectuer des pré-calculs sur le CPU passer les résultats comme paramètres uniformes des programmes Performances 9. Minimiser le code conditionnel une instruction conditionnelle tend à être exécuté à la même vitesse que celle atteinte si toutes ses branches étaient exécutées, mieux vaut disposer de plusieurs programmes (un par branche) et d’activer le programme correspondant lorsqu’il est possible dévaluer la condition sur le CPU en résumé ! Penser GPU et non pas CPU ! Liens • www.nvidia.com : Cg toolkit + exemples de codes • www.gpgpu.org : portail pour le GPGPU • www.cgshaders.org : de nombreux exemples • www.realtimerendering.com : panel exhaustif • http://www.shadertech.com : articles, exemples de codes Livres • The Cg Tutorial :The Definitive Guide to Programmable Real-Time Graphics • GPU Gems I et GPU Gems II • Real-Time Rendering