Hardware Composer HAL implementieren

Der Hardware Composer (HWC) HAL fasst die von SurfaceFlinger empfangenen Ebenen zusammen, wodurch die Menge der Zusammensetzung von OpenGL ES (GLES) und der GPU reduziert wird.

Der HWC abstrahiert Objekte wie Overlays und 2D-Blitter zur Komposition von Oberflächen und kommuniziert mit spezieller Hardware für die Fensterkomposition, um Fenster zu kombinieren. Verwenden Sie die HWC zum Zusammensetzen von Fenstern, anstatt SurfaceFlinger mit der GPU zusammenzusetzen. Die meisten GPUs sind nicht für die Komposition optimiert. Wenn die GPU Ebenen aus SurfaceFlinger zusammensetzt, können Apps die GPU nicht für ihr eigenes Rendering verwenden.

HWC-Implementierungen sollten Folgendes unterstützen:

  • Mindestens vier Overlays:
    • Statusleiste
    • Systemleiste
    • App
    • Hintergrund
  • Ebenen, die größer als das Display sind (z. B. ein Hintergrund)
  • Gleichzeitige vormultiplizierte Alphamischung pro Pixel und Alphamischung pro Ebene
  • Hardwarepfad für die Wiedergabe geschützter Videos
  • RGBA-Paketreihenfolge, YUV-Formate sowie Eigenschaften für das Tiling, das Swizzlen und den Schritt

So implementieren Sie die HWC:

  1. Implementieren Sie einen nicht funktionsfähigen HWC und senden Sie alle Zusammenstellungsarbeiten an GLES.
  2. Implementieren Sie einen Algorithmus, um die Komposition schrittweise an die HWC zu delegieren. Weisen Sie beispielsweise nur die ersten drei oder vier Oberflächen der Overlay-Hardware des HWC zu.
  3. HWC optimieren Dazu gehören unter anderem:
    • Auswahl von Oberflächen, die die Last von der GPU maximieren und an die HWC senden.
    • Erkennen, ob der Bildschirm aktualisiert wird Andernfalls delegieren Sie die Zusammensetzung an GLES anstelle der HWC, um Strom zu sparen. Wenn sich das Display wieder aktualisiert, lade die Zusammensetzung weiterhin an die HWC aus.
    • Vorbereitung auf gängige Anwendungsfälle wie:
      • Der Startbildschirm mit Statusleiste, Systemleiste, App-Fenster und Live-Hintergründen
      • Vollbildspiele im Hoch- und Querformat
      • Vollbildvideo mit Untertiteln und Wiedergabesteuerung
      • Wiedergabe geschützter Videos
      • Splitscreen-Multiwindow

HWC-Primitive

Die HWC bietet zwei Primitive, Ebenen und Displays, um die Zusammensetzung und ihre Interaktion mit der Displayhardware darzustellen. Der HWC bietet auch eine Steuerung für VSYNC und einen Rückruf an SurfaceFlinger, um ihn über ein VSYNC-Ereignis zu benachrichtigen.

HIDL-Schnittstelle

Android 8.0 und höher verwenden eine HIDL-Schnittstelle namens Composer HAL für die bindungsbasierte IPC zwischen HWC und SurfaceFlinger. Die Composer HAL ersetzt die alte hwcomposer2.h-Benutzeroberfläche. Wenn Anbieter eine Composer HAL-Implementierung der HWC bereitstellen, akzeptiert die Composer HAL HIDL-Aufrufe direkt von SurfaceFlinger. Wenn Anbieter eine ältere Implementierung der HWC bereitstellen, lädt Composer HAL Funktionszeigeter aus hwcomposer2.h und leitet HIDL-Aufrufe an Funktionszeigeraufrufe weiter.

Die HWC bietet Funktionen zum Ermitteln der Eigenschaften eines bestimmten Displays, zum Wechseln zwischen verschiedenen Displaykonfigurationen (z. B. 4K oder 1080p) und Farbmodi (z. B. native Farbe oder echtes sRGB) sowie zum Ein- und Ausschalten des Displays oder zum Aktivieren eines Energiesparmodus, sofern unterstützt.

Funktionszeiger

Wenn Anbieter die Composer HAL direkt implementieren, ruft SurfaceFlinger die Funktionen über HIDL IPC auf. Wenn beispielsweise eine Ebene erstellt werden soll, ruft SurfaceFlinger createLayer() in der Composer HAL auf.

Wenn Anbieter die hwcomposer2.h-Schnittstelle implementieren, ruft Composer HAL hwcomposer2.h-Funktionszeigers auf. In hwcomposer2.h-Kommentaren werden HWC-Schnittstellenfunktionen mit Namen im CamelCase-Format bezeichnet, die in der Schnittstelle nicht als benannte Felder vorhanden sind. Fast jede Funktion wird geladen, indem ein Funktionszeiger mit getFunction angefordert wird, der von hwc2_device_t bereitgestellt wird. Die Funktion createLayer ist beispielsweise ein Funktionszeiger vom Typ HWC2_PFN_CREATE_LAYER, der zurückgegeben wird, wenn der enumerierte Wert HWC2_FUNCTION_CREATE_LAYER an getFunction übergeben wird.

Eine ausführliche Dokumentation zu HAL-Funktionen von Composer und Funktionen zur Weiterleitung von HWC-Funktionen finden Sie unter composer. Eine ausführliche Dokumentation zu HWC-Funktionszeigern finden Sie unter hwcomposer2.h.

Ziehpunkte für Ebenen und Displays

Ebenen und Displays werden über vom HWC generierte Handles manipuliert. Die Handles sind für SurfaceFlinger nicht transparent.

Wenn SurfaceFlinger eine neue Ebene erstellt, ruft es createLayer auf, das bei direkten Implementierungen den Typ Layer und bei Passthrough-Implementierungen den Typ hwc2_layer_t zurückgibt. Wenn SurfaceFlinger eine Eigenschaft dieser Ebene ändert, gibt SurfaceFlinger den Wert hwc2_layer_t zusammen mit allen anderen Informationen, die für die Änderung erforderlich sind, an die entsprechende Änderungsfunktion weiter. Der Typ hwc2_layer_t ist groß genug, um entweder einen Verweis oder einen Index zu enthalten.

Physische Displays werden durch Hotplugging erstellt. Wenn ein physisches Display Hot-Plugged wird, erstellt die HWC einen Handle und übergibt ihn über den Hotplug-Callback an SurfaceFlinger. Virtuelle Displays werden von SurfaceFlinger erstellt, indem createVirtualDisplay() aufgerufen wird, um ein Display anzufordern. Wenn die HWC die Zusammensetzung virtueller Displays unterstützt, gibt sie einen Handle zurück. Anschließend delegiert SurfaceFlinger die Zusammensetzung der Displays an die HWC. Wenn die HWC die Zusammensetzung des virtuellen Displays nicht unterstützt, erstellt SurfaceFlinger den Handle und stellt das Display zusammen.

Displayzusammensetzungsvorgänge

Einmal pro VSYNC wird SurfaceFlinger gestartet, wenn neue Inhalte zusammengesetzt werden müssen. Diese neuen Inhalte können neue Bildbuffer von Apps oder eine Änderung der Eigenschaften einer oder mehrerer Ebenen sein. Wenn SurfaceFlinger es aufweckt:

  1. Verwaltet Transaktionen, falls vorhanden.
  2. Verriegelt neue Grafik-Buffer, falls vorhanden.
  3. Führt eine neue Zusammensetzung aus, wenn Schritt 1 oder 2 zu einer Änderung der angezeigten Inhalte geführt hat.

Für eine neue Komposition erstellt und zerstört SurfaceFlinger Ebenen oder ändert gegebenenfalls deren Status. Außerdem werden Ebenen mit ihren aktuellen Inhalten aktualisiert, indem Aufrufe wie setLayerBuffer oder setLayerColor verwendet werden. Nachdem alle Ebenen aktualisiert wurden, ruft SurfaceFlinger validateDisplay auf, wodurch die HWC aufgefordert wird, den Status der Ebenen zu prüfen und zu bestimmen, wie die Zusammensetzung fortgesetzt wird. Standardmäßig versucht SurfaceFlinger, jede Ebene so zu konfigurieren, dass sie vom HWC zusammengesetzt wird. In einigen Fällen stellt SurfaceFlinger Ebenen jedoch über den GPU-Fallback zusammen.

Nach dem Aufruf von validateDisplay ruft SurfaceFlinger getChangedCompositionTypes auf, um zu prüfen, ob die HWC einen der Ebenenzusammensetzungstypen ändern möchte, bevor die Zusammensetzung ausgeführt wird. Um die Änderungen zu akzeptieren, ruft SurfaceFlinger acceptDisplayChanges auf.

Wenn Ebenen für die SurfaceFlinger-Komposition markiert sind, werden sie von SurfaceFlinger in den Zielpuffer zusammengesetzt. SurfaceFlinger ruft dann setClientTarget auf, um den Puffer an das Display weiterzuleiten, damit er auf dem Bildschirm angezeigt oder mit Ebenen kombiniert werden kann, die nicht für die SurfaceFlinger-Komposition gekennzeichnet wurden. Wenn keine Ebenen für die SurfaceFlinger-Komposition gekennzeichnet sind, überspringt SurfaceFlinger den Kompositionschritt.

Schließlich ruft SurfaceFlinger presentDisplay auf, um dem HWC zu signalisieren, dass der Zusammensetzungsprozess abgeschlossen und das Endergebnis angezeigt werden soll.

Mehrere Displays

Android 10 unterstützt mehrere physische Displays. Bei der Entwicklung einer HWC-Implementierung für Android 7.0 und höher gelten einige Einschränkungen, die in der HWC-Definition nicht enthalten sind:

  • Es wird davon ausgegangen, dass es genau ein internes Display gibt. Das interne Display ist das Display, das beim Starten vom hotplug-Dienst gemeldet wird. Nachdem das interne Display per Hotplug verbunden wurde, kann es nicht mehr getrennt werden.
  • Zusätzlich zum internen Display kann während des normalen Betriebs des Geräts eine beliebige Anzahl externer Displays per Hot-Plug 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 sie fälschlicherweise als Display.TYPE_HDMI statt als Display.TYPE_BUILT_IN kategorisiert.

Die oben beschriebenen SurfaceFlinger-Vorgänge werden zwar pro Display ausgeführt, aber nacheinander für alle aktiven Displays, auch wenn nur der Inhalt eines Displays aktualisiert wird.

Wenn beispielsweise das externe Display aktualisiert wird, sieht die Abfolge so aus:

// 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>)

Zusammensetzung virtueller Displays

Die Zusammensetzung des virtuellen Displays ähnelt der eines externen Displays. Der Unterschied zwischen der Zusammensetzung virtueller und physischer Displays besteht darin, dass virtuelle Displays die Ausgabe an einen Gralloc-Puffer statt an das Display senden. Der Hardware Composer (HWC) schreibt die Ausgabe in einen Puffer, stellt den Abschlusszaun bereit und sendet den Puffer an einen Verbraucher (z. B. den Videoencoder, die GPU oder die CPU). Virtuelle Displays können 2D/Blitter oder Overlays verwenden, wenn die Displaypipeline in den Arbeitsspeicher schreibt.

Modi

Jeder Frame befindet sich in einem der drei Modi, nachdem SurfaceFlinger die validateDisplay()-HWC-Methode aufgerufen hat:

  • GLES: Die GPU kombiniert alle Ebenen und schreibt direkt in den Ausgabebuffer. Der HWC ist nicht an der Komposition beteiligt.
  • MIXED: Die GPU kombiniert einige Ebenen mit dem Framebuffer und HWC kombiniert den Framebuffer mit den verbleibenden Ebenen und schreibt direkt in den Ausgabebuffer.
  • HWC: HWC kombiniert alle Ebenen und schreibt sie direkt in den Ausgabebuffer.

Ausgabeformat

Die Ausgabeformate des virtuellen Display-Buffers hängen vom Modus ab:

  • GLES-Modus: Der EGL-Treiber legt das Ausgabebufferformat in dequeueBuffer() fest, normalerweise RGBA_8888. Der Verbraucher muss das vom Treiber festgelegte Ausgabeformat akzeptieren können, da der Puffer sonst nicht gelesen werden kann.
  • MIXED- und HWC-Modi: Wenn der Verbraucher CPU-Zugriff benötigt, legt er das Format fest. Andernfalls ist das Format IMPLEMENTATION_DEFINED und Gralloc legt das beste Format basierend auf den Nutzungsflags fest. Beispielsweise legt Gralloc ein YCbCr-Format fest, wenn der Verbraucher ein Videoencoder ist und HWC das Format effizient schreiben kann.

Synchronisationsschranken

Synchronisationssperren sind ein wichtiger Aspekt des Android-Grafiksystems. Mit Fences können CPU-Arbeiten unabhängig von gleichzeitigen GPU-Arbeiten ausgeführt werden. Sie werden nur blockiert, wenn eine echte Abhängigkeit besteht.

Wenn eine App beispielsweise einen Puffer einreicht, der auf der GPU erstellt wird, reicht sie auch ein Synchronisationsobjekt ein. Dieser Zaun signalisiert, dass die GPU mit dem Schreiben in den Puffer fertig ist.

Der HWC erfordert, dass die GPU das Schreiben von Buffers beendet, bevor Buffers angezeigt werden. Synchronisationsschranken werden mit Buffers durch die Grafikpipeline übergeben und signalisieren, wenn Buffers geschrieben werden. Bevor ein Puffer angezeigt wird, prüft der HWC, ob der Synchronisierungs-Fence ein Signal gesendet hat. Ist das der Fall, wird der Puffer angezeigt.

Weitere Informationen zu Synchronisierungsschranken finden Sie unter Hardware Composer-Integration.