embedded multitouch (hmi 2014)
DESCRIPTION
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2TRANSCRIPT
Jahn Fuchs, Zühlke Engineering GmbH |
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2
1
Aus dem Projektalltag: Embedded
Multitouch mit QML/QtQuick 2
Ziel dieses Vortrags ist es dem Zuhörer einen
Überblick über QtQuick 2/QML anhand eines
(bereits umgesetzten) Projektes zu verschaffen
und ein Gefühl vermitteln, ob diese
Technologie für eigene Projekte interessant ist
und mit welchen Herausforderungen zu
rechnen ist.
Ein Premiumhersteller für Präzisions-
Lasersysteme für Wissenschaft und Industrie
möchte im Rahmen einer Produkt-
neuentwicklung ein Multitouch-Display
einsetzen. Wir werden wichtige Heraus-
forderungen und Erkenntnisse dieses
inzwischen umgesetzten Projekts
herausgreifen und betrachten.
Umgesetzt wurde das Projekt mit Qt Quick 2,
einer Technologie, die mit solidem C++
Backend direkt auf OpenGL aufbaut, dabei
aber das Erstellen von Oberflächen in der
deklarativen Sprache QML mit hoher
Abstraktion erlaubt.
Gegenstand des Entwickungsprojekts war ein
digitaler Laser-Controller. Im Vergleich zu
bisherigen Modellen sollte die neue
Produktgeneration mit Touch bedienbar sein
und mehr Komfort bieten.
Abbildung 1: Laser-Controller vorheriger Generation
Neben der technischen Umsetzung war die
Gestaltung eines stimmigen Gesamtdesigns
der Frontplatte und der Benutzeroberfläche
ebenso Gegenstand dieses Projektes.
Abbildung 2: Diodenlaser-System, bestehend aus dem Laser-Kopf mit der Laser-Diode (die blaue Box) und dem Laser-Controller mit Touch-Display (das weiße Rack mit den roten Griffen)
In diesem Vortrag werde ich auf wichtige
technische Details der Implementierung und
der Architektur, die auf Embedded Linux, C++
und QtQuick2/QML aufsetzt, eingehen.
Außerdem werde ich auf die Performance bei
Multitouch im embedded Bereich eingehen,
so wie auf das Zusammenspiel des
Multitouch-Displays mit anderen
Eingabeformen. Zum Schluss machen wir noch
einen kurzen Ausflug in das Thema
automatisiertes Testen von QML
Anwendungen.
Hardware Fundament Die Hardware wurde in diesem Projekt schon
vom Kunden vor unserem Eintritt in das
Projekt ausgewählt. Im Vergleich zu heutigen
Smartphones mit 4-Kern-Prozessoren bewegt
sich die Hardware leistungsmäßig eher in der
unteren Klasse. Jedoch verfügt die Hardware
schon über eine GPU, die eine grafische
Beschleunigung der Oberfläche mittels
OpenGL ermöglicht.
Abbildung 3: Hardware-Fundament des Laser-Controllers
• Texas Instruments Sitara SoC
• CPU: ARM Cortex-A8, 600 MHz, Single Core
• GPU: Imagination Technologies PowerVR SGX
530
• 256 MB RAM
• 512 MB Flash
• Display
• kapazitiv, Multitouch
• 7 Zoll, 800x480 px
Jahn Fuchs, Zühlke Engineering GmbH |
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2
2
In diesem Projekt existiert nur eine Vollbild-
Benutzeroberfläche, die auf den Bildschirm
zugreift. Der Prozess der Benutzeroberfläche
teilt sich den Einkern-Prozessor mit dem
Hauptsteuerprozess und kleineren Service-
Skripten.
QtDeclarative-Architektur Im Abbildung 4 ist der Software-Stack von Qt
Quick bildlich dargestellt. Der Titel
QtDeclarative-Architektur bewusst gewählt,
da Qt Quick und QML selbst nur Teile des
gesamten Systems sind. Die entsprechenden
Quellen findet man bei Qt im QtDeclarative
Modul.
Abbildung 4: QtDeclarative-Architektur
Von der unten startend:
• Die unterste Schicht (lila) stellt die
zugrundeliegende Hardware dar. Neben
der CPU ist auch die GPU ein wichtiges
Element. Qt Quick 2 benötigt OpenGL und
baut auf Hardwarebeschleunigung.
• Der Betriebssystem-Kern (blau)
abstrahiert die Hardware, z.B. mittels
eines OpenGL-Treibers. In unserem Fall
kommt der OpenGL-Treiber als
quelloffenes Linux-Kernel-Modul vom
Hersteller des SoC, dem „TI Graphics SDK“.
• Die eigentliche OpenGL-API-
Implementierung liegt als Userspace-
Library vor und ist nicht quelloffen. Sie ist
ebenfalls Bestandteil des TI Graphics SDK.
• Die in grün dargestellten Blöcke
(QtDeclarative Frontend, Scenegraph
Backend, QtQuick Items) werden von Qt
bereitgestellt. Direkt auf dem
Betriebssystem setzt das QtBase-Modul
auf. Das QtDeclarative-Modul stellt die
QML und Javascript-Engines zur
Verfügung.
• Das Scenegraph-Backend ist als eigener
Block dargestellt, da es von der QML-Welt
einigermaßen deutlich getrennt ist. Der
Scenegraph nutzt ein sog. Platform Plugin,
das die Anbindung an den nativen
Fenster-Manager – oder allgemeiner: den
Grafik-Kontext – vornimmt. Hier passiert
die Anbindung an den Fenster-Manager
bei Desktop-Systemen, also bei Linux z.B.
X11 oder Wayland. Für Embedded
Systeme ohne Fenster-Manager – also
Anwendungen mit nur einem GUI-Prozess
– ist das EGLFS-Plugin gut geeignet. EGLFS
= EGL (OpenGL-API) Fullscreen. In den
EGLFS Hooks können Anpassungen an die
jeweilige Hardware vorgenommen
werden (z.B. LCD Refresh Rate). Auf den
Scenegraph werden wir im Detail in den
nächsten Abschnitten eingehen.
• Ganz oben steht die eigentliche
Anwendung, die typischerweise sowohl
aus Standard-Items sowie Anwendungs-
spezifischen Items (Custom Items)
besteht. Auf Custom Items werden wir im
späteren Verlauf noch ausführlicher
eingehen.
Jahn Fuchs, Zühlke Engineering GmbH |
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2
3
Kurzer QML Überblick QML ist die deklarative, zur Laufzeit
interpretierte, Sprache mit der sich in Qt
Quick Oberflächen beschreiben lassen. QML
kann mit Javascript angereichert werden, z.B.
für Interface-Logik auf hoher Ebene.
Durch QML ist eine gute Aufteilung von
Arbeiten zwischen Interface Designer und
Programmierer möglich. Das solide Backend
ermöglicht es performance-kritische Teile in
C++ zu schreiben. QML kommt mit vielen
Funktionalitäten „out of the Box“ wie z.B.
Animationen, States und Transitionen,
OpenGL Shader und Multitouch Support.
QML im Detail zu besprechen liegt außerhalb
des Rahmens dieses Vortrags. Für den
Interessierten findet sich im Internet eine
Fülle von Tutorials und Einführungen.
Custom QML Items QML kommt in QtQuick mit vielen
Funktionalitäten von Haus aus und in den
neuesten Versionen finden sich sogar
Kontrollelemente wie Slider oder
Fortschrittsbalken. Auch lassen sich in QML
selber wiederverwendbare Komponenten
schreiben. Bei nicht-trivialen Anwendungen
stößt man auch damit jedoch schnell an die
Grenzen des machbaren.
Als Beispiel nehmen wir das Plot-Anzeige- und
Kontrollelement aus der Laser-Controller
Oberfläche (Abbildung 5). Dieses Element soll
verschiedene Messkurven des Lasers
anzeigen. Dem Nutzer soll es möglich sein die
Anzeige mit Pan- und Zoomgesten zu ändern.
Hierbei werden transparent im Hintergrund
neue Laserparameter gesetzt und neue
Messwerte angefordert.
Abbildung 5: Foto der Laser-Controller Benutzeroberfläche
Dies lässt sich sogar rein in QML und
Javascript lösen (es existiert ein QML Canvas
Item auf dem sich mit Javascript malen lässt).
Dies ist jedoch nicht sehr performant – der
Nutzer erwartet ein fluides Verhalten bei den
Gesten, wie er es von seinem Smartphone
kennt.
Qt bietet hier die Möglichkeit eigene visuelle
Items in C++ zu implementieren. Möchte man
„Custom QML Items“ implementieren dann
benötigt man jedoch auf jeden Fall ein
Grundverständnis des QtQuick Scene Graphs
und dessen API. Seit QtQuick 2 läuft alles
Rendering über den Scene Graph.
Bei komplexen Items oder Items mit
besonderen Perfomance-Anforderungen ist
außerdem OpenGL KnowHow
empfehlenswert. Die Scene Graph API ist in
großen Teilen eine Abstrahierung der OpenGL
API, aber dennoch sehr nahe an OpenGL dran.
Entwicklern die sich schon mit OpenGL
beschäftigt haben, werden viele Funktionen
und Methoden bekannt vorkommen.
Jahn Fuchs, Zühlke Engineering GmbH |
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2
4
Der Scene Graph Der Scene Graph ist zentraler Bestandteil des
QtDeclarative Moduls. Es wird über den Scene
Graph mit OpenGL gerendert und dargestellt.
Abbildung 6: Qt/QML Architektur vor und nach Einführung des Scene Graphs
Der Scene Graph wurde aus Performance-
Gründen eingeführt. Abbildung 6 zeigt auf
hoher Abstraktions-ebene wie sich der Scene
Graph auf die Architektur im Vergleich zu
QtQuick1 auswirkt.
Der Scene Graph ist die graphische
Repräsentation der QML Szene, also aller
visuellen QML Items. In Abbildung 7 sehen wir
eine beispielhafte Darstellung eines Scene
Graphs.
Abbildung 7: Der Scene Graph enthält die grafische Repräsentation der aller QML Items der QML Szene auf dem Bildschirm.
Der Scene Graph ist eine Baumstruktur, die
aus einzelnen QSG-Knoten (QtSceneGraph
Nodes) aufgebaut ist. Wir werden später noch
darauf eingehen, wann der Scene Graph mit
der QML Szene abgeglichen wird.
Ein Vorteil von der Benutzung einen Scene
Graphs im Vergleich zu anderen (imperativen)
Systemen (wie z.B. QPainter) ist, dass die zu
renderne Szene zwischen den einzelnen
Frames erhalten bleibt und vor dem
eigentlichen Rendern, der komplette Satz von
Primitiven bekannt ist. Das Scene Graph
Renderer optmiert, indem er versucht die
Anzahl der OpenGL Aufrufe zu minimieren.
Dies passiert z.B. durch Batching
(zusammenfassen von gleichartigen
Primitiven) oder Sortieren nach Objekten mit
und ohne Transparenz. Der Scene Graph
Renderer wendet auch weitere Optmierungen
an wie z.B. das packen von kleinen Texturen in
eine große (Texture Atlas) und versucht
unveränderte Bildschirmbereiche zu
detektieren.
Ohne zu sehr auf C++ Implementierungs-
details einzugehen möchte ich im Folgenden
noch kurz ausführen wie Custom QML Items in
QtQuick realisiert werden.
QQuickItem
Um ein Custom QML Item zu implementieren
leitet man von der Basisklasse aller visuellen
QML Items „QQuickItem“ ab und
implementiert, die updatePaintNode
Methode. In dieser Methode besteht die
Möglichkeit einen Unterknoten bzw.
Unterbaum aus dem Scene Graph zu erstellen,
manipulieren, zu löschen oder einfach im
aktuellen Zustand belassen.
Abbildung 8: Der Scene Graph Renderer aktualisiert den Scene Graph in dem die updatePaintNode Methode der QML Items aufgerufen wird.
Wenn der Scene Graph aktualisiert wird
werden die virtuelle updatePaintNode
Methode aller visuellen QML Items
aufgerufen.
Jahn Fuchs, Zühlke Engineering GmbH |
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2
5
Für Legacy Code: QQuickPaintedItem
QQuickPaintedItem ermöglicht die
Verwendung von der QPainter API für die
Implementierung von Custom QML Items im
Zusammenspiel mit dem Scene Graph. Dies
kann sinnvoll für Legacy Code sein oder für
einfache Items und Programmen bei denen
Performance keine Rollen spielen.
Abbildung 9: QQuickPaintedItem Standardverhalten: Es wird in ein Image gemalt, dies wir d als Textur verwendet.
Beim Standardverhalten des
QQuickPaintedItem wird in ein Bild mit der
QPainter API gemalt, welches dann als Textur
verwendet wird. QQuickpaintedItem bietet
auch die Option direkt mit der OpenGL
PaintEngine in ein Framebufferobjekt zu
zeichnen. Beide Varianten bringen jedoch
immer Perfomance-Einbußen mit sich. Das
Verhalten ist dann dem in Abbildung 6 links
Vergleichbar.
QtQuick Rendering Insbesondere von Touch-Benutzeroberflächen
erwartet der Benutzer heute flüssige
Bedienung und flüssige Animationen. Selbst
bei einer sehr einfachen und technischen
Oberfläche, wie z.B. bei den Parametermenüs
des Laser-Controllers kommen durch
Bedienelemente wie z.B. scrollbaren Listen
automatisch neue Anforderungen hinzu. Die
Liste muss beim scrollen flüssig animiert sein.
Ein Bildschirm hat üblicherweise eine
Bildwiederholrate von 60Hz, dies bedeutet im
Umkehrschluss, dass für wirklich flüssige
Animationen jede 16ms ein neues Bild erzeugt
und angezeigt werden muss.
Abbildung 10: Durch Elemente wie z.B. scrollbare Listen in einer Oberfläche bringen implizite Anforderungen an die Performance mit sich.
Werden zu viele Bilder nicht rechtzeitig auf
dem Bildschirm aktualisiert wird dies als
ruckeln wahrgenommen.
Man kann sich heute
quasi keine grafische
Touch-Oberfläche
ohne flüssig animierte
Elemente vorstellen.
Provokant gefragt:
Bedeuted Multitouch = Echtzeit?
QtQuick verwendet zwei Threads: den GUI
Thread und den Render Thread. Im GUI
Thread wird die QML Szene berechnet (z.B.
die Schritte von einer animierten Transition
von einem State in den nächsten) und die
Applikation hat Zeit sich anderen Dingen
zuzuwenden.
Abbildung 11: QtQuick Rendering
Der GUI Thread teilt mit, wenn der die QML
Szene mit dem Scene Graph synchronisiert
werden kann. Mit dem VSync-Signal werden
Jahn Fuchs, Zühlke Engineering GmbH |
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2
6
darauf hin die Framebuffer getauscht und der
Scene Graph akualisiert. Während der
Synchronisation ist der GUI Thread blockiert.
Dann können wieder beide Threads parallel
arbeiten.
Wenn es ruckelt Sollte es ruckeln und zu Performance-
problemen kommen kann man der Ursache
mit Profiling auf den Grund gehen. Hier bietet
QtQuick verschiedene Optionen an (z.B.
QSG_RENDER_TIMING oder
QST_RENDERER_DEBUG) mit denen Details zu
den einzelnen Renderschritten ausgegeben
werden.
Man sollte unbedingt darauf achten die
Komplexität der QML-Szene reduzieren. Wenn
man auf transparente Objekte (z.B. PNG
Bilder) verzichten kann, bringt dies auch einen
Performancevorteil.
Sollten Profiling und Komplexitätsreduzierung
der QML Szene nicht zum Erfolg führen gibt es
auch noch die Möglichkeit das Scene Graph
Backend im Ganzen oder in Teilen für die
eigene Applikation zu optimieren oder gar
ganz auszutauschen.
Weitere Hinweise für Performance-Tuning
finden sich auf dem Blog von Gunnar Sletta:
http://blog.qt.digia.com/blog/author/gunnar
Testen von QML Anwendungen Obwohl die Wichtigkeit von Softwaretests
bekannt ist, werden Tests doch sehr oft
vernachlässigt. Bei QML Anwendungen sind
Tests nicht minder wichtig.
QML ist eine deklarative Spache, die zur
Laufzeit interpretiert wird. Somit werden
Fehler im Code erst zur Laufzeit bekannt. Im
Gegensatz zu C++ werden hier nicht schon
viele Fehler durch einen Compiler abgefangen.
Zusätzlich kann QML durch Javascript
angereichert werden. Auch Javascript wird
zur Laufzeit interpretiert und bietet keine
Typsicherheit.
Automatisierte Tests sind dadurch bei QML
Anwendungen noch wichtiger als bei reinen
C++ Projekten!
Im Falle der Benutzeroberfläche für den
digitalen Laser-Controller haben wir uns für
automatisierte Tests mit dem GUI
Testwerkzeug Squish der Firma Froglogic
entschieden.
Squish hängt sich direkt an Qt und kennt die
interne Struktur von Qt, dessen Objekten und
Events. Die Tests wurden in das Buildsystem
mit Jenkins integriert und nach jeder
Änderung automatisch ausgeführt. Ein Build
ist nur erfolgreich wenn auch die Tests alle
erfolgreich durchgelaufen sind.
Nun ist die Frage: Wie viele Tests schreibt
man? Wann sind genug Tests vorhanden?
Abbildung 12: Beispielhafte Verlaufsdarstellung der QML Abdeckungsmetrik – wurde bei diesem Projekt so mit in Jenkins integriert.
Jahn Fuchs, Zühlke Engineering GmbH |
Aus dem Projektalltag: Embedded Multitouch mit QML/QtQuick 2
7
Als ein Test Abbruchkriterium bei unseren GUI
Tests haben wir uns die QML Abdeckungs-
metrik ausgedacht.
Dabei wird bei Ausführung der Test-Suite
überprüft, wie viele von den im
Gesamtprojekt existierenden QML Dateien
über alle Tests geladen wurden. Schon alleine
durch Laden aller QML Dokumente werden
Syntaxfehler oder fehlende Grafiken im
gesamten Projekt gefunden.
Allerdings enthalten die meisten QML
Dokumente auch Javascript. Für Javascript
haben wir keine sinnvolle Metrik gefunden.
Bisher ist es in Squish auch nicht möglich die
Test-Abdeckung des Javascript Codes zu
messen. Bei Gesprächen auf den Qt Developer
Days mit Mitarbeitern von Froglogic zeigte
sich, dass sie aber wohl schon intern an einer
Lösung dafür arbeiten.
.
Über den Autor: Dipl.-Inf. Jahn Fuchs ist Software
Engineer bei der Firma Zühlke
Engineering GmbH und beschäftigt
sich beruflich wie privat mit
vielfältigen Themen aus der
Software-entwicklung. Die Erfahrungsschwerpunkte und
Interessen liegen im Bereich (embedded) Linux, C++,
Oberflächenentwicklung mit Qt, Buildsystemen und
Testinfrastrukturen. Wenn sich die Möglichkeit bietet
hält er seit 2013 auch Vorträge über Themen, die ihn
aktuell beschäftigen. Privat beschäftigt er sich neben der
Technik am liebsten mit Gitarren, Poker und
Tischfußball. Außerdem genießt er im Sommer gerne die
Isar und das schöne München.