L'HAL Hardware Composer (HWC) compone i livelli ricevuti da SurfaceFlinger, riducendo la quantità di composizione OpenGL ES (GLES) e le prestazioni della GPU.
L'HWC esegue l'astrazione di oggetti, come overlay e blitter 2D, per le superfici composite e comunica con l'hardware specializzato per la composizione delle finestre per comporre le finestre. Utilizza l'HWC per comporre le finestre anziché avere la composizione di SurfaceFlinger con la GPU. La maggior parte delle GPU non è ottimizzata per la composizione e, quando la GPU compone i livelli da SurfaceFlinger, le app non possono utilizzare la GPU per il proprio rendering.
Le implementazioni HWC devono supportare:
- Almeno quattro overlay:
- Barra di stato
- Barra di sistema
- App
- Sfondo/sfondo
- Livelli più grandi del display (ad esempio uno sfondo)
- Fusione alfa premoltiplicata per pixel e fusione alfa per piano simultanee
- Percorso hardware per la riproduzione di video protetti
- Ordine di imballaggio RGBA, formati YUV e affiancamento, roteare e passo proprietà
Per implementare HWC:
- Implementa un HWC non operativo e invia tutto il lavoro di composizione a GLES.
- Implementare un algoritmo per delegare la composizione all'HWC in modo incrementale. Ad esempio, delega solo le prime tre o quattro piattaforme all'hardware di overlay del HWC.
- Ottimizza l'HWC. Ecco alcuni esempi:
- Selezionare le piattaforme che massimizzano il carico rimosso dalla GPU e inviarle all'HWC.
- Rileva se lo schermo è in aggiornamento. In caso contrario, delega in GLES anziché in HWC per risparmiare energia. Quando la schermata si aggiorna di nuovo, continua a scaricare la composizione sull'HWC.
- Prepararsi a casi d'uso comuni come:
- La schermata Home, che include la barra di stato, la barra di sistema, la finestra dell'app e gli sfondi animati
- Giochi a schermo intero in modalità verticale e orizzontale
- Video a schermo intero con sottotitoli codificati e controllo della riproduzione
- Riproduzione di video protetti
- Multischermo con schermo diviso
Primitive HWC
HWC fornisce due primitive, layer e display, per rappresentare le opere di composizione e la sua interazione con l'hardware del display. L'HWC fornisce anche il controllo su VSYNC e un callback a SurfaceFlinger per notificare quando si verifica un evento VSYNC.
Interfaccia HIDL
Android 8.0 e versioni successive utilizza un
Interfaccia HIDL chiamata Composer HAL per
IPC binderizzato tra HWC e SurfaceFlinger. Composer HAL sostituisce
nell'interfaccia precedente di hwcomposer2.h
. Se i fornitori forniscono un'implementazione dell'HWC per Composer HAL, quest'ultimo accetta direttamente le chiamate HIDL da SurfaceFlinger. Se i fornitori forniscono un'implementazione precedente dell'HWC, Composer
HAL carica i puntatori funzione da hwcomposer2.h
,
inoltra le chiamate HIDL alle chiamate dei puntatori funzione.
L'HWC fornisce funzioni per determinare le proprietà di un determinato display, per passare da una configurazione all'altra (ad esempio la risoluzione 4K o 1080p) e per le modalità di colore (ad esempio il colore nativo o il vero sRGB) e per accendere, spegnere o mettere il display in modalità a basso consumo, se supportata.
Puntatori di funzione
Se i fornitori implementano direttamente l'HAL Composer, SurfaceFlinger chiama le relative funzioni tramite l'IPC HIDL. Ad esempio, per creare un livello, SurfaceFlinger chiama
createLayer()
nell'HAL Composer.
Se i fornitori implementano l'interfaccia hwcomposer2.h
, Composer HAL
nei puntatori di funzione hwcomposer2.h
. In hwcomposer2.h
commenti,
Le funzioni dell'interfaccia HWC
a cui si fa riferimento con nomi emptyCamelCase che non esistono nell'interfaccia
come campi denominati. Quasi tutte le funzioni vengono caricate richiedendo un
puntatore a funzione utilizzando getFunction
fornito da
hwc2_device_t
. Ad esempio, la funzione createLayer
è un puntatore di funzione di tipo HWC2_PFN_CREATE_LAYER
, che viene restituito quando il valore enumerato HWC2_FUNCTION_CREATE_LAYER
viene passato a getFunction
.
Per la documentazione dettagliata sulle funzioni HAL di Composer e sul passthrough delle funzioni HWC
vedi composer
. Per una documentazione dettagliata sui puntatori di funzione HWC, consulta il hwcomposer2.h
.
Handle per livelli e visualizzazione
Livelli e visualizzazioni vengono manipolati tramite i punti di manipolazione generati da HWC. Gli handle sono opachi per SurfaceFlinger.
Quando SurfaceFlinger crea un nuovo livello, chiama createLayer
,
che restituisce un valore di tipo Layer
per le implementazioni dirette o hwc2_layer_t
per le implementazioni passthrough. Quando
SurfaceFlinger modifica una proprietà dello strato, SurfaceFlinger passa
Il valore hwc2_layer_t
nella funzione di modifica appropriata
ed eventuali altre informazioni necessarie per apportare la modifica. Il tipo hwc2_layer_t
è abbastanza grande da contenere un puntatore o un indice.
I display fisici vengono creati tramite il collegamento a caldo. Quando viene mostrato un display fisico
HWC crea un handle e lo passa a SurfaceFlinger
con il callback hotplug. I display virtuali vengono creati da SurfaceFlinger chiamando createVirtualDisplay()
per richiedere un display. Se l'HWC
supporta la composizione in display virtuale, restituisce un handle. Quindi, SurfaceFlinger
delega la composizione dei display all'HWC. Se l'HWC non supporta la composizione del display virtuale, SurfaceFlinger crea l'handle e compone il display.
Operazioni di composizione della visualizzazione
Una volta per VSYNC, SurfaceFlinger si riattiva se ha nuovi contenuti da compositare. Questi nuovi contenuti possono essere nuovi buffer di immagini delle app o una modifica delle proprietà di uno o più livelli. Quando SurfaceFlinger lo attiva:
- Gestisce le transazioni, se presenti.
- Memorizza i nuovi buffer grafici, se presenti.
- Esegui una nuova composizione se il passaggio 1 o 2 ha comportato una modifica ai contenuti visualizzati.
Per eseguire una nuova composizione, SurfaceFlinger crea e distrugge i livelli o ne modifica gli stati, a seconda dei casi. Inoltre, si aggiorna
con i loro contenuti attuali, usando chiamate come
setLayerBuffer
o setLayerColor
. Dopo che tutti i livelli sono stati aggiornati, SurfaceFlinger chiama validateDisplay
, che indica all'HWC di esaminare lo stato dei livelli e determinare come procedere con la composizione. Per impostazione predefinita, SurfaceFlinger tenta di configurare ogni livello
in modo che lo strato sia composto dall'HWC; anche se in alcuni
circostanze, SurfaceFlinger compone gli strati attraverso il fallback della GPU.
Dopo la chiamata a validateDisplay
, SurfaceFlinger chiama
getChangedCompositionTypes
per vedere se l'HWC
desidera modificare uno qualsiasi dei tipi di composizione dei livelli prima di eseguire
composizione. Per accettare le modifiche, SurfaceFlinger chiama
acceptDisplayChanges
.
Se alcuni strati sono contrassegnati per la composizione di SurfaceFlinger, SurfaceFlinger
le compone nel buffer di destinazione. SurfaceFlinger chiama quindi
setClientTarget
per trasferire il buffer al display in modo che
il buffer può essere visualizzato sullo schermo o ulteriormente combinato con strati
non sono state contrassegnate per la composizione SurfaceFlinger. Se non sono contrassegnati livelli per la composizione di SurfaceFlinger, SurfaceFlinger ignora il passaggio di composizione.
Infine, SurfaceFlinger chiama presentDisplay
per indicare all'HWC di completare la procedura di composizione e visualizzare il risultato finale.
Più display
Android 10 supporta più display fisici. Durante la progettazione di un'implementazione HWC destinata all'uso su Android 7.0 e superiore, esistono alcune restrizioni non presenti nella definizione di HWC:
- Si presume che sia presente un solo display interno. Il display interno è quello segnalato dal hotplug iniziale durante l'avvio. Una volta collegato il display interno, non può essere disconnesso.
- Oltre al display interno, può essere collegato a caldo qualsiasi numero di display esterni
durante il normale funzionamento del dispositivo. Il framework presuppone che tutti
i connettori a caldo dopo il primo display interno sono display esterni, quindi se
vengono aggiunti display interni, sono classificati erroneamente come
Display.TYPE_HDMI
anzichéDisplay.TYPE_BUILT_IN
.
Le operazioni SurfaceFlinger descritte in precedenza vengono eseguite per display, vengono eseguite in sequenza per tutte le visualizzazioni attive anche se i contenuti di un solo display vengono aggiornati.
Ad esempio, se il display esterno viene aggiornato, la sequenza è:
// In Android 9 and lower: // Update state for internal display // Update state for external display validateDisplay(<internal display>) validateDisplay(<external display>) presentDisplay(<internal display>) presentDisplay(<external display>) // In Android 10 and higher: // Update state for internal display // Update state for external display validateInternal(<internal display>) presentInternal(<internal display>) validateExternal(<external display>) presentExternal(<external display>)
Composizione display virtuale
La composizione del display virtuale è simile alla composizione del display esterno. La differenza tra la composizione del display virtuale e la composizione del display fisico è che i display virtuali inviano l'output a un buffer Gralloc anziché allo schermo. Il compositore hardware (HWC) scrive l'output in un buffer, fornisce la recinzione di completamento e invia il buffer a un consumatore (ad esempio il codificatore video, la GPU, la CPU e così via). I display virtuali possono utilizzare 2D/blitter o overlay se la pipeline di visualizzazione scrive in memoria.
Modalità
Ogni frame è in una delle tre modalità dopo che SurfaceFlinger chiama il metodo validateDisplay()
HWC:
- GLES: la GPU compone tutti i livelli, scrivendo direttamente nel buffer di output. La HWC non è coinvolta nella composizione.
- MIX: la GPU compone alcuni strati alla framebuffer e HWC creano il framebuffer e gli strati rimanenti, scrivere direttamente nel buffer di output.
- HWC: HWC compone tutti i livelli e scrive direttamente nel buffer di output.
Formato di output
I formati di output del buffer del display virtuale dipendono dalla relativa modalità:
- Modalità GLES: il driver EGL imposta il formato del buffer di output su
dequeueBuffer()
, in genereRGBA_8888
. Il consumer deve essere in grado di accettare il formato di output impostato dal driver o la buffer non può essere letto. - Modalità MIXED e HWC: se il consumatore ha bisogno di accedere alla CPU, è lui a impostare il formato. In caso contrario, il formato è
IMPLEMENTATION_DEFINED
e Gralloc imposta il formato migliore in base ai flag di utilizzo. Ad esempio, Gralloc imposta un formato YCbCr se il consumatore è un codificatore video e HWC può scrivere il formato in modo efficiente.
Barriere di sincronizzazione
La sincronizzazione delle recinzioni è un aspetto cruciale della grafica Android di un sistema operativo completo. Le barriere consentono al lavoro della CPU di procedere indipendentemente dal lavoro simultaneo della GPU, il blocco solo quando c'è una vera dipendenza.
Ad esempio, quando un'app invia un buffer in produzione alla GPU, invia anche un oggetto recinto di sincronizzazione. Questo recinto segnala quando La GPU ha terminato di scrivere nel buffer.
L'HWC richiede che la GPU finisca di scrivere i buffer prima che vengano visualizzati. Le barriere di sincronizzazione vengono fatte passare attraverso la pipeline grafica con i buffer e segnala quando vengono scritti i buffer. Prima che venga visualizzato un buffer, controlla se la barriera di sincronizzazione è stata segnalata e, in caso affermativo, visualizza buffer.
Per ulteriori informazioni sulle barriere di sincronizzazione, consulta Hardware Composer Integrazione.