Implementieren Sie Hardware Composer HAL

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:

  1. Implementieren Sie ein nicht betriebsbereites HWC und senden Sie alle Kompositionsarbeiten an GLES.
  2. 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.
  3. 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:

  1. Verarbeitet Transaktionen, sofern vorhanden.
  2. Sperrt neue Grafikpuffer, falls vorhanden.
  3. 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 als Display.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, normalerweise RGBA_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 .