Couches et écrans

Les calques et les affichages sont deux primitives qui représentent le travail de composition et les interactions avec le matériel d'affichage.

Calques

Une couche est l'unité de composition la plus importante. Une couche est une combinaison d'une surface et d'une instance de SurfaceControl. Chaque calque possède un ensemble de propriétés qui définissent son interaction avec les autres calques. Les propriétés des calques sont décrites dans le tableau suivant :

Propriété Description
Positionnel Définit l'emplacement du calque sur l'écran. Inclut des informations telles que la position des bords d'un calque et son ordre Z par rapport aux autres calques (s'il doit se trouver devant ou derrière les autres calques).
Contenu Définit la façon dont le contenu affiché sur le calque doit être présenté dans les limites définies par les propriétés de position. Inclut des informations telles que le recadrage (pour agrandir une partie du contenu afin de remplir les limites du calque) et la transformation (pour afficher le contenu pivoté ou inversé).
Composition Définit la manière dont le calque doit être composé avec d'autres calques. Inclut des informations telles que le mode de fusion et une valeur alpha à l'échelle du calque pour la composition alpha.
Optimisation Fournit des informations qui ne sont pas strictement nécessaires pour composer correctement le calque, mais qui peuvent être utilisées par le compositeur matériel (HWC) pour optimiser la façon dont il effectue la composition. Inclut des informations telles que la région visible du calque et la partie du calque qui a été mise à jour depuis la frame précédente.

Écrans

Un affichage est une autre unité de composition importante. Un système peut comporter plusieurs écrans, et des écrans peuvent être ajoutés ou supprimés lors des opérations système normales. Les affichages sont ajoutés ou supprimés à la demande du HWC ou du framework. L'appareil HWC demande l'ajout ou la suppression d'écrans lorsqu'un écran externe est connecté ou déconnecté de l'appareil, ce qui s'appelle le branchement à chaud. Les clients demandent des écrans virtuels, dont le contenu est affiché dans un tampon hors écran plutôt que sur un écran physique.

Écrans virtuels

SurfaceFlinger est compatible avec un écran interne (intégré au téléphone ou à la tablette), des écrans externes (comme un téléviseur connecté via HDMI) et un ou plusieurs écrans virtuels qui rendent la sortie composite disponible dans le système. Les écrans virtuels peuvent être utilisés pour enregistrer l'écran ou l'envoyer sur un réseau. Les frames générés pour un écran virtuel sont écrits dans une BufferQueue.

Les affichages virtuels peuvent partager le même ensemble de calques que l'affichage principal (la pile de calques) ou avoir leur propre ensemble. Il n'y a pas de VSync pour un écran virtuel. Par conséquent, le VSync de l'écran interne déclenche la composition pour tous les écrans.

Sur les implémentations HWC qui les prennent en charge, les affichages virtuels peuvent être composés avec OpenGL ES (GLES), HWC ou les deux. Sur les implémentations non compatibles, les affichages virtuels sont toujours composés à l'aide de GLES.

Étude de cas : screenrecord

La commande screenrecord permet à l'utilisateur d'enregistrer tout ce qui s'affiche à l'écran sous forme de fichier MP4 sur le disque. Pour ce faire, le système reçoit des frames composites de SurfaceFlinger, les écrit dans l'encodeur vidéo, puis écrit les données vidéo encodées dans un fichier. Les codecs vidéo sont gérés par un processus distinct (mediaserver). Les grands tampons graphiques doivent donc se déplacer dans le système. Pour rendre le défi plus difficile, l'objectif est d'enregistrer une vidéo à 60 fps en résolution maximale. BufferQueue est la clé pour que cela fonctionne efficacement.

La classe MediaCodec permet à une application de fournir des données sous forme d'octets bruts dans des tampons ou via une surface. Lorsque screenrecord demande l'accès à un encodeur vidéo, le processus mediaserver crée une BufferQueue, se connecte au côté consommateur, puis renvoie le côté producteur à screenrecord sous forme de surface.

L'utilitaire screenrecord demande ensuite à SurfaceFlinger de créer un écran virtuel qui reflète l'écran principal (c'est-à-dire qu'il comporte les mêmes calques) et lui demande d'envoyer la sortie à la surface provenant du processus mediaserver. Dans ce cas, SurfaceFlinger est le producteur de tampons plutôt que le consommateur.

Une fois la configuration terminée, screenrecord se déclenche lorsque les données encodées s'affichent. Lorsque les applications dessinent, leurs tampons sont envoyés à SurfaceFlinger, qui les compose en un seul tampon envoyé directement à l'encodeur vidéo dans le processus mediaserver. Les frames complets ne sont jamais vus par le processus screenrecord. En interne, le processus mediaserver a sa propre façon de déplacer les tampons, qui transmet également les données par handle, ce qui minimise la surcharge.

Étude de cas : simuler des écrans secondaires

WindowManager peut demander à SurfaceFlinger de créer un calque visible pour lequel SurfaceFlinger agit en tant que consommateur BufferQueue. Il est également possible de demander à SurfaceFlinger de créer un écran virtuel, pour lequel SurfaceFlinger agit en tant que producteur BufferQueue.

Si vous connectez un écran virtuel à un calque visible, une boucle fermée est créée, dans laquelle l'écran composite apparaît dans une fenêtre. Cette fenêtre fait désormais partie de la sortie composite. Ainsi, lors de la prochaine actualisation, l'image composite à l'intérieur de la fenêtre affichera également le contenu de la fenêtre. Pour voir comment cela fonctionne, activez les options pour les développeurs dans Paramètres, sélectionnez Simuler les écrans secondaires, puis activez une fenêtre. Pour voir les écrans secondaires en action, utilisez screenrecord pour capturer l'action d'activation de l'écran, puis lisez-la image par image.