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 (vedere hardware/interfaces/graphics/allocator/
e hardware/interfaces/graphics/mapper/
). La funzione allocate()
accetta gli argomenti previsti (larghezza, altezza, formato pixel) nonché un insieme di flag di utilizzo.
Produttori e consumatori di BufferQueue
I consumatori creano e possiedono la struttura 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 del buffer. Il produttore quindi popola il buffer e restituisce il buffer alla coda chiamando queueBuffer()
. Successivamente, il consumatore acquisisce il buffer con acquireBuffer()
e utilizza il contenuto del buffer. Al termine, il consumatore restituisce il buffer alla coda chiamando releaseBuffer()
. Il framework di sincronizzazione controlla il modo in cui i buffer si spostano attraverso la pipeline grafica Android.
Alcune caratteristiche di 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 conservati a meno che le caratteristiche non cambino; ad esempio, se un produttore richiede buffer di dimensione diversa, i vecchi buffer vengono liberati e i nuovi buffer vengono allocati su richiesta.
I contenuti del buffer non vengono mai copiati da BufferQueue, poiché spostare così tanti dati è inefficiente. Invece, i buffer vengono sempre passati da un handle.
Tieni traccia di BufferQueue con Systrace
Per capire come si muovono i buffer grafici, utilizza 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 esegui una traccia mentre è in esecuzione il video Play di Grafika (SurfaceView) , la riga denominata SurfaceView ti dice quanti buffer sono stati in coda in un dato momento.
Il valore aumenta mentre l'app è attiva, il che attiva il rendering dei fotogrammi da parte del decoder MediaCodec. Il valore diminuisce mentre SurfaceFlinger funziona e consuma buffer. Quando si mostra un video a 30 fps, il valore della coda varia da 0 a 1 perché la visualizzazione a ~60 fps può tenere il passo con la sorgente. SurfaceFlinger si riattiva solo quando c'è del lavoro da svolgere, non 60 volte al secondo. Il sistema tenta di evitare il lavoro e disabilita VSYNC se nulla sta aggiornando lo schermo.
Se passi al video di riproduzione di Grafika (TextureView) e prendi 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'HAL dell'allocatore Gralloc hardware/libhardware/include/hardware/gralloc.h
esegue le allocazioni del buffer tramite flag di utilizzo. I flag di utilizzo includono attributi come:
- La frequenza con cui si accederà alla memoria dal software (CPU)
- La frequenza con cui si accederà alla memoria dall'hardware (GPU)
- Se la memoria verrà utilizzata come texture OpenGL ES (GLES).
- Indica 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 si accederà 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 al suo buffer si accederà solo dall'hardware e come texture GLES, Gralloc può fare tutto ciò che il driver GLES desidera, come l'ordinamento BGRA, layout swizzled non lineari e formati di colore alternativi. Consentire all'hardware di utilizzare il 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 l'aggiunta dell'accesso al software e la specifica di RGBA_8888
non riescono.
L'handle restituito da Gralloc può essere passato tra processi tramite Binder.
Buffer protetti
Il flag di utilizzo Gralloc GRALLOC_USAGE_PROTECTED
consente la visualizzazione del buffer grafico solo attraverso un percorso protetto dall'hardware. Questi piani di sovrapposizione sono l'unico modo per visualizzare il contenuto DRM (non è possibile accedere ai buffer protetti da DRM 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 tramite hardware devono essere visualizzati sulla sovrapposizione di Hardware Composer (ovvero, i video protetti scompaiono dal display se Hardware Composer passa alla composizione OpenGL ES).
Per dettagli sui contenuti protetti, vedere DRM .