Implementazione del compositore hardware HAL

Gli strati compositi HAL di Hardware Composer (HWC) ricevuti da SurfaceFlinger, riducendo la quantità di composizione che OpenGL ES (GLES) e la GPU eseguono.

L'HWC astrae oggetti, come sovrapposizioni e blitter 2D, su superfici composite e comunica con hardware specializzato per la composizione di finestre alle finestre composite. Usa l'HWC per comporre finestre invece di avere SurfaceFlinger composito con la GPU. La maggior parte delle GPU non sono ottimizzate 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 dovrebbero supportare:

  • Almeno quattro sovrapposizioni:
    • Barra di stato
    • Barra di sistema
    • App
    • Carta da parati / sfondo
  • Livelli più grandi del display (ad esempio, uno sfondo)
  • Fusione alfa premoltiplicata simultanea per pixel e fusione alfa per piano
  • Percorso hardware per la riproduzione video protetta
  • Ordine di imballaggio RGBA, formati YUV e proprietà di piastrellatura, swizzling e falcata

Per implementare l'HWC:

  1. Implementa un HWC non operativo e invia tutto il lavoro di composizione a GLES.
  2. Implementa un algoritmo per delegare la composizione all'HWC in modo incrementale. Ad esempio, delegare solo le prime tre o quattro superfici all'hardware di sovrapposizione dell'HWC.
  3. Ottimizza l'HWC. Ciò può includere:
    • Selezionare le superfici che massimizzano il carico tolto dalla GPU e inviarle all'HWC.
    • Rilevare se lo schermo si sta aggiornando. In caso contrario, delegare la composizione a GLES invece che all'HWC per risparmiare energia. Quando lo schermo si aggiorna di nuovo, continua a scaricare la composizione sull'HWC.
    • Preparazione per casi d'uso comuni come:
      • La schermata iniziale, 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 video protetta
      • Multifinestra a schermo diviso

Primitive HWC

L'HWC fornisce due primitive, livelli e visualizzazioni , per rappresentare il lavoro di composizione e la sua interazione con l'hardware di visualizzazione. L'HWC fornisce anche il controllo su VSYNC e una richiamata a SurfaceFlinger per notificarlo quando si verifica un evento VSYNC.

Interfaccia HIDL

Android 8.0 e versioni successive utilizzano un'interfaccia HIDL chiamata Composer HAL per IPC binderized tra HWC e SurfaceFlinger. Il Composer HAL sostituisce l'interfaccia legacy hwcomposer2.h . Se i fornitori forniscono un'implementazione HAL di Composer dell'HWC, HAL di Composer accetta direttamente le chiamate HIDL da SurfaceFlinger. Se i fornitori forniscono un'implementazione legacy dell'HWC, Composer HAL carica i puntatori a funzione da hwcomposer2.h , inoltrando le chiamate HIDL in chiamate di puntatori a funzione.

L'HWC fornisce funzioni per determinare le proprietà di un dato display; per passare tra diverse configurazioni di visualizzazione (come risoluzione 4k o 1080p) e modalità colore (come colore nativo o vero sRGB); e per accendere, spegnere o attivare il display in una modalità a basso consumo, se supportata.

Puntatori a funzione

Se i fornitori implementano direttamente Composer HAL, SurfaceFlinger chiama le sue funzioni tramite HIDL IPC. Ad esempio, per creare un livello, SurfaceFlinger chiama createLayer() sul Composer HAL.

Se i fornitori implementano l'interfaccia hwcomposer2.h , Composer HAL chiama i puntatori a funzione hwcomposer2.h . In hwcomposer2.h commenti, funzioni di interfaccia HWC sono indicati con nomi lowerCamelCase che non esistono nell'interfaccia come campi denominati. Quasi ogni funzione viene caricata richiedendo un puntatore a funzione utilizzando getFunction fornito da hwc2_device_t . Ad esempio, la funzione createLayer è un puntatore a funzione di tipo HWC2_PFN_CREATE_LAYER , che viene restituito quando il valore enumerato HWC2_FUNCTION_CREATE_LAYER viene passato a getFunction .

Per una documentazione dettagliata sulle funzioni HAL del compositore e sulle funzioni passthrough delle funzioni HWC, vedere composer . Per una documentazione dettagliata sui puntatori a funzione HWC, vedere hwcomposer2.h .

Layer e maniglie di visualizzazione

I livelli e le visualizzazioni vengono manipolati dalle maniglie generate dall'HWC. Le maniglie sono opache per SurfaceFlinger.

Quando SurfaceFlinger crea un nuovo livello, chiama createLayer , che restituisce il tipo Layer per le implementazioni dirette o hwc2_layer_t per le implementazioni passthrough. Quando SurfaceFlinger modifica una proprietà di quel livello, SurfaceFlinger passa il valore hwc2_layer_t alla funzione di modifica appropriata insieme a qualsiasi altra informazione necessaria per apportare la modifica. Il tipo hwc2_layer_t è abbastanza grande da contenere un puntatore o un indice.

I display fisici vengono creati mediante collegamento a caldo. Quando un display fisico è hotplugged, l'HWC crea un handle e lo passa a SurfaceFlinger tramite la richiamata hotplug. I display virtuali vengono creati da SurfaceFlinger chiamando createVirtualDisplay() per richiedere un display. Se l'HWC supporta la composizione del display virtuale, restituisce una maniglia. Quindi, SurfaceFlinger delega la composizione dei display all'HWC. Se l'HWC non supporta la composizione del display virtuale, SurfaceFlinger crea la maniglia e compone il display.

Visualizza le operazioni di composizione

Una volta per VSYNC, SurfaceFlinger si riattiva se ha nuovi contenuti da comporre. Questo nuovo contenuto può essere un nuovo buffer di immagini dalle app o una modifica nelle proprietà di uno o più livelli. Quando SurfaceFlinger lo sveglia:

  1. Gestisce le transazioni, se presenti.
  2. Aggancia i nuovi buffer grafici, se presenti.
  3. Esegue una nuova composizione, se il passaggio 1 o 2 ha comportato una modifica al contenuto del display.

Per eseguire una nuova composizione, SurfaceFlinger crea e distrugge i livelli o modifica gli stati dei livelli, a seconda dei casi. Aggiorna anche i livelli con i loro contenuti correnti, utilizzando chiamate come setLayerBuffer o setLayerColor . Dopo che tutti i livelli sono stati aggiornati, SurfaceFlinger chiama validateDisplay , che dice all'HWC di esaminare lo stato dei livelli e determinare come procederà la composizione. Per impostazione predefinita, SurfaceFlinger tenta di configurare ogni livello in modo tale che il livello sia composto dall'HWC; sebbene in alcune circostanze, SurfaceFlinger componga i livelli attraverso il fallback della GPU.

Dopo la chiamata a validateDisplay , SurfaceFlinger chiama getChangedCompositionTypes per vedere se l'HWC desidera che uno dei tipi di composizione dei livelli venga modificato prima di eseguire la composizione. Per accettare le modifiche, SurfaceFlinger chiama acceptDisplayChanges .

Se alcuni livelli sono contrassegnati per la composizione di SurfaceFlinger, SurfaceFlinger li compone nel buffer di destinazione. SurfaceFlinger chiama quindi setClientTarget per fornire il buffer al display in modo che il buffer possa essere visualizzato sullo schermo o ulteriormente composto con livelli che non sono stati contrassegnati per la composizione di SurfaceFlinger. Se nessun livello è contrassegnato per la composizione di SurfaceFlinger, SurfaceFlinger ignora il passaggio di composizione.

Infine, SurfaceFlinger chiama presentDisplay per dire all'HWC di completare il processo di composizione e visualizzare il risultato finale.

Display multipli

Android 10 supporta più display fisici. Quando si progetta un'implementazione HWC destinata all'uso su Android 7.0 e versioni successive, ci sono alcune limitazioni non presenti nella definizione HWC:

  • Si presume che ci sia esattamente un display interno . Il display interno è il display segnalato dall'hotplug iniziale durante l'avvio. Dopo che il display interno è stato collegato a caldo, non può essere scollegato.
  • Oltre al display interno, un numero qualsiasi di display esterni può essere collegato a caldo durante il normale funzionamento del dispositivo. Il framework presuppone che tutti gli hotplug dopo il primo display interno siano display esterni, quindi se vengono aggiunti altri display interni, vengono classificati in modo errato come Display.TYPE_HDMI invece di Display.TYPE_BUILT_IN .

Mentre le operazioni di SurfaceFlinger descritte sopra vengono eseguite per display, vengono eseguite in sequenza per tutti i display attivi, anche se il contenuto di un solo display viene aggiornato.

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 invece che allo schermo. Hardware Composer (HWC) scrive l'output in un buffer, fornisce la barriera di completamento e invia il buffer a un consumatore (come il codificatore video, la GPU, la CPU e così via). I display virtuali possono utilizzare 2D / blitter o sovrapposizioni se la pipeline di visualizzazione scrive in memoria.

Modalità

Ogni frame è in una delle tre modalità dopo che SurfaceFlinger chiama il metodo HWC validateDisplay() :

  • GLES - La GPU compone tutti i livelli, scrivendo direttamente nel buffer di output. L'HWC non è coinvolto nella composizione.
  • MIXED - La GPU compone alcuni livelli al framebuffer e HWC compone il framebuffer e i restanti livelli, scrivendo 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 di visualizzazione virtuale dipendono dalla loro modalità:

  • Modalità GLES - Il driver EGL imposta il formato del buffer di output in dequeueBuffer() , tipicamente RGBA_8888 . Il consumatore deve essere in grado di accettare il formato di output impostato dal driver o il buffer non può essere letto.
  • Modalità MIXED e HWC : se il consumatore necessita dell'accesso alla CPU, il consumatore imposta 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.

Recinzioni di sincronizzazione

I recinti di sincronizzazione (sincronizzazione) sono un aspetto cruciale del sistema grafico Android. I recinti consentono alla CPU di funzionare indipendentemente dal lavoro simultaneo della GPU, bloccandosi solo quando c'è una vera dipendenza.

Ad esempio, quando un'app invia un buffer che viene prodotto sulla GPU, invia anche un oggetto di recinzione di sincronizzazione. Questa barriera segnala quando la GPU ha terminato la scrittura nel buffer.

L'HWC richiede che la GPU finisca di scrivere i buffer prima che i buffer vengano visualizzati. I recinti di sincronizzazione vengono fatti passare attraverso la pipeline grafica con buffer e segnalano quando i buffer vengono scritti. Prima che venga visualizzato un buffer, l'HWC controlla se il recinto di sincronizzazione ha segnalato e, in caso affermativo, visualizza il buffer.

Per ulteriori informazioni sui recinti di sincronizzazione, vedere Integrazione di Hardware Composer .