Thursday, February 10, 2011

QGraphicsView performance

Few days ago I realized the game was having a horrible performance when I added a background. It started to be slower and slower until it was impossible to be at all.

I started changing  the image. Less resolution, less colors, less quality... but it wasn't enough. Actually, it seemed like I did nothing. And when I tried to use the cache it went even worse...

So, I started to read, read and read about QGraphicsView performance and right now is going as expected. Actually, it´s going even better.

So, how to improve QGraphicsView's performance?

This video should be the starting point. Actually, most of the things I found on the web are already said.

So, what to do?

First of all: use the raster. OpenGL graphic system is still experimental so it's quite slow. The "normal" option is quite slow... use raster instead.
To do it, you just need to call the static function QApplication::setGraphicsSystem("raster") before the QApplication constructor is called. Basically, at the beginning of the main.

If you mix that with an openGL object taking care of the render you will have all the major improvements. Note Symbian^3 does this by default. On the other hand OviStore is still not compatible with Qt4.7.1, and that's te first version when they add the openGL files.
How to do it? don't forget to add opengl to your pro file (QT += core gui opengl) and:

        ui.m_pView->setViewport(new QGLWidget());

I think you can setup a proper QGLWidget, depending your needs... but  it's pretty ok. 
Those are the major issues, but there are still more minor improvements:
 - Use the proper viewportUpdateMode. It's better if you test, test, test, test and test it again. In my opinion
fullviewportUpdateMode works better in most cases when we are talking about videogames. The device won't
be trying to guess what to paint, what he shouldn't paint and you will surely have some animations on screen (in
the end it was going to paint almost everything, so "stop calculating and draw it all!").
 - DON'T USE UPDATES IN YOUR GAME LOOP: actually, if you can, don't use updates. It
schedules a redraw, what means he will think twice what to draw. And he will paint on screen when he's in 
the mood. Let Qt paint whenever he wants to.
- Flag "dontsavepainterstate". If we are not using brush-pens... we don't care if the painter is reset each
time Qt paints.
- setframestyle(0): less to paint.
- setAttribute(Qt::WA_TranslucentBackground, false): seems like it was activated by default.
- Choose the best setItemIndexMethod for your scene (test, test, test, test). You don't like to have a BSP
tree if you don't need it.
-  itemhasnocontents: if you want an invisble item, this is the best choice. In my case, this means all my 
bounding items, which means 95% of the items on the screen won't try to calculate how to be drawn.
- itemcoordinatecache: the item will be store in cache and the paint event won't be called again if you don't
force it (another good reason: don't call an update). In my case, the backgrounds are set as
QGraphicsPixmapItem... it takes 5 msecs to be drawn. Storing it on cache improves the performance.
That's all!