BufferQueue e Gralloc

La classe BufferQueue collega i componenti che generano buffer di dati grafici ( produttori ) ai componenti che accettano i dati per la visualizzazione o l'ulteriore elaborazione ( consumatori ). Quasi tutto ciò che sposta i buffer di dati grafici attraverso il sistema si basa su BufferQueue.

L'allocatore di memoria Gralloc esegue allocazioni di buffer ed è implementato tramite due interfacce HIDL specifiche del fornitore (vedi hardware/interfaces/graphics/allocator/ e hardware/interfaces/graphics/mapper/ ). La funzione allocate() accetta gli argomenti previsti (larghezza, altezza, formato pixel) e un insieme di flag di utilizzo.

BufferQueue produttori e consumatori

I consumatori creano e possiedono la struttura dei dati BufferQueue e possono esistere in processi diversi rispetto ai loro produttori. Quando un produttore ha bisogno di un buffer, richiede un buffer libero da BufferQueue chiamando dequeueBuffer() , specificando la larghezza, l'altezza, il formato pixel e i flag di utilizzo dei buffer. Il produttore quindi compila il buffer e lo restituisce alla coda chiamando queueBuffer() . Successivamente, il consumatore acquisisce il buffer con acquireBuffer() e utilizza il contenuto del buffer. Quando il consumer ha terminato, restituisce il buffer alla coda chiamando releaseBuffer() . Il framework di sincronizzazione controlla il modo in cui i buffer si spostano attraverso la pipeline grafica di Android.

Alcune caratteristiche del BufferQueue, come il numero massimo di buffer che può contenere, sono determinate congiuntamente dal produttore e dal consumatore. Tuttavia, BufferQueue alloca i buffer quando ne ha bisogno. I buffer vengono mantenuti a meno che le caratteristiche non cambino; ad esempio, se un produttore richiede buffer di dimensioni diverse, i vecchi buffer vengono liberati e i nuovi buffer vengono assegnati su richiesta.

Il contenuto del buffer non viene mai copiato da BufferQueue, poiché spostare così tanti dati in giro è inefficiente. Al contrario, i buffer vengono sempre passati da un handle.

Tracciamento di BufferQueue con Systrace

Per capire come si muovono i buffer grafici, usa Systrace , uno strumento che registra l'attività del dispositivo in un breve periodo di tempo. Il codice grafico a livello di sistema è ben strumentato, così come gran parte del codice del framework dell'app pertinente.

Per utilizzare Systrace, abilita i tag gfx , view e sched . Gli oggetti BufferQueue vengono visualizzati nella traccia. Ad esempio, se si esegue una traccia mentre il video di riproduzione di Grafika (SurfaceView) è in esecuzione, la riga denominata SurfaceView indica quanti buffer sono stati accodati in un dato momento.

Il valore aumenta mentre l'app è attiva, il che attiva il rendering dei frame da parte del decoder MediaCodec. Il valore diminuisce mentre SurfaceFlinger funziona e consuma i buffer. Quando si mostra un video a 30 fps, il valore della coda varia da 0 a 1 perché il display a ~60 fps può tenere il passo con la sorgente. SurfaceFlinger si riattiva solo quando c'è del lavoro da fare, non 60 volte al secondo. Il sistema cerca di evitare il lavoro e disabilita VSYNC se nulla sta aggiornando lo schermo.

Se passi a Grafika's Play video (TextureView) e acquisisci una nuova traccia, vedrai una riga etichettata com.android.grafika / com.android.grafika.PlayMovieActivity . Questo è il livello principale dell'interfaccia utente, che è un altro BufferQueue. Poiché TextureView esegue il rendering nel livello dell'interfaccia utente anziché in un livello separato, tutti gli aggiornamenti guidati dal video vengono visualizzati qui.

Gralloc

L'allocatore Gralloc HAL hardware/libhardware/include/hardware/gralloc.h esegue allocazioni del buffer tramite flag di utilizzo. I flag di utilizzo includono attributi come:

  • Con quale frequenza si accederà alla memoria dal software (CPU)
  • Con quale frequenza si accederà alla memoria dall'hardware (GPU)
  • Se la memoria verrà utilizzata come texture OpenGL ES (GLES).
  • Se la memoria verrà utilizzata da un codificatore video

Ad esempio, se il formato del buffer di un produttore specifica i pixel RGBA_8888 e il produttore indica che sarà possibile accedere al buffer dal software (il che significa che un'app toccherà i pixel sulla CPU), Gralloc crea un buffer con 4 byte per pixel in ordine RGBA. Se invece un produttore specifica che il suo buffer sarà accessibile solo dall'hardware e come texture GLES, Gralloc può fare tutto ciò che il driver GLES vuole, come ordini BGRA, layout swizzled non lineari e formati di colore alternativi. Consentire all'hardware di utilizzare il suo formato preferito può migliorare le prestazioni.

Alcuni valori non possono essere combinati su determinate piattaforme. Ad esempio, il flag del codificatore video potrebbe richiedere pixel YUV, quindi aggiungere l'accesso al software e specificare RGBA_8888 non riesce.

L'handle restituito da Gralloc può essere passato tra processi tramite Binder.

Buffer protetti

Il flag di utilizzo di Gralloc GRALLOC_USAGE_PROTECTED consente al buffer grafico di essere visualizzato solo attraverso un percorso protetto dall'hardware. Questi piani di sovrapposizione sono l'unico modo per visualizzare il contenuto DRM (i buffer protetti da DRM non sono accessibili da SurfaceFlinger o dal driver OpenGL ES).

Il video protetto da DRM può essere presentato solo su un piano di sovrapposizione. I lettori video che supportano il contenuto protetto devono essere implementati con SurfaceView. Il software in esecuzione su hardware non protetto non può leggere o scrivere il buffer; i percorsi protetti dall'hardware devono apparire sull'overlay di Hardware Composer (ovvero, i video protetti scompaiono dal display se Hardware Composer passa alla composizione OpenGL ES).

Per i dettagli sul contenuto protetto, vedere DRM .