I want to create few threads to load objects with textures, but it doesn't work. I've read that I should create new OpenGL context in each thread, but when I do it, program crashes on it. Is other way to do it?
I use freeGLUT.
These are functions i want to use in threads:
glGenBuffers()
glBindBuffer()
glBufferData()
glGenTextures()
glBindTexture()
glTexImage2D()
glGenerateMipmap()
glTexParameteri()
glTexEnvi()
None of those you can call in a different thread. Not unless you create another connected openGL context in the other thread but that is not simple.
What is simpler is creating the object in memory in another thread and then having the main thread dump it in the VBO. after the loading thread signals it has done.
Another option is first creating and allocating the buffer in the main thread and using glMapBuffer to get a pointer you can write to (even from another thread) and letting the loading thread store its data in there and signal back when it's done after which the main thread can unmap it.
Related
I have a setup where an scene is rendered in an offscreen OpenGL framebuffer, then a compute shader extracts some data from it, and buts it into a ring buffer allocated on the device. This ring buffer is mapped with glMapBufferRange() to host-readable memory.
On the host side, there should be an interface where a Push() function enqueues the OpenGL operations on the command queue, followed by a glFenceSync().
And a Pull() function uses glClientWaitSync() to wait for a sync object to be finished, and then reads and returns the data from part of the ring buffer.
Ideally it should be possible to call Push() and Pull() from different threads.
But there is the problem that an OpenGL context can only be current on one thread at a time, but glClientWaitSync() like all other GL functions needs the proper context to be current.
So with this the Pull() thread would take the OpenGL context, and then call glClientWaitSync() which can be blocking. During that time Push() cannot be called because the context still belongs to the other context while it is waiting.
Is there a way to temporarily release the thread's current OpenGL context while waiting in glClientWaitSync() (in a way similar to how std::condition_variable::wait() unlocks the mutex), or to wait on a GLSync object belonging to another context?
The only solution seems to be to periodically poll glClientWaitSync() with zero timeout instead (and release the context inbetween), or to setup a second OpenGL context with resource sharing.
You cannot change the current context in someone else's thread. Well you can (by making that context current in yours), but that causes a data race if the other thread is currently in, or tries to call, an OpenGL function.
Instead, you should have two contexts with objects shared between them. Sync objects are shared between contexts, so that's not a problem. However, you need to flush the fence after you create it on the context which created the fence before another thread tries to wait on it.
My app has been drawing its graphics from a worker thread for over 10 years now and I've never had any problems with it. The worker thread draws to my HWND (created by the main thread) like this:
hdc = GetDC(hwnd);
SetDIBitsToDevice() ... or StretchDIBits()
ReleaseDC(hwnd, hdc);
After having ported my app to other platforms, I began to realize that drawing from any other thread than the main thread is usually a no-go on many platforms (e.g. macOS). My research has shown that this might be true for Win32 as well but I'm still lacking a definite answer.
Thus, my question:
Is it allowed to draw to my window like shown above from a worker thread that did not create the window it is drawing to? Note that the worker thread is really the only thread that draws to the window. The main thread doesn't do any drawing. Not even in WM_PAINT. Drawing in WM_PAINT is unnecessary in my case because the worker thread draws at 50fps.
If it isn't allowed, what's the best way to delegate drawing from the worker thread to the main thread?
Is it allowed to draw to my window like shown above from a worker thread that did not create the window it is drawing to?
It may not be the best solution to your problem, but it's safe, as long as you respect the documented rules for GetDC:
Note that the handle to the DC can only be used by a single thread at any one time.
ReleaseDC must be called from the same thread that called GetDC.
If you do render to the same device context from multiple threads, you are responsible for synchronizing accesses to it.*
As explained in the comments, a better solution would be to generate the DIB from the worker thread, and have this thread update the window by calling RedrawWindow. The main thread can then StretchBlt in its WM_PAINT handler. Calling RedrawWindow across threads implements a synchronization barrier. When the call returns, rendering on the target thread has run to completion, and it's safe to re-use the DIB.
* See Thread affinity of user interface objects, part 2: Device contexts.
I have several QQuickFramebufferObjects between which I want to share some GL objects (shaders and VBOs mainly). My initial plan was:
Create a class SharedGLData to hold the shared object
Instantiate this class on the stack in C++'s main()
Pass a pointer the object to QML via ctx->assignRootProperty or something
Pass the object as a property to the QML items of type SharedGLData
Access the pointer from C++
But that means I'd be creating GL objects on the main thread and later access them on the render thread. I'm pretty sure that's forbidden, for example see here where it says:
QOpenGLContext can be moved to a different thread with moveToThread(). Do not call makeCurrent() from a different thread than the one to which the QOpenGLContext object belongs.
Is it ok to follow my initial plan or is there a way to create shared GL objects on the render thread?
A possible hack would be to put the shared stuff into a singleton that gets initialized on first use, and make my first use be directly from the rendering code. But that's a hack.
Another idea is to call moveToThread on the QQFBO's GL context to move it to the main thread, instantiate SharedGLData, then move the GL context back to the render thread. But I don't have a pointer to the render thread...
Clarification after the answer I got: By "render thread" I mean the thread that Qt SceneGraph silently creates to do all the rendering. It's not a thread that I'm creating!
If you want multiple threads sharing OpenGL objects,
Create a QOpenGLContext. Usually, the first one you create should be the one belonging to the window (which will actually draw to the screen).
Create a second QOpenGLContext, but call setShareContext before calling create.
You now have two OpenGL contexts which share objects (shaders, VBOs, etc) and you can now use these contexts simultaneously from different threads.
But... this often not an ideal experience. In many cases, using OpenGL simultaneously from different threads will be no faster than using it from one thread, or it will be slower, or it will be buggier. You are at the mercy of the OpenGL implementation.
A Different Way
It sounds like your goal is to load assets (shaders, textures, vertex data) in a background thread while your main thread continues to render. There is a more straightforward way of doing this that does not involve creating multiple contexts at all.
Simply map OpenGL buffers into memory in the rendering thread, and then pass the pointer to the background loader thread. The loader thread is free to write data into the buffer while the render thread continues to make OpenGL calls. When the loader thread is done, it signals the main thread, which does the appropriate synchronization and calls glTexImage2D or whatever. These days, you can even keep a single buffer persistently mapped, but the traditional two-buffer method also works quite well.
Under this scheme, your rendering thread does not have to do any IO, and your background thread does not have to make any OpenGL calls at all.
You can't use this to compile shaders in the background but c'est la vie.
Currently I'm trying to understand what happens when a shared library spawns a thread, which does not terminate and the shared library is then unloaded.
What happens to the thread if the parent does not wait for the thread to exit?
Does the thread die or does it remain in the running state?
If it does then how can the parent detect when it's being unloaded and somehow terminate the thread?
Thanks for any help.
I assume the shared library is some plugin dynamically loaded at runtime using dlopen(3) and later explicitly unloaded using dlclose.
The dlopen and dlclose functions are internally using a reference counter and they are mmap(2)-ing (for dlopen) and munmap-ing (for dlclose) some segments inside the ELF shared object when appropriate (i.e. when the ref counter crosses the 0 border).
If a thread is running some function inside the dlclose-d shared library, the code of that function becomes munmap-ed and as soon as you jump (or return into) that function, you get a SIGBUS, SIGILL or SIGSEGV signal.
So you don't want that munmapto happen: hence you could:
avoid calling dlclose; this works very well in practice (unless you have a server program), because mmap consumes mostly address space for text read-only segments of shared object. As my manydl.c demonstrates, you can dlopen hundreds of thousands of shared objects on a desktop without reaching serious limits.
or pass RTLD_NODELETE to dlopen asking it to never unmap the library
Alternatively, use some facilities (i.e. destructor-attributed functions in the shared library) or conventions (perhaps atexit(3)?) to be sure that the thread has ended before dlclose
Shared library is loaded into process, so spawn thread will run in process address space.
Thread will keep running if not noticed to exit. and when process is exit, thread will also be terminated.
As shared library spawn the thread, so it is better that shared library also provide a function which will notice thread to exit so process can call the function to exit thread before unload library.
I want to load assets for my OpenGL application in a separate thread so that I can create a loading screen, but when I try to call an OpenGL function in another thread, the application crashes, and I need them to load textures. Is there anyway I can use multithreading and OpenGL? Or am I going to say, load an asset every frame, and make the screen kinda choppy and bad looking? I've seen that you can accomplish this on Windows, but I want this to run on Unix (specifically MacOSX) much more than windows.
Messing with a single OpenGL context in different threads is usually bound to result in trouble. What you can do though is make use of a Pixel Buffer Object (PBO) for the texture update, map this in the main (OpenGL) thread, pass the mapped pointer to the loading thread to be filled with file contents, and unmap the PBO followed by a glTexImage2D (using the PBO, of course) in the main thread once the loading thread has finished. By using two different PBOs, one that is currently filled by the loading thread and one that is currently copied into a texture by the main thread and some proper synchronization, you can get the file loading and texture update to work concurrently (look at the linked tutorial for some, yet single-threaded, examples).