Unsolved Having many non-overlapping items affect the QML performance
-
In the following QML, the only dynamic part is the blinking rectangle. While it has no relation to the generated items, the blinking rectangle causes a heavy load and slows down the system (e.g. 100% CPU load on i.MX6 processor I am using), even when there is no overlap/binding between it and other items. Removing the Repeater solves the issue and rectangle smoothly blinks.
import QtQuick 2.3 Rectangle { id: root anchors.fill: parent Repeater { model: 10000 delegate: Rectangle { width: 5 height: 5 x: (index % 200)*6 y: 50 + Math.floor(index / 200)*6 color: "blue" border.color: "black" } } Rectangle { property bool blinker: false width: 20 height: 20 color: blinker ? "green" : "red" Timer { running: true interval: 100 repeat: true onTriggered: { parent.blinker = !parent.blinker } } } }
I've replaced Repeater with the following javascript code to generate the same number of objects with the same properties:
Component.onCompleted: { var objstr = 'import QtQuick 2.0;Rectangle{id:sample;width:5; height:5;color:"blue";border.color: "black"}'; for(var i=0;i<200;i++) { for(var j=0;j<50;j++) { var obj = Qt.createQmlObject(objstr,root); obj.x = i * 6 obj.y = 50 + j*6 } } }
Based on this article, I've done the following examinations:
QSG_RENDERER_DEBUG=render
Setting this flag outputs some debugging information about rendering and batching. The output for the test applicationisaac@ubuntu:~$ QSG_RENDERER_DEBUG=render ./qml-test QML debugging is enabled. Only use this in a safe environment. Batch thresholds: nodes: 64 vertices: 1024 Using buffer strategy: static Renderer::render() QSGAbstractRenderer(0x93b9570) "rebuild: full" Rendering: -> Opaque: 14002 nodes in 2 batches... -> Alpha: 0 nodes in 0 batches... - 0x8f0a698 [ upload] [ clip] [opaque] [ merged] Nodes: 14000 Vertices: 168000 Indices: 224000 root: 0xb3e2a90 sets: 3 - 0x8f0b310 [ upload] [noclip] [opaque] [ merged] Nodes: 2 Vertices: 8 Indices: 12 root: 0x0 Renderer::render() QSGAbstractRenderer(0x93b9570) "rebuild: none" Rendering: -> Opaque: 14002 nodes in 2 batches... -> Alpha: 0 nodes in 0 batches... - 0x8f0a698 [retained] [ clip] [opaque] [ merged] Nodes: 14000 Vertices: 168000 Indices: 224000 root: 0xb3e2a90 sets: 3 - 0x8f0b310 [retained] [noclip] [opaque] [ merged] Nodes: 2 Vertices: 8 Indices: 12 root: 0x0 Renderer::render() QSGAbstractRenderer(0x93b9570) "rebuild: none"
This tells that items are batched in 2 group; one with 14000 nodes and one with 2 nodes. This seems to be what we expect.
QSG_VISUALIZE=batches
This switch visualizes the batches on the UI. Running this shows a solid color covering the whole UI. This means the blinking rectangle and the small rectangles are being rendered in one batch.Setting clip: true didn't help to force separating the batches. By setting opacity: 0.5 for blinking rectangle, I finally succeeded to force QML engine to put it into another batch.
Interestingly, the blinking was still affected and slowed down by the high number of small rectangles!
QSG_RENDER_TIMING=1
The last flag I tried was
QSG_RENDER_TIMING
which report some timing information for rendering. Based on the output, the actual time spent is forrender
in the render loop. Based on the Qt documentation,render
time isTotal time spent rendering the frame, including preparing and uploading all the necessary data to the GPU. This is the gross render time. Do not confuse it with the net Render Render time below.
but this wasn't helpful to me. So far, I haven't be able to find the root cause of this issue.
isaac@ubuntu:~$ QSG_RENDER_TIMING=1 ./qml-test QML debugging is enabled. Only use this in a safe environment. qt.scenegraph.time.compilation: shader compiled in 3ms qt.scenegraph.time.renderer: time in renderer: total=27ms, preprocess=0, updates=5, binding=0, rendering=21 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 107ms, polish=0, sync=65, render=27, swap=1, frameDelta=0 qt.scenegraph.time.renderer: time in renderer: total=1ms, preprocess=0, updates=0, binding=0, rendering=1 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 1ms, polish=0, sync=0, render=1, swap=0, frameDelta=2 qt.scenegraph.time.renderer: time in renderer: total=8ms, preprocess=0, updates=0, binding=0, rendering=8 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 255ms, polish=0, sync=0, render=8, swap=24, frameDelta=255 qt.scenegraph.time.renderer: time in renderer: total=1ms, preprocess=0, updates=0, binding=0, rendering=1 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 290ms, polish=0, sync=0, render=1, swap=28, frameDelta=297 qt.scenegraph.time.renderer: time in renderer: total=0ms, preprocess=0, updates=0, binding=0, rendering=0 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 296ms, polish=0, sync=0, render=0, swap=29, frameDelta=303 qt.scenegraph.time.renderer: time in renderer: total=298ms, preprocess=0, updates=0, binding=0, rendering=298 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 300ms, polish=0, sync=0, render=298, swap=0, frameDelta=306 qt.scenegraph.time.renderer: time in renderer: total=592ms, preprocess=0, updates=0, binding=0, rendering=592 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 593ms, polish=0, sync=0, render=592, swap=0, frameDelta=600 qt.scenegraph.time.renderer: time in renderer: total=292ms, preprocess=0, updates=0, binding=0, rendering=292 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 298ms, polish=0, sync=0, render=295, swap=0, frameDelta=305 qt.scenegraph.time.renderer: time in renderer: total=286ms, preprocess=0, updates=0, binding=0, rendering=286 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 291ms, polish=0, sync=0, render=286, swap=0, frameDelta=298 qt.scenegraph.time.renderer: time in renderer: total=291ms, preprocess=0, updates=0, binding=0, rendering=291 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 296ms, polish=0, sync=0, render=294, swap=0, frameDelta=305 qt.scenegraph.time.renderer: time in renderer: total=286ms, preprocess=0, updates=0, binding=0, rendering=286 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 292ms, polish=0, sync=0, render=286, swap=0, frameDelta=298 qt.scenegraph.time.renderer: time in renderer: total=290ms, preprocess=0, updates=0, binding=0, rendering=290 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 295ms, polish=0, sync=0, render=291, swap=0, frameDelta=301 qt.scenegraph.time.renderer: time in renderer: total=297ms, preprocess=0, updates=0, binding=0, rendering=297 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 302ms, polish=0, sync=0, render=298, swap=0, frameDelta=310 qt.scenegraph.time.renderer: time in renderer: total=290ms, preprocess=0, updates=0, binding=0, rendering=290 qt.scenegraph.time.renderloop: Frame rendered with 'basic' renderloop in 293ms, polish=0, sync=0, render=290, swap=0, frameDelta=316