Die Hardware Composer (HWC) HAL-Verbundschichten, die von SurfaceFlinger empfangen wurden, reduzieren den Umfang der Kompositionsleistung von OpenGL ES (GLES) und der GPU.
Der HWC abstrahiert Objekte wie Overlays und 2D-Blitter zu zusammengesetzten Oberflächen und kommuniziert mit spezieller Fensterkompositionshardware zu zusammengesetzten Fenstern. Verwenden Sie HWC zum Zusammensetzen von Fenstern, anstatt SurfaceFlinger mit der GPU zusammenzusetzen. Die meisten GPUs sind nicht für die Komposition optimiert, und wenn die GPU Ebenen aus SurfaceFlinger zusammenstellt, können Apps die GPU nicht für ihr eigenes Rendering verwenden.
HWC-Implementierungen sollten Folgendes unterstützen:
- Mindestens vier Overlays:
- Statusleiste
- Systemleiste
- App
- Tapete/Hintergrund
- Ebenen, die größer als die Anzeige sind (z. B. ein Hintergrundbild)
- Gleichzeitiges vormultipliziertes Alpha-Blending pro Pixel und Alpha-Blending pro Ebene
- Hardwarepfad für geschützte Videowiedergabe
- RGBA-Packreihenfolge, YUV-Formate sowie Kachel-, Swizzling- und Stride-Eigenschaften
So implementieren Sie das HWC:
- Implementieren Sie ein nicht betriebsbereites HWC und senden Sie alle Kompositionsarbeiten an GLES.
- Implementieren Sie einen Algorithmus, um die Komposition schrittweise an das HWC zu delegieren. Delegieren Sie beispielsweise nur die ersten drei oder vier Oberflächen an die Overlay-Hardware des HWC.
- Optimieren Sie das HWC. Dies kann Folgendes umfassen:
- Auswählen von Oberflächen, die die von der GPU entlastete Last maximieren, und Senden dieser an den HWC.
- Erkennen, ob der Bildschirm aktualisiert wird. Ist dies nicht der Fall, delegieren Sie die Komposition an GLES statt an HWC, um Strom zu sparen. Wenn der Bildschirm erneut aktualisiert wird, fahren Sie mit der Auslagerung der Komposition auf das HWC fort.
- Vorbereitung auf häufige Anwendungsfälle wie:
- Der Startbildschirm, der die Statusleiste, die Systemleiste, das App-Fenster und Live-Hintergründe enthält
- Vollbildspiele im Hoch- und Querformat
- Vollbildvideo mit Untertiteln und Wiedergabesteuerung
- Geschützte Videowiedergabe
- Mehrfenster mit geteiltem Bildschirm
HWC-Primitive
Das HWC bietet zwei Grundelemente, Ebenen und Displays , um die Kompositionsarbeit und ihre Interaktion mit der Display-Hardware darzustellen. Das HWC bietet außerdem Kontrolle über VSYNC und einen Rückruf an SurfaceFlinger, um es zu benachrichtigen, wenn ein VSYNC-Ereignis auftritt.
HIDL-Schnittstelle
Android 8.0 und höher verwendet eine HIDL- Schnittstelle namens Composer HAL für gebundene IPCs zwischen HWC und SurfaceFlinger. Die Composer-HAL ersetzt die alte hwcomposer2.h
Schnittstelle. Wenn Anbieter eine Composer-HAL-Implementierung des HWC bereitstellen, akzeptiert Composer HAL direkt HIDL-Aufrufe von SurfaceFlinger. Wenn Anbieter eine Legacy-Implementierung des HWC bereitstellen, lädt Composer HAL Funktionszeiger von hwcomposer2.h
und leitet HIDL-Aufrufe in Funktionszeigeraufrufe weiter.
Das HWC bietet Funktionen zum Bestimmen der Eigenschaften einer bestimmten Anzeige. um zwischen verschiedenen Anzeigekonfigurationen (z. B. 4k- oder 1080p-Auflösung) und Farbmodi (z. B. native Farbe oder echtes sRGB) zu wechseln; und um das Display ein- und auszuschalten oder in einen Energiesparmodus zu versetzen, sofern dies unterstützt wird.
Funktionszeiger
Wenn Anbieter Composer HAL direkt implementieren, ruft SurfaceFlinger seine Funktionen über HIDL IPC auf. Um beispielsweise eine Ebene zu erstellen, ruft SurfaceFlinger createLayer()
auf der Composer-HAL auf.
Wenn Anbieter die hwcomposer2.h
Schnittstelle implementieren, ruft Composer HAL hwcomposer2.h
Funktionszeiger auf. In hwcomposer2.h
Kommentaren werden HWC-Schnittstellenfunktionen durch Namen in niedrigerer Größe (CamelCase) bezeichnet, die in der Schnittstelle nicht als benannte Felder vorhanden sind. Fast jede Funktion wird geladen, indem ein Funktionszeiger mithilfe der von hwc2_device_t
bereitgestellten getFunction
angefordert wird. Beispielsweise ist die Funktion createLayer
ein Funktionszeiger vom Typ HWC2_PFN_CREATE_LAYER
, der zurückgegeben wird, wenn der Aufzählungswert HWC2_FUNCTION_CREATE_LAYER
an getFunction
übergeben wird.
Eine ausführliche Dokumentation zu Composer-HAL-Funktionen und HWC-Funktions-Passthrough-Funktionen finden Sie unter composer
. Eine ausführliche Dokumentation zu HWC-Funktionszeigern finden Sie in hwcomposer2.h
.
Ebenen- und Anzeigegriffe
Ebenen und Anzeigen werden durch vom HWC generierte Handles manipuliert. Die Griffe sind für SurfaceFlinger undurchsichtig.
Wenn SurfaceFlinger eine neue Ebene erstellt, ruft es createLayer
auf, das den Typ Layer
für direkte Implementierungen oder hwc2_layer_t
für Passthrough-Implementierungen zurückgibt. Wenn SurfaceFlinger eine Eigenschaft dieser Ebene ändert, übergibt SurfaceFlinger den hwc2_layer_t
Wert zusammen mit allen anderen für die Änderung erforderlichen Informationen an die entsprechende Änderungsfunktion. Der Typ hwc2_layer_t
ist groß genug, um entweder einen Zeiger oder einen Index aufzunehmen.
Physische Displays werden durch Hotpluggen erstellt. Wenn eine physische Anzeige per Hotplug angeschlossen wird, erstellt das HWC ein Handle und übergibt das Handle über den Hotplug-Rückruf an SurfaceFlinger. Virtuelle Anzeigen werden erstellt, indem SurfaceFlinger createVirtualDisplay()
aufruft, um eine Anzeige anzufordern. Wenn der HWC die virtuelle Anzeigekomposition unterstützt, gibt er ein Handle zurück. Anschließend delegiert SurfaceFlinger die Zusammenstellung der Displays an das HWC. Wenn das HWC die virtuelle Displaykomposition nicht unterstützt, erstellt SurfaceFlinger das Handle und setzt die Anzeige zusammen.
Kompositionsvorgänge anzeigen
Einmal pro VSYNC wird SurfaceFlinger aktiviert, wenn neue Inhalte zusammengesetzt werden müssen. Bei diesen neuen Inhalten kann es sich um neue Bildpuffer von Apps oder eine Änderung der Eigenschaften einer oder mehrerer Ebenen handeln. Wenn SurfaceFlinger es aufweckt:
- Verarbeitet Transaktionen, sofern vorhanden.
- Sperrt neue Grafikpuffer, falls vorhanden.
- Führt eine neue Komposition durch, wenn Schritt 1 oder 2 zu einer Änderung des Anzeigeinhalts geführt hat.
Um eine neue Komposition durchzuführen, erstellt und zerstört SurfaceFlinger je nach Bedarf Ebenen oder ändert Ebenenzustände. Darüber hinaus werden Ebenen mithilfe von Aufrufen wie setLayerBuffer
oder setLayerColor
mit ihren aktuellen Inhalten aktualisiert. Nachdem alle Ebenen aktualisiert wurden, ruft SurfaceFlinger validateDisplay
auf, wodurch das HWC angewiesen wird, den Status der Ebenen zu untersuchen und zu bestimmen, wie die Komposition fortgesetzt wird. Standardmäßig versucht SurfaceFlinger, jede Ebene so zu konfigurieren, dass die Ebene vom HWC zusammengesetzt wird. Allerdings setzt SurfaceFlinger unter bestimmten Umständen Schichten über den GPU-Fallback zusammen.
Nach dem Aufruf von validateDisplay
ruft SurfaceFlinger getChangedCompositionTypes
auf, um zu sehen, ob das HWC möchte, dass einer der Layer-Kompositionstypen geändert wird, bevor die Komposition durchgeführt wird. Um die Änderungen zu akzeptieren, ruft SurfaceFlinger acceptDisplayChanges
auf.
Wenn Ebenen für die SurfaceFlinger-Zusammensetzung markiert sind, fügt SurfaceFlinger sie im Zielpuffer zusammen. SurfaceFlinger ruft dann setClientTarget
auf, um den Puffer an die Anzeige weiterzugeben, sodass der Puffer auf dem Bildschirm angezeigt oder weiter mit Ebenen zusammengesetzt werden kann, die nicht für die SurfaceFlinger-Komposition markiert wurden. Wenn keine Ebenen für die SurfaceFlinger-Komposition markiert sind, umgeht SurfaceFlinger den Kompositionsschritt.
Schließlich ruft SurfaceFlinger presentDisplay
auf, um das HWC anzuweisen, den Kompositionsprozess abzuschließen und das Endergebnis anzuzeigen.
Mehrere Displays
Android 10 unterstützt mehrere physische Displays. Beim Entwerfen einer HWC-Implementierung, die für die Verwendung auf Android 7.0 und höher vorgesehen ist, gibt es einige Einschränkungen, die in der HWC-Definition nicht enthalten sind:
- Es wird davon ausgegangen, dass es genau eine interne Anzeige gibt. Die interne Anzeige ist die Anzeige, die der anfängliche Hotplug beim Booten meldet. Nachdem das interne Display per Hotplug angeschlossen wurde, kann es nicht mehr getrennt werden.
- Zusätzlich zum internen Display können im normalen Betrieb des Geräts beliebig viele externe Displays per Hotplug angeschlossen werden. Das Framework geht davon aus, dass alle Hotplugs nach dem ersten internen Display externe Displays sind. Wenn also weitere interne Displays hinzugefügt werden, werden diese fälschlicherweise als
Display.TYPE_HDMI
statt alsDisplay.TYPE_BUILT_IN
kategorisiert.
Während die oben beschriebenen SurfaceFlinger-Vorgänge pro Anzeige ausgeführt werden, werden sie nacheinander für alle aktiven Anzeigen ausgeführt, auch wenn der Inhalt nur einer Anzeige aktualisiert wird.
Wenn beispielsweise die externe Anzeige aktualisiert wird, ist die Reihenfolge:
// In Android 9 and lower: // Update state for internal display // Update state for external display validateDisplay(<internal display>) validateDisplay(<external display>) presentDisplay(<internal display>) presentDisplay(<external display>) // In Android 10 and higher: // Update state for internal display // Update state for external display validateInternal(<internal display>) presentInternal(<internal display>) validateExternal(<external display>) presentExternal(<external display>)
Virtuelle Displaykomposition
Die Zusammensetzung der virtuellen Anzeige ähnelt der Zusammensetzung der externen Anzeige. Der Unterschied zwischen der Komposition virtueller Displays und der Komposition physischer Displays besteht darin, dass virtuelle Displays die Ausgabe an einen Gralloc-Puffer statt an den Bildschirm senden. Hardware Composer (HWC) schreibt die Ausgabe in einen Puffer, stellt den Abschlusszaun bereit und sendet den Puffer an einen Verbraucher (z. B. den Video-Encoder, die GPU, die CPU usw.). Virtuelle Displays können 2D/Blitter oder Overlays verwenden, wenn die Display-Pipeline in den Speicher schreibt.
Modi
Jeder Frame befindet sich in einem von drei Modi, nachdem SurfaceFlinger die validateDisplay()
HWC-Methode aufruft:
- GLES – Die GPU fügt alle Ebenen zusammen und schreibt direkt in den Ausgabepuffer. Das HWC ist an der Komposition nicht beteiligt.
- GEMISCHT – Die GPU fügt einige Schichten zum Framebuffer zusammen und HWC fügt den Framebuffer und die übrigen Schichten zusammen und schreibt direkt in den Ausgabepuffer.
- HWC – HWC fügt alle Schichten zusammen und schreibt direkt in den Ausgabepuffer.
Ausgabeformat
Die Ausgabeformate des virtuellen Anzeigepuffers hängen von ihrem Modus ab:
- GLES-Modus – Der EGL-Treiber legt das Ausgabepufferformat in
dequeueBuffer()
fest, normalerweiseRGBA_8888
. Der Verbraucher muss in der Lage sein, das vom Treiber festgelegte Ausgabeformat zu akzeptieren, sonst kann der Puffer nicht gelesen werden. - MIXED- und HWC-Modi – Wenn der Verbraucher CPU-Zugriff benötigt, legt er das Format fest. Andernfalls lautet das Format
IMPLEMENTATION_DEFINED
und Gralloc legt das beste Format basierend auf den Verwendungsflags fest. Gralloc legt beispielsweise ein YCbCr-Format fest, wenn der Verbraucher ein Videoencoder ist und HWC das Format effizient schreiben kann.
Synchronisationszäune
Synchronisations-(Synchronisations-)Zäune sind ein entscheidender Aspekt des Android-Grafiksystems. Durch Zäune kann die CPU-Arbeit unabhängig von der gleichzeitigen GPU-Arbeit ablaufen und nur blockiert werden, wenn eine echte Abhängigkeit besteht.
Wenn eine App beispielsweise einen Puffer übermittelt, der auf der GPU erzeugt wird, übermittelt sie auch ein Synchronisierungszaunobjekt. Dieser Zaun signalisiert, wenn die GPU mit dem Schreiben in den Puffer fertig ist.
Der HWC erfordert, dass die GPU das Schreiben von Puffern beendet, bevor Puffer angezeigt werden. Synchronisierungsgrenzen werden mit Puffern durch die Grafikpipeline geleitet und signalisieren, wenn Puffer geschrieben werden. Bevor ein Puffer angezeigt wird, prüft das HWC, ob der Synchronisierungszaun ein Signal gegeben hat, und wenn ja, zeigt es den Puffer an.
Weitere Informationen zu Synchronisierungszauns finden Sie unter Hardware Composer-Integration .