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

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

0 Members and 2 Guests are viewing this topic.

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 #15 on: July 23, 2013, 08:45:30 pm »
Quote
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...
But.. OpenGL :'( programming... it's hard like OpenGL :'(
I've never seen anyone color their maps so the glColorPointer call and the 4 bytes from your own specialized sf::Vertex could be scrapped for 20% instant size cut... I think. I don't know OpenGL :'( at all. Most people here(ie. me) probably don't know assembly, OpenGL :'( and c++ at all or as good as you do.

Quote
(typically it's not 2 in STL implementations).
GCC and its STL like to troll apparently, not only operator[] does not assert at all(!!), the vector new length is calculated like: size + max(size,1) so it goes from 0 to 1and then keeps doubling... and netrick is on Linux so.. yeah, it's actually exactly 80 mbs allocated for 4 million pushed vertices. It probably could sum up and the virtual memory, minor page faults from stl structures that grow in advance, dlls and so on might make it seem worse: http://www.frogatto.com/?p=3
« Last Edit: July 23, 2013, 09:10:01 pm by FRex »
Back to C++ gamedev with SFML in May 2023

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Vertex array - HUGE memory usage and bad performance
« Reply #16 on: July 23, 2013, 09:57:40 pm »
To explain why the factor 2 is a particularly bad choice: It represents exactly the threshold that inhibits the usage of previously allocated memory. Growing by a factor of 2 is the worst possible allocation strategy.

Consider the scenario where a vector grows multiple times in a row (no other allocations occur in between).  Typically, there may be a large block of memory, at the beginning of which the vector is placed initially. # denotes an allocated and - an unusable byte.

When the vector grows by a factor of 2, the sum of the previous blocks is always a single byte too small for the new vector. As a consequence, the memory of all of its previous allocations cannot be used again, and the vector wanders continuously forward in memory.
Round     Allocated     Memory Usage
  1.          1         #
  2.          2         -##
  3.          4         ---####
  4.          8         -------########
  5.         16         ---------------################

As a result, a vector of capacity N uses 2N-1 bytes while growing. In the worst case, only slightly more than 50% of the elements are actually used, resulting in an effective usage of 25% of the memory, while 75% are wasted. Even though 50% can be used for future allocations, the growing process itself requires an overly big amount of memory.

The Dinkumware STL implementation of MSVC uses a factor 1.5 and therefore avoids this issue. After 4 allocations, old blocks can be used again.
Round     Allocated     Memory Usage
  1.          1         #
  2.          2         -##
  3.          3         ---###
  4.          4         ------####
  5.          6         ######----
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 #17 on: July 23, 2013, 10:12:17 pm »
I know ;), I just forgot gcc uses 2, I knew visuals 1.5.
That's also what folly tried to leverage in its favor: https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md
And then you wonder why people reimplement STL while gcc uses 2x and doesn't check []. ;D
Who knows what other semi-witchcraft code sits in some STL implementation of some compiler.
« Last Edit: July 23, 2013, 10:14:12 pm by FRex »
Back to C++ gamedev with SFML in May 2023

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #18 on: July 24, 2013, 09:22:37 am »
Is there any good STL implementation out there that I can use with gcc? In some aspects gcc generates really bad code compared to other compilers...

Silvah

  • Guest
Re: Vertex array - HUGE memory usage and bad performance
« Reply #19 on: July 24, 2013, 03:23:12 pm »
GCC and its STL like to troll apparently, not only operator[] does not assert at all(!!)
Have you tried enabling the debug mode? If you don't enable it, the debug checks are disabled, obviously.

To explain why the factor 2 is a particularly bad choice: It represents exactly the threshold that inhibits the usage of previously allocated memory. Growing by a factor of 2 is the worst possible allocation strategy.
It's a tradeoff. Factor of 1.5 copies more often, factor of 2 wastes more memory.

Of course, if you think that a factor of 2 is egregiously bad, you should file a bug in libstdc++. Still, the developers are aware of potential drawbacks, but they have some evidence that for real world code factor of 2 is faster.

At any rate, if you think that a smaller factor will benefit your case, you can implement it. if(vector.size() + itemsToAdd > vector.capacity()) vector.reserve(getNewCapacity(vector.capacity(), itemsToAdd)); is not exactly rocket science. And while reserve guarantees merely that capacity >= N, not capacity == N, on most if not all real implementations it'll grow to N.
« Last Edit: July 24, 2013, 03:42:48 pm by Silvah »

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 #20 on: July 24, 2013, 03:59:05 pm »
The debug mode is 'enabled' as in NDEBUG is not defined so asserts happen.
It's 'disabled' as in _GLIBCXX_DEBUG is not defined and without it glibc++ doesn't have even asserts in vector.
And _GLIBCXX_DEBUG is "Undefined by default" (because it might mess up badly if a stl class is passed between units that are not both compiled with same debug switch because the sizes of stl classes change in debug) so there's a nasty surprise waiting to happen.
Back to C++ gamedev with SFML in May 2023

netrick

  • Full Member
  • ***
  • Posts: 174
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #21 on: July 24, 2013, 05:15:49 pm »
Going back to orginal topic, now I make a new vertex array from visible tiles every frame. I get constant 800fps and very low memory usage even when map is 1000 x 1000 tiles (40mb in that case).

Ancurio

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #22 on: July 25, 2013, 07:51:31 pm »
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...

Can you explain to me where these redundant vertices could be slashed off? Having recently implemented a tmx loader in openGL using indexed VBOs, I came to the conclusion that it's not really very viable, because the only cullable vertices would be those where two adjacent tiles on the screen were also adjacent in the tileset, in which case you'd safe 2 vertices per occurance, which IMO doesn't happen that often (as compared to eg. the same ground tile repeated over huge parts of the map).

Also, on the topic of the wasted std::vector memory: If the amount of vertices per tile and the amount of tiles is known before hand, why not just call vector.reserve(count) at the beginning (avoiding all reallocations) and avoid the waster memory?

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 #23 on: July 25, 2013, 09:13:52 pm »
Can you explain to me where these redundant vertices could be slashed off? Having recently implemented a tmx loader in openGL using indexed VBOs, I came to the conclusion that it's not really very viable, because the only cullable vertices would be those where two adjacent tiles on the screen were also adjacent in the tileset, in which case you'd safe 2 vertices per occurance, which IMO doesn't happen that often (as compared to eg. the same ground tile repeated over huge parts of the map).
The idea is that you use indexing, yes... but you don't advance all attributes at the same pace, i.e. glVertexAttribDivisor. As you probably noticed, there is no way of going around newer OpenGL if you want all the performance you can get ;). If you use your own VBO for tile rendering you can already drop the redundant color data (-20%). If you are really crazy, you could write your own shader to render the tiles with minimal data. Think about it, you are just iterating through a grid and changing the texture that is applied to each quad along the way. You don't have to provide much besides basic information about the grid structure and the type data at each tile. Haven't done this myself, however it seems theoretically possible (maybe something I might try when I get really bored ::)).

Also, on the topic of the wasted std::vector memory: If the amount of vertices per tile and the amount of tiles is known before hand, why not just call vector.reserve(count) at the beginning (avoiding all reallocations) and avoid the waster memory?
You can do this already by using sf::VertexArray::reserve() and just indexing the data instead of constantly appending, or even better just specifying at construction how large the sf::VertexArray should be, however many beginners haven't had the privilege of being part of this discussion yet ;).
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Ancurio

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Re: Vertex array - HUGE memory usage and bad performance
« Reply #24 on: July 26, 2013, 11:08:21 am »
The idea is that you use indexing, yes... but you don't advance all attributes at the same pace, i.e. glVertexAttribDivisor. As you probably noticed, there is no way of going around newer OpenGL if you want all the performance you can get ;). If you use your own VBO for tile rendering you can already drop the redundant color data (-20%). If you are really crazy, you could write your own shader to render the tiles with minimal data. Think about it, you are just iterating through a grid and changing the texture that is applied to each quad along the way. You don't have to provide much besides basic information about the grid structure and the type data at each tile. Haven't done this myself, however it seems theoretically possible (maybe something I might try when I get really bored ::)).

Ah... Yes, yes, I see. You would provide the raw tile index data, set the attrib divisor to 4 so packs of 4 vertices describing one tile/quad get the same tile index (or is it based on indices, ie. 6 because 6 indices per tile?), and the rest of all the vertex pos and texpos data could be generated on the fly based on the provided vertex id in the shader. For a map with eg. 100x100 tiles, you would only specify a 100x100 big ushort buffer and that's all.

That would be an interesting space/computation trade off (you'd be calculating the same exact data 60 times per second), but for huge maps it might indeed help with memory concerns. Interesting.

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 #25 on: July 26, 2013, 07:26:43 pm »
Quote
If you are really crazy, you could write your own shader to render the tiles with minimal data. Think about it, you are just iterating through a grid and changing the texture that is applied to each quad along the way. You don't have to provide much besides basic information about the grid structure and the type data at each tile. Haven't done this myself, however it seems theoretically possible (maybe something I might try when I get really bored ::)).
Like Dbug's shader that I improved or even more minimal?
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 #26 on: July 26, 2013, 10:12:29 pm »
What... there was someone who already did it? Man... now what will I do when I get bored ::)... I had a look, it looks pretty minimal. Doubt I can beat that without a few months worth of thinking ;D.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

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 #27 on: July 26, 2013, 10:26:13 pm »
Quote
I had a look, it looks pretty minimal. Doubt I can beat that without a few months worth of thinking ;D.
I feel flattered, I probably shouldn't because I written it based on dbug's comments and code but I do. ;D

Quote
Man... now what will I do when I get bored ::)...
SFGU.. :-X I dunno, hex or isometric tile shader? ;D
Back to C++ gamedev with SFML in May 2023