Discussion:
[Interest] How to share a native OpenGL context with Qt?
Marc Gilleron
2015-06-17 15:54:53 UTC
Permalink
Hello,

We have to integrate Qt in our application. A part of it uses OpenGL to
perform custom rendering on various platforms.

Our context is created in a custom way, nothing to do with Qt in the first
place.
We made a test with a QML window and another non-Qt window where we used to
render OpenGL, and it doesn't works because of resource clashes.
So we need to share.

Is there a way to do this with Qt by setting the
Qt::AA_ShareOpenGLContexts flag?
I didn't found any global context to call share on it in the public API...

Note: I know there are canonical ways to draw OpenGL stuff in Qt, however,
none of them currently suits our needs in terms of existing codebase and
time. We want to be able to draw from our own loop, in our own surface,
which is neither inside a paintGL()/Qt call, nor in another thread.
Giuseppe D'Angelo
2015-06-17 21:41:52 UTC
Permalink
Hi,
Post by Marc Gilleron
Our context is created in a custom way, nothing to do with Qt in the
first place.
We made a test with a QML window and another non-Qt window where we used
to render OpenGL, and it doesn't works because of resource clashes.
So we need to share.
Is there a way to do this with Qt by setting the
|Qt::AA_ShareOpenGLContexts |flag? I didn't found any global context to
call share on it in the public API...
http://doc-snapshots.qt.io/qt5-5.5/qopenglcontext.html#globalShareContext
If you peek at the implementation you can actually also grab it on <=
5.4 by using some private APIs.
Post by Marc Gilleron
Note: I know there are canonical ways to draw OpenGL stuff in Qt,
however, none of them currently suits our needs in terms of existing
codebase and time. We want to be able to draw from our own loop, in our
own surface, which is neither inside a paintGL()/Qt call, nor in another
thread.
Now from your email I'm not 100% sure of what you need to achieve. Do
you want to draw QML content on top of some other OpenGL content, and do
that in a non-Qt window / GL context? There's QQuickRenderControl for that.

Hope this helps,
--
Giuseppe D'Angelo | ***@kdab.com | Software Engineer
KDAB (UK) Ltd., a KDAB Group company | Tel: UK +44-1625-809908
KDAB - The Qt Experts
Marc Gilleron
2015-06-18 16:11:18 UTC
Permalink
Actually, here is what we have:

Our application has a main thread loop.
It loads Qt dynamically (because we don't necessarily need it at compile
time). Qt doesn't wraps our app.
At some point in our main thread, we create a QApplication and widgets.
Then, as we did before Qt integration, we load our OpenGL renderer. It
creates its own context, may load resources at any time, and currently
draws in its own non-Qt window.

But, the simple fact we now have Qt Windows and non-Qt windows with OpenGL
at the same time produces glitches in our renderer, and we're trying to
solve it.
(We do this to keep them independant from each other. In the future we may
wrap our renderer window in a QWindow but at the moment we try to make it
just work).

Here is the kind of code I used to perform sharing, just after we create
our custom OpenGL context:

// Get the main Qt context
Q_ASSERT(qGuiApp);
QOpenGLContext * qtContext = qt_gl_global_share_context();
if (qtContext == 0)
{
// Qt: Global OpenGL context is not available
return 0;
}
#ifdef WIN32
// We get our renderer's OpenGL context
HGLRC hOurContext = /* get from somewhere */
HWND hOurWindow = /* get from somewhere */

QWGLNativeContext ourNativeContext(hOurContext, hOurWindow);
QOpenGLContext * ourContext = new QOpenGLContext;
ourContext->setNativeHandle(QVariant::fromValue(ourNativeContext));
ourContext->setShareContext(qtContext);
ourContext->create();
#else

However I didn't noticed any difference. Or is this the wrong way to share?

Or maybe there is one more problem:
we are still single-threaded, so we need to make sure the current OpenGL is
the good one when we perform our calls.
I said we cannot use the the approaches needing paintGL() and the like,
because we would be outside of our main loop, and would lead to
side-effects.

I also wonder if we can put the Qt main loop in ours, because at the moment
we have no clue when it updates...
Marc Gilleron
2015-06-25 12:50:51 UTC
Permalink
I managed to create our custom renderer by sharing the OpenGL context Qt
provides with qt_gl_global_share_context() and Qt::AA_ShareOpenGLContexts.
Using wglCreateContextAttribsARB() on our side, wharing worked without
errors, and it fixed some of our visual bugs.
We also made sure to call wglMakeCurrent() before we draw.

however I still get glitches: QML widget drawn in a half-quad, black
window, Qt window resizing our framebuffer, hover effects making our
renderer flicker... etc

I tried to launch gDebugger to see what's going on, and it seems not all of
Qt's contextes are shared.
Any idea how it can be solved?
Post by Marc Gilleron
Our application has a main thread loop.
It loads Qt dynamically (because we don't necessarily need it at compile
time). Qt doesn't wraps our app.
At some point in our main thread, we create a QApplication and widgets.
Then, as we did before Qt integration, we load our OpenGL renderer. It
creates its own context, may load resources at any time, and currently
draws in its own non-Qt window.
But, the simple fact we now have Qt Windows and non-Qt windows with OpenGL
at the same time produces glitches in our renderer, and we're trying to
solve it.
(We do this to keep them independant from each other. In the future we may
wrap our renderer window in a QWindow but at the moment we try to make it
just work).
Here is the kind of code I used to perform sharing, just after we create
// Get the main Qt context
Q_ASSERT(qGuiApp);
QOpenGLContext * qtContext = qt_gl_global_share_context();
if (qtContext == 0)
{
// Qt: Global OpenGL context is not available
return 0;
}
#ifdef WIN32
// We get our renderer's OpenGL context
HGLRC hOurContext = /* get from somewhere */
HWND hOurWindow = /* get from somewhere */
QWGLNativeContext ourNativeContext(hOurContext, hOurWindow);
QOpenGLContext * ourContext = new QOpenGLContext;
ourContext->setNativeHandle(QVariant::fromValue(ourNativeContext));
ourContext->setShareContext(qtContext);
ourContext->create();
#else
However I didn't noticed any difference. Or is this the wrong way to share?
we are still single-threaded, so we need to make sure the current OpenGL
is the good one when we perform our calls.
I said we cannot use the the approaches needing paintGL() and the like,
because we would be outside of our main loop, and would lead to
side-effects.
I also wonder if we can put the Qt main loop in ours, because at the
moment we have no clue when it updates...
Loading...