AKA: Canvas requestPaint() too slow; requestAnimationFrame() too fast
I'm trying to create a QML Canvas that repaints as fast as possible—once per update in the main UI render loop—in order to create an FPS timer.
I initially wrote this simple test:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
visible:true; width:100; height:100
Canvas {
anchors.fill:parent
onPaint: console.log(+new Date)
}
}
I only get the callback once. So I added requestPaint()
:
onPaint: {
console.log(+new Date)
requestPaint()
}
No change: I still only get one callback. Same if I use markDirty()
. Same if I actually paint something on the canvas each callback.
So I moved to requestAnimationFrame()
:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
visible:true; width:100; height:100
Canvas {
anchors.fill:parent
Component.onCompleted: crank()
function crank(){
console.log(+new Date)
requestAnimationFrame(crank)
}
}
}
Now I get callbacks, but way too many. On average, I get 77 callbacks per millisecond, some times as many as 127 callbacks in a single millisecond. So many callbacks that nothing else in the application displays, not even initially. Even if I remove the console.log()
, to prove that I'm not i/o bound).
How can I get my canvas to repaint once "per frame", so that I can measure the FPS semi-accurately? Any why does requestPaint()
not actually work? And why is requestAnimationFrame()
apparently useless?
There was a bug with requestAnimationFrame()
prior to Qt 5.9. This bug has been fixed.
The following code works as expected and desired to keep the canvas continuously redrawing:
Canvas {
width:100; height:100;
property var ctx
onAvailableChanged: if (available) ctx = getContext('2d');
onPaint: {
if (!ctx) return;
ctx.clearRect(0, 0, width, height);
// draw here
requestAnimationFrame(paint);
}
}