IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

Performance pixel shader


Sujet :

OpenGL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    396
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 396
    Par défaut Performance pixel shader
    Hello,

    J'ai un pixel shader qui ressemble à ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    for(int j=0; j<100;j++)
    {
    	//..
    	float NdotL = dot(normal, vertexToLightNormalized);
    	if(NdotL > 0.0001){
    		color += att * (diffuse * NdotL);
    	}
    }
    Nombre de fps que j'obtiens avec ce shader: 44fps.

    Si je change mon shader comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for(int j=0; j<100;j++)
    {
    	//..
    	float NdotL = max(dot(normal, vertexToLightNormalized), 0.0);
    	color += att * (diffuse * NdotL);
    }
    Nombre de fps que j'obtiens avec ce shader: 107fps.

    La difference de fps me parait assez énormeeeee: comment ça peut s'expliquer ?
    Existe t-il des articles sur Internet qui parle de l'optimisation des pixel shaders ?

    Merci d'avance.

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 145
    Billets dans le blog
    150
    Par défaut
    Bonjour,

    Moi j'ai appris que dans un shader on ne doit pas faire de boucles, ni trop de branchements (des if)
    Donc lorsque je vois:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(int j=0; j<100;j++)
    Et bah je tique un peu.

    Si vous voulez énormément de lampe (moi j'ai réussi à faire plus de 512 points de lumière) il faut utiliser du deferred shading (une technique en deux passes). En résumé, cela permet de faire le calcul d'une lampe que au endroit où il faut et non sur toute la scène (ce que vous, vous faites).

    En terme de calcul que vous demandez:
    (Le pixel shader pouvant parcourir la taille de la fenêtre au maximum) cela lui fait déjà
    1024x768 pixels.
    Maintenant, vous lui demandez de faire 100 itérations pour chaque pixel:
    1024x768x100

    Et la mauvaise nouvelle ... c'est qu'il peut faire plus que la taille de la fenêtre car si deux objets sont l'un derrière l'autre ... dans certains cas ... les deux objets peuvent se retrouver calculer dans le pixel shader ... et ça peut faire énorme dans une scène 3D complète. (surtout lorsque l'on ne calcul pas que l'éclairage)

    Pour résumé ... ne faites pas des boucles de 100 itérations dans un pixel shader. Pour le deferred shading, on trouve pas mal de document (notamment en anglais :p dans les GPU Gems de NVidia (voir leur site, c'est libre)).

    Note hors sujet: J'ai eu un code qui ne compilait pas avec DirectX car trop de boucles dans le code ... (notamment pour la lumière )
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    396
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 396
    Par défaut
    Merci pour ta réponse.

    C'est un pixel shader de deferred shading .
    - Dans ma première passe, je remplis mes textures de diffuse, depth, normal, etc.
    - Dans ma seconde passe, je lis ces textures et j'applique l'éclairage.

    Dans ma seconde passe, je suis bien obligé de boucler sur toutes mes lampes, non ? (je peux biensur éviter d'envoyer les lampes qui n'affecte pas du tout la scène à mon shader).
    Ensuite dans la boucle, je peux ajouter un test du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if(!attenuationOfLight[j] > 0.0){
      /*J'applique l'éclairage sur ce pixel*/
    }else{
      /*La lampe 'j' n'affecte pas ce pixel, je passe à la lampe suivante.*/
      continue;
    }
    Ma question initial était surtout: pourquoi un 'if' est bcp bcp plus lent qu'une fonction 'max' ou une addition, etc. J'aimerai connaitre la raison technique.

    Merci d'avance.

  4. #4
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 145
    Billets dans le blog
    150
    Par défaut
    Euh le deferred shading, c'est pour éviter la boucle. Comment ? Simplement que dans la deuxième passe (passe des lampes) on va appliquer les shaders que sur les parties éclairés (en dessinant un rectangle autour de la lampe).
    Ce qui évite:
    - De dessiner les zones complètement noirs (pas de lampe)
    - De passer 100 fois alors que seulement 2 lampes éclaire cette zone

    Pour les branchements / contre les commandes built-in, c'est parce que le GPU n'est pas un CPU (Wouhou !). Plus précisément, le GPU est spécialisé dans les calculs, qui multithread de base (il éxecute le pixel shader en parallèle sur 8 ou 16 pixels à la fois) et que, à cause de sa spécialisation dans les calcul, les tests le dérange ...
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  5. #5
    Membre éclairé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 35

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    (il éxecute le pixel shader en parallèle sur 8 ou 16 pixels à la fois)
    Beaucoup plus, non?

  6. #6
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 145
    Billets dans le blog
    150
    Par défaut
    Citation Envoyé par TNT89 Voir le message
    Beaucoup plus, non?
    Bah peut être ... cela dépend de la carte graphique ... (je ne sais pas précisément ).

    Par contre si j'ai bien compris un prof, les cartes graphiques sont capables de faire les calculs blocs par blocs de pixels (genre ... on a une surface uniforme assez grande ... celle-ci peut être calculé par petits blocs au lieu de simple pixels)
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  7. #7
    Rédacteur
    Avatar de bafman
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    2 574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2003
    Messages : 2 574
    Par défaut
    Citation Envoyé par zenux Voir le message
    Merci pour ta réponse.

    C'est un pixel shader de deferred shading .
    - Dans ma première passe, je remplis mes textures de diffuse, depth, normal, etc.
    - Dans ma seconde passe, je lis ces textures et j'applique l'éclairage.

    Dans ma seconde passe, je suis bien obligé de boucler sur toutes mes lampes, non ? (je peux biensur éviter d'envoyer les lampes qui n'affecte pas du tout la scène à mon shader).
    Ensuite dans la boucle, je peux ajouter un test du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if(!attenuationOfLight[j] > 0.0){
      /*J'applique l'éclairage sur ce pixel*/
    }else{
      /*La lampe 'j' n'affecte pas ce pixel, je passe à la lampe suivante.*/
      continue;
    }
    Ma question initial était surtout: pourquoi un 'if' est bcp bcp plus lent qu'une fonction 'max' ou une addition, etc. J'aimerai connaitre la raison technique.

    Merci d'avance.
    ha mais c'est très simple... Les cartes graphique moderne sont conçu pour faire du traitement numerique très rapide. Pour cela, elle sont decomposé en unités de calculs. Pleins. Tout pleins d'unités de calculs, un peut comme les core des CPU actuels, mais moins généraliste et beaucoup plus nombreux. Du coup, ta carte graphique est capable de traiter pleins de pixels en parallèle. Le seul problème, c'est qu'elle est aussi capable de faire des calculs de dérivations. Pour avoir une dérivé partielle, il faut, au minimum, avoir un voisin en x et un voisin en y. Problème résolu simplement en traitant toujours les pixel par petits paquets (en général, 2x2). L'avantage de cette technique, c'est qu'on gagne sur plusieurs points :
    * On a une ganularité de calcul assez faible pour pouvoir saturer les unités de calculs
    * 2x2, tiens, justement, ça fait 4 !!! ce qui est le nombre d'operation faite par les operateur SIMD 128 bits classiques
    * les caches sont contents d'avoir une localité géographique

    du coup, quand on a un code homogene dans son traitement, ça va vite. Très vite.

    Problème: justement, quand on ajoute un if, on a plus du code homogène (le pixel 1 peut aller d'un coté du if quand le pixel 2 peut aller de l'autre coté)
    Du coup, le compilateur de shader perd pleins (vraiment) de possibilité d'optimisation. Déjà, la première, c'est qu'il ne fera probablement pas de SIMD (aïe). La deuxième, c'est qu'il devra utilisé une unité logique pour faire la comparaison, ce dont il est peu pourvu car il est justement conçu pour faire du calcul. La troisième, c'est que (a priori, je n'ai pas verifié) ce genre de processeur est du type "out of order", ce qui signifie qu'il peut réordonnancer les opérations en interne pour gagner du temps, mais du coup, un branchement raté, c'est une catastrophe, il doit vider sont pipeline pour ré exécuter le code... (et en plus, je ne pense pas qu'il y ai de branch target buffer sur GPU )

    Bref, si les GPU ne sont pas rapide pour exécuter des if, c'est qu'ils sont conçu pour faire du calculs et pas trop d’arithmétique (mais ils peuvent quand même en faire.)
    Une règle assez efficace, est que si tu peut faire le même calcul sans branchement, généralement, il ira plus vite même si il fait du calcul inutile (mais pas trop quand même).

    Par contre, le cas des boucles for est généralement différent[1]. En effet, une boucle peut être facilement découpé en 2 parties : les N premier éléments (avec N un multiple de 4) et les M suivant (avec M <= 3). Du coup, on peut facilement utiliser du SIMD dans la première boucle, et la seconde est certes lente, mais limité à 3 éléments max.

    pfuiiiii, j'ai encore pondu un pavé. Zut. Et du coup, mon introduction en disant que c'etait simple perd un peut de sons sens

    [1] je ne prend pas en compte ici les boucle for qui n'en sont pas (condition de terminaison non constante, break, continue et autre truc qui facilite la vie du programmeur mais pas de l'optimiseur)
    * Il est infiniment plus simple de faire rapidement un code qui marche que de faire un code rapide qui marche
    * pour faciliter les recherches, n'oubliez pas de voter pour les réponses pertinentes
    Mes articles

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2005
    Messages
    208
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 208
    Par défaut
    Bonsoir !

    Sujet fort intéressant !

    Mais alors, comment gérer efficacement plusieurs cas?
    Je pense notamment à la présence ou non de textures diffuse / spéculaire / ambiante...

    A l'heure actuel, mon fragment shader reçoit un uniform bool pour chaque texture.
    Je teste chaque booléen, s'il est true j'utilise la valeur de texture, sinon j'utilise une valeur passée par uniform (couleur matériau, intensité spéculaire...).

    Existe t'il une façon plus propre, plus adapté aux shaders ?
    Histoire de limiter les nombres de tests.

  9. #9
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 145
    Billets dans le blog
    150
    Par défaut
    On peut penser de faire un shader par effet (un effet == diffuse + speculare ; un autre effet == diffuse + globale) par exemple.

    Sinon je n'ai pas vraiment compris quel effet vous voulez faire, mais il y a surement mieux.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

Discussions similaires

  1. Pixel Shaders (en Managed)
    Par Ingham dans le forum DirectX
    Réponses: 10
    Dernier message: 20/12/2004, 19h05
  2. effets de pixel shaders 1.1
    Par cemoi dans le forum DirectX
    Réponses: 11
    Dernier message: 12/12/2003, 15h13
  3. pixel shader 2.0
    Par trois_1 dans le forum DirectX
    Réponses: 3
    Dernier message: 20/10/2003, 15h39
  4. Vertex et Pixel Shader
    Par Riko dans le forum OpenGL
    Réponses: 2
    Dernier message: 06/06/2003, 16h45
  5. carte graphique et pixels shader
    Par yeeep dans le forum DirectX
    Réponses: 2
    Dernier message: 26/04/2003, 10h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo