Implémentation de Hardware Composer HAL

Le Hardware Composer (HWC) HAL compose les couches reçues de SurfaceFlinger, réduisant la quantité de composition OpenGL ES (GLES) et le GPU exécutés .

Le HWC fait abstraction d'objets, tels que des superpositions et des blitters 2D, sur des surfaces composites et communique avec du matériel de composition de fenêtre spécialisé vers des fenêtres composites. Utilisez le HWC pour composer des fenêtres au lieu d'avoir un composite SurfaceFlinger 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 implémentations HWC doivent prendre en charge:

  • Au moins quatre superpositions:
    • Barre d'état
    • Barre système
    • Appli
    • Fond d'écran / arrière-plan
  • Calques plus grands que l'écran (par exemple, un papier peint)
  • Fusion alpha par pixel prémultipliée et fusion alpha par plan simultanées
  • Chemin matériel pour la lecture vidéo protégée
  • Ordre d'emballage RGBA, formats YUV et propriétés de mosaïque, de swizzling et de foulée

Pour mettre en œuvre le HWC:

  1. Implémentez un HWC non opérationnel et envoyez tout le travail de composition à GLES.
  2. Implémentez un algorithme pour déléguer la composition au HWC de manière incrémentielle. Par exemple, ne déléguez que les trois ou quatre premières surfaces au matériel de superposition du HWC.
  3. Optimiser le HWC. 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 à GLES au lieu du HWC pour économiser 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 d'application et les fonds d'écran animés
      • Jeux plein écran en mode portrait et paysage
      • Vidéo plein écran avec sous-titrage codé et contrôle de la lecture
      • Lecture vidéo protégée
      • Fenêtres multiples en écran partagé

Primitives HWC

Le HWC fournit deux primitives, des couches et des 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 les versions ultérieures utilisent une interface HIDL appelée Composer HAL pour IPC lié entre le HWC et SurfaceFlinger. Le Composer HAL remplace l' hwcomposer2.h 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 en 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 (comme la résolution 4k ou 1080p) et les modes de couleur (comme la couleur native ou le vrai sRGB); et pour allumer, éteindre ou passer l'écran en mode basse consommation si 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 le 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 d'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 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 une documentation détaillée sur les fonctions HAL de Composer et les fonctions de relais de fonction HWC, voir composer . Pour une documentation détaillée sur les pointeurs de fonction HWC, consultez le 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 le HWC. Les poignées sont opaques pour SurfaceFlinger.

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

Les affichages physiques sont créés en étant branché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 une poignée. 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.

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 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, SurfaceFlinger compose des couches via le processeur de secours 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'exécuter 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 couches qui n'ont pas été marquées 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 y a exactement un affichage interne . L'affichage interne est l'affichage que le hotplug initial signale pendant le démarrage. Une fois que l'écran interne est branché à chaud, il ne peut pas être déconnecté.
  • En plus de l'affichage interne, n'importe quel nombre d'écrans externes peut être branché à chaud pendant le fonctionnement normal de l'appareil. La structure 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 de manière incorrecte comme Display.TYPE_HDMI au lieu de Display.TYPE_BUILT_IN .

Alors que les opérations SurfaceFlinger décrites ci-dessus sont 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'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 d'affichage virtuel est similaire à la composition d'affichage externe. La différence entre la composition d'affichage virtuel et la composition d'affichage physique est que les affichages virtuels envoient la sortie à une mémoire tampon Gralloc plutôt qu'à 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 affichages virtuels peuvent utiliser 2D / blitter ou superpositions si le pipeline d'affichage écrit dans la mémoire.

Les modes

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

  • 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 avec 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 les pilotes ou le tampon ne peut pas être lu.
  • Modes MIXTE et HWC - Si le consommateur a besoin d'un accès au processeur, le consommateur 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 travail du processeur de se dérouler indépendamment du travail simultané du GPU, ne bloquant que lorsqu'il existe une vraie dépendance.

Par exemple, lorsqu'une application soumet un tampon en cours de production sur le GPU, elle soumet également un objet de clôture de synchronisation. Cette clôture signale lorsque le GPU a fini d'écrire dans la mémoire 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 passées à travers le pipeline graphique avec des tampons et un signal lorsque les tampons sont écrits. Avant qu'un tampon ne soit affiché, le HWC vérifie si la clôture de synchronisation a signalé un 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 .