Forum de la communauté SFML

Aide => Graphique => Discussion démarrée par: PetitPoney le Septembre 20, 2013, 12:37:13 pm

Titre: Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Septembre 20, 2013, 12:37:13 pm
Bonjour !  :)

Dans le cadre de mon projet je suis ammené à utiliser beaucoup de shaders pour mes effets. Cependant j'ai quelques questions à propos de l'utilisation de ceux-ci.

On peut les séparer en deux catégorie différentes :
-> Ceux qui ne s'appliquent qu'à un seul objet
-> Ceux qui s'appliquent à la scène en globalité

Dans les deux cas, il faudra parfois passer par des sf::RenderTexture (si un shader à besoin de plusieurs "pass").
Pour avoir donc une architecture propre, je voudrais donc passer par une classe abstraite (qui hérite de sf::Drawable et sf::Transform) pour manipuler mes objets graphiques (ils sont purement graphiques, les calculs de jeux sont dans un GameEngine).

Pour ainsi dire, je voudrais pour chaque objet, le dessiner avant tout dans un sf::RenderTexture (afin d'appliquer les shaders spécifique à chaques objets).
Dans un second temps, je dessinerais le résultat de chaques objet dans un autre sf::RenderTexture qui lui contiendra la scène entière a afficher sur l'écran. J'appliquerais sur ce dernier les shaders "globaux".
Je dessinerais enfin ma scène finale sur l'écran.

J'ai donc plusieurs questions :
-> Premièrement, systématiquement passer par des sf::RenderTexture est-il adapté à l'implémentation de nombreux shaders ? (en gros, est-ce que je suis pas en plein délire)
-> Draw / Clear de nombreux sf::RenderTexture n'est-il pas trop gourmand en ressources ?

Cordialement
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent le Septembre 20, 2013, 01:54:34 pm
Citer
-> Premièrement, systématiquement passer par des sf::RenderTexture est-il adapté à l'implémentation de nombreux shaders ? (en gros, est-ce que je suis pas en plein délire)
Il n'y a a priori pas d'autre solution que de dessiner sur des textures intermédiaires pour appliquer plusieurs shaders. Donc la question des performances ne se pose pas, c'est la seule façon de faire.

Citer
-> Draw / Clear de nombreux sf::RenderTexture n'est-il pas trop gourmand en ressources ?
Dessiner sur un sf::RenderTexture c'est pareil que sur un sf::RenderTarget.
Dessiner un sf::RenderTexture via un sprite c'est pareil que de dessiner n'importe quelle texture via un sprite.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Septembre 20, 2013, 01:57:08 pm
D'accord. Je vais partir là dessus alors.
J'essaierai d'apporter des feedback ici  :).

Merci beaucoup Laurent !
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Septembre 30, 2013, 02:01:11 pm
Bonjour !

J'apporte un peu mon ressenti après notre discussion.


J'ai été confronté à un problème de performance lors de l'application de shader "globaux".
En effet, pour appliquer un effet de flou gaussien sur ma scène, je devais dessiner dans deux textures de la taille de ma fenêtre à chaques frames.
Or draw des renderTexture de 1920*1080 est super gourmand (mes fps étaient divisé par deux).

Le tutoriel explique que les sf::RenderTexture sont un bon moyen d'appliquer des shader globaux, or je ne suis pas d'accord au vu de l'expérience que j'en ai tiré.
L'utilisation de sf::RenderTexture est très utile en effet pour l'application de multiple shader, or appliquer un shader à tout une scène est beaucoup trop gourmand en ressources.
Il vaut donc mieux appliqué le même shader à chaques objets en utilisant de petite sf::RenderTexture.

Je ne pense pas que ce soit un problème d'implémentation mais bien un problème de performance (soit venant de SFML, soit matériel, voir même les deux).

Ëtes vous d'accord avec mon propos Laurent ?

Cordialement.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent le Septembre 30, 2013, 02:05:52 pm
Ca ne devrait pas être aussi lent, à moins que tu aies une carte graphique très vieille.

Le problème avec l'application de shader individuellement sur chaque objet, c'est que ça limite beaucoup le nombre d'effets implémentables. Par exemple tu ne peux pas réaliser un flou gaussien comme ça (pas un flou global en tout cas).

Il n'y a pas d'autre solution complètement équivalente.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Septembre 30, 2013, 02:25:14 pm
Au niveau de la carte graphique je ne pense pas trop être à la ramasse  :)
http://www.notebookcheck.net/NVIDIA-Quadro-NVS-5100M.24946.0.html (http://www.notebookcheck.net/NVIDIA-Quadro-NVS-5100M.24946.0.html)

C'est pourtant flagrant. Dès que j'active mon shadering global, les fps du jeux dégringolent (de 60 à 30).

Voilà la boucle qui ralentit le jeux dès que la fenêtre devient trop grande :

Avec :
std::list<Shader*>::iterator it, end  // Mes itérator sur ma list de shader
class Shader : public sf::Shader
sf::RenderTexture _buffer1, _buffer2   // De la taille de ma fenêtre
sf::Sprite tmpRes

  while (it != end)
    {
      if (lastBuffer == 1)
        {
          tmpRes.setTexture(_buffer1.getTexture());
          _buffer2.draw(tmpRes, (*it));
          lastBuffer = 2;
        }
      else
        {
          tmpRes.setTexture(_buffer2.getTexture());
          _buffer1.draw(tmpRes, (*it));
          lastBuffer = 1;
        }
      ++it;
    }
 

Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent le Septembre 30, 2013, 02:45:35 pm
Est-ce que tu as activé une limite de framerate, ou bien la synchro verticale ? 60, 30, ça a l'air bloqué tout ça, essaye de mesurer les performances sans aucune limitation (regarde aussi dans les options de ton driver graphique).

Note que tu aurais un code plus simple avec deux pointeurs que tu peux échanger, plutôt qu'un entier qui te dit dans quelle render-texture travailler.

Et n'oublie pas les appels à display().

sf::RenderTexture* front = &_buffer1;
sf::RenderTexture* back = &_buffer2;

while (it != end)
{
    front->draw(sf::Sprite(back->getTexture()), *it);
    front->display();
    std::swap(front, back);
}
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Septembre 30, 2013, 03:17:11 pm
Citer
Est-ce que tu as activé une limite de framerate, ou bien la synchro verticale ? 60, 30, ça a l'air bloqué tout ça, essaye de mesurer les performances sans aucune limitation (regarde aussi dans les options de ton driver graphique).

Bien vu ! En désactivant la syncro verticale c'est beaucoup plus fluide. Normal d'un côté mais je n'y avais pas pensé.
Pas mal votre bout de code aussi ! Beaucoup plus pro que le miens en effet. Merci !

Autre question par rapport au sf::RenderTexture.
Est-ce que l'appel à sf::RenderTexture::create est long en temps normal ?
Imaginons que j'ai un personnage qui tire des projectiles de façon rapide et répété (disons 10/sec) et que je veux appliquer des shader sur chaque projectile. Si je créer un/deux sf::RenderTexture pour chaque projectile, le programme ne va-y-il pas en souffrir ? (sachant que mes RenderTexture sont petites, disons 20*20)
Le mieux serait peut être de partager deux sf::RenderTexture entre tous les projectiles ?
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent le Septembre 30, 2013, 03:25:35 pm
Citer
Est-ce que l'appel à sf::RenderTexture::create est long en temps normal ?
Oui, très.

Citer
Imaginons que j'ai un personnage qui tire des projectiles de façon rapide et répété (disons 10/sec) et que je veux appliquer des shader sur chaque projectile. Si je créer un/deux sf::RenderTexture pour chaque projectile, le programme ne va-y-il pas en souffrir ?
Oublie tout de suite ce genre de stratégie, tu vas plomber tes performances avec ça ;)

Citer
Le mieux serait peut être de partager deux sf::RenderTexture entre tous les projectiles ?
Voire entre tous tes objets. Ce n'est pas parce qu'un objet fait 20x20 qu'il ne peut pas utiliser un bout d'une render-texture de 50x50 par exemple (n'oublie pas Sprite::setTextureRect).
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Septembre 30, 2013, 03:30:35 pm
D'accord !

Je venais de tester en effet et à chaque tir j'ai un gros lag (alors que ma texture fait 15*15).  :)

Citer
Citer
Le mieux serait peut être de partager deux sf::RenderTexture entre tous les projectiles ?
Voire entre tous tes objets. Ce n'est pas parce qu'un objet fait 20x20 qu'il ne peut pas utiliser un bout d'une render-texture de 50x50 par exemple (n'oublie pas Sprite::setTextureRect).

Je vais donc partir là dessus, et d'un côté ça m'arrange car ça sera plus propre au niveau du code.

Merci beaucoup Laurent !
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Octobre 01, 2013, 10:19:28 am
Bonjour  :)

Je vais exposer ici un problème de performance que j'ai et qui d'après moi est tout a fait normal. Je cherche juste la meileure solution afin de contourner ce problème.

Reprenons l'exemple que j'ai donner plus tôt dans ce topic.

Citer
Imaginons que j'ai un personnage qui tire des projectiles de façon rapide et répété (disons 10/sec) et que je veux appliquer des shader sur chaque projectile

Pour l'instant, j'ai deux sf::RenderTexture partagée entre tout mes objets. Cependant, si dans une frame j'ai 200 projectiles à dessiner, cela prend du temps (200 * (clear + draw)).
Forcément, le programme en souffre.

J'ai donc penser à un sf::VertexArray.
Pourquoi :
Utiliser un vertexArray pour afficher tout mes projectiles d'un coup. Cependant cela me limite au niveau des shaders (si je veux plusieurs projectiles différents, il me faut plusieurs vertexArray). Ce sera quoi qu'il en soit toujours plus performant que l'implémentation actuelle.

Y-aurait-il une autre approche que les vertexArray ?

Cordialement.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent le Octobre 01, 2013, 10:36:02 am
Moi je reste toujours bloqué sur le fait que tu n'arrives pas à avoir des performances correctes en appliquant tes shaders sur tout l'écran. Tu ne devrais pas avoir à bidouiller comme tu le fais là.

Est-ce que tu pourrais écrire un code complet minimal qui reproduit ton problème de performances ? J'aimerais bien m'assurer que tu n'as pas de bêtise dedans ;)
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Octobre 01, 2013, 10:54:02 am
Citer
Moi je reste toujours bloqué sur le fait que tu n'arrives pas à avoir des performances correctes en appliquant tes shaders sur tout l'écran. Tu ne devrais pas avoir à bidouiller comme tu le fais là.

Ce problème (limitation des fps à 30) était causé par la syncronisation verticale. Vous aviez pointé ce problème. De plus j'ai pour le moment enlever l'application des shaders globaux car la structure de base n'est pas encore tout à fait à mon goût.
Je vais quand même faire un code minimal au cas où je verrais mal la chose.
Cependant, corriger ce problème ne me permettrait de contourner pas le soucis que j'ai pour afficher de nombreux objets à chaques frames (car le nombre d'appel à clear/draw sera toujours aussi important).

Au passage, j'ai une petite question un peu plus "technique".
Est-ce que SFML met plus de temps à draw lorsqu'on lui passe un shader en paramètre ?
Si j'ai bien compris openGL, les shaders "prennent la place" de certains module dans le pipeline d'openGL.
Conclusion, les performances devraient être à peu près équivalente, n'est-ce pas ?
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent le Octobre 01, 2013, 11:10:59 am
Citer
Cependant, corriger ce problème ne me permettrait de contourner pas le soucis que j'ai pour afficher de nombreux objets à chaques frames (car le nombre d'appel à clear/draw sera toujours aussi important).
Ok. Donc là on ne parle plus de shaders, juste d'optimiser l'affichage des objets ?

Citer
Est-ce que SFML met plus de temps à draw lorsqu'on lui passe un shader en paramètre ?
Si j'ai bien compris openGL, les shaders "prennent la place" de certains module dans le pipeline d'openGL.
Conclusion, les performances devraient être à peu près équivalente, n'est-ce pas ?
En effet. Cependant, suivant la complexité des shaders et leur nombre, tu peux avoir des trucs assez lourds. En l'occurence, si on parle toujours bien d'un shader de flou gaussien, les nombreuses passes et texture lookup (désolé j'ai pas d'équivalent en français :P) sont typiquement assez lourds en exécution.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Octobre 01, 2013, 11:23:07 am
Citer
Citer
Cependant, corriger ce problème ne me permettrait de contourner pas le soucis que j'ai pour afficher de nombreux objets à chaques frames (car le nombre d'appel à clear/draw sera toujours aussi important).
Ok. Donc là on ne parle plus de shaders, juste d'optimiser l'affichage des objets ?

Exact  :). Car dans une frame je peux me retrouver avec une (voir plusieurs, je ne veux limiter en aucun cas mon projet) centaines d'objet à dessiner.
J'ai déjà piqué votre système de particule pour faire mes explosions, et je pensais faire quelque chose d'a peu près identique pour gérer ma/mes centaines de projectile. Cependant si je veux plusieurs projectiles différents (en utilisant des shaders différents), je dois passer par plusieurs vertexArray du coup.

Exact ?  :D

PS : Je reviendrais plus tard sur mon application de shader globaux
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent 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 ;)
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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  :)
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent 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.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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  :)

Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent 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.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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 ?
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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 :

Avantages :
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent 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 ?
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent 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.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent 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.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney 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.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent 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
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Octobre 24, 2013, 02:57:22 pm
Je comprend tout à fait.

Cependant, je n'ai toujours pas trouvé de solutions pour appliquer mes shader de façon globale sur mon écran 1080p sans tomber à 30fps (si ce n'est utilisé de plus petit sf::RenderTexture ce qui donne un résultat moche).

Pensez vous que je gagnerais à passer directement par openGL et utiliser des VBO ?
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: Laurent le Octobre 24, 2013, 03:11:08 pm
Est-ce que c'est toujours 30 fps ? Ou bien des fois tu as des valeurs entre 30 et 60 ?

L'optimisation est un sujet délicat, tout ce que je peux te dire c'est qu'avant d'essayer tout et n'importe quoi (OpenGL + VBO ? pourquoi ça et pas autre chose ?), il faut identifier ce qui est optimisable.
Titre: Re : Performance, sf::RenderTexture et nombreux Shaders
Posté par: PetitPoney le Octobre 24, 2013, 03:37:40 pm
Non, ça peut descendre en dessous mais c'est "a vu d'oeil" la valeur maximale.

Pourquoi les VBO ?


J'ai déjà fait pas mal d'openGL + VBO pour un jeux en 3D qui avait plus d'affichage à faire que mon projet 2D actuel, pourtant celui-ci était plus rapide. Par contre il n'y avait en effet pas d'utilisation de shader.

Au niveau de l'optimisation.

Comme je l'ai dis précédement j'ai déjà fait un gros travail d'optimisation en rassemblant les objets du même groupe dans trois vertexArray afin de n'avoir que trois draw à utiliser pour plusieurs centaines d'objet.

Actuellement si je spam comme un sale pour avoir un maximum d'objet à l'écran, je monte au grand maxium à 20 draw/frame (en comprenant donc l'application de shader). En utilisant des sf::RenderTexture de la taille de ma fenêtre, je suis en fullscreen à ~25fps, en 1280*720 je monte à ~40pfs, en 800*600 c'est la fête je passe à ~70fps.

Je suppose donc que le problème vient des sf::RenderTexture.
Ce que je ne comprend pas c'est que j'utilise une texture (loadFromFile)  de 2048*2048 pour dessiner mon background étoilé dynamic (sf::VertexArray de 500 sf::Triangles) et je n'ai pas de soucis avec ça.

Pourquoi ça et pas autre chose ?
J'ai déjà pensé à multiThread mes mise à jour de sf::VertexArray, mais je n'ai pas vraiment approfondi le sujet.

EDIT : Les mises à jours des deux plus gros sf::VertexArray ont maintenant leur propre thread. Ce qui ne ralenti pas l'affichage lors de ces mises à jours.
Je n'ai pas gagner en fps, toujours à cause des sf::RenderTexture et de l'application de mes shaders.

En faisant quelques recherches je suis tomber sur ça http://www.jonathanhaehnel.fr/blog/article/render-to-texture-avec-opengl-3-et-glsl-shaders.html (http://www.jonathanhaehnel.fr/blog/article/render-to-texture-avec-opengl-3-et-glsl-shaders.html)
Si mon problème vient bel et bien des sf::RenderTexture, cette technique pourrait-elle m'aider ?

EDIT 2 : D'après les sources de la SFML, les FBO sont déjà implémenté dans la sfml, je ne me trompe pas ?

EDIT3 : J'obtiens finalement des performances correcte en appliquant qu'un seul glow global à toute ma scène. J'utilise donc deux sf::RenderTexture de la taille de ma fenêtre (+ quelques plus petits pour l'application de petits shader locaux).
Je suis maintenant à ~55fps en 1920*1080 ce qui est satisfaisant.