Page 1 of 2 12 LastLast
Results 1 to 20 of 22

Thread: Drawing lines in QPainter takes a lot of time

  1. #1
    Join Date
    Mar 2016
    Posts
    14
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Drawing lines in QPainter takes a lot of time

    Hi,

    I currently have a problem with line drawing in QPainter. I draw "only" simple 2000 lines but it takes something like 50ms for each update. My problem is all the lines continuously move to draw a nice slowly rotating graph (note : it's not just a rotate()).
    To check I run the following code only :
    Qt Code:
    1. void Widget::paintEvent(QPaintEvent *event)
    2. {
    3. QElapsedTimer chronoPainter;
    4.  
    5. QPainter myPainter(this);
    6. const int cst_nbLines = 5000;
    7.  
    8. chronoPainter.start();
    9. for (int i=0 ; i<cst_nbLines ; i++)
    10. {
    11. QLine myLine(i/10, i/10, i/10+300, i/10);
    12. myPainter.drawLine(myLine);
    13. }
    14. qint64 elapsed_ns = chronoPainter.nsecsElapsed();
    15. qint64 elapsed_ms = elapsed_ns/1000000L;
    16.  
    17. qDebug() << "End, time to paint : " << elapsed_ms << "ms";
    18. }
    To copy to clipboard, switch view to plain text mode 

    And drawing my 2000 very simple lines takes... 50ms. Not way to have a 50FPS animation with that. Have you got an idea of how I can draw all the lines faster?
    I've tried with
    Qt Code:
    1. QVector<QLine> linesVector;
    2. for (int i=0 ; i<cst_nbLines ; i++)
    3. {
    4. linesVector.append(QLine(i/10, i/10, i/10+300, i/10));
    5. }
    6. myPainter.drawLines(linesVector);
    To copy to clipboard, switch view to plain text mode 
    but it not helps (same drawing time).

    Thank you!
    Last edited by xcxl; 4th June 2019 at 13:55.

  2. #2
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Did you know that in your example, you draw every line 10 times?

  3. #3
    Join Date
    Mar 2016
    Posts
    14
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Quote Originally Posted by Lesiok View Post
    Did you know that in your example, you draw every line 10 times?
    Hummm no I didn't know... I just add a counter (counter+=1 just after the drawLine()), and I really have 5000 iterations. Could you explain why you said I draw it 10 times please?

  4. #4
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Because i is integer for i in <0,9> i/10 == 0.

  5. #5
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Quote Originally Posted by xcxl View Post
    Qt Code:
    1. QVector<QLine> linesVector;
    2. for (int i=0 ; i<cst_nbLines ; i++)
    3. {
    4. linesVector.append(QLine(i/10, i/10, i/10+300, i/10));
    5. }
    6. myPainter.drawLines(linesVector);
    To copy to clipboard, switch view to plain text mode 
    Likely not directly responsible, but call QVector::reserve() before that loop.
    Otherwise you could get 5000 memory realliocations.

    Cheers.
    _

  6. #6
    Join Date
    Jan 2006
    Location
    Bremen, Germany
    Posts
    554
    Thanked 86 Times in 81 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Quote Originally Posted by anda_skoa View Post
    Otherwise you could get 5000 memory realliocations.
    Not 5000 but also not only 1.

  7. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    If you do not need to change the graphics with every paint event, then use a QPainterPath as a member variable of the Widget class. During the paintEvent(), all you need to do is call QPainter::drawPath(). When the graphics need to be changed, re-create the content of the QPainterPath and then call QWidget::update() if needed. For even faster performance, draw to an offscreen QImage and use QPainter::drawImage() in the paint event.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  8. #8
    Join Date
    Mar 2016
    Posts
    14
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Hi everybody, thanks for the answers!

    Quote Originally Posted by Lesiok
    Because i is integer for i in <0,9> i/10 == 0.
    Sorry, I didn't understand your sentence. You said I draw every lines 10 times with the same coordinates, and I understood "the loop run 10x cst_nbLines".

    Quote Originally Posted by d_stranz View Post
    If you do not need to change the graphics with every paint event, then use a QPainterPath as a member variable of the Widget class. During the paintEvent(), all you need to do is call QPainter::drawPath(). When the graphics need to be changed, re-create the content of the QPainterPath and then call QWidget::update() if needed. For even faster performance, draw to an offscreen QImage and use QPainter::drawImage() in the paint event.
    I tried each methods (code below for any other visitors), the results are (for 5000 lines) :

    - With all myPainter.drawLine(myLine) => 17ms
    - With myPainter.drawLines(linesVector) and a reserve() => 17ms
    - With myPainter.drawPath() => 17 ms, it looks like this fct draw every lines as before...
    - With myPainter.drawImage() => <1ms for drawing the pixmap. Very fast but if a do an animation with a move of each points at each frame, it takes between 30-40ms to generate the QImage

    So nothing under 17ms to draw my 5000 moving lines. I don't know why it takes so long, drawing 5000 simple points takes 1-2ms. Would it be faster to draw with OpenGL directly? 5k lines is nothing compared with complex 3D models...

    The code :
    Qt Code:
    1. const int cst_nbLines = 5000;
    2.  
    3. // TEST1
    4. for (int i=0 ; i<cst_nbLines ; i++)
    5. {
    6. QLine myLine(i/10, i/10, i/10+300, i/10);
    7. myPainter.drawLine(myLine);
    8.  
    9. }
    10.  
    11. // TEST2
    12. QVector<QLineF> linesVector;
    13. linesVector.reserve(cst_nbLines);
    14. for (int i=0 ; i<cst_nbLines ; i++)
    15. {
    16. //linesVector.append(QLine(i/10, i/10, i/10+300, i/10));
    17. linesVector.append(QLineF(i/10, i/10, i/10+300, i/10));
    18. counter++;
    19. }
    20. myPainter.drawLines(linesVector);
    21.  
    22. // TEST3
    23. myPainter.drawPath(myPath);
    24.  
    25. // TEST4
    26. generateQImage();
    27. myPainter.drawImage(QPoint(0,0), *myImage);
    To copy to clipboard, switch view to plain text mode 

  9. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    The code :
    Where does this code live? In the paintEvent()? The creation of the QPainterPath and QImage for tests 3 and 4 should occur outside the paintEvent.

    OpenGL would probably be faster, but you probably know that in modern OpenGL you don't do any active drawing - you create the equivalent of a scene that the rendering pipeline and shaders process to put on screen. So your programming model will be similar to that used in the Qt Graphics / View architecture.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  10. #10
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Maybe I repeat myself but... This is the original code :
    Qt Code:
    1. const int cst_nbLines = 5000;
    2.  
    3. for (int i=0 ; i<cst_nbLines ; i++)
    4. {
    5. QLine myLine(i/10, i/10, i/10+300, i/10);
    6. myPainter.drawLine(myLine);
    7. }
    To copy to clipboard, switch view to plain text mode 
    This is the code giving the same final result but 10 times faster :
    Qt Code:
    1. const int cst_nbLines = 5000;
    2.  
    3. for (int i=0 ; i<cst_nbLines/10 ; i++)
    4. {
    5. QLine myLine(i, i, i+300, i);
    6. myPainter.drawLine(myLine);
    7. }
    To copy to clipboard, switch view to plain text mode 

  11. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    This is the code giving the same final result but 10 times faster :
    I think the OP understands he is drawing the same line 10 times. He misunderstood your original comment (as I did when I first read it) to say that he was executing the loop 10 times (to give 50k lines). His point is that even if these were 5000 individual lines with different coordinates, the time it takes to draw all of them is too long, no matter what method he uses.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  12. #12
    Join Date
    Mar 2016
    Posts
    14
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Quote Originally Posted by d_stranz View Post
    Where does this code live? In the paintEvent()? The creation of the QPainterPath and QImage for tests 3 and 4 should occur outside the paintEvent.

    OpenGL would probably be faster, but you probably know that in modern OpenGL you don't do any active drawing - you create the equivalent of a scene that the rendering pipeline and shaders process to put on screen. So your programming model will be similar to that used in the Qt Graphics / View architecture.
    Yes this code is in the paintEvent (only one test at a time of course), and the creation of the QPainterPath and QImage is in the QWidget constructor. I understand the problem with OpenGL. It is just that drawing 5000 lines doesn't look a lot to me, but it may be normal for it to take 10-20ms. I thought I was doing something wrong. Maybe the best way for me to draw very fast is to modify each pixel one by one by myself on a QPixmap.

    Quote Originally Posted by Lesiok
    This is the code giving the same final result but 10 times faster
    Yes I understand Lesiok but the goal of this example is to draw 5000 lines, in a full window (to avoid partial drawing) without scaling anything to be sure to have default parameters.
    Of course the code could be :

    Qt Code:
    1. for (int i=0 ; i<cst_nbLines ; i++)
    2. {
    3. linesVector.append(QLineF(double(i)/10.0, double(i)/10.0, double(i)/10.0+100.0, double(i)/10.0));
    4. }
    To copy to clipboard, switch view to plain text mode 
    It gives me the same time to draw, but looks less clear to me for a basic example.

  13. #13
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    OK, it's clear.

  14. #14
    Join Date
    Mar 2016
    Posts
    14
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    For later visitors, I found on internet some algorithms probably faster to draw all my lines pixels by pixels on a QImage.
    I will try the Bresenham's line algorithm and see.

  15. #15
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    I am pretty sure that is what the Qt Raster backend is using or an even more advanced algorithm.

    And the raster backend uses lots of CPU extension (e.g. SSE5) were possible.

    Cheers,
    _

  16. #16
    Join Date
    Mar 2016
    Posts
    14
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Quote Originally Posted by anda_skoa View Post
    I am pretty sure that is what the Qt Raster backend is using or an even more advanced algorithm.

    And the raster backend uses lots of CPU extension (e.g. SSE5) were possible.

    Cheers,
    _
    Hi anda_skoa, just for "fun" I tried to implement my own fast line drawing algorithm, with the hope that I can do better knowing at the start the size of line, color, etc.
    But you were right, I draw everything in 40ms instead of 50ms, which is a bit better but not really different. I think I will just keep the Qt code for drawing all the lines and do with a "low FPS".

    I let my code here for future visitors :
    Qt Code:
    1. void RenderGraphThread::testFctFastLineDrawingAlgorithm(QImage &r_image, int32_t x1, int32_t y1, int32_t x2, int32_t y2)
    2. {
    3. int x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
    4. dx=x2-x1;
    5. dy=y2-y1;
    6. dx1=std::abs(dx);
    7. dy1=std::abs(dy);
    8. px=2*dy1-dx1;
    9. py=2*dx1-dy1;
    10. if(dy1<=dx1)
    11. {
    12. if(dx>=0)
    13. {
    14. x=x1;
    15. y=y1;
    16. xe=x2;
    17. }
    18. else
    19. {
    20. x=x2;
    21. y=y2;
    22. xe=x1;
    23. }
    24. testFctPutPixelOnImage(r_image,x,y, 0xFF0B9F8A); // green
    25. for(i=0;x<xe;i++)
    26. {
    27. x=x+1;
    28. if(px<0)
    29. {
    30. px=px+2*dy1;
    31. }
    32. else
    33. {
    34. if((dx<0 && dy<0) || (dx>0 && dy>0))
    35. {
    36. y=y+1;
    37. }
    38. else
    39. {
    40. y=y-1;
    41. }
    42. px=px+2*(dy1-dx1);
    43. }
    44. testFctPutPixelOnImage(r_image,x,y, 0xFF0B9F8A); // green
    45. }
    46. }
    47. else
    48. {
    49. if(dy>=0)
    50. {
    51. x=x1;
    52. y=y1;
    53. ye=y2;
    54. }
    55. else
    56. {
    57. x=x2;
    58. y=y2;
    59. ye=y1;
    60. }
    61. testFctPutPixelOnImage(r_image,x,y, 0xFF0B9F8A); // green
    62. for(i=0;y<ye;i++)
    63. {
    64. y=y+1;
    65. if(py<=0)
    66. {
    67. py=py+2*dx1;
    68. }
    69. else
    70. {
    71. if ((dx<0 && dy<0) || (dx>0 && dy>0))
    72. {
    73. x=x+1;
    74. }
    75. else
    76. {
    77. x=x-1;
    78. }
    79. py=py+2*(dx1-dy1);
    80. }
    81. testFctPutPixelOnImage(r_image,x,y, 0xFF0B9F8A); // green
    82. }
    83. }
    84. }
    85.  
    86. // TEST CODE FOR FAST DRAWING LINES
    87. void RenderGraphThread::testFctPutPixelOnImage(QImage &r_image, const int32_t x, const int32_t y, const uint32_t _color)
    88. {
    89. if (y<r_image.height() && x<r_image.width() && x>=0 && y>=0)
    90. {
    91. uchar *pFirstLine = r_image.bits();
    92. int32_t depth = 4;
    93. QRgb* rgbpixel = reinterpret_cast<QRgb*>(pFirstLine + r_image.width()*depth*y + x*depth);
    94. *rgbpixel = _color;
    95. }
    96. }
    To copy to clipboard, switch view to plain text mode 

  17. #17
    Join Date
    Mar 2016
    Posts
    14
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Hi everybody,

    3 years after, I come back to give my benchmark results, and my answer to my own problem. I hope it will give to the next dev some ideas.

    A small synthesis of my initial problem : I have to draw 5000 moving lines on the screen, with an update of line size at each frame (to perform a "moving network animation").

    I tried 6 ways to draw a lot of lines (10 000 to 50 000 lines) on screen to find the lowest cost for CPU/GPU. Here are the results :

    TEST1 - Direct painting with QPainter.drawline() :
    => 8.8 FPS for 25 000 lines
    => 20.0 FPS for 10 000 lines
    Note : a bit laggy for a nice animation

    TEST2 - Direct painting with QPainter.drawlines(), so calculation and then draw all at once :
    => 9.0 FPS for 25 000 lines
    => 21.0 FPS for 10 000 lines

    TEST3 - Draw everything on a QImage and then copy the image to screen
    => 8.5 FPS for 25 000 lines
    => 19.7 FPS for 10 000 lines

    TEST4 - Use a QScene to create all the line items, then just move them a each paintEvent()
    => 0.5 FPS for 2 000 lines
    => 4.9 FPS for 1 000 lines
    Remark : a lot worse

    TEST 5 - Using a QOpenGLWidget, and draw all lines with a GLSL fragment shader
    => 5.0 FPS for 2 000 lines
    => 10.0 FPS for 1 000 lines
    Remark : no so good, fragment shader are apparently not made for big a big loop

    TEST 6 - Using a QOpenGLWidget, and draw all lines with a very simple GLSL vertex & fragment shader (based on HelloGL2 example), updating coordinates of each lines in a QOpenGLBuffer (=Uniform Buffer Object in GLSL terms)
    => 40.0 FPS, GPU 32% for 5 000 lines
    => 35.0 FPS, GPU 37% for 10 000 lines
    => 35.0 FPS, GPU 62% for 25 000 lines
    => 30.0 FPS, GPU 90% for 50 000 lines
    Note1 : the Uniform Buffer allows me to draw more than 4096 lines, the limit on my GPU for uniform fixed arrays. It was my first try and fail with glsl.
    Note2 : CPU is less than 20% for all this TEST6.

    This last TEST6 offered me enough performance (even on a small intel GPU HDRaphics 520), so I will stop there and use this method now.


    Have a good day.

  18. The following 2 users say thank you to xcxl for this useful post:

    Cruz (15th February 2022), d_stranz (18th January 2022)

  19. #18
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Thanks for coming back to update your post!

    TEST 6 - Using a QOpenGLWidget, and draw all lines with a very simple GLSL vertex & fragment shader
    These results makes sense since most of the work is being done on the GPU, which is optimized for just this kind of thing. Glad you could get the performance you needed.
    Last edited by d_stranz; 18th January 2022 at 21:29.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  20. #19
    Join Date
    Nov 2006
    Location
    Dresden, Germany
    Posts
    108
    Thanks
    9
    Thanked 12 Times in 10 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    Thanks for the insight: quick question, could you share the code piece where you update/transfer the buffer to the GPU? This might be another bottleneck on modern hardware architectures.

    For example, you can use the classical:
    Qt Code:
    1. m_vertexBufferObject.bind();
    2. m_vertexBufferObject.allocate(m_vertexBufferData.data(), m_vertexBufferData.size()*sizeof(Vertex));
    3. m_vertexBufferObject.release();
    To copy to clipboard, switch view to plain text mode 

    where the memory for the buffer is newly allocated. Or you could map the GPU memory to CPU memory like:

    Qt Code:
    1. auto ptr = m_colorBufferObject.mapRange(0, m_colorBufferData.size() * sizeof(ColorRGBA),
    2. QOpenGLBuffer::RangeInvalidateBuffer | QOpenGLBuffer::RangeWrite);
    3. std::memcpy(ptr, m_colorBufferData.data(), m_colorBufferData.size()*sizeof(ColorRGBA));
    4. m_colorBufferObject.unmap();
    To copy to clipboard, switch view to plain text mode 

    I'd be interested to know how that affects performence.

    -Andreas
    Andreas

  21. #20
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing lines in QPainter takes a lot of time

    could you share the code piece where you update/transfer the buffer to the GPU?
    Oops, sorry if I gave the impression that I have code that does this - from my reading of the OpenGL pipeline I have learned that once you get all of the data transferred to the GPU, and the shaders set up, the GPU pretty much takes over. It is optimized to do computations in parallel, so you can get huge speedups over doing things point by point or line by line in the CPU.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. Drawing Lines In Real Time (PyQt)
    By n3ziy in forum Qt Programming
    Replies: 1
    Last Post: 24th April 2016, 20:09
  2. drawing lines on a canvas and move them dynamically
    By smrati.johri in forum Newbie
    Replies: 4
    Last Post: 7th April 2016, 23:35
  3. Drawing lines on qwtpolarplot
    By jerrychan in forum Qwt
    Replies: 3
    Last Post: 12th June 2013, 11:55
  4. drawing lines using qpainter from file
    By neutrino in forum Qt Programming
    Replies: 2
    Last Post: 9th February 2013, 10:03
  5. Drawing row/column lines in QTreeWidget
    By warvimo in forum Newbie
    Replies: 0
    Last Post: 25th May 2012, 18:33

Tags for this Thread

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.