Optimizing Qt 4 Graphics View

来源:互联网 发布:男士保湿面霜推荐 知乎 编辑:程序博客网 时间:2024/05/17 06:39

During the summer I worked a lot with one of the latest addition to the Qt framework,the graphics view. The graphics view is basically a canvas to draw2D-graphics, and replaced the QCanvas class from Qt 3.x. It was addedto Qt in version 4.2.

The application I worked on is used for displaying a sea map alongwith various other maritime related information (and a lot of otherstuff that’s not really relevant). While the application functioned theway it was, we wanted to replace our old (somewhat hackish) way ofrepresenting the parts of the program as CSS-themed top-level widgetsand using a embedded graphics view to represent the entire UI of theapplication. This approach would give us a better ability to integratethe various parts of the application, as well as support transitionsbetween various view states of the program (and other nifty graphicseffects). With the recent addition of QGraphicsProxyWidget in Qt 4.4this was finally an option, so we decided to give it a shot.

During the initial porting of the application, we did not noticemuch in the way of performance loss, but as soon as we added more (andlarger) dynamical elements to the GUI, it started slowing down. Thisled me to investigate why the application was slowing down, and how toremedy the situation. The reason why is pretty simple: in order for Qtto draw widgets inside the graphics view, it apparently has to renderthem twice. Qt will first render the widget to an off-screen buffer,and then render the content of the off-screen buffer to the graphicsscene as a texture. As soon as we knew why, we started looking at howto optimize it.

Accelerating the Scene:

Qt allows you to use OpenGL to accelerate the scene. This cangreatly increase the performance, assuming the graphics card in yourcomputer has decent support for hardware accelerating 2D operations(this is not the case for nVidia today). To enable OpenGL acceleration,you will have to create a QGLWidget and tell the graphics scene to useit as a viewport.  Here’s an example:

QGLWidget* viewport = new QGLWidget(QGLFormat(QGL::DoubleBuffer | QGL::Rgba |
QGL::AlphaChannel | QGL::DirectRendering | QGL::SampleBuffers));
myGraphicsScene->setViewport(viewport);


Item Cache:

The graphics view allows you to independently set the cache mode for each item in the scene.  Setting the cache mode to QGraphicsItem::DeviceCoordinateCachewill make Qt use the cached version of a item instead of redrawing theitem (twice) every time the scene is updated. This sort of cache willnot work if you need to transform (rotate, scale, shear, etc.) theitem. If you need transformation you should have a look at the QGraphicsItem::ItemCoordinateCache cache mode.

Increasing the Pixmap Cache Size:

While caching the items works good when you’ve got a small amount ofsmall objects, I soon figured out that when adding larger items, orjust a lot of small ones, the drawing becomes slow again. It took mesome time, but I finally figured out why. When you tell Qt to use cachefor graphics items, it uses its internal QPixmapCache as a buffer forthe items. This is not explicitly mentioned in the documentation, onlya hint is given in the “See also”-section of the documentation. Thedefault size for this cache is 1024kb, which explainswhy it gets slower the more items you add. Increasing the cache size isimperative if your application will use a lot of objects and you wantcache. You can achieve this by calling the static function QPixmapCache::setCacheLimit(int), just keep in mind it takes kilobytes as the argument.

Other tricks:

While these tricks are the ones that gave the greatest increase inperformance (a dogmatic conclusion, no real benchmarks where made) inour application, there are several other functions you might wantto  look at:

QGraphicsView::setOptimizationFlag
QGraphicsView::setViewportUpdateMode
QGraphicsScene::setItemIndexMethod

These functions may give an increase in performance, depending on the nature of the application.