PDA

View Full Version : glMapBuffer/glUnmapBuffer



Roest
08-04-2009, 01:45 AM
For some rendering mode i need to use two arrays that i have in VBO's. Now with nvidia boards this



glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[1] );
colors = (float *) glMapBuffer( GL_ARRAY_BUFFER, GL_READ_ONLY );
glUnmapBuffer( GL_ARRAY_BUFFER );
glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[2] );
normals = (float *) glMapBuffer( GL_ARRAY_BUFFER, GL_READ_ONLY );
glUnmapBuffer( GL_ARRAY_BUFFER );


worked perfectly fine. I could map the buffers, unmap them and work with the pointers then. Not sure if that's already bad style but the nivida drivers seem to be very forgiving there. I'm talking linux, windows, mac and all kinds of nvidia boards from 6600 to 295 here. Now this segfaults with an ATI board. If I comment out the glUnmapBuffer commands it doesn't segfault but of course i need to unmap the buffers to reference them again.
So how do i specify which buffer to unmap or would a glUnmapBuffer( GL_ARRAY_BUFFER ); unmap both?

_NK47
08-04-2009, 01:52 AM
glUnmapBuffer( GL_ARRAY_BUFFER ) unmaps the currently bound one. looks like a driver bug, you could try to update to latest driver version to be sure. other then that what <memory> and <usage> you specify for your buffer?

Roest
08-04-2009, 02:30 AM
just float arrays with GL_STATIC_DRAW

It would seem my way is the correct one, since you can't bind them again to unmap. Due to my recent experiences with ATI i'm also willing to believe in driver bugs :)

kowal
08-04-2009, 08:08 AM
from gl man pages :
When a data store is unmapped, the pointer to its data store becomes invalid...

unmap your buffer after working with pointer.

mfort
08-04-2009, 08:32 AM
If you need to write to that memory by CPU, change the access mode to GL_WRITE_ONLY. In theory the driver can give you memory that is only for reading. If you try to write something there, segfault can be thrown.

As kowal said, never use the pointers after you unmap the memory.

Roest
08-04-2009, 09:07 AM
Thanks for replies but as stated in the first post I have two buffers I map to pointers. I would gladly do the unmapping after I worked with the arrays, which is read-only access by the way. So the question was and still is: How do I unmap buffers if I mapped two at once?

mfort
08-04-2009, 09:26 AM
You cannot unmap them in one call.

But this is fine:



glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[1] );
glUnmapBuffer( GL_ARRAY_BUFFER );
glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[2] );
glUnmapBuffer( GL_ARRAY_BUFFER );

Roest
08-04-2009, 09:40 AM
I'm pretty sure i tried that already and got some "undefined operation" gl error. Think this is the reason why i unmapped them imediatly. I can't check right now since i already went home, but will try first thing in the morning tomorrow. Thanks for the help.

Roest
08-04-2009, 11:35 PM
You cannot unmap them in one call.

But this is fine:



glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[1] );
glUnmapBuffer( GL_ARRAY_BUFFER );
glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[2] );
glUnmapBuffer( GL_ARRAY_BUFFER );


Yes I tried that already and it doesn't work. The gluErrorString contains "invalid operation". I suspect you can't do glBindBuffer on a buffer that is already mapped but I'm only guessing here. My workaround for now is not to delete the source arrays once I put them into VBO's and use them instead, but they tend to get pretty big so this is ugly.

mfort
08-04-2009, 11:49 PM
Look for programming error.
Either the m_bufferObjects[i] is 0 or you are unmapping the buffer twice or your have it in between glBegin/End or the error comes from earlier problem.

The code sample I wrote is the normal way to unmap buffers.

Check what API fails (unmap or bind) to see more.

Roest
08-05-2009, 12:09 AM
Check what API fails (unmap or bind) to see more.


It fails on bind.

Here's the whole function in question.


float *colors;
float *normals;
#if 1
if ( m_dh->useVBO )
{
glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[1] );
colors = (float *) glMapBuffer( GL_ARRAY_BUFFER, GL_READ_ONLY );
//glUnmapBuffer( GL_ARRAY_BUFFER );
glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[2] );
normals = (float *) glMapBuffer( GL_ARRAY_BUFFER, GL_READ_ONLY );
//glUnmapBuffer( GL_ARRAY_BUFFER );
}
else
{
colors = &amp;m_colorArray[0];
normals = &amp;m_normalArray[0];
}

#else
colors = &amp;m_colorArray[0];
normals = &amp;m_normalArray[0];
#endif

if ( m_dh->getPointMode() )
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
else
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

for ( int i = 0; i < m_countLines; ++i )
{
if ( m_selected[i] == 1 )
{
glBegin( GL_QUAD_STRIP );
int idx = getStartIndexForLine( i ) * 3;
for ( int k = 0; k < getPointsPerLine( i ); ++k )
{
glNormal3f( normals[idx], normals[idx + 1], normals[idx + 2] );
glColor3f( colors[idx], colors[idx + 1], colors[idx + 2] );

glMultiTexCoord2f(GL_TEXTURE0, -1.0f, 0.0f);
glVertex3f( m_pointArray[idx], m_pointArray[idx + 1], m_pointArray[idx + 2] );
glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f);
glVertex3f( m_pointArray[idx], m_pointArray[idx + 1], m_pointArray[idx + 2] );
idx += 3;
//
}
glEnd();
}
}
if ( m_dh->useVBO )
{
glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[1] ); //this produces an error
glUnmapBuffer( GL_ARRAY_BUFFER );
glBindBuffer( GL_ARRAY_BUFFER, m_bufferObjects[2] );
glUnmapBuffer( GL_ARRAY_BUFFER );
}

To explain it. I render lines using VBO's. So i have 3 arrays, vertices, colors and normals. For a tube like rendering i need to render them as quads using every vertex twice. With a binary parameter the vertices are moved in a shader and textured with a 1D texture. Here's how it looks like (http://schurade.googlepages.com/pic19.png).

mfort
08-05-2009, 12:39 AM
btw. very strange way of using the buffers.
The buffer should be written by application and read by OpenGL.
Methods like glDrawArrays should be used instead of glVertex/Normal/... functions.

Maybe the m_bufferObjects is not properly initialized.
check that values in m_bufferObjects are > 0 and ware properly obtained by glGenBuffers().

Are you sure the error is generated by that Bind?
try to put getGetError() just before the bind to clear the pending OGL error.

glBindBuffer says:
GL_INVALID_OPERATION is generated if glBindBuffer is executed between the execution of glBegin and the corresponding execution of glEnd.
It seems this is not your case.

btw. do you really have 3 buffers in m_bufferObjects.
(indexed 1, 2).

Jan
08-05-2009, 02:22 AM
Roest, i don't want to be rude, but you definitely haven't understood how VBOs work.

You are NOT "rendering your lines using VBO". You are rendering your lines with immediate mode using an ugly, unintended abuse of VBOs to store your data.

When you switched from immediate mode to "VBO mode" didn't it actually get slower ?

Anyway, as suggested above, look at glDrawArrays and glDrawElements. The VBO spec actually contains a good example at the bottom.

Jan.

Roest
08-05-2009, 03:48 AM
Roest, i don't want to be rude, but you definitely haven't understood how VBOs work.

Jan i don't want to be rude but you haven't read my previous posts. Not sure what else there is about VBOs but I'm not that stupid to pack data into VBOs and then map them to memory again to render them in immediate mode just for that.

I render the lines using VBOs, however for this special mode i need to access the data in the VBOs and render them this way because i need to render quads with extra parameters instead of lines.

Jan
08-05-2009, 04:15 AM
Ok, sorry, didn't get that part.

But maybe you could store the extra data in the VBO too and then render the lines with a geometry shader to turn them into quads?

If that extra data changes frequently, you could put it into a separate buffer and only bind that one, when needed (that way you can use glBufferData to discard that whole chunk of data, but not the rest, that doesn't change).

I agree that glMapBuffer etc. are not working as well, as they should, though.

Jan.

Roest
08-05-2009, 04:22 AM
Well it sounded like a good idea that I could free the arrays after putting them into VBOs and just access the VBOs when needed. But, and that's the simplest solution here, i can just keep the source arrays.