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

Documents pareils