Memory Management question

I seem to be able to bring the OpenGL driver to its knees with my test application. I create/destroy about 6k VBO buffers per second. The entire machine starts to act unstable. The mouse gets jumpy and erratic, all applications get unresponsive, etc. But, during this time the CPU is not pegged, so it is DMA or other bottlenecks. If there is a high amount of change in geometry what is the recommended approach. Should I recycle the buffers and look for an older one that is the right size? Should I be using something other than VBO buffers for this type of application?

This is all on a 1Ghz Powerbook Ti with 1GB of ram and a Radeon 9000 mobility chip.

Michael

You want to avoid creating/destroying VBO buffers in the game loop. Only creating a few per frame can make the animation choppy. You want to create all your buffers at the loading stage. They don’t have to fit your geometry exactly. You can craete a large buffer and use only part of it. More than one geometry can share buffer. So, yes, you’ll need a couple of large buffers that you reuse.

If the geometry changes a lot you can skip VBO and just use vertex arrays.

Create one big VBO for your dynamic geometry. Use it forever.

Cas :slight_smile:

That is type type of input I expected. In a general case where various types of primitives and states are required (quads, strips, fans, different textures, different texture coordinates, etc) preallocating enough different VBO buffers seems challenging. You indicated I can place multiple types in one buffer. Which calls are those? Right now I allocate VBO buffers for each array call (vertex, color, tex coord), should I be looking at a different way of doing this? Some comments indicated that interleved was not any faster, and could be slower. My application is not a game, so some of the uses are differnt. I originally used arrays and got noticeable speed up by using VBOs for the drawing. So, knowing which parts are going to change often for a period of time would seem to be an issue. Also, is the allocation of the buffer the issue, or the bandwidth to update the data in the buffer? If it is just the allocation, then pre-allocating and reusing buffers would seem to be an easy solution.

Michael

Managing the allocation of the buffer is the big issue. Grab a nice big VBO and use it for all sorts of different things. Split it up logically if necessary. But the crucial thing is - keep it hanging around. They are specifically designed to work this way - you allocate them according to a particular usage pattern depending on how often you expect to write (and maybe read from) them. Depending on whether there is an R in the month and a function of my grandma’s age, the VBO will be allocated either directly in VRAM, in AGP RAM, or maybe in system RAM; but provided you are correct about your expected usage of the buffer - eg. writing all vertices out to it every frame - you’ll get the best possible performance out of OpenGL.

Interleaved buffers are generally no different to buffers specified in all sorts of different locations. However it is worth making sure that your vertices fit into convenient bus-sized chunks like 32 or 64 or 128 bytes as the transfers are optimised to work best in this way. I’m not sure about how JOGL and co. align buffers but that might possibly have some effect.

Cas :slight_smile:

[quote]In a general case where various types of primitives and states are required (quads, strips, fans, different textures, different texture coordinates, etc) preallocating enough different VBO buffers seems challenging. You indicated I can place multiple types in one buffer. Which calls are those? Right now I allocate VBO buffers for each array call (vertex, color, tex coord), should I be looking at a different way of doing this?
[/quote]
VBO is just an array of data. You can draw any goemetry type (quads, strips, fans, triangles etc) using the same VBO. You just have to but the data in the right order.

If you don’t use interleaved array you create on array for each type that you use (vertex, color, normal. tex coord). A geometry, like a mesh, will use a subrange of the global array. If you create and delete a lot of geometry you need to manage the subranges. Chanses are the array will get fragmented and you need to deal with it. You basicly need to create your own memory manager :slight_smile:

[quote]Some comments indicated that interleved was not any faster, and could be slower. My application is not a game, so some of the uses are differnt. I originally used arrays and got noticeable speed up by using VBOs for the drawing. So, knowing which parts are going to change often for a period of time would seem to be an issue. Also, is the allocation of the buffer the issue, or the bandwidth to update the data in the buffer? If it is just the allocation, then pre-allocating and reusing buffers would seem to be an easy solution.
[/quote]
Allocation is pretty bad, so you defenetly want to pre-allocate. Uploading the data is slow compared to having it permenently stored on the card. But it is fast enough to be done in real time. With VBOs you can give the driver a hint of how often you will update your data. This can then influance where the data is stored. Either on card, on agp memory or in system memory. There is a great paper on this on the nvidea site. Search for it.

I have spent all day on this and it is still not clearing up. In order to use VBO buffers for glDrawArrays or glMultiDrawArrays the vertex format must be the same, since all I can specify is element position to start for all aspects of the drawing. If I have some geometry in one format and some in another (color vs. texture coordinates) I need separate buffers for each format. Since I need to set the pointers for each component at the start of the VBO, I need to use an index (vertex number) to identify each individual geometry to be drawn, or use glMultiDrawArrays to use indices. I can not really have just one VBO for an arbitrary collection of geometry and just use offsets into that buffer for each call to glXXXPointer (which would be the easier case for me).

With “one VBO”, I mean that you only use one buffer for each of the types you need (vertex, texcoord, color etc), or use interleaved arrays. Even if you set more than one buffers in code, they are used as one array when you call drawArrays.

So you set up one array of each of the types you need. Make them all the same “size”. Where size I mean logical size, not size in bytes. Store the data in the different arrays at the same logical location.

Then I think you can just specify the offset in drawArrays.

You can also mess with the buffers offset using BindBufferARB with UFFER_MAP_POINTER_ARB if you don’t have the different type buffers setup equaly.

I do not get any results when looking for UPPER_MAP_POINTER_ARB or several varriations. Can you elaborate please?

Sorry, typo: BUFFER_MAP_POINTER_ARB.

Btw. Have you looked at:
http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt

I see that that is for mapping VBO data to client address space. But how does that help me draw from an offset position in a VBO? If I pass a mapped pointer to calls like glVertexPointer does it do the right thing and use the server memory rather than passing the data from the client address space? It also indicates you can only have one mapping in place per VBO so I could not have mixed data in one VBO and use that for multiple pointers at different offsets right?

In C you would pass in an offset instead of a void pointer to glVertexPointer to specify where in memory to start. This don’t work in java so it must be done another way. In LWJGL there is a special glVertexPointer function that takes an int offset instead of the direct byte buffer that is used with normal vertex arrays. I don’t know how this is done in JOGL as I use LWJGL instead :wink:

Useing vertexPointer it seems you can have all your different data types in the same array. Forgot about that. Seems I’m a bit rusty with the vbo stuff. It’s been a while since I used it :slight_smile:

In the JOGL library you currently need to use the BufferUtils.bufferOffset() method to construct Buffer objects to be used as offsets for glVertexPointer, glNormalPointer, etc. when they are used with VBOs. See the VertexBufferObject demo in the jogl-demos workspace for an example.