4

From the docs:

The default renderer does not do any CPU-side viewport clipping nor occlusion detection. If something is not supposed to be visible, it should not be shown. Use Item::visible: false for items that should not be drawn. The primary reason for not adding such logic is that it adds additional cost which would also hurt applications that took care in behaving well.

So is there a trick to do it easily, without implementing it myself?

Note that in my case the items that are outside the visible area are there because they are in a ScrollView and they are not scrolled-to.

The reason I want culling is to reduce CPU usage for full-scene redraws.

Stefan Monov
  • 11,332
  • 10
  • 63
  • 120
  • Are you using the software renderer, then? Because Qt Quick always renders the full scene on the GPU and there's not much impact to it. – Kuba hasn't forgotten Monica Apr 19 '17 at 17:35
  • It would be quite amateurish if it actually renders things that are actually not displayed. I've been able to save on RAM by simplifying the children of items which are outside the visible area, but it is far from trivial. It actually used more CPU however, as it involved plenty of extra work. – dtech Apr 19 '17 at 17:38
  • @KubaOber: I'm using the hardware render, but still having the CPU usage problems. Note that I have ~250 items, so, not so few. – Stefan Monov Apr 19 '17 at 17:40
  • 2
    A list view will do that automatically, and only load items that approach the visible area, but there you have the model as a data backend. Without that it will require a custom data structure to store stuff that is being culled away, it also requires quite a lot of coordinate mapping, and it has a disadvantage - you cannot reflect changes that happen to items which are "offline". – dtech Apr 19 '17 at 17:41
  • Finally, without knowing the actual usage scenario, it is practically impossible to offer an implementation strategy. "Items in a scroll view" can be a lot of things, ranging from very to non optimizable... – dtech Apr 19 '17 at 17:48
  • @dtech: Re: "Items in a scroll view can be a lot of things": all that matters is that I can set `visible: false` on them and then `true` again. To save on repainting-CPU. Note that I'm not trying to save on RAM. – Stefan Monov Apr 19 '17 at 18:10
  • Just calculate the "absolute position" of the item relative to the view, and if it is inside the view's tracked visible area enable, else disable. However I am not convinced setting visible to false alone is going to win you much. Tracking and switching visibility might end up eating more CPU. – dtech Apr 19 '17 at 18:12
  • @dtech: Just an update on this: Setting `opacity: 0` on items outside the viewport did win me much. IIRC I went from 12% CPU usage to 3.5% CPU usage for 257 items of which 21 are in the viewport. I think experiments in which I used `visible: false` showed a similar kind of improvement. – Stefan Monov May 01 '17 at 15:25
  • @StefanMonov - this is good news, but it is strange that your CPU usage is so high. My project easily handles 20k objects, laid out via bindings in a complex tree. What kind of hardware are you targeting? Or maybe it is the items? – dtech May 01 '17 at 17:08
  • @dtech: The measurements I mention are done on my own laptop, which is a fairly good one: [see specs](https://support.hp.com/bg-en/document/c04933701). Have you actually looked at your cpu usage, or are you assuming it's low because your framerate is good? Note that my framerate is good too, without culling. – Stefan Monov May 01 '17 at 18:21
  • @dtech: Also note that my scene is getting repainted at 60fps because of a single animation that constantly runs at 60fps. Is that true in your case? – Stefan Monov May 01 '17 at 18:36
  • Scrolling through 1000 objects, each made of around 15 individual QML elements, I get about 5% of CPU usage. But then again, that's on a 4.5 GHz i7. I don't care much about framerate as long as it doesn't stutter. It is a tree editor after all, and it runs fine even on my aging note 3 phone. The key here is in my case tree branches can be collapsed, which is the only sane way to navigate a tree that's typically 100k to multi million objects. So in practice object count is not that much of an issue for me, but I nevertheless have pushed it to see how QML does, and it does POORLY :) – dtech May 01 '17 at 18:39
  • Hopefully https://bugreports.qt.io/browse/QTBUG-67274 gathers some discussion about this topic eventually. – Mitch Mar 23 '18 at 13:10

2 Answers2

5

Here is a trivial example you can extend upon:

Window {
  visible: true
  width: 640
  height: 480

  Rectangle {
    anchors.centerIn: parent
    width: 200
    height: 200
    color: "yellow"

    Flickable {
      id: view
      anchors.fill: parent
      contentWidth: 200
      contentHeight: col.height
      property real span : contentY + height
      Column {
        id: col
        x: 90
        spacing: 2
        Repeater {
          model: 50
          delegate: Rectangle {
            width: 10
            height: 10
            color: inView ? "blue" : "red"
            property bool inView: y > view.contentY && y < view.span
          }
        }
      }
    }
  }
}

Obviously, a full-proof solution would also include the item's height in the calculation. You can also do the check in the x axis if necessary.

dtech
  • 47,916
  • 17
  • 112
  • 190
  • I'd say it should be `y >= view.contentY && y + height <= view.span` or `y + height >= view.contenY && y <= view.span` ;-) – Amfasis Mar 17 '20 at 13:13
0

To add to dtech's answer, I just learned that there are QML components, such as GridView and ListView, that do culling automatically.

Stefan Monov
  • 11,332
  • 10
  • 63
  • 120