Rendering into a Qt QOpenGLFramebufferObject

1,749 views
Skip to first unread message

james...@gmail.com

unread,
Feb 9, 2018, 5:18:23 PM2/9/18
to Magnum C++/OpenGL Graphics Engine
Hello,

I was wondering if someone on here could help me please. I am working on a new Qt Quick project in which I would like to add 2D/3D graphics to support visualisation of some data. I have done this previously using QOpenGLFramebufferObjects (via QQuickFramebufferObject) and pure OpenGL to render graphics such as point clouds. Since then I have been on the search for a new library/framework that would make this and adding extra functionality easier, such as text and object picking. This is when I came across Magnum which looks great thanks to the showcase, online documentation and guides.

However, while integrating Magnum into my QQuickFramebufferObject class I have ran into an issue pretty early on. I have followed a number of guides/examples on the Magnum website and have began to implement via the basic steps shown in the magnum-bootstrap base-qt code (https://github.com/mosra/magnum-bootstrap/blob/base-qt/src/MyApplication.cpp) to create the context and call clear() on the default framebuffer. I have also integrated the basic triangle example (http://doc.magnum.graphics/magnum/examples-triangle.html) to check that basic rendering is possible. This all seems to work fine, until the second frame is rendered at which point the whole QQuickFramebufferObject appears to turn white in colour.

I have checked through the troubleshooting page on the Magnum website and unfortunately this hasn't helped me this time. Enabling debug output also revealed nothing.

So, I was wondering if anyone might have any ideas or tips to help me fix this issue?

To give some more detail on the issue I am writing this on Windows 7 using Qt 5.9.2 compiled for MinGW-w64 (64-bit), creating a basic QQuickFramebufferObject based on http://blog.qt.io/blog/2015/05/11/integrating-custom-opengl-rendering-with-qt-quick-via-qquickframebufferobject/, initialising the Magnum context similarly to https://github.com/mosra/magnum-bootstrap/blob/base-qt/src/MyApplication.cpp and trying to draw a basic triangle.

If you think it would help I can also provide a portion of the source code.

Thanks in advance,
James

Vladimír Vondruš

unread,
Feb 10, 2018, 5:53:43 AM2/10/18
to james...@gmail.com, Magnum C++/OpenGL Graphics Engine
Hi!

first of all, thanks for the appreciation!

I did just a quick glance over the Qt blog post and the "Pitfalls: context and state" section confirmed my suspicion -- there's probably some state that gets set by Qt without Magnum being aware of that. The fully white output could be caused simply by wrong shader being used (I've encountered far too many cases of this on NVidia cards). The Troubleshooting page mentions using Context::resetState() ( http://doc.magnum.graphics/magnum/classMagnum_1_1Context.html#ac75cc4e484a300bac27d802ed41bb203 ) and the Qt blog post mentions using QQuickWindow::resetOpenGLState() to solve this. To be safe, I would call Context::resetState() at the beginning of your render() implementation (so Magnum behaves properly after) and QQuickWindow::resetOpenGLState() at the end (so Qt behaves properly after).

Also, depending on what all you need to do with the Qt framebuffer object, you might later want to wrap QOpenGLFramebufferObject::handle() in Magnum::Framebuffer using Framebuffer::wrap() ( http://doc.magnum.graphics/magnum/classMagnum_1_1Framebuffer.html#a7e25010147fba25d7f52d645421f4a0f ) so you can then do clearing, setup and everything directly using Magnum APIs instead of using Qt and deal with conflicts in state trackers again. But .. this might bring up more issues if used in a way that Qt doesn't expect, so be cautious.

Hope this helps :)

Regards
mosra

______________________________________________________________
> Od: james...@gmail.com
> Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com>
> Datum: 09.02.2018 23:18
> Předmět: [magnum] Rendering into a Qt QOpenGLFramebufferObject
>--
>You received this message because you are subscribed to the Google Groups "Magnum C++/OpenGL Graphics Engine" group.
>To unsubscribe from this group and stop receiving emails from it, send an email to magnum-engin...@googlegroups.com.
>To post to this group, send email to magnum...@googlegroups.com.
>Visit this group at https://groups.google.com/group/magnum-engine.
>For more options, visit https://groups.google.com/d/optout.
>
>

james...@gmail.com

unread,
Feb 10, 2018, 3:14:13 PM2/10/18
to Magnum C++/OpenGL Graphics Engine
Hi mosra,

Thanks for the speedy response. I have tried out your suggestions and initially had no luck. After some experimenting I finally managed to get everything to render properly!

The Context::resetState() and QQuickWindow::resetOpenGLState() calls as you suggested are essential, also wrapping of the QOpenGLFramebufferObject with Framebuffer::wrap is required to make clearing work properly.

The missing piece of my puzzle was the actual framebuffer clear, where clearing both color and depth buffers are required (initially, I was only cleaning color). Another issue, once finding that, was that the clear color seems to be altered by Qt, changing it to white. So my solution was to call Framebuffer::clearColor and ::clearDepth each separately.

Cheers for your help!

James

Vladimír Vondruš

unread,
Feb 10, 2018, 5:29:16 PM2/10/18
to james...@gmail.com, Magnum C++/OpenGL Graphics Engine
Great to hear that it works now! :)

Besides calling clearColor() and clearDepth() separately you could also use Renderer::setClearColor() ( http://doc.magnum.graphics/magnum/classMagnum_1_1Renderer.html#a19365b6b55bfa5e7d97ceeead2db64f5 ) to revert the state change that Qt did. This would also make it work on embedded systems that have only GLES 2.0 (or, potentially, WebGL 1).

______________________________________________________________
> Od: james...@gmail.com
> Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com>
> Datum: 10.02.2018 21:14
> Předmět: Re: [magnum] Rendering into a Qt QOpenGLFramebufferObject
>
>Hi mosra,
>
>Thanks for the speedy response. I have tried out your suggestions and
>initially had no luck. After some experimenting I finally managed to get
>everything to render properly!
>
>The Context::resetState() and QQuickWindow::resetOpenGLState() calls as you
>suggested are essential, also wrapping of the QOpenGLFramebufferObject with
>Framebuffer::wrap is required to make clearing work properly.
>
>The missing piece of my puzzle was the actual framebuffer clear, where
>clearing both color and depth buffers are required (initially, I was only
>cleaning color). Another issue, once finding that, was that the clear color
>seems to be altered by Qt, changing it to white. So my solution was to call
>Framebuffer::clearColor and ::clearDepth each separately.
>
>Cheers for your help!
>
>James
>
>
>
>On Saturday, 10 February 2018 10:53:43 UTC, mosra wrote:
>>
>> > Od: james...@gmail.com <javascript:>
>> > Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com
>> <javascript:>>
>> email to magnum-engin...@googlegroups.com <javascript:>.
>> >To post to this group, send email to magnum...@googlegroups.com
>> <javascript:>.

james...@gmail.com

unread,
Feb 12, 2018, 7:16:09 PM2/12/18
to Magnum C++/OpenGL Graphics Engine
Hi mosra,

That's great thanks for the help. Renderer::setClearColor works perfectly!

However, if you don't mind, I've ran into another issue :(

I'm trying to 'upgrade' my application to the Primitives Example. Now the first frame renders correctly, but second frame causes a segfault caused by a call to glDrawRangeElements in Mesh::drawInternal() (https://github.com/mosra/magnum/blob/master/src/Magnum/Mesh.cpp#L315) -- now running a debug build of Magnum from the latest on master.

My hunch is that Qt playing around with OpenGL state is to blame again.. Context::resetState() is still being used before any render calls.

Any ideas with this one? Thanks again in advance for your help!

Cheers
James

Vladimír Vondruš

unread,
Feb 13, 2018, 4:54:54 AM2/13/18
to james...@gmail.com, Magnum C++/OpenGL Graphics Engine
Hi,

after thinking about this a bit, I think I know exactly what's the problem -- there's one really filthy corner of the whole OpenGL state machine, where it's possible to accidentally modify a VAO if one (un)binds an index buffer while a VAO is bound. And that's I think exactly what Qt is doing: unbinding an index buffer, which then causes a crash because it's trying to load index data from memory at pointer zero. Boom.

Anyway, that's me just thinking out loud. Can you try the following? Once you confirm that this is indeed the case, I'll make it part of Magnum API:

- Right before QQuickWindow::resetOpenGLState(), so at the end of your magnum code block, call glBindVertexArray(0);

Thanks
mosra

______________________________________________________________
> Od: james...@gmail.com
> Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com>
> Datum: 13.02.2018 01:16
> Předmět: Re: [magnum] Rendering into a Qt QOpenGLFramebufferObject
>
>Hi mosra,
>
>That's great thanks for the help. Renderer::setClearColor works perfectly!
>
>However, if you don't mind, I've ran into another issue :(
>
>I'm trying to 'upgrade' my application to the Primitives Example. Now the
>first frame renders correctly, but second frame causes a segfault caused by
>a call to glDrawRangeElements in Mesh::drawInternal()
>(https://github.com/mosra/magnum/blob/master/src/Magnum/Mesh.cpp#L315) --
>now running a debug build of Magnum from the latest on master.
>
>My hunch is that Qt playing around with OpenGL state is to blame again..
>Context::resetState() is still being used before any render calls.
>
>Any ideas with this one? Thanks again in advance for your help!
>
>Cheers
>James
>
>On Saturday, 10 February 2018 22:29:16 UTC, mosra wrote:
>>
>> Great to hear that it works now! :)
>>
>> Besides calling clearColor() and clearDepth() separately you could also
>> use Renderer::setClearColor() (
>> http://doc.magnum.graphics/magnum/classMagnum_1_1Renderer.html#a19365b6b55bfa5e7d97ceeead2db64f5
>> ) to revert the state change that Qt did. This would also make it work on
>> embedded systems that have only GLES 2.0 (or, potentially, WebGL 1).
>>
>> ______________________________________________________________

james...@gmail.com

unread,
Feb 13, 2018, 5:51:15 AM2/13/18
to Magnum C++/OpenGL Graphics Engine
That solved it!

My cube is now changing colours perfectly!

Massive thanks for your help with this!

Vladimír Vondruš

unread,
Feb 14, 2018, 8:12:41 AM2/14/18
to james...@gmail.com, Magnum C++/OpenGL Graphics Engine
Hi,

I updated the resetState() API to handle this case properly. See the updated docs: http://doc.magnum.graphics/magnum/opengl-wrapping.html#opengl-state-tracking

The particular change is present in https://github.com/mosra/magnum/commit/14a213f6eb8f785ce523922013a7bf226162b383 .

Thanks for reporting all the issues, you helped to improve this area of Magnum quite a lot!

mosra

______________________________________________________________
> Od: james...@gmail.com
> Komu: Magnum C++/OpenGL Graphics Engine <magnum...@googlegroups.com>
> Datum: 13.02.2018 11:51
> Předmět: Re: [magnum] Rendering into a Qt QOpenGLFramebufferObject
>
>That solved it!
>
>My cube is now changing colours perfectly!
>
>Massive thanks for your help with this!
>
>On Tuesday, 13 February 2018 09:54:54 UTC, mosra wrote:
>>
>> Hi,
>>
>> after thinking about this a bit, I think I know exactly what's the problem
>> -- there's one really filthy corner of the whole OpenGL state machine,
>> where it's possible to accidentally modify a VAO if one (un)binds an index
>> buffer while a VAO is bound. And that's I think exactly what Qt is doing:
>> unbinding an index buffer, which then causes a crash because it's trying to
>> load index data from memory at pointer zero. Boom.
>>
>> Anyway, that's me just thinking out loud. Can you try the following? Once
>> you confirm that this is indeed the case, I'll make it part of Magnum API:
>>
>> - Right before QQuickWindow::resetOpenGLState(), so at the end of your
>> magnum code block, call glBindVertexArray(0);
>>
>> Thanks
>> mosra
>>
>> ______________________________________________________________

james...@gmail.com

unread,
Feb 24, 2018, 11:25:35 AM2/24/18
to Magnum C++/OpenGL Graphics Engine
Hi mosra,

Thanks for implementing the fix in the API. I'll update to the latest Magnum release when I'm back playing with GL code again!

Cheers,
James

philippe...@gmail.com

unread,
Oct 3, 2018, 3:01:35 PM10/3/18
to Magnum C++/OpenGL Graphics Engine

Hello,
does someone have a working example of this? I'd be very interested in classic "Triangle Example" as a starting point for a QML project.

Thank you,
 Philipp

james...@gmail.com

unread,
Oct 3, 2018, 5:27:59 PM10/3/18
to Magnum C++/OpenGL Graphics Engine
Hi Philipp, I don't know of any complete QML examples, but if you are creating a renderer that inherits from QOpenGLFramebufferObject it is very easy to integrate magnum and it's basically covered in this post: http://blog.magnum.graphics/announcements/2018.02/#better-interoperability-with-3rd-party-code

Hope that helps!

philippe...@gmail.com

unread,
Oct 7, 2018, 10:48:28 AM10/7/18
to Magnum C++/OpenGL Graphics Engine

Thank you, James, I'll give that a try!
Reply all
Reply to author
Forward
0 new messages