When you want to draw a custom item in QtQuick, then you essentially have 3 options:
- draw using OpenGL by using QQuickItem (or a built-in item)
- draw using QPainter by using QQuickPaintedItem
- draw using HTML5 like canvas by using the QtQuick Canvas item
One can read here and there that OpenGL is the fastest. QQuickPaintedItem is slow. And Canvas is really slow. But I couldn’t find any information on how fast or slow each solution is. So I decided to do a quick comparison, to get an idea of their performances. So I did a quick and simple rendering of many rectangles using each technology. And measured the frames per second.
The measurement was very simple like this in main.cpp:
QQuickView view; int totalDuration = 0; int loops = 0; QElapsedTimer timer; timer.start(); QObject::connect(&view, &QQuickView::beforeRendering, [&](){ totalDuration += timer.elapsed(); ++loops; if (totalDuration > 10*1000) { qDebug() << (1000.0 * loops) / totalDuration << "fps"; totalDuration = 0; loops = 0; } timer.restart(); });
And here the QML code and the code for the QQuickPaintedItem:
import QtQuick 2.6 import test 1.0 Rectangle { id: root width: 1200 height: 1100 property color col: "black" // 0 for QtQuick, 1 for paintedItem, 2 for canvas property int solution: 2 property int rectangleSize: 512 property int numberOfRectangles: 1000 ColorAnimation on col { from: "red" to: "green" duration: 8000 loops: 100 } Repeater { model: root.numberOfRectangles Loader { width: root.rectangleSize height:root.rectangleSize opacity: 0.9 // even if overlap, drawing is needed sourceComponent: root.solution == 0 ? qtquickComponent : root.solution == 1 ? paintedComponent : canvasComponent } } // QtQuick OpenGL based solution Component { id: qtquickComponent Rectangle { color: root.col } } // QQuickPaintedItem based solution Component { id: paintedComponent PainterRectItem { color: root.col } } // Canvas based solution Component { id: canvasComponent Canvas { id: canvasRect Connections { target: root onColChanged: canvasRect.requestPaint(); } onPaint: { var ctx = getContext("2d"); ctx.fillStyle = root.col; ctx.fillRect(0, 0, width, height); } } } }
class PainterRectItem : public QQuickPaintedItem { Q_OBJECT Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) public: explicit PainterRectItem(QQuickItem* parent = nullptr); void paint(QPainter* painter) override { painter->save(); painter->fillRect(QRectF(0.0, 0.0, width(), height()), m_color); painter->restore(); } QColor color() const { return m_color; } public slots: void setColor(QColor color) { m_color = color; emit colorChanged(m_color); update(); } signals: void colorChanged(QColor color); private: QColor m_color; };
The results for 10,000 rectangles of size 4×4 are:
- QtQuick OpenGL 31 fps
- QQuickPaintetItem 10.4 fps
- Canvas 1.0 fps
The results for 10,000 rectangles of size 64×64 are:
- QtQuick OpenGL 31 fps
- QQuickPaintetItem 4.2 fps
- Canvas 2.2 fps
The results for 1,000 rectangles of size 512×512 are:
- QtQuick OpenGL 18 fps
- QQuickPaintetItem 1.2 fps
- Canvas 1.2 fps
Of course this is only a very limited test on my Linux X11 box using Qt 5.6. And real performance depends on many more things and can vary a lot. But at least you get an idea of the performance.
And one can see that QQuickPaintetItem heavily depends on the size of the item, as the item is drawn on a texture which needs to be transferred to the GPU.