GL ES: Optimisation du shader de fragments

8

Résumé: je reçois un ralentissement FPS dès que j'essaie de teinter les sprites (c'est-à-dire: multiplier la texture avec la couleur dans le fragment shader)

Détails:

Matériel: iPod touch 4

Je dessine 700 sprites sur l'écran à l'aide de glDrawArrays. Et oui, je regroupe tout cela en un seul appel. Voici la structure des données Vertex:

struct Vertex {
    float Position[2];
    float Color[4];
    float Texture[2];
};

Oui, j'envoie de la couleur avec chaque sommet car j'ai besoin de teinter sélectivement certains sprites mais pas d'autres. Voici le fragment shader que j'utilise:

varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord );
}

Jusqu'à présent, il fonctionne très bien, me donnant 60 FPS complets !!!

MAIS

Dès que je change le shader du fragment comme suit (pour autoriser la teinture):

varying lowp vec4 DestinationColor;
varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord ) * DestinationColor;
}

Utilisation de la texture png 64x64 suivante contenant le canal alpha, rendu avec glEnable (GL_BLEND):

entrez la description de l'image ici

Les performances chutent à 47 FPS uniquement en raison de ce changement unique {simplement par multiplication avec UN vecteur} (FPS mesuré à l'aide d'instruments xcode et d'un détective OpenGL). Une idée sur ce qu'il se passe ?

Merci.

Éditer:

J'ai également essayé de supprimer l'attribut de couleur par sommet:

struct Vertex {
    float Position[2];
    float Texture[2];
};

Et en modifiant le fragment shader comme suit:

precision lowp float;
varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord ) * vec4(1.0,0.0,0.0,1.0);
}

Il tourne à 52 FPS pour 700 sprites (un gain de seulement 5 FPS). Ce n'est donc pas de l'interpolation, il semble que la multiplication soit extrêmement coûteuse. Juste UNE SEULE multiplication?

fakhir
la source
Avez-vous activé vsync? Les chiffres pourraient signifier qu'après le changement, vous commencez à manquer tous les autres vsync, ce qui conduit à 45 FPS en moyenne.
msell
Je teste sur iPhone 4, je suppose que vsync est déjà activé par défaut. Il montre 47 FPS d'ailleurs dans les instruments xcode, donc je pense que vsync n'est pas vraiment un problème du tout. Mais ma vraie question est: pourquoi les performances ralentissent et comment les améliorer?
fakhir
1
Votre texture a-t-elle un canal alpha? Si la texture n'a pas de canal alpha et que le rgb est multiplié par un vec3, dessine-t-il encore à 60 ips?
Will
Oui, la texture a un canal alpha. Veuillez voir la texture ci-dessus.
fakhir
2
Monocœur SGX 535, écran haute résolution avec un GPU jamais conçu pour le gérer. Les performances des graphiques en résolution native sur ces appareils étaient toujours horribles. Vous devez soit réduire la résolution, soit viser 30 ips ou cibler du matériel plus récent. Vous attendez des miracles de ce GPU. Il ne faut pas grand-chose pour le remplir.
Sean Middleditch

Réponses:

2

Je ne pense pas que le problème de performance se produit sur la multiplication, mais sur l' interpolation de votre à DestinationColortravers les triangles, entre les vertex et les shaders de fragments. Vous avez quatre floats pour interpoler entre les sommets des arbres, pour chaque fragment pour chaque sprite.

Pour 700 sprites 64x64 pixels chacun, cela représente 11468800 opérations supplémentaires par image que vous demandez au GPU d'effectuer. Il est tout à fait possible que vous manquiez des vsyncs et que vous tombiez donc à 40 FPS.

Si vous voulez que chaque sommet ait une couleur différente, afin que vous puissiez avoir des dégradés pour chaque image-objet, vous n'avez pas de chance. Il y a aussi d'autres astuces que vous voudrez peut-être essayer, mais je pense que ce n'est pas le cas.

Étant donné que ce que vous semblez faire est de teinter chaque image-objet, vous pouvez rétrograder votre DestinationColorà un uniform, l'utiliser directement dans le fragment shader et le changer pour chaque appel. De cette façon, aucune interpolation n'aura lieu. Vous perdrez l'intégralité du traitement par lots, mais vous pourrez peut-être un traitement par lots si vous les triez par couleur.

Pyjama Panda
la source
J'ai édité la question ci-dessus et ajouté quelques détails. Fondamentalement, j'ai essayé de supprimer la couleur par sommet et de multiplier simplement la texture avec un vecteur CONSTANT, c'est-à-dire: gl_FragColor = texture2D (TextureSampler, TexCoord) * vec4 (1.0,0.0,0,0,0,1,0); . A obtenu 52 FPS, un gain de près de 5 FPS. Mais toujours beaucoup trop lent par rapport à aucune teinte. Ralentissement de 8 FPS uniquement en raison d'une seule multiplication vectorielle?
fakhir
3
Mais ce n'est pas une seule multiplication - c'est ~ 11 millions par image.
Maximus Minimus
1
@fakhir La résolution de l'écran de l'iPod Touch 4 est de 960x640 pixels. C'est 614400 pixels au total. Vous voulez rendre 700 sprites 64x64 pixels chacun. Cela représente 2867200 pixels, soit près de 5 fois tout l'écran. Vous avez probablement obtenu vos 60 images par seconde d'origine parce que l'optimiseur a compris ce que vous faisiez et a peut-être échantillonné l'image une seule fois, mais ne vous attendez pas à ce que cela se produise dans tous les cas. La programmation graphique mobile est beaucoup plus limitée que la programmation de bureau, alors agissez en conséquence.
Panda Pyjama