0

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);
}
  • 1
    I know this won't help you much but : do you have a use case in mind for multiple windows support? It sounds like an amazing way to give yourself issues through the rest of development, so if it's happening as a side thought without real user demand, the easier solution might be to skip it alltogether. – Alceste_ Sep 10 '22 at 04:21
  • Yes, I added more context to the original post, but to answer your question, I want to be able to render to multiple windows so I can have multiple views of the same world. Each view will be used by a different user/player. Each user/player will interface with the application through different windows (by using controllers, not mouse and keyboard). – Christopher Barrios Agosto Sep 10 '22 at 04:25
  • Welp, have never tried it myself, but you could probably have a look at Windows GDI documentation (https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-wglmakecurrent) and this quite similar, but less accurate question : https://stackoverflow.com/questions/10465462/multiple-windows-opengl-glut . Good luck, have fun. – Alceste_ Sep 10 '22 at 04:31
  • 1
    https://stackoverflow.com/questions/59616686, https://github.com/nigels-com/glew/issues/38 – genpfault Sep 10 '22 at 04:45

1 Answers1

1

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.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11
  • I see. The intention is to indeed use context sharing. The impression I am getting is that if I use context sharing, I do not have to call ```glewInit```. The source of the question raised when I wanted to initialize the engine first and then created the window. I got an error for calling ```glewInit``` before having a valid context current. Just to clarify though, I can get away with having one main window, calling ```glewInit``` for the main window, and then not call it for the other windows that share the context of the main window, correct? – Christopher Barrios Agosto Sep 10 '22 at 09:57
  • This problem only arises on windows (and only if there are multiple gpu's from different vendors). To clarify: 1. create the main window (therefore a context) 2. call `glewInit` 3. create as many windows and use as many context switches as you want - at least that is my understanding. To be absolutely on the safe side, call `glewInit` every time a context switch occurs (basically after a call of `glfwMakeContextCurrent`). – Erdal Küçük Sep 10 '22 at 10:10
  • No problem. But be prepared, the OpenGL wiki speaks of 'In practice', that is no guarantee, at most a hint. – Erdal Küçük Sep 10 '22 at 10:19
  • Another hint: have a look at https://gen.glad.sh. At the bottom, there are different options to choose from. The one(s), which might be of interest would be `mx` (Enables support for multiple GL contexts) and `mx global` (Mimic global GL functions with context switching). – Erdal Küçük Sep 10 '22 at 10:30