les couches composites HAL (Hardware Composer) reçues de SurfaceFlinger, ce qui réduit la quantité de composition OpenGL ES (GLES) et les performances du GPU.
Le HWC effectue une abstraction des objets, tels que les superpositions et les blitters 2D, pour composer des surfaces et communique avec du matériel de composition de fenêtre spécialisé pour composer des fenêtres. Utilisez le matériel pour créer des fenêtres composites au lieu d'utiliser un composite SurfaceFlinger avec le GPU. La plupart des GPU ne sont pas optimisés pour la composition. Lorsque le GPU compose des calques à partir de SurfaceFlinger, les applications ne peuvent pas utiliser le GPU pour leur propre rendu.
Les implémentations de HWC doivent prendre en charge les éléments suivants:
- Au moins quatre superpositions :
- Barre d'état
- Barre système
- Application
- Fond d'écran/Arrière-plan
- Calques plus grands que l'écran (par exemple, un fond d'écran)
- Mélange alpha prémultiplié simultané par pixel et par plan
- Chemin matériel pour la lecture vidéo protégée
- Ordre d'empaquetage RGBA, formats YUV, et propriétés de mosaïque, de mélange et de pas
Pour implémenter le HWC:
- Implémentez un HWC non opérationnel et envoyez toute la tâche de composition à GLES.
- Implémentez un algorithme pour déléguer progressivement la composition au matériel. Par exemple, déléguez uniquement les trois ou quatre premières surfaces au matériel de superposition du HWC.
- Optimisez le HWC. Voici quelques exemples :
- Sélection des surfaces qui maximisent la charge retirée du GPU et les envoient au HWC.
- Détecter si l'écran est en cours de mise à jour Si ce n'est pas le cas, déléguez la composition à GLES au lieu du HWC pour économiser de l'énergie. Lorsque l'écran s'actualise à nouveau, continuez à décharger la composition sur le HWC.
- Préparation aux cas d'utilisation courants, par exemple :
- L'écran d'accueil, qui comprend la barre d'état, la barre système, la fenêtre de l'application et les fonds d'écran animés
- Jeux en plein écran en mode portrait et paysage
- Vidéo en plein écran avec sous-titres et contrôle de la lecture
- Lecture de vidéos protégées
- Écran partagé multifenêtre
Primitives de matériel Web
Le HWC fournit deux primitives, les couches et les écrans, pour représenter le travail de composition et son interaction avec le matériel d'affichage. Le HWC permet également de contrôler VSYNC et un rappel vers SurfaceFlinger pour l'informer lorsqu'un événement VSYNC se produit.
Interface HIDL
Android 8.0 et les versions ultérieures utilisent une interface HIDL appelée HAL Composer pour l'IPC liée entre le HWC et SurfaceFlinger. Le HAL de Composer remplace l'ancienne interface hwcomposer2.h
. Si les fournisseurs fournissent une implémentation du HAL Composer du HWC, le HAL Composer accepte directement les appels HIDL de SurfaceFlinger. Si les fournisseurs fournissent une ancienne implémentation du HWC, le HAL Composer charge des pointeurs de fonction à partir de hwcomposer2.h
, transmettant les appels HIDL en appels de pointeur de fonction.
Le HWC fournit des fonctions permettant de déterminer les propriétés d'un écran donné, de basculer entre différentes configurations d'affichage (telles que la résolution 4K ou 1080p) et des modes de couleur (telles que la couleur native ou le vrai sRGB), et d'allumer, d'éteindre ou de mettre l'écran en mode basse consommation, le cas échéant.
Pointeurs de fonction
Si les fournisseurs implémentent directement le HAL Composer, SurfaceFlinger appelle ses fonctions via l'IPC HIDL. Par exemple, pour créer une couche, SurfaceFlinger appelle createLayer()
sur le HAL Composer.
Si les fournisseurs implémentent l'interface hwcomposer2.h
, le HAL de Composer appelle les pointeurs de fonction hwcomposer2.h
. Dans les commentaires hwcomposer2.h
, les fonctions d'interface HWC sont désignées par des noms en CamelCase inférieur qui n'existent pas dans l'interface en tant que champs nommés. Presque toutes les fonctions sont chargées en demandant un pointeur de fonction à l'aide de getFunction
fourni par hwc2_device_t
. Par exemple, la fonction createLayer
est un pointeur de fonction de type HWC2_PFN_CREATE_LAYER
, qui est renvoyé lorsque la valeur énumérée HWC2_FUNCTION_CREATE_LAYER
est transmise à getFunction
.
Pour obtenir une documentation détaillée sur les fonctions HAL de Composer et sur les fonctions passthrough de fonctions HWC, consultez la section composer
. Pour obtenir une documentation détaillée sur les pointeurs de fonction HWC, consultez hwcomposer2.h
.
Poignées de calque et d'affichage
Les calques et les écrans sont manipulés par des poignées générées par le HWC. Les poignées sont opaques pour SurfaceFlinger.
Lorsque SurfaceFlinger crée une couche, il appelle createLayer
, qui renvoie un type Layer
pour les implémentations directes ou hwc2_layer_t
pour les implémentations de passthrough. Lorsque SurfaceFlinger modifie une propriété de cette couche, il transmet la valeur hwc2_layer_t
à la fonction de modification appropriée, ainsi que toutes les autres informations nécessaires à la modification. Le type hwc2_layer_t
est suffisamment grand pour contenir un pointeur ou un indice.
Les écrans physiques sont créés grâce au branchement à chaud. Lorsqu'un écran physique est branché à un branchement à chaud, le HWC crée une poignée et la transmet à SurfaceFlinger via le rappel de hotplug. Les écrans virtuels sont créés par SurfaceFlinger en appelant createVirtualDisplay()
pour demander un affichage. Si le HWC est compatible avec la composition d'écran virtuel, il renvoie un handle. Ensuite, SurfaceFlinger délègue la composition des écrans au HWC. Si le HWC n'est pas compatible avec la composition d'écran virtuel, SurfaceFlinger crée la poignée et compose l'écran.
Afficher les opérations de composition
Une fois par VSYNC, SurfaceFlinger se réveille s'il a un nouveau contenu à composer. Ce nouveau contenu peut être de nouveaux tampons d'image provenant d'applications ou une modification des propriétés d'un ou de plusieurs calques. Lorsque SurfaceFlinger l'active:
- Gère les transactions, le cas échéant.
- Ajoute de nouveaux tampons graphiques, s'ils sont présents.
- Effectue une nouvelle composition si l'étape 1 ou 2 a entraîné une modification du contenu à afficher.
Pour effectuer une nouvelle composition, SurfaceFlinger crée et détruit des calques ou modifie les états des calques, le cas échéant. Il met également à jour les calques avec leur contenu actuel, à l'aide d'appels tels que setLayerBuffer
ou setLayerColor
. Une fois toutes les couches mises à jour, SurfaceFlinger appelle validateDisplay
, qui indique au HWC d'examiner l'état des couches et de déterminer comment la composition va se dérouler. Par défaut, SurfaceFlinger tente de configurer chaque couche de sorte qu'elle soit composée par le HWC. Toutefois, dans certains cas, SurfaceFlinger compose des couches via le remplacement du GPU.
Après l'appel de validateDisplay
, SurfaceFlinger appelle getChangedCompositionTypes
pour voir si le HWC souhaite modifier l'un des types de composition de calques avant d'effectuer la composition. Pour accepter les modifications, SurfaceFlinger appelle acceptDisplayChanges
.
Si des calques sont marqués pour la composition SurfaceFlinger, SurfaceFlinger les compose dans le tampon cible. SurfaceFlinger appelle ensuite setClientTarget
pour transmettre le tampon à l'écran afin qu'il puisse être affiché à l'écran ou composé avec des calques qui n'ont pas été marqués pour la composition SurfaceFlinger. Si aucune couche n'est marquée pour la composition SurfaceFlinger, SurfaceFlinger contourne l'étape de composition.
Enfin, SurfaceFlinger appelle presentDisplay
pour demander au HWC de terminer le processus de composition et d'afficher le résultat final.
Plusieurs écrans
Android 10 est compatible avec plusieurs écrans physiques. Lors de la conception d'une implémentation HWC destinée à être utilisée sur Android 7.0 ou version ultérieure, certaines restrictions ne sont pas présentes dans la définition de HWC:
- On suppose qu'il n'y a qu'un seul écran interne. L'écran interne est celui que le hotplug initial signale au démarrage. Une fois l'écran interne connecté, il ne peut plus être déconnecté.
- En plus de l'écran interne, autant d'écrans externes peuvent être branchés à chaud pendant le fonctionnement normal de l'appareil. Le framework suppose que tous les hotplugs après le premier écran interne sont des écrans externes. Par conséquent, si d'autres écrans internes sont ajoutés, ils sont classés de manière incorrecte en tant que
Display.TYPE_HDMI
au lieu deDisplay.TYPE_BUILT_IN
.
Bien que les opérations SurfaceFlinger décrites ci-dessus soient effectuées par écran, elles sont effectuées de manière séquentielle pour tous les écrans actifs, même si le contenu d'un seul écran est mis à jour.
Par exemple, si l'écran externe est mis à jour, la séquence est la suivante:
// 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>)
Composition de l'écran virtuel
La composition d'écran virtuel est semblable à la composition d'écran externe. La différence entre la composition d'un écran virtuel et la composition d'un écran physique est que les écrans virtuels envoient la sortie vers un tampon Gralloc au lieu de l'écran. Le compilateur matériel (HWC) écrit la sortie dans un tampon, fournit la clôture de fin et envoie le tampon à un consommateur (tel que l'encodeur vidéo, le GPU, le processeur, etc.). Les écrans virtuels peuvent utiliser des 2D/blitter ou des superpositions si le pipeline d'affichage écrit dans la mémoire.
Modes
Chaque frame se trouve dans l'un des trois modes suivants après que SurfaceFlinger a appelé la méthode HWC validateDisplay()
:
- GLES : le GPU compose toutes les couches, en écrivant directement dans le tampon de sortie. Le HWC n'est pas impliqué dans la composition.
- MIXÉ : le GPU compose certaines couches dans le framebuffer et HWC compose le tampon de frame et les couches restantes, en écrivant directement dans le tampon de sortie.
- HWC : HWC compose toutes les couches et écrit directement dans le tampon de sortie.
Format de sortie
Les formats de sortie du tampon d'affichage virtuel dépendent de leur mode:
- Mode GLES : le pilote EGL définit le format du tampon de sortie dans
dequeueBuffer()
, généralementRGBA_8888
. Le client doit pouvoir accepter le format de sortie défini par le pilote, sinon le tampon ne peut pas être lu. - Modes MIXTE et HWC : si le client a besoin d'accéder au processeur, le client définit le format. Sinon, le format est
IMPLEMENTATION_DEFINED
, et Gralloc définit le meilleur format en fonction des indicateurs d'utilisation. Par exemple, Gralloc définit un format YCbCr si le consommateur est un encodeur vidéo et que HWC peut écrire le format de manière efficace.
Limites de synchronisation
Les barrières de synchronisation (sync) sont un aspect crucial du système graphique Android. Les clôtures permettent au processeur de fonctionner indépendamment des tâches simultanées de GPU, en ne bloquant qu'en cas de véritable dépendance.
Par exemple, lorsqu'une application envoie un tampon produit sur le GPU, elle envoie également un objet de barrière de synchronisation. Cette barrière indique quand le GPU a terminé d'écrire dans le tampon.
Le HWC exige que le GPU termine l'écriture des tampons avant leur affichage. Les barrières de synchronisation sont transmises via le pipeline graphique avec des tampons et un signal lorsque les tampons sont écrits. Avant qu'un tampon ne s'affiche, le HWC vérifie si la barrière de synchronisation a signalé, et si c'est le cas, il affiche le tampon.
Pour en savoir plus sur les barrières de synchronisation, consultez la section Intégration du matériel de composition.