C
Qt Quick Ultralite Performance Guide
Before applying any of the optimizations described in this section, it is important to gather important performance metrics such as CPU usage, memory consumption, application ROM footprint and so on. See Qt Quick Ultralite Performance Logging for more information. This page describes different optimization techniques to improve performance and reduce memory footprint of the application. Besides these optimization techniques, you should also follow the best practices while writing QML code.
Memory optimization
Flash and RAM footprints can be reduced by using one or more of the following optimization features or techniques:
Enabling resource compression
PNG compression
If QUL_RESOURCE_COMPRESSION is set, an image is stored with PNG compression and will be decompressed into the cache when needed. This reduces the size of the binary but adds decompression overhead. See QUL_RESOURCE_COMPRESSION to learn more about enabling and using PNG compression in Qt Quick Ultralite applications.
RLE compression
Unlike images using QUL_RESOURCE_COMPRESSION, images with pixel formats RGB888RLE, XRGB8888RLE, and ARGB888RLE are decoded on the fly during rendering, and thus don't require any additional storage. The limitation is that scales, rotations, shears, and perspective transforms are not supported for these RLE pixel formats.
See Lossless compressed image formats for more information.
Framebuffer size
Framebuffer size can be optimized by choosing lower color-depth and/or single buffering. Refer to the Framebuffer Requirements page for detailed information about the framebuffer size requirements.
You can also improve performance using the hardware layers if your platform supports it. Refer to Improving performance using hardware layers for more information.
Font quality
The font.quality property allows more fine-grained optimization, by providing hints to render low-quality glyphs. To save memory consumed by glyphs, set the font quality in your QML code to Font.QualityVeryLow.
Refer to QUL_DEFAULT_FONT_QUALITY for more information.
Application performance
Selecting a framebuffer strategy
Qt Quick Ultralite supports both single and double buffering strategies, offering a choice of better performance over memory usage. The single buffer strategy uses less memory but may come with performance overhead, whereas the double buffer strategy uses more memory but offers better performance.
See Framebuffering strategies for more information.
Selecting a font engine
Qt Quick Ultralite provides two font engine options: Montoype Spark and Static font engines.
Monotype font engine
- It is a better choice for internationalized applications that use a wide range of characters.
- It supports languages that require text shaping for correct layout.
- It enables text scaling support at runtime, without compromising on performance and text quality.
Static font engine
- It is simple and appropriate for applications that do not use complex text, and has lower footprint.
- It operates on static precomputed data, with very fast lookup operations.
- It does not have any font processing overhead at runtime, because fonts are processed while building the application.
Refer to the Feature comparison table for detailed comparison between the two font engines.
Using cache
Application performance can be enhanced by caching images and text.
Image caching
CMake Source file property QUL_RESOURCE_CACHE_POLICY can be used to set the caching policy for image resources.
- By default, all images are loaded from flash to RAM on startup.
- Resource cache size can be set with qul_set_maximum_resource_cache_size to desired size.
- Set the QUL_RESOURCE_CACHE_POLICY resource property to
OnDemand
for individual image resources. Alternatively, it can be set at once for all the images by setting QUL_DEFAULT_RESOURCE_CACHE_POLICY - Caching can also be disabled by setting QUL_RESOURCE_CACHE_POLICY to
NoCaching
to keep resources in flash. This involves some potential cost in rendering performance.
Note: Source file properties must be set before adding image files to the application using the qul_add_resource CMake function.
Font cache priming
If application contains a lot of text, it affects the application startup significantly. The font cache can be prepopulated at build time to improve startup time of the application.
Note: Cache priming is only supported by Monotype Spark font engine.
See Cache priming for more information.
Text caching
Text rendering performance can be improved further if text cache is enabled for the Qt Quick Ultralite application. On enabling the text cache, pixel data for each text element is cached, reducing the number of calls to the drawing engine.
Refer to Text caching section, which explains in detail about text caching feature and how to enable it.
Using hardware layers
On the MCU platforms that support hardware layers, performance can be enhanced by using multiple framebuffers. Hardware layer capabilities of the MCU can be used to blend these framebuffers together and produce the final image to be displayed. Using hardware layers can help reduce footprint and rendering time.
See Improving performance using hardware layers for more information about hardware layer usage.
QML best practices
The way the QML code is written can have a significant impact on the flash and random access memory footprint of the application. In general, avoiding duplication in the QML code will also reduce the amount of C++ code that is generated and reduce the flash memory footprint. There are also some other things to watch out for to prevent high memory usage and improve performance.
Create reusable components
Instead of repeating the same code patterns in a lot of places in the code, try to encapsulate the pattern in a separate QML file whenever possible.
For example, the code below has a list of labels, each containing some text and an image:
Column { spacing: 15 anchors.centerIn: parent Rectangle { width: 250 height: 120 color: "#e7e3e7" Row { anchors.centerIn: parent spacing: 10 Text { anchors.verticalCenter: parent.verticalCenter text: "Entry 1" color: "#22322f" font.pixelSize: 22 } Image { anchors.verticalCenter: parent.verticalCenter source: "img1.png" } } } Rectangle { width: 250 height: 120 color: "#e7e3e7" Row { anchors.centerIn: parent spacing: 10 Text { anchors.verticalCenter: parent.verticalCenter text: "Entry 2" color: "#22322f" font.pixelSize: 22 } Image { anchors.verticalCenter: parent.verticalCenter source: "img2.png" } } } }
This code can be simplified by creating a separate QML file called Label.qml, with the adjustable parts exposed as properties or property aliases as shown here:
import QtQuick 2.15 Rectangle { property alias imageSource: imageItem.source property alias text: textItem.text width: 250 height: 120 color: "#e7e3e7" Row { anchors.centerIn: parent spacing: 10 Text { id: textItem anchors.verticalCenter: parent.verticalCenter color: "#22322f" font.pixelSize: 22 } Image { id: imageItem anchors.verticalCenter: parent.verticalCenter } } }
This QML component can then be reused in the original QML code, avoiding duplication:
Column { spacing: 15 anchors.centerIn: parent Label { text: "Entry 1" imageSource: "img1.png" } Label { text: "Entry 2" imageSource: "img2.png" } }
Limiting PropertyChanges
A QML file with a lot of states and many properties that are affected by those states through PropertyChanges, leads to generating large and complex C++ code. The size of the generated code will be N x M
, where N is the number of states and M is the number of unique properties updated by PropertyChanges in those states.
Here's an example with just two states and two properties, but imagine that there would be a lot more similar states to choose between a variety of views in the same QML component:
Item { state: "0" states: [ State { name: "0" PropertyChanges { target: viewA; visible: true } }, State { name: "1" PropertyChanges { target: viewB; visible: true } } ] ViewA { id: viewA visible: false } ViewB { id: viewB visible: false } }
This can be optimized by setting the visible property of the views directly based on the state:
Item { id: root state: "0" states: [ State { name: "0" }, State { name: "1" } ] ViewA { id: viewA visible: root.state == "0" } ViewB { id: viewB visible: root.state == "1" } }
Avoid empty container items
The Item type can be useful for grouping other items, making it possible to set their visibility and position in a combined way. Limit the use of container items as they increase the memory usage. For example, the outer Item in the code snippet below is unnecessary:
It serves no good purpose in this case, as the contained Image item can be used directly instead:
Image { anchors.fill: parent source: "img.png" }
Save RAM by loading components dynamically
Your application might contain QML components with multiple complex items that consist of many sub-items, which are visible at different times. You can reduce RAM usage of such items by dynamically loading them. Use the Repeater API as shown in the following example:
Item { id: root state: "0" states: [ State { name: "0" }, State { name: "1" }, State { name: "2" } ] Repeater { id: viewA property bool active: root.state == "0" model: viewA.active ? 1 : 0 delegate: ViewA {} } Repeater { id: viewB property bool active: root.state == "1" model: viewB.active ? 1 : 0 delegate: ViewB {} } Repeater { id: viewB property bool active: root.state == "2" model: viewC.active ? 1 : 0 delegate: ViewC {} } }
Reduce the number of visual components
Each visual item typically carries some processing and rendering overhead at runtime. When possible, try reduce the number of visual items required to compose the UI. Below are some examples of how this can be done.
Reduce overlapping images
If two images are always overlapping in the UI, it might be better to combine them into a single image. A lot of overlapping images can reduce performance and will consume more memory. For example, the inner.png
in the following code snippet is smaller than the outer.png
image:
Instead, combine inner.png
and outer.png
into a single image:
Image { source: "combined.png" }
If some static text is also overlapping the image, it is worth combining that into the image, instead of using separate Text or StaticText items.
Reduce the Text items
Avoid arranging multiple Text items in a row if they can be combined into a single Text item. For example, the following code snippet shows two Text items arranged in a row:
They can be combined into a single Text item:
Text { text: "Temperature: " + root.temperature }
Available under certain Qt licenses.
Find out more.