Performance of QQuickWidget
-
No I'm not sure that they're getting repainted, but if I have just one active meter visible and nothing else, the CPU % goes down. But if I have 20 visible and only one active then the CPU is much higher. Since the other 19 shouldn't be getting repainted why would the CPU still be higher? The 19 meters that are inactive just have a black opaque background.
The VU meters are built just using qml. Only the QQuickView derived class is C++ and it has basically nothing in it. This is just a small test app I've built with no frills.Any ideas?
Thanks.
-
@zepfan I guess there could be some other problem then. May be some connections or properties that are getting updated. Even if it gets repainted I think CPU usage wont go that much high as QML uses scenegraph which in turn uses OpenGL so most of the rendering is done by the hardware.
Can you post a complete minimal runnable example to test ? -
Here is the qml file that defines the meter. I use a Repeater to create multiple instances of these and give each one a unique index (meterIndex).
In the code you can see I check to see if it is the first meter (meterIndex = 0) and if so then only that one's clip rectangle is active. I've since realised that setting the rest to invisible actually brings down the CPU %. But if I leave them visible then the CPU increases, even though there's no activity. Is it normal to set items to invisible if you don't want anything rendered for them?import QtQuick 2.0 Rectangle { id: myMeter width: 20 height: 100 property int meterIndex: 0 color: "black" Rectangle { id: clipRect width: parent.width height: 0 clip: true Timer { id: myTimer interval: 20 repeat: true running: true triggeredOnStart: true onTriggered: { if(myMeter.meterIndex == 0) { clipRect.height = myMeter.height * Math.random(); } else { clipRect.visible = false; myTimer.stop(); } } } color: "blue" } }
-
@zepfan I see you are starting a
Timer
of interval 20 and it seems you are starting it for all the other remaining meters. ATimer
of such a low interval and that too for 20 items is ofcourse going to be CPU intensive. I would suggest here to not start theTimer
for the rest in first place. You can add s condition like:Timer { running: myMeter.meterIndex == 0 }
So the
Timer
will start only for the Item with meterIndex = 0Is it normal to set items to invisible if you don't want anything rendered for them?
Yes it reduces the cost of drawing again. See over-drawing-and-invisible-elements.
-
So if I have other elements on screen but they have not changed, does that mean they will be re-rendered every time also? I can't change them to (visible: false) as obviously I need to see them!
Is there a flag/setting that you can set that will make sure only items that are 'dirty' will be rendered?
Thanks
-
@zepfan No change no rendering again.
Is there a flag/setting that you can set that will make sure only items that are 'dirty' will be rendered?
I'm not aware of any such in QML.
But as I explained earlier your timer is eating the CPU. Even if Item is invisible timer will be active. 20 ms timeout for 20 items is CPU intensive. -
@p3c0 said:
But as I explained earlier your timer is eating the CPU. Even if Item is invisible timer will be active. 20 ms timeout for 20 items is CPU intensive.
True, but if I only have the timer running for one meter there is still quite a difference in CPU % between having the idle meters' clipRect visible or not visible. If they're not being repainted (since they're not active) then there shouldn't be a difference in CPU %?
-
If you use the code above for the actual Meter (MyMeter), and here is its parent which uses a Repeater to construct 20 of them. Try having the timer just running in the first meter, compared with having the timer running in all of them. I don't notice much change in CPU when having one of them getting its clipRect.height changed or having all of them get their clipRect.height changed.
I should state that the reason I've made this test application is because I'm doing something similar in work (which I obviously can't post) and am getting similar results. My suspicion is that the whole scene is getting re-rendered rather than just the item that needs it.
import QtQuick 2.0 Rectangle { visible: true width: 900 height: 700 color: "green" Column { id: myColumn spacing: 10 Repeater { model: 2 Row { id: myRow x: 50 y: 50 spacing: 40 property int rowIndex: index Repeater { id: innerRepeater model: 10 MyMeter { objectName: "Meter " + (index + (myRow.rowIndex * innerRepeater.model)) meterIndex: (index + (myRow.rowIndex * innerRepeater.model)) width: 15 height: 150 } } } } } }
-
I don't have the exact figure on me at the moment, but the figure itself isn't relevant. For my test app the figure wasn't too high, but my concern is that the CPU % doesn't change much whether I have one meter active or 20 meters active. Once they are all visible it's pretty much the same. And obviously this affects the real project I'm working on even more.
I've actually also just posted in the QtQuick forum just to see if anyone has any thoughts on rendering performance/improvements.Thanks
-
@zepfan As told earlier the rendering is all done by OpenGL which in turn is handled by the GPU so that wont matter. The
Timer
is what is affecting the CPU.
QtQuick renderer is capable of handling thousands of items at a time. Please check it here. Also here are some benchmark examples.
Extremetable example loads100000
items as and when required.
Anyway here are some more link that you may fine useful:
http://doc.qt.io/qt-5/qtquick-performance.html
http://www.sletta.org/apps/blog/show/42708211-looking-at-throughput-in-qt-quick
http://doc.qt.io/qt-5/qtquick-visualcanvas-scenegraph-renderer.html
Try profiling your example.