I livelli e i display sono due primitive che rappresentano il lavoro di composizione e le interazioni con l'hardware del display.
Strati
Uno strato è l'unità di composizione più importante. Un livello è una combinazione di una superficie e un'istanza di SurfaceControl
. Ogni livello ha una serie di proprietà che definiscono come interagisce con gli altri livelli. Le proprietà del layer sono descritte nella tabella seguente.
Proprietà | Descrizione |
---|---|
Posizionale | Definisce dove appare il livello sul suo display. Include informazioni come la posizione dei bordi di un livello e il suo ordine Z rispetto ad altri livelli (se deve trovarsi davanti o dietro altri livelli). |
Contenuto | Definisce il modo in cui il contenuto visualizzato sul layer deve essere presentato entro i limiti definiti dalle proprietà posizionali. Include informazioni come il ritaglio (per espandere una parte del contenuto per riempire i limiti del livello) e la trasformazione (per mostrare il contenuto ruotato o capovolto). |
Composizione | Definisce come il livello deve essere composto con altri livelli. Include informazioni come la modalità di fusione e un valore alfa a livello di livello per la composizione alfa . |
Ottimizzazione | Fornisce informazioni non strettamente necessarie per comporre correttamente il livello, ma che possono essere utilizzate dal dispositivo Hardware Composer (HWC) per ottimizzare il modo in cui esegue la composizione. Include informazioni come la regione visibile del livello e quale porzione del livello è stata aggiornata rispetto al fotogramma precedente. |
Visualizza
Un display è un'altra importante unità di composizione. Un sistema può avere più display ed è possibile aggiungere o rimuovere display durante le normali operazioni del sistema. I display vengono aggiunti/rimossi su richiesta dell'HWC o su richiesta del framework. Il dispositivo HWC richiede che i display vengano aggiunti o rimossi quando un display esterno viene collegato o disconnesso dal dispositivo, operazione denominata hotplugging . I client richiedono display virtuali , i cui contenuti vengono visualizzati in un buffer fuori schermo anziché su un display fisico.
Display virtuali
SurfaceFlinger supporta uno schermo interno (integrato nel telefono o nel tablet), schermi esterni (come un televisore collegato tramite HDMI) e uno o più schermi virtuali che rendono disponibile l'output composito all'interno del sistema. I display virtuali possono essere utilizzati per registrare lo schermo o inviarlo su una rete. I fotogrammi generati per un display virtuale vengono scritti in un BufferQueue.
I display virtuali possono condividere lo stesso set di livelli del display principale (la pila di livelli) o avere un proprio set. Non esiste VSYNC per un display virtuale, quindi VSYNC per il display interno attiva la composizione per tutti i display.
Nelle implementazioni HWC che li supportano, i display virtuali possono essere compositi con OpenGL ES (GLES), HWC o sia GLES che HWC. Nelle implementazioni non di supporto, i display virtuali vengono sempre composti utilizzando GLES.
Caso di studio: registrazione dello schermo
Il comando screenrecord
consente all'utente di registrare tutto ciò che appare sullo schermo come file .mp4
su disco. Per implementare ciò, il sistema riceve fotogrammi compositi da SurfaceFlinger, li scrive nel codificatore video e quindi scrive i dati video codificati in un file. I codec video sono gestiti da un processo separato ( mediaserver
), quindi i buffer grafici di grandi dimensioni devono spostarsi nel sistema. Per renderlo più impegnativo, l'obiettivo è registrare video a 60 fps alla massima risoluzione. La chiave per far funzionare tutto questo in modo efficiente è BufferQueue.
La classe MediaCodec
consente a un'app di fornire dati come byte non elaborati nei buffer o attraverso una superficie. Quando screenrecord
richiede l'accesso a un codificatore video, il processo mediaserver
crea una BufferQueue, si connette al lato consumatore, quindi restituisce il lato produttore a screenrecord
come superficie.
L'utilità screenrecord
chiede quindi a SurfaceFlinger di creare un display virtuale che rispecchia il display principale (ovvero, ha tutti gli stessi livelli) e lo indirizza a inviare l'output alla superficie proveniente dal processo mediaserver
. In questo caso, SurfaceFlinger è il produttore di buffer anziché il consumatore.
Una volta completata la configurazione, screenrecord
si attiva quando vengono visualizzati i dati codificati. Mentre le app disegnano, i loro buffer viaggiano su SurfaceFlinger, che li compone in un singolo buffer che viene inviato direttamente al codificatore video nel processo mediaserver
. I fotogrammi completi non vengono mai visualizzati dal processo screenrecord
. Internamente, il processo mediaserver
ha il proprio modo di spostare i buffer che passa anche i dati tramite handle, riducendo al minimo il sovraccarico.
Caso di studio: simulare display secondari
Il WindowManager può chiedere a SurfaceFlinger di creare un livello visibile per il quale SurfaceFlinger funge da consumatore BufferQueue. È anche possibile chiedere a SurfaceFlinger di creare un display virtuale, per il quale SurfaceFlinger funge da produttore di BufferQueue.
Se colleghi un display virtuale a un livello visibile, viene creato un circuito chiuso in cui lo schermo composito appare in una finestra. Quella finestra ora fa parte dell'output composito, quindi al successivo aggiornamento l'immagine composita all'interno della finestra mostra anche il contenuto della finestra. Per vederlo in azione, abilita le Opzioni sviluppatore in Impostazioni , seleziona Simula display secondari e abilita una finestra. Per vedere i display secondari in azione, utilizza screenrecord
per catturare l'atto di attivazione del display, quindi riprodurlo fotogramma per fotogramma.