Problems creating multiple contexts in different threads (Win32)

I’ve written a plugin DLL for the AviSynth+ framserver which uses OpenGL compute shaders. Since the plugin can be called multiple times, and the hosting application may have an OpenGL context of its own, the DLL launches a separate worker thread which uses GLFW to create its own hidden window (otherwise the hosting application would start receiving events for my hidden window and wouldn’t know what to do with them).

This seems to work for a small number of instances of my plugin’s class - usually only two, but seemingly sometimes more - but then glfwCreateWindow starts failing. glfwSetErrorCallback shows me that the error is:

Win32: Failed to register window class: Class already exists.

Is there any way around this, or should I be doing something else differently? I made various attempts at trying to share the same context between different instances of the DLL’s plugin class but couldn’t get anywhere.

the DLL launches a separate worker thread which uses GLFW to create its own hidden window

GLFW has threading limitations, see the documentation on thread safety.

Win32: Failed to register window class: Class already exists.

This likely happens because you have multiple instances of GLFW in your application. This isn’t supported.

When the first window is created GLFW creates a windows class, which sets a number of parameters including the window function used for events. GLFW stores the returned information and uses this for subsequent calls to create a window. This can fail if the window class has already been registered by the application, which can occur if GLFW was instantiated by different statically linked versions of GLFW.

Ah okay, thanks. I got conflicting information on thread safety and it was confusing me that it was kind of working, sometimes. I’m pretty sure I was only static linking to GLFW once, but it seems like if the framework I’m working with tries to load my DLL twice, it starts having issues? I’m not entirely sure to be honest.

Is this idea just a total non-starter, or do you know if some other library could help me out?

It seems like the kind of thing that other people must have run into before…

but it seems like if the framework I’m working with tries to load my DLL twice, it starts having issues?

Ah, if your DLL is runtime loaded and the host application unloads the DLL, then when it next loads it GLFW will try to create the window class but it will already have been created by the application.

If this is the case then you should make sure that glfwTerminate is called when your DLL is unloaded, as this will unregister the class and allow it to be used again.

the DLL launches a separate worker thread which uses GLFW to create its own hidden window (otherwise the hosting application would start receiving events for my hidden window and wouldn’t know what to do with them).

Note that you should not use a separate thread. GLFW’s windows use it’s own windows class to set the window callback function to be a GLFW one, so your host application will not receive events for that window.

Okay, thanks, I’ll look into those suggestions, though I don’t think it unloads my DLL at any point. If it does, it should first call destructors on the classes the DLL provides, which should be calling glfwTerminate already.

It’s all a bit odd and complicated in that I seem to be able to create multiple contexts in multiple threads when one scripting environment (AviSynth+) asks for them, but if a second scripting environment is created and tries to do the same thing, that’s when I get the error (but annoyingly, not every time!)

I know I’m terrible at explaining things so I don’t expect you to have any insight to that, if it even makes any sense. Just putting it out there in case helps give context to my issues.

Two of the host applications I use were throwing errors or crashing silently initially, and using a separate thread resolved that (one, written with wxWidgets, would write “‘GetWindowRect’ failed with error 0x00000578 (Invalid window handle.)” to debug, suggesting it was at least “aware” of the glfw window in some sense). But in any case there’s I can’t guarantee my DLL will be called from the process’s main tread.

Is this kind of thing just not something people do with OpenGL? It didn’t seem like an outlandish use case to me (DLL providing access to Compute shaders and should be able to work from any thread) when I started writing it.

Is this kind of thing just not something people do with OpenGL? It didn’t seem like an outlandish use case to me (DLL providing access to Compute shaders and should be able to work from any thread) when I started writing it.

The particular issue you are having is not with OpenGL, but with GLFW. GLFW isn’t designed to be used in plugins, and GLFW imposes a number of restrictions related to multiplatform compatibility, which can complicate things for your use case.

My recommendation is to first try to understand what is happening in detail, either through debugging or logging, then either resolve these issues, alter GLFW code to suit your purpose, or write your own code to create an OpenGL context. Vulkan is also an option, and you don’t need a window to work with Vulkan compute shaders although setup is a lot more complicated.