PDA

View Full Version : Updating a VBO



w00tguy123
04-16-2011, 12:45 AM
I have a large vertex buffer object and I only want to update a small portion of it. Google tells me that this is a job for the glBufferSubData function but I'm not sure how to use it. I've been able to replace data in a array of vertices, but I'd rather leave them alone and work with the indices instead. However, trying to use glBufferSubData on my index VBO causes the entire array to go blank (my object disappears, anyway) and so I've just been recreating the entire array for each update (very slow). Here's my code for updating (written in Java with the lwjgl lib):


public int updateChunk(int indexVboId, int totalVerts) {

// Bind and buffer VBO
ARBVertexBufferObject.glBindBufferARB(ARBVertexBuf ferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, indexVboId);
ARBVertexBufferObject.glBufferDataARB(ARBVertexBuf ferObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
intSize*totalVerts, ARBVertexBufferObject.GL_STREAM_DRAW_ARB);

// Map VBO
ByteBuffer indexBuffer = ARBVertexBufferObject.glMapBufferARB(ARBVertexBuff erObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
ARBVertexBufferObject.GL_WRITE_ONLY_ARB, intSize*totalVerts, null);

// start replacing data at the beginning of the array (0)
GL15.glBufferSubData(ARBVertexBufferObject.GL_ELEM ENT_ARRAY_BUFFER_ARB, 0, indexBuffer);

// replace first 4 indices with these
indexBuffer.putInt(0).putInt(1).putInt(2).putInt(3 ).putInt(4);

indexBuffer.flip();

//unmap and unbind
ARBVertexBufferObject.glUnmapBufferARB(ARBVertexBu fferObject.GL_ELEMENT_ARRAY_BUFFER_ARB);
ARBVertexBufferObject.glBindBufferARB(ARBVertexBuf ferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

return 1;

}

Does anything look wrong here? Why would this code work for an array of vertices but not indices?

Also, how would I remove indices from the VBO?

Alfonse Reinheart
04-16-2011, 01:04 AM
Let me make sure I understand what you're doing here.

You have a buffer object. Then you map it with glMapBuffer. Then you take the pointer you mapped, the one that you told OpenGL would be only used for writing (GL_WRITE_ONLY_ARB), and use it as the input to glBufferSubData.

If you ask for a write-only pointer from glMapBuffer, you must actually treat it like a write-only pointer. By not reading from it.

Furthermore, I don't see why you're calling glBufferSubData at all (which I'm fairly sure is illegal for mapped buffers). The point of mapping a write-only pointer to the buffer is, presumably, to change the contents of the buffer. Thus, even if the glBufferSubData call actually worked (and it doesn't, since even if you could glBufferSubData to mapped buffers, you're still reading from a write-only pointer), it would do nothing. It would just be copying the data from the mapped pointer to itself.

w00tguy123
04-16-2011, 01:24 AM
I pretty much guessed on how to use glBufferSubData here, since I can't find any tutorials on using it or any sample code for updating a VBO. I figured that the last argument in glBufferSubData indicated which buffer to replace data in (instead of the actual data), but I guess binding the buffer does this?

My goal is to replace, add, and subtract indices from the buffer. What would be the simplest and most efficient way to do this?


Edit: I think I might have figured it out. Should I create a new temporary buffer, map data to it (allow it to be read and written to) and then sub that temporary buffer into my main buffer?

Alfonse Reinheart
04-16-2011, 02:12 AM
since I can't find any tutorials on using it or any sample code for updating a VBO.

*cough* (http://www.arcsynthesis.org/gltut/Positioning/Tutorial%2003.html)


My goal is to replace, add, and subtract indices from the buffer. What would be the simplest and most efficient way to do this?

If you intend to "add" indices, then you first need to figure out what the maximum number of indices will be and allocate a buffer that big. Buffer objects are like arrays in C/C++; it's not getting any bigger than what you asked for.

There is no "simplest and most efficient" way. There is a simple way to do it, and there may be a "most efficient" way which is both potentially hardware-dependent and almost certainly is not the simple way.

The simple way is just to change the data however you see fit. You can use glMapBuffer to map the data and change the values in the pointer you get. Or you can use glBufferSubData (aka: memcpy) to write to the buffer.

w00tguy123
04-16-2011, 02:37 AM
Ok, thank you for that link (and replies). I understand how adding data would work and I have allocated enough memory. However, subtracting data seems like it would be more difficult. My first idea would be to use glBufferSubData to replace a portion of the big buffer with an empty buffer, but then the big buffer would have a dataless hole in it (and I assume cause a crash or something). Do I need to redefine the entire buffer just to get rid of that gap (defeating the purpose of using glBufferSubData)?

w00tguy123
04-16-2011, 12:29 PM
I'm still having trouble getting glBufferSubData to work. I've made my method for updating very simple now but it crashes the program (EXCEPTION_ACCESS_VIOLATION) as soon as it's called:


public int updateChunk(int bigBuffer, int smallBuffer) {

// get pointer to small buffer
ByteBuffer data = ARBVertexBufferObject.glGetBufferPointerARB(ARBVer texBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, smallBuffer);

// bind big buffer, sub data into it, then unbind
ARBVertexBufferObject.glBindBufferARB(ARBVertexBuf ferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, bigBuffer);
GL15.glBufferSubData(ARBVertexBufferObject.GL_ELEM ENT_ARRAY_BUFFER_ARB, 0, data);
ARBVertexBufferObject.glBindBufferARB(ARBVertexBuf ferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

return 1;

}

Is there anything wrong with this code? I know that the small buffer is indeed smaller than the big buffer, and that they are both element_arrays that hold Int values.

BionicBytes
04-16-2011, 02:27 PM
I don't know if this has anything to do with it but you have a mixture of ARB function calls and core GL function calls. Are both of these initialised?
Why not use the core functions always and be consistent?

V-man
04-16-2011, 02:32 PM
ARBVertexBufferObject.glGetBufferPointerARB(ARBVer texBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, smallBuffer);

should be

ARBVertexBufferObject.glGetBufferPointerARB(ARBVer texBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, ARBVertexBufferObject.GL_BUFFER_MAP_POINTER);


PS: you can only call that on a VBO that you have glMapBuffer. But them glMapBuffer gives you the pointer so you don't really need glGetBufferPointerARB

I'm assuming you are using LWJGL

w00tguy123
04-16-2011, 03:41 PM
Alright, I've replaced the glGetBufferPointer call with glMapBuffer and glBufferSubData is now working correctly!

The problem now is that I don't know how to subtract data from the big buffer. Adding data was easy because all I had to do was set the offset in glBufferSubData to the last vertex in the big buffer, but you can't subtract data from the big buffer simply by replacing part of the big buffer with an empty buffer. Is there a way to remove vertices without remapping the entire buffer?

@BionicBytes: I thought using ARB calls was the only way to work with VBOs (learned pretty much everything I know from one example file), but I just looked at the OpenGL function lists and saw that they're available in the core as well. Thanks for pointing that out.