Search code examples
c#c++qtgraphics2ddirect2d

Will Direct 2D be better than Qt at rendering lines onto a off screen buffer


I have a data visualization application (Parallel Coordinates). This involves drawing loads of lines on screen. The application is for huge datasets. The test data set involves ~ 2.5M lines (2527700 exact). The screen is going to be cluttered but it shows some pattern. The application has facility to scale along X and Y. At typical zoom levels it draws around 300K lines. The application is written in Qt and the time taken to render is respectable. Typical numbers are (time in ms)

Time taken: 496 Drew 1003226 lines

Time taken: 603 Drew 1210032 lines

Time taken: 112 Drew 344582 lines

Time taken: 182 Drew 387960 lines

Time taken: 178 Drew 361424 lines

Time taken: 222 Drew 676470 lines

Time taken: 171 Drew 475652 lines

Time taken: 251 Drew 318709 lines

Time taken: 5 Drew 14160 lines

Time taken: 16 Drew 27233 lines

The following code segment is used to time and count line segments drawn. Rendering happens to a off screen image (QImage with format Format_ARGB32_Premultiplied). The size of the QImage is at max 1366 x 768. segments type is QVector.

QTime m_timer;
m_timer.start();
painter.drawLines(segments);
qDebug() << "Time taken: " << m_timer.elapsed();
painter.end();
qDebug() << "Drew " << segments.size();

This QImage is cached to save future draws. I have never used DirectX. Will Direct 2D rendering give any more performance advantage than what I already have. Is there any way to improve on these numbers?

If Direct 2D rendering can improve these numbers what tech stack to use? Will using C#/SharpDX be better? I ask this because Qt can do DirectX through translation only (not sure what the cost is) and since the app is predominantly windows C# might ease the dev. process.


Solution

  • It might be optimal to create your own line drawing function, operating on QImage memory buffer directly. There you can make some assumptions which Qt's painter probably can not do and achieve better performance. Then blit the image to screen antialiased (and possibly zoomed?) using QGLWidget.

    Good line drawing code: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Simplification . Though for C++ and memory buffer implemenation, it can be further optimized by replacing x0 and y0 coordinates with single pointer.

    Most importantly, you can then get line drawing inlined within you lines loop and have zero function calls while iterating over a million lines.

    If you let the blitting part do antialiasing, you can just set a memory word per pixel without checking what kind of pen it is etc.

    Also doing zooming in HW to any desired target resolution, you can freely optimize the QImage size for getting the pattern you want, separate from showing it on screen.

    If you can have the lines mostly sorted by Y coordinate, that will help with caching, as setting pixels of sequential lines will be closer in memory in the QImage buffer.

    However you do it, crank up optimization (-O3 flag for gcc, not sure of MS compiler), default is not max at least for gcc.

    Another thing you can do is parallelize the drawing at per-image level, that will work even with QPainter. It is allowed to draw on QImage in other than main thread, and Qt makes it easy to just send QImages as signal parameter from drawing threads to GUI thread. What you do is heavily CPU and memory bound so better have drawing thread count same as real core count, not counting hyperthreading.