For opening a thread I am using SDL2 and for opengl I am using glew.
In my program, I have a thread in which I load and initialize all my resources. After doing a bit of research online I learned that a GLContext is only viable for the thread it was created on.
I could create another GLContext on my second thread, but then I won't have access to all the compiled shaders on my first thread.
Any ideas?
Related
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.
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.
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).
Is there anything wrong with creating a window in a separate thread, which will also contain the message loop, then creating an OpenGL Context in another thread?
You should be able to get it to work, if you're careful. See the parallel opengl faq.
Q: Why does my OpenGL application crash/not work when
I am rendering from another thread?
A: The OpenGL context is thread-specific. You have to
make it current in the thread using glXMakeCurrent,
wglMakeCurrent or aglSetCurrentContext, depending on
your operating system.
What you want to do is perfectly possible. Even better, OpenGL contexts can migrate between threads and even be used with multiple windows as long as their pixel format is compatible. The one constraint is, that a OpenGL context can be bound in only one thread at a time and that only a unbound context can be bound.
So you could even create the window and the context in one thread, then unbind the context, create another thread and re-bind the context to the window in the secondary thread. No problem there.
The only thing you must be aware of is, that OpenGL itself doesn't like to be multithreaded. The API itself is more or less thread safe, as only one context can be bound to a thread at a time. But all the bookkeeping required if OpenGL operations spawn over several threads may trigger nasty driver bugs and also has a certain performance hit.
In Native Client, is it possible to set up animation loop in a separate thread? I was not able to find any examples that do this.
If you mean OpenGL ES 2.0 based animations, then NO, you have to make all OpenGL calls from the main thread. But you can keep different threads for calculating framecounters or other calculations.
Only restriction is to make all OpenGL calls from main thread.