PDA

View Full Version : OGLWidget + setPixel = slow



JimJey
9th April 2008, 06:10
I'm writing a raytracing application that should display the image being synthesized to the user. Currently I was taking this approach (QGraphicsView and QGraphicsScene are used to present the image):
1) Construct QImage to hold the image data
2) Periodically update QImage using setPixel
3) Convert the QImage to QPixmap and call
QGraphicsPixmapItem.setPixmap to reflect the changes in the QGraphicsScene

First I wasn't specifying any special viewport. Updates on the QImage were performed quite quickly, however zooming proved to be laggy.
Then I switched the viewport to an OGLWidget. Zooming became very smooth, but updating the QImage takes about seconds now!

I can't really imagine how setting a different viewport affects the performance of the setPixel operation (diving into the source code of QImage also didn't clarify the issue).

Is the way I am using QImage/QGraphicsView/QGraphicsScene the recommended way? Why becomes setting pixels so slow whenever I change the viewport to OpenGL?
Any solutions?

Thank you very much.

JimJey
9th April 2008, 20:08
After looking into the Qt source code more carefully and debugging the application I found the following:
Everytime setPixel is called, detach is also called. Detach looks like the following:


void QImage::detach()
{
if (d) {
if (qt_image_cleanup_hook_64 && d->ref == 1)
qt_image_cleanup_hook_64(cacheKey());

if (d->ref != 1 || d->ro_data)
*this = copy();
++d->detach_no;
}
}


The important part here is "qt_image_cleanup_hook_64". This global (!) function pointer is initialized to qt_gl_image_cleanup only by the OpenGL module (so when rendering normally, the following functions won't be called).
qt_gl_image_cleanup might then call qt_gl_clean_cache which also does some processing.
You see, it adds a lot of overhead to the simple setPixel operation (and therefore reduces the performance). To conclude it's necessary to manipulate the bits directly in order to avoid the performance hit (just call QImage::bits() once for each image update)