Die BufferQueue-Klasse verbindet Komponenten, die Puffer für grafische Daten generieren ( Produzenten ), mit Komponenten, die die Daten zur Anzeige oder Weiterverarbeitung akzeptieren ( Konsumenten ). Fast alles, was Puffer mit grafischen Daten durch das System bewegt, basiert auf BufferQueue.
Der Gralloc-Speicherzuweiser führt Pufferzuweisungen durch und wird über zwei herstellerspezifische HIDL-Schnittstellen implementiert (siehe hardware/interfaces/graphics/allocator/
und hardware/interfaces/graphics/mapper/
). Die Funktion allocate()
akzeptiert erwartete Argumente (Breite, Höhe, Pixelformat) sowie eine Reihe von Verwendungsflags.
BufferQueue-Produzenten und -Konsumenten
Verbraucher erstellen und besitzen die BufferQueue-Datenstruktur und können in anderen Prozessen als ihre Produzenten 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 Verwendungsflags des Puffers angibt. Anschließend füllt der Produzent den Puffer und gibt ihn durch Aufrufen queueBuffer()
an die Warteschlange zurück. Als nächstes erwirbt der Verbraucher den Puffer mit acquireBuffer()
und nutzt den Pufferinhalt. Wenn der Verbraucher fertig ist, gibt er den Puffer durch den Aufruf releaseBuffer()
an die Warteschlange zurück. Das Synchronisierungsframework steuert, wie sich Puffer durch die Android-Grafikpipeline bewegen.
Einige Eigenschaften der BufferQueue, beispielsweise die maximale Anzahl an Puffern, die sie aufnehmen kann, werden gemeinsam vom Produzenten und Konsumenten festgelegt. Allerdings weist die BufferQueue Puffer nach Bedarf zu. Puffer bleiben erhalten, es sei denn, die Eigenschaften ändern sich; Wenn ein Produzent beispielsweise Puffer mit einer anderen Größe anfordert, werden alte Puffer freigegeben und neue Puffer bei Bedarf zugewiesen.
Pufferinhalte werden von BufferQueue niemals kopiert, da das Verschieben so vieler Daten ineffizient ist. Stattdessen werden Puffer immer über ein Handle übergeben.
Verfolgen Sie 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 durchführen, während das Wiedergabevideo (SurfaceView) von Grafika ausgeführt wird, erfahren Sie in der Zeile mit der Bezeichnung „SurfaceView“ , wie viele Puffer zu einem bestimmten Zeitpunkt in der Warteschlange standen.
Der Wert erhöht sich, während die App aktiv ist, was das Rendern von Frames durch den MediaCodec-Decoder auslöst. Der Wert verringert sich, während SurfaceFlinger arbeitet und Puffer verbraucht. Bei der Wiedergabe von Videos mit 30 Bildern pro Sekunde variiert der Wert der Warteschlange zwischen 0 und 1, da die Anzeige mit ca. 60 Bildern pro Sekunde mit der Quelle mithalten kann. SurfaceFlinger wird nur aktiviert, wenn Arbeit erledigt werden muss, nicht 60 Mal pro Sekunde. Das System versucht, Arbeit zu vermeiden und deaktiviert VSYNC, wenn der Bildschirm nicht aktualisiert wird.
Wenn Sie zu Grafikas Play-Video (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, bei der es sich um eine weitere BufferQueue handelt. Da TextureView in der UI-Ebene und nicht in einer separaten Ebene gerendert wird, werden alle videogesteuerten Aktualisierungen hier angezeigt.
Gralloc
Der Gralloc-Allokator HAL hardware/libhardware/include/hardware/gralloc.h
führt Pufferzuweisungen über Nutzungsflags durch. Zu den Nutzungsflags gehören 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 Video-Encoder verwendet wird
Wenn beispielsweise das Pufferformat eines Herstellers RGBA_8888
Pixel angibt und der Hersteller angibt, dass über die Software auf den Puffer 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 ein Hersteller stattdessen angibt, dass auf seinen Puffer nur über Hardware und als GLES-Textur zugegriffen werden soll, kann Gralloc alles tun, was der GLES-Treiber verlangt, wie z. B. BGRA-Reihenfolge, 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 von RGBA_8888
fehlschlägt.
Das von Gralloc zurückgegebene Handle kann über Binder zwischen Prozessen übergeben werden.
Geschützte Puffer
Das Gralloc-Nutzungsflag GRALLOC_USAGE_PROTECTED
ermöglicht die Anzeige des Grafikpuffers nur über einen hardwaregeschützten Pfad. Diese Überlagerungsebenen sind die einzige Möglichkeit, DRM-Inhalte anzuzeigen (SurfaceFlinger oder der OpenGL ES-Treiber können nicht auf DRM-geschützte Puffer zugreifen).
DRM-geschützte Videos können nur auf einer Overlay-Ebene präsentiert werden. Videoplayer, die geschützte Inhalte unterstützen, müssen mit SurfaceView implementiert werden. Auf ungeschützter Hardware ausgeführte Software kann den Puffer weder lesen noch schreiben. Hardware-geschützte Pfade müssen auf dem Hardware Composer-Overlay angezeigt werden (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 .