Qt-interest Archive, March 2008
slow image performance for scaled QGraphicsView
Message 1 in thread
I have a QGraphicsView, which is mostly showing a large bitmap overlayed
with other things.
The bitmap is implemented as a QGraphicsItem which has a special paint
method:
void FitsImgItem::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *)
{
const QRectF &exposedRect = option->exposedRect;
QImage image = convertToQImage( int(exposedRect.left()),
int(exposedRect.right())+1,
int(exposedRect.top()),
int(exposedRect.bottom())+1 );
painter->drawImage( QPoint( int(exposedRect.left()),
int(exposedRect.top()) ),
image );
}
where convertToQImage converts part of a dataset to a QImage for the region
shown.
This works quite nicely, except it is very slow if the QGraphicsView is
scaled (this is X11 on Linux). It is even slow for 2x, 4x, 0.5x, etc...
I have to repaint the window frequently to get colour scaling (the user
interactively modifies the colour table in my data conversion).
The speed isn't helped much by simple scaling, and the exposed coordinates
passed to the function seem okay, so it isn't doing too much drawing.
Am I simply correct that scaled images are horribly slow under X11?
I could do the scaling of the dataset myself, but I can't see a way of
drawing a normal 1:1 image when the QGraphicsView has been scaled.
I suppose I'll have to avoid the framework and do all the hard work myself.
Any ideas?
Thanks
Jeremy
--
[ signature omitted ]
Message 2 in thread
Sorry if it seems a bit of a cop out answer, but have you run a profiler
on the code yet, something like valgrind/callgrind and the like?
May help to pinpoint the areas where your slowdowns are occuring, and if
it's in Qt code, then, definately, let us know, as performance
improvements are always welcomed.
Jeremy Sanders wrote:
> I have a QGraphicsView, which is mostly showing a large bitmap overlayed
> with other things.
>
> The bitmap is implemented as a QGraphicsItem which has a special paint
> method:
>
>
> void FitsImgItem::paint(QPainter *painter,
> const QStyleOptionGraphicsItem *option,
> QWidget *)
> {
> const QRectF &exposedRect = option->exposedRect;
>
> QImage image = convertToQImage( int(exposedRect.left()),
> int(exposedRect.right())+1,
> int(exposedRect.top()),
> int(exposedRect.bottom())+1 );
>
> painter->drawImage( QPoint( int(exposedRect.left()),
> int(exposedRect.top()) ),
> image );
>
> }
>
> where convertToQImage converts part of a dataset to a QImage for the region
> shown.
>
> This works quite nicely, except it is very slow if the QGraphicsView is
> scaled (this is X11 on Linux). It is even slow for 2x, 4x, 0.5x, etc...
> I have to repaint the window frequently to get colour scaling (the user
> interactively modifies the colour table in my data conversion).
>
> The speed isn't helped much by simple scaling, and the exposed coordinates
> passed to the function seem okay, so it isn't doing too much drawing.
>
> Am I simply correct that scaled images are horribly slow under X11?
>
> I could do the scaling of the dataset myself, but I can't see a way of
> drawing a normal 1:1 image when the QGraphicsView has been scaled.
>
> I suppose I'll have to avoid the framework and do all the hard work myself.
>
> Any ideas?
>
> Thanks
>
> Jeremy
>
>
--
[ signature omitted ]
Message 3 in thread
Jeremy Sanders wrote:
> QImage image = convertToQImage( int(exposedRect.left()),
> int(exposedRect.right())+1,
> int(exposedRect.top()),
> int(exposedRect.bottom())+1 );
> painter->drawImage( QPoint( int(exposedRect.left()),
> int(exposedRect.top()) ),
> image );
This code is slow for two reasons. Copying an image is slow because it
allocates and moves large blocks of memory. The speed of drawing an image
using QPainter depends on the platform. On X11 it involves uploading the
image to the X-server (for every call to paint()). With OpenGL, the image
is cached as a texture server-side, so it's slow only the first time. If
the item is scaled and you're not using GL, QPainter does a local image
transform in software before uploading, which makes it slow.
--
[ signature omitted ]
Message 4 in thread
Andreas Aardal Hanssen wrote:
> This code is slow for two reasons. Copying an image is slow because it
> allocates and moves large blocks of memory. The speed of drawing an image
> using QPainter depends on the platform. On X11 it involves uploading the
> image to the X-server (for every call to paint()). With OpenGL, the image
> is cached as a texture server-side, so it's slow only the first time. If
> the item is scaled and you're not using GL, QPainter does a local image
> transform in software before uploading, which makes it slow.
Thanks, however the code is pretty fast when there is no scaling. Also,
QImage "uses implicit data sharing", so I don't think I'm doing any extra
copying here in my code (though of course a new QImage is created each time
with a different size).
Scaling an image without interpolation or arbitrary rotation should be
trivial and fast, so I presume Qt is using a rather poor scaling algorithm.
Is there a way to quickly draw a pixmap/image in a QGraphicsView, when it is
being computed on the fly from other data? Other X11 programs can quickly
update the screen with new bitmaps (movie players, flash, etc...), so Qt
should be able to (though it is difficult in a general framework like
QGraphicsView, I suppose).
Jeremy
--
[ signature omitted ]
Message 5 in thread
Jeremy Sanders wrote:
> Thanks, however the code is pretty fast when there is no scaling. Also,
> QImage "uses implicit data sharing", so I don't think I'm doing any extra
> copying here in my code (though of course a new QImage is created each
> time with a different size).
Well if you create a new image, and copy out a subsection, then implicit
sharing has no effect on you; you'll be allocating data and copying all the
memory over. If you run a profiler (e.g., valgrind/callgrind &
kcachegrind), might quickly see that those lines are quite expensive :-).
> Scaling an image without interpolation or arbitrary rotation should be
> trivial and fast, so I presume Qt is using a rather poor scaling
> algorithm.
It's not Qt, it's X11. Qt's scaling algorithm is also used on Windows. If
you try your app on Windows, it's likely to fly :-).
> Is there a way to quickly draw a pixmap/image in a QGraphicsView, when it
> is being computed on the fly from other data? Other X11 programs can
You should use OpenGL; constructing QGLWidget solves this problem for
you. :-)
> quickly update the screen with new bitmaps (movie players, flash, etc...),
> so Qt should be able to (though it is difficult in a general framework
> like QGraphicsView, I suppose).
If you try to run a scaled flash application on X11 (larger than a simple
banner), with rotating or scaled pixmaps, it's really just as slow. Movie
players get help with the scaling from the drivers. Generally speaking, X11
is no good for scaled vector graphics, especially pixmaps. But OpenGL is
available all over the scale now, and it usually solves this problem. :-)
--
[ signature omitted ]
Message 6 in thread
Andreas Aardal Hanssen wrote:
> Jeremy Sanders wrote:
>> Thanks, however the code is pretty fast when there is no scaling. Also,
>> QImage "uses implicit data sharing", so I don't think I'm doing any extra
>> copying here in my code (though of course a new QImage is created each
>> time with a different size).
>
> Well if you create a new image, and copy out a subsection, then implicit
> sharing has no effect on you; you'll be allocating data and copying all
> the memory over. If you run a profiler (e.g., valgrind/callgrind &
> kcachegrind), might quickly see that those lines are quite expensive :-).
It's a big win in this case I'm applying scaling to scientific data. It's
easier to do the value -> colour transformation in real time for the bit
which is being viewed, rather than the whole 6700x7000 image. It's pretty
fast for unscaled data.
>> Scaling an image without interpolation or arbitrary rotation should be
>> trivial and fast, so I presume Qt is using a rather poor scaling
>> algorithm.
>
> It's not Qt, it's X11. Qt's scaling algorithm is also used on Windows. If
> you try your app on Windows, it's likely to fly :-).
Oh well. I suppose Qt could do the scaling itself before sending it to X11,
but that's extra work for it. It's a shame my program can't scale the
pixmap itself. Maybe I could undo the scale in the QPainter, draw the
scaled pixmap, then put it back to how it was...
>> Is there a way to quickly draw a pixmap/image in a QGraphicsView, when it
>> is being computed on the fly from other data? Other X11 programs can
>
> You should use OpenGL; constructing QGLWidget solves this problem for
> you. :-)
Maybe this is the best solution. I'd better check whether my X11 drivers do
OpenGL properly on my development computer!
Thanks
Jeremy
--
[ signature omitted ]
Message 7 in thread
>>
>> You should use OpenGL; constructing QGLWidget solves this problem for
>> you. :-)
>
>Maybe this is the best solution. I'd better check whether my X11 drivers do
>OpenGL properly on my development computer!
If you do scale QImage yourself, Please never use OpenGL!
It will make the same copying situation.
When I did scale QImage with my code and display with OpenGL,it was slower
than without OpenGL.
If you are familiar with OpenGL,
I recommend you using OpenGL native methods for scaling and color mapping.
Sam.
--
[ signature omitted ]