How to switch between two OpenGL contexts - opengl

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);

Related

Interactions between Onscreen and Offscreen rendering in Qt5 with QOpenGL\* classes

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.

Combining GLX (OpenGL) and X11 graphics

I have to write an application on Linux using X11 for the interface (in C++). The application uses GLX to render some openGL graphics, but I also need to write some custom UI for this app within the same window.
When I create window I created a GC and a GLX context. Ideally I'd need to "draw" the openGL into a region of the window (say the left part) and the draw the UI on the side of the GL viewport.
How can I do that?
how can i combine GLX and GC drawing calls, such as XDrawString for example.
what would be the best way for me to create a layout within the same window, reserving a region of the window in which I draw the GL content, and having another region of the window in which I draw the UI using X calls. Do I need to create sub-windows for that?
I actually found a useful answer here:
Create GLX context in specific region of a window
The idea is to spawn a sub-window from the current window and draw the GL content to it.
I'd suggest to use BindTexImage extension, draw your X11 (via core / xrender / whatever ) commands to offscreen pixmap and then later composite it as a texture.

SDL2 and OpenGL functions with two windows

I am trying to make one application with two windows with SDL2. To make draw process faster and capable to run 3d animations I am using OpenGL. But when I open second window, how can I said to OpenGL (gl functions) to draw in second window?
I searched into libsdl wiki but cant find anything.
You are looking for the SDL_GL_MakeCurrent function.
Use this function to set up an OpenGL context for rendering into an OpenGL window.
Example:
SDL_GL_MakeCurrent(window, gl_context);
// OpenGL functions will draw to window
// ...
SDL_GL_MakeCurrent(window2, gl_context);
// OpenGL functions will draw to window2

Hide GLUT window

Is it possible to hide OpenGL window and the rendering are still running? I use glutHideWindow which will never trigger display function.
If that is not possible, is it possible in the program to change the focus of the current window? I want to run opengl program but I don't need that window. In fact, I want to use the framebuffer that opengl updates at each frame in another program. But it's always annoying to toggle between the two programs. (They both have window)
Is it possible to hide OpenGL window and the rendering are still running?
Yes and No to both parts of the question.
If you hide a window, all the pixels of the window's viewport will fail the pixel ownership test when rendering. So you can't use a hidden window as a drawable for OpenGL to operate on.
What you need is an off-screen drawable to draw to.
The modern variant are Framebuffer Objects (FBOs), which you can create on a regular OpenGL context, that might even work on a hidden window. FBOs take some drawable attachments (render buffers, textures) and allow OpenGL to draw to these instead to the window.
An older method are PBuffers, also widely supported, but not as easy to use as FBOs.
Note that if you want to perform off-screen rendering on Linux/X11 the X server must be active, i.e. owning the VT so that the GPU actually processes the commands. So you can't just start an X server "in the background" but have another X server use the display device.
After creating the window, you can use glutHideWindow() to go offscreen. Then you still render as nomal and use glReadPixels to read back and get buffer to use it later.

Can you create OpenGL context without opening a window?

Occassionally I hit places where I'd want to get an OpenGL framebuffer object, but where I'm not interested about opening a window of any kind.
Is it possible to create an opengl context without attaching it to a window of any kind?
Yes! you can use the desktop window as the window passed to OpenGL- as long as you don't try to display anything on it ;)
Just Call GetDesktopWindow and pass the result as an argument when creating new OpenGL window.
http://www.opengl.org/wiki/Creating_an_OpenGL_Context
According to this Web page, WGL_ARB_create_context can be used to create a context without a window. I have not actually tried it myself. I used freeGLUT to create the context and then rendered off-screen to a framebuffer+renderbuffer. I exit the program without ever calling glutMainLoop. It is klugy, but it works for my purposes.
Yes, you can perform off-screen rendering with OpenGL, but the exact way to set it up is dependent on the operating system.
The closest you get to an OS independent way would be to use Mesa 3D, but then your off-screen rendering would not be hw accelerated.