winapiopenglvclopenglcontextwgl

Changing OpenGL (wgl) context to a different window handle


I am creating an application using OpenGL (4.2). By default, the rendering is done on a panel in a window, it works without issues, but the panel can be docked/undocked, which causes the underlying window handle to change, therefore I am recreating the context.

There are no errors (glGetError = GL_NO_ERROR), the context exists (wglGetCurrentContext returns nonzero).

  // This snippet happens in response to window handle changed.
  fDC := GetDC(Handle); // Always recreate DC

  if not fIsGlInitialized then
      fRC := CreateRenderingContextVersion(fDC, ...); // Only one RC

  wglMakeCurrent(fDC, fRC); // Edit: Fails with ERROR_INVALID_PIXEL_FORMAT 
  fIsGlInitialized := True;
  InitOpenGL(); // Reload OpenGL function pointers just in case

However, after the handle changes, there is nothing rendered (the panel just has default gray color).

What is the correct way of recreating the context, assuming I want to keep my OpenGL objects (such as VAOs)?

Tried recreating the rendering context: Causes Invalid Operation on glBindVertexArray with VAO created in the old context.

Tried using wglShareLists: Same error although I am not sure I used it correctly, I have seen people complaining it's legacy and some drivers are buggy, also I don't need multiple living contexts.

Tried creating new rendering context, using wglCopyContext(oldRC, fRC, GL_ALL_ATTRIB_BITS) and wglDeleteContext(oldRC), causes the same error.


Solution

  • It is sufficient to call GetDC and use wglMakeCurrent with the new DC handle and old RC, however, it might be necessary to set your pixel format on the new DC.

    As @BDL suggested, check the return value of wglMakeCurrent to avoid such bugs.