1

As the title suggests, I'm trying to find the cause of a bug in my program. glBindVertexArray() creates a GL_INVALID_OPERATION when drawing a scene in my program, even though I have properly initialized it beforehand.

The program uses Qt 5.15, with the help of the libQGLViewer library. It is composed of multiple QGLViewer instances on the same screen, and uses an underlying Scene class in order to draw the same content from the same buffers/textures/VBOs in multiple Qt widgets.

The Scene class inherits from the QOpenGLFunction_4_0_Core class, making it OpenGL 4.0 compliant and thus able to use VAOs/VBOs. Here's the problem : I have a couple of draw functions, depending on the type of widget asking for the draw. Here's an overview of the code that triggers a draw :

// in viewer1.hpp :

class Viewer1 : public QGLViewer {
    // ...
    virtual void initGL() override; // Overrides QGLViewer's initGL function, similar to the QOpenGLWidget function of the same name
    virtual void draw() override; // Overrides QGLViewer's draw function
  protected:
    Scene* scene;
    // ...
}

// In viewer2.hpp :

class Viewer2 : public QGLViewer {
    // ...
    virtual void initGL() override; // Overrides QGLViewer's initGL function, similar to the QOpenGLWidget function of the same name
    virtual void draw() override; // Overrides QGLViewer's draw function
  protected:
    Scene* scene;
    // ...
}

// In scene.hpp :

void GetOpenGLError(); // <- Checks OpenGL error(s) and prints them, clearing the error state

class Scene : public QOpenGLFunctions_4_0_Core {
    // ...
    void initScene();
    void drawFromViewer1(GLfloat* vMat, GLfloat* pMat);
    void drawFromViewer2(GLfloat* vMat, GLfloat* pMat);
  protected:
    bool isInitialized;
    GLuint vaoHandle;
    // I have a special technique of volumetric drawing with difficult
    // requirements which cannot be handled with the other VAO :
    GLuint vaoHandle_volumetric;
    // other opengl 'handles' (OpenGL names/IDs) to VBOs, textures ...
}

In my initGL() functions, one of the only thing it does is call the initScene() function, which checks if the scene has been initialized (or began to be initialized) already using the Scene::isInitialized boolean member (so the scene is not initialized twice). In the initScene() function, I call this->initializeOpenGLFunctions() in order to have the OpenGL function pointers provided by Qt initialized to the right values, which will later allow me to draw the scene in the different viewers. Speaking of which, here's the overview of the code for the different draw functions :

void Scene::initScene() {
    // ...
    glGenVertexArrays(1, &this->vaoHandle);
    GetOpenGLError(); // <- Prints nothing
    glBindVertexArray(this->vaoHandle);
    GetOpenGLError(); // <- Prints nothing
    if (glIsVertexArray(this->vaoHandle) == GL_FALSE) {
        throw std::runtime_error("VAO error in initScene()"); // <- doesn't get triggered
    }
    // Specify VAO state and pointers (...)
    // ...
}

void Scene::drawFromViewer1(GLfloat* vMat, GLfloat* pMat) {
    // Set the uniforms for the draw
    glBindVertexArray(this->vaoHandle);
    GetOpenGLError(); // <- Prints GL_INVALID_OPERATION !!!
    // Draw after binding index buffer ...
    // ...
}

void Scene::drawFromViewer2(GLfloat* vMat, GLfloat* pMat) {
    // Set the uniforms for the draw
    glBindVertexArray(this->vaoHandle);
    GetOpenGLError(); // <- Prints GL_INVALID_OPERATION !!!
    // Draw after binding index buffer ...
    // ...
}

What doesn't make sense is the fact that at the VAO's creation/specification time, the handle is valid, but it is not anymore when drawing !

I did call QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); before the creation of my QMainWindow/QApplication in order for the OpenGL viewers to share the same context, but this hasn't changed anything, everytime the VAO is bound, the operation always returns GL_INVALID_OPERATION which according to the OpenGL spec can only happen when the VAO hasn't been created with a previous call to glGenVertexArrays()/glBindVertexArrays() !

I have tried for a few days on and off to get this problem fixed, but I cannot seem to get it fixed. Has anyone had experience debugging OpenGL/Qt programs like that before ? There doesn't seem to be a whole lot of people who use recent desktop OpenGL versions with Qt on help forums ...

  • Are you sure there's a valid OpenGL context associated with the current thread when you call `glBindVertexArray`? – G.M. Jan 13 '21 at 10:32
  • @G.M. Yes, I forgot to mention it but in the `initScene()` function, I pass a pointer to a `QOpenGLContext` which in turn, gets checked by using the `isValid()` function. And since this pointer comes from the viewers' `QOpenGLWidget::context()` function, is it the context which is made current to the running thread. – Thibault de Villèle Jan 13 '21 at 10:46

1 Answers1

1

Although Vertex Buffer Objects can be shared between OpenGL contexts, Vertex Array Objects cannot: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Array_Object

Kim
  • 728
  • 10
  • 20