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

Auteur Sujet: [sfml-2.0] vertexArray et renderTexture : soucis de performances  (Lu 4291 fois)

0 Membres et 1 Invité sur ce sujet

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Salut,

en parcourant les forums j'ai souvent vu qu'il était préférable de limiter les appels de la fonctions "draw" en utilisant un vertexArray englobant un maximum d'objet.
J'ai donc fait un test où je dessine 100 fois un sf::Quad sur une texture, soit 100 appels à la fonction draw d'un renderTexture. Puis j'ai comparé avec un seul appel d'un vertexArray comprenant 100 fois le même sf::Quad.

Au final ça tourne à 30 FPS en moyenne dans les 2 cas et la majorité du temps est passé dans le window.display()  (même lorsque j'active le display() de renderTexture juste avant).
Je vous envoie un code simplifié de ce que je fais pour essayer de comprendre pourquoi je n'obtiens pas de meilleurs performances dans le cas où je ne fais qu'un seul appel à la fonction "draw".

Cordialement,
ugo

Je suis sous SFML 2.0 dernière version en release. Je possède une carte NVidia.


#include <SFML/Graphics.hpp>

void initVertexArrays(sf::VertexArray &bigVertex, sf::VertexArray &smallVertex, unsigned nbRect, sf::RenderWindow const& window);

int main()
{
    sf::RenderWindow window(sf::VideoMode(124*8, 124*8), "My window");

    sf::RenderTexture  renderTexture;
    renderTexture.create(window.getSize().x,window.getSize().y);

    unsigned int nbRect = 100;
    bool bigVertexEnable = false;       // pour afficher le gros vertex plutot que le petit :D
    bool textureDisplayEnable = false; // pour autoriser le display de la texture en plus de celui sur window

    sf::VertexArray bigVertex;                  // Vertex array contenant nbRect fois un carré
    bigVertex.setPrimitiveType(sf::Quads);
    bigVertex.resize(4*nbRect);

    sf::VertexArray smallVertex;                // Vertex array contenant seulement un carré, mais affiché nbRect fois
    smallVertex.setPrimitiveType(sf::Quads);
    smallVertex.resize(4);

    initVertexArrays(bigVertex, smallVertex,nbRect, window) ; // Initialisation des deux vertex

    ///////////////////////////////////////////////////////////////////////////////////////
    while (window.isOpen())
    {
            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed) window.close();

                if(event.type == sf::Event::KeyPressed)
                {
                    if(event.key.code==sf::Keyboard::Space) bigVertexEnable = ! bigVertexEnable;                // dessin du gros ou du petit vertexArray
                    else if(event.key.code==sf::Keyboard::Return) textureDisplayEnable =! textureDisplayEnable; // display ou non de la renderTexture
                }
            }

            window.clear();
            renderTexture.clear();

            if(bigVertexEnable)                         renderTexture.draw(bigVertex);  // Un seul appel à la fonction draw pour dessiner nbRect fois un quad à la fois
            else     { for(unsigned i=0; i< nbRect;i++) renderTexture.draw(smallVertex); } // nbRect appels à la fonction draw pour dessiner un seul quad à la fois


            if(textureDisplayEnable) renderTexture.display();     // display de la renderTexture

            window.draw(sf::Sprite(renderTexture.getTexture()));    // Dessin de la texture sur la fenêtre

            window.display();   // DISPLAY

    } //Endwhile
    ///////////////////////////////////////////////////////////////////////////////////////

    return 0;
}


 

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #1 le: Mars 05, 2013, 04:43:20 pm »
Et si tu ne dessines rien (just clear() + display()), tu as combien de FPS ? Tu le mesures comment, au fait ?
Laurent Gomila - SFML developer

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #2 le: Mars 05, 2013, 04:53:21 pm »
Salut,

je dessine mes vertexArrays sur un sf::renderTexture, puis j'applique la texture résultante sur la fenêtre.

Les positions des vertexes et les couleurs sont initialisées dans la fonction "void initVertexArrays(...)".
Ce sont des carrés verts avec un coin en rouge pour faire classe :)

Pour le fps, j'utilise tout simplement un sf::clock et je prend le temps pour dessiner, puis celui pour faire le windows.display() sur une seconde. Et au bout d'une seconde j'affiche sur la console le temps moyen de ces deux étapes.
Je peux envoyer le code complet (130 lignes +ou-), là j'ai essayé de mettre un code minimal.

ugo




Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #3 le: Mars 05, 2013, 05:03:02 pm »
Tu devrais mesurer le FPS avec un logiciel externe type FRAPS.

Et sinon, je ne t'ai pas demandé de détailler ce que fait ton programme, mais juste d'essayer ça :
Citer
Et si tu ne dessines rien (just clear() + display()), tu as combien de FPS ?
;D
Laurent Gomila - SFML developer

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #4 le: Mars 05, 2013, 05:11:33 pm »
A mince, j'ai lu de travers :D

Ok donc sans le dessin je suis proche des 400 FPS.
Par contre les chutes de performances avec le dessin se voient directement, la fenêtre est beaucoup moins fluide. Et dans les deux configurations.

Je vais cherche Fraps et tester pour avoir une mesure plus précise.

Sinon dans le code que j'ai posté il n'y a rien de choquant sur l'utilisation des vertexArrays et renderTexture?

ugo

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #5 le: Mars 05, 2013, 05:58:37 pm »
Essaye sans render-texture, elle n'a rien à voir avec ce que tu veux tester.
Laurent Gomila - SFML developer

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #6 le: Mars 05, 2013, 06:09:29 pm »
Ok donc je suis passé en dessin sur la fenêtre et j'ai retiré la texture.

Je tourne toujours autour des 30 FPS (avec ma méthode de mesure, pas les droits admin au boulot pour installer Fraps).
Le temps de calcul de la fonction window.draw(sf::VertexArray ...) est quasi nul, alors que celui du windows.display() est de l'ordre de 30 msec. Forcément il n'y a plus l'étape où je recopie la texture à l'écran.

En désactivant le dessin ça tourne à 1000 FPS.

ugo

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #7 le: Mars 05, 2013, 08:16:05 pm »
Dans ce cas, peux-tu faire un code vraiment minimal de chez minimal (pas de truc tarabiscoté avec les vertex arrays, dessine juste le truc le plus simple que tu peux), et qui montre ton calcul de FPS.
Laurent Gomila - SFML developer

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #8 le: Mars 05, 2013, 11:35:12 pm »
Voilà j'ai installé à la maison Fraps et j'ai pu faire quelques tests.
Mon affichage du FPS donne les mêmes valeurs (à vu d'oeil) que Fraps.

Par contre je n'ai pas la même carte graphique qu'au boulot, c'est une AMD Radeon HD 6800.
Elle est plus puissante et le cas de cet après midi qui tournait autour de 30 FPS au boulot, se retrouve à 60 FPS chez moi. Puis au bout d'un moment la fonction display() n'est plus aussi gourmande et ça file à 145 FPS.

Comme tu me l'as demandé, j'ai fait un code minimal où je dessine un simple sf::CircleShape. J'y ai mi ma façon de calculer le FPS, ainsi que le temps moyen des parties dessin et display.
Chez moi, avec ma carte AMD, je tourne à 200FPS pendant un moment puis tout s'emballe et j'arrive à 2000+ FPS. En regardant le benchmark sous Fraps cela arrive après une vingtaine de secondes. Sur mon affichage console j'observe que le temps nécessaire pour la fonction display est de 4.5 msec, puis il tombe à 0.45 msec ce qui entraîne le pique de FPS.

ugo

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

using namespace std;

int main()
{
    sf::RenderWindow window(sf::VideoMode(124*8, 124*8), "My window");


    // Création d'un cercle de rayon 500 pixel
    sf::CircleShape circle;
    circle.setRadius(500.0f);

    // Timers
    sf::Clock clock;
    float timerGlobal = 0.0f;   // Pour mesurer le temps d'une frame
    float timerDraw = 0.0f;     // Mesure du temps passé à dessiner
    float timerDisplay = 0.0f;  // Mesure du temps pour window.display()
    float t1,t2,t3,t4;          // Pour stocker le temps facilement
    unsigned nbFps = 0;         // Pour compter le nombre d'image par seconde

    ///////////////////////////////////////////////////////////////////////////////////////
    while (window.isOpen())
    {
            t1 = clock.getElapsedTime().asMilliseconds();   // on prend le temps en début de frame

            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed) window.close();
            }


            t2 = clock.getElapsedTime().asMilliseconds();

            ///////////////////////////////////////////////////////////////////
            // DESSIN
            window.clear();

            window.draw(circle);

            t3 = clock.getElapsedTime().asMilliseconds();
            timerDraw += t3 - t2;
            ///////////////////////////////////////////////////////////////////

            ///////////////////////////////////////////////////////////////////
            // DISPLAY
            window.display();

            t4 = clock.getElapsedTime().asMilliseconds() ;
            timerDisplay += t4 - t3;
            ///////////////////////////////////////////////////////////////////


            timerGlobal  += t4 - t1;    // ajout du temps de la frame (

            nbFps++;
            if(timerGlobal>1000.0f) // toutes les secondes on fait les comptes et on affiche les temps
            {
                cout << "FPS " << nbFps << '\n';
                cout << "draw " << timerDraw/static_cast<float>(nbFps) << '\n';
                cout << "display " << timerDisplay/static_cast<float>(nbFps) << "\n\n";

                nbFps = 0;          // reset des timers
                timerDraw = 0.0f;
                timerDisplay = 0.0f;

                timerGlobal -= 1000.0f ; // on garde ce qui dépasse de la seconde
                timerGlobal += (clock.getElapsedTime().asMilliseconds() - t4); // les sorties coutent , donc je les ajoute
            }

    } //Endwhile
    ///////////////////////////////////////////////////////////////////////////////////////

    return 0;
}

 

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #9 le: Mars 07, 2013, 10:34:11 am »
Finalement je pense que c'est parce que je ne comprends pas exactement ce que fait la fonction display() que je n'arrive pas à optimiser mon code.

Si j'ai bien compris, quand j'effectue un window.display(), j'affiche à l'écran ce qui a été dessiné? Donc à priori la fonction window.display() devrait être constante par rapport au nombre de pixel à dessiner (correspondant à la taille de la fenêtre). Or son temps varie lorsque je fais un grand nombre de dessins (ils peuvent se superposer car il arrive que  je fasse plusieurs passe pour un rendu particulier).
Donc finalement la fonction draw met en mémoire les formes et la fonction display dessine tout? J'ai lu dans les forums qu'elle contenait la fonction glFLush() d'openGL. J'ai donc testé de mettre un glFlush() après un dessin, mais aucun changement (mauvaise configuration de ma part peut être).
Bref que fait la fonction display et comment dessiner pour être optimal?

J'ai aussi voulu tester les sf::RenderTexture car j'ai vu qu'il y avait la fonction sf::renderTexture::display(). Mais cette fonction semble n'avoir aucune incidence sur le window.display final. Et en plus l'image est retournée. Dans le code SFML j'ai pu lire que cette fonction devait être appelée pour éviter de laisser la texture dans un état indéfinie. Cela signifie quoi? cette fonction est elle vraiment indispensable? Y a t il des conséquences (performances / plantages) à ne pas l'utiliser?

ugo

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #10 le: Mars 07, 2013, 10:40:41 am »
En fait, OpenGL fonctionne en mode asynchrone. C'est-à-dire que lorsque tu appelles une fonction OpenGL (enfin, lorsque SFML le fait), ça ne va pas directement l'exécuter ; au lieu de cela, le pilote graphique va stocker la commande dans une file d'attente, et cette file d'attente ne sera exécutée que plus tard. Typiquement, elle est traitée lors de l'appel à la fonction display() . C'est pour cela que le temps de calcul est généralement concentré dans cette fonction. La fonction glFlush(), quand à elle, permet de forcer l'exécution de la file d'attente des commandes.

Bref, à moins d'avoir une bonne connaissance des mécanismes OpenGL sous-jacents, il n'est pas utile de mesurer le temps d'exécution des fonctions individuellement, les résultats ne seront pas ce à quoi tu t'attends puisque rien n'est exécuté "en live".

En ce qui concerne sf::RenderTexture, tu n'as pas à te poser ce genre de question. L'API est faite de sorte qu'il est obligatoire d'appeler la fonction display(), donc fais-le ;)
Si ça pose des problèmes alors fais un rapport de bug en bonne et dûe forme.
Laurent Gomila - SFML developer

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #11 le: Mars 07, 2013, 10:47:46 am »
Ah, ça explique pas mal de chose, merci beaucoup j'ai l'impression de mieux cerner ce qui se passe.

Par contre pour sf::RenderTexture, ça ne bug pas pour moi. Au contraire!!! Je comprends le retournement de l'image lorsqu'on passe par un FBO. Mais si je ne fais pas appel à la fonction display(), l'image n'est pas retournée, moins de temps de calcul (la fonction sf::RenderTexture::display() coute un peu et je n'ai pas vu de différence dans le display() final) et surtout elle contient exactement ce que je voulais dessiner \o/
Donc je serais tenté de ne pas l'appeler, c'est pour ça que ta réponse sur les sf::RenderTexture ne me fait pas sentir son utilité.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #12 le: Mars 07, 2013, 10:52:48 am »
Ben normalement, si ta carte supporte les FBO, RenderTexture::display() ne fait que le retournement de texture justement (enfin elle met un flag qui indique à la texture qu'elle est retournée). Et peut-être aussi un glFlush(), je ne me rappelle plus.

Du coup si, chez toi ça bug. Est-ce que tu pourrais me faire un code complet minimal qui montre le problème ?
Laurent Gomila - SFML developer

Suskive

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #13 le: Mars 07, 2013, 10:58:26 am »
Tu veux dire que normalement le FBO retourne la texture et que le display() permet de la remettre dans le bon sens?

Je vais regarder ça.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [sfml-2.0] vertexArray et renderTexture : soucis de performances
« Réponse #14 le: Mars 07, 2013, 11:37:23 am »
Citer
Tu veux dire que normalement le FBO retourne la texture et que le display() permet de la remettre dans le bon sens?
Exactement.
Laurent Gomila - SFML developer