I am trying to move some of my rendering in OpenGL and some other calculations to a second thread. The problems start when I do anything related to OpenGL.
I have read that one OpenGL context can only be used by one thread.
I'm creating my context using this command from OpenGL:
SDL_GLContext context = SDL_GL_CreateContext(window);
How can I generate a second context for the same window? And can I use multiple contexts on one window?
Related
I want to get the unity context into opengl so I can display a unity render texture in an opengl glfw window. I tried using
oldContext = glfwGetCurrentContext(); but the value of oldContext is just null.
I am trying to use the low-level native unity plugin and Texture.GetNativeTexturePtr
Any help would be greatly appreciated!
OpenGL context cannot be queried like OpenGL state related objects via some glGet* API.Context is not part of OpenGL API,it is a part of the system you're running on and it exists to allow you maintaining of OpenGL state and issue command to the driver. You must access a system specific handle that points to the context via system specific API.On Windows (WinGDI)that's would be
HGLRC wglGetCurrentContext();
On linux see related GLX API. You need to find functions to access GLXContext
I did it once in Unity3D (framebuffer readout plugin). But it used Unity's OpenGL or DirectX context to issue API commands only.
Also,I am not sure you can 'inject' or share a context for a window that doesn't own that context. You see, when you (or Unity) init display it creates context and related GL resources,like the default FBO with all required attachments on its own,and that FBO is mapped to some system resource(device) which takes actually care of presenting those pixels on the screen. Therefore, I am not sure display context can be moved from Window to Window in the same manner that a context can be shared between threads.(But I can be wrong on this one)
You can create your plugin Window on some thread,with its own GL context. Then create and share a texture object between those two. Remember, GL textures are shareable. If you copy contents from Unity's screen FBO into that texture,then you can copy it into your plugin's screen FBO from that texture as well.
Btw,look at this SO question .You can see there vendor specific GL extensions which allow copying data into texture from different contexts without requiring shared context,share lists setup.
Regarding why GLFW returns you nullptr. In your example you use GLFW library.
glfwGetCurrentContext()
But if you look at the source code,you see this:
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetTls(&_glfw.contextSlot);
}
Which probably means that it retrieves a pointer to GLFWWindow from its own cache and not from the system.And if you didn't create that context via GLFW,you won't get any valid pointer. So try working directly with your system related API as explained above.
Objective:
To make some onscreen and offscreen rendering via Qt5 OpenGL framework, such that the resources can be easily shared between both rendering parts. Specifically,
the rendering work is done through the offscreen part (the framebuffer might be larger than the display screen);
the results of the offscreen rendering can be displayed in multiple onscreen parts (say, QOpenGLWidgets) under different settings, e.g. different sizes, for simplicity;
the results of the offscreen rendering can also be extracted from GPU and saved into a QImage or cv::Mat object;
the above tasks can be executed asynchronously (doing the second offscreen rendering, while displaying or extracting the first offscreen result).
Current solution:
Since I don't know how to share resources between both parts, the actual rendering work are done redundantly in both parts in my current solution:
The onscreen part:
A QMainWindow containing multiple QOpenGLWidget (subclass of QOpenGLWidget) objects;
The offscreen part:
A custom class involving members of QOffscreenSurface, QOpenGLContext, and QOpenGLFramebufferObject pointers, as well as a QOpenGLFunctions pointer to invoke OpenGL functions do the actual rendering work, much similar to this link.
The actual renderer:
As the reason above, the actual rendering work is extracted into a seperated class and both parts (onscreen and offscreen) have its handle.
Questions:
There are two QOpenGLContexts:
When doing the offscreen work in a background thread (for asynchronously rendering), it says the QWindow-based QOffscreenSurface are not allowed to exist outside the gui thread;
When doing this in the main (GUI) thread, it says the QOpenGLContext is invalid.
So my questions are:
Should I do the offscreen and onscreen work in the same GUI thread or not?
What is the best way of communicating and sharing resources between the offscreen and onscreen parts?
A brief actual code example doing a simple rendering work (say, draw a triangle via shading language) will be much appreciated.
Assuming that QOpenGLContext *main_ctx is the context that was created by QOpenGLWidget for actual rendering, you can create another context ctx in any thread and make it share textures and buffers with the first one:
ctx = std::make_unique<QOpenGLContext>();
ctx->setFormat(main_ctx->format());
ctx->setShareContext(main_ctx);
ctx->create();
I don't think that QOffscreenSurface must be a QWindow-based.
offscreen_surface = std::make_unique<QOffscreenSurface>();
offscreen_surface->setFormat(ctx->format());
offscreen_surface->create();
ctx->makeCurrent(offscreen_surface);
Then create a QOpenGLFramebufferObject and render into it from the second context (second thread).
Then use its texture in the main context: glBindTexture(GL_TEXTURE_2D, fbo->texture());. Maybe there is a need for some synchronization when doing this.
We have a 3D rendering window created using GLFW and we want to use QWebkit for displaying a QWebPage inside the rendering (aka render the QWebPage to an OpenGL texture). Using only the CPU version is too slow and Qt supports rendering QWebkit into QOpenGLFramebufferObjects (using QOpenGLPaintDevice).
However, doing so requires the creation of a QOpenGLContext (which requires its own window and so on), eventually interfering with our whole application. (Switching between GLFW and Qt Context also causes an infinite amount of GL_INVALID_OPERATIONs)
Best case solution: we get Qt to use the GLFW Context.
Code example:
QOpenGLFramebufferObject qfbo(mWidth, mHeight); //< this crashes because he will implicitly try to get QOpenGLFunctions which gets the default context which is null
qfbo.bind();
QOpenGLPaintDevice paintdev(mWidth, mHeight);
QPainter painter(&paintdev);
painter.beginNativePainting();
mPage->mainFrame()->render( &painter );
painter.endNativePainting();
So here are some questions:
is it possible to get Qt to use the GLFW OpenGL context?
if not, how can we switch between GLFW context and Qt context? (using texture sharing for transferring the rendered QWebPage)
if all of this is impossible, is there a free Webkit project with 64bit, Windows/Linux/Mac support that can render using OpenGL?
#Sebastian Cabot wrote:
You can't directly mix the two context objects using QT. QT is great but in order to keep itself portable it also has some limitations - mainly accessing the low level handles of the objects and manipulating them directly. So Even trying to use a QOpenGLContext from a different thread then the one it was created in will fail. And in order to use any of the QT OpenGL wrappers you will need a valid QOpenGLContext current. So what you want is not possible without hacking into the QT implementation.
I have a program that has an OpenGL window to draw various things in it. At the same time, I am doing offscreen rendering to get image masks.
Each one of them has a separate OpenGL context that they draw to. The offscreen rendering is called regularly, say every second.
What happens is that the offscreen context does not "switch back" the default context to the GUI context, so I end up drawing things to the GUI from offscreen.
What's a way of telling OpenGL "use this other context from this moment on" ?
With GLX, you can use glXMakeCurrent, which has the signature:
Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx);
We have an OpenGL Application (using Ogre3d and SDL, not directly calling OpenGL) and we are trying to change the Resolution at runtime. It seems that we need to re-initialize our OpenGL context with the new Resolution but a number of items are breaking along the way. On Linux it seems to work for a while, then we get graphical corruption on screen. On Windows it simply crashes the next time we try to render a frame. We have forced the reloading of textures in Ogre, and if we rendering nothing but textures (no 3d models) then this works fine, but any 3d models cause a crash and reloading before rendering them has no effect.
Here is a link to an in depth explanation of Ogre3d calls we are doing: http://www.ogre3d.org/forums/viewtopic.php?f=2&t=62825
All we really need to know is, When re-initializing an Opengl context what resources need to be restored?
Why does adjusting an OpenGL context affect other resources? Is it the way OpenGL works, or did one of the libraries we use introduce this issue? Could we have added this issue without knowing it?
Did you have a look at this forum thread ?
SDL seems to destroy the OpenGL when changing resolution. In this case, all you GL resources are destroyed with the context.
One possible solution would be to create another 'dummy' GL context, sharing resources with you 'real' GL context, and to keep it alive with SDL destroys the 'main' context. This way most of your resources should survive.
Note that some resources can't be shared, textures and VBO are fine, but VAO can't.
OpenGL support was added SDL after its surface code had been established. That's why changing the size of a SDL window is destructive. You were pointed to OpenGL context sharing and its caveats. However I'd avoid the problem alltogether by not using SDL for creating an OpenGL window. You can use all the other facilities SDL provides without a window managed by SDL, so the only thing that would change is input event processing and how the window's created. Instead of SDL I'd use GLFW, which like SDL requires you to implement your own event processing loop, so using GLFW as a drop-in replacement for OpenGL window and context creation is straightforward.