I. Optimisation du vertex shader▲
Précédemment, j'ai publié un simple code d'exemple pour calculer la position et la normale dans le vertex shader en OpenGL (GLSL) et Direct3D (HLSL). Le but était de montrer le fonctionnement des différentes matrices : projection, view (vue) et model (modèle) pour déterminer la variable gl_Position et notamment l'ordre des multiplications des matrices avec OpenGL et Direct3D. Voici le vertex shader GLSL (nommé VS_A) :
uniform mat4 M; // Matrice du modèle
uniform mat4 V; // Matrice de vue
uniform mat4 P; // Matrice de projection
void main()
{
vec4 v = gl_Vertex;
mat4 MV = V * M;
mat4 MVP = P * MV;
vec4 v1 = MVP * v;
gl_Position = v1;
}Cette méthode construit la matrice de transformation finale (MVP ou ModelViewProjection) et la multiplie avec la position du vertex dans l'espace local de l'objet (gl_Vertex). Cette méthode fonctionne mais génère un grand nombre d'instructions GPU.
J'ai démarré l'outil GPU Shader Analyzer et compilé le vertex shader précédent :

Une fois compilé, le vertex shader VS_A génère 49 instructions UAL(1).
Daniel Rakos m'a montré une solution plus rapide :
uniform mat4 M; // Matrice du modèle
uniform mat4 V; // Matrice de vue
uniform mat4 P; // Matrice de projection
void main()
{
vec4 v = gl_Vertex;
vec4 v1 = M * v;
vec4 v2 = V * v1;
vec4 v3 = P * v2;
gl_Position = v3;
}Une fois compilé dans GPU ShaderAnalyzer, VS_B génère 13 instructions UAL.

J'ai rapidement effectué un test dans GeeXLab avec un objet (sphère) contenant deux millions de faces et un million de vertex :
- VS_A : 425 FPS ;
- VS_B : 425 FPS.
J'ai aussi effectué un test avec une simple démonstration OpenGL (une simple application de test win32) avec de l'instanciation géométrique (10 000 instances, 900 vertex par instance), sans trouver de différence entre les deux vertex shaders. Je m'attendais à une petite différence. Une explication peut être due à la simplicité de la scène. Je suis cependant sûr que nous allons voir une différence dans des shaders ou des scènes 3D plus complexes, car il doit y avoir un gain de performances entre 49 et 13 instructions ALU…
I-A. Mise à jour du 31 octobre 2011▲
Je pense avoir trouvé une réponse possible : le surcoût provoqué par l'appel du shader et/ou de l'accès aux vertex. En effet, si la charge de travail réelle du vertex shader est trop petite, la majorité du temps est perdue dans d'autres tâches telles que la récupération des vertex ou l'appel au shader ou, plus généralement, toute tâche venant avant ou après l'exécution du vertex shader. En conséquence, une différence d'une trentaine d'instructions ALU n'est pas visible.
Pour valider cette idée, j'ai augmenté le travail du vertex shader et comparé les deux vertex shaders suivants avec un objet constitué d'un million de vertex :
uniform mat4 M; // Matrice du modèle
uniform mat4 V; // Matrice de vue
uniform mat4 P; // Matrice de projection
void main()
{
vec4 v = gl_Vertex;
vec4 pos = vec4(0.0);
for (int i=0; i<100; i++)
{
mat4 MV = V * M;
mat4 MVP = P * MV;
vec4 v1 = MVP * v;
pos += v1;
}
gl_Position = pos / 100.0;
}et
uniform mat4 M; // Matrice du modèle
uniform mat4 V; // Matrice de vue
uniform mat4 P; // Matrice de projection
void main()
{
vec4 v = gl_Vertex;
vec4 pos = vec4(0.0);
for (int i=0; i<100; i++)
{
vec4 v1 = M * v;
vec4 v2 = V * v1;
vec4 v3 = P * v2;
pos += v3;
}
gl_Position = pos / 100.0;
}Avec le vertex shader A, la démonstration tourne à 19 FPS. Avec le vertex shader B, la démonstration tourne à 64 FPS.
Ouf, trouvé ! L'intuition était bonne : il y a une importante différence de vitesse entre ces deux vertex shaders.
II. Remerciements▲
Cet article est une traduction autorisée de l'article paru sur Geeks3D.com.
Je tiens à remercier Winjerome et dourouc05 pour leur relecture lors de la traduction de cet article, ainsi que ClaudeLELOUP et _Max_ pour leur relecture orthographique.





