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

Author Topic: Vertex array - HUGE memory usage and bad performance  (Read 14145 times)

0 Members and 2 Guests are viewing this topic.

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Vertex array - HUGE memory usage and bad performance
« on: July 23, 2013, 07:27:10 pm »
I use vertex array tile map code from the tutorial. I use exactly the same draw function as in tutorial and the loading is the same algorithm (I only load from a file but the in-app representation is the same as in tutorial).

When my map is 100 x 100 32px tiles I get 1350 FPS and memory usage of my app is 39mb. Great.
When my map is 300 x 300 32px tiles I get 200 FPS and memory usage 59mb. Well acceptable.

However when I draw a map which is 1000 x 1000 32px tiles, memory usage is 300mb and FPS is 19. That's very bad, I need maps of that size in my game.

Debug and release builds change nothing here. Is it a bug in SFML that memory usage and fps are that bad with increasing number of vertexes? It seems like vertexes are stored in some ineffective way (why they take so much of memory?)

Also I think that vertex array should be stored on GPU side rather than on RAM, correct?

Or it has to be that way and vertex array is overrated? In that case I will just use quad tree of vertex arrays but I'd like to avoid it for the sake of simplicity.

It looks like one vertex takes 65 bytes of RAM which is quite a lot. It should be a lightweight object stored on GPU side I think.
« Last Edit: July 23, 2013, 07:30:48 pm by netrick »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Vertex array - HUGE memory usage and bad performance
« Reply #1 on: July 23, 2013, 07:34:24 pm »
Here's the memory usage calculation:
1000x1000x32x8 = 256000000
256000000 / 1024 / 1024 = 244.140625 MiB

Though I'm not sure what should get saved where etc.

The question now is, do you need to draw those 1000x1000x32 pixels at one time? If so you might indeed have a problem, if not you should start using an octree or similar structures, so you'll only draw what's needed.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #2 on: July 23, 2013, 07:38:42 pm »
I used a method where  I draw 30x20 visible tiles sprite-by-sprite. That way I had constant 200 fps no matter the map size (also 1 000 x 1 000 tiles only took 4mb in memory, as the array of int).

I wanted to switch to vertex array so I could use sf::View to zoom and scroll easier. My previous method didn't allow zooming, only scrolling.

So it looks like I have to use something like quad tree to have a bunch of vertex array and render 1-4 at one time.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Vertex array - HUGE memory usage and bad performance
« Reply #3 on: July 23, 2013, 07:39:01 pm »
It seems like vertexes are stored in some ineffective way (why they take so much of memory?)
It seems like you store them in a ineffective way. Do you duplicate the tile textures?

I don't know why you mention 32 pixels, the size of the vertex array does not depend on the tile size. It is roughly sizeof(sf::Vertex) * numberOfVertices. The vertex array is stored in the RAM and loaded to the graphics card when rendered.

Or it has to be that way and vertex array is overrated?
They are in so far overrated as people think they magically solve any performance problems. Their main advantage in comparison to sf::Sprite is (besides flexibility) the reduction of draw calls.

What you still have to consider yourself, is culling geometries you don't render (namely the part of the map which is not on the screen). Don't put the whole map into a single vertex array.

Here's the memory usage calculation:
This is for the texture, not the vertex array. And only in the case where tiles are needlessly duplicated.
« Last Edit: July 23, 2013, 07:42:02 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #4 on: July 23, 2013, 07:44:02 pm »
Quote
It seems like you store them in a ineffective way. Do you duplicate the tile textures?

I use the exact code from Lautent's tutorial. There is only one single texture with all tiles, which is stored in just one place in the app. Do you think that he stores them ineffectively there? I doubt it could be improved really.

sf::Vertex size is 48 bytes. So it should be 190mb and not 240mb anyway.
« Last Edit: July 23, 2013, 07:49:33 pm by netrick »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Vertex array - HUGE memory usage and bad performance
« Reply #5 on: July 23, 2013, 07:50:43 pm »
I doubt how it could be improved really.
You missed the most important part of my post. Do you store the whole map, including all the invisible parts, in a vertex array? If so, you have your answer.

Laurent's example is meant to show a simple usage of vertex arrays, not to be a 1:1 code to apply in every possible case.

sf::Vertex size is 48 bytes. So it should be 190mb and not 240mb anyway.
Since sf::VertexArray uses a std::vector internally, it may allocate more than necessary to allow faster growing. If this is an issue, call shrink_to_fit(), but keep in mind that this results in a copy of all vertices.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #6 on: July 23, 2013, 07:55:11 pm »
You missed the most important part of my post. Do you store the whole map, including all the invisible parts, in a vertex array? If so, you have your answer.

Okay, I get it. I will just divide world in a few vertex arrays and draw only visible one(s).

Thank you for help.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Vertex array - HUGE memory usage and bad performance
« Reply #7 on: July 23, 2013, 07:58:12 pm »
Okay, I get it. I will just divide world in a few vertex arrays and draw only visible one(s).
That's a good idea for static tile sets.

Alternatively, you can rebuild the vertex array directly from the visible tiles. Especially if tiles are animated or change over time, you will need a more dynamic approach.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #8 on: July 23, 2013, 08:02:13 pm »
]That's a good idea for static tile sets.

Alternatively, you can rebuild the vertex array directly from the visible tiles. Especially if tiles are animated or change over time, you will need a more dynamic approach.

That would be much easier and more flexible solution that some kind of a tree. I will try it, I hope that rebuilding 30x25 tiles vertex array every frame won't have a big impact of performance.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Vertex array - HUGE memory usage and bad performance
« Reply #9 on: July 23, 2013, 08:06:19 pm »
However when I draw a map which is 1000 x 1000 32px tiles, memory usage is 300mb and FPS is 19. That's very bad, I need maps of that size in my game.
Well, yes you might need maps of that size in your game, but nobody said you need to render it all, all the time. The only way you would be able to realistically see all the detail would be on a 32000x32000 (1 Gigapixel) screen. Don't give the industry these kinds of ideas yet please ::).

Debug and release builds change nothing here. Is it a bug in SFML that memory usage and fps are that bad with increasing number of vertexes? It seems like vertexes are stored in some ineffective way (why they take so much of memory?)

Also I think that vertex array should be stored on GPU side rather than on RAM, correct?

It looks like one vertex takes 65 bytes of RAM which is quite a lot. It should be a lightweight object stored on GPU side I think.
sf::VertexArray stores its data in system RAM for you to manipulate as much as you want. As soon as you draw it, it takes the long journey across your PCIe bus to your graphics RAM and waits there until the GPU renders it to the screen. Keep in mind, this happens EVERY frame because SFML doesn't use VBOs. Given that a single sf::Vertex contains an sf::Vector2f for position data, an sf::Vector2f for texture coordinate data and a sf::Color for color data, that sums up to 2*4+2*4+4*1=20 bytes per vertex. Because sf::Vertex is not polymorphic, the size of its members should constitute its own size. No idea where you got the 65 bytes (or 48 bytes) from... How the data is stored in graphics RAM is another question. It is an internal detail and something we don't need to know about, but I have a feeling it isn't more than the space requirement in system RAM.

If an sf::Vertex is 20 bytes large and you have 1001*1001 of them (1000*1000 tiles) you should end up with an sf::VertexArray of at least 20MB. That leaves the majority of memory consumption to the rest of your application including the baseline that SFML needs to run.

If you are hellbent on displaying that much graphical content on the screen, SFML won't really help you further, you need to code something in OpenGL yourself (you might want to look at VBOs for this). My GPU has no problem rendering a VBO of 2 million triangles every frame.

As Nexus and eXpl0it3r already said, for the panning issue, you need to reduce the amount of stuff you are drawing if you know most of it is offscreen. When zooming out, you can either compute custom mipmaps of regions much like OpenGL does, or you can think of some fancy LOD algorithm that takes care of seamless zooming while keeping the primitive count down. All very advanced topics, but who am I to stop someone from tinkering ;).
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Vertex array - HUGE memory usage and bad performance
« Reply #10 on: July 23, 2013, 08:17:59 pm »
I hope that rebuilding 30x25 tiles vertex array every frame won't have a big impact of performance.
Certainly not. For my platformer Zloxx II, I created sf::Sprites every frame anew and drew them individually, using a similar amount of tiles (vertex arrays in SFML didn't exist at that time). That was no problem, even on netbooks or older desktops...
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Vertex array - HUGE memory usage and bad performance
« Reply #11 on: July 23, 2013, 08:18:49 pm »
Quote
sf::Vertex size is 48 bytes.
Is it really? What system and compiler is that?

You can also use dbug's shader(my improved version) to draw tiles using shaders keeping 1 tile per pixel in map texture but then you're limited by shader version(honestly I'm not sure that #version 130 is needed at the top but dbug had it) and texture size and so on and might need to create option to use/fallback vertex arrays if shader doesn't run.
But on the plus side you get ok performance, free rotating/scaling/culling/etc., map is a single sf::Sprite and even quite ancient cards have 1024x1024 textures at least(or you could load your map in few goes then into few textures and sprites or fallback to vertex arrays) and you get few bits per each tile(each tile has 2^32 values) to optionally put your own stuff and can add animation, alpha, etc. as you desire to the shader, also maps are automatically compressed in png/whatever other format and you can copy, paste and edit them using gimp, paint or sf::Image in code easily etc.

Quote
If an sf::Vertex is 20 bytes large and you have 1001*1001 of them (1000*1000 tiles) you should end up with an sf::VertexArray of at least 20MB.
Binary, a tile is 4 vertices... ;D
Back to C++ gamedev with SFML in May 2023

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Vertex array - HUGE memory usage and bad performance
« Reply #12 on: July 23, 2013, 08:23:25 pm »
Quote
If an sf::Vertex is 20 bytes large and you have 1001*1001 of them (1000*1000 tiles) you should end up with an sf::VertexArray of at least 20MB.
Binary, a tile is 4 vertices... ;D
Hmm yeah forgot that sf::VertexArray needlessly duplicates vertices position data... oh well don't use them myself anyways ::). Using indexed VBOs you could slash so much off that requirement...
« Last Edit: July 23, 2013, 08:25:37 pm by binary1248 »
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #13 on: July 23, 2013, 08:27:03 pm »
Quote
sf::Vertex size is 48 bytes.
Is it really? What system and compiler is that?

Uh sorry, it is 20 bytes. I was thinking of something different when typing this lol.

1000 x 1000 x 4 x 20 = 80mb for 1000 tiles.
I don't know what is using so much of memory. std::vector itself and other internal things can't take 160mb of memory...

BTW I will look into shader map.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Vertex array - HUGE memory usage and bad performance
« Reply #14 on: July 23, 2013, 08:32:46 pm »
std::vector itself and other internal things can't take 160mb of memory...
Why not? Let's assume the vector has a grow factor of 2 (typically it's not 2 in STL implementations) and the following worst case scenario occurs:

The old vector has a size of 80MB which is exhausted, and only a few bytes more are required. The newly allocated vector thus has a size of 160MB, wasting almost 50% of its memory. For exception safety, the old memory won't be released before the new one has been allocated, that is, 240MB are used at the same time. After std::vector::push_back(), 80MB can be released, but the application usually doesn't return unused memory directly to the operating system.

If you are interested, change SFML's source code to check for the eventual std::vector::capacity(), and compare it with size(). By specifying the number of vertices beforehand, rather than appending them continuously, you can avoid unnecessary reallocations.
« Last Edit: July 23, 2013, 08:37:30 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development: