Die BufferQueue-Klasse verbindet Komponenten, die Buffers mit grafischen Daten generieren (Produzenten), mit Komponenten, die die Daten zur Anzeige oder weiteren Verarbeitung akzeptieren (Verbraucher). Fast alles, was Puffer mit grafischen Daten durch das System bewegt, basiert auf BufferQueue.
Der Gralloc-Speicherallokator führt Bufferzuweisungen durch und wird über zwei anbieterspezifische HIDL-Schnittstellen implementiert (siehe hardware/interfaces/graphics/allocator/
und hardware/interfaces/graphics/mapper/
). Die Funktion allocate()
nimmt die erwarteten Argumente (Breite, Höhe, Pixelformat) sowie eine Reihe von Nutzungsflags an.
BufferQueue-Ersteller und -Nutzer
Verbraucher erstellen und sind Eigentümer der BufferQueue-Datenstruktur und können in anderen Prozessen als ihre Ersteller vorhanden sein. Wenn ein Produzent einen Puffer benötigt, fordert er einen kostenlosen Puffer von BufferQueue an, indem er dequeueBuffer()
aufruft und die Breite, Höhe, das Pixelformat und die Nutzungsflags des Puffers angibt. Der Producer füllt dann den Puffer und gibt ihn durch Aufrufen von queueBuffer()
an die Warteschlange zurück. Als Nächstes ruft der Verbraucher den Puffer mit acquireBuffer()
ab und nutzt den Pufferinhalt. Wenn der Verbraucher fertig ist, gibt er den Puffer durch Aufrufen von releaseBuffer()
an die Warteschlange zurück. Das Synchronisierungs-Framework steuert, wie Buffers durch die Android-Grafikpipeline geleitet werden.
Einige Eigenschaften der BufferQueue, z. B. die maximale Anzahl der darin enthaltenen Buffers, werden gemeinsam vom Erzeuger und Verbraucher festgelegt. Die BufferQueue weist jedoch nach Bedarf Puffer zu. Buffers werden beibehalten, es sei denn, die Eigenschaften ändern sich. Wenn ein Produzent beispielsweise Buffers mit einer anderen Größe anfordert, werden alte Buffers freigegeben und neue Buffers werden bei Bedarf zugewiesen.
Der Pufferinhalt wird von BufferQueue nie kopiert, da das Verschieben so vieler Daten ineffizient ist. Stattdessen werden Buffers immer über einen Handle übergeben.
BufferQueue mit Systrace erfassen
Wenn Sie nachvollziehen möchten, wie sich Grafik-Buffers bewegen, verwenden Sie Systrace, ein Tool, mit dem die Geräteaktivität über einen kurzen Zeitraum aufgezeichnet wird. Der Grafikcode auf Systemebene ist gut instrumentiert, ebenso wie ein Großteil des relevanten App-Framework-Codes.
Wenn Sie Systrace verwenden möchten, aktivieren Sie die Tags gfx
, view
und sched
. BufferQueue-Objekte werden im Trace angezeigt.
Wenn Sie beispielsweise eine Aufzeichnung erstellen, während Grafika's Play-Video (SurfaceView) ausgeführt wird, sehen Sie in der Zeile SurfaceView, wie viele Buffers zu einem bestimmten Zeitpunkt in der Warteschlange waren.
Der Wert wird erhöht, während die App aktiv ist, was das Rendern von Frames durch den MediaCodec-Decoder auslöst. Der Wert nimmt ab, während SurfaceFlinger arbeitet und Buffers belegt. Wenn Videos mit 30 fps wiedergegeben werden, variiert der Wert der Warteschlange zwischen 0 und 1, da die Wiedergabe mit etwa 60 fps mit der Quelle mithalten kann. SurfaceFlinger wird nur dann gestartet, wenn Arbeit ansteht, nicht 60-mal pro Sekunde. Das System versucht, Arbeit zu vermeiden und deaktiviert VSYNC, wenn das Display nicht aktualisiert wird.
Wenn Sie zum Play-Video von Grafika (TextureView) wechseln und eine neue Spur erfassen, sehen Sie eine Zeile mit der Beschriftung com.android.grafika
 / com.android.grafika.PlayMovieActivity
.
Dies ist die Haupt-UI-Ebene, eine weitere BufferQueue. Da TextureView in der UI-Ebene und nicht in einer separaten Ebene gerendert wird, werden hier alle videobasierten Updates angezeigt.
Gralloch
Der Gralloc-Allocator HALhardware/libhardware/include/hardware/gralloc.h
führt die Pufferzuweisung über Nutzungsflags durch. Zu den Nutzungsflags gehören Attribute wie:
- Wie oft auf den Arbeitsspeicher von der Software (CPU) zugegriffen wird
- Gibt an, wie oft auf den Arbeitsspeicher von der Hardware (GPU) zugegriffen wird.
- Ob der Arbeitsspeicher als OpenGL ES-Textur (GLES) verwendet wird
- Ob der Arbeitsspeicher von einem Videoencoder verwendet wird
Wenn im Bufferformat eines Herstellers beispielsweise RGBA_8888
Pixel angegeben sind und der Hersteller angibt, dass auf den Buffer über Software zugegriffen wird (d. h., dass eine App Pixel auf der CPU berührt), erstellt Gralloc einen Buffer mit 4 Byte pro Pixel in der Reihenfolge R-G-B-A. Wenn ein Produzent stattdessen angibt, dass auf seinen Buffer nur über die Hardware und als GLES-Textur zugegriffen werden soll, kann Gralloc alles tun, was der GLES-Treiber benötigt, z. B. BGRA-Sortierung, nichtlineare vertauschte Layouts und alternative Farbformate. Wenn Sie der Hardware erlauben, ihr bevorzugtes Format zu verwenden, kann sich die Leistung verbessern.
Einige Werte können auf bestimmten Plattformen nicht kombiniert werden. Für das Videoencoder-Flag sind beispielsweise YUV-Pixel erforderlich. Wenn Sie also den Softwarezugriff hinzufügen und RGBA_8888
angeben, schlägt das fehl.
Der von Gralloc zurückgegebene Handle kann über Binder zwischen Prozessen übergeben werden.
Geschützte Puffer
Mit dem Gralloc-Nutzungsflag GRALLOC_USAGE_PROTECTED
kann der Grafikbuffer nur über einen hardwaregeschützten Pfad angezeigt werden. Diese Overlay-Ebenen sind die einzige Möglichkeit, DRM-Inhalte anzuzeigen. Auf DRM-geschützte Buffers kann nicht von SurfaceFlinger oder dem OpenGL ES-Treiber zugegriffen werden.
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. Software, die auf ungeschützter Hardware ausgeführt wird, kann den Puffer nicht lesen oder darauf schreiben. Hardware-geschützte Pfade müssen im Hardware Composer-Overlay angezeigt werden. Das bedeutet, dass geschützte Videos vom Display verschwinden, wenn der Hardware Composer zur OpenGL ES-Komposition wechselt.
Weitere Informationen zu geschützten Inhalten finden Sie unter Digital Rights Management.