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;
}
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;
}