1

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.

Community
  • 1
  • 1
oaheix
  • 13
  • 3

1 Answers1

1

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.

Velkan
  • 7,067
  • 6
  • 43
  • 87
  • Thanks for your help. What about multiple *offscreen* parts (in multiple threads), whose rendering results will be displayed in the same *onscreen* part in turn by some rules? Should their `ctx`s all share the same `main_ctx`? If multiple `fbo`s (from multiple *offscreen* parts) are then used, will they overlap each other? or will multiple `fbo->texture()`s return the same value? If so, how to avoid it? I don't quite familiar with the mechanism of `fbo` and texture. – oaheix Aug 31 '16 at 06:54
  • It's not like "share the same main_ctx", because all shared contexts have equal rights: they share share textures, shaders, and other OpenGL resources. About FBOs: it seems that for each FBO Qt creates a separate texture to use. – Velkan Aug 31 '16 at 07:11
  • Thanks again for you kind help! With your suggestions, I've tried to transfer the texture id `unit` from the FBO (*offscreen* part) to `QOpenGLTexture` (*onscreen* part), it didn't display the desired texture. I think the reason might be the unfamiliarity to the use of `QOpenGLTexture` with FBO. The document of Qt5.7 says that one can render **TO** texture and also render **WITH** texture. Is there any simple example about these two usages. (That might be another question, should I launch a new post?) – oaheix Sep 02 '16 at 09:10
  • Make another question, so there would be a space to show the code with `QOpenGLFramebufferObject` that doesn't work. Then someone may fix the code if that code is a sufficiently self-contained example. – Velkan Sep 02 '16 at 10:33
  • A new question ([this link](http://stackoverflow.com/questions/39295154/render-to-and-with-texture-using-qopengltexture-and-qopenglframebufferobject)) has been posted. Thank you very much! – oaheix Sep 02 '16 at 14:47