I am trying to port an older osgEarth-based application to use OSG 3.6.5, osgEarth 3.0, and the new osgQt node kit. Currently I am able to see a globe but I am getting intermittent crashes as I move around. The crashes consistently happen in the engine_rex driver in the SharedGeometry::drawImplementation() function. It is crashing on the call to glDrawElements() inside the driver for my video card so I took a closer look at the GL calls using GLIntercept. The GL calls made by the function looks something like this:
That looks good but I noticed one thing when I looked earlier in the log. Nothing is currently bound to the GL_ARRAY_BUFFER target. If I move backwards in the log from the crash point the last glBindBuffer call involving GL_ARRAY_BUFFER looks like this:
Earlier in the GL log I usually see something like glBindBuffer(GL_ARRAY_BUFFER, <non-zero buffer handle>) prior to these blocks of calls. Isn't it required that both the GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER targets have bound buffers for glDrawElements() to work?
Have any of you seen this error before? I am running on Windows 10 and built OSG, osgEarth, and osgQt with the default cmake settings.
Yes, but OSG 3.6 uses VAOs and the GL_ARRAY_BUFFER binding is stored as part of the VAO state. So you only need to bind it once when you first create the VAO. The same is supposedly true of the GL_ELEMENT_ARRAY_BUFFER state, but for some reason (that I could never figure out) it doesn't work...so you have to bind it manually.
I ran my application in the debugger to verify the settings inside VertexArrayState. The _vertexArrayObject member variable inside the vas variable is always zero. I also verified that glGenVertexArrays() is never being invoked from within OSG. That must be happening inside the QOpenGLWidget initialization.
I put a breakpoint inside SharedGeometry::createVertexArrayStateImplementation() to check why the generateVertexArrayObject() function is never being called. It turns out that createVertexArrayStateImplementation() never gets called either. I'm not sure if that is normal behavior.
So if I am using OSG 3.6.5 and my card supports the GL_ARB_vertex_array_object extension should the normal path be for osgEarth to use a VAO for the map tiles? If so, should it happen automatically or is there something I need to enable on my end?
I believe that VAOs are only on by default if you build OSG for GL3 or GLCORE profile. I have been using GL CORE exclusively for years so the details are hazy, but I think you force them on with an environment variable.
Thanks for the info. I built OSG with GL2 so it shouldn't be using VAOs.
One thing I noticed is that the crash only seems to happen if I have the OSG StatsHandler actively drawing its rectangles on the screen. I am able to run without the stats being visible or with just the frame rate showing and everything works. I saw another person had a similar issue with glDrawElements crashing with StatsHandler active but it appears that SharedGeometry already follows the OSG team recommendations made here:
There is one other thing I want to check though regarding my setup. In the past I think there was a requirement that the osgEarthQt classes had to call frame() no faster than every 17 msec to avoid a bug with the earth manipulator. The new osgQt node kit is set up internally to tick every 10 msec and I have not modified that. Is that still going to cause an issue?
From what I have seen in the debugger triggering the OSG StatsHandler causes the _isVertexBufferObjectSupported variable inside VertexArrayState to change to false more than once while they draw the various elements. I assume this means that the static elements in the stats HUD are being drawn with display lists rather than VBOs.
In any case after the HUD is enabled I enter SharedGeometry::drawImplementation() when this flag happens to be last set to false by the HUD. Then vas->setVertexArray() is called. Ultimately this function causes the vertex buffer to not be bound since VertexArrayState::isVertexBufferObjectSupported() will return false and trigger an unbind rather than a bind.
I looked at the differences between osg::Geometry::drawImplementation() and SharedGeometry::drawImplementation() for a clue. Geometry has a few lines of code prior to draw where they set the VBO flag in VertexArrayState according to some Geometry member variable settings.
If I insert the following lines of code in SharedGeometry::drawImplementation() immediately after the vas variable is set I no longer encounter the crash:
Do you happen to know why these lines are not present in SharedGeometry normally? What's strange is this does not happen with the osgEarth examples when I enable the stats handler on those. Maybe that is an artifact of having Qt in the loop.
I don't know why, maybe they seemed unnecessary. But if you want to submit a PR we can merge them in there. Just make sure to include a comment for posterity so someone doesn't remove them later :) Thanks.