Les couches 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 de calque sont décrites dans le tableau ci-dessous.
Propriété | Description |
---|---|
Positionnel | Définit l'endroit où le calque apparaît sur son écran. Elles incluent des informations telles que la position des bords d'un calque et son ordre de plan par rapport aux autres couches (qu'elles doivent se trouver devant ou derrière d'autres couches). |
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 développer une partie du contenu afin de remplir les limites de la couche) et la transformation (pour afficher du contenu pivoté ou inversé). |
Composition | Définit la manière dont la couche doit être composée avec d'autres couches. Inclut des informations telles que le mode de fusion et une valeur alpha à l'échelle de la couche pour le compositing alpha. |
Optimisation | Fournit des informations qui ne sont pas strictement nécessaires à la composition correcte de la couche, mais qui peuvent être utilisées par l'appareil HWC (Hardware Composer) pour optimiser la façon dont il effectue la composition. Inclut des informations telles que la région visible de la couche et la partie de la couche qui a été mise à jour depuis le frame précédent. |
Écrans
Un écran est une autre unité de composition importante. Un système peut comporter plusieurs écrans, et ces écrans peuvent être ajoutés ou supprimés pendant le fonctionnement normal du système. Les écrans sont ajoutés/supprimés à la demande du HWC ou du framework. L'appareil HWC demande que des écrans soient ajoutés ou supprimés lorsqu'un écran externe est connecté ou déconnecté de l'appareil, ce qui s'appelle le hotplugging. Les clients demandent des écrans virtuels, dont le contenu est affiché dans un tampon hors écran au lieu d'un écran physique.
Affichages virtuels
SurfaceFlinger est compatible avec un écran interne (intégré au téléphone ou à la tablette), des écrans externes (tels qu'un téléviseur connecté via HDMI) et un ou plusieurs écrans virtuels qui rendent la sortie composite disponible dans le système. Les affichages virtuels peuvent être utilisés pour enregistrer l'écran ou l'envoyer sur un réseau. Les frames générées pour un écran virtuel sont écrites dans une BufferQueue.
Les écrans virtuels peuvent partager le même ensemble de calques que l'écran 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 compatibles, les écrans virtuels peuvent être composés avec OpenGL ES (GLES), HWC ou les deux. Dans 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 en tant que fichier .mp4
sur le disque. Pour ce faire, le système reçoit des frames composés 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
). Par conséquent, de grands tampons graphiques doivent 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 pleine résolution. 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 du côté consommateur, puis transmet le côté producteur à screenrecord
en tant que surface.
L'utilitaire screenrecord
demande ensuite à SurfaceFlinger de créer un écran virtuel qui reflète l'écran principal (c'est-à-dire qu'il possède toutes les mêmes couches) et lui demande d'envoyer une 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 apparaissent. Lorsque les applications dessinent, leurs tampons se déplacent vers SurfaceFlinger, qui les compose en un seul tampon qui est envoyé directement à l'encodeur vidéo dans le processus mediaserver
. Les images complètes ne sont jamais vues par le processus screenrecord
. En interne, le processus mediaserver
a sa propre méthode de déplacement des tampons qui transfère également des données par poignée, ce qui réduit les frais généraux.
Étude de cas: simuler des écrans secondaires
WindowManager peut demander à SurfaceFlinger de créer une couche visible pour laquelle SurfaceFlinger agit en tant que consommateur de BufferQueue. Vous pouvez également demander à SurfaceFlinger de créer un écran virtuel, pour lequel SurfaceFlinger agit en tant que producteur de BufferQueue.
Si vous connectez un écran virtuel à une couche 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. Par conséquent, lors du prochain rafraîchissement, l'image composite dans la fenêtre affiche également le contenu de la fenêtre. Pour voir cela en action, activez les options pour les développeurs dans Paramètres, sélectionnez Simuler des écrans secondaires, puis activez une fenêtre. Pour voir les écrans secondaires en action, utilisez screenrecord
pour capturer l'activation de l'écran, puis le lire image par image.