Results 1 to 19 of 19

Thread: What is the fastest way to draw a circle ?

  1. #1
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default What is the fastest way to draw a circle ?

    Hello All !

    I'm using QGraphicsView to visualize a huge amount of particles which are basically circles with fixed size (about 14x14px). The particles can have non-integer coordinates so I'm using antialiasing (without it the scene looks just horrible). When the number of particles is around 200 performance becomes very poor. I've tried drawing using two different methods:
    Qt Code:
    1. painter->setPen(Qt::NoPen);
    2. painter->setBrush(Qt::black);
    3. painter->drawEllipse(QRectF(-radius,-radius,radius*2,radius*2));
    To copy to clipboard, switch view to plain text mode 
    and
    Qt Code:
    1. painter->setPen(QPen(Qt::black, radius));
    2. painter->drawPoint(0,0);
    To copy to clipboard, switch view to plain text mode 
    Both gives approx. the same performance. I've also tried drawing in-advance into QPixmap, but then I can't place that pixmap at non-integer position and there is very noticeable jitter when particle moves.

    Are there any suggestions on how to improve drawing performance ? Thanks in advance !

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: What is the fastest way to draw a circle ?

    Could you provide a minimal compilable example reproducing the problem?

  3. #3
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    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:
    1. #include <QtGui>
    2. #include <QtCore>
    3.  
    4. const int N = 1000;
    5. const int S = 500;
    6. const int DT = 10;
    7. const double R = 7;
    8.  
    9. class MyGraphicsItem: public QGraphicsItem
    10. {
    11. public:
    12. MyGraphicsItem(): _vel((double(qrand())/RAND_MAX-0.5)*S/10,(double(qrand())/RAND_MAX-0.5)*S/10),
    13. _rect(-R,-R,2*R,2*R), _color(QColor::fromRgba(qrand())) {
    14. setPos(double(qrand())/RAND_MAX*S,double(qrand())/RAND_MAX*S);
    15. }
    16. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
    17. painter->setRenderHint(QPainter::Antialiasing, true);
    18. painter->setPen(Qt::NoPen);
    19. painter->setBrush(_color);
    20. painter->drawEllipse(_rect);
    21. }
    22. QRectF boundingRect() const { return _rect; }
    23. void step() {
    24. setPos(pos() + _vel*double(DT)/1000);
    25. if(pos().x() < 0 || pos().x() > S) _vel.setX(-_vel.x());
    26. if(pos().y() < 0 || pos().y() > S) _vel.setY(-_vel.y());
    27. }
    28.  
    29. protected:
    30. QPointF _vel;
    31. QRectF _rect;
    32. QColor _color;
    33. };
    34.  
    35. class MyGraphicsScene: public QGraphicsScene
    36. {
    37. public:
    38. MyGraphicsScene(): _startTime(QTime::currentTime()), _framesCount(0) {
    39. for(int i=0; i<N; ++i) addItem(new MyGraphicsItem);
    40. startTimer(0);
    41. }
    42.  
    43. protected:
    44. void timerEvent(QTimerEvent* event) {
    45. foreach(QGraphicsItem* item, items())
    46. static_cast<MyGraphicsItem*>(item)->step();
    47. QApplication::processEvents();
    48. ++_framesCount;
    49. if(_framesCount == 50) {
    50. qDebug() << "FPS:" << double(_framesCount) / _startTime.msecsTo(QTime::currentTime()) * 1000;
    51. _startTime = QTime::currentTime();
    52. _framesCount = 0;
    53. }
    54. }
    55. QTime _startTime;
    56. int _framesCount;
    57. };
    58.  
    59. int main(int argc, char *argv[])
    60. {
    61. QApplication app(argc, argv);
    62.  
    63. MyGraphicsScene scene;
    64. QGraphicsView view(&scene);
    65. view.setOptimizationFlags(QGraphicsView::DontClipPainter);
    66. view.setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
    67. view.resize(S,S);
    68. view.scale(0.95,0.95);
    69.  
    70. view.show();
    71. return app.exec();
    72. }
    To copy to clipboard, switch view to plain text mode 

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: What is the fastest way to draw a circle ?

    The first thing I would try is to use OpenGL viewport instead of a regular one (call setViewport(new QGLWidget)) on the view).

  5. #5
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    With OpenGL I'm getting 17 fps but with worse rendering quality.

  6. #6
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    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

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: What is the fastest way to draw a circle ?

    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.

  8. #8
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by Gopala Krishna View Post
    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.
    Yes, removing it improves performance, but for some strange reason without it MyGraphicsItem:aint() is called only once per two frames !

  9. #9
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    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:
    1. #include <QtGui>
    2. #include <QtCore>
    3.  
    4. const int N = 1000;
    5. const int S = 500;
    6. const int DT = 10;
    7. const double R = 7;
    8.  
    9. class MyGraphicsItem: public QGraphicsItem
    10. {
    11. public:
    12. MyGraphicsItem(): _vel((double(qrand())/RAND_MAX-0.5)*S/10,(double(qrand())/RAND_MAX-0.5)*S/10),
    13. _rect(-R,-R,2*R,2*R), _color(QColor::fromRgba(qrand())) {
    14.  
    15. setPos(double(qrand())/RAND_MAX*S,double(qrand())/RAND_MAX*S);
    16. }
    17. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
    18. painter->setRenderHint(QPainter::Antialiasing, true);
    19. painter->setPen(Qt::NoPen);
    20. painter->setBrush(_color);
    21. painter->drawEllipse(_rect);
    22. }
    23. QRectF boundingRect() const { return _rect; }
    24. void step() {
    25. setPos(pos() + (_vel*double(DT)/1000));
    26. if(pos().x() < 0 || pos().x() > S) _vel.setX(-_vel.x());
    27. if(pos().y() < 0 || pos().y() > S) _vel.setY(-_vel.y());
    28. }
    29.  
    30. protected:
    31. QPointF _vel;
    32. QRectF _rect;
    33. QColor _color;
    34. };
    35.  
    36. class MyGraphicsScene: public QGraphicsScene
    37. {
    38. public:
    39. MyGraphicsScene(): _startTime(QTime::currentTime()), _framesCount(0) {
    40. setItemIndexMethod(NoIndex);
    41. for(int i=0; i<N; ++i) {
    42. MyGraphicsItem *it = new MyGraphicsItem();
    43. addItem(it);
    44. it->setCacheMode(QGraphicsItem::DynamicCache);
    45. }
    46. startTimer(0);
    47. }
    48.  
    49. protected:
    50. void timerEvent(QTimerEvent* event) {
    51. foreach(QGraphicsItem *item, items()) {
    52. static_cast<MyGraphicsItem*>(item)->step();
    53. }
    54.  
    55. QApplication::processEvents();
    56. ++_framesCount;
    57. if(_framesCount == 50) {
    58. qDebug() << "FPS:" << double(_framesCount) / _startTime.msecsTo(QTime::currentTime()) * 1000;
    59. _startTime = QTime::currentTime();
    60. _framesCount = 0;
    61. }
    62. }
    63. QTime _startTime;
    64. int _framesCount;
    65. };
    66.  
    67. int main(int argc, char *argv[])
    68. {
    69. QApplication app(argc, argv);
    70.  
    71. MyGraphicsScene scene;
    72. QGraphicsView view(&scene);
    73. view.setOptimizationFlags(QGraphicsView::DontClipPainter);
    74. view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
    75. view.resize(S,S);
    76.  
    77. view.show();
    78. return app.exec();
    79. }
    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

  10. The following user says thank you to Gopala Krishna for this useful post:

    Vladimir (6th September 2007)

  11. #10
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by wysota View Post
    Try passing QGLFormat(QGL::SampleBuffers) as the first argument to the GLWidget constructor. As far as I remember this should allow antialiasing to work.
    Thanks, it really works !

    Quote Originally Posted by wysota View Post
    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.
    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 ?
    Attached Files Attached Files
    Last edited by Vladimir; 6th September 2007 at 10:20.

  12. #11
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by Gopala Krishna View Post
    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.
    Thanks for the advice ! But when using QPixmap I'm getting very noticeable jitter when particle moves because QPixmap can only be drawn at integer position. Are this problem fixed with the patch you mentioned ?

  13. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by Vladimir View Post
    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 ?
    QGLFormat::hasOpenGL()
    QGLFormat::sampleBuffers()

    Quote Originally Posted by Vladimir View Post
    Thanks for the advice ! But when using QPixmap I'm getting very noticeable jitter when particle moves because QPixmap can only be drawn at integer position. Are this problem fixed with the patch you mentioned ?
    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.

  14. The following user says thank you to wysota for this useful post:

    Vladimir (6th September 2007)

  15. #13
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by Vladimir View Post
    Thanks for the advice ! But when using QPixmap I'm getting very noticeable jitter when particle moves because QPixmap can only be drawn at integer position. Are this problem fixed with the patch you mentioned ?
    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 -
    void QPainter::drawPixmap ( const QRectF & target, const QPixmap & pixmap, const QRectF & source )
    I found this prototype in assistant.

    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

  16. #14
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by Gopala Krishna View Post
    I found this prototype in assistant.
    I've tried this but it still gives the same result.

  17. #15
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by wysota View Post
    QGLFormat::hasOpenGL()
    QGLFormat::sampleBuffers()
    Thanks !

    Quote Originally Posted by wysota View Post
    You can speed up pixmap scaling by tweaking transformation modes from smooth to fast. You can improve quality by doing the opposite thing.
    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.

  18. #16
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: What is the fastest way to draw a circle ?

    Well... you can't draw in the middle of a pixel. If you scale up the painter, the precision should increase.

  19. #17
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by wysota View Post
    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.

  20. #18
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: What is the fastest way to draw a circle ?

    Here is something to play with. Some parts of the code are commented and uncommenting some of them might change the behavior a bit.

    The most important part is the one that makes sure the animation is "lag-undependent" - items will move properly regardless of the number of frames the hardware can handle.
    Attached Files Attached Files

  21. #19
    Join Date
    Jan 2007
    Posts
    45
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: What is the fastest way to draw a circle ?

    Quote Originally Posted by wysota View Post
    Here is something to play with. Some parts of the code are commented and uncommenting some of them might change the behavior a bit.

    The most important part is the one that makes sure the animation is "lag-undependent" - items will move properly regardless of the number of frames the hardware can handle.
    Thanks ! GL version gives 25fps for me. In my case position calculation is more complicated: each frame is calculated in separate thread and calculation sometimes can be long. However frame time is adjustable so I'll try to follow your ideas and adjust it when rendering takes more time than calculations.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.