BufferQueue und Gralloc

Die BufferQueue-Klasse verbindet Komponenten, die Puffer von grafischen Daten erzeugen ( Producer ), mit Komponenten, die die Daten zur Anzeige oder weiteren Verarbeitung entgegennehmen ( Consumer ). Nahezu alles, was Puffer mit Grafikdaten durch das System bewegt, verlässt sich auf BufferQueue.

Der Gralloc-Speicherzuordner führt Pufferzuweisungen durch und wird durch zwei herstellerspezifische HIDL-Schnittstellen implementiert (siehe hardware/interfaces/graphics/allocator/ und hardware/interfaces/graphics/mapper/ ). Die Funktion allocate() nimmt erwartete Argumente (Breite, Höhe, Pixelformat) sowie eine Reihe von Verwendungs-Flags entgegen.

BufferQueue-Erzeuger und -Verbraucher

Verbraucher erstellen und besitzen die BufferQueue-Datenstruktur und können in anderen Prozessen als ihre Erzeuger existieren. Wenn ein Produzent einen Puffer benötigt, fordert er einen freien Puffer von BufferQueue an, indem er dequeueBuffer() aufruft und dabei die Breite, Höhe, das Pixelformat und die Verwendungs-Flags des Puffers angibt. Der Producer füllt dann den Puffer und gibt den Puffer an die Warteschlange zurück, indem er queueBuffer() . Als nächstes erwirbt der Konsument den Puffer mit der acquireBuffer() und verwendet den Inhalt des Puffers. Wenn der Konsument fertig ist, gibt er den Puffer an die Warteschlange zurück, indem er releaseBuffer() . Das Synchronisierungsframework steuert, wie sich Puffer durch die Android-Grafikpipeline bewegen.

Einige Eigenschaften der BufferQueue, wie z. B. die maximale Anzahl von Puffern, die sie aufnehmen kann, werden gemeinsam von Erzeuger und Verbraucher festgelegt. Die BufferQueue weist Puffer jedoch nach Bedarf zu. Puffer werden beibehalten, es sei denn, die Eigenschaften ändern sich; Wenn beispielsweise ein Produzent Puffer mit einer anderen Größe anfordert, werden alte Puffer freigegeben und neue Puffer bei Bedarf zugewiesen.

Pufferinhalte werden niemals von BufferQueue kopiert, da das Verschieben so vieler Daten ineffizient ist. Stattdessen werden Puffer immer von einem Handle übergeben.

Verfolgen von BufferQueue mit Systrace

Um zu verstehen, wie sich Grafikpuffer bewegen, verwenden Sie Systrace , ein Tool, das die Geräteaktivität über einen kurzen Zeitraum aufzeichnet. Der Grafikcode auf Systemebene ist gut instrumentiert, ebenso wie ein Großteil des relevanten App-Framework-Codes.

Um Systrace zu verwenden, aktivieren Sie die Tags gfx , view und sched . BufferQueue-Objekte werden im Trace angezeigt. Wenn Sie beispielsweise eine Ablaufverfolgung erstellen, während Grafikas Play-Video (SurfaceView) ausgeführt wird, zeigt Ihnen die Zeile mit der Bezeichnung SurfaceView , wie viele Puffer zu einem bestimmten Zeitpunkt in die Warteschlange gestellt wurden.

Der Wert erhöht sich, während die App aktiv ist, wodurch das Rendern von Frames durch den MediaCodec-Decoder ausgelöst wird. Der Wert wird verringert, während SurfaceFlinger arbeitet und Puffer verbraucht. Wenn ein Video mit 30 fps angezeigt wird, variiert der Wert der Warteschlange zwischen 0 und 1, da die Anzeige mit ~60 fps mit der Quelle Schritt halten kann. SurfaceFlinger wacht nur auf, wenn Arbeit zu erledigen ist, nicht 60 Mal pro Sekunde. Das System versucht Arbeit zu vermeiden und deaktiviert VSYNC, wenn nichts den Bildschirm aktualisiert.

Wenn Sie zu Grafikas Wiedergabevideo (TextureView) wechseln und eine neue Spur aufnehmen, sehen Sie eine Zeile mit der Bezeichnung com.android.grafika / com.android.grafika.PlayMovieActivity . Dies ist die Hauptebene der Benutzeroberfläche, die eine weitere BufferQueue ist. Da TextureView in die UI-Ebene und nicht in eine separate Ebene gerendert wird, werden alle videogesteuerten Aktualisierungen hier angezeigt.

Gralloc

Der Gralloc-Zuordner HAL hardware/libhardware/include/hardware/gralloc.h führt Pufferzuweisungen durch Verwendungs-Flags durch. Verwendungs-Flags umfassen Attribute wie:

  • Wie oft wird von der Software (CPU) auf den Speicher zugegriffen
  • Wie oft wird von der Hardware (GPU) auf den Speicher zugegriffen
  • Ob der Speicher als OpenGL ES (GLES)-Textur verwendet wird
  • Ob der Speicher von einem Videoencoder verwendet wird

Wenn beispielsweise das Pufferformat eines Herstellers RGBA_8888 Pixel angibt und der Hersteller angibt, dass auf den Puffer von der Software aus zugegriffen wird (was bedeutet, dass eine App Pixel auf der CPU berührt), erstellt Gralloc einen Puffer mit 4 Bytes pro Pixel in RGBA-Reihenfolge. Wenn stattdessen ein Hersteller angibt, dass auf seinen Puffer nur von der Hardware und als GLES-Textur zugegriffen wird, kann Gralloc alles tun, was der GLES-Treiber will, wie z. B. BGRA-Ordnung, nichtlineare Swizzled-Layouts und alternative Farbformate. Wenn Sie der Hardware erlauben, ihr bevorzugtes Format zu verwenden, kann die Leistung verbessert werden.

Einige Werte können auf bestimmten Plattformen nicht kombiniert werden. Beispielsweise erfordert das Video-Encoder-Flag möglicherweise YUV-Pixel, sodass das Hinzufügen von Softwarezugriff und die Angabe RGBA_8888 fehlschlagen.

Das von Gralloc zurückgegebene Handle kann über Binder zwischen Prozessen weitergegeben werden.

Geschützte Puffer

Das Gralloc-Verwendungsflag GRALLOC_USAGE_PROTECTED ermöglicht, dass der Grafikpuffer nur über einen hardwaregeschützten Pfad angezeigt wird. Diese Overlay-Ebenen sind die einzige Möglichkeit, DRM-Inhalte anzuzeigen (auf DRM-geschützte Puffer kann von SurfaceFlinger oder dem OpenGL ES-Treiber nicht zugegriffen werden).

DRM-geschütztes Video kann nur auf einer Overlay-Ebene dargestellt werden. Videoplayer, die geschützte Inhalte unterstützen, müssen mit SurfaceView implementiert werden. Software, die auf ungeschützter Hardware ausgeführt wird, kann den Puffer nicht lesen oder schreiben; hardwaregeschützte Pfade müssen auf dem Hardware Composer-Overlay erscheinen (d. h. geschützte Videos verschwinden aus der Anzeige, wenn Hardware Composer zur OpenGL ES-Komposition wechselt).

Einzelheiten zu geschützten Inhalten finden Sie unter DRM .