Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Performance, sf::RenderTexture et nombreux Shaders  (Lu 10990 fois)

0 Membres et 2 Invités sur ce sujet

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #15 le: Octobre 01, 2013, 11:26:16 am »
Oui exact.

Mais plusieurs centaines de projectiles, c'est potentiellement pas grand chose (regarde les millions de triangles que les cartes graphiques sont capables d'afficher dans les jeux récents). Ne fais pas d'optimisation prématurée ;)
Laurent Gomila - SFML developer

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #16 le: Octobre 01, 2013, 12:06:41 pm »
Citer
Mais plusieurs centaines de projectiles, c'est potentiellement pas grand chose

Si ils sont stoqué sur la carte graphique oui, mais si il faut clear/draw leur buffer à chaque frame, mettre à jour leur geometrie etc ça commence à faire  :-\
D'ailleurs, est-ce que les sf::VertexArray sont push sur la carte graphique ?
J'ai déjà fais des VBO sous openGL et je me souviens que mon programme était devenu un fusée après ça  :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #17 le: Octobre 01, 2013, 12:17:36 pm »
Citer
Si ils sont stoqué sur la carte graphique oui, mais si il faut clear/draw leur buffer à chaque frame, mettre à jour leur geometrie etc ça commence à faire
Tu te bases sur quoi pour affirmer que "ça commence à faire [beaucoup]" ? A moins que ce ne soient les résultats de ton programme qui te permettent d'arriver à cette conclusion, ça ne sert à rien. Tirer des conclusions sur les performances a priori, ça ne mène qu'à des problèmes fictifs et une complication de code pour... pas grand chose.

Citer
D'ailleurs, est-ce que les sf::VertexArray sont push sur la carte graphique ?
Non, afin de garder une flexibilité maximale. Une fois sur la carte graphique, c'est plus délicat à toucher. Et comme l'API de SFML permet de changer facilement les attributs des entités à tout moment, ça flinguerait les performances de tout mettre systématiquement sur la carte graphique via des VBOs.
Laurent Gomila - SFML developer

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #18 le: Octobre 01, 2013, 12:33:06 pm »
Citer
Tu te bases sur quoi pour affirmer que "ça commence à faire [beaucoup]" ? A moins que ce ne soient les résultats de ton programme qui te permettent d'arriver à cette conclusion, ça ne sert à rien. Tirer des conclusions sur les performances a priori, ça ne mène qu'à des problèmes fictifs et une complication de code pour... pas grand chose.
Citer
A moins que ce ne soient les résultats de ton programme qui te permettent d'arriver à cette conclusion
C'est exactement ça. Mon groupe a fait pas mal de profiling hier soir sur notre programme pour détecter les parties les plus gourmandes en ressources, et en l'occurence il s'agit de la partie "dessin" de tout mes objets (quand la liste dépasse la centaine d'objet).
D'ailleurs quand j'y pense, ce n'est pas normal. Car j'avais déjà fais un projet précédent qui affichait beaucoup plus d'objets que ça par frame, et les performances était bien meilleure (les pertes de performances arrivaient lorsque que j'avais plusieurs milliers d'objets à tracer).
Il faudrait que je me porte plus sérieusement sur mon programme plutôt que sur des problèmes que je peux penser venir de SFML.

Quelques chiffres au passage pour illustrer mon propos
0.200ms pour un clear et un draw dans mon programme
Faisant un clear et un draw (au minimum) pour chaques objets je passe 0.400ms par objet / frame.
Avec une centaine d'objet ça me fait donc 40ms / frame soit 25fps.

Cependant ces performances viennent peut être aussi du fait que la taille de mes sf::RenderTexture partagée ne convient pas du tout à la taille de mes projectile (beaucoup de gaspillage de ressources du coup).

Citer
Non, afin de garder une flexibilité maximale. Une fois sur la carte graphique, c'est plus délicat à toucher. Et comme l'API de SFML permet de changer facilement les attributs des entités à tout moment, ça flinguerait les performances de tout mettre systématiquement sur la carte graphique via des VBOs.
D'accord  :)

« Modifié: Octobre 01, 2013, 12:43:02 pm par PetitPoney »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #19 le: Octobre 01, 2013, 01:09:31 pm »
Citer
Quelques chiffres au passage pour illustrer mon propos
0.200ms pour un clear et un draw dans mon programme
Faisant un clear et un draw (au minimum) pour chaques objets je passe 0.400ms par objet / frame.
Avec une centaine d'objet ça me fait donc 40ms / frame soit 25fps.
N'extrapole pas des performances générales à partir de la mesure d'un seul appel de fonction. Ce n'est pas représentatif ; surtout qu'OpenGL est une API asynchrone, le temps pris pour le dessin n'est pas forcément dans la fonction draw.

La seule mesure fiable, c'est de regarder le FPS d'une appli qui tourne avec un nombre non négligeable d'entités.

Citer
Cependant ces performances viennent peut être aussi du fait que la taille de mes sf::RenderTexture partagée ne convient pas du tout à la taille de mes projectile (beaucoup de gaspillage de ressources du coup).
Bof, au pire tu perds un peu de RAM graphique. Je ne pense pas que ça joue sur les performances.
Laurent Gomila - SFML developer

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #20 le: Octobre 01, 2013, 01:36:22 pm »
Merci pour ces explications.

Je vais implémenter mes sf::VertexArray et je reviendrais poster mon feedback   :)

D'ailleurs, je vois que la classe sf::VertexArray est en fait une surcouche d'un std::vector. Pourquoi ne pas proposer une fonction permettant de supprimer tel ou tel élement du VertexArray ?
Car en l'occurence j'en ai besoin pour delete les projectiles qui depop de la scène.

Ah, c'est sûrement à cause de ça (doc c++)
Citer
Compared to the other dynamic sequence containers (deques, lists and forward_lists), vectors are very efficient accessing its elements (just like arrays) and relatively efficient adding or removing elements from its end. For operations that involve inserting or removing elements at positions other than the end, they perform worse than the others, and have less consistent iterators and references than lists and forward_lists.

Du coup il faudrait que pour chaques frame je recharge mon sf::VertexArray ?  :-\. C'est bof quand même non ?
« Modifié: Octobre 01, 2013, 01:51:13 pm par PetitPoney »

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #21 le: Octobre 03, 2013, 12:38:31 pm »
Du coup voilà comment je procède.

J'ai crée une classe que l'on va appelé "ProjectileSystem" qui a pour attribut :
  • Un conteneur d'objet "Projectile" (une unsorted_map)
  • Une principale renderTexture dans lequel je trace tous mes projectiles
  • Deux autre renderTexture que l'utilise pour appliquer mes shader

Avantages :
  • Une unsorted_map est très pratique et pas très gourmande pour les opérations de suppression (log si je me souviens bien)
  • Elle permet justement de supprimer simplement des élements de la map
  • Si je veux plusieurs type de bullet, je n'ai qu'à créer plusieurs "principales" renderTexture et je dispatch mes projectiles dans l'une ou l'autre
  • Tout cela convient parfaitement à mon système de ping / pong pour l'application de shaders
  • Performances nickel !  :)

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #22 le: Octobre 23, 2013, 08:47:17 pm »
Bonjour !

Je me permet de relancer ce topic car je n'ai toujours pas réglé mon problème de performance pour l'application de shader globaux.

Avant tout, j'ai fais un gros travail d'optimisation dans le code. En effet, toute mes "bullets" font maintenant parties d'un seul sf::VertexArray que je met à jour à chaque frame. Aussi, tout mes systèmes de particules sont également rassemblé dans un seul sf::VertexArray.
En gros, je dois gagner environ 300/350 draw par frame (HUGE :D).

Cependant, j'ai toujours un problème de chute de fps pour l'application de shader globaux. J'ai donc décidé de faire un exemple de code qui illustre ce problème.

Les shaders ne seront pas en std::string car il y a pas mal de code, ils sont donc en pièce jointe a mettre dans le même répertoire de le binaire.

#include <SFML/Graphics.hpp>
#include <sstream>

std::string intToString(const int &i)
{
        std::stringstream ss;

        ss << i;
        return ss.str();
}

void loadShader(sf::Shader &pass1, sf::Shader &pass2)
{
        pass1.loadFromFile("vertex.vert", "fragment.frag");
        pass2.loadFromFile("vertex.vert", "fragment.frag");

        pass1.setParameter("texture", pass1.CurrentTexture);
        pass1.setParameter("pixelSize", 1.0f / (float)1920.0f,
                1.0f / (float)1080.0f);
        pass1.setParameter("pass", 0.0);
        pass1.setParameter("range", 2.0);
        pass1.setParameter("intensity", 1.0);

        pass2.setParameter("texture", pass2.CurrentTexture);
        pass2.setParameter("pixelSize", 1.0f / (float)1920.0f,
                1.0f / (float)1080.0f);
        pass2.setParameter("pass", 1.0);
        pass2.setParameter("range", 2.0);
        pass2.setParameter("intensity", 1.0);
}

sf::RenderTexture *applyShader(sf::RenderTexture &buffer1, sf::RenderTexture &buffer2,
        sf::CircleShape &shape, sf::Text &fps,
        sf::Shader &pass1, sf::Shader &pass2)
{
        buffer1.clear();
        buffer2.clear();

        // Draw objects in first buffer
        buffer1.draw(shape);
        buffer1.draw(fps);
        buffer1.display();

        pass1.setParameter("textureBase", buffer1.getTexture());
        pass2.setParameter("textureBase", buffer1.getTexture());

        // Apply shader
        buffer2.draw(sf::Sprite(buffer1.getTexture()), &pass1);
        buffer2.display();
        buffer1.draw(sf::Sprite(buffer2.getTexture()), &pass2);
        buffer2.display();

        return &buffer1;
}

int main(void)
{
        sf::RenderWindow window(sf::VideoMode(1920, 1080), "Shader application, performance", sf::Style::Fullscreen);
       
        // Buffers
        sf::RenderTexture buffer1;
        buffer1.create(1920, 1080);
        sf::RenderTexture buffer2;
        buffer2.create(1920, 1080);

        // CircleShape
        sf::CircleShape shape;
        shape.setRadius(200);
        shape.setPosition(1920.0f / 2.0f, 1080.0f / 2.0f);
        shape.setOrigin(shape.getRadius(), shape.getRadius());
        shape.setFillColor(sf::Color::Green);

        // FPS
        sf::Clock clock;
        clock.restart();
        int frame = 0;
        sf::Font font;
        font.loadFromFile("arial.ttf");
        sf::Text fps("", font);

        // Shaders
        sf::Shader pass1;
        sf::Shader pass2;
        loadShader(pass1, pass2);
       
        while (window.isOpen())
    {
        // Process events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window : exit
            if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                window.close();
        }
               
                // Clear
                window.clear();

                // FPS
                if (clock.getElapsedTime().asSeconds() > 1.0f)
                {
                        fps.setString("fps : " + intToString(frame));
                        clock.restart();
                        frame = 0;
                }
       
                // Shader version, comment this to desactivate shader
                sf::RenderTexture *final = applyShader(buffer1, buffer2, shape, fps, pass1, pass2);            
                window.draw(sf::Sprite(final->getTexture()));

                // No shader version, uncomment this to desactivate shader
                //window.draw(fps);
                //window.draw(shape);

                window.display();
                frame++;
        }

        return 0;
}
 


Sans shader, je tourne preque à 1000 fps (je viens de mettre à jour mes drivers graphiques).
Avec, je tombe à 60 fps.

J'ai déjà essayé d'utiliser des texture puissance de 2, le problème c'est que 1024*1024 c'est petit (donc pour scale à la taille de l'écran c'est moche), 2048*2048 c'est trop gourmand.

J'espère avoir été clair  :).

Merci d'avoir pris le temps de lire mon post.
Cordialement

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #23 le: Octobre 23, 2013, 09:18:46 pm »
Citer
Les shaders ne seront pas en std::string car il y a pas mal de code
Et tu ne t'es pas dit que c'était peut-être la raison ? T'as pas essayé avec des shaders simples ?
Laurent Gomila - SFML developer

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #24 le: Octobre 23, 2013, 09:31:35 pm »
Je viens d'essayer avec un shader qui ne fait que renvoyer la couleur de la texture reçue en entrée (toujours en deux pass pour rester dans mon objectif d'application multiple de shader).
Je tourne à 200 fps ce qui fait malgré tout une belle chutte.

Est-ce qu'utiliser un shader loadFromMemory est plus performant qu'un shader loadFromFile ?


Au passage, voilà le shader qui applique un glow à toute la scène

uniform sampler2D       texture;
uniform sampler2D       textureBase;
uniform vec2            pixelSize;
uniform float           pass;
uniform float           range;
uniform float           intensity;

void firstPass(float values[25])
{
  vec2 pos = gl_FragCoord.xy * pixelSize;
  vec4 result = vec4(0, 0, 0, 0);
  vec2 curSamplePos = vec2(pos.x - range * 12.0 * pixelSize.x, pos.y);

  for(int i = 0; i < 25; i++)
    {
      result += texture2D(texture, curSamplePos) * values[i];
      curSamplePos.x += range * pixelSize.x;
    }
  gl_FragColor = result * intensity;
}

void secondPass(float values[25])
{
  vec2 pos = gl_FragCoord.xy * pixelSize;
  vec4 result = vec4(0, 0, 0, 0);
  vec2 curSamplePos = vec2(pos.x, pos.y - range * 12.0 * pixelSize.y);

  for(int i = 0; i < 25; i++)
    {
      result += texture2D(texture, curSamplePos) * values[i];
      curSamplePos.y += range * pixelSize.y;
    }
  // Final result
  gl_FragColor = result * intensity + texture2D(textureBase, gl_TexCoord[0].xy);
}

void main()
{
  float values[25];
  int i = 0;

  values[i++]=0.015; values[i++]=0.015; values[i++]=0.031; values[i++]=0.031; values[i++]=0.031;
  values[i++]=0.031; values[i++]=0.046; values[i++]=0.046; values[i++]=0.046; values[i++]=0.046;
  values[i++]=0.061; values[i++]=0.061; values[i++]=0.076; values[i++]=0.061; values[i++]=0.061;
  values[i++]=0.046; values[i++]=0.046; values[i++]=0.046; values[i++]=0.046; values[i++]=0.031;
  values[i++]=0.031; values[i++]=0.031; values[i++]=0.031; values[i++]=0.015; values[i++]=0.015;

  /* First pass */
  if (pass == 0.0)
    firstPass(values);
  /* Second pass */
  else if (pass == 1.0)
    secondPass(values);
}
 

Autre test que je viens de faire :
Utiliser des textures de 800*600 dans une fenêtre de 800*600. Avec le shader glow de base, je suis à ~200fps. J'ai également séparer mes deux pass en deux shader différents.
« Modifié: Octobre 23, 2013, 10:04:03 pm par PetitPoney »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #25 le: Octobre 23, 2013, 10:14:23 pm »
Je ne vois rien d'anormal ici. Les choses que tu as identifiées sont effectivement coûteuses, il y a bien un moment où les performances doivent chuter lorsque tu ajoutes des choses ;)

Quant à la chute de 1000 à 300 FPS, c'est pas tant que ça. Compte plutôt en millisecondes, les FPS ne sont pas bons pour comparer des performances, surtout au-delà d'une certaine limite.
Laurent Gomila - SFML developer

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #26 le: Octobre 23, 2013, 10:24:40 pm »
D'accord donc si je comprend bien j'atteins les limites de ma machine ? Ou même de la SFML (du moins openGL plutôt je dirais) ?

Ce que je ne comprend pas, c'est qu'en faisant des choses relativement simple mon programme n'est pas performant, alors qu'en parrallèle un StarCraft2 tourne en medium sans problème.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #27 le: Octobre 24, 2013, 07:45:50 am »
Citer
Ce que je ne comprend pas, c'est qu'en faisant des choses relativement simple mon programme n'est pas performant
Si avec tout ce que tu veux d'activé il tourne à 60 FPS, c'est pas ce que j'appelle "pas performant". Attend qu'il le soit vraiment au lieu d'essayer d'extrapoler ; n'oublie pas que les FPS chutent rapidement au début puis de moins en moins lorsque tu ajoutes des trucs (c'est du 1/N, ce n'est pas linéaire).

Bref, écris ton programme, ne te prends pas la tête sur des non-problèmes pour le moment.
Laurent Gomila - SFML developer

PetitPoney

  • Newbie
  • *
  • Messages: 44
    • Voir le profil
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #28 le: Octobre 24, 2013, 02:35:59 pm »
Justement, le programme sur lequel je travail actuellement est pour moi assez avancé pour se pencher sur des questions de performances car nous atteignons environ 30fps (du exclusivement à la partie graphique) ce qui n'est pas correct.

C'est pour cette raison que je cherche à ne pas faire du gaspillage de ressources à ce niveau.

Si vous êtes intéressé par notre projet et nos problèmatiques nous pouvons vous donner un accès a notre git.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Performance, sf::RenderTexture et nombreux Shaders
« Réponse #29 le: Octobre 24, 2013, 02:45:26 pm »
Moi je ne peux que me baser sur ce que tu dis pour te répondre. Or tu parlais de 60 fps, pas de 30.

J'aimerais vraiment n'avoir que ça à faire que de plonger dans les sources de ton projet, mais... c'est pas le cas :P
Laurent Gomila - SFML developer