Vous êtes sur la page 1sur 37

GPGPU

Implmentation dun simple


oprateur algbrique linaire sur
GPU: saxpy()

Objectif
Lopration saxpy() :
un exemple simple
ne require pratiquement aucun background
en algbre linaire
illustre trs bien les concepts GPGPU.
Consiste calculer y = y + alpha * x
avec x et y vecteurs de longueur N et alpha une
valeur scalaire

Configuration de OpenGL-GLUT
GLUT (OpenGL Utility Toolkit), :
fournit des fonctions pour grer les vnements windows
Permet de crer de simples menus
etc. (voir http://raphaello.univ-fcomte.fr/ig/opengl/Glut.htm)

Nous lutiliserons pour configurer un OpenGL valide afin


daccder au priphrique graphique, travers lAPI GL,
avec le minimum de ligne de code possible
#include <GL/glut.h>

// inclue le fichier header GLUT

// A appeler partir du main()


void initGLUT(int argc, char **argv) {
glutInit ( &argc, argv );
glutCreateWindow(" TEST SAXPY");
}
3

Configuration de OpenGL-GLEW
La plupart des mcanismes requis pour faire du GPGPU
ne font pas partie du noyau dOpenGL
GLEW (OpenGL Extension Wrangler) est une libraire qui
tend OpenGL pour avoir plus de contrle sur le matriel
travers lAPI OpenGL
Dautres extensions OpenGL sont disponibles
ladresse http://www.opengl.org/registry/
Il est possible dexplorer les extensions supportes par
la carte graphique avec les outils :

glewinfo (qui est fournit avec GLEW)


OpenGL extension viewer
GPU Caps Viewer
Etc.
4

Interface minimalistique
void initGLEW (void)
{
// initialiser GLEW et obtenir les pointeurs sur les fonctions
int err = glewInit();
// Attention : Ce code ne teste pas si lextension est supporte par le matriel
// dans le cas chant glewInit() sera gale NULL
if (err!=GLEW_OK)
{
printf((char*)glewGetErrorString(err));
exit(ERROR_GLEW);
}
}

Prparation de OpenGL pour un


rendu offscreen
Dhabitude, le pipeline graphique se termine au niveau
du frame buffer
La taille max des donnes du frame buffer est de 32
bit (RGBA)
soit 8 bit par couleur  16 millions de couleurs
Chaque couleur prend une valeur entre 0 et 256

Pour pouvoir avec des rels on peut stocker des


donnes au format IEEE 32-bit :
SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF=(-1)s2e-1271.f

Lextension OpenGL appele EXT_framebuffer_object


permet dutiliser un offscreen buffer (FBO) pour stocker
les vecteurs des rendus
6

Utilisation de lextension
EXT_framebuffer_object

GLuint fb;
void initFBO(void) {
// crer un FBO (off-screen framebuffer)
glGenFramebuffersEXT(1, &fb);
// se brancher sur offscreen buffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
}

GPGPU concept 1:
tableaux = textures
Pour le CPU :
nativement sur une seule dimension
accds moyennant des indices a[i][j]=a[i*M+j]

Pour le GPU :
nativement sur 2 dimensions
supporte 1 et 3 dimensions mais implique des pnalits sur les
performances
Laccs se fait moyennant des coordonnes de textures
appels textures ou texture samplers
les dimensions des textures sont limites (peuvent tre obtenues
par une requte OpenGL une fois GLUT initialis)
int maxtexsize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxtexsize);
printf("GL_MAX_TEXTURE_SIZE, %d\n",maxtexsize);
8

Cration des tableaux sur CPU


Rappelons que lon souhaite calculer
y = y + alpha * x
Nous avons besoin de 2 tableaux de rels X et Y
de taille N et dun rel alpha
Ces donnes seront allous et initialiss par le
CPU malgr que le calcul sera effectu sur GPU
float* dataX = (float*)malloc(N*sizeof(float));
float* dataY = (float*)malloc(N*sizeof(float));
float alpha;
9

Cration de textures avec des


nombres virgule flottante sur GPU
On va limiter la prsentation 2 texture 2D :
La texture traditionnelle dans OpenGL : GL_TEXTURE_2D
Lextension OpenGL : ARB_texture_rectangle plus facile
utiliser par des non graphistes)
Texture2D

Texture rectangle

Texture cible

GL_TEXTURE_2D

GL_TEXTURE_RECTANGLE_ARB

Coordonnes
des textures

Doivent tre normalises


lintervalle [0,1] sur [0,1]
indpendament de la dimension
[0,M] sur [0,N] de la texture

Ne sont pas normaliss

Dimensions
des textures

Doivent tre une puissance de 2


sauf si le pilote supporte
lextension
ARB_non_power_of_two ou quil
prsente OpenGL 2.0

Les dimensions peuvent tre


arbitraires

10

Format des textures


Le GPU permet le traitement simultan de :
Scalaires : GL_LUMINANCE est le format de texture
adapt pour stocker une seule valeur en virgule
flottante par texel  32 bits / texel
Tuples
Triples
Quadriples : GL_RGBA est le format de texture
adapt pour stocker quatre valeur en virgule flottante
par texel  128 bits / texel

11

Formats internes pour les textures


Il existe 3 extensions OpenGL qui prsentent des
formats pour les nombres virgule flottante pour les
textures :
NV_float_buffer
ATI_texture_float
ARB_texture_float

Chaque extension dfinit un ensemble dnumrants


(ex. : GL_FLOAT_R32_NV) et des symboles (ex.
0x8880) qui peuvent tre utiliss pour dfinir et allouer
les textures
12

Enumrants
Les numrants des 2 formats de textures auxquels
nous nous intressons sont :
GL_FLOAT_R32_NV : informe le GL que nous souhaitons
stocker un seul nombre virgule flottante par texel
GL_FLOAT_RGBA32_NV : stocke un 4-tuplet de nombres
virgule flottante

Les 2 extensions ATI_texture_float et ARB_texture_float


sont identiques sauf quils dfinissent diffrents numrant pour
le mme symbol (cest une question de prfrences)
sont supportes par les carte GeForce 6 (ou +) et ATI
ont pour numrants respectifs

GL_LUMINANCE_FLOAT32_ATI
GL_RGBA_FLOAT32_ATI
GL_LUMINANCE32F_ARB
GL_RGBA32F_ARB
13

Mapping CPU-GPU
Comment associer un vecteur (CPU) une
texture (GPU) ?
La solution la plus simple :
Pour les formats LUMINANCE : Associer un vecteur de taille
N (on suppose que N est une puissance de 2) une texture
de taille sqrt(N) par sqrt(N)
Pour les formats RGBA : Associer un vecteur de taille N
une texture de taille sqrt(N/4) par sqrt(N/4). On suppose que
N correspond une taille qui soit adapte pour tresupporte
par la texture (ex. N=1024^2 peut tre stocke dans une
texture de taille 512 sur 512). La valeur correspondante sera
stocke dans texSize.
14

Rcap.

Cible

Format

Format
interne

NVIDIA GeForce
FX (NV3x)

NV4x, G7x, G8x NV4x, G7x, G8x


(RECT)
(2D)

ATI

texture rectangle

texture
rectangle

texture2D et
texture
rectangle

texture2D

LUMINANCE et RGBA (et RG et RGB)


Attention : ces formats sont supports en tant que textures mais pas
comme cible de rendu
NV_float_buffer

NV_float_buffer

ATI_texture_float NV_float_buffer

15

Allocation pour les textures


Il suffit de connatre :
La texture cible :
GL_TEXTURE_2D
GL_TEXTURE_RECTANGLE_ARB

Le format de la texture
GL_LUMINANCE
GL_RGBA

Le format interne que lon souhaite utiliser


NV_float_buffer
ATI_texture_float
ARB_texture_float
16

Code pour lallocation de la texture


// crer un nouveau id pour une texture
GLuint texID;
glGenTextures (1, &texID);
// associer lid de la texture une texture cible
glBindTexture(texture_target,texID);
// Arrter le filtrage et configurer le wrap mode
// (obligatoire pour les texures de rels)
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
// Configurer le texenv REPLACE la place de la valeur par dfaut MODULATE
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// Allouer la mmoire graphique
glTexImage2D(texture_target, 0, internal_format, texSize, texSize, 0, texture_format,
GL_FLOAT, 0);

17

Association index tableaucoordonnes texture


Dans la suite, nous allons chercher modifier les donnes stockes
dans les textures par les donnes du rendu.
Pour pouvoir contrler quel lment traiter ou accder dans la
mmoire texture, on a besoin :
deffectuer une projection qui permet de passer des coordonnes du
modle 3D en coordonnes daffichage 2D  projection orthogonale
en plus dun mapping 1:1 entre coordonnes gomtriques (utilises
dans le rendering), les coordonnes de textures (donnes accder
pou traitement : entre) et les coordonnes des pixels (rsultat du rendu
: sortie)  utiliser un bon viewport

Le mapping se base sur la taille (dans chaque dimension) utilise


pour allouer les textures.
Pour configurer le mapping on met la valeur de z 0 dans les
coordonnes du modle et on applique un mapping 1:1
Les lignes suivant peuvent tre ajout la routine initFBO()

18

viewport pour un mapping 1:1

// viewport pour un mapping 1:1 pixel=texel=geometry


glMatrixMode(GL_PROJECTION);
glLoadIdentity();//
gluOrtho2D(0.0, texSize, 0.0, texSize);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, texSize, texSize);

19

Utilisation des textures comme


cible (sortie)

Lextension framebuffer_object permet de renvoyer le rendu directement


dans une texture.
Le problme cest que les textures sont soit en mode lecture soit criture.
Que faire pour y = y + alpha * x ?
Pour utiliser une texture comme cible il faut attacher la texture au FBO en
supposant que le framebuffer est dj mis en offscreen
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, //jusqu 4 attachements par FBO
texture_target, texID, 0);

20

Transfert de donnes
tableau (CPU)texture (GPU)
Pour transfrer les donnes vers les
textures il faut les associer des textures
cibles et ordonnancer le transfert avec des
appels OpenGL.
glBindTexture(texture_target, texID);
glTexSubImage2D(texture_target,0,0,0,texSize,texSize,
texture_format,GL_FLOAT,data);

21

Transfert de donnes
texture (GPU)  tableau (CPU)
Il y a 2 faons pour implmenter le transfert des
textures GPU vers des tableaux CPU
Lapproche traditionnelle OpenGL moyennant un
appel glGetTexImage() qui permet dassocier une
texture une texture cible
glBindTexture(texture_target,texID);
glGetTexImage(texture_target,0,texture_format,GL_FLOAT,data);

Si la texture rcuprer est dj attache un FBO,


il est possible dutiliser la technique de redirection
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0,0,texSize,texSize,texture_format,GL_FLOAT,data);
22

Le plus petit Progamme!


// initialiser les paramtres de la texture
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
int main(int argc, char **argv) {
GL_TEXTURE_WRAP_S, GL_CLAMP);
// declarer la taille de la texture texSize
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
// la donne sera de taille texSize*texSize*4
GL_TEXTURE_WRAP_T, GL_CLAMP);
int texSize = 2;
// dfinir la texture avec le format floating point
// cration des donnes de test
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGBA32F_ARB,
float* data = (float*)malloc(4*texSize*texSize*sizeof(float));
texSize,texSize,0,GL_RGBA,GL_FLOAT,0);
float* result = (float*)malloc(4*texSize*texSize*sizeof(float));
// attacher la texture
for (int i=0; i<texSize*texSize*4; i++)
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
data[i] = i+1.0;
GL_COLOR_ATTACHMENT0_EXT,
// initialisation de glut pour prparer un contexte GL
GL_TEXTURE_RECTANGLE_ARB,tex,0);
// afin de pouvoir initialiser lextension glew
// transfrer la donne data texture
glutInit (&argc, argv);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,texSize,texSize,
glutCreateWindow("TP2");
GL_RGBA,GL_FLOAT,data);
glewInit();
// faire un read back
// transformer le viewport pour un mapping 1:1 pixel=texel=data
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glMatrixMode(GL_PROJECTION);
glReadPixels(0, 0, texSize, texSize,GL_RGBA,GL_FLOAT,result);
glLoadIdentity();//remplace la matrice courante avec lidentit
// imprimer le rsulta
gluOrtho2D(0.0,texSize,0.0,texSize);
printf("Data before roundtrip:\n");
glMatrixMode(GL_MODELVIEW);
for (int i=0; i<texSize*texSize*4; i++)
glLoadIdentity();
printf("%f\n",data[i]);
glViewport(0,0,texSize,texSize);
printf("Data after roundtrip:\n");
// crer un FBO offscreen et lassocier comme cible de rendu
for (int i=0; i<texSize*texSize*4; i++)
GLuint fb;
printf("%f\n",result[i]);
glGenFramebuffersEXT(1,&fb);
// librer la mmoire
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);
free(data);
// crer une texture
free(result);
GLuint tex;
glDeleteFramebuffersEXT (1,&fb);
glGenTextures (1, &tex);
glDeleteTextures (1,&tex);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB,tex);
return 0;
}
23
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>

Pages de rfrence OpenGL

24

GPGPU concept 2 :
kernel = shader
y = y + alpha * x

for (int i=0; i<N; i++)


dataY[i] = dataY[i] + alpha * dataX[i];

Avec un vecteur de N processeur, pas besoin de


boucles (paradigme SIMD)
Kernel : y_new[i] = y_old[i] + alpha * x[i]
Le traitement est divis sur lensemble des units de calculs
disponibles

25

Cration dun shader avec Cg


Texture cible : texture2D

float saxpy ( float2 coords : TEXCOORD0, uniform sampler2D textureY,


uniform sampler2D textureX, uniform float alpha ) : COLOR
{
float result;
float y = tex2D(textureY,coords); //float yval=y_old[i];
float x = tex2D(textureX,coords); //float xval=x[i];
result = y + alpha * x; //y_new[i]=yval+alpha*xval;
return result;
}

26

Cration dun shader avec Cg


version 4-tuples en parallle
Texture cible : texture rectangle
float4 saxpy ( float2 coords : TEXCOORD0, uniform samplerRECT
textureY, uniform samplerRECT textureX, uniform float alpha ) : COLOR
{
float4 result;
float4 y = texRECT(textureY,coords);
float4 x = texRECT(textureX,coords);
result = y + alpha*x;
// equivalent: result.rgba=y.rgba+alpha*x.rgba
return result;
}

27

O placer le shader ?
Le code source dun shader peut tre
stock dans une chane de caractres ou
bien dans un fichier .cg et il sera accd
par OpenGL via le Cg runtime

28

Configuration du runtime Cg
Inclure lentte Cg
#include <cg\cg.h>// Cg Header
#include <cg\cggl.h>// Header spcifique Cg OpenGL

Ajouter les librairies pour ldition des liens


#pragma comment( lib, "cg.lib")
#pragma comment( lib, "cggl.lib")

Dclaration de certains variables


CGcontext cgContext; //point dentre pou le runtime Cg
CGprofile fragmentProfile; //on sintresse au pixel pipeline
CGprogram fragmentProgram; //conteneur pour le programme
CGparameter yParam, xParam, alphaParam;
char* program_source = "float saxpy( [....] return result; } ";
29

Initialisation du runtime Cg
void initCG(void) {
// set up Cg
cgContext = cgCreateContext();
fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
cgGLSetOptimalOptions(fragmentProfile);
// create fragment program
fragmentProgram = cgCreateProgram (
cgContext,CG_SOURCE,program_source,
fragmentProfile,"saxpy",NULL);
// load program
cgGLLoadProgram (fragmentProgram);
// and get parameter handles by name
yParam = cgGetNamedParameter (fragmentProgram,"textureY");
xParam = cgGetNamedParameter (fragmentProgram,"textureX");
alphaParam = cgGetNamedParameter (fragmentProgram,"alpha");
}

30

GPGPU concept 3 :
Calculer = dessiner
Quatre tapes sont ncessaires :
Activation du noyaux en utilisant le Cg
runtime
Assignation des tableaux d entre et de
sortie au shader runtime Cg
Dclenchement du traitement

31

Etape 1 : Activation du noyau


Pour activer le noyau en utilisant le Cg runtime :
Le fragment profile doit tre activ
Le shader dj crit et charg est attach

On ne peut activer quun seul shader du mme type la


fois
Lactivation est assure par le code suivant :
// Activer le profil fragment
cgGLEnableProfile(fragmentProfile);
// Associer le programme saxpy
cgGLBindProgram(fragmentProgram);

32

Etape 2 : Configuration des


entres tableaux textures
// Activer la texture y_old (lecture seule)
cgGLSetTextureParameter(yParam, y_oldTexID);
cgGLEnableTextureParameter(yParam);
// Activer la texture x (lecture seule)
cgGLSetTextureParameter(xParam, xTexID);
cgGLEnableTextureParameter(xParam);
// Activer le scalaire alpha
cgSetParameter1f(alphaParam, alpha);

33

Etape 3 : Configuration des


sorties tableaux textures

// Attacher la texture cible au premier point dattachment


glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, texture_target, y_newTexID, 0);
// Configurer la texture comme cible de rendu
glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);

34

Etape 4 : Traitement
Rappelons ce que nous avons fait.
Activ un mapping 1:1 entre les pixels cibles, les coordonnes de
texture et la gomtrie
Prpar un fragment shader excuter sur chaque fragment

Ce qui reste faire :


tre sr que chaque donne t transfr correctement dans un
fragment
Ceci est relativement facile grce aux settings de la projection et du viewport
Tout ce dont on a besoin cest un carr (quad) qui couvre la totalit du
viewport (dfinissable grce au standard OpenGL)
on dfinit 4 vertices coins du carr
On assigne les coordonnes de texture comme attributs des 4 vertices (les vertices seront
transforms en espace cran)
La rastrisation (fonction fixe du pipeline) qui se trouve entre le vertex et le fragment pipeline se
chargera du de lassociation entre pixel et coordonnes texture pour gnrer un fragment pour
chaque pixel couvert par le carr
Chaque valeur sera passe automatiquement au fragment shader
 Le quad sert comme un gnrateur de flux de donnes pour le program shader

35

j avec une texture rectangles


Les coordonnes de textures sont
identiques aux coordonnes des pixels
// make quad filled to hit every pixel/texel
glPolygonMode(GL_FRONT,GL_FILL);
// and render quad
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(0.0, 0.0);
glTexCoord2f(texSize, 0.0);
glVertex2f(texSize, 0.0);
glTexCoord2f(texSize, texSize);
glVertex2f(texSize, texSize);
glTexCoord2f(0.0, texSize);
glVertex2f(0.0, texSize);
glEnd();

36

j avec une texture 2D


Les coordonnes de textures sont
normalises
// make quad filled to hit every pixel/texel
glPolygonMode(GL_FRONT,GL_FILL);
// and render quad
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(0.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex2f(texSize, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex2f(texSize, texSize);
glTexCoord2f(0.0, 1.0);
glVertex2f(0.0, texSize);
glEnd();

37

Vous aimerez peut-être aussi