Unable to preserve OpenGL states when creating a second window (by sharing)

Started by Headphones, July 30, 2017, 14:24:23

Previous topic - Next topic

Headphones

I have tried following: http://www.glfw.org/docs/latest/context.html#context_sharing

// Assume existingWindowHandle is properly set from an existing window.
window = glfwCreateWindow(width, height, title, monitor, existingWindowHandle);


So far I'm able to create the new window and go fullscreen, but then it has no color on it. I've tried moving over the GL capabilities with:

GL.setCapabilities(previousCapabilities);


This doesn't fix it, however I'm just shooting at the dark here. Further, I don't kill the previous window (since I'm just trying to get it working for now). It will do the color clearing, it just won't draw anything that I've pushed to a VBO/EBO/VAO. I'm assuming my textures are also toasted by this.

The window does work and everything, my input loop and all is working fine. Do I need to recompile shaders after changing the context? I was hoping that by creating a new window I could keep all my old stuff that was done (textures/settings/states...etc) and just continue on by creating a new window with the existing window handle.

I don't know if I'm not sharing the context right, or maybe I'm not misunderstanding what the context is (I thought it just contains all the GL states that are used in rendering so I don't have to recompile the shaders or anything).

Is there a way for me to create a new window and keep rendering without recompiling all the shaders or re-deploying all the textures to? Is that even possible what I'm trying to do?

Kai

You should read about how OpenGL context sharing works.

When sharing a context, _only_ those GL objects are shared which represent data stored on the graphics card, which is: textures, shader programs, buffer objects, renderbuffers, sampler objects and query objects.
Things that are _not_ shared are container objects: vertex array objects, program pipeline objects, transform feedback objects and framebuffer objects.

What is also not shared (and this is probably your specific case), is: all binding states of the GL context, such as: which shader is currently bound, what is the current clear color, all vertex attributes' states (bound VBO, stride, offset, type, etc.) and enable states.

That means: When you create an OpenGL context by sharing it with another context, you get a fresh context with all state attributes set to their defaults, and the names/identifiers/integers of shareable GL objects mentioned above are known to this context which you can then reuse in that context (such as by binding them to the various context binding points (GL_ARRAY_BUFFER, ...) or by manipulating their data (glBufferData, ...).

EDIT:
Another solution that works, but requires you to interface with the native OS OpenGL window manager APIs (WGL, GLX, ...) is to reuse the same OpenGL context for multiple windows. GLFW itself does not provide this by itself, but it exposes some functions also exported by LWJGL3 to implement this yourself via the `GLFWNative*` classes in LWJGL3. LWJGL3 also provides bindings for other necessary OS system functions, such as WGL, GDI32 and User32 for Windows.

An example of rendering the same OpenGL context on multiple windows on Windows is here:
// Create two GLFW windows
// ...

long hwnd1 = GLFWNativeWin32.glfwGetWin32Window(window1);
long hwnd2 = GLFWNativeWin32.glfwGetWin32Window(window2);
// Only use the OpenGL context of the first window
long hglrc1 = GLFWNativeWGL.glfwGetWGLContext(window1);

glfwMakeContextCurrent(window1);
GL.createCapabilities();
// Initialize the context with LWJGL here
// ...

// Now the render loop:
while (!glfwWindowShouldClose(window1) && !glfwWindowShouldClose(window2)) {
    long dc1 = User32.GetDC(hwnd1);
    WGL.wglMakeCurrent(dc1, hglrc1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Render onto the first window with its own context
    // ...
    GDI32.SwapBuffers(dc1);
    User32.ReleaseDC(hwnd1, dc1);

    long dc2 = User32.GetDC(hwnd2);
    WGL.wglMakeCurrent(dc2, hglrc1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Render on the second window using the first window's context
    // ...
    GDI32.SwapBuffers(dc2);
    User32.ReleaseDC(hwnd2, dc2);

    glfwPollEvents();
}

Please note that this is only the code needed on Windows. Handling Linux and Mac OS is another story.