1
votes

I'm tyring to figure out how I can accelerate drawing of a QML scene that shows a game map made up of hexagonal tiles. Each tile is a qml item dynamically instantiated via JavaScript on startup. The highlight property of each tile is toggled based on mouse-over movement.

The tile object looks similar to this:

Item {
    id: tile

    x: // is set to fixed value by JS code on item instantiation
    y: // is set to fixed value by JS code on item instantiation
    width: // is set to fixed value by JS code on item instantiation
    height: // is set to fixed value by JS code on item instantiation

    property bool highlight: false

    Canvas {
        id: background
        anchors.fill: parent
        onPaint: {
            // draw filled hexagon
        }
    }
    Canvas {
        id: border
        anchors.fill: parent
        onPaint: {
            // draw hexagon outline
        }
    }
    Canvas {
        id: highlightItem
        anchors.fill: parent
        visible: highlight
        onPaint: {
            // draw filled yellow hexagon
        }
    }
}

The issue is that this type of scene is dead slow to render when toggling single tile highlights, with about 11fps at ~300 tiles total in the scene.

If I remove the background and border canvas elements, I am getting more than triple the framerate. I have confirmed that none of the onPaint() methods are called again after the initial paint operation is done.

Below is a QML profiler view of a single highlight event and the time it takes for the signal handler to process. The thin line is where it toggles the highlight property.

Does anyone have ideas why such a simple scene is so slow and how it can be sped up?

QML Profiler

1

1 Answers

0
votes

I guess the bytecode blocks are Canvas.onPaint code which is usual suspect when it comes to realtime rendering bottlenecks.

It really depends on what triggers Canvas.onPaint. This does not happen implicitly, some code must call Canvas.requestPaint() explicitly. Check your code, if that is the case. Maybe that is not necessary.

If some elements have to be repainted every frame, I would suggest to use ShaderEffect. You have to write your rendering code as fragment and vertex shaders, which is very different from canvas API. But it usually orders of magnitude faster.