Could you provide a minimal compilable example reproducing the problem?
Could you provide a minimal compilable example reproducing the problem?
Yes, I've prepared an example. Running it on my (not very old) PC I'm getting around 10 FPS. Are there any suggestions how to improve performance ?
Qt Code:
#include <QtGui> #include <QtCore> const int N = 1000; const int S = 500; const int DT = 10; const double R = 7; { public: MyGraphicsItem(): _vel((double(qrand())/RAND_MAX-0.5)*S/10,(double(qrand())/RAND_MAX-0.5)*S/10), setPos(double(qrand())/RAND_MAX*S,double(qrand())/RAND_MAX*S); } painter->setPen(Qt::NoPen); painter->setBrush(_color); painter->drawEllipse(_rect); } void step() { setPos(pos() + _vel*double(DT)/1000); if(pos().x() < 0 || pos().x() > S) _vel.setX(-_vel.x()); if(pos().y() < 0 || pos().y() > S) _vel.setY(-_vel.y()); } protected: QPointF _vel; QRectF _rect; QColor _color; }; { public: for(int i=0; i<N; ++i) addItem(new MyGraphicsItem); startTimer(0); } protected: static_cast<MyGraphicsItem*>(item)->step(); ++_framesCount; if(_framesCount == 50) { _framesCount = 0; } } QTime _startTime; int _framesCount; }; int main(int argc, char *argv[]) { MyGraphicsScene scene; view.resize(S,S); view.scale(0.95,0.95); view.show(); return app.exec(); }To copy to clipboard, switch view to plain text mode
The first thing I would try is to use OpenGL viewport instead of a regular one (call setViewport(new QGLWidget)) on the view).
With OpenGL I'm getting 17 fps but with worse rendering quality.
Removing QApplication:: processEvents improved FPS by 10 on mys system. I don't think you need to call that since you are not using an infinite loop.
The biggest difference between time and space is that you can't reuse time.
-- Merrick Furst
I guess Wysota is correct in recommending item caching in pixmap. Actually i tried andreas's new item caching patch with your program and with some modifications to your program i could get ~30 FPS. With processEvents i could get ~20FPS.
Here are the changes i made
- Firstly i applied the patch specified
- Changed update mode to FullViewportMode
- Removed scaling
- Enabled item's dynamic cache(available only through patch)
Qt Code:
#include <QtGui> #include <QtCore> const int N = 1000; const int S = 500; const int DT = 10; const double R = 7; { public: MyGraphicsItem(): _vel((double(qrand())/RAND_MAX-0.5)*S/10,(double(qrand())/RAND_MAX-0.5)*S/10), setPos(double(qrand())/RAND_MAX*S,double(qrand())/RAND_MAX*S); } painter->setPen(Qt::NoPen); painter->setBrush(_color); painter->drawEllipse(_rect); } void step() { setPos(pos() + (_vel*double(DT)/1000)); if(pos().x() < 0 || pos().x() > S) _vel.setX(-_vel.x()); if(pos().y() < 0 || pos().y() > S) _vel.setY(-_vel.y()); } protected: QPointF _vel; QRectF _rect; QColor _color; }; { public: setItemIndexMethod(NoIndex); for(int i=0; i<N; ++i) { MyGraphicsItem *it = new MyGraphicsItem(); addItem(it); } startTimer(0); } protected: static_cast<MyGraphicsItem*>(item)->step(); } ++_framesCount; if(_framesCount == 50) { _framesCount = 0; } } QTime _startTime; int _framesCount; }; int main(int argc, char *argv[]) { MyGraphicsScene scene; view.resize(S,S); view.show(); return app.exec(); }To copy to clipboard, switch view to plain text mode
EDIT: Forgot to inform you about my hardware. I have descent hardware with 1 GB ram, 3 GHz processor and an ATI Radeon XPress 200m card.
The biggest difference between time and space is that you can't reuse time.
-- Merrick Furst
Vladimir (6th September 2007)
QGLFormat::hasOpenGL()
QGLFormat::sampleBuffers()
You can speed up pixmap scaling by tweaking transformation modes from smooth to fast. You can improve quality by doing the opposite thing. You'll always have aliasing when using pixmaps, because they are pixel based (using smooth transform mode will reduce the effect). But if you use GL pixel buffers and render the circle to texture, you should avoid any artifacts at all. Should be very simple in your case.
Vladimir (6th September 2007)
Thanks !
I still can't figure out how to do it. I can draw into QPixmap with antialiasing but the problem is that when I'm calling QPainter::drawPixmap (even without any transformations) the pixmap is always painted starting from some pixel on the screen, for example when position of the item is (15.4,19.7) it will still be drawn at position (15,20). When items are slowly moving it gives the impression that the movement is shaky.
Well... you can't draw in the middle of a pixel. If you scale up the painter, the precision should increase.
I could suppose that QT can resample my pixmap using algorithm similar to one using for resizing...
Anyway, for now I've decided to use OpenGL which should be available in 90% cases with fallback to slow software rendering in other cases. On old machines without OpenGL even QPixmap approach can be too slow so I'll probably provide advances options to draw particles as points instead of circles.
By jitter you mean shaky movement right ? I did get them when using the caching mechanism. But anyway I think pixmap can be drawn in real positions too -
I found this prototype in assistant.void QPainter::drawPixmap ( const QRectF & target, const QPixmap & pixmap, const QRectF & source )
With both caching and gl i could get 20 FPS. (your card is better than mine)
The biggest difference between time and space is that you can't reuse time.
-- Merrick Furst
Try passing QGLFormat(QGL::SampleBuffers) as the first argument to the GLWidget constructor. As far as I remember this should allow antialiasing to work. Also get rid of the scene scaling and change the timer interval from 0 to 50 and see if you can achieve 20fps with it. I seem to have worse hardware than you but I managed to go up to 15fps with it. You could also use the pixel buffer of your graphics card to render the circles. Hopefully it would be faster this way, but you'd probably have to reimplement your paint method to use GL calls (I'm not sure of that though). See the pixel buffer example for details. Maybe you could use a single texture that contains a cirle and just render it differently.
Another thing to try is to render each circle into a pixmap and use drawPixmap() to render the item instead of drawing the ellipse each time.
Thanks, it really works !
I've tried different combinations of it and here is my results:
using drawPixmap (but this gives jitter!):
without GL, without scaling: 25 fps
without GL, scaling: 4 fps (in all other cases scaling does not changes anything)
with GL: 18 fps
using drawEllipse:
without GL: 11 fps
with GL: 17 fps
using drawPoint and big pen:
without GL, without scaling: 9 fps
without GL, without scaling: 7 fps
with GL, without scaling: 13 fps
with GL, with scaling: 12 fps
using drawRect (which is not what I want):
without GL: 15 fps
with GL: 25 fps
EDIT: My hardware is Athlon X2 3800+, 1GB ram, GeForce FX 5500. The code I've used in this benchmark is in the attached file.
So I'll probably stick with using GL. But what if user has not OpenGL (I've tried to run my program in Xephyr and got just error messages). Are there any ways to check it at runtime ?
Last edited by Vladimir; 6th September 2007 at 10:20.
Bookmarks