PDA

View Full Version : Performance issues when using QWidget::render with a QGLWidget's painter



Bjartr
3rd November 2010, 21:01
I'm currently drawing widgets to a QGLWidget using render() inside of the QGLWidget's paintEvent. The problem I have occurs when I use setOpacity() on the painter, the performance tanks and the app becomes unusably slow until the widget is hidden.

During this time I notice that my CPU spikes, which I didn't expect because I thought this technique would make use of QOpenGLPaintEngine and thus be hardware accelerated.

Why is this not being accelerated and what can I do to speed this up?

Bjartr
4th November 2010, 14:47
After some experimentation I've found that each widget rendered in this manner causes a noticeable hit to performance and so a widget with several children (a frame with 8 buttons, an image, and some labels in my case) together cause the slowdown.

Is it possible for me optimize this? Rendering without transparency to an intermediary pixmap and then drawing that with transparency to the QGLWidget doesn't seem to help, which is counterintuitive to me.

Bjartr
5th November 2010, 14:17
After further experimentation I've found that images used in the UI severely hurt performance, possibly because images are copied to an intermediary pixmap by QOpenGLPaintEngine before they are drawn.

I greatly appreciate any advice for optimization.

Bjartr
8th November 2010, 15:29
According to a co-worker these performance issues were less problematic when using a QGraphicsScene, is that rendering pipeline really so different?

wysota
8th November 2010, 15:32
Yes, it's completely different. With every update of QGLWidget the whole widget is redrawn from scratch. With regular widgets and graphics item only the portions that changed are getting redrawn. At least by default.

Bjartr
8th November 2010, 18:22
Yes, it's completely different. With every update of QGLWidget the whole widget is redrawn from scratch. With regular widgets and graphics item only the portions that changed are getting redrawn. At least by default.

Sorry I wasn't clear, I didn't mean the difference between drawing a QGLWidget and a regular QWidget, I am well aware of that. I meant the difference between rendering a widget to to a GL context in a QGraphicsScene versus rendering the same widget to a QGLWidget. Why is former performant and the latter slow?

wysota
9th November 2010, 11:26
Again, if you render an item that doesn't change in the graphics scene, it is likely there is a clean copy of it available and your paint() implementation for it (that calls render()) will not be called. With a pure widget if you don't do any caching yourself, render() will be called for every widget involved during every repaint. Calling render() is generally expensive so you want to avoid it if you can - cache everything you can in pixmaps. And if the only reason for doing all this is that you want to have semi-transparent widgets on a GL scene, find a better approach than this, you'll have tons of trouble making your "widget stamps" work like real widgets (i.e. focus handling). It's easiest to go through GraphicsScene, it handles such a situation and has everything required for it to work already implemented.

Bjartr
9th November 2010, 18:04
cache everything you can in pixmaps.

Even when doing caching and only updating the pixmaps when something changes each change causes a noticeable hiccup in the QGLWidget as well as the rest of the application. I am curious as to why this does not occur when using a QGraphicsScene, how are the pixmaps being managed and utilized in such a way that don't cause this hiccup?


find a better approach than this

Unfortunately, due to the nature of the target platform (weak intel integrated graphics), most easy solutions fail due to driver issues or their own performance problems. (What I would give to simply be able to have `-graphicssystem opengl` work)


you'll have tons of trouble making your "widget stamps" work like real widgets (i.e. focus handling).

Not if the widget is actually above the QGLWidget, but left undrawn (by Qt's normal drawing) using clip masks.


It's easiest to go through GraphicsScene

This requires the current drawing done in the several QGLWidgets involved to be rewritten for the QGraphicsScene context, which is not insignificant. I am trying to get a good handle on the various avenues available to me to determine where best to put my efforts.

I'm not saying our current implementation was the right choice, but we're trying to solve this in a way that minimizes modifications to the existing app's architecture.

wysota
9th November 2010, 22:11
Even when doing caching and only updating the pixmaps when something changes each change causes a noticeable hiccup in the QGLWidget as well as the rest of the application. I am curious as to why this does not occur when using a QGraphicsScene, how are the pixmaps being managed and utilized in such a way that don't cause this hiccup?
I'd have to see your code to be able to say anything.



Unfortunately, due to the nature of the target platform (weak intel integrated graphics), most easy solutions fail due to driver issues or their own performance problems. (What I would give to simply be able to have `-graphicssystem opengl` work)
I would go through graphics view. And I would try -graphicssystem raster too.



Not if the widget is actually above the QGLWidget, but left undrawn (by Qt's normal drawing) using clip masks.
Clipping is slooooo(o...)ow.


This requires the current drawing done in the several QGLWidgets involved to be rewritten for the QGraphicsScene context, which is not insignificant. I am trying to get a good handle on the various avenues available to me to determine where best to put my efforts.
If your OpenGL implementation supports pixel buffers, you can render to a pixel buffer using OpenGL and display the results on graphics items.


I'm not saying our current implementation was the right choice, but we're trying to solve this in a way that minimizes modifications to the existing app's architecture.
Sometimes it's faster to scrap everything and go the right way instead of working around broken code.