Search code examples
c++openglglfwvisual-studio-2022glew

Do I need to call glewInit() for every GLFW window I create?


This is my first big OpenGL project and am confused about a new feature I want to implement.

I am working on a game engine. In my engine I have two classes: Renderer and CustomWindow. GLFW needs to be initialized, then an OpenGL context needs to be created, then glew can be initialized. There is no problem with this, until I decided to support multiple windows to be created at the same time. Here are the things I am confused about:

  • Do I need to initialize GLEW for every window that is created? If no, can I still call glewInit() for every window creation and everything be fine?
  • If I create a window, and then destroy it, do I have to call glewInit() again and will I have to call these functions again?:
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &numberOfTexturesSupported);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_MULTISAMPLE);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_PROGRAM_POINT_SIZE);

If there is any off topic comments that would help, they are very welcomed.

Update 1: More Context

For reference, the reason I want to do this is to implement multiple window rendering that share the same OpenGL context. Note, each window uses its own vertex array object (VAO). Here is the code for reference:

// CustomWindow.cpp
CustomWindow::CustomWindow() {
    window = nullptr;
    title = defaultTitle;
    shouldClose = false;
    error = false;
    vertexArrayObjectID = 0;
    frameRate = defaultFrameRate;

    window = glfwCreateWindow(defaultWidth, defaultHeight, title.c_str(), nullptr, nullptr);
    if (!window) {
        error = true;
        return;
    }

    glfwMakeContextCurrent(window);
    if (glewInit() != GLEW_OK) {
        error = true;
        return;
    }
    
    glGenVertexArrays(1, &vertexArrayObjectID);
    glBindVertexArray(vertexArrayObjectID);

    allWindows.push_back(this);
}
CustomWindow::CustomWindow(int width, int height, const std::string& title, GLFWmonitor* monitor, GLFWwindow* share) {
    window = nullptr;
    this->title = title;
    shouldClose = false;
    error = false;
    vertexArrayObjectID = 0;
    frameRate = defaultFrameRate;

    window = glfwCreateWindow(width, height, title.c_str(), monitor, share);
    if (!window) {
        error = true;
        return;
    }

    glfwMakeContextCurrent(window);
    glGenVertexArrays(1, &vertexArrayObjectID);

    allWindows.push_back(this);
}
CustomWindow::~CustomWindow() {
    if (window != nullptr || error)
        glfwDestroyWindow(window);

    unsigned int position = 0;
    for (unsigned int i = 0; i < allWindows.size(); i++)
        if (allWindows[i] == this) {
            position = i;
            break;
        }
    allWindows.erase(allWindows.begin() + position);
    if (mainWindow == this)
        mainWindow = nullptr;
}
// Rendere.cpp
Renderer::Renderer() {
    error = false;
    numberOfTexturesSupported = 0;

    if (singleton != nullptr) {
        error = true;
        return;
    }
    singleton = this;

    // Init GLFW
    if (!glfwInit()) {
        error = true;
        return;
    }

    // Set window hints
    glfwWindowHint(GLFW_MAXIMIZED, true);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
    glfwWindowHint(GLFW_SAMPLES, 4);

    // Init GLEW
    if (glewInit() != GLEW_OK) {
        error = true;
        return;
    }

    // Set graphics message reporting
    glEnable(GL_DEBUG_OUTPUT);
    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
    glDebugMessageCallback(openglDebugCallback, nullptr);

    // Set up OpenGL
    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &numberOfTexturesSupported);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
    glEnable(GL_MULTISAMPLE);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_PROGRAM_POINT_SIZE);
}

Solution

  • After some research, i would say that it depends, therefore it's always best to have a look at the base to form an opinion.

    The OpenGL wiki has some useful information to offer.

    Loading OpenGL Functions is an important task for initializing OpenGL after creating an OpenGL context. You are strongly advised to use an OpenGL Loading Library instead of a manual process. However, if you want to know how it works manually, read on.

    Windows

    This function only works in the presence of a valid OpenGL context. Indeed, the function pointers it returns are themselves context-specific. The Windows documentation for this function states that the functions returned may work with another context, depending on the vendor of that context and that context's pixel format.

    In practice, if two contexts come from the same vendor and refer to the same GPU, then the function pointers pulled from one context will work in the other.

    Linux and X-Windows

    This function can operate without an OpenGL context, though the functions it returns obviously can't. This means that functions are not associated with a context in any way.

    If you take a look into the source code of glew (./src/glew.c), you will see that the lib simply calls the loading procedures of the underlying system and assigns the results of those calls to the global function pointers.

    In other words, calling glewInit multiple times has no other side effect other than that explained in the OpenGL wiki.


    Another question would be: do you really need multiple windows for that task? A different approach could be achieved with only one context and multiple framebuffer objects.

    Multiple contexts (sharing resources between them) and event handling (which can only be called from the 'main' thread) needs proper synchronization and multiple context switches.