Skip to content

Detecting Overdraw in QML HMIs with GammaRay

Overdraw happens when one QML item fully eclipses another QML item. The QML renderer always draws both items, although there is no need to draw the eclipsed item. You must help out the renderer by explicitly setting visible: false on the eclipsed item.

On embedded systems, heavy overdraw makes animations or flicking jerky. In the worst case, it freezes your HMI. Fortunately, the Qt experts at KDAB developed a tool, GammaRay, which makes detecting overdraw a piece of cake. I’ll show you how to build GammaRay, how to detect overdraw in the home screen of a harvester HMI, and how to fix the overdraw.

Building GammaRay

You must build GammaRay against the same Qt version used by your QML application, because GammaRay uses private Qt headers. So, it’s best to build GammaRay from sources (see also Getting GammaRay). Here are the commands to build GammaRay on Ubuntu 16.04.

$ git clone git://github.com/KDAB/GammaRay.git
$ cd GammaRay
$ mkdir build-gammaray-with-qt5.13.1
$ cd build-gammaray-with-qt5.13.1
$ cmake -D CMAKE_PREFIX_PATH=/path/to/qt \
    -D CMAKE_INSTALL_PREFIX=/path/to/gammaray ..
$ make -j8
$ make install

CMAKE_PREFIX_PATH specifies the base directory of your Qt installation and binds GammaRay to a specific Qt version. ${CMAKE_PREFIX_PATH}/bin/qmake points to the qmake executable. CMAKE_INSTALL_PREFIX determines the installation location of GammaRay. If you skip CMAKE_INSTALL_PREFIX, GammaRay will be installed into /usr/local.

Detecting Overdraw

Start GammaRay with

$ /path/to/gammaray/bin/gammaray &

You’ll see the launcher window.

Enter the path to your Executable, the Working Directory and the Program arguments. Then, press the Launch button. You’ll see GammaRay’s main window.

Select the Visualize Overdraw tool marked by the red circle. GammaRay shows a 3D view of the application launched, the home screen of a harvester HMI. The 3D view visualises the z-order (stacking order) of the QML items.

The dark-grey background item is in the lowest layer 0. The upper and lower three green items belong to a list view each. The items in the list view are opaque and cover the background below. So, they are in layer 1. Only the middle list view item is visible to users. The left and right list view items are clipped and not visible to users. Additionally, the right list view items are outside the monitor. The yellow items on top of the green items are in layer 2.

Home screen of harvester HMI with heavy overdraw

Although the left and right list view items are not visible to the user, the QML renderer still draws them and wastes GPU and CPU cycles on them. This is called overdraw. As you can see from the 3D visualisation, the home screen suffers from heavy overdraw.

Each list view item has a size of 596 x 324 pixels. The six list view items cover an area of 1788 x 648 pixels (1.2 million pixels). The display has a resolution of 1280 x 1028 (1.0 million pixels). The overdraw more than doubles the rendering area from 1.0 million to 2.2 million pixels. You shouldn’t be surprised that the list views stutter and freeze when flicked.

Fixing the Overdraw

My first idea for fixing the overdraw was to set cacheBuffer: 0 in the two list views. The Qt documentation says about cacheBuffer:

This property determines whether delegates are retained outside the visible area of the view.

So, setting cacheBuffer to 0 should should stop ListView from creating the previous and the next item in advance, from caching and rendering them. Unfortunately, it does not, as a look with GammaRay reveals.

My next idea was to set

visible: ListView.isCurrentItem

in the delegates of the list views – as told by GammaRay. This setting ensures that all items in the list views but the current item are invisible. A look with GammaRay confirms that.

No overdraw in the list views

This solution leaves a little problem. When you flick an item, say, to the left, the right half of the item’s area stays empty. It stays empty, because the next item to the right is invisible until it covers more than half of the list view. At the half point, the current item becomes invisible and the next item visible. Users don’t see in advance to which item they are moving. The new item comes as a surprise.

Flicking leaves half of the delegate empty

You get rid of the sudden switch of items by extending the visible condition.

visible: ListView.isCurrentItem || 
         droot.ListView.view.moving

In addition to the current item, the list view makes the moving item visible. The moving item gradually replaces the current item. While the flicking goes on, the QML engine renders two list view items, but never three.

Two list view items shown during flicking

As soon as the user stops flicking, the QML engine only renders one item in each list view. The GPU included in the SoC (an i.MX6) easily handles the temporary overdraw.

Acknowledgement

Guiseppe d’Angelo, KDAB, gave a fantastic talk about Optimizing the Rendering of Qt Quick 2 Applications with GammaRay at the Qt Day Italy 2019. Just follow this link to the video. Guiseppe shows that GammaRay makes it easy to detect Overdraw, Clipping, OpenGL batches and other rendering problems in QML applications. My thanks go to Guiseppe for a very instructive talk and to KDAB for building GammaRay.

Leave a Reply

Your email address will not be published. Required fields are marked *