Livelli e display

Livelli e display sono due primitive che rappresentano il lavoro di composizione e le interazioni con l'hardware del display.

Livelli

Un livello è l'unità di composizione più importante. Un livello è una combinazione di una superficie e un'istanza di SurfaceControl. Ogni livello ha un insieme di proprietà che definiscono il modo in cui interagisce con gli altri livelli. Le proprietà dei livelli sono descritte nella tabella seguente:

Proprietà Descrizione
Posizionale Definisce la posizione in cui il livello viene visualizzato sul display. Include informazioni come le posizioni dei bordi di un livello e il relativo ordine Z rispetto ad altri livelli (se deve essere davanti o dietro altri livelli).
Contenuti Specifica la modalità di visualizzazione dei contenuti sul livello entro i limiti impostati dalle proprietà posizionali. Sono inclusi il ritaglio (per espandere i contenuti in modo da riempire i limiti del livello) e la trasformazione (per mostrare i contenuti ruotati o capovolti).
Composizione Definisce la modalità di composizione del livello con altri livelli. Include informazioni come la modalità di fusione e un valore alfa a livello di livello per la composizione alfa .
Ottimizzazione Offre informazioni non strettamente necessarie per la composizione corretta dei livelli, ma che il dispositivo Hardware Composer (HWC) può utilizzare per ottimizzare il rendimento della composizione. Sono inclusi la regione visibile del livello e la parte aggiornata dall'ultimo frame.

Display

Un display è un'altra unità di composizione importante. Un sistema può avere più display e i display possono essere aggiunti o rimossi durante le normali operazioni di sistema. I display vengono aggiunti o rimossi su richiesta dell'HWC o del framework.

Il dispositivo HWC richiede l'aggiunta o la rimozione dei display quando un display esterno viene collegato o scollegato dal dispositivo, operazione chiamata hotplugging. I client richiedono display virtuali, i cui contenuti vengono sottoposti a rendering in un buffer fuori schermo anziché su un display fisico display.

Display virtuali

SurfaceFlinger supporta un display interno (integrato nello smartphone o nel tablet), display esterni (ad esempio un televisore collegato tramite HDMI) e uno o più display virtuali che rendono disponibile l'output composto all'interno del sistema. I display virtuali possono essere utilizzati per registrare lo schermo o inviarlo tramite una rete. I frame generati per un display virtuale vengono scritti in un BufferQueue.

I display virtuali possono condividere lo stesso insieme di livelli del display principale (lo stack di livelli) o avere il proprio insieme. Non è presente VSync per un display virtuale, quindi il VSync per il display interno attiva la composizione per tutti i display.

Nelle implementazioni HWC che li supportano, i display virtuali possono essere composti con OpenGL ES (GLES), HWC o entrambi. Nelle implementazioni non supportate, i display virtuali vengono sempre composti utilizzando GLES.

Case study: screenrecord

Il comando screenrecord consente all'utente di registrare tutto ciò che viene visualizzato sullo schermo come file MP4 su disco. Per implementare questa funzionalità, il sistema riceve i frame composti da SurfaceFlinger, li scrive nel codificatore video e poi 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 essere spostati nel sistema. Per rendere la situazione ancora più difficile, l'obiettivo è registrare video a 60 fps a risoluzione completa. La chiave per un funzionamento efficiente è BufferQueue.

La classe MediaCodec consente a un'app di fornire dati come byte non elaborati nei buffer o tramite una superficie. Quando screenrecord richiede l'accesso a un codificatore video, il processo mediaserver crea un BufferQueue, si connette al lato consumer e poi passa il lato producer a screenrecord come superficie.

L'utilità screenrecord chiede quindi a SurfaceFlinger di creare un display virtuale che rispecchi il display principale (ovvero che abbia tutti gli stessi livelli) e gli indica di inviare l'output alla superficie proveniente dal processo mediaserver. In questo caso, SurfaceFlinger è il producer dei buffer anziché il consumer.

Al termine della configurazione, screenrecord si attiva quando vengono visualizzati i dati codificati. Quando le app disegnano, i relativi buffer vengono inviati a SurfaceFlinger, che li compone in un unico buffer inviato direttamente al codificatore video nel processo mediaserver. I frame completi non vengono mai visualizzati dal processo screenrecord. Internamente, il processo mediaserver ha un proprio modo di spostare i buffer che passa anche i dati tramite handle, riducendo al minimo l'overhead.

Case study: simula display secondari

WindowManager può chiedere a SurfaceFlinger di creare un livello visibile per il quale SurfaceFlinger funge da consumer BufferQueue. È anche possibile chiedere a SurfaceFlinger di creare un display virtuale, per il quale SurfaceFlinger funge da producer BufferQueue.

Se colleghi un display virtuale a un livello visibile, viene creato un loop chiuso in cui lo schermo composto viene visualizzato in una finestra. Questa finestra fa ora parte dell'output composto, quindi al successivo aggiornamento l'immagine composta all'interno della finestra mostra anche i contenuti della finestra. Per vedere questa funzionalità in azione, attiva le opzioni sviluppatore in Impostazioni, seleziona Simula display secondari e attiva una finestra. Per vedere i display secondari in azione, utilizza screenrecord per acquisire l'atto di attivazione del display e poi riproducilo frame per frame.