Les causes de branchement dans GLSL dépendent du modèle GPU et de la version du pilote OpenGL.
La plupart des GPU semblent avoir une forme d'opération "sélectionner l'une des deux valeurs" qui n'a pas de coût de branchement:
n = (a==b) ? x : y;
et parfois même des choses comme:
if(a==b) {
n = x;
m = y;
} else {
n = y;
m = x;
}
sera réduit à quelques opérations de sélection de valeur sans pénalité de branchement.
Certains GPU / Drivers ont (eu?) Une pénalité sur l'opérateur de comparaison entre deux valeurs mais une opération plus rapide sur la comparaison contre zéro.
Où il pourrait être plus rapide de le faire:
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
plutôt que de comparer (tmp1 != tmp2)
directement, mais cela dépend beaucoup du GPU et du pilote, donc à moins que vous ne cibliez un GPU très spécifique et aucun autre, je recommande d'utiliser l'opération de comparaison et de laisser cette tâche d'optimisation au pilote OpenGL car un autre pilote pourrait avoir un problème avec le formulaire plus long et soyez plus rapide avec la manière la plus simple et la plus lisible.
Les "succursales" ne sont pas toujours une mauvaise chose non plus. Par exemple sur le GPU SGX530 utilisé dans OpenPandora, ce shader scale2x (30ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
if ((D - F) * (H - B) == vec3(0.0)) {
gl_FragColor.xyz = E;
} else {
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
}
A fini considérablement plus rapide que ce shader équivalent (80 ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
lowp vec3 tmp3 = D == F || H == B ? E : tmp1;
gl_FragColor.xyz = tmp1 == tmp2 ? tmp3 : E;
Vous ne savez jamais à l'avance comment un compilateur GLSL spécifique ou un GPU spécifique fonctionnera jusqu'à ce que vous le compariez.
Pour ajouter le point (même si je n'ai pas de numéros de synchronisation réels et de code de shader à vous présenter pour cette partie), j'utilise actuellement comme matériel de test régulier:
- Intel HD Graphics 3000
- Carte graphique Intel HD 405
- nVidia GTX 560M
- nVidia GTX 960
- AMD Radeon R7 260X
- nVidia GTX 1050
En tant que large éventail de modèles de GPU différents et courants à tester.
Tester chacun avec les pilotes OpenGL et OpenCL de Windows, Linux propriétaire et Linux open source.
Et chaque fois que j'essaie de micro-optimiser le shader GLSL (comme dans l'exemple SGX530 ci-dessus) ou les opérations OpenCL pour un combo GPU / Driver particulier, je finis par nuire également aux performances de plusieurs des autres GPU / Drivers.
Donc, à part réduire clairement la complexité mathématique de haut niveau (par exemple: convertir 5 divisions identiques en une seule réciproque et 5 multiplications à la place) et réduire les recherches de texture / bande passante, ce sera probablement une perte de temps.
Chaque GPU est trop différent des autres.
Si vous travailliez spécifiquement sur une (des) console (s) de jeu avec un GPU spécifique, ce serait une autre histoire.
L'autre aspect (moins important pour les développeurs de petits jeux mais toujours notable) est que les pilotes de GPU informatiques pourraient un jour remplacer silencieusement vos shaders ( si votre jeu devient assez populaire ) par des pilotes personnalisés réécrits optimisés pour ce GPU particulier. Faire tout cela fonctionne pour vous.
Ils le feront pour les jeux populaires qui sont fréquemment utilisés comme références.
Ou si vous donnez à vos joueurs l'accès aux shaders afin qu'ils puissent facilement les éditer eux-mêmes, certains d'entre eux pourraient serrer quelques FPS supplémentaires à leur propre avantage.
Par exemple, il existe des packs de shaders et de textures créés par des fans pour Oblivion afin d'augmenter considérablement la fréquence d'images sur du matériel autrement difficilement jouable.
Et enfin, une fois que votre shader est suffisamment complexe, votre jeu est presque terminé et que vous commencez à tester sur différents matériels, vous serez assez occupé à simplement réparer vos shaders pour qu'ils fonctionnent sur une variété de GPU car cela est dû à divers bogues que vous ne rencontrerez pas. avoir le temps de les optimiser à ce degré.