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

Author Topic: Drawing Large Numbers of Shapes Efficiently  (Read 11930 times)

0 Members and 5 Guests are viewing this topic.

BobTheFish

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing Large Numbers of Shapes Efficiently
« on: February 21, 2010, 09:44:10 am »
I have approximately 100,000 shapes, each with its own color and size.
They are going to be moving objects, so I must redraw them all each frame. They are all visible on the screen every frame.

Currently I'm rendering like this each loop:
Code: [Select]
App.Clear();
for (std::vector<sf::Shape>::iterator i = shapes.begin(); i != shapes.end(); i++)
{
App.Draw(*i);
}
App.Display();


I'm getting around 2 frames per second, which is obviously no good.
How can I significantly improve my rendering speed?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing Large Numbers of Shapes Efficiently
« Reply #1 on: February 21, 2010, 10:43:01 am »
Hi

What is your graphics card? Do you run your application in release mode?

There's no way to improve this code, however SFML 2 is optimized for this kind of situation so you may try it if you can.
Laurent Gomila - SFML developer

BobTheFish

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing Large Numbers of Shapes Efficiently
« Reply #2 on: February 21, 2010, 11:10:15 am »
Yes I am running in release mode.

Mobile Intel 945GM Express: 2 fps
Nvidia GeForce 7600GT: 3 fps
Nvidia GeForce GTX 260: 6 fps

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing Large Numbers of Shapes Efficiently
« Reply #3 on: February 21, 2010, 11:12:46 am »
Ok, so you should really try SFML 2. And if it's still not enough, you'll have to use OpenGL directly, 100,000 shapes is quite a huge number for SFML.

By the way, what kind of shapes is it? Rectangles (4 points per shape) or circles (40 points per shape)?
Laurent Gomila - SFML developer

BobTheFish

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing Large Numbers of Shapes Efficiently
« Reply #4 on: February 21, 2010, 11:19:17 am »
Ok I will try SFML 2.

I did actually try straight OpenGL using points and glPointWidth (no display lists or anything like that) and it's only a tiny bit faster.
 
They're squares. I tried circles at first but they were a lot worse (understandably now that I know there are 40 points per shape).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing Large Numbers of Shapes Efficiently
« Reply #5 on: February 21, 2010, 11:50:02 am »
Quote
I did actually try straight OpenGL using points and glPointWidth (no display lists or anything like that) and it's only a tiny bit faster.

To make it efficient using OpenGL, you should try dynamic VBOs or vertex arrays.
Laurent Gomila - SFML developer

BobTheFish

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing Large Numbers of Shapes Efficiently
« Reply #6 on: February 21, 2010, 12:09:18 pm »
You were right about SFML2, I'm getting 11 fps instead of 2!

I'd still like to see if I can get it even faster again, I'll try those things you suggested.

Thanks!

BobTheFish

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing Large Numbers of Shapes Efficiently
« Reply #7 on: February 21, 2010, 12:38:35 pm »
I figure that if SFML2 is working for basic things I can probably use it (instead of SFML1.5) for my project since it's real simple.

But Views aren't working? Or am I doing something wrong? All I did was recompile with SFML2  (for the above issue) and it seems that although Views compile fine they don't function. I'm still using SFML shapes, not OpenGL calls.

Is that because they're not implemented yet?

To be specific, the methods I'm using are View.Zoom and View.Move. They compile fine but calling them doesn't affect the View?

I noticed that App.SetView isn't in the autocomplete list that VC2008 drops down. It does compile though if I type it in manually. Is that related somehow too?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing Large Numbers of Shapes Efficiently
« Reply #8 on: February 21, 2010, 12:50:55 pm »
Many things have changed in SFML 2 (you're lucky that your entire source code compiled with no error!).

In SFML 1, the render window had a reference to your own view, so that any modification to it was always immediately applied.

Now in SFML 2, the render window store its own copy of your view, and you have to call SetView everytime you modify it.
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Drawing Large Numbers of Shapes Efficiently
« Reply #9 on: February 21, 2010, 01:30:29 pm »
Quote from: "Laurent"
There's no way to improve this code
There is. Even if it is rather a small, possibly irrelevant optimization, use pre- instead of postincrement at iterators.

for (std::vector<sf::Shape>::iterator i = shapes.begin(); i != shapes.end(); ++i)

Maybe storing end() helps as well, but this depends on your implementation.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

BobTheFish

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing Large Numbers of Shapes Efficiently
« Reply #10 on: February 21, 2010, 02:32:14 pm »
Thanks for the help guys.

Is there a forum section for SFML2 issues? Or documentation? Had a quick look and couldn't find anything (could be just bad at looking).

Apparently there's a size limit for Views? As soon as the total area gets above 40 million square units (see below for examples) the ConvertCoords method returns incorrect results (small negative numbers).

I can post source if you want?

In SFML1.5, Views with an area over 40 million worked fine.

Example tests I ran:
10000x4000 (40,000,000 square units) works fine, 10000x4001 (40010000 square units) is broken.
6324x6324 (39,992,976 square units) works fine, 6325x6325 (40005625 square units) is broken.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing Large Numbers of Shapes Efficiently
« Reply #11 on: February 21, 2010, 02:57:17 pm »
Quote
There is. Even if it is rather a small, possibly irrelevant optimization, use pre- instead of postincrement at iterators.

for (std::vector<sf::Shape>::iterator i = shapes.begin(); i != shapes.end(); ++i)

Maybe storing end() helps as well, but this depends on your implementation.

Well, this is irrelevant :P

The problem here is that he's changing 100,000 times all the OpenGL states needed to render one shape, which is what slows down 99% of SFML applications. His own code is perfect, he can't do anything about that.

Quote
Is there a forum section for SFML2 issues?

No, just use the Graphics forum if it's about graphics, etc. You can also use the "SFML 2" topic in the general forum if you prefer.

Quote
Or documentation?

Not yet (sorry!), but you can generate the API documentation with doxygen. I've almost finished improving the API documentation (a lot) in SFML 2, only the network module and some graphics classes are not up to date.

Quote
Apparently there's a size limit for Views? As soon as the total area gets above 40 million square units (see below for examples) the ConvertCoords method returns incorrect results (small negative numbers).

I can post source if you want?

Yes please :)
This is not supposed to happen.
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Drawing Large Numbers of Shapes Efficiently
« Reply #12 on: February 21, 2010, 03:06:49 pm »
Quote from: "Laurent"
Well, this is irrelevant :P
Yeah. But it's nice to know if a loop iteration contains less CPU-intensive operations (not related to rendering, for example).

Sorry if it was a bit offtopic, just wanted to say it for other cases. Some time ago in another forum, we had a case where one could really improve performances by using pre-increment (but of course, it was a simple loop). ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

phear-

  • Jr. Member
  • **
  • Posts: 64
    • MSN Messenger - LOApokalypse@hotmail.com
    • View Profile
    • http://gtproductions.org
Drawing Large Numbers of Shapes Efficiently
« Reply #13 on: February 21, 2010, 05:38:21 pm »
This is just a thought/suggestion and it will require some work on your end, but have you ever thought about using multithreading to break up the renderer and your logic? Im assuming you have an update function for your shapes so they move around the screen. Maybe splitting that up into a thread (or two) and then using the main thread or creating another for the actual rendering?
Eugene Alfonso
GTP | Twitter

BobTheFish

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing Large Numbers of Shapes Efficiently
« Reply #14 on: February 21, 2010, 10:45:04 pm »
I have every intention of using threads, I just want to be sure that my rendering thread is efficient :)

Quote from: "Laurent"
Yes please :)
This is not supposed to happen.

To see what I mean, watch the console window when moving the mouse around in the graphics window.
Then close and recompile with a different view size, and see the difference. Or you could zoom in and out with the scroll wheel.

Code: [Select]
#include <SFML/Graphics.hpp>
#include <iostream>

sf::RenderWindow App;
//change this to test different View sizes
sf::View View(sf::FloatRect(0.0f, 0.0f, 10000, 4001));

int main()
{
App.Create(sf::VideoMode(800,600,32), "Test App", sf::Style::Close);
App.SetView(View);

while (App.IsOpened())
    {

sf::Event Event;
while(App.GetEvent(Event))
{
if(Event.Type == sf::Event::Closed)
App.Close();
if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
App.Close();

if(Event.Type == sf::Event::MouseWheelMoved)
{
//Assume delta of 1 or -1
if (Event.MouseWheel.Delta > 0) View.Zoom(0.8f);
else if (Event.MouseWheel.Delta < 0) View.Zoom(1.25f);
App.SetView(View);
}
}

sf::Vector2f mouse = App.ConvertCoords(App.GetInput().GetMouseX(), App.GetInput().GetMouseY());
sf::Vector2f viewsize = View.GetSize();

App.Clear();
App.Display();

std::cout << "Mouse(" << mouse.x << ',' << mouse.y << ") View(" << viewsize.x << ',' << viewsize.y << ')' << std::endl;


        sf::Sleep(0.1f);
}

    return 0;
}