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 application

    isaac@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 for render in the render loop. Based on the Qt documentation, render time is

    Total 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
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.