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 buffer di dati grafici nel 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.

Produttori e consumatori di BufferQueue

I consumatori creano e possiedono la struttura di dati BufferQueue e possono esistere in procedimenti 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 dei pixel e i flag di utilizzo dei buffer. Il produttore compila quindi il buffer e lo restituisce alla coda chiamando queueBuffer(). Successivamente, il consumatore acquisisce il buffer con acquireBuffer() e utilizza i contenuti del buffer. Al termine, il consumatore restituisce il buffer alla coda chiamando releaseBuffer(). Il framework di sincronizzazione controlla come i buffer si spostano nella pipeline grafica di Android.

Alcune caratteristiche di BufferQueue, ad esempio il numero massimo di buffer che può contenere, vengono determinate congiuntamente dal producer e dal consumer. Tuttavia, BufferQueue alloca i buffer in base alle proprie esigenze. I buffer vengono mantenuti a meno che le caratteristiche non cambino; ad esempio, se un produttore richiede buffer di dimensioni diverse, i buffer vecchi vengono liberati e quelli nuovi vengono allocati su richiesta.

I contenuti del buffer non vengono mai copiati da BufferQueue, poiché spostare così tanti dati non è efficiente. I buffer vengono invece sempre passati da un handle.

Monitorare BufferQueue con Systrace

Per capire come si spostano 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 per app pertinente.

Per utilizzare Systrace, attiva i tag gfx, view e sched. Gli oggetti BufferQueue vengono visualizzati nella traccia. Ad esempio, se acquisisci una traccia mentre è in esecuzione il video di Grafika (SurfaceView), la riga etichettata come SurfaceView indica quanti buffer sono stati messi in coda in un determinato momento.

Il valore aumenta mentre l'app è attiva, il che attiva il rendering delle cornici da parte del decodificatore MediaCodec. Il valore diminuisce mentre SurfaceFlinger è in funzione e consuma buffer. Quando viene mostrato un video a 30 fps, il valore della coda varia da 0 a 1 perché la visualizzazione a circa 60 fps può stare al 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 disattiva VSYNC se non c'è nulla che aggiorna lo schermo.

Se passi al video di Grafika Play (TextureView) e acquisisci una nuova traccia, vedrai una riga etichettata come com.android.grafika / com.android.grafika.PlayMovieActivity. Questo è il livello dell'interfaccia utente principale, che è un'altra BufferQueue. Poiché TextureView viene visualizzato nel livello dell'interfaccia utente anziché in un livello separato, tutti gli aggiornamenti basati sui video vengono visualizzati qui.

Gralloc

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

  • La frequenza con cui verrà eseguito l'accesso alla memoria dal software (CPU)
  • La frequenza con cui verrà eseguito l'accesso 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 verrà eseguito l'accesso al buffer dal software (ovvero un'app toccherà i pixel sulla CPU), Gralloc crea un buffer con 4 byte per pixel nell'ordine R-G-B-A. 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, ad esempio l'ordinamento BGRA, i layout con swizzle non lineari e i 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, pertanto l'aggiunta dell'accesso al software e la specifica di RGBA_8888 non va a buon fine.

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

Buffer protetti

Il flag di utilizzo Gralloc GRALLOC_USAGE_PROTECTED consente di visualizzare il buffer grafico solo tramite un percorso protetto dall'hardware. Questi piani di overlay sono l'unico modo per visualizzare i contenuti DRM (non è possibile accedere ai buffer protetti da DRM da parte di SurfaceFlinger o del driver OpenGL ES).

I video protetti da DRM possono essere presentati solo su un piano di overlay. I video player che supportano i contenuti protetti 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 Hardware Composer (ovvero i video protetti scompaiono dal display se Hardware Composer passa alla composizione OpenGL ES).

Per informazioni dettagliate sui contenuti protetti, vedi DRM.