Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Why it could be slower render with a sf::VertexArray than using sf::Sprites ?  (Read 3674 times)

0 Members and 1 Guest are viewing this topic.

Jose Luis

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Thanks in advance, the point is the next. I have making a little particle engine, the problem come when i tried to optimize it using a vertexarray to render it. The first implementation, using sf::Sprites, could render 10K particles without problem in my machine, but when I have changed to a sf::VertexArray implementation the render process become slower, it cannot mantain the framerate with 3K particles. What Could I be doing wrong?.

One thing more, I belive noticed the problem is in the RenderWindow::draw call because I have monitoring the program with and without this call. I let you some code snippet. Thanks again.
void System::draw (sf::RenderWindow& theWindow)
{
   mVertices.clear();

   std::list<Particle>::const_iterator it;
   for(it = mParticles.begin();it != mParticles.end();it++)
   {

      sf::Transform anTransform;

      anTransform.translate(it->getPosition().x,it->getPosition().y);
      anTransform.rotate(it->getAngle());
      anTransform.scale(it->getScale().x,it->getScale().y);
      sf::Rect<int> anTexRect = it->getTexRect();

      sf::Vector2f anPositions[4];
      anPositions[0] = anTransform.transformPoint(sf::Vector2f(-(anTexRect.width / 2),-(anTexRect.height /2)));
      anPositions[1] = anTransform.transformPoint(sf::Vector2f( (anTexRect.width / 2),-(anTexRect.height /2)));
      anPositions[2] = anTransform.transformPoint(sf::Vector2f( (anTexRect.width / 2), (anTexRect.height /2)));
      anPositions[3] = anTransform.transformPoint(sf::Vector2f(-(anTexRect.width / 2), (anTexRect.height /2)));

      sf::Vector2f anTexCoords[4];
      anTexCoords[0] = sf::Vector2f(anTexRect.left,                  anTexRect.top);
      anTexCoords[1] = sf::Vector2f(anTexRect.left + anTexRect.width, anTexRect.top);
      anTexCoords[2] = sf::Vector2f(anTexRect.left + anTexRect.width, anTexRect.top + anTexRect.height);
      anTexCoords[3] = sf::Vector2f(anTexRect.left,                  anTexRect.top + anTexRect.height);

      for (int i = 0; i < 4;i++)
      {
         mVertices.append(sf::Vertex(anPositions[i], sf::Color(255, 255, 255, 255),anTexCoords[i]));
      }
      theWindow.draw(mVertices,mStates);
   }
 

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
You're drawing your whole vertex array for every particle. The last line (the draw call) should be outside the loop.
Laurent Gomila - SFML developer

Jose Luis

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
I'm very shamed. Thank you.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
So what performances do you get now? ;)
Laurent Gomila - SFML developer

Jose Luis

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
I cannot prove it right now, but I have done it with a big tiled map and the improvement was very high. When I fix it i'll tell you the result. Thanks a lot again.

Jose Luis

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Great!. Very notable performance improvement.

Haze

  • Full Member
  • ***
  • Posts: 201
    • View Profile
    • Github Profile
Just wondering, rebuilding a vertex array for each frame (which can induce memory reallocation + copy) is more efficient than drawing each particle one at a time with a different draw call?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
There's no reallocation because sf::VertexArray is based on std::vector which never frees its memory until it is destroyed. Moreover, draw calls are very expensive, the graphics card is not designed for many draw calls, but rather for few calls that draw many polygons at once.
Laurent Gomila - SFML developer

Haze

  • Full Member
  • ***
  • Posts: 201
    • View Profile
    • Github Profile
There's no reallocation because sf::VertexArray is based on std::vector which never frees its memory until it is destroyed.
But the number of particles will increase overtime, so if a vector doesn't have enough memory allocated, a new chunk of memory will be allocated and the old content is copied, then free'd.
But I think I overestimated this, reallocations shouldn't happen often thanks to the vector growing strategy.

Moreover, draw calls are very expensive, the graphics card is not designed for many draw calls, but rather for few calls that draw many polygons at once.
Good to know, thanks for the tip.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Quote
But the number of particles will increase overtime, so if a vector doesn't have enough memory allocated, a new chunk of memory will be allocated and the old content is copied, then free'd.
I wouldn't say "over time". The vector will most likely reach its maximum size after a few updates, and if it's still a problem then you can allocate the required memory at init time instead of letting the vector grow.
Laurent Gomila - SFML developer