4

I have an existing OpenGL context that I would like to share with a new QOpenGLWidget.

I know I can do this:

  1. Create QOpenGLWidget
  2. Wait until initializeGL is called and save the context
  3. Create new QOpenGLContext, and make it shared with the saved context

However, I would like to do it in the other order:

  1. Create QOpenGLContext
  2. Create QOpenGLWidget, providing the existing context and making them shared

Is this possible?

Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105
  • You can also do the sharing in the initGL call – ratchet freak Nov 10 '15 at 17:00
  • @ratchetfreak How? I think, when initGL is called, the OpenGL context is already created and cannot be set to share another context... – Jan Rüegg Nov 11 '15 at 08:07
  • Where does it say you can't share a context after it is created? – steventaitinger Jan 07 '16 at 22:38
  • I think that you don't need `QOpenGLWidget` at all. You may use `QWindow` with custom gl surface (or with your context) + `QWidget::createWindowContainer` to use it as a widget. – Dmitry Sazonov Jan 11 '16 at 16:55
  • @SaZ: thanks for the idea. I actually tried to do this first. However, using a QWindow as WindowContainer brings other problems with layouts and stuff, since it is not a proper widget. So I would rather like to stay with the Widget instead... – Jan Rüegg Jan 12 '16 at 07:23
  • @JanRüegg we didn't have any problems with layouting. You may check next code (a bit different, but), there is custom `QWindow` that creates a GL context and share it with external framework: https://github.com/dava/dava.framework/blob/80bfa3b832fe1a24d50783828868f0f73f1ab31b/Sources/Tools/QtTools/DavaGLWidget/davaglwidget.cpp – Dmitry Sazonov Jan 12 '16 at 08:57
  • @Saz: Interesting... maybe we did something wrong. Thanks for the link, I will have a look at it! – Jan Rüegg Jan 12 '16 at 09:06
  • yeah, I need to do the exact same thing this question is asking and QWindow is no longer an option, we were using that as a work around, but now it has to be a widget – ComradeJoecool Oct 31 '17 at 20:34

1 Answers1

3

Edit, I don't know much about QOpenGLFramebufferObject yet so ignore my previous answer content.

In the QOpenGLWidget it always sets its context to share with its closest top level window (or itself if it is a window). You are correct in your understanding that there is no way to change the QOpenGLWidget member context without subclassing it to totally change how it works. In the QOpenGLWidgetPrivate::initialize() function the context is initialized from the defaultFormat and from the top level shareContext. If you want to work with the context before you create the QOpenGLWidget then it must be through the global shared context. Qt::AA_ShareOpenGLContexts needs to be set before your QGuiApplication object is created.

You need to wait until QGuiApplication has initialized the global context before you try to access it. As the global_share_context is a static member of the QOpenGLContext class then you can just create any QOpenGLContext and access it via context.globalShareContext(). Then just delete your initial QOpenGLContext. Any QOpenGLWidget you create will share with that context automatically. If you can find a way of getting a pointer to the global shared context before you create() your special context then you can just share with the global context and you are good to go as the sharing goes both ways. The sharing is through the whole group of shared contexts that are shared with each other so any sharing with one context shares with the whole group.

Also, I don't know if this changes anything but The QOpenGLContext says it can share framebuffer objects too.

steventaitinger
  • 382
  • 2
  • 13
  • Are you sure you can change the OpenGL context in *initializeGL*? On this page: http://doc.qt.io/qt-5/qopenglwidget.html#initializeGL it says "The QOpenGLWidget's associated OpenGL context is guaranteed to be current whenever initializeGL() and paintGL() are invoked." To be current, the context must already be created, however. And setShareContext has to be called before creating the context... – Jan Rüegg Jan 08 '16 at 10:57
  • Just re create the context then and that should solve the problem. – steventaitinger Jan 08 '16 at 15:58
  • @stevantatinger Ah, I could try that. I guess the disadvantage (from a performance reason) is, that the context is created twice, right? – Jan Rüegg Jan 12 '16 at 07:24
  • @Jan Rüegg Yes the code I showed above would create the context twice on initialization. Have you tried just passing your existing context (making sure it is in the correct thread) and then calling makeCurrent()? If you re implemented initializeGL, paintGL and resizeGL to call makeCurrent at the beginning of each I don't see why you can't just use whatever context you want. Although it might be calling makeCurrent on two contexts each time which may affect performance a bit. – steventaitinger Jan 12 '16 at 15:11
  • @stevantatinger I didn't try yet, but I think this will not work: As far as I know, paintGL draws into a framebuffer that is set up by the QOpenGLWidget. If this framebuffer is set up by the widgets context, and a different context tries to draw into the framebuffer, this would probably be undefined behaviour. – Jan Rüegg Jan 13 '16 at 08:13
  • @stevantatinger Also, your second line in the second code box above: Shouldn't it be widget_context->setShareContext(m_context); ? – Jan Rüegg Jan 13 '16 at 08:16
  • @stavantatinger the last line in the second code box also doesn't work, makeCurrent needs a QSurface as argument... – Jan Rüegg Jan 13 '16 at 08:25
  • Sorry! Fixed. You need to work with the global shared context that QGuiApplication initializes. – steventaitinger Jan 13 '16 at 16:47
  • @stavantatinger Thanks for all the ideas, I really appreciate :) However, I think it still doesn't solve the problem, because when creating the QOpenGLWidget (which is after creating the global shared QOpenGLContext) I can still not make the widgets context shared with my special context, created in step 1) of the question... – Jan Rüegg Jan 13 '16 at 22:05
  • If your special context is the global shared context then the widgets context is automatically shared with it. The sharing goes both ways. You just need to use the global shared context as your special context. Why does that not work for you? You could probably even not use the global shared context but just share your special context with the global one to enable your widgets context to access the resources of your special context. – steventaitinger Jan 14 '16 at 05:01
  • Hmm... yes, that actually might answer the question, you're right. How do I know the global shared context is initialized? – Jan Rüegg Jan 14 '16 at 08:15
  • It is initialized in void QGuiApplicationPrivate::init() [here](https://github.com/qtproject/qtbase/blob/ad16478a76815f8f61d454bf7760aaf9ffbb4b51/src/gui/kernel/qguiapplication.cpp). globalShareContext() returns a null pointer if not initialized yet. – steventaitinger Jan 14 '16 at 14:31
  • that is my problem exactly, globalShareContext() is always null, and I cannot initialize the glFunctions. Only other problem is, this is a QWidget based application so I need QApplication, not QGuiApplication. – ComradeJoecool Nov 01 '17 at 15:08
  • Yo, how did this go at the end and where is the example code you guys keep talking about? – Dariusz Jun 14 '19 at 05:17
  • We weren't talking about example code. You would need to ask the OP for any code he was willing to provide. I was referring to the Qt docs for code. – steventaitinger Aug 26 '19 at 02:00
  • Does `QOpenGLContext::globalShareContext()` work on Android and iOS? Doesn't look like `QOpenGLContext::globalShareContext()` is an option on Android and iOS? – TheWaterProgrammer Mar 13 '23 at 12:14