Search code examples
c++openglvisual-c++glslglfw

OpenGL Invalid Operation Errors on separate Input Thread


I have a "checkErrors" method attached to all components of the Project so that I can call 'checkErrors("Context Name")' and it will tell me what errors (if any) have occurred up to that point. The method looks like this: (print is a method of my own, just interpret it as a simple printf)

void checkErrors(std::string context="Unknwon Context") {
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR)
    {
        print("OpenGL Error:");
        print("\t CONTEXT: " + context);
        if (err == GL_INVALID_ENUM) print("\t TYPE: Invalid Enum");
        else if (err == GL_INVALID_VALUE) print("\t TYPE: Invalid Value");
        else if (err == GL_INVALID_OPERATION) print("\t TYPE: Invalid Operation");
        else if (err == GL_OUT_OF_MEMORY) print("\t TYPE: Out of Memory");
        else if (err == GL_INVALID_FRAMEBUFFER_OPERATION) print("\t TYPE: Invalid Framebuffer Operation");
        else if (err == GL_CONTEXT_LOST) print("\t TYPE: Context Lost");
        else print("\t TYPE: Undefined Error");
    }
}

I am running a separate thread that takes input from the terminal/console and changes variables locked behind a mutex that alter the program respectively. The function/method looks like this:

void Engine::console() {
    std::string input;
    while (true)
    {
        std::cin >> input;

        settingMutex.lock();

        if (input == "something") doSomething();
        // More possible console command here...
        else print(this, "Unknwon Command");

        checkErrors("Console Command");

        settingMutex.unlock();
    }
}

I then start this function on a separate thread shortly before starting the main Render-Loop:

consoleThread = std::thread(&Engine::console, this);
consoleThread.detach();

//Render loop:
while (!window->shouldClose())
{
    settingMutex.lock();

    //Some stuff here...

    // render
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //Objects are drawn here...

    settingMutex.unlock();

    glfwSwapBuffers(window->getGLFWwindow());
    glfwPollEvents();

    checkErrors("Engine Loop");
}

Everything works as I intended it to. The objects are being drawn correctly and the Render-Loop outputs no errors.

If I comment out the 'checkErrors("Console Command")' in the console() function, my input commands do exactly what they should aswell.

However, if I don't comment that line out, no matter what string I enter, I essentially get infinitely many "Invalid Operation" Errors, coming from the "Console Command" context as output.

I can even remove everything from the console() function except for the checkErrors call and I still get an endless stream of Invalid Operation Errors. The Render-Loop, meanwhile keeps going completely error free.

I have a feeling that the OpenGL context doesn't exist outside the main thread, so simply calling glGetError on a separate thread results in an invalid operation error, but I haven't been able to confirm it.

Anybody have insight as to what is happening here?


Solution

  • Different threads do not share OpenGL context created in one of them, which means, when you are putting the console on a new thread, the call to glGetError() has no base context, and produces an exception.