Auf dieser Seite

Qt für Embedded Linux

Plattform-Plugins für Embedded-Linux-Geräte

Auf Embedded-Linux-Systemen stehen mehrere Plattform-Plugins zur Verfügung: EGLFS, VkKhrDisplay, LinuxFB oder Wayland. Die Verfügbarkeit dieser Plugins hängt davon ab, wie Qt konfiguriert ist. Von diesen erfordert Wayland das Vorhandensein eines Compositors und bietet ein vollständiges Fenstersystem, das mehrere Fenster unterstützt, ähnlich wie X11 oder Windows. Die anderen funktionieren ohne Fenstersystem, was bedeutet, dass die Qt-Anwendung die volle Kontrolle über das Rendering und die Ausgabe hat. Sie unterstützen in der Regel ein Qt-„Fenster“ im Vollbildmodus pro Bildschirm.

EGLFS ist auf vielen Grafikkarten das Standard-Plugin. Sollte es nicht geeignet sein, verwenden Sie die Umgebungsvariable ` QT_QPA_PLATFORM `, um ein anderes Plugin anzugeben. Alternativ können Sie für schnelle Tests das Befehlszeilenargument ` -platform ` mit derselben Syntax verwenden.

Hinweis: Ab Qt 5.0 verfügt Qt nicht mehr über eine eigene Implementierung des Fenstersystems (QWS). Für Anwendungsfälle mit einem einzigen Prozess ist die Qt Platform Abstraction die bessere Lösung; Anwendungsfälle mit mehreren Prozessen werden über Wayland unterstützt.

Unter „Konfigurieren eines Embedded-Linux-Geräts“ finden Sie eine Übersicht über die Konfiguration von Qt für die Cross-Kompilierung mit einer Embedded-Linux-Toolchain.

EGLFS

EGL ist eine Schnittstelle zwischen OpenGL und dem nativen Fenstersystem. Qt kann EGL für die Kontext- und Oberflächenverwaltung nutzen, allerdings enthält die API keine plattformspezifischen Elemente. Das Erstellen eines nativen Fensters – das nicht unbedingt ein tatsächliches Fenster auf dem Bildschirm sein muss – muss weiterhin mit plattformspezifischen Mitteln erfolgen. Aus diesem Grund benötigen wir den board- oder GPU-spezifischen Anpassungscode. In der Regel werden diese Anpassungen wie folgt bereitgestellt:

  • EGLFS-Hooks– eine einzelne Quelldatei, die in das Plattform-Plugin kompiliert wird
  • EGL-Geräteintegration– dynamisch geladene Plugins

EGLFS ist ein Plattform-Plugin zur Ausführung von Qt-Anwendungen auf Basis von EGL und OpenGL ES 2.0 ohne ein eigentliches Fenstersystem wie X11 oder Wayland. Es ist das empfohlene Plugin für moderne Embedded-Linux-Geräte, die über eine GPU verfügen.

Neben „ Qt Quick “- und nativen OpenGL-Anwendungen unterstützt EGLFS auch softwaregerenderte Fenster wie „ QWidget “. Bei „ QWidget “ werden die Inhalte der Widgets mithilfe der CPU in Bilder gerendert, die anschließend in Texturen geladen und vom Plugin zusammengesetzt werden.

EGLFS erzwingt, dass das erste Fenster der obersten Ebene – entweder ein „ QWidget “ oder ein „ QQuickView“ – im Vollbildmodus angezeigt wird. Dieses Fenster wird zudem als Root-Widget-Fenster ausgewählt, in das alle anderen Widgets der obersten Ebene zusammengesetzt werden. Beispiele hierfür sind Dialoge, Popup-Menüs oder Kombinationsfelder. Dieses Verhalten ist notwendig, da es bei EGLFS immer genau ein natives Fenster und eine EGL-Fensteroberfläche gibt; diese gehören zu dem Widget oder Fenster, das zuerst erstellt wird. Dieser Ansatz funktioniert gut, wenn es ein Hauptfenster gibt, das für die gesamte Laufzeit der Anwendung besteht, und alle anderen Widgets entweder nicht auf oberster Ebene liegen oder erst danach erstellt werden, sobald das Hauptfenster angezeigt wird.

Für OpenGL-basierte Fenster gelten weitere Einschränkungen. EGLFS unterstützt (ab Qt 5.3) ein einzelnes GL-Vollbildfenster, wie z. B. OpenGL-basierte „ QWindow “, „ QQuickView “ oder „ QOpenGLWidget “. Das Öffnen weiterer OpenGL-Fenster oder das Mischen solcher Fenster mit Inhalten auf Basis von „ QWidget “ wird nicht unterstützt; Qt beendet die Anwendung mit einer Fehlermeldung.

Darüber hinaus werden APIs, die für Desktop-Plattformen oder Umgebungen mit einem Fenstersystem entwickelt wurden, wie beispielsweise Drag & Drop, auf EGLFS nicht unterstützt.

Von EGLFS verwendete Umgebungsvariablen

Bei Bedarf kann „ eglfs “ mithilfe der folgenden Umgebungsvariablen konfiguriert werden:

UmgebungsvariableBeschreibung
QT_QPA_EGLFS_INTEGRATIONZusätzlich zu den fest eingebauten Hooks ist es auch möglich, dynamisch geladene Plugins zu verwenden, um geräte- oder herstellerspezifische Anpassungen vorzunehmen. Diese Umgebungsvariable erzwingt die Verwendung eines bestimmten Plugins. Wird sie beispielsweise auf `eglfs_kms` gesetzt, wird das KMS/DRM-Backend verwendet. Dies ist nur dann eine Option, wenn in den Geräte-Makespecs keine statischen oder fest integrierten Hooks angegeben wurden. In der Praxis werden die traditionellen fest integrierten Hooks nur noch selten verwendet; fast alle Backends sind mittlerweile auf Plugins umgestellt. Die Geräte-Makespecs enthalten weiterhin einen entsprechenden, wenn auch optionalen Eintrag für „ EGLFS_DEVICE_INTEGRATION “: den Namen des bevorzugten Backends für das jeweilige Gerät. Vermeiden Sie es, diese Umgebungsvariable zu setzen, wenn auf dem Zielsystem mehr als ein Plugin vorhanden ist. In einer Desktop-Umgebung werden je nach Vorhandensein der Umgebungsvariable „ DISPLAY “ die KMS- oder X11-Backends priorisiert.

Hinweis: Auf einigen Boards wird anstelle eines tatsächlichen Plugins ein spezieller Wert für ` none ` verwendet. Dies bedeutet, dass für die Verwendung von EGL mit dem Framebuffer keine spezielle Integration erforderlich ist; es müssen keine Plugins geladen werden.

QT_QPA_EGLFS_PHYSICAL_WIDTH und QT_QPA_EGLFS_PHYSICAL_HEIGHTGibt die physische Breite und Höhe des Bildschirms in Millimetern an. Beachten Sie, dass seit Qt 6 die physische Bildschirmgröße nicht mehr zur Bestimmung der logischen dpi herangezogen wird.
QT_QPA_EGLFS_ROTATIONLegt die Drehung fest, die auf softwaregerenderte Inhalte in „ QWidget “-basierten Anwendungen angewendet wird. Unterstützte Werte sind 180, 90 und -90. Diese Variable gilt nicht für OpenGL-basierte Fenster, einschließlich „ Qt Quick “. „ Qt Quick “-Anwendungen können stattdessen Transformationen in ihrer QML-Szene anwenden. Der Standard-Mauszeiger eglfs berücksichtigt den Wert stets und zeigt ein entsprechend positioniertes und gedrehtes Zeigerbild an, unabhängig vom Anwendungstyp. Spezielle Zeigerimplementierungen, wie beispielsweise der Hardware-Zeiger des KMS/DRM-Backends, unterstützen die Drehung jedoch möglicherweise nicht. Diese Einstellung hat keinerlei Auswirkungen auf andere Bereiche, einschließlich der Touch-Eingabe. Die Touch-Eingabe-Backends evdevtouch und libinput verfügen jeweils über eigene Mechanismen zur Konfiguration der Drehung. Weitere Informationen zur Konfiguration der Touch-Eingabe finden Sie unter „Inputs on an Embedded Linux Device “.
QT_QPA_EGLFS_FORCEVSYNCWenn diese Option gesetzt ist, fordert „ eglfs “ nach jedem Aufruf von `eglSwapBuffers()` den Wert von ` FBIO_WAITFORVSYNC ` auf dem Framebuffer-Gerät an. Diese Variable ist nur für Backends relevant, die auf das veraltete Linux-Subsystem „ fbdev “ zurückgreifen. Normalerweise geht Qt bei einem Standard-Swap-Intervall von 1 davon aus, dass der Aufruf von `eglSwapBuffers()` die Vsync-Synchronisation übernimmt; sollte dies nicht der Fall sein (beispielsweise aufgrund von Treiberfehlern), versuchen Sie, ` QT_QPA_EGLFS_FORCEVSYNC ` auf einen Wert ungleich Null zu setzen.
QT_QPA_EGLFS_FORCE888Ist diese Option gesetzt, werden die Größen der roten, grünen und blauen Farbkanäle ignoriert, wenn „ eglfs “ einen neuen Kontext, ein neues Fenster oder eine neue Off-Screen-Oberfläche erstellt. Stattdessen fordert das Plugin eine Konfiguration mit 8 Bit pro Kanal an. Dies kann auf Geräten hilfreich sein, auf denen standardmäßig Konfigurationen mit weniger als 32 oder 24 Bit pro Pixel (z. B. 5-6-5 oder 4-4-4) gewählt werden, obwohl bekannt ist, dass diese nicht ideal sind, beispielsweise aufgrund von Streifenbildung. Anstatt den Anwendungscode zu ändern, bietet diese Variable eine Abkürzung, um Konfigurationen mit 24 oder 32 bpp zu erzwingen.

Darüber hinaus stehen die folgenden, seltener verwendeten Variablen zur Verfügung:

UmgebungsvariableBeschreibung
QT_QPA_EGLFS_FBÜberschreibt das Framebuffer-Gerät. Der Standardwert ist „ /dev/fb0 “. Auf den meisten Embedded-Plattformen ist diese Variable nicht besonders relevant, da der Framebuffer nur zur Abfrage von Einstellungen wie den Bildschirmauflösungen verwendet wird. Auf bestimmten Geräten bietet diese Variable jedoch die Möglichkeit, bei Konfigurationen mit mehreren Bildschirmen anzugeben, welcher Bildschirm verwendet werden soll – ähnlich wie der Parameter „ fb “ in LinuxFB.
QT_QPA_EGLFS_WIDTH und QT_QPA_EGLFS_HEIGHTEnthält die Breite und Höhe des Bildschirms in Pixeln. Zwar versucht ` eglfs `, die Abmessungen über das Framebuffer-Gerät `/dev/fb0` zu ermitteln, doch funktioniert dies nicht immer. Es kann erforderlich sein, die Größen manuell anzugeben.
QT_QPA_EGLFS_DEPTHÜberschreibt die Farbtiefe für den Bildschirm. Auf Plattformen, auf denen das Framebuffer-Gerät /dev/fb0 nicht verfügbar ist oder die Abfrage fehlschlägt, wird der Standardwert „ 32 “ verwendet. Verwenden Sie diese Variable, um solche Standardwerte zu überschreiben.

Hinweis: Diese Variable wirkt sich nur auf den von QScreen gemeldeten Wert für die Farbtiefe aus. Sie steht in keinem Zusammenhang mit EGL-Konfigurationen und der für das OpenGL-Rendering verwendeten Farbtiefe.

QT_QPA_EGLFS_SWAPINTERVALStandardmäßig wird ein Swap-Intervall von ` 1 ` angefordert. Diese Variable ermöglicht die Synchronisation mit der vertikalen Bildwiederholfrequenz des Bildschirms. Verwenden Sie diese Variable, um den Wert des Swap-Intervalls zu überschreiben. Wenn Sie beispielsweise den Wert 0 übergeben, wird das Blockieren beim Swap deaktiviert, was dazu führt, dass der Prozess ohne jegliche Synchronisation so schnell wie möglich ausgeführt wird.
QT_QPA_EGLFS_DEBUGWenn diese Option gesetzt ist, werden einige Debugging-Informationen in der Debug-Ausgabe angezeigt. Beispielsweise werden beim Erstellen eines neuen Kontexts der Eingabewert „ QSurfaceFormat “ sowie die Eigenschaften der ausgewählten EGL-Konfiguration ausgegeben. In Verbindung mit der Variablen „ QSG_INFO “ von Qt Quick erhalten Sie nützliche Informationen zur Fehlerbehebung bei Problemen im Zusammenhang mit der EGL-Konfiguration.

Protokollierung

Neben ` QT_QPA_EGLFS_DEBUG` unterstützt ` eglfs ` auch das moderne, kategorisierte Protokollierungssystem von Qt. Die folgenden Protokollierungskategorien stehen zur Verfügung:

  • qt.qpa.egldeviceintegration – Aktiviert die Protokollierung für dynamisch geladene Backends. Verwenden Sie diese Kategorie, um zu überprüfen, welches Backend gerade verwendet wird.
  • qt.qpa.input – Aktiviert die Debug-Ausgabe sowohl vom Eingabe-Handler „ evdev “ als auch vom Eingabe-Handler „ libinput “. Verwenden Sie diese Kategorie, um zu überprüfen, ob ein bestimmtes Eingabegerät erkannt und geöffnet wurde.
  • qt.qpa.eglfs.kms – Aktiviert die ausführliche Protokollierung im KMS/DRM-Backend.

Nachdem Sie ` configure` ausgeführt haben, überprüfen Sie unbedingt die Ausgabe. Dies ist der einfachste und schnellste Weg, um festzustellen, ob das erforderliche EGLFS-Backend, libudev oder libinput aktiviert ist. Kurz gesagt: Wenn in der Ausgabe von ` configure ` ein unerwünschtes „no“ erscheint, führen Sie Folgendes aus:

./configure -v

um die ausführliche Ausgabe zu aktivieren, sodass Sie die Compiler- und Linker-Aufrufe für jeden „configure“-Test sehen können.

Hinweis: Wenn Fehlermeldungen wegen fehlender Header, Bibliotheken oder scheinbar kryptischer Linker-Fehler auftreten, deuten diese oft auf ein unvollständiges oder beschädigtes sysroot hin und stehen in keinem Zusammenhang mit Qt.

Wenn Sie beispielsweise den Raspberry Pi mit den proprietären Broadcom-Grafiktreibern als Zielplattform festlegen, sollte die Ausgabe in etwa wie folgt aussehen:

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

Ist dies nicht der Fall, ist es nicht ratsam, mit dem Build fortzufahren, da die Grafikbeschleunigung ohne das Raspberry-Pi-spezifische Backend nicht funktionieren wird, selbst wenn der Rest von Qt erfolgreich kompiliert wird.

VkKhrDisplay

Während EGLFS nur OpenGL (ES) unterstützt, ist VkKhrDisplay ein experimentelles Plattform-Plugin, das das Rendern mit der Vulkan-API unterstützt. Zum Aufzählen von Displays und zum Einrichten des Renderings stützt es sich auf die Erweiterungsfamilie VK_KHR_display. Beachten Sie, dass es nicht selbstverständlich ist, dass eine Vulkan-Implementierung innerhalb eines Grafikstacks diese Funktionalität unterstützt. Derzeit wurde dieses Plattform-Plugin mit Mesa und V3DV auf einem Raspberry Pi 4 verifiziert und getestet.

Dieses Plattform-Plugin unterstützt weder OpenGL noch Software-Rendering. Der Versuch, eine auf „ QWidget “ basierende Benutzeroberfläche anzuzeigen, schlägt daher fehl. Der einzige unterstützte Oberflächentyp für „ QWindow “ ist „ QSurface::VulkanSurface “. Für Anwendungen unter „ Qt Quick “ bedeutet dies, dass das Vulkan-basierte Rendering entweder durch die Einstellung von „ QSG_RHI_BACKEND=vulkan “ in der Umgebung oder durch den Aufruf von „ QQuickWindow::setGraphicsApi “ (QSGRendererInterface::Vulkan) erzwungen werden muss – und zwar frühzeitig, bevor ein „ QQuickWindow “ oder „ QQuickView “ erstellt wird.

Um dieses Plattform-Plugin zu verwenden, führen Sie die Anwendung mit „ -platform vkkhrdisplay “ aus oder setzen Sie „ QT_QPA_PLATFORM “ auf „ vkkhrdisplay “. Das Plugin wird nur erstellt, wenn Qt mit Vulkan-Unterstützung konfiguriert ist.

Erweiterte Konfigurationen im EGLFS-Stil (z. B. die JSON-Konfigurationsdatei) oder die Ausgabe auf mehrere Bildschirme aus derselben Anwendung sind derzeit nicht implementiert. Anwendungen können jedoch über Umgebungsvariablen den zu verwendenden Bildschirm auswählen.

Um die Indexwerte zu ermitteln, überprüfen Sie die vom Plugin in der Debug-Ausgabe ausgegebenen Protokolle. Derzeit sind diese Protokolle nicht kategorisiert (Ausgabe über ` qDebug`), da ihre Überprüfung in den meisten Fällen unerlässlich ist, um sicherzustellen, dass das Plugin das richtige Display und den richtigen Modus auswählt.

  • QT_VK_DISPLAY_INDEX - Wenn diese Option gesetzt ist, wird das Display mit dem angegebenen Index verwendet.
  • QT_VK_MODE_INDEX - Wenn diese Option gesetzt ist, wird der Modus mit dem angegebenen Index verwendet.
  • QT_VK_PHYSICAL_DEVICE_INDEX - Wenn diese Option gesetzt ist, wird das Vulkan-Hardwaregerät mit dem angegebenen Index verwendet. Dies ist in den meisten Fällen bei Embedded-Systemen nicht relevant. Beachten Sie, dass diese Variable auch vom restlichen Qt-Grafik-Stack verwendet wird.

Die Eingabeverarbeitung (Tastatur, Maus, Touch) ähnelt der von EGLFS und unterstützt „ evdev “, „ libinput “ sowie „ tslib “. Eine Darstellung des Mauszeigers ist jedoch nicht implementiert. Dies liegt daran, dass es in dieser Umgebung kein Konzept eines Hardware-Cursors gibt und die Darstellung eines Cursors mit Vulkan innerhalb des Plattform-Plugins – ähnlich wie bei EGLFS mit OpenGL – aus mehreren Gründen problematisch ist. Daher ist dieses Plattform-Plugin derzeit nicht gut für mausbasierte Eingaben geeignet.

Die zugehörigen Umgebungsvariablen lauten:

  • QT_QPA_DISABLE_INPUT - Deaktiviert Tastatur-, Maus- und Touch-Eingaben.
  • QT_QPA_NO_LIBINPUT - Bevorzugt die evdev-basierten Eingabehandler, selbst wenn libinput verfügbar ist.
  • QT_QPA_TSLIB - Fordert die Verwendung der veralteten tslib -Bibliothek an.

LinuxFB

Dieses Plugin schreibt über das fbdev-Subsystem von Linux direkt in den Framebuffer. Es werden ausschließlich softwaregerenderte Inhalte unterstützt. Beachten Sie, dass die Anzeigeleistung bei einigen Konfigurationen voraussichtlich eingeschränkt ist. Um „ Qt Quick “-Anwendungen mit diesem Plattform-Plugin zu verwenden, muss das „ software “-Scenegraph-Backend verwendet werden, entweder durch Setzen von „ QT_QUICK_BACKEND=software “ in der Umgebung oder durch Aufruf von „ setGraphicsApi()“ mit „ QSGRendererInterface::Software “. „ QWidget “-Anwendungen oder „ QWindow “ mit einem Oberflächentyp von „ QSurface::RasterSurface “ werden unterstützt, dies schließt jedoch spezielle Widgets wie „ QOpenGLWidget “ nicht ein.

Da fbdev im Linux-Kernel als veraltet gilt, ist auch die Unterstützung für DRM-Dumb-Buffer verfügbar. Um diese zu nutzen, setzen Sie die Umgebungsvariable „ QT_QPA_FB_DRM “ auf einen Wert ungleich Null. Ist diese Variable gesetzt und werden „Dumb Buffers“ von Ihrem System unterstützt, wird nicht auf ältere Framebuffer-Geräte wie /dev/fb0 zugegriffen. Stattdessen erfolgt die Darstellung über die DRM-APIs, ähnlich wie beim Backend „ eglfs_kms “ in EGLFS. Die Ausgabe erfolgt doppelt gepuffert und mit Seitenwechsel, wodurch auch für softwaregerenderte Inhalte eine korrekte Vsync-Synchronisation gewährleistet ist.

Hinweis: Bei Verwendung von „dumb buffers“ sind keine der unten beschriebenen Optionen anwendbar, da Eigenschaften wie die physische und logische Bildschirmgröße automatisch abgefragt werden.

Festlegen zusätzlicher Einstellungen

Das Plugin „ linuxfb “ ermöglicht es Ihnen, zusätzliche Einstellungen über die Umgebungsvariable „ QT_QPA_PLATFORM “ oder die Befehlszeilenoption „ -platform “ festzulegen. Beispielsweise legt „ QT_QPA_PLATFORM=linuxfb:fb=/dev/fb1 “ fest, dass anstelle des Standardgeräts „ fb0 “ das Framebuffer-Gerät „ /dev/fb1 “ verwendet werden soll. Um mehrere Einstellungen anzugeben, trennen Sie diese durch einen Doppelpunkt (:).

EinstellungenBeschreibung
fb=/dev/fbNLegt die Framebuffer-Geräte fest. Bei Konfigurationen mit mehreren Bildschirmen ermöglicht diese Einstellung die Ausführung der Anwendung auf verschiedenen Bildschirmen. Derzeit gibt es keine Möglichkeit, mehrere Framebuffer aus einer Qt-Anwendung heraus zu nutzen.
size=<width>x<height>Legt die Bildschirmgröße in Pixeln fest. Das Plugin versucht, die physikalischen und logischen Bildschirmabmessungen vom Framebuffer-Gerät abzufragen. Diese Abfrage führt jedoch möglicherweise nicht immer zu korrekten Ergebnissen; daher kann es erforderlich sein, die Werte explizit anzugeben.
mmsize=<width>x<height>Gibt die physikalische Breite und Höhe in Millimetern an.
offset=<width>x<height>Gibt den Versatz der oberen linken Ecke des Bildschirms in Pixeln an. Die Standardposition ist „ (0, 0) “.
nographicsmodeswitchLegt fest, dass das virtuelle Terminal nicht in den Grafikmodus (KD_GRAPHICS) umgeschaltet wird. Normalerweise werden durch die Aktivierung des Grafikmodus der blinkende Cursor und die Bildschirmausblendung deaktiviert. Wenn dieser Parameter jedoch gesetzt ist, werden diese beiden Funktionen ebenfalls übersprungen.
tty=/dev/ttyNÜberschreibt die virtuelle Konsole. Wird nur verwendet, wenn „ nographicsmodeswitch “ nicht gesetzt ist.

Ab Qt 5.9 wurde das Verhalten von EGLFS und LinuxFB hinsichtlich der Fenstergrößenregelung synchronisiert: Das erste Fenster der obersten Ebene wird bei beiden Plattform-Plugins so eingestellt, dass es den gesamten Bildschirm ausfüllt. Wenn dies nicht gewünscht ist, setzen Sie die Umgebungsvariable „ QT_QPA_FB_FORCE_FULLSCREEN “ auf „ 0 “, um das Verhalten früherer Qt-Versionen wiederherzustellen.

Anzeigeausgabe

Der Umfang der Unterstützung für die Ansteuerung eines oder mehrerer Bildschirme durch eine einzelne Qt-Anwendung variiert je nach Plattform-Plugin. Die Unterstützung hängt oft vom Gerät und dessen Grafikstack ab.

EGLFS mit dem eglfs_kms-Backend

Wenn das KMS/DRM-Backend verwendet wird, meldet EGLFS alle verfügbaren Bildschirme über ` QGuiApplication::screens()`. Anwendungen können über ` QWindow::setScreen()` verschiedene Fenster auf unterschiedlichen Bildschirmen anzeigen.

Hinweis: Die Einschränkung auf ein einziges Vollbildfenster pro Bildschirm gilt weiterhin. Ein Wechsel des Bildschirms, nachdem „ QWindow “ sichtbar gemacht wurde, wird ebenfalls nicht unterstützt. Daher ist es unerlässlich, dass eingebettete Anwendungen alle erforderlichen „ QWindow::setScreen()“-Aufrufe ausführen, bevor sie „ QWindow::show()“ aufrufen.

Wenn Sie mit der Entwicklung auf einem bestimmten eingebetteten Gerät beginnen, ist es oft notwendig, das Verhalten des Geräts und der Treiber zu überprüfen und sicherzustellen, dass die angeschlossenen Bildschirme ordnungsgemäß funktionieren. Eine einfache Möglichkeit hierfür ist die Verwendung des Beispiels „hellowindow “. Wenn Sie es mit den Argumenten „ -platform eglfs --multiscreen --timeout “ starten, wird auf jedem angeschlossenen Bildschirm für einige Sekunden ein rotierendes Qt-Logo angezeigt.

Benutzerdefinierte Konfiguration

Das KMS/DRM-Backend unterstützt zudem benutzerdefinierte Konfigurationen über eine JSON-Datei. Um dies zu aktivieren, setzen Sie die Umgebungsvariable ` QT_QPA_EGLFS_KMS_CONFIG ` auf den Namen der Datei. Sie können diese Datei auch über das Qt-Ressourcensystem in die Anwendung einbetten.

Die meisten dieser Konfigurationsoptionen gelten für alle KMS/DRM-basierten Backends, unabhängig von der verwendeten Pufferverwaltungstechnologie (GBM oder EGLStreams).

Hinweis: Konfigurationsdateien gelten als vertrauenswürdige Inhalte, die vollständig vom Hersteller des Geräts oder der Plattform kontrolliert und verwaltet werden. Es ist nicht vorgesehen, dass sie dem Endbenutzer in irgendeiner Form zugänglich gemacht werden.

Hier ist ein Beispiel für eine Konfiguration:

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

Hier konfigurieren wir das angegebene Gerät so, dass:

  • Der Hardware-Cursor nicht verwendet wird (es wird stattdessen auf die Darstellung des Mauszeigers über OpenGL zurückgegriffen; standardmäßig sind Hardware-Cursor aktiviert, da sie effizienter sind).
  • QOffscreenSurface us mit Standard-EGL-pbuffer-Oberflächen unterstützt wird (standardmäßig ist dies deaktiviert und stattdessen wird eine gbm-Oberfläche verwendet).
  • Die Ausgabe über den VGA-Anschluss ist deaktiviert, während HDMI mit einer Auflösung von 1024x768 aktiv ist.

Zudem deaktiviert eine solche Konfiguration auch die Suche nach einem Gerät über „ libudev “; stattdessen wird das angegebene Gerät verwendet.

Wenn „ mode “ nicht definiert ist, wird der vom System bevorzugte Modus gewählt. Die zulässigen Werte für „ mode “ sind: „ off “, „ current “, „ preferred “, „ skip “, „widthxheight“, „widthxheight“, „@vrefresh“ oder eine Modeline-Zeichenkette.

Durch die Angabe von „ current “ wird ein Modus mit einer Auflösung ausgewählt, die der aktuellen entspricht. Da die Moduseinstellung nur dann erfolgt, wenn sich der gewünschte Modus tatsächlich vom aktiven unterscheidet (es sei denn, dies wird über die Umgebungsvariable „ QT_QPA_EGLFS_ALWAYS_SET_MODE “ erzwungen), ist dieser Wert nützlich, um den aktuellen Modus und alle Inhalte in den Ebenen beizubehalten, die von Qt nicht verändert wurden.

skip bewirkt, dass der Anschluss für die Ausgabe ignoriert wird, als wäre er nicht angeschlossen. „ off “ funktioniert ähnlich, ändert jedoch den Modus und schaltet die Anzeige aus.

Standardverhalten

Standardmäßig werden alle von der DRM-Schicht gemeldeten Bildschirme als ein großer virtueller Desktop behandelt. Die Implementierung des Mauszeigers berücksichtigt dies und bewegt sich wie erwartet über die Bildschirme hinweg. Obwohl dies nicht empfohlen wird, können Sie den virtuellen Desktop deaktivieren, indem Sie separateScreens in der Konfiguration auf false setzen.

Standardmäßig wird der virtuelle Desktop von links nach rechts gebildet, basierend auf der vom System gemeldeten Reihenfolge der Anschlüsse. Um dies zu ändern, setzen Sie „ virtualIndex “ auf einen Wert, der bei 0 beginnt.

Die folgende Konfiguration verwendet beispielsweise die bevorzugte Auflösung, stellt jedoch sicher, dass die linke Seite des virtuellen Desktops der an den HDMI-Anschluss angeschlossene Bildschirm ist, während die rechte Seite der an den DisplayPort angeschlossene Bildschirm ist:

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

Die Reihenfolge der Elemente im Array ist irrelevant. Ausgänge mit nicht angegebenen virtuellen Indizes werden hinter den anderen platziert, wobei die ursprüngliche Reihenfolge in der DRM-Anschlussliste beibehalten wird.

Um einen vertikalen Desktop-Bereich zu erstellen (d. h. die Anordnung von oben nach unten statt von links nach rechts), fügen Sie nach „ device “ die Eigenschaft „ virtualDesktopLayout “ mit dem Wert „ vertical “ hinzu.

Warnung: Es wird empfohlen, dass alle Bildschirme auf dem virtuellen Desktop dieselbe Auflösung verwenden. Andernfalls können sich Elemente wie der Mauszeiger unerwartet verhalten, wenn sie Bereiche betreten, die nur auf einem bestimmten Bildschirm vorhanden sind.

Wenn „ virtualIndex “ nicht ausreicht, kann die Eigenschaft „ virtualPos “ verwendet werden, um die Position oben links des betreffenden Bildschirms explizit anzugeben. Ausgehend vom vorherigen Beispiel und unter der Annahme einer Auflösung von 1080p für HDMI1 platziert der folgende Codeausschnitt einen zweiten HDMI-Bildschirm unterhalb des ersten:

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

Hinweis: Vermeiden Sie solche Konfigurationen, wenn Mausunterstützung gewünscht ist. Das Verhalten des Mauszeigers kann bei nichtlinearen Layouts unerwartet sein. Bei Touch-Bedienung sollten keine Probleme auftreten.

Automatische Abfrage der physikalischen Bildschirmgröße

In einigen Fällen kann die automatische Ermittlung der physikalischen Bildschirmgröße über DRM fehlschlagen. Normalerweise würden die Umgebungsvariablen „ QT_QPA_EGLFS_PHYSICAL_WIDTH “ und „ QT_QPA_EGLFS_PHYSICAL_HEIGHT “ verwendet, um die fehlenden Werte bereitzustellen. Dies ist jedoch nicht mehr geeignet, wenn mehrere Bildschirme vorhanden sind. Verwenden Sie stattdessen die Eigenschaften „ physicalWidth “ und „ physicalHeight “ in der Liste „ outputs “, um die Größen in Millimetern anzugeben.

Hinweis: Vonunterschiedlichen physikalischen Größen und damit abweichenden logischen DPIs wird abgeraten, da dies zu unerwarteten Problemen führen kann, da einige Komponenten des Grafikstacks nicht über mehrere Bildschirme informiert sind und sich ausschließlich auf die Werte des ersten Bildschirms stützen.

Aktive Ausgänge und QScreen-Instanzen

Jeder aktive Ausgang aus dem Array „ outputs “ entspricht einer „ QScreen “-Instanz, die von „ QGuiApplication::screens()“ gemeldet wird. Standardmäßig ist der primäre Bildschirm, den „ QGuiApplication::primaryScreen()“ meldet, der Bildschirm, der als erster registriert wurde. Wenn Sie „ virtualIndex “ nicht verwenden, bedeutet dies, dass die Entscheidung auf der Reihenfolge der DRM-Anschlüsse basiert. Um dies zu überschreiben, setzen Sie die Eigenschaft „ primary “ für den gewünschten Eintrag in der Liste „ outputs “ auf „ true “.

Um beispielsweise sicherzustellen, dass der Bildschirm, der dem VGA-Ausgang entspricht, als primärer Bildschirm festgelegt wird, auch wenn das System zufällig zuerst den HDMI-Ausgang meldet, gehen Sie wie folgt vor:

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

Zur Fehlerbehebung kann es hilfreich sein, Debug-Protokolle aus dem KMS/DRM-Backend zu aktivieren. Aktivieren Sie dazu die Protokollierungsregel der Kategorie „ qt.qpa.eglfs.kms “.

Hinweis: In einer eingebetteten Umgebung sind virtuelle Desktops im Vergleich zu einem vollständigen Fenstersystem eingeschränkter. Windows, die sich über mehrere Bildschirme erstrecken, Nicht-Vollbild-Fenster und das Verschieben von Fenstern zwischen Bildschirmen sollten vermieden werden und funktionieren möglicherweise nicht wie erwartet.

Ein häufiger Anwendungsfall

Der häufigste und am besten unterstützte Anwendungsfall für eine Mehrbildschirmkonfiguration besteht darin, für jeden Bildschirm ein eigenes „ QQuickWindow “- oder „ QQuickView “-Fenster zu öffnen. Mit der standardmäßigen „ threaded “-Render-Schleife des „ Qt Quick “-Szenengraphen erhält jedes dieser Fenster einen eigenen Render-Thread. Dies ist vorteilhaft, da die Threads unabhängig voneinander basierend auf Vsync gedrosselt werden können und sich nicht gegenseitig stören. Bei der „ basic “-Schleife kann dies zu Problemen führen und die Qualität der Animationen beeinträchtigen.

Beispielsweise lässt sich das Erkennen aller angeschlossenen Bildschirme und das Erstellen eines „ QQuickView “ für jeden einzelnen wie folgt bewerkstelligen:

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;
}

Erweiterte Funktionen von eglfs_kms

Klonen (Spiegeln)

Das Klonen (Spiegeln) von Bildschirmen wird unterstützt. Dies wird über die Eigenschaft „ clones “ aktiviert:

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

In diesem Fall entspricht der Inhalt auf dem über DisplayPort angeschlossenen Bildschirm dem auf dem HDMI-Bildschirm. Dies wird dadurch gewährleistet, dass auf beiden Bildschirmen derselbe Puffer ausgegeben wird.

Diese Funktion kann jedoch nur funktionieren, wenn die Auflösungen identisch sind, keine Inkompatibilitäten hinsichtlich der akzeptierten Pufferformate bestehen und die Anwendung keine Ausgabe auf dem „ QScreen “ hat, der einem Klonziel zugeordnet ist. In der Praxis bedeutet Letzteres, dass kein „ QWindow “, der mit dem betreffenden „ QScreen “ – im Beispiel DP1 – verbunden ist, jemals einen „ QOpenGLContext::swapBuffers()“-Vorgang ausführen darf. Es liegt an der Konfiguration und der Anwendung, dies sicherzustellen.

Headless-Modus mit DRM-Render

Der Headless-Modus über DRM-Render-Knoten wird unterstützt. Dies ermöglicht die Durchführung von GPU-Berechnungen (OpenGL-Compute-Shader, OpenCL) oder Off-Screen-OpenGL-Rendering, ohne dass DRM-Master-Rechte erforderlich sind. In diesem Modus können Anwendungen auch dann funktionieren, wenn bereits ein anderer Prozess auf dem Bildschirm ausgibt.

Das bloße Umschalten von ` device ` von ` /dev/dri/card0 ` auf ` /dev/dri/renderD128 ` ist für sich genommen sinnlos, da es eine Reihe von Operationen gibt, die im Headless-Modus nicht ausgeführt werden können. Daher muss dies mit der Eigenschaft ` headless ` kombiniert werden, zum Beispiel:

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

Beachten Sie, dass die Fenster weiterhin an die – nun virtuelle – Bildschirmgröße angepasst werden; daher ist es erforderlich, in der Eigenschaft „ headless “ eine Größe anzugeben. Außerdem fehlt die auf Vsync basierende Drosselung.

Nach der Aktivierung haben Anwendungen zwei typische Möglichkeiten, um im Headless-Modus Off-Screen-Rendering durchzuführen:

Verwenden Sie ein gewöhnliches Fenster, beispielsweise eine Unterklasse von ` QOpenGLWindow `, das auf den Standard-Framebuffer des Fensters abzielt – in der Praxis also ein ` gbm_surface `:

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

Oder den typischen Offscreen-Ansatz mit einem zusätzlichen FBO:

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();

Auswahl der DRM-API

KMS/DRM kann mit zwei verschiedenen DRM-APIs verwendet werden: „Legacy “ und „Atomic“. Der Hauptvorteil der DRM-Atomic-API besteht darin, dass mehrere DRM-Ebenen-Aktualisierungen innerhalb derselben Render-Schleife möglich sind, während die Legacy-API eine Ebenen-Aktualisierung pro Vsync erfordert.

Die „atomic“-API ist nützlich, wenn Ihre Anwendung Inhalte in Overlays einblenden muss, wobei alle Aktualisierungen innerhalb desselben Vsync erfolgen sollen. Allerdings unterstützen noch nicht alle Geräte diese API, und auf einigen älteren Geräten ist sie möglicherweise nicht verfügbar. Das KMS-Backend verwendet standardmäßig die „legacy“-API, aber Sie können die DRM-„atomic“-API aktivieren, indem Sie die Umgebungsvariable ` QT_QPA_EGLFS_KMS_ATOMIC ` auf 1 setzen.

Die Verwendung eines Framebuffers, der kleiner ist als die Bildschirmauflösung, kann ebenfalls nützlich sein. Dies ist mit der DRM-Atomic-API mithilfe des Parameters ` size ` in der JSON-Datei möglich. Das folgende Beispiel verwendet einen Framebuffer mit 1280x720 im Videomodus 3840x2160:

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

EGLFS-Hot-Plug und Hot-Reload

Wenn eine KMS-Konfigurationsdatei über ` QT_QPA_EGLFS_KMS_CONFIG` festgelegt wird, wird die referenzierte Datei von einem ` QFileSystemWatcher` überwacht. Jede Änderung an dieser Datei löst ein erneutes Einlesen aus und bewirkt entsprechende Aktualisierungen, z. B. Layoutänderungen, Moduswechsel oder das Ein- und Ausschalten von Bildschirmen.

In ähnlicher Weise, jedoch streng auf freiwilliger Basis, kann „ QT_QPA_EGLFS_HOTPLUG_ENABLED “ festgelegt werden, wodurch ein „QDeviceDiscovery“ das KMS-Gerät auf Änderungen wie das Anschließen bzw. Trennen von Bildschirmen überwacht.

Beide Funktionen können und werden oft parallel genutzt.

Um die durch Hot-Plug und Hot-Reload ausgelösten dynamischen Änderungen ordnungsgemäß zu unterstützen, ist es wichtig, darauf zu reagieren, indem Fenster auf den jeweils erscheinenden und verschwindenden Bildschirmen erstellt und gelöscht werden.

Beispielcode:

#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();
}

Bitte beachten Sie im obigen Beispiel die Zeile bezüglich „ QWindow::setGeometry “ – dies ist entscheidend dafür, dass Fenster auf dem Bildschirm erscheinen, für den sie vorgesehen sind!

Da dieselben Signale auch für QML existieren, kann entsprechender Code ebenfalls in QML geschrieben werden.

Insbesondere bei „ QT_QPA_EGLFS_HOTPLUG_ENABLED “ ist es unerlässlich, den Code entsprechend anzupassen, da sich manche Bildschirme beim Ausschalten so verhalten, als wären sie getrennt. Ohne diese aktivierte Funktion werden weder Qt noch der Code auf Anwendungsebene über Trennungen benachrichtigt. Alle Backend-Ressourcen bleiben in der Regel einfach intakt, weshalb der Bildschirm wieder erscheint, als wäre nichts geschehen. Mit „ QT_QPA_EGLFS_HOTPLUG_ENABLED “ werden die Qt-Ressourcen auf dem Bildschirm (z. B. ` QScreen`, `QPlatformScreen`, `backing-store`, …) zerstört und bei der Wiederverbindung (z. B. beim Wiedereinschalten des Bildschirms) neu erstellt. Daher müssen auch die Ressourcen auf Anwendungsebene (z. B. ` QWindow`) neu erstellt werden.

Der Fallback-Bildschirm namens „qt_Headless“ dient dazu, den Wechsel zu und von einer Konfiguration ohne Bildschirm zu erleichtern. Für Fenster auf Anwendungsebene kann und sollte dieser Bildschirm in den meisten Fällen ignoriert werden.

EGLFS mit einem „eglfs_kms_egldevice“-Backend

Dieses Backend, das typischerweise auf Tegra-Geräten verwendet wird, ähnelt dem oben erwähnten KMS/DRM-Backend, außer dass es auf die Erweiterungen EGLDevice und EGLStream anstelle von GBM zurückgreift.

Technische Details zu diesem Ansatz finden Sie in dieser Präsentation.

Ab Qt 5.7 teilt dieses Backend einen Großteil seiner internen Implementierung mit dem GBM-basierten Backend. Das bedeutet, dass mehrere Bildschirme und die erweiterte Konfiguration über ` QT_QPA_EGLFS_KMS_CONFIG ` unterstützt werden. Einige Einstellungen, wie beispielsweise ` hwcursor ` und ` pbuffers `, sind jedoch nicht anwendbar.

Standardmäßig wählt das Backend automatisch die richtige EGL-Ebene für die Standardebene jeder Ausgabe aus. Bei Bedarf kann dies überschrieben werden, indem die Umgebungsvariable ` QT_QPA_EGLFS_LAYER_INDEX ` auf den Index der gewünschten Ebene gesetzt wird. Dieser Ansatz unterstützt derzeit keine mehreren Ausgänge, daher sollte seine Verwendung auf Systeme mit einem einzigen Bildschirm beschränkt bleiben. Um zu sehen, welche Ebenen verfügbar sind, und um mögliche Startprobleme zu beheben, aktivieren Sie die Protokollierungskategorie „ qt.qpa.eglfs.kms “.

In einigen Fällen kann es erforderlich sein, beim Start der Anwendung eine Videomodus-Einstellung vorzunehmen, selbst wenn der Bildschirm meldet, dass die gewünschte Auflösung bereits eingestellt ist. Dies wird normalerweise automatisch optimiert, doch sollte der Bildschirm ausgeschaltet bleiben, versuchen Sie, die Umgebungsvariable ` QT_QPA_EGLFS_ALWAYS_SET_MODE ` auf einen Wert ungleich Null zu setzen und die Anwendung neu zu starten.

Um das Verhalten des vom Backend verwendeten EGLStream-Objekts zu konfigurieren, verwenden Sie die Umgebungsvariable „ QT_QPA_EGLFS_STREAM_FIFO_LENGTH “. Dabei wird vorausgesetzt, dass „ KHR_stream_fifo “ vom Zielsystem unterstützt wird. Standardmäßig arbeitet der Stream im Mailbox-Modus. Um in den FIFO-Modus zu wechseln, setzen Sie einen Wert von 1 oder größer. Der Wert gibt die maximale Anzahl an Frames an, die der Stream aufnehmen kann.

Auf einigen Systemen kann es erforderlich werden, über einen vordefinierten Connector eine bestimmte Overlay-Ebene anzusteuern. Das bloße Erzwingen eines Layer-Index über ` QT_QPA_EGLFS_LAYER_INDEX ` führt keine Ebenenkonfiguration durch und ist daher für sich genommen nicht geeignet. Verwenden Sie stattdessen in solchen speziellen Szenarien die Umgebungsvariablen ` QT_QPA_EGLFS_KMS_CONNECTOR_INDEX ` und ` QT_QPA_EGLFS_KMS_PLANE_INDEX `. Wenn diese gesetzt sind, werden nur der angegebene Connector und die angegebene Ebene verwendet; alle anderen Ausgänge werden ignoriert. Das Backend übernimmt die Auswahl der EGL-Ebene, die der gewünschten Ebene entspricht, sowie die Konfiguration der Ebene.

Touch-Eingaben in Systemen mit mehreren Bildschirmen unter KMS/DRM

Touchscreens erfordern in Multi-Display-Systemen zusätzliche Überlegungen, da Touch-Ereignisse an den richtigen virtuellen Bildschirm weitergeleitet werden müssen, was eine korrekte Zuordnung zwischen Touchscreens und Bildschirmausgängen erfordert.

Die Zuordnung erfolgt über die JSON-Konfigurationsdatei, die unter QT_QPA_EGLFS_KMS_CONFIG angegeben und in den vorangegangenen Abschnitten beschrieben ist. Wenn in einem Element des Arrays „ outputs “ eine Eigenschaft „ touchDevice “ vorhanden ist, wird der Wert als Geräteknoten behandelt und das Touch-Gerät dem betreffenden Bildschirmausgang zugeordnet.

Angenommen, unser Touchscreen hat den Geräteknoten /dev/input/event5 und ist ein Touchscreen, der als sekundärer Bildschirm über HDMI in den Monitor integriert ist, dann gewährleistet die folgende Konfiguration die korrekte Übersetzung von Touch- (und synthetisierten Maus-)Ereignissen:

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

Hinweis: Im Zweifelsfall sollten Sie die Protokollierung sowohl des Grafik- als auch des Eingabesubsystems aktivieren, indem Sie vor dem Start der Anwendung die Umgebungsvariable ` QT_LOGGING_RULES=qt.qpa.*=true ` setzen. Dies hilft bei der Identifizierung der richtigen Eingabegeräteknoten und kann Probleme bei der Ausgabekonfiguration aufdecken, die sonst schwer zu beheben sind.

Hinweis: Ab Qt 5.14 wird das oben Beschriebene nur für die Backends „evdevtouch“ und „libinput“ unterstützt. Andere Varianten leiten Ereignisse weiterhin an den primären Bildschirm weiter. Um die Verwendung von „evdevtouch“ auf Systemen zu erzwingen, auf denen mehrere Eingabe-Backends verfügbar sind, setzen Sie die Umgebungsvariable ` QT_QPA_EGLFS_NO_LIBINPUT ` auf ` 1`.

EGLFS mit anderen Backends

Andere Backends, die in der Regel darauf basieren, den Framebuffer oder eine Compositing-API direkt über die EGL-Implementierung des Herstellers anzusteuern, bieten meist nur eingeschränkte oder gar keine Unterstützung für mehrere Bildschirme. Auf i.MX6-basierten Boards mit Vivante-GPUs kann die Umgebungsvariable „ QT_QPA_EGLFS_FB “ verwendet werden, um den anzusteuernden Framebuffer anzugeben, ähnlich wie bei „linuxfb“. Auf dem Raspberry Pi kann die Umgebungsvariable „ QT_QPA_EGLFS_DISPMANX_ID “ verwendet werden, um den Bildschirm anzugeben, auf dem die Ausgabe erfolgen soll. Der Wert entspricht einer der Konstanten aus „ DISPMANX_ID_ “; siehe dazu die Dispmanx-Dokumentation. Beachten Sie, dass diese Ansätze im Gegensatz zu KMS/DRM in der Regel keine Ausgabe auf mehrere Bildschirme aus derselben Anwendung zulassen. Alternativ stehen möglicherweise auch treiberspezifische Umgebungsvariablen oder Kernel-Parameter zur Steuerung des verwendeten Framebuffers zur Verfügung. Siehe dazu die Dokumentation des Embedded-Boards.

Grafikspeicher

Bei Systemen mit einer festen Menge an dediziertem Grafikspeicher ist möglicherweise besondere Vorsicht geboten, bevor Qt-Anwendungen ausgeführt werden, die auf ` Qt Quick ` oder Klassen wie ` QOpenGLWidget` basieren. Die Standardeinstellung reicht für solche Anwendungen möglicherweise nicht aus, insbesondere wenn sie auf einem Bildschirm mit hoher Auflösung (z. B. Full HD) angezeigt werden. In diesem Fall können unerwartete Fehler auftreten. Es wird empfohlen, sicherzustellen, dass mindestens 128 MB GPU-Speicher verfügbar sind. Bei Systemen, bei denen keine feste Speichermenge für die GPU reserviert ist, stellt dies kein Problem dar.

linuxfb

Verwenden Sie den Plugin-Parameter „ fb “, um das zu verwendende Framebuffer-Gerät anzugeben.

Unix-Signal-Handler und Konsolenstatus

Die konsolenorientierten Plattform-Plugins wie eglfs und linuxfb installieren standardmäßig Signal-Handler, um Interrupts (SIGINT), das Anhalten und Fortsetzen (SIGTSTP, SIGCONT) sowie das Beenden (SIGTERM) zu erfassen. Auf diese Weise können die Tastatur, der Terminal-Cursor und möglicherweise andere Grafikzustände wiederhergestellt werden, wenn die Anwendung beendet oder aufgrund von kill, Ctrl+C oder Ctrl+Z in den Ruhezustand versetzt wird. (Das Beenden oder in den Ruhezustand versetzen über die Tastatur ist allerdings nur möglich, wenn QT_QPA_ENABLE_TERMINAL_KEYBOARD gesetzt ist; siehe „Eingaben auf einem Embedded-Linux-Gerät“). In manchen Fällen kann das Abfangen von „ SIGINT “ jedoch unerwünscht sein, da es beispielsweise zu Konflikten mit der Remote-Fehlersuche führen kann. Daher steht die Umgebungsvariable „ QT_QPA_NO_SIGNAL_HANDLER “ zur Verfügung, um die gesamte integrierte Signalbehandlung zu deaktivieren.

Die Handler werden bei der Initialisierung des Plattform-Plugins installiert und ersetzen dabei alle zuvor von der Anwendung eingerichteten Handler.

Warnung: Bei „ SIGINT “ und „ SIGTERM “ wird der Konsolenstatus wiederhergestellt und der Prozess anschließend über „ _exit() “ beendet. Es werden keine „ atexit() “-Handler, statischen Destruktoren oder Qt-Shutdown-Code ausgeführt, und gepufferte Daten werden nicht geleert. „ systemctl stop “ oder ein einfaches „ kill “ beendet die Anwendung daher sofort. Eine Anwendung, die ihren Zustand unter SIGTERM beibehalten muss, muss QT_QPA_NO_SIGNAL_HANDLER setzen und einen eigenen Handler installieren, der auch die Wiederherstellung des Konsolenstatus übernimmt.

Der Konsolenstatus wird nur auf diesen Pfaden und bei normalem Herunterfahren wiederhergestellt. Er wird nicht wiederhergestellt, wenn der Prozess durch „ SIGSEGV “, „ SIGABRT “ oder „ std::terminate() “ beendet wird. Bei „linuxfb“, das das virtuelle Terminal ebenfalls in den Grafikmodus umschaltet, kann eine abnormal beendete Anwendung dazu führen, dass die lokale Konsole leer bleibt und nicht mehr auf Tastatureingaben reagiert, bis das Gerät neu gestartet wird. Auf Geräten, bei denen diese Konsole der einzige lokale Wiederherstellungsweg ist, sollten Sie eine Alternative bereitstellen, beispielsweise eine serielle Konsole oder einen Watchdog, der das Gerät neu startet. Verwenden Sie „ QT_QPA_PRESERVE_CONSOLE_STATE “, um die Einstellungen für den Terminal-Cursor und die Bildschirmausblendung unverändert zu lassen, und „ nographicsmodeswitch “ von linuxfb, um die Umschaltung in den Grafikmodus zu überspringen.

Sicherheitsaspekte

Die auf dieser Seite beschriebenen Plattform-Plugins laufen ohne Fenstersystem und übernehmen daher Aufgaben, die normalerweise einem Compositor oder einem Display-Server obliegen würden. In diesem Abschnitt wird beschrieben, welchen Inhalten sie vertrauen und welche Kontrolle von einem Geräteentwickler erwartet wird. Siehe auch Qt Shared Security Model.

Die Konfiguration gilt als vertrauenswürdiger Inhalt

Das Verhalten der eingebetteten Plattform-Plugins – welche Geräteknoten geöffnet werden, welches Geräteintegrations-Plugin in den Prozess geladen wird, wie Touch-Koordinaten auf Bildschirme abgebildet werden – wird durch Umgebungsvariablen, durch die KMS/DRM-JSON-Konfigurationsdatei sowie durch die optionalen Keymap- und Cursor-Atlas-Dateien bestimmt. All dies sind vertrauenswürdige Inhalte: Es wird erwartet, dass sie beim Erstellen des Geräte-Images festgelegt und danach vom Gerätehersteller kontrolliert werden. Qt prüft, ob sie wohlgeformt sind, führt jedoch keine weitere Validierung durch, und sie sind nicht dazu bestimmt, dem Endnutzer des Geräts in irgendeiner Form zugänglich gemacht zu werden.

Zwei Einträge verdienen besondere Beachtung:

  • QT_QPA_EGLFS_INTEGRATION schränkt die Plugins, die geladen werden dürfen, nicht ein. Das angeforderte Backend wird lediglich an den Anfang der Kandidatenliste verschoben; sollte dessen Initialisierung fehlschlagen, werden die verbleibenden Backends weiterhin der Reihe nach ausprobiert. Auf einem System, auf dem mehrere Geräteintegrations-Plugins vorhanden sind, kann es vorkommen, dass ein Backend, das bei der Bereitstellung nicht benannt wurde, geladen wird und die Hardware initialisiert. Stellen Sie nur die Backends bereit, die das Gerät benötigt.
  • Die Touch-Kalibrierung und -Drehung – unabhängig davon, ob sie über die Parameter „ QT_QPA_LIBINPUT_TOUCH_MATRIX “, „ evdev “, „ rotate “, „ invertx “ und „ inverty “ oder über die Zuordnung „ touchDevice “ in der JSON-Konfigurationsdatei festgelegt werden – bestimmen, wo ein Druck gemeldet wird. Eine falsche Einstellung führt dazu, dass der Benutzer ein anderes Steuerelement aktiviert als das, das er berührt hat – was bei einer Mensch-Maschine-Schnittstelle ein Sicherheitsmerkmal darstellt. Behandeln Sie diese Einstellungen als Teil der verifizierten Konfiguration des Geräts und nicht als vor Ort anpassbare Einstellung.

Eingabegeräte werden nicht gefiltert

Die Geräteerkennung von Qt öffnet jeden „ /dev/input/event* “-Knoten, der der gesuchten Fähigkeitsklasse entspricht, und – sofern „ libudev “-Unterstützung verfügbar ist – auch Geräte, die erst später während der Ausführung der Anwendung hinzukommen. Es gibt keine Zulassungsliste, keinen Hersteller- oder Produktfilter und keine Vorstellung von einer erwarteten Gerätegruppe. Ereignisse von jedem akzeptierten Gerät werden an die Anwendung übermittelt, als kämen sie von dem beabsichtigten Gerät; die Anwendung kann sie nicht voneinander unterscheiden.

Die Einschränkung, welche Geräte existieren und wer sie auslesen darf, ist daher Aufgabe des Geräteherstellers und erfolgt auf der Ebene des Kernels, der „ udev “ sowie der Dateisystemberechtigungen und nicht in der Anwendung. Eine Qt-Anwendung, die keine Berechtigung zum Auslesen von „ /dev/input/* “ hat, liest überhaupt keine Eingaben aus. Außerdem:

  • Die explizite Benennung der Geräte in ` QT_QPA_EVDEV_MOUSE_PARAMETERS`, ` QT_QPA_EVDEV_KEYBOARD_PARAMETERS ` und ` QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS ` umgeht die Erkennung und legt den Gerätesatz fest, den die Anwendung verwendet.
  • Die Übergabe von ` grab=1 ` gewährt der Anwendung exklusiven Zugriff auf ein Gerät, was bei einem Gerät, auf dem nur eine einzige Anwendung läuft, in Betracht gezogen werden sollte.
  • Beachten Sie „ disable-zap “ – siehe „Eingaben auf einem Embedded-Linux-Gerät“.

Anzeigen gelten als nicht vertrauenswürdige Eingabe

Der EDID-Block, den ein Bildschirm über den Anschluss übermittelt, wird von dem jeweils angeschlossenen Gerät bereitgestellt – dies kann ein Monitor, ein Adapter, ein KVM-Switch oder ein Aufnahmegerät sein – und bei jedem Hotplug-Ereignis erneut geparst. Bei eglfs mit dem KMS/DRM-Backend gelangen die darin enthaltenen Werte über ` QScreen::manufacturer()`, ` QScreen::model()`, ` QScreen::serialNumber()` und die gemeldete physische Größe zur Anwendung. Behandeln Sie diese als extern beeinflusst: Verwenden Sie sie nicht als Identifikator und beachten Sie, dass sie möglicherweise in Protokollen landen. Die physische Größe kann mit ` QT_QPA_EGLFS_PHYSICAL_WIDTH ` und ` QT_QPA_EGLFS_PHYSICAL_HEIGHT` oder pro Ausgabe in der JSON-Konfigurationsdatei überschrieben werden.

Laufzeitabhängigkeiten

Die Plugins für eingebettete Plattformen sind schlanke Adapter für Bibliotheken, die vom Board-Support-Paket oder der Distribution bereitgestellt werden, nicht von Qt, und die im Prozess der Anwendung ausgeführt werden. Je nach Konfiguration sind dies:

  • eglfs: EGL sowie, je nach Backend, GBM, Mesa und der GPU-Treiber oder eine herstellerspezifische EGL-Implementierung; libdrm für die KMS/DRM-Backends.
  • vkkhrdisplay: der Vulkan-Loader und die installierten Vulkan-Treiber.
  • linuxfb: die Kernel- fbdev -Schnittstelle oder „ libdrm “, wenn „ QT_QPA_FB_DRM “ gesetzt ist.
  • Eingabe: libinput, libudev und mtdev; xkbcommon, das zusätzlich Keymap-Daten aus dem System ausliest; oder tslib, dessen eigene Konfigurationsdatei bestimmt, welche Filtermodule geladen werden und welche Qt daher weder auswählen noch auflisten kann.

Nehmen Sie diese in die Software-Stückliste des Geräts auf, halten Sie sie auf dem neuesten Stand und konfigurieren Sie Qt ausschließlich mit den Backends, die das Gerät tatsächlich verwendet. Bei neuen Geräten sollten Sie libinput dem veralteten tslib vorziehen.

Schriftarten

Qt verwendet normalerweise fontconfig, um Zugriff auf Systemschriftarten zu gewähren. Wenn fontconfig nicht verfügbar ist, greift Qt auf QBasicFontDatabase zurück. In diesem Fall suchen Qt-Anwendungen nach Schriftarten im Verzeichnis „ lib/fonts “ von Qt. Qt erkennt vorgerenderte Schriftarten und TrueType-Schriftarten automatisch. Dieses Verzeichnis kann durch Setzen der Umgebungsvariablen „ QT_QPA_FONTDIR “ überschrieben werden.

Weitere Informationen zu den unterstützten Formaten finden Sie unter „Qt for Embedded Linux Fonts“.

Hinweis: Qt liefert keine Schriftarten mehr im Verzeichnis „ lib/fonts “ aus. Das bedeutet, dass es Aufgabe der Plattform (des System-Images) ist, die erforderlichen Schriftarten bereitzustellen.

Plattform-Plugins für Fenstersysteme auf Embedded-Linux-Geräten

XCB

Dies ist das X11-Plugin, das auf herkömmlichen Desktop-Linux-Plattformen verwendet wird. In einigen Embedded-Umgebungen, die X und die erforderlichen Entwicklungsdateien für xcb bereitstellen, funktioniert dieses Plugin genauso wie auf einem herkömmlichen PC-Desktop.

Hinweis: Auf einigen Geräten ist unter X keine EGL- und OpenGL-Unterstützung verfügbar, da die EGL-Implementierung nicht mit Xlib kompatibel ist. In diesem Fall wird das XCB-Plugin ohne EGL-Unterstützung erstellt, was bedeutet, dass „ Qt Quick 2“ oder andere OpenGL-basierte Anwendungen mit diesem Plattform-Plugin nicht funktionieren. Es kann jedoch weiterhin verwendet werden, um softwaregerenderte Anwendungen (beispielsweise auf Basis von QWidget ) auszuführen.

Generell ist die Verwendung von XCB auf eingebetteten Geräten nicht empfehlenswert. Plugins wie eglfs bieten wahrscheinlich eine bessere Leistung und Hardwarebeschleunigung.

Wayland

Wayland ist ein leichtgewichtiges Fenstersystem; genauer gesagt handelt es sich um ein Protokoll, über das Clients mit einem Display-Server kommunizieren.

Qt Wayland stellt ein Plattform-Plugin namens „ wayland “ bereit, das es Qt-Anwendungen ermöglicht, eine Verbindung zu einem Wayland-Compositor herzustellen.

Weitere Informationen finden Sie unter „Wayland und Qt“.

Richtlinien zur Leistungsoptimierung

Verwenden Sie nach Möglichkeit Hardware-Rendering

Wenn die Leistung für Ihre Anwendung entscheidend ist, vermeiden Sie die Verwendung von Qt-Modulen, die auf Software-Rendering basieren. Bevorzugen Sie stattdessen, wo immer möglich, Module, die auf Hardware-Rendering basieren.

Befolgen Sie die Best Practices für Qt Quick

Befolgen Sie die Best Practices für QML und „ Qt Quick “, insbesondere hinsichtlich der Einbindung der QML-CMake-API, damit qmllint, der QML-Skript-Compiler (qmlsc) und der QML-Typ-Compiler (qmltc) verfügbar sind. Darüber hinaus ist es empfehlenswert, deklaratives QML zu schreiben und JavaScript auf ein Minimum zu beschränken. Weitere Informationen dazu, wie sich die Verwendung von übermäßigem JavaScript auf die Leistung auswirken kann, finden Sie unter „QML-Leistungsaspekte und Empfehlungen“.

Verwenden Sie Bilder/Texturen und Shader-Effekte anstelle des QML-Typs „Canvas“

Verwenden Sie zum Zeichnen benutzerdefinierter UI-Elemente Bilder/Texturen und Shader-Effekte. Verwenden Sie nicht den QML-Typ „ Canvas “. Shader erfordern Hardwarebeschleunigung (GPU).

Verwenden Sie „ Qt Quick “ anstelle von Qt Widgets

Bei „ Qt Quick “ können Sie entweder hardwarebeschleunigte oder softwaregerenderte Backends verwenden. Bei komplexen Benutzeroberflächen wird die Verwendung von „ Qt Widgets “ auf eingebetteten Zielsystemen nicht empfohlen, da dabei immer ein Software-Backend verwendet wird.

Hier gibt es Vor- und Nachteile:

  • Die Verwendung der QML-Engine und von „ Qt Quick “ ist mit anfänglichem Overhead verbunden.
  • Wenn Ihre Benutzeroberfläche sehr einfach ist und nur selten neu gezeichnet wird, läuft sie möglicherweise schneller, wenn sie mit Widgets statt mit QML implementiert wird.
  • Wenn Ihre Benutzeroberfläche von Animationen, „ smooth scrolling “, „ scaling “, „ rendering effects “ oder 3D profitiert, benötigen Sie GPU-Beschleunigung und somit „ Qt Quick “.

Wählen Sie eine für die Größe Ihrer Benutzeroberfläche geeignete Auflösung

Bei höheren Auflösungen ist Vorsicht geboten. Auflösungen von 720p und höher können die Leistung beeinträchtigen.

Verwenden Sie einen QML-Fenstertyp als Stammelement Ihrer Anwendung

Verwenden Sie ein „ Window “ als Stammelement Ihrer Anwendung mit dem Hintergrund der Anwendung „ color “.

Der Grund dafür ist, dass eine „Window“-Komponente über eine Farbeigenschaft verfügt, die die Wirkung eines Puffer-Clears hat. Das Rendern des Hintergrunds mithilfe eines Vollbild-„ Rectangle “ als Stamm Item der Anwendung würde einen zusätzlichen Zeichenaufruf verursachen. Bei einigen RHI-Backends mag dies zwar dasselbe sein, doch es besteht ein Unterschied zwischen einem „ glClear “-Aufruf und dem Zeichnen eines Quadrats. In den meisten Fällen hat ein einzelnes, undurchsichtiges Bild möglicherweise keine großen Auswirkungen auf die Leistung, doch wenn Sie einen Alpha-Wert in der Farbe dieses Elements verwenden, kann es zu erheblichen Leistungseinbußen kommen.

© 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.