Implémenter Hardware Composer HAL

Les couches composites HAL de Hardware Composer (HWC) reçues de SurfaceFlinger, réduisant la quantité de composition OpenGL ES (GLES) et la performance du GPU.

Le HWC extrait des objets, tels que des superpositions et des blitters 2D, sur des surfaces composites et communique avec du matériel de composition de fenêtres spécialisé pour les fenêtres composites. Utilisez le HWC pour composer des fenêtres au lieu d'avoir SurfaceFlinger composite avec le GPU. La plupart des GPU ne sont pas optimisés pour la composition, et lorsque le GPU compose des couches à partir de SurfaceFlinger, les applications ne peuvent pas utiliser le GPU pour leur propre rendu.

Les mises en œuvre de HWC doivent prendre en charge :

  • 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é par pixel et mélange alpha par plan simultanés
  • Chemin matériel pour la lecture vidéo protégée
  • Ordre d'emballage RGBA, formats YUV et propriétés de carrelage, de tourbillon et de foulée

Pour mettre en œuvre le CHF :

  1. Mettre en œuvre un HWC non opérationnel et envoyer tous les travaux de composition au GLES.
  2. Implémentez un algorithme pour déléguer progressivement la composition au HWC. Par exemple, déléguez uniquement les trois ou quatre premières surfaces au matériel de superposition du HWC.
  3. Optimiser le CHF. Cela peut inclure :
    • Sélectionner des surfaces qui maximisent la charge retirée du GPU et les envoyer 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 au GLES au lieu du HWC pour économiser de l'énergie. Lorsque l'écran est à nouveau mis à jour, continuez à décharger la composition vers le HWC.
    • Préparation aux cas d'utilisation courants tels que :
      • 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 plein écran en mode portrait et paysage
      • Vidéo plein écran avec sous-titrage et contrôle de lecture
      • Lecture vidéo protégée
      • Multifenêtre en écran partagé

Primitives HWC

Le HWC fournit deux primitives, couches et affichages , pour représenter le travail de composition et son interaction avec le matériel d'affichage. Le HWC fournit également un contrôle sur VSYNC et un rappel à SurfaceFlinger pour le notifier lorsqu'un événement VSYNC se produit.

Interface HIDL

Android 8.0 et versions ultérieures utilisent une interface HIDL appelée Composer HAL pour l'IPC binderisé entre le HWC et SurfaceFlinger. Le Composer HAL remplace l'ancienne interface hwcomposer2.h . Si les fournisseurs fournissent une implémentation Composer HAL du HWC, Composer HAL accepte directement les appels HIDL de SurfaceFlinger. Si les fournisseurs fournissent une implémentation héritée du HWC, Composer HAL charge les pointeurs de fonction à partir de hwcomposer2.h , transférant les appels HIDL vers les appels de pointeur de fonction.

Le HWC fournit des fonctions pour déterminer les propriétés d'un affichage donné ; pour basculer entre différentes configurations d'affichage (telles que la résolution 4k ou 1080p) et les modes de couleur (tels que la couleur native ou le vrai sRGB) ; et pour allumer, éteindre l'écran ou le mettre en mode basse consommation si cela est pris en charge.

Pointeurs de fonction

Si les fournisseurs implémentent directement Composer HAL, SurfaceFlinger appelle ses fonctions via HIDL IPC. Par exemple, pour créer un calque, SurfaceFlinger appelle createLayer() sur Composer HAL.

Si les fournisseurs implémentent l'interface hwcomposer2.h , Composer HAL appelle les pointeurs de fonction hwcomposer2.h . Dans les commentaires hwcomposer2.h , les fonctions de l'interface HWC sont désignées par des noms lowerCamelCase 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 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 une documentation détaillée sur les fonctions Composer HAL et les fonctions passthrough des fonctions HWC, voir composer . Pour 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 affichages sont manipulés par des poignées générées par HWC. Les poignées sont opaques à SurfaceFlinger.

Lorsque SurfaceFlinger crée une nouvelle couche, il appelle createLayer , qui renvoie le type Layer pour les implémentations directes ou hwc2_layer_t pour les implémentations passthrough. Lorsque SurfaceFlinger modifie une propriété de cette couche, SurfaceFlinger transmet la valeur hwc2_layer_t dans la fonction de modification appropriée ainsi que toute autre information nécessaire pour effectuer la modification. Le type hwc2_layer_t est suffisamment grand pour contenir soit un pointeur, soit un index.

Les affichages physiques sont créés en étant connectés à chaud. Lorsqu'un écran physique est connecté à chaud, le HWC crée un handle et le transmet à SurfaceFlinger via le rappel hotplug. Les affichages virtuels sont créés par SurfaceFlinger appelant createVirtualDisplay() pour demander un affichage. Si le HWC prend en charge la composition d’affichage virtuel, il renvoie un handle. Ensuite, SurfaceFlinger délègue la composition des écrans au HWC. Si le HWC ne prend pas en charge la composition d'affichage virtuel, SurfaceFlinger crée la poignée et compose l'affichage.

Opérations de composition d’affichage

Une fois par VSYNC, SurfaceFlinger se réveille s'il a un nouveau contenu à composer. Ce nouveau contenu peut être de nouveaux tampons d'images provenant d'applications ou une modification des propriétés d'un ou plusieurs calques. Lorsque SurfaceFlinger le réveille :

  1. Gère les transactions, le cas échéant.
  2. Verrouille les nouveaux tampons graphiques, le cas échéant.
  3. Effectue une nouvelle composition si l'étape 1 ou 2 a entraîné une modification du contenu de l'affichage.

Pour effectuer une nouvelle composition, SurfaceFlinger crée et détruit des calques ou modifie les états des calques, selon le cas. 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 se déroulera. Par défaut, SurfaceFlinger tente de configurer chaque couche de telle sorte que la couche soit composée par le HWC ; bien que dans certaines circonstances, les couches composites SurfaceFlinger passent par le repli du GPU.

Après l'appel à validateDisplay , SurfaceFlinger appelle getChangedCompositionTypes pour voir si le HWC souhaite que l'un des types de composition de calque soit modifié 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 donner le tampon à l'affichage afin que le tampon puisse être affiché à l'écran ou composé davantage avec des calques qui n'ont pas été marqués pour la composition SurfaceFlinger. Si aucun calque n’est marqué pour la composition SurfaceFlinger, SurfaceFlinger contourne l’étape de composition.

Enfin, SurfaceFlinger appelle presentDisplay pour indiquer au HWC de terminer le processus de composition et d'afficher le résultat final.

Plusieurs affichages

Android 10 prend en charge plusieurs écrans physiques. Lors de la conception d'une implémentation HWC destinée à être utilisée sur Android 7.0 et versions ultérieures, certaines restrictions ne sont pas présentes dans la définition HWC :

  • On suppose qu’il existe exactement un affichage interne . L'affichage interne est l'affichage signalé par le hotplug initial lors du démarrage. Une fois l'écran interne branché à chaud, il ne peut plus être déconnecté.
  • En plus de l'écran interne, n'importe quel nombre d'écrans externes peuvent être connectés à chaud pendant le fonctionnement normal de l'appareil. Le framework suppose que tous les hotplugs après le premier affichage interne sont des écrans externes, donc si d'autres écrans internes sont ajoutés, ils sont classés à tort comme Display.TYPE_HDMI au lieu de Display.TYPE_BUILT_IN .

Bien que les opérations SurfaceFlinger décrites ci-dessus soient effectuées par affichage, elles sont effectuées séquentiellement pour tous les affichages actifs, même si le contenu d'un seul affichage est mis à jour.

Par exemple, si l'affichage externe est mis à jour, la séquence est :

// 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 d'affichage virtuel

La composition de l'affichage virtuel est similaire à la composition de l'affichage externe. La différence entre la composition d'affichage virtuel et la composition d'affichage physique réside dans le fait que les écrans virtuels envoient la sortie vers un tampon Gralloc plutôt que vers l'écran. Hardware Composer (HWC) écrit la sortie dans un tampon, fournit la clôture d'achèvement et envoie le tampon à un consommateur (tel que l'encodeur vidéo, le GPU, le CPU, etc.). Les écrans virtuels peuvent utiliser la 2D/blitter ou des superpositions si le pipeline d'affichage écrit dans la mémoire.

Modes

Chaque image est dans l'un des trois modes après que SurfaceFlinger appelle la méthode HWC validateDisplay() :

  • GLES — Le GPU compose toutes les couches, écrivant directement dans le tampon de sortie. Le HWC n'est pas impliqué dans la composition.
  • MIXTE — Le GPU compose certaines couches dans le framebuffer et HWC compose le framebuffer 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éralement RGBA_8888 . Le consommateur doit être en mesure d'accepter le format de sortie défini par le pilote, sinon le tampon ne pourra pas être lu.
  • Modes MIXTE et HWC — Si le consommateur a besoin d'un accès au processeur, il 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 efficacement.

Clôtures de synchronisation

Les clôtures de synchronisation (sync) sont un aspect crucial du système graphique Android. Les clôtures permettent au processeur de fonctionner indépendamment du travail simultané du GPU, bloquant uniquement lorsqu'il existe une véritable dépendance.

Par exemple, lorsqu'une application soumet un tampon produit sur le GPU, elle soumet également un objet de clôture de synchronisation. Cette barrière signale quand le GPU a fini d'écrire dans le tampon.

Le HWC exige que le GPU termine l’écriture des tampons avant que les tampons ne soient affichés. Les clôtures de synchronisation sont transmises via le pipeline graphique avec des tampons et signalent lorsque les tampons sont écrits. Avant qu'un tampon ne soit affiché, le HWC vérifie si la clôture de synchronisation a signalé, et si c'est le cas, il affiche le tampon.

Pour plus d'informations sur les clôtures de synchronisation, voir Intégration de Hardware Composer .