Search code examples
qtqmlvisibilityvisible

QML Item visibility and computation


I have a qml file BackgrounPage.qml which is used as a background for all my qml pages in my application.

This background can be a gradient, a solid color or an image.

So I did:

BackgroundPage{

  property bool isGradient: false
  property bool isSolid: true //by default
  property bool isImage: false

  //gradient background
  Rectangle{
    visible: isGradient

    ...//create the rectangle

    LinearGradient{
      ...//create gradient
    }
  }

  //solid background
  Rectangle{
    visible: isSolid

    //create rectangle

    color: ...
  }

  Image{
    visible: isImage
    source: ...
  }
}

It works well but for performance, optimization, I wonder if a non visible item is computed or not by QML. If I create a solid background, I don't want the gradient and the image to be computed.

So my question is: are non visible item computed in QML?


Solution

  • What is "computed" for you?

    Yes, the objects are created and are "alive" - so if there are any bindings that affect those Items, those will be evaluated.

    Whether they will be rendered? No. When they are invisible, the engine prevents them from going to the GPU.

    To validate that claim see this example:

    ApplicationWindow {
        id: window
        visible: true
        width: 600
        height: 600
    
    
        Rectangle {
            width: 100
            height: 100
            color: 'green'
    
            Timer {
                running: true
                interval: 1000
                repeat: true
                onTriggered: parent.visible = !parent.visible
            }
        }
    }
    

    The visiblity of the Rectangle is toggled every second.
    If you watch the output generated by setting the envrionment variable:

    QSG_DEBUG_RENDERER=render
    

    you will see, that this toggels the amount of rendered nodes between 0 and 1.

    Rendering:
     -> Opaque: 0 nodes in 0 batches...
     -> Alpha: 0 nodes in 0 batches...
     -> times: build: 0, prepare(opaque/alpha): 0/0, sorting: 0, upload(opaque/alpha): 0/0, render: 0
    Renderer::render() QSGAbstractRenderer(0x2341b258) "rebuild: full"
    Rendering:
     -> Opaque: 1 nodes in 1 batches...
     -> Alpha: 0 nodes in 0 batches...
     - 0x38589200 [  upload] [noclip] [opaque] [  merged]  Nodes:    1  Vertices:     4  Indices:     6  root: 0x0
     -> times: build: 0, prepare(opaque/alpha): 0/0, sorting: 0, upload(opaque/alpha): 0/0, render: 1
    Renderer::render() QSGAbstractRenderer(0x2341b258) "rebuild: none"
    

    The better solution however would be to have use a Loader to load the right component:

    Loader {
        sourceComponent: (isGradient ? gradientComponent :
                          (isSolid ? solidComponent :
                           (isImage ? imageComponent : null)))
        Component {
            id: gradientComponent
            ...
        }
        ...
    }