Implementare l'HAL Hardware Composer

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:

  1. Implementa un HWC non operativo e invia tutto il lavoro di composizione a GLES.
  2. 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.
  3. 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:

  1. Gestisce le transazioni, se presenti.
  2. Memorizza i nuovi buffer grafici, se presenti.
  3. 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 genere RGBA_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.