Sur cette page

Qt pour Linux embarqué

Plug-ins de plateforme pour les appareils Linux embarqués

Sur les systèmes Linux embarqués, plusieurs plugins de plateforme sont disponibles : EGLFS, VkKhrDisplay, LinuxFB ou Wayland. La disponibilité de ces plugins dépend de la configuration de Qt. Parmi ceux-ci, Wayland nécessite la présence d'un compositeur et fournit un système de fenêtrage complet prenant en charge plusieurs fenêtres, à l'instar de X11 ou de Windows. Les autres fonctionnent sans aucun système de fenêtrage, ce qui signifie que l'application Qt contrôle entièrement le rendu et la sortie. Ils prennent généralement en charge une « fenêtre » Qt en plein écran par écran.

EGLFS est le plugin par défaut sur de nombreuses cartes graphiques. S’il ne convient pas, utilisez la variable d’environnement ` QT_QPA_PLATFORM ` pour demander un autre plugin. Sinon, pour des tests rapides, utilisez l’argument de ligne de commande ` -platform ` avec la même syntaxe.

Remarque : depuis Qt 5.0, Qt ne dispose plus de sa propre implémentation de système de fenêtrage (QWS). Pour les cas d’utilisation à processus unique, Qt Platform Abstraction constitue une solution supérieure ; les cas d’utilisation multiprocessus sont pris en charge via Wayland.

Consultez la section « Configurer un périphérique Linux embarqué » pour obtenir un aperçu de la configuration de Qt en vue d’une compilation croisée à l’aide d’une chaîne d’outils Linux embarquée.

EGLFS

EGL est une interface entre OpenGL et le système de fenêtrage natif. Qt peut utiliser EGL pour la gestion des contextes et des surfaces, mais l’API ne contient aucune spécificité propre à la plate-forme. La création d’une fenêtre native, qui ne sera pas nécessairement une fenêtre réelle à l’écran, doit tout de même être effectuée à l’aide de moyens spécifiques à la plate-forme. C’est pourquoi nous avons besoin d’un code d’adaptation spécifique à la carte ou au GPU. Généralement, ces adaptations sont fournies sous la forme :

  • des hooks EGLFS— un fichier source unique compilé dans le plugin de la plateforme
  • Intégration de périphériques EGL— des plugins chargés dynamiquement

EGLFS est un plugin de plateforme permettant d’exécuter des applications Qt par-dessus EGL et OpenGL ES 2.0, sans système de fenêtrage proprement dit tel que X11 ou Wayland. C’est le plugin recommandé pour les appareils Linux embarqués modernes équipés d’un GPU.

Outre les applications OpenGL natives et celles utilisant la fonction « Qt Quick », EGLFS prend également en charge les fenêtres avec rendu logiciel, comme QWidget. Pour QWidget, le contenu des widgets est rendu par le processeur sous forme d’images, qui sont ensuite chargées dans des textures et composées par le plugin.

EGLFS force la première fenêtre de niveau supérieur — qu’il s’agisse d’une fenêtre QWidget ou d’une fenêtre QQuickView— à passer en plein écran. Cette fenêtre est également choisie comme fenêtre racine dans laquelle tous les autres widgets de niveau supérieur sont composés. Par exemple, les boîtes de dialogue, les menus contextuels ou les listes déroulantes. Ce comportement est nécessaire car, avec EGLFS, il n’y a toujours qu’une seule fenêtre native et une seule surface de fenêtre EGL ; celles-ci appartiennent au widget ou à la fenêtre créée en premier. Cette approche fonctionne bien lorsqu’il existe une fenêtre principale qui perdure pendant toute la durée de vie de l’application et que tous les autres widgets ne sont soit pas de niveau supérieur, soit créés par la suite, une fois la fenêtre principale affichée.

Il existe d’autres restrictions pour les fenêtres basées sur OpenGL. EGLFS prend en charge une seule fenêtre GL en plein écran (à partir de Qt 5.3), comme QWindow, QQuickView ou QOpenGLWidget. L’ouverture de fenêtres OpenGL supplémentaires ou le mélange de telles fenêtres avec du contenu basé sur QWidget n’est pas pris en charge ; Qt met fin à l’application en affichant un message d’erreur.

De plus, les API conçues pour les plateformes de bureau ou les environnements dotés d’un système de fenêtrage, telles que le glisser-déposer, ne sont pas prises en charge sur EGLFS.

Variables d’environnement utilisées par EGLFS

Si nécessaire, « eglfs » peut être configuré à l'aide des variables d'environnement suivantes :

Variable d'environnementDescription
QT_QPA_EGLFS_INTEGRATIONOutre les hooks intégrés à la compilation, il est également possible d’utiliser des plugins chargés dynamiquement pour permettre une adaptation spécifique à un périphérique ou à un fournisseur. Cette variable d’environnement impose l’utilisation d’un plugin spécifique. Par exemple, la définir sur eglfs_kms permet d’utiliser le backend KMS/DRM. Cette option n’est disponible que si aucun hook statique ou intégré n’a été spécifié dans les spécifications de fabrication (makespecs) du périphérique. En pratique, les hooks traditionnels intégrés sont rarement utilisés, la quasi-totalité des backends ayant désormais migré vers des plugins. Les spécifications de fabrication du périphérique contiennent toujours une entrée EGLFS_DEVICE_INTEGRATION pertinente, bien que facultative : le nom du backend préféré pour ce périphérique particulier. Évitez de définir cette variable d’environnement s’il existe plusieurs plugins sur le système cible. Dans un environnement de bureau, les backends KMS ou X11 sont prioritaires, en fonction de la présence de la variable d’environnement ` DISPLAY `.

Remarque : sur certaines cartes, une valeur spéciale est attribuée à none à la place d’un plugin proprement dit. Cela indique qu’aucune intégration particulière n’est nécessaire pour utiliser EGL avec le framebuffer ; aucun plugin ne doit être chargé.

QT_QPA_EGLFS_PHYSICAL_WIDTH et QT_QPA_EGLFS_PHYSICAL_HEIGHTSpécifie la largeur et la hauteur de l’écran physique en millimètres. Notez que depuis Qt 6, la taille physique de l’écran n’est plus utilisée pour déterminer le dpi logique.
QT_QPA_EGLFS_ROTATIONSpécifie la rotation appliquée au contenu rendu par logiciel dans les applications basées sur « QWidget ». Les valeurs prises en charge sont 180, 90 et -90. Cette variable ne s’applique pas aux fenêtres basées sur OpenGL, y compris « Qt Quick ». Les applications « Qt Quick » peuvent appliquer des transformations dans leur scène QML à la place. Le curseur de souris standard eglfs tient toujours compte de cette valeur, avec une image de pointeur correctement positionnée et pivotée, quel que soit le type d’application. Cependant, certaines implémentations spéciales de curseur, telles que le curseur matériel du backend KMS/DRM, peuvent ne pas prendre en charge la rotation. Ce paramètre n’a aucun effet sur quoi que ce soit d’autre, y compris les entrées tactiles. Les backends d’entrée tactile evdevtouch et libinput disposent chacun de leurs propres mécanismes pour configurer la rotation. Consultez la section « Entrées sur un périphérique Linux embarqué » pour plus d’informations sur la configuration des entrées tactiles.
QT_QPA_EGLFS_FORCEVSYNCLorsqu’il est activé, ` eglfs ` demande à ` FBIO_WAITFORVSYNC ` sur le périphérique framebuffer après chaque appel à `eglSwapBuffers()`. Cette variable ne concerne que les backends s’appuyant sur l’ancien sous-système Linux ` fbdev `. Normalement, avec un intervalle de synchronisation par défaut de 1, Qt part du principe que l’appel à eglSwapBuffers() gère la synchronisation verticale (vsync) ; si ce n’est pas le cas (par exemple, en raison de bogues du pilote), essayez de définir QT_QPA_EGLFS_FORCEVSYNC sur une valeur non nulle.
QT_QPA_EGLFS_FORCE888Lorsqu’elle est définie, les tailles des canaux de couleur rouge, vert et bleu sont ignorées lorsque ` eglfs ` crée un nouveau contexte, une nouvelle fenêtre ou une nouvelle surface hors écran. À la place, le plugin demande une configuration à 8 bits par canal. Cela peut s’avérer utile sur les appareils où des configurations inférieures à 32 ou 24 bits par pixel (par exemple, 5-6-5 ou 4-4-4) sont choisies par défaut, bien que l’on sache qu’elles ne sont pas idéales, notamment en raison d’effets de bandes. Au lieu de modifier le code de l’application, cette variable offre un raccourci pour forcer des configurations à 24 ou 32 bpp.

De plus, les variables suivantes, moins couramment utilisées, sont disponibles :

Variable d’environnementDescription
QT_QPA_EGLFS_FBRemplace le périphérique de framebuffer. La valeur par défaut est /dev/fb0. Sur la plupart des plateformes embarquées, cette variable n’est pas très pertinente car le framebuffer n’est utilisé que pour interroger des paramètres tels que les dimensions de l’écran. Cependant, sur certains périphériques, cette variable permet de spécifier quel écran utiliser dans des configurations à plusieurs écrans, de manière similaire au paramètre fb dans LinuxFB.
QT_QPA_EGLFS_WIDTH et QT_QPA_EGLFS_HEIGHTContient la largeur et la hauteur de l’écran en pixels. Bien que ` eglfs ` tente de déterminer les dimensions à partir du périphérique de framebuffer `/dev/fb0`, cela ne fonctionne pas toujours. Il peut s’avérer nécessaire de spécifier manuellement ces dimensions.
QT_QPA_EGLFS_DEPTHRemplace la profondeur de couleur de l’écran. Sur les plateformes où le périphérique de framebuffer /dev/fb0 n’est pas disponible ou lorsque la requête échoue, la valeur par défaut 32 est utilisée. Utilisez cette variable pour remplacer ces valeurs par défaut.

Remarque : cette variable n’affecte que la valeur de profondeur de couleur renvoyée par QScreen. Elle n’a aucun lien avec les configurations EGL ni avec la profondeur de couleur utilisée pour le rendu OpenGL.

QT_QPA_EGLFS_SWAPINTERVALPar défaut, un intervalle de commutation de 1 est demandé. Cette variable permet la synchronisation avec le rafraîchissement vertical de l'écran. Utilisez cette variable pour remplacer la valeur de l'intervalle de commutation. Par exemple, en passant la valeur 0, on désactive le blocage lors de la commutation, ce qui permet un fonctionnement aussi rapide que possible sans aucune synchronisation.
QT_QPA_EGLFS_DEBUGLorsqu’elle est activée, certaines informations de débogage s’affichent dans la sortie de débogage. Par exemple, l’ QSurfaceFormat d’entrée et les propriétés de la configuration EGL choisie s’affichent lors de la création d’un nouveau contexte. Utilisée conjointement avec la variable QSG_INFO de Qt Quick, elle permet d’obtenir des informations utiles pour le dépannage des problèmes liés à la configuration EGL.

Journalisation

Outre ` QT_QPA_EGLFS_DEBUG`, ` eglfs ` prend également en charge le système moderne de journalisation par catégories de Qt. Les catégories de journalisation suivantes sont disponibles :

  • qt.qpa.egldeviceintegration – Active la journalisation pour les backends chargés dynamiquement. Utilisez cette catégorie pour vérifier quel backend est utilisé.
  • qt.qpa.input – Active la sortie de débogage provenant à la fois des gestionnaires d’entrée evdev et libinput. Utilisez cette catégorie pour vérifier si un périphérique d’entrée donné a été reconnu et ouvert.
  • qt.qpa.eglfs.kms – Active la journalisation détaillée dans le backend KMS/DRM.

Après avoir exécuté ` configure`, veillez à examiner sa sortie. C’est le moyen le plus simple et le plus rapide de vérifier si le backend EGLFS, libudev ou libinput nécessaire est bien activé. En bref, si la sortie de ` configure ` contient un « non » indésirable, exécutez :

./configure -v

pour activer le mode de sortie détaillé, ce qui vous permettra de voir les appels au compilateur et à l’éditeur de liens pour chaque test de configuration.

Remarque : si vous rencontrez des erreurs liées à des en-têtes ou des bibliothèques manquantes, ou encore des échecs de l'éditeur de liens apparemment cryptiques, cela indique souvent que le sysroot est incomplet ou corrompu et n'est pas lié à Qt.

À titre d’exemple, lorsque vous ciblez le Raspberry Pi avec les pilotes graphiques propriétaires de Broadcom, la sortie devrait ressembler à ce qui suit :

QPA backends:
EGLFS ................................ yes
EGLFS details:
  EGLFS i.Mx6 ........................ no
  EGLFS i.Mx6 Wayland ................ no
  EGLFS EGLDevice .................... no
  EGLFS GBM .......................... no
  EGLFS Mali ......................... no
  EGLFS Raspberry Pi ................. yes
  EGL on X11 ......................... no

Si ce n'est pas le cas, il n'est pas recommandé de poursuivre la compilation, car l'accélération graphique ne fonctionnera pas sans le backend spécifique au Raspberry Pi, même si le reste de Qt se compile correctement.

VkKhrDisplay

Alors qu’EGLFS ne prend en charge qu’OpenGL (ES), VkKhrDisplay est un plugin de plateforme expérimental qui prend en charge le rendu via l’API Vulkan. Pour répertorier les écrans et configurer le rendu, il s’appuie sur la famille d’extensions VK_KHR_display. Notez qu’il n’est pas certain qu’une implémentation de Vulkan au sein d’une pile graphique prenne en charge cette fonctionnalité. Actuellement, ce plugin de plateforme a été vérifié et testé avec Mesa et V3DV fonctionnant sur un Raspberry Pi 4.

Ce plugin de plateforme ne prend pas en charge OpenGL ni aucun rendu logiciel. Toute tentative d’affichage d’une interface utilisateur basée sur « QWidget » échouera donc. Le seul type de surface d’ QWindow pris en charge est « QSurface::VulkanSurface ». Pour les applications « Qt Quick », cela implique que le rendu basé sur Vulkan doit être imposé soit en définissant « QSG_RHI_BACKEND=vulkan » dans l’environnement, soit en appelant « QQuickWindow::setGraphicsApi » (QSGRendererInterface::Vulkan) ; et ce, bien avant de créer un « QQuickWindow » ou un « QQuickView ».

Pour utiliser ce plugin de plateforme, exécutez l’application avec l’option « -platform vkkhrdisplay » ou définissez la variable d’environnement « QT_QPA_PLATFORM » sur « vkkhrdisplay ». Le plugin n’est compilé que si Qt est configuré avec la prise en charge de Vulkan.

La configuration avancée de type EGLFS (par exemple, le fichier de configuration JSON) ou l’affichage sur plusieurs écrans à partir d’une même application ne sont pas encore implémentés. Les applications peuvent toutefois choisir l’écran à utiliser via des variables d’environnement.

Pour déterminer les valeurs d’index, consultez les journaux affichés dans la sortie de débogage par le plugin. Actuellement, ces journaux ne sont pas classés par catégorie (affichés via qDebug) car il est essentiel, dans la plupart des cas, de les examiner afin de s’assurer que le plugin sélectionne l’écran et le mode appropriés.

  • QT_VK_DISPLAY_INDEX - Lorsqu’il est défini, l’affichage correspondant à l’index indiqué est utilisé.
  • QT_VK_MODE_INDEX - Lorsqu’elle est définie, le mode correspondant à l’index indiqué est utilisé.
  • QT_VK_PHYSICAL_DEVICE_INDEX - Lorsqu’elle est définie, le périphérique physique Vulkan portant l’index indiqué est utilisé. Cela ne sera généralement pas pertinent dans la plupart des cas en environnement embarqué. Notez que cette variable est également utilisée par le reste de la pile graphique Qt.

La gestion des entrées (clavier, souris, tactile) est similaire à celle d’EGLFS et prend en charge les fonctions ` evdev`, ` libinput` et ` tslib`. Le rendu du curseur de souris n’est toutefois pas implémenté. En effet, il n’existe pas de concept de curseur matériel dans cet environnement, et le rendu d’un curseur avec Vulkan au sein du plugin de plateforme, à l’instar de ce que fait EGLFS avec OpenGL, pose problème pour plusieurs raisons. Par conséquent, ce plugin de plateforme n’est pour l’instant pas bien adapté aux entrées par souris.

Les variables d’environnement associées sont les suivantes :

  • QT_QPA_DISABLE_INPUT - Désactive les entrées clavier/souris/tactiles.
  • QT_QPA_NO_LIBINPUT - Privilégie les gestionnaires d'entrée basés sur evdev, même lorsque libinput est disponible.
  • QT_QPA_TSLIB - Demande l'utilisation de l'ancienne bibliothèque tslib.

LinuxFB

Ce plugin écrit directement dans le framebuffer via le sous-système fbdev de Linux. Seul le contenu rendu par logiciel est pris en charge. Notez que, dans certaines configurations, les performances d'affichage risquent d'être limitées. Pour utiliser des applications de type « Qt Quick » avec ce plugin de plateforme, il faut utiliser le backend de graphe de scène « software », soit en définissant ` QT_QUICK_BACKEND=software ` dans l'environnement, soit en appelant ` setGraphicsApi()` avec ` QSGRendererInterface::Software`. Les applications de type « QWidget », ou « QWindow » avec un type de surface « QSurface::RasterSurface », sont prises en charge, mais cela n'inclut pas les widgets spéciaux tels que « QOpenGLWidget ».

Comme fbdev est en voie de dépréciation dans le noyau Linux, la prise en charge des tampons « muets » DRM est également disponible. Pour l’utiliser, définissez la variable d’environnement QT_QPA_FB_DRM sur une valeur non nulle. Une fois cette variable définie, et à condition que les tampons « dumb » soient pris en charge par votre système, les périphériques de framebuffer hérités tels que /dev/fb0 ne seront pas utilisés. À la place, le rendu est géré via les API DRM, de manière similaire au backend eglfs_kms dans EGLFS. La sortie est en double tampon et utilise le « page flip », ce qui assure une synchronisation verticale (vsync) correcte, même pour le contenu rendu par logiciel.

Remarque : lorsque les tampons « dumb » sont utilisés, aucune des options décrites ci-dessous n’est applicable, car les propriétés telles que les tailles d’écran physiques et logiques sont toutes interrogées automatiquement.

Spécification de paramètres supplémentaires

Le plugin « linuxfb » vous permet de définir des paramètres supplémentaires via la variable d'environnement ` QT_QPA_PLATFORM ` ou l'option de ligne de commande ` -platform `. Par exemple, ` QT_QPA_PLATFORM=linuxfb:fb=/dev/fb1 ` spécifie que le périphérique framebuffer ` /dev/fb1 ` doit être utilisé à la place du périphérique par défaut ` fb0`. Pour définir plusieurs paramètres, séparez-les par deux points (:).

ParamètresDescription
fb=/dev/fbNSpécifie les périphériques de framebuffer. Dans les configurations à plusieurs écrans, ce paramètre vous permet d’exécuter l’application sur différents écrans. Actuellement, il n’est pas possible d’utiliser plusieurs framebuffers à partir d’une seule application Qt.
size=<width>x<height>Spécifie la taille de l'écran en pixels. Le plugin tente d'interroger le périphérique de framebuffer pour obtenir les dimensions de l'écran, tant physiques que logiques. Cependant, cette interrogation ne donne pas toujours des résultats corrects ; il peut être nécessaire de spécifier les valeurs explicitement.
mmsize=<width>x<height>Spécifie la largeur et la hauteur physiques en millimètres.
offset=<width>x<height>Spécifie le décalage en pixels du coin supérieur gauche de l’écran. La position par défaut est (0, 0).
nographicsmodeswitchSpécifie de ne pas basculer le terminal virtuel en mode graphique (KD_GRAPHICS). En règle générale, l’activation du mode graphique désactive le clignotement du curseur et la mise à zéro de l’écran. Cependant, lorsque ce paramètre est défini, ces deux fonctionnalités sont également ignorées.
tty=/dev/ttyNRemplace la console virtuelle. N'est utilisé que lorsque nographicsmodeswitch n'est pas défini.

À partir de Qt 5.9, le comportement d’EGLFS et de LinuxFB a été synchronisé en ce qui concerne la politique de redimensionnement des fenêtres : la première fenêtre de niveau supérieur est forcée de couvrir l’intégralité de l’écran, avec les deux plugins de plateforme. Si ce comportement n’est pas souhaité, définissez la variable d’environnement QT_QPA_FB_FORCE_FULLSCREEN sur 0 pour rétablir le comportement des versions antérieures de Qt.

Affichage de la sortie

Le niveau de prise en charge permettant de cibler un ou plusieurs écrans à partir d’une seule application Qt varie selon les plugins de plate-forme. Cette prise en charge dépend souvent du périphérique et de sa pile graphique.

EGLFS avec le backend eglfs_kms

Lorsque le backend KMS/DRM est utilisé, EGLFS signale tous les écrans disponibles via la fonction ` QGuiApplication::screens()`. Les applications peuvent cibler différents écrans avec différentes fenêtres via la fonction ` QWindow::setScreen()`.

Remarque : la restriction à une seule fenêtre en plein écran par écran s'applique toujours. Le changement d'écran après avoir rendu l'QWindow e visible n'est pas non plus pris en charge. Il est donc essentiel que les applications embarquées effectuent tous les appels QWindow::setScreen() nécessaires avant d'appeler QWindow::show().

Lorsque vous commencez à développer sur un périphérique embarqué donné, il est souvent nécessaire de vérifier le comportement du périphérique et des pilotes, ainsi que le bon fonctionnement des écrans connectés. Une méthode simple consiste à utiliser l’exemple hellowindow. Son lancement avec les arguments -platform eglfs --multiscreen --timeout affiche un logo Qt tournant sur chaque écran connecté pendant quelques secondes.

Configuration personnalisée

Le backend KMS/DRM prend également en charge les configurations personnalisées via un fichier JSON. Pour activer cette fonctionnalité, définissez la variable d’environnement ` QT_QPA_EGLFS_KMS_CONFIG ` sur le nom du fichier. Vous pouvez également intégrer ce fichier dans l’application via le système de ressources Qt.

La plupart de ces options de configuration s'appliquent à tous les backends basés sur KMS/DRM, quelle que soit la technologie de gestion des tampons utilisée (GBM ou EGLStreams).

Remarque : les fichiersde configuration sont considérés comme du contenu fiable, entièrement contrôlé et géré par le créateur de l’appareil ou de la plateforme. Ils ne sont en aucun cas destinés à être exposés à l’utilisateur final, sous quelque forme que ce soit.

Voici un exemple de configuration :

{
  "device": "/dev/dri/card1",
  "hwcursor": false,
  "pbuffers": true,
  "outputs": [
    {
      "name": "VGA1",
      "mode": "off"
    },
    {
      "name": "HDMI1",
      "mode": "1024x768"
    }
  ]
}

Ici, nous configurons l'appareil spécifié de manière à ce que :

  • Il n'utilise pas le curseur matériel (il se rabat alors sur le rendu du curseur de souris via OpenGL ; par défaut, les curseurs matériels sont activés car ils sont plus efficaces).
  • Il prenne en charge l'QOffscreenSurface ation avec des surfaces pbuffer EGL standard (par défaut, cette fonctionnalité est désactivée et une surface gbm est utilisée à la place).
  • La sortie sur le connecteur VGA est désactivée, tandis que la sortie HDMI est active avec une résolution de 1024x768.

De plus, une telle configuration désactive également la recherche d’un périphérique via ` libudev` ; à la place, le périphérique spécifié est utilisé.

Lorsque mode n’est pas défini, le mode préféré du système est sélectionné. Les valeurs acceptées pour mode sont : off, current, preferred, skip, widthxheight, widthxheight@vrefresh, ou une chaîne de caractères de ligne de modèle.

La spécification de « current » permet de choisir un mode dont la résolution correspond à celle du mode actuel. Étant donné que la configuration du mode n’est effectuée que lorsque le mode souhaité est effectivement différent du mode actif (sauf si cela est forcé via la variable d’environnement « QT_QPA_EGLFS_ALWAYS_SET_MODE »), cette valeur est utile pour conserver le mode actuel ainsi que tout contenu des plans non modifiés par Qt.

skip provoque l’ignorance du connecteur de sortie, comme s’il était déconnecté. ` off ` est similaire, mais modifie le mode et désactive l’affichage.

Comportement par défaut

Par défaut, tous les écrans signalés par la couche DRM sont traités comme un seul et même grand bureau virtuel. L'implémentation du curseur de souris en tient compte et se déplace d'un écran à l'autre comme prévu. Bien que cela ne soit pas recommandé, vous pouvez désactiver le bureau virtuel en définissant separateScreens sur false dans la configuration.

Par défaut, le bureau virtuel est formé de gauche à droite, en fonction de l’ordre des connecteurs tel qu’il est signalé par le système. Pour modifier cela, définissez ` virtualIndex ` sur une valeur commençant par 0.

Par exemple, la configuration suivante utilise la résolution préférée tout en garantissant que le côté gauche du bureau virtuel correspond à l’écran connecté au port HDMI, tandis que le côté droit correspond à l’écran connecté au port DisplayPort :

{
  "device": "drm-nvdc",
  "outputs": [
    {
      "name": "HDMI1",
      "virtualIndex": 0
    },
    {
      "name": "DP1",
      "virtualIndex": 1
    }
  ]
}

L'ordre des éléments dans le tableau n'a pas d'importance. Les sorties dont l'indice virtuel n'est pas spécifié sont placées après les autres, l'ordre d'origine de la liste des connecteurs DRM étant conservé.

Pour créer un espace de bureau vertical (c'est-à-dire pour empiler de haut en bas plutôt que de gauche à droite), ajoutez une propriété « virtualDesktopLayout » après « device » avec la valeur « vertical ».

Avertissement : il est recommandé que tous les écrans du bureau virtuel utilisent la même résolution ; sinon, des éléments tels que le curseur de la souris peuvent se comporter de manière inattendue lorsqu’ils pénètrent dans des zones qui n’existent que sur un écran donné.

Lorsque la propriété ` virtualIndex ` ne suffit pas, la propriété ` virtualPos ` peut être utilisée pour spécifier explicitement la position en haut à gauche de l’écran en question. En reprenant l’exemple précédent et en supposant une résolution de 1080p pour HDMI1, l’extrait de code suivant place un deuxième écran HDMI sous le premier :

{
   ...
  "outputs": [
    ...
    {
      "name": "HDMI2",
      "virtualPos": "0, 1080"
    }
  ]
}

Remarque : évitez ce type de configuration lorsque vous souhaitez utiliser la souris. Le comportement du curseur de la souris peut être imprévisible avec des dispositions non linéaires. L’utilisation tactile ne devrait poser aucun problème.

Détection automatique de la taille physique de l'écran

Dans certains cas, la détection automatique de la taille physique de l'écran via DRM peut échouer. Normalement, les variables d'environnement ` QT_QPA_EGLFS_PHYSICAL_WIDTH ` et ` QT_QPA_EGLFS_PHYSICAL_HEIGHT ` seraient utilisées pour fournir les valeurs manquantes. Cela n'est toutefois plus adapté en présence de plusieurs écrans. Utilisez plutôt les propriétés ` physicalWidth ` et ` physicalHeight ` de la liste ` outputs ` pour spécifier les tailles en millimètres.

Remarque : il est déconseillé d’utiliser des tailles physiquesdifférentes , et donc des DPI logiques différents, car cela peut entraîner des problèmes inattendus : certains composants de la pile graphique ne prennent pas en charge les écrans multiples et se basent uniquement sur les valeurs du premier écran.

Sorties actives et instances QScreen

Chaque sortie active du tableau ` outputs ` correspond à une instance ` QScreen ` renvoyée par la fonction ` QGuiApplication::screens()`. Par défaut, l’écran principal renvoyé par la fonction ` QGuiApplication::primaryScreen()` est celui qui a été enregistré en premier. Si vous n’utilisez pas la fonction ` virtualIndex`, cela signifie que le choix est basé sur l’ordre des connecteurs DRM. Pour contourner ce comportement, définissez la propriété ` primary ` sur ` true ` pour l’entrée souhaitée dans la liste ` outputs `.

Par exemple, pour vous assurer que l'écran correspondant à la sortie VGA reste l'écran principal même si le système signale en premier celui de la sortie HDMI, procédez comme suit :

{
  "device": "/dev/dri/card0",
  "outputs": [
      { "name": "HDMI1" },
      { "name": "VGA1", "mode": "1280x720", "primary": true },
      { "name": "LVDS1", "mode": "off" }
  ]
}

Pour le dépannage, il peut être utile d’activer les journaux de débogage du backend KMS/DRM. Pour ce faire, activez la règle de journalisation classée « qt.qpa.eglfs.kms ».

Remarque : dans un environnement embarqué, les bureaux virtuels sont plus limités que dans un système de fenêtrage complet. Il convient d’éviter les fenêtres Windows qui se chevauchent sur plusieurs écrans, les fenêtres non plein écran et le déplacement de fenêtres d’un écran à l’autre, car ces opérations risquent de ne pas fonctionner comme prévu.

Un cas d’utilisation courant

Le cas d’utilisation le plus courant et le mieux pris en charge pour une configuration multi-écrans consiste à ouvrir une fenêtre dédiée « QQuickWindow » ou « QQuickView » pour chaque écran. Avec la boucle de rendu par défaut « threaded » du graphe de scène « Qt Quick », chacune de ces fenêtres disposera de son propre thread de rendu dédié. Cela présente un avantage, car les threads peuvent être régulés indépendamment en fonction du vsync et n’interfèrent pas les uns avec les autres. Avec la boucle « basic », cela peut poser problème et entraîner une dégradation des animations.

Par exemple, la détection de tous les écrans connectés et la création d’un objet ` QQuickView ` pour chacun d’entre eux peuvent s’effectuer comme suit :

int main(int argc, char **argv)
{
    QGuiApplication app(argc, argv);

    QVector<QQuickView *> views;
    for (QScreen *screen : app.screens()) {
        QQuickView *view = new QQuickView;
        view->setScreen(screen);
        view->setResizeMode(QQuickView::SizeRootObjectToView);
        view->setSource(QUrl("qrc:/main.qml"));
        QObject::connect(view->engine(), &QQmlEngine::quit, qGuiApp, &QCoreApplication::quit);
        views.append(view);
        view->showFullScreen();
    }

    int result = app.exec();

    qDeleteAll(views);
    return result;
}

Fonctionnalités avancées d’eglfs_kms

Clonage (mise en miroir)

Le clonage d’écran (mise en miroir) est pris en charge. Cette fonctionnalité s’active via la propriété ` clones ` :

{
  "device": "/dev/dri/card0",
  "outputs": [
      { "name": "HDMI1", "mode": "1920x1080" },
      { "name": "DP1", "mode": "1920x1080", "clones": "HDMI1" }
 ]
}

Dans ce cas, le contenu affiché sur l’écran connecté via DisplayPort sera identique à celui de l’écran HDMI. Ceci est assuré par la transmission du même tampon sur les deux écrans.

Cependant, cette fonctionnalité ne peut fonctionner que si les résolutions sont identiques, s’il n’y a aucune incompatibilité au niveau des formats de tampon acceptés et si l’application n’a aucune sortie sur l’ QScreen associée à une destination de clonage. En pratique, cela signifie qu’aucun « QWindow » associé à l’ QScreen en question — DP1 dans l’exemple — ne doit jamais effectuer d’opération « QOpenGLContext::swapBuffers() ». Il appartient à la configuration et à l’application de garantir ces conditions.

Mode sans affichage utilisant le rendu DRM

Le mode « headless » via les nœuds de rendu DRM est pris en charge. Cela permet d’effectuer des calculs sur GPU (shaders de calcul OpenGL, OpenCL) ou un rendu OpenGL hors écran sans avoir besoin des privilèges de maître DRM. Dans ce mode, les applications peuvent fonctionner même lorsqu’un autre processus affiche déjà quelque chose à l’écran.

Le simple fait de remplacer device par /dev/dri/card0 par /dev/dri/renderD128 est insuffisant en soi, car certaines opérations ne peuvent pas être effectuées en mode sans affichage. Il faut donc combiner cette modification avec la propriété headless, par exemple :

{
    "device": "/dev/dri/renderD128",
    "headless": "1024x768"
}

Gardez à l’esprit que les fenêtres sont toujours redimensionnées pour s’adapter à la taille de l’écran (désormais virtuel), d’où la nécessité de spécifier une taille dans la propriété headless. Il n’y a pas non plus de limitation basée sur le vsync.

Une fois cette fonctionnalité activée, les applications disposent de deux options courantes pour effectuer un rendu hors écran en mode sans affichage :

Utiliser une fenêtre classique, telle qu’une sous-classe de ` QOpenGLWindow `, ciblant le framebuffer par défaut de la fenêtre, ce qui correspond en pratique à ` gbm_surface ` :

MyOpenGLWindow w;
w.show(); // will not actually show up on screen
w.grabFramebuffer().save("output.png");

Ou l’approche hors écran classique avec un FBO supplémentaire :

QOffscreenSurface s;
s.setFormat(ctx.format());
s.create();
ctx.makeCurrent(&s);
QOpenGLFramebufferObject fbo(1024, 768);
fbo.bind();
ctx.functions()->glClearColor(1, 0, 0, 1);
ctx.functions()->glClear(GL_COLOR_BUFFER_BIT);
fbo.toImage().save("output.png");
ctx.doneCurrent();

Sélection de l’API DRM

KMS/DRM peut être utilisé avec deux API DRM différentes : « legacy » et « atomic ». Le principal avantage de l’API DRM « atomic » est de permettre plusieurs mises à jour du plan DRM au sein d’une même boucle de rendu, alors que l’API « legacy » nécessiterait une mise à jour du plan par vsync.

L’API « atomic » est utile lorsque votre application doit fusionner du contenu dans des superpositions tout en conservant toutes les mises à jour au sein d’un même vsync. Cependant, tous les appareils ne prennent pas encore en charge cette API, qui peut s’avérer indisponible sur certains appareils plus anciens. Le backend KMS utilise par défaut l’API « legacy », mais vous pouvez activer l’API DRM « atomic » en définissant la variable d’environnement ` QT_QPA_EGLFS_KMS_ATOMIC ` sur 1.

Il peut également être utile d’utiliser un framebuffer plus petit que la résolution de l’écran. Cela est possible avec l’API atomique DRM en utilisant le paramètre ` size ` dans le fichier JSON. L’exemple ci-dessous utilise un framebuffer de 1280x720 dans un mode vidéo de 3840x2160 :

{
  "device": "/dev/dri/card0",
  "outputs": [
    { "name": "HDMI1", "mode": "3840x2160", "size": "1280x720", "format": "argb8888" }
  ]
}

Hot-plug et hot-reload EGLFS

Si un fichier de configuration KMS est défini via ` QT_QPA_EGLFS_KMS_CONFIG`, le fichier référencé sera surveillé par un ` QFileSystemWatcher`. Toute modification apportée à ce fichier déclenchera sa relecture et entraînera les mises à jour appropriées. Par exemple : changements de disposition, changements de mode, activation/désactivation d’écrans.

De la même manière, mais de façon strictement facultative, QT_QPA_EGLFS_HOTPLUG_ENABLED peut être défini et permettra à un QDeviceDiscovery de surveiller le périphérique KMS pour détecter toute modification, telle que la connexion ou la déconnexion d’écrans.

Ces deux fonctionnalités peuvent être utilisées en parallèle, ce qui est souvent le cas.

Pour gérer correctement les changements dynamiques déclenchés par le branchement à chaud et le rechargement à chaud, il est important de réagir en créant et en détruisant des fenêtres sur les écrans respectivement qui apparaissent et qui disparaissent.

Exemple de code :

#include <QGuiApplication>
#include <QQuickView>
#include <QQuickItem>
#include <QScreen>
#include <QQmlContext>

QHash<QString, QQuickView*> screenNameToViewMap;

int main(int argc, char* argv[])
{
    QGuiApplication app(argc,argv);
    app.setQuitOnLastWindowClosed(false);

    auto lRemove = [&](QScreen *screen) {
        if (screen->name().compare(QStringLiteral("qt_Headless")) == 0)
            return;

        if (!screenNameToViewMap.contains(screen->name()))
            return;

        QQuickView *view = screenNameToViewMap.take(screen->name());
        delete view;
    };

    auto lAdd = [&](QScreen *screen) {
        if (screen->handle() == nullptr)
            return;

        if (screen->name().compare(QStringLiteral("qt_Headless")) == 0)
            return;

        if (screenNameToViewMap.contains(screen->name()))
            return;

        QQuickView *view = new QQuickView;

        view->setSource(QUrl(QStringLiteral("qrc:/main.qml")));
        view->setScreen(screen);                    // This is not as important as the next line, but good practice
        view->setGeometry(screen->geometry());      // This is vital! Otherwise QWindow::show (/QWindowPrivate::create) will change the screen!
        view->show();

        screenNameToViewMap.insert(screen->name(), view);
    };

    QObject::connect(&app, &QGuiApplication::screenAdded, &app, lAdd, Qt::QueuedConnection);
    QObject::connect(&app, &QGuiApplication::screenRemoved, &app, lRemove);

    for (QScreen *screen : app.screens())
        lAdd(screen);

    return app.exec();
}

Veuillez noter dans l’exemple ci-dessus la ligne concernant ` QWindow::setGeometry` ; celle-ci est essentielle pour que les fenêtres s’affichent bien sur l’écran auquel elles sont destinées !

Comme les mêmes signaux existent également pour QML, un code équivalent peut être écrit en QML.

Il est particulièrement important d’adapter votre code pour la fonction « QT_QPA_EGLFS_HOTPLUG_ENABLED », car certains écrans se comportent comme s’ils étaient déconnectés lorsqu’ils sont éteints. Si cette fonctionnalité n’est pas activée, ni Qt ni le code au niveau de l’application ne seront informés des déconnexions. Toutes les ressources du backend resteront généralement intactes et l’écran réapparaîtra donc comme si de rien n’était. Avec l’option « QT_QPA_EGLFS_HOTPLUG_ENABLED », les ressources Qt présentes à l’écran (par exemple : QScreen, QPlatformScreen, backing-store, etc.) seront détruites puis recréées lors de la reconnexion (par exemple, lorsque l’écran est rallumé). Ainsi, les ressources au niveau de l’application (par exemple : QWindow) doivent également être recréées.

L'écran de secours appelé « qt_Headless » est là pour faciliter toute transition vers ou depuis une configuration sans écran. Pour les fenêtres au niveau de l'application, cet écran peut et doit, dans la plupart des cas, être ignoré.

EGLFS avec un backend eglfs_kms_egldevice

Ce backend, généralement utilisé sur les appareils Tegra, est similaire au backend KMS/DRM mentionné ci-dessus, à la différence qu’il s’appuie sur les extensions EGLDevice et EGLStream au lieu de GBM.

Pour plus de détails techniques sur cette approche, consultez cette présentation.

À partir de Qt 5.7, ce backend partage une grande partie de son implémentation interne avec le backend basé sur GBM. Cela signifie que la prise en charge de plusieurs écrans et la configuration avancée via ` QT_QPA_EGLFS_KMS_CONFIG ` sont assurées. Certains paramètres, tels que ` hwcursor ` et ` pbuffers `, ne sont toutefois pas applicables.

Par défaut, le backend choisit automatiquement la couche EGL appropriée pour le plan par défaut de chaque sortie. Si nécessaire, il est possible de passer outre ce comportement en définissant la variable d’environnement QT_QPA_EGLFS_LAYER_INDEX sur l’index de la couche souhaitée. Cette approche ne prend actuellement pas en charge les sorties multiples ; son utilisation doit donc être limitée aux systèmes dotés d’un seul écran. Pour connaître les couches disponibles et déboguer d’éventuels problèmes au démarrage, activez la catégorie de journalisation « qt.qpa.eglfs.kms ».

Dans certains cas, il peut être nécessaire de définir un mode vidéo au démarrage de l’application, même lorsque l’écran indique que la résolution souhaitée est déjà configurée. Cette opération est normalement optimisée et supprimée, mais si l’écran reste éteint, essayez de définir la variable d’environnement ` QT_QPA_EGLFS_ALWAYS_SET_MODE ` sur une valeur non nulle et relancez l’application.

Pour configurer le comportement de l’objet EGLStream utilisé par le backend, utilisez la variable d’environnement QT_QPA_EGLFS_STREAM_FIFO_LENGTH. Cela suppose que la fonction KHR_stream_fifo soit prise en charge par le système cible. Par défaut, le flux fonctionne en mode « mailbox ». Pour passer en mode FIFO, définissez une valeur égale ou supérieure à 1. Cette valeur spécifie le nombre maximal d’images que le flux peut contenir.

Sur certains systèmes, il peut s’avérer nécessaire de cibler un plan de superposition spécifique via un connecteur prédéfini. Le simple fait d’imposer un index de couche via QT_QPA_EGLFS_LAYER_INDEX n’effectue pas la configuration du plan et n’est donc pas suffisant en soi. Dans de tels cas particuliers, utilisez plutôt les variables d’environnement QT_QPA_EGLFS_KMS_CONNECTOR_INDEX et QT_QPA_EGLFS_KMS_PLANE_INDEX. Lorsque celles-ci sont définies, seuls le connecteur et le plan spécifiés seront utilisés ; toutes les autres sorties seront ignorées. Le backend se chargera de sélectionner la couche EGL correspondant au plan souhaité et de configurer ce dernier.

Entrées tactiles dans les systèmes à écrans multiples sous KMS/DRM

Les écrans tactiles nécessitent des précautions supplémentaires dans les systèmes multi-écrans, car les événements tactiles doivent être acheminés vers le bon écran virtuel, ce qui requiert un mappage correct entre les écrans tactiles et les sorties d’affichage.

Ce mappage s’effectue via le fichier de configuration JSON spécifié dans QT_QPA_EGLFS_KMS_CONFIG et décrit dans les sections précédentes. Lorsqu’une propriété touchDevice est présente dans un élément du tableau outputs, sa valeur est traitée comme un nœud de périphérique et le périphérique tactile est associé à la sortie d’affichage en question.

Par exemple, en supposant que notre écran tactile ait un nœud de périphérique /dev/input/event5 et qu’il s’agisse d’un écran tactile intégré au moniteur connecté via HDMI en tant qu’écran secondaire, la configuration suivante garantit une traduction correcte des événements tactiles (et de la souris synthétisée) :

 {
    "device": "drm-nvdc",
    "outputs": [
      {
        "name": "HDMI1",
        "touchDevice": "/dev/input/event5",
        "virtualIndex": 1
      },
      {
        "name": "DP1",
        "virtualIndex": 0
      }
    ]
}

Remarque : en cas de doute, activez la journalisation à la fois du sous-système graphique et du sous-système d’entrée en définissant la variable d’environnement ` QT_LOGGING_RULES=qt.qpa.*=true ` avant de lancer l’application. Cela vous aidera à identifier les nœuds de périphériques d’entrée corrects et pourra mettre au jour des problèmes de configuration de sortie qui seraient autrement difficiles à déboguer.

Remarque : à partir de Qt 5.14, ce qui précède n’est pris en charge que pour les backends evdevtouch et libinput. Les autres variantes continueront d’acheminer les événements vers l’écran principal. Pour forcer l’utilisation d’evdevtouch sur les systèmes où plusieurs backends d’entrée sont disponibles, définissez la variable d’environnement QT_QPA_EGLFS_NO_LIBINPUT sur 1.

EGLFS avec d’autres backends

Les autres backends, qui reposent généralement sur une interfaçage direct avec le framebuffer ou une API de composition via l’implémentation EGL du fournisseur, offrent généralement une prise en charge limitée, voire inexistante, des affichages multiples. Sur les cartes basées sur i.MX6 équipées de GPU Vivante, la variable d’environnement ` QT_QPA_EGLFS_FB ` peut être utilisée pour spécifier le framebuffer à cibler, de manière similaire à `linuxfb`. Sur le Raspberry Pi, la variable d’environnement ` QT_QPA_EGLFS_DISPMANX_ID ` peut être utilisée pour spécifier l’écran vers lequel l’affichage doit se faire. La valeur correspond à l’une des constantes de ` DISPMANX_ID_ ` ; reportez-vous à la documentation de Dispmanx. Notez que ces approches, contrairement à KMS/DRM, ne permettent généralement pas l’affichage sur plusieurs écrans à partir d’une même application. Par ailleurs, des variables d’environnement spécifiques au pilote ou des paramètres du noyau peuvent également être disponibles pour contrôler le framebuffer utilisé. Reportez-vous à la documentation de la carte embarquée.

Mémoire vidéo

Les systèmes disposant d’une quantité fixe de mémoire vidéo dédiée peuvent nécessiter une attention particulière avant l’exécution d’applications Qt basées sur Qt Quick ou des classes telles que QOpenGLWidget. Le paramètre par défaut peut s’avérer insuffisant pour de telles applications, en particulier lorsqu’elles s’affichent sur un écran à haute résolution (par exemple, Full HD). Dans ce cas, elles peuvent présenter des dysfonctionnements inattendus. Il est recommandé de s’assurer qu’au moins 128 Mo de mémoire GPU sont disponibles. Pour les systèmes ne disposant pas d’une quantité fixe de mémoire réservée au GPU, cela ne pose pas de problème.

linuxfb

Utilisez le paramètre du plugin « fb » pour spécifier le périphérique de framebuffer à utiliser.

Gestionnaires de signaux Unix et état de la console

Les plugins de plate-forme orientés console, tels que eglfs et linuxfb, installent par défaut des gestionnaires de signaux pour détecter les interruptions (SIGINT), la mise en veille et la reprise (SIGTSTP, SIGCONT) ainsi que la fermeture (SIGTERM). De cette manière, le clavier, le curseur du terminal et éventuellement d’autres états graphiques peuvent être restaurés lorsque l’application se termine ou est suspendue en raison de kill, ou Ctrl+C ou Ctrl+Z. (Bien que la terminaison ou la suspension via le clavier ne soit possible que lorsque QT_QPA_ENABLE_TERMINAL_KEYBOARD est défini, voir Entrées sur un périphérique Linux embarqué). Cependant, dans certains cas, la capture d’ SIGINT s peut s’avérer indésirable, car elle peut entrer en conflit avec le débogage à distance, par exemple. C’est pourquoi la variable d’environnement QT_QPA_NO_SIGNAL_HANDLER est fournie pour désactiver toute gestion intégrée des signaux.

Les gestionnaires sont installés lors de l’initialisation du plugin de plateforme, remplaçant ainsi toute configuration précédemment définie par l’application.

Avertissement : lors d’une « SIGINT » etd’une « SIGTERM » , l’état de la console est restauré et le processus se termine ensuite via « _exit() ». Aucun gestionnaire « atexit() », aucun destructeur statique ni aucun code d’arrêt Qt ne s’exécute, et les données mises en mémoire tampon ne sont pas vidées. « systemctl stop » ou un simple « kill » met donc immédiatement fin à l’application. Une application qui doit conserver son état lors d’un arrêt via SIGTERM doit définir QT_QPA_NO_SIGNAL_HANDLER et installer son propre gestionnaire, en se chargeant également de restaurer l’état de la console.

L’état de la console n’est restauré que via ces chemins et lors d’un arrêt normal. Il n’est pas restauré lorsque le processus se termine de manière anormale via SIGSEGV, SIGABRT ou std::terminate(). Avec linuxfb, qui bascule également le terminal virtuel en mode graphique, une application qui se termine de manière anormale peut laisser la console locale vide et insensible aux entrées clavier jusqu’au redémarrage de l’appareil. Sur les appareils où cette console constitue la seule voie de récupération locale, prévoyez une alternative, telle qu’une console série ou un chien de garde (watchdog) qui redémarre l’appareil. Utilisez ` QT_QPA_PRESERVE_CONSOLE_STATE ` pour conserver les paramètres par défaut du curseur du terminal et de la mise en veille de l’écran, et ` nographicsmodeswitch ` de linuxfb pour ignorer le passage en mode graphique.

Considérations de sécurité

Les plugins de plate-forme décrits sur cette page s’exécutent sans système de fenêtrage et assument donc les responsabilités qui incombent normalement à un compositeur ou à un serveur d’affichage. Cette section décrit ce à quoi ils font confiance et ce qu’un créateur de périphérique est censé contrôler. Voir également le modèle de sécurité partagée de Qt.

La configuration est un contenu de confiance

Le comportement des plugins de plateforme embarqués — quels nœuds de périphérique sont ouverts, quel plugin d’intégration de périphérique est chargé dans le processus, comment les coordonnées tactiles sont mappées sur les écrans — est déterminé par des variables d’environnement, par le fichier de configuration JSON KMS/DRM, ainsi que par les fichiers optionnels de configuration du clavier et de l’atlas de curseurs. Tous ces éléments constituent du contenu de confiance : ils sont censés être figés lors de la compilation de l’image du périphérique, puis contrôlés par le créateur du périphérique par la suite. Qt vérifie qu’ils sont bien formés, mais n’effectue aucune validation supplémentaire, et ils ne sont en aucun cas destinés à être exposés à l’utilisateur final du périphérique.

Deux entrées méritent une attention particulière :

  • QT_QPA_EGLFS_INTEGRATION ne limite pas les plugins pouvant être chargés. Le backend demandé est simplement placé en tête de la liste des candidats ; s’il ne parvient pas à s’initialiser, les backends restants sont tout de même essayés à tour de rôle. Sur un système comportant plusieurs plugins d’intégration de périphériques, un backend non spécifié lors du déploiement peut finir par être chargé et initialiser le matériel. Ne fournissez que les backends dont le périphérique a besoin.
  • Le calibrage tactile et la rotation, qu’ils soient définis via QT_QPA_LIBINPUT_TOUCH_MATRIX, les paramètres evdev, rotate, invertx et inverty, ou le mappage touchDevice dans le fichier de configuration JSON, déterminent où une pression est signalée. Un paramètre incorrect signifie que l’utilisateur active une commande différente de celle qu’il a touchée, ce qui, dans une interface homme-machine, constitue une propriété de sécurité. Considérez ces paramètres comme faisant partie de la configuration vérifiée de l’appareil plutôt que comme des réglages modifiables sur le terrain.

Les périphériques d’entrée ne sont pas filtrés

La détection des périphériques de Qt ouvre chaque nœud /dev/input/event* correspondant à la classe de capacité recherchée et, lorsque la prise en charge d’ libudev est disponible, ouvre également les périphériques qui apparaissent ultérieurement pendant l’exécution de l’application. Il n’existe pas de liste blanche, pas de filtre par fabricant ou par produit, ni de notion d’ensemble de périphériques attendus. Les événements provenant de chaque périphérique accepté sont transmis à l’application comme s’ils provenaient du périphérique prévu ; l’application ne peut pas les distinguer.

Il incombe donc au créateur du périphérique de restreindre quels périphériques existent et qui est autorisé à les lire ; cette restriction s’effectue au niveau du noyau, de la fonction ` udev ` et des permissions du système de fichiers, plutôt qu’au niveau de l’application. Une application Qt qui n’est pas autorisée à lire ` /dev/input/* ` ne lit aucune entrée. De plus :

  • Nommer explicitement les périphériques dans ` QT_QPA_EVDEV_MOUSE_PARAMETERS`, ` QT_QPA_EVDEV_KEYBOARD_PARAMETERS ` et ` QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS ` contourne la détection et fixe l’ensemble de périphériques utilisé par l’application.
  • Le passage de grab=1 confère à l’application un accès exclusif à un périphérique, ce qui mérite d’être pris en compte sur un périphérique exécutant une seule application.
  • En savoir plus sur ` disable-zap` : voir « Entrées sur un appareil Linux embarqué ».

Les écrans constituent une source d’entrée non fiable

Le bloc EDID qu’un écran transmet via le connecteur est fourni par le périphérique connecté, qu’il s’agisse d’un moniteur, d’un adaptateur, d’un commutateur KVM ou d’un périphérique de capture, et il est réanalysé à chaque événement de connexion à chaud. Sur eglfs avec le backend KMS/DRM, les valeurs qu’il contient parviennent à l’application via ` QScreen::manufacturer()`, ` QScreen::model()`, ` QScreen::serialNumber()` et la taille physique signalée. Considérez ces valeurs comme influencées par des facteurs externes : ne les utilisez pas comme identifiant et sachez qu’elles peuvent apparaître dans les journaux. La taille physique peut être redéfinie à l’aide de ` QT_QPA_EGLFS_PHYSICAL_WIDTH ` et ` QT_QPA_EGLFS_PHYSICAL_HEIGHT`, ou par sortie dans le fichier de configuration JSON.

Dépendances d’exécution

Les plugins de plate-forme intégrés sont des adaptateurs légers sur des bibliothèques fournies par le pack de support de la carte ou la distribution, et non par Qt, et qui s’exécutent dans le processus de l’application. Selon la configuration, il s’agit de :

  • eglfs: EGL et, selon le backend, GBM, Mesa et le pilote GPU, ou une implémentation EGL propriétaire ; libdrm pour les backends KMS/DRM.
  • vkkhrdisplay: le chargeur Vulkan et les pilotes Vulkan installés.
  • linuxfb: l’interface d’ fbdev du noyau, ou libdrm lorsque l’option « QT_QPA_FB_DRM » est activée.
  • Entrée: libinput, libudev et mtdev; xkbcommon, qui lit en outre les données de configuration du clavier à partir du système ; ou tslib, dont le fichier de configuration détermine quels modules de filtrage sont chargés, et que Qt ne peut donc ni sélectionner ni répertorier.

Intégrez-les dans la nomenclature logicielle de l’appareil et tenez-les à jour, puis configurez Qt en n’utilisant que les backends dont l’appareil a réellement besoin. Pour les nouveaux appareils, privilégiez libinput plutôt que l’ancienne version tslib.

Polices

Qt utilise normalement fontconfig pour donner accès aux polices système. Si fontconfig n’est pas disponible, Qt se rabattra sur QBasicFontDatabase. Dans ce cas, les applications Qt rechercheront les polices dans le répertoire lib/fonts de Qt. Qt détectera automatiquement les polices pré-rendues et les polices TrueType. Ce répertoire peut être redéfini en définissant la variable d’environnement QT_QPA_FONTDIR.

Pour plus d’informations sur les formats pris en charge, consultez la section « Qt for Embedded Linux Fonts ».

Remarque : Qt ne fournit plus aucune police dans le répertoire lib/fonts. Cela signifie qu’il incombe à la plate-forme (l’image système) de fournir les polices nécessaires.

Plug-ins de plate-forme pour les systèmes de fenêtrage sur les appareils Linux embarqués

XCB

Il s’agit du plugin X11 utilisé sur les plateformes Linux de bureau classiques. Dans certains environnements embarqués fournissant X et les fichiers de développement nécessaires pour xcb, ce plugin fonctionne exactement comme sur un PC de bureau classique.

Remarque : sur certains appareils, la prise en charge d’EGL et d’OpenGL n’est pas disponible sous X, car l’implémentation d’EGL n’est pas compatible avec Xlib. Dans ce cas, le plugin XCB est compilé sans prise en charge d’EGL, ce qui signifie que Qt Quick 2 ou d’autres applications basées sur OpenGL ne fonctionnent pas avec ce plugin de plateforme. Il peut toutefois être utilisé pour exécuter des applications utilisant un rendu logiciel (basées sur QWidget par exemple).

En règle générale, l’utilisation de XCB sur des appareils embarqués n’est pas recommandée. Des plugins tels que eglfs sont susceptibles d’offrir de meilleures performances et une accélération matérielle.

Wayland

Wayland est un système de fenêtrage léger ; ou plus précisément, il s’agit d’un protocole permettant aux clients de communiquer avec un serveur d’affichage.

Qt Wayland fournit un plugin de plateforme wayland qui permet aux applications Qt de se connecter à un compositeur Wayland.

Pour plus de détails, consultez Wayland et Qt.

Recommandations pour améliorer les performances

Utilisez le rendu matériel dans la mesure du possible

Lorsque les performances sont essentielles pour votre application, évitez d'utiliser des modules Qt qui reposent sur le rendu logiciel. Privilégiez plutôt les modules qui s'appuient sur le rendu matériel, dans la mesure du possible.

Suivez les bonnes pratiques pour Qt Quick

Suivez les bonnes pratiques pour QML et Qt Quick, notamment en ce qui concerne l’intégration de l’API CMake de QML, afin que qmllint, le compilateur de scripts QML (qmlsc) et le compilateur de types QML (qmltc) soient disponibles. De plus, il est préférable d’écrire du code QML déclaratif et de réduire au minimum l’utilisation de JavaScript. Pour plus d’informations sur l’impact que peut avoir une utilisation excessive de JavaScript sur les performances, consultez la section « Considérations et suggestions relatives aux performances de QML ».

Utilisez des images/textures et des effets de shader à la place du type QML « Canvas »

Pour dessiner des éléments d'interface utilisateur personnalisés, utilisez des images/textures et des effets de shader. N'utilisez pas le type QML « Canvas ». Les shaders nécessitent une accélération matérielle (GPU).

Utilisez « Qt Quick » plutôt que Qt Widgets

Avec ` Qt Quick`, il est possible d’utiliser soit un backend avec accélération matérielle, soit un backend avec rendu logiciel. Pour les interfaces utilisateur complexes, l’utilisation de ` Qt Widgets ` sur des cibles embarquées n’est pas recommandée, car cela entraînera systématiquement l’utilisation d’un backend logiciel.

Il y a ici des compromis à faire :

  • L'utilisation du moteur QML et de ` Qt Quick ` entraîne une surcharge initiale.
  • Si votre interface utilisateur est très simple et ne se rafraîchit que rarement, elle peut s'avérer plus rapide lorsqu'elle est implémentée à l'aide de widgets plutôt qu'en QML.
  • Si votre interface utilisateur tire parti des animations, d’ smooth scrolling, d’ scaling, d’ rendering effects ou de la 3D, vous devez disposer d’une accélération GPU, et donc d’ Qt Quick.

Choisissez une résolution adaptée à la taille de votre interface utilisateur

La prudence est de mise avec les résolutions élevées. Les résolutions de 720p et supérieures peuvent réduire les performances.

Utilisez un élément de type « QML Window » comme élément racine de votre application

Utilisez une « Window » comme élément racine de votre application avec l’arrière-plan de l’ color.

La raison en est qu'un composant « Window » dispose d'une propriété « color » qui a pour effet d'effacer le tampon. Le rendu de l'arrière-plan à l'aide d'une « Rectangle » en plein écran comme élément racine de l'Item entraînerait un appel de dessin supplémentaire. Pour certains backends RHI, cela peut revenir au même, mais il existe une différence entre un appel « glClear » et le dessin d’un quadrilatère. Dans la plupart des cas, une image opaque unique n’aura probablement pas d’impact significatif sur les performances, mais si vous utilisez une valeur alpha dans la couleur de cet élément, vous pourriez constater une baisse significative des performances.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.