Is there a conflict between using VBO and Display List's?

Hi everyone! :smiley:
How are you doing?

Right now, I am struggling having a serious problem with VBO… any help will be greatly appreciated :slight_smile:

All my engine is Display-List based and I am now implemmenting my Terrain to be drawn apart with VBO’s (VBO’s alone, not inside a display list).

The VBO code has been tested on a stand alone app and it works perfectly using Glee for defining VBO’s.

However, I have now embeeded that code into my own engine, without using Glee and defining my own virtual functions as I do for the rest of the extensions, and my app crashes.

The weird part is where where it crashes. After debugging I found out that the function that triggers the crash is where I am building the FBO: buildBufferObjectVertexArrays.
However, the crash appears not in that function, but in a function that has nothing to do with FBO’s nor my Terrain: that is the function I use to render my other objects with Display List’s:

glCallList(this->DisplayListID);

//I get an access violation trigerred on this line , on a memory address that does not correspond to "this" object (I wasn't able to track where this memory address is from). The 'this' object is perfectly fine, as has all correct values at the debugging moment.

The mistery is that if I comment the buildBufferObjectVertexArrays function out, everything works perfectly fine.

Therefore I suspect:

  1. VBO’s and Display List cannot be used together in the same app?!!?
  2. More probably, I defined the virtual functions badly?! Could that cause a problem of this scope?!

What do you guys think!? GL_CHECK_ERROR returns nothing.

Special Note: Some functions in the original code where for example “glGenBuffers” (without ‘ARB’). However, as I found in the internet the definition for glGenBuffersARB, I replaced all glGenBuffers for glGenBuffersARB. I suspect this generates no problem, does it? I am using both ARB and no-ARB for VBO functions.

Thanks so much in advance,
Any tip, or hint, will be appreciated
Rod

This is my extensions code:

//HEADER .h:
	typedef void (APIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
	typedef void (APIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
	typedef void (APIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
	typedef void (APIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage);
	extern PFNGLGENBUFFERSARBPROC glGenBuffersARB ;					// VBO Name Generation Procedure
	extern PFNGLBINDBUFFERARBPROC glBindBufferARB ;					// VBO Bind Procedure
	extern PFNGLBUFFERDATAARBPROC glBufferDataARB ;					// VBO Data Loading Procedure
	extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB ;				// VBO Deletion Procedure	

	typedef GLvoid* (APIENTRY* PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
	typedef GLboolean (APIENTRY* PFNGLUNMAPBUFFERPROC) (GLenum target);

	extern PFNGLMAPBUFFERPROC glMapBuffer ;
	extern PFNGLUNMAPBUFFERPROC glUnmapBuffer ;

//SOURCE .cpp
	PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;					// VBO Name Generation Procedure
		PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;					// VBO Bind Procedure
		PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;					// VBO Data Loading Procedure
		PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;				// VBO Deletion Procedure#endif
	

		PFNGLMAPBUFFERPROC glMapBuffer =NULL;
		PFNGLUNMAPBUFFERPROC glUnmapBuffer =NULL;

void InitVBO
{
		glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) extgl_GetProcAddress("glGenBuffersARB");
		glBindBufferARB = (PFNGLBINDBUFFERARBPROC) extgl_GetProcAddress("glBindBufferARB");
		glBufferDataARB = (PFNGLBUFFERDATAARBPROC) extgl_GetProcAddress("glBufferDataARB");
		glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) extgl_GetProcAddress("glDeleteBuffersARB");
			
	   glMapBuffer     =  (PFNGLMAPBUFFERPROC) extgl_GetProcAddress("glMapBuffer");
	   glUnmapBuffer   =  (PFNGLUNMAPBUFFERPROC) extgl_GetProcAddress("glUnmapBuffer");
}

Those are called function pointers, not virtual function.

Seems as if you copy and pasted the definition of the VBO functions from glext.h
and you are getting the function pointers and there isn’t anything wrong with that.

The problem must be elsewhere.

BTW, you don’t need display list if using VBO
I’m not saying you can’t use them. You can of course.

I have a similar issue. That is, trying to migrate from display lists to vbos. Well, not being ideological about it, I’d like to use both. Though, on the mac putting a vbo in a display list works on ppc and x86. But reading the red book, one would conclude, I’m violating standards by having a vbo inside display list because the bind is a no no call.

“BTW, you don’t need display list if using VBO.”

I hear that all the time. This leads me to another question. The main point of the vbo is to get rid of calls like glVertex etc – the calls that are specific to setting information about a vertex. But what about everything else? I bind textures too and call glEnable/glDisable, blending in certain cases.etc. Am I suppose to do everything else in immediate mode without displays lists?

Also, the display list creates an id / name. This is really convenient to pass around in a program. :wink:

Am I suppose to do everything else in immediate mode without displays lists?
You may as well. You’re getting no speedup from putting state like that in a display list. Except for minor things like function-call overhead, but that’s it.

Thanks guys for your answers!

Just to make it clear, it makes no difference if I use glGenBuffersARB or glGenBuffers? Or if mix ARB functions with no-ARB functions for using VBO?

Regarding the access violation error that appears in a portion of a code not related to the new VBO code that is causing the error, I suspect it has to do probably with some wrong defined or filled pointers used for VBO that are trying to access bad memory address used for something else in other portions of the code. Could this be the case?

Anyone had a similar error using VBO?
Should I take any more precautions than safe C++ standards when using VBO?

If the extensions are well defined, and VBO can be used with DL (not VBO inside a DL, but separetly used), then I could conclude the error is about some unsafe memory declarations on the pointers used to store my VBO data. Do you think this makes sense?

Thanks so much in advance!
Cheers!
Rod

When you render not using VBO,are you binded to buffer 0 ?

Originally posted by Rodrix:
Just to make it clear, it makes no difference if I use glGenBuffersARB or glGenBuffers? Or if mix ARB functions with no-ARB functions for using VBO?
Don’t do stupid things. It might be true that there is no difference on computer X, but it might be different on computer Y.

Most of the time, ARB functions that become core don’t go through any changes and it was the case with VBO. Use only one of them anyway.

Originally posted by V-man:
Use only one of them anyway.
Ok! Thanks for the tip! :wink: I changed everything to non-ARB. I’ve just deleted ‘ARB’ from all my calls and for from the gl_GetProcAddress function.

Is this correct?

Originally posted by Claude:
When you render not using VBO,are you binded to buffer 0 ?
No… I am actually using glGenBuffers… :rolleyes:

This is the function causing the error. If I comment out this function, no error occurs on the rest of my code:

    // Height data struct.
    struct heightData
    {
        float y;                // Height at this location.
        SVector normal;            // Normal at this location.
        SColor color;            // The color at this location.
        float u, v;                // Texture coordinates at this location.
        float lightU, lightV;    // Texture coordinates for the lightmap.
        float horizon;            // Slope of the horizon at this location.
    };


//////////////////////////////////////////////////////////
///    Function: "buildBufferObjectVertexArrays"
//
///    FirstModified: 5/12/2005
//
///    \param None
//
///    Output: None
//
///    \return None
//
///    Purpose: Creates the VBO's for the heightmap.
//////////////////////////////////////////////////////////
void CTerrainVBOCull::buildBufferObjectVertexArrays(void)
{
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    

    glClientActiveTextureARB(GL_TEXTURE0_ARB);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glClientActiveTextureARB(GL_TEXTURE1_ARB);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
    glClientActiveTextureARB(GL_TEXTURE2_ARB);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glClientActiveTextureARB(GL_TEXTURE3_ARB);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

            CHECK_GL_ERROR();

    // Create vertex list.
    if (bufferVertList > 0)
        glDeleteBuffers(1, &bufferVertList);
    glGenBuffers(1, &bufferVertList);
    
        CHECK_GL_ERROR();

    // 'allocate' memory for the vertex list.
    glBindBuffer(GL_ARRAY_BUFFER, bufferVertList);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * Height * Width * 10 + (sizeof(GLbyte) * Height * Width * 4), NULL, GL_STATIC_DRAW);

    // Calculate the offset in the array for the vertex, normal, and colors.
    vertOffset = 0;
    normalOffset = Height*Width*3;
    textureCoordOffset = Height*Width*6;
    lightmapTexCoordOffset = Height*Width*8;
    colorOffset = Height*Width*10;


    // Copy data into the buffer objects.
    GLfloat *vertBuff = (GLfloat *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
    int currentIndex = 0;



    for (int z = 0; z < Height; z+=1)
    {
        for (int x = 0; x < Width; x+=1)
        {
            // Verticies.
            vertBuff[vertOffset]   = (float)x;        
            vertBuff[vertOffset+1] = data[x][z].y;  //data is defined as         heightData **data; in the class members.
            vertBuff[vertOffset+2] = (float)z;
            vertOffset += 3;
            
            // Normals.
            vertBuff[normalOffset]   = data[x][z].normal.x;
            vertBuff[normalOffset+1] = data[x][z].normal.y;
            vertBuff[normalOffset+2] = data[x][z].normal.z;
            normalOffset += 3;

            // Texture Coordinates.
            vertBuff[textureCoordOffset]   = data[x][z].u;
            vertBuff[textureCoordOffset+1] = data[x][z].v;
            textureCoordOffset += 2;

            // Lightmap texture Coordinates.
            vertBuff[lightmapTexCoordOffset]   = data[x][z].lightU;
            vertBuff[lightmapTexCoordOffset+1] = data[x][z].lightV;
            lightmapTexCoordOffset += 2;

            // Colors
            GLubyte *byteBuff = (GLubyte *)&vertBuff[colorOffset];
            byteBuff[0] = data[x][z].color.r;
            byteBuff[1] = data[x][z].color.g;
            byteBuff[2] = data[x][z].color.b;
            byteBuff[3] = data[x][z].color.a;
            colorOffset += 1;
        }
    }
    glUnmapBuffer(GL_ARRAY_BUFFER);

            CHECK_GL_ERROR();
    
//IF I COMMENT EVERYTHING BELOW THIS POINT, I get No access violation errors (and no VBO's of course). So the the error must be in the code below.

    // Recalculate the offset in the array for the vertex, normal, and colors.
    vertOffset = 0;
    normalOffset = Height*Width*3;
    textureCoordOffset = Height*Width*6;
    lightmapTexCoordOffset = Height*Width*8;
    colorOffset = Height*Width*10;

    
    // Calculate the triangle index lists for each chunk.
    for (int chunkZ = 0; chunkZ < Height/(ChunkHeight-1); chunkZ++)
    {
        for (int chunkX = 0; chunkX < Width/(ChunkWidth-1); chunkX++)
        {
            // Create the index buffer.
            if (chunkArray[chunkX][chunkZ].bufferTriList > 0)
                glDeleteBuffers(1, &chunkArray[chunkX][chunkZ].bufferTriList);
    
            glGenBuffers(1, &chunkArray[chunkX][chunkZ].bufferTriList);

            // 'allocate' memory for the buffer.
            numElements = ((ChunkHeight-1) * (ChunkWidth*2+2))-2;
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunkArray[chunkX][chunkZ].bufferTriList);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * numElements, NULL, GL_STATIC_DRAW);




            // Fill triangle buffer.
            GLuint *triBuff = (GLuint *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
            currentIndex = 0;


                                                                                
            // Calculate the extents of the chunk.
            int startx = chunkX * (ChunkWidth-1);
            int startz = chunkZ * (ChunkHeight-1);
            int endx = startx + ChunkWidth;
            int endz = startz + ChunkHeight;

            // Initialize the min and max values based on the first vertex.
            float maxX, maxY, maxZ;
            float minX, minY, minZ;

            maxX = startx;
            minX = startx;
            maxY = data[startx][startz].y;
            minY = data[startx][startz].y;
            maxZ = startz;
            minZ = startz;

            // Loop through the chunk extents and create the list.
            for (int z = startz; z < endz-1; z++)
            {
                for (int x = startx; x < endx; x++)
                {
                    // Update the min and max values.
                    maxX = maxX > x ? maxX : x;
                    minX = minX < x ? minX : x;
                    maxY = maxY > data[x][z].y ? maxY : data[x][z].y;
                    minY = minY < data[x][z].y ? minY : data[x][z].y;
                    maxZ = maxZ > z ? maxZ : z;
                    minZ = minZ < z ? minZ : z;

                    // Used for degenerate triangles.
                    if (x == startx && z != startz)
                        triBuff[currentIndex++] = x + (z * Width);

                    triBuff[currentIndex++] = x + (z * Width);
                    triBuff[currentIndex++] = x + ((z+1) * Width);

                    // Used for degenerate triangles.
                    if (x == endx-1 && z != endz-2)
                        triBuff[currentIndex++] = x + ((z+1) * Width);
                }
            }
            glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB);
            
            // Assign the min and max values found.
            chunkArray[chunkX][chunkZ].maxX = maxX;
            chunkArray[chunkX][chunkZ].maxY = maxY;
            chunkArray[chunkX][chunkZ].maxZ = maxZ;
            chunkArray[chunkX][chunkZ].minX = minX;
            chunkArray[chunkX][chunkZ].minY = minY;
            chunkArray[chunkX][chunkZ].minZ = minZ;

        }


    }
    CHECK_GL_ERROR();
        
}

I commented in the code, the segment I identified as the cause of the error . However, I have no idea what the error is. Any ideas? I am becoming desperate… :confused:

Thanks so much everyone :slight_smile:

Rod

First,does your code work with only the VBO,no
display list?
Second,I think you didn’t understand my post.Maybe
not detailed enough.
glGenBuffersARB gets you a buffer name or ID
glBindBufferARB binds to a buffer name or ID so
that you can work on it.
When you’re thru using VBOs,in my opinion it’s good to bind to the GL-reserved name zero like
that:
glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );

Originally posted by Claude:

When you’re thru using VBOs,in my opinion it’s good to bind to the GL-reserved name zero like
that:
glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );

Thanks Claude!
Should I call glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); right after calling glBufferData or do I have to call it after I have already binded GL_ELEMENT_ARRAY_BUFFER_ARB and call
glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
together?

Thanks so much!
Rod

Both should be called when you’re finished working
with VBO.
So,normally they should be the last 2 instructions
of your BUILDVBO function and your DRAWVBO
function.

Claude!!! THANKS THANKS THANKS!!! :smiley:
That solved the problem! Thanks I am really happy, you solved almost two weeks of anguish! :slight_smile: :slight_smile: :slight_smile:

Now that is solved I need to understand it: why not calling glBindBufferARB(0) causes an access violation error?!How does it work internally?

Cheers!
Rod

Welcome.
Glad to be able to help.

Bye
Claude