VBO Size Questions

Started by
8 comments, last by V-man 17 years, 8 months ago
My research tells me that it's best to keep a VBO under 6-8 megs. However, none of my findings are very current, so I have no way to know if this figure is accurate or not. Can someone confirm this? When considering size, assuming 6-8 megs is optimal, does this mean that each individual buffer should be less than 6-8 megs? Or does it mean total sum of all buffers? For example: 1) verts[] + colors[] + texCoords[] <= 6-8 megs Vs. 2) verts[] <= 6-8 megs, colors[] <= 6-8 megs, etc. Assuming I need to render 20,000 quads, would it be better to break things up into smaller chunks? How costly is it to switch pointers and bind different buffers? I ask because I'm optimizing a sprite engine. Currently, I don't discriminate between the "types" of sprites being sent to the engine, and they all get sent to one gigantic VBO. I'd like to break things up into multiple VBOs based on certain logic, and I'm just trying to plan out what's feasible.
Advertisement
It's best to have one VBO for your vertex, color and texcoord

Make a struct like

struct MyVertexFormat{   float x, y, z;   uint color;   float s, t;}


The order of vertex, color and tex don't matter (I'm told)
Also, it's best that your struct is multiple of 32 bytes so make that

struct MyVertexFormat{   float x, y, z;   uint color;   float s, t;   float padding[2];}


I think 1 to 8 MB sounds good. nVidia says not too small and not too big.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
The size of the struct shouldn't have any effect over the size of the VBO on the card. Or am I misunderstanding the reason behind making the struct a certain size?

Actually though, I'm using Java so I can't use structs. I hope I wasn't confusing anyone with my "array math" example. To put it another way, I was wondering if the size is important due to data transfer or data storage.

For example, when I use glVertexPointer(), should the pointer be 6-8 megs? If so, this would imply that it's better to transfer 6-8 megs to the card at a time.

If the whole VBO must be 6-8 megs (glVertexPointer, glTexCoordPointer, etc), then it tells me that the card prefers storing VBOs in chunks of 6-8 megs.
"The size of the struct shouldn't have any effect over the size of the VBO on the card. Or am I misunderstanding the reason behind making the struct a certain size?"

That's correct. When I said it should be multiples of 32 bytes, it's for memory alignment on ATI cards and the GPU accesses VRAM moer quickly. The information comes from ATI, in some pdf, distributed at GDC or some event.

"Actually though, I'm using Java so I can't use structs. I hope I wasn't confusing anyone with my "array math" example. To put it another way, I was wondering if the size is important due to data transfer or data storage."

I don't know about Java, but without struct, maybe you can use class. They are essentially the same thing on C++.
Both reasons can apply.
The size is important for memory management. There might not be enough VRAM so the VBO goes into AGP memory or RAM. If VBO is too big, the driver will not work too well.
If you are using streaming VBO, it might work better for the driver to push the smaller VBO to VRAM, instead of a 100 MB VBO

Memory management is really a driver thing. The GPU doesn't care how big the VBO is. The GPU prefers data that is local (xyz, color, s, t all close together)
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
I thought I would just point out that you can only bind one buffer at a time, which means that you always need to consider position+normal+texture as a whole.
Quote:Original post by rick_appleton
I thought I would just point out that you can only bind one buffer at a time, which means that you always need to consider position+normal+texture as a whole.

That doesn't matter beacuse you can set the pointers before the draw call [smile].
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);glVertexPointer(...);glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);glNormalPointer(...);glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);glTexCoordPointer(...);glDrawElements(...);

@OP: However, as everyone has pointed out, it's good practice interleave the data as you gain better cache behavior.
Quote:Original post by deavik
Quote:Original post by rick_appleton
I thought I would just point out that you can only bind one buffer at a time, which means that you always need to consider position+normal+texture as a whole.

That doesn't matter beacuse you can set the pointers before the draw call [smile].
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);glVertexPointer(...);glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);glNormalPointer(...);glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);glTexCoordPointer(...);glDrawElements(...);

@OP: However, as everyone has pointed out, it's good practice interleave the data as you gain better cache behavior.


I thought you could only use a single buffer, so I checked the specs. Turns out you are correct (emphasis mine)!

Quote:specs
In the case of vertex arrays, this extension defines not merely one
binding for all attributes, but a separate binding for each
individual attribute. As a result, applications can source their
attributes from multiple buffers
. An application might, for example,
have a model with constant texture coordinates and variable geometry.
The texture coordinates might be retrieved from a buffer object with
the usage mode "STATIC_DRAW", indicating to the GL that the
application does not expect to update the contents of the buffer
frequently or even at all, while the vertices might be retrieved from
a buffer object with the usage mode "STREAM_DRAW", indicating that
the vertices will be updated on a regular basis.

Perhaps the bit about 32 byte vertices was gleaned from this? http://www.ati.com/developer/gdc/PerformanceTuning.pdf

I wonder though, if I have only 4 floats to store per vertex is it really worth doubling the size of my buffer with padding? If I have only 1 is it worth 8x'ing the size?

Thanks, ~SPH

AIM ME: aGaBoOgAmOnGeR
I think I saw a slightly different slide. If 32bytes is a whole multiple of your vertex size (so vertex size = 16byte or 8 byte), then you are fine also.
You would have to benchmark. Typically, people use texcoord (st) and normal (xyz) and vertex(xyz) and perhaps color (rgba) so it comes close to 32 or just over 32.
The slide says this is not good.

It's only worthwhile to make the change if your app will benifit and high end games need it.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

This topic is closed to new replies.

Advertisement