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.
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
x0andy0coordinates 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.