Written by Günter Schwann
2017/05/10
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.