Améliorer les performances de QML

| Christophe Dumez | traducteur : Thibaut Cuvelier |

Quelques trucs et astuces assez simples permettent d'améliorer les performances de QML, les voici résumés dans un article.

Commentez

- Titre : Améliorer les performances de QML

- Auteurs : Christophe Dumez, traducteur : Thibaut Cuvelier

- Parution : 4 février 2012

- Mise à jour : 10 février 2012

- Licence : Copyright ® 2012 Christophe Dumez. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. L'article original

- II. Utiliser un autre système graphique

- III. Utiliser showFullScreen()

- IV. Limiter JavaScript

- V. N'activer la coupure qu'en cas de nécessité

- VI. Délégués de vue

- VII. Images

- VIII. Utiliser des ancres plutôt que des fixations pour positionner les éléments relativement l'un à l'autre

- IX. Lecture recommandée

- X. Remerciements

I - L'article original

Cet article est une adaptation en langue française de Ways to improve QML performance.

II - Utiliser un autre système graphique

Utiliser un autre système graphique que le natif donne parfois des performances supérieures (particulièrement sur X11).

Une configuration recommandée pour les périphériques embarqués basés sur X11 est d'utiliser un système de rendu raster avec un QGLWidget pour le viewport de la QDeclarativeView.

Voici comment le faire :

QApplication a(argc, argv);
// Utiliser un système de rendu raster
QApplication::setGraphicsSystem("raster"); // On peut aussi essayer ici "opengl"
QDeclarativeView *view = new QDeclarativeView;
// Utiliser un QGLWidget pour le viewport
QGLFormat format = QGLFormat::defaultFormat();
// On peut commenter la ligne suivante si les résultats graphiques ne sont pas
// acceptables.
format.setSampleBuffers(false);
QGLWidget *glWidget = new QGLWidget(format);
// Commenter la ligne suivante en cas de problèmes d'affichage (généralement
// quand l'élément de plus haut niveau est un Item et non un Rectangle).
glWidget->setAutoFillBackground(false);
view->setViewport(glWidget);
view->setSource("qml/main.qml");

Pour ceux qui utilisent le visualiseur QML, il semble qu'il utilise déjà le système de rendu raster par défaut sur X11 et Mac OS X. On peut utiliser l'option en ligne de commande -opengl pour utiliser un QGLWidget comme viewport pour la vue (pas nécessaire sous Mac OS X).

III - Utiliser showFullScreen()

Il est recommandé d'utiliser QDeclarativeView::showFullScreen() au lieu de QDeclarativeView::show() pour éviter une surcharge de compositing. Ceci devrait améliorer légèrement les performances.

Pour ceux qui utilisent le visualiseur QML, on peut utiliser l'option -fullscreen.

IV - Limiter JavaScript

Le code JavaScript devrait être minoritaire (on peut souvent utiliser du C++ à la place, particulièrement pour la logique métier).

On devrait notamment éviter d'utiliser du JavaScript pendant une animation (par exemple, utiliser une expression JavaScript complexe pour chaque image d'une animation pour une certaine propriété).

Simplifier les expressions JavaScript autant que possible et les écrire en ligne si possible peut aussi aider. QML est compilé en un flux optimisé et les expressions JavaScript passent dans un évaluateur optimisé pour les expressions simples.

V - N'activer la coupure qu'en cas de nécessité

Item.clip est défini à false par défaut et on ne devrait l'activer qu'en cas de stricte nécessité. Si la coupure est activée, un item coupera son propre rendu, tout comme pour ses enfants, aux bordures de son rectangle.

VI - Délégués de vue

Les performances lors du flicking d'une vue sont dépendantes de la taille de ses délégués et de la rapidité du modèle de données. On devrait essayer de garder le code QML des délégués aussi petit que possible et utiliser un Loader pour toute fonctionnalité qui n'est pas requise directement pour l'affichage des données (par exemple, seulement après un clic).

La valeur de la propriété cacheBuffer de la vue (ListView, GridView) peut aussi être augmentée pour améliorer la régularité du mouvement. Cette propriété détermine le nombre de délégués maintenus en dehors de la zone de la vue.

VII - Images

De grandes images consomment beaucoup de mémoire. Il est conseillé de définir la propriété Image.sourceSize à une taille pas plus grande que ce qui est nécessaire pour l'afficher. L'image gardée en mémoire sera redimensionnée à cette valeur pour économiser de l'espace.

Si une image n'a pas besoin d'être affichée directement, on peut définir la propriété Image.asynchronous à true. Ainsi, l'image sera chargée dans un thread de basse priorité.

N'activer Image.smooth qu'en cas de nécessité. Cette propriété fait que les opérations de changement d'échelle ou de transformation sur l'image seront effectuées de manière lissée. Cela donne une meilleure qualité visuelle tout en étant plus lent. En lieu et place, il vaut mieux s'assurer que l'image a la bonne taille directement, ce qui évite de la redimensionner (Image.smooth n'aura alors pas d'impact visuel ou sur les performances). Si cette option est réellement requise, il est recommandé de la désactiver si l'image est animée (des artéfacts de changement d'échelle ne sont généralement pas remarquables en cas d'animation).

Il est aussi recommandé de ne fournir qu'une seule ressource d'image plutôt qu'une composition d'un certain nombre d'éléments. Par exemple, un cadre avec une ombre pourrait être créé avec un Rectangle placé sur une Image fournissant l'ombre. Il est plus efficace de fournir une image qui inclut le cadre et l'ombre.

VIII - Utiliser des ancres plutôt que des fixations pour positionner les éléments relativement l'un à l'autre

On considère des rectangles rect1 et rect2 positionnés relativement en spécifiant des tailles fixes :

Rectangle {
id: rect1
x: 20
width: 200; height: 200
}
Rectangle {
id: rect2
x: rect1.x
y: rect1.y + rect1.height
width: rect1.width - 20
height: 200
}

On peut avoir le même effet de manière plus performante avec des ancres :

Rectangle {
id: rect1
x: 20
width: 200; height: 200
}
Rectangle {
id: rect2
height: 200
anchors.left: rect1.left
anchors.top: rect1.bottom
anchors.right: rect1.right
anchors.rightMargin: 20
}

IX - Lecture recommandée

La documentation de référence sur les performances avec QML.

X - Remerciements

Merci à Guillaume Belz et Maxime Gault pour leur relecture attentive !