SFML community forums

Help => Graphics => Topic started by: alwayslearning on April 21, 2010, 11:02:20 pm

Title: Looking for a better design for drawing sprites in order.
Post by: alwayslearning on April 21, 2010, 11:02:20 pm
The problem is, code execution order does not guarantee sprites will be drawn in order without some sort of method to track their levels, sort the sprites, and then drawing them.

What are your ways of doing this?

My method:
If the drawables need to be rendered they are added to a draw vector (only happens when set view == true, not every frame)
At the end of each frame, drawables on vector are sorted (std::sort), then merged with an in-order drawables list.
Then the list is iterated through executing windows::draw()

By the end, the draw list contains all the drawables rendered last frame in order, removing the need to continually adding, sorting sprites every frame.


If a drawable is no longer visible, it is removed from the list.
I use a map to do this rather than iterate through the list looking for the drawable.
Title: Looking for a better design for drawing sprites in order.
Post by: Ashenwraith on April 21, 2010, 11:12:59 pm
You should not be changing your list if nothing is changed.

Ideally you should be trying to recycle as many sprites as you can or draw them off screen if they are reappearing fast.
Title: Looking for a better design for drawing sprites in order.
Post by: alwayslearning on April 22, 2010, 08:24:23 am
I agree.  Objects are only added and removed if their visibility or levels have changed.  Which is not a common occurrence in the middle of a non-game state.

I am wondering if there are any implementation designs that are an improvement over mine as it is costly to remove drawables from the list.   All drawables on the list are used as the key and the list iterators used as the value within an std::map to facilitate searching drawables for removal.

This requires 2 calls to map (find, and erase) and 3rd call to list (erase).
Title: Looking for a better design for drawing sprites in order.
Post by: Ashenwraith on April 22, 2010, 08:29:08 am
Did you try sprite recycling like I suggested?

For example, you have a fixed average for drawables and you edit the drawables themselves.

Instead of taking them out of an array you could replace their image with a sf:Color(0,0,0,0)

If they reappear soon you could move them offscreen

You have to look at the workload and see if it's the gpu or the cpu that could use the most benefit.
Title: Looking for a better design for drawing sprites in order.
Post by: Laurent on April 22, 2010, 09:55:27 am
Removing a sprite from a collection will always be much faster than sending all the OpenGL commands required to draw it.
Title: Looking for a better design for drawing sprites in order.
Post by: Ashenwraith on April 22, 2010, 11:37:21 am
Quote from: "Laurent"
Removing a sprite from a collection will always be much faster than sending all the OpenGL commands required to draw it.


That's what I thought, but what if you are doing snow or constant enemies. Wouldn't it be better to just move it off screen?

Also say you have an enemy die, you could make it 0,0,0,0 then change it to treasure in the same sprite set?

I'm trying to think of what would keep the cache as consistent as possible with tricks.
Title: Looking for a better design for drawing sprites in order.
Post by: Laurent on April 22, 2010, 12:04:21 pm
"The fastest geometry is the one that you don't draw".

Reusing sprite instances is not really an optimization, a sprite is a lightweight object and its creation/destruction doesn't involve expensive operations.
Title: Looking for a better design for drawing sprites in order.
Post by: Cyrano on April 22, 2010, 04:00:39 pm
Quote from: "Laurent"
"The fastest geometry is the one that you don't draw".

Reusing sprite instances is not really an optimization, a sprite is a lightweight object and its creation/destruction doesn't involve expensive operations.


So then, what is an optimization?

I can see how not drawing geometry over and over is a good idea. It wastes time and CPU power, but aside from reducing redundancy and useless system calls, what other optimizations can you make?
Title: Looking for a better design for drawing sprites in order.
Post by: Laurent on April 22, 2010, 06:32:38 pm
Optimizations that you can make depend on what the application, what it draws and how it uses the graphics module.

But basically, SFML is designed so that people can concentrate on high-level stuff and not on finding the most optimized way of doing things -- there's only one in SFML.
Title: Looking for a better design for drawing sprites in order.
Post by: Cyrano on April 22, 2010, 06:41:15 pm
Quote from: "Laurent"
Optimizations that you can make depend on what the application, what it draws and how it uses the graphics module.

But basically, SFML is designed so that people can concentrate on high-level stuff and not on finding the most optimized way of doing things -- there's only one in SFML.


I like that line of reasoning. :)

The reason I asked was simply to find out whether or not there was a more efficient way of getting the job done.

Thanks!

-Cyrano
Title: Looking for a better design for drawing sprites in order.
Post by: alwayslearning on April 23, 2010, 11:01:47 am
For anyone still reading.

I wrote up another method of storing drawables by using std::multiset and compared it with my original.

It's approximately 2x faster.
Using the list, vector, and map = ~37 seconds
Using multiset = ~20 seconds

I'm going to stick with multiset.
Title: Looking for a better design for drawing sprites in order.
Post by: Ashenwraith on April 23, 2010, 11:25:27 am
That's interesting, I was researching multiset.

Can you post your code?
Title: Looking for a better design for drawing sprites in order.
Post by: panithadrum on April 23, 2010, 12:42:51 pm
Quote from: "alwayslearning"
For anyone still reading.

I wrote up another method of storing drawables by using std::multiset and compared it with my original.

It's approximately 2x faster.
Using the list, vector, and map = ~37 seconds
Using multiset = ~20 seconds

I'm going to stick with multiset.


You should test it with different amount of drawables (10, 100, 1000 and 10000 for example). I'm sure the results will be different from a certain number of it.

What about std::multimap?
Title: Looking for a better design for drawing sprites in order.
Post by: gsaurus on April 23, 2010, 01:48:32 pm
I didn't noticed there were 2 threads about the same thing. I posted an example using multiset here (http://www.sfml-dev.org/forum/viewtopic.php?t=2367)
Title: Looking for a better design for drawing sprites in order.
Post by: alwayslearning on April 23, 2010, 08:24:05 pm
Running with differing amount of drawables.  

This is my test scenario (worst case)
Adding sprites 1 by 1.
Drawing through.
Removing 1 by 1 using the find/lookup methods.

Here are the results so far (in ticks):
10,000 loops
a) map + vector + list
b) multiset

10 sprites
a) 343
b) 188

100 sprites
a) 3797
b) 2047

1000
a) 326,219
b) 26,812

(retested 1000 sprites)
a) 392,266
b) 26,406

10000
a) -
b) -

I'll write one up using multimap in a second.
Title: Looking for a better design for drawing sprites in order.
Post by: alwayslearning on April 23, 2010, 09:06:40 pm
Here are the results of multimap vs multiset (using same test case as above)

Here are the results so far (in ticks):
10,000 loops

10 sprites  
[map] average: 234
234
234
234

[set] average : 254
312
234
218

100 sprites
[map] average : 2755
2844
2734
2688

[set] average : 2668
2047
2500
3459

1000 sprites
[map] average : 34,568
34,813
34,297
34,594

[set] average : 32,291
32,390
32,375
32,109

10000
multimap) 388,969

multiset) 388,563


Its pretty damn close.
Title: Looking for a better design for drawing sprites in order.
Post by: gsaurus on April 23, 2010, 10:00:57 pm
Quote from: "alwayslearning"
Its pretty damn close.

Yes, because they are internally implemented basically in the same way.
Title: Looking for a better design for drawing sprites in order.
Post by: Nexus on April 23, 2010, 11:00:54 pm
The reason why a programmer has to decide between std::multiset and std::multimap is never performance. It depends on him requiring separate keys and values or not.

It's not very meaningful to directly compare std::vector, std::set and std::map, either. These containers have quite different concepts.