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