BufferQueue e Gralloc

La classe BufferQueue collega i componenti che generano buffer di dati grafici ( produttori ) a componenti che accettano i dati per la visualizzazione o l'ulteriore elaborazione ( consumatori ). Quasi tutto ciò che muove 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) così come un insieme di flag di utilizzo.

BufferQueue produttori e consumatori

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 gratuito da BufferQueue chiamando dequeueBuffer() , specificando la larghezza, l'altezza, il formato dei pixel e le 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. Quando il consumatore ha finito, 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 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 tamponi vengono conservati a meno che le caratteristiche non cambino; ad esempio, se un produttore richiede buffer con una dimensione diversa, i vecchi buffer vengono liberati e nuovi buffer vengono allocati su richiesta.

I contenuti del buffer non vengono mai copiati da BufferQueue, poiché lo spostamento di così tanti dati è inefficiente. Invece, i buffer vengono sempre passati da un handle.

Monitoraggio 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, abilitare il gfx , view , e sched tag. Gli oggetti BufferQueue vengono visualizzati nella traccia. Ad esempio, se prendi una traccia mentre il video di riproduzione di Grafika (SurfaceView) è in esecuzione, la riga etichettata SurfaceView ti dice quanti buffer sono stati messi in coda 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é la visualizzazione di ~ 60 fps può tenere il passo con la sorgente. SurfaceFlinger si attiva 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 al video di riproduzione di Grafika (TextureView) e prendi una nuova traccia, vedrai una riga denominata com.android.grafika / com.android.grafika.PlayMovieActivity . Questo è il livello dell'interfaccia utente principale, 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 di buffer tramite flag di utilizzo. I flag di utilizzo includono attributi come:

  • Con quale frequenza si accederà alla memoria dal software (CPU)
  • La frequenza con cui si accederà alla memoria dall'hardware (GPU)
  • Indica 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 RGBA_8888 pixel 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 il suo buffer sarà accessibile solo dall'hardware e come texture GLES, Gralloc può fare tutto ciò che vuole il driver GLES, 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 riesce.

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

Buffer protetti

Il flag di utilizzo di Gralloc GRALLOC_USAGE_PROTECTED consente la visualizzazione del buffer grafico solo tramite 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 essere visualizzati 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 .