Le framework de synchronisation décrit explicitement les dépendances différentes opérations asynchrones dans le système graphique Android. Le cadre fournit une API qui permet aux composants d'indiquer à quel moment les tampons sont libérés. Le cadre permet de transmettre les primitives de synchronisation entre les pilotes du noyau à l'espace utilisateur et entre les processus d'espace utilisateur eux-mêmes.
Par exemple, une application peut mettre en file d'attente des tâches à effectuer dans le GPU. Le GPU commence à dessiner cette image. Bien que l'image n'ait pas été dessinée en mémoire, le pointeur de tampon est transmis à la fenêtre compositeur avec une clôture qui indique à quel moment le travail GPU terminer. Le compositeur de fenêtres lance le traitement à l'avance, transmet la tâche au contrôleur d'affichage. De la même manière, le CPU fonctionne est effectuée à l'avance. Une fois l'exécution du GPU terminée, le contrôleur d'affichage affiche immédiatement l'image.
Le framework de synchronisation permet également aux responsables de la mise en œuvre d'exploiter de synchronisation dans leurs propres composants matériels. Enfin, la fonction offre une visibilité sur le pipeline graphique pour vous aider le débogage.
Synchronisation explicite
La synchronisation explicite permet aux producteurs et aux utilisateurs de tampons graphiques pour signaler qu'ils ont fini d'utiliser un tampon. La synchronisation explicite est implémentée dans l'espace kernel-space.
Les avantages d'une synchronisation explicite sont les suivants:
- Moins de variations de comportement d'un appareil à l'autre
- Meilleure assistance au débogage
- Amélioration des métriques de test
Le framework de synchronisation comporte trois types d'objets:
sync_timeline
sync_pt
sync_fence
synchronisation_chronologie
sync_timeline
est une chronologie à augmentation monotone qui
les fournisseurs doivent implémenter pour chaque instance de pilote, comme un contexte GL,
un contrôleur d'affichage ou un blitter 2D. sync_timeline
décomptes
des jobs envoyés au noyau
pour un matériel spécifique.
sync_timeline
fournit des garanties sur l'ordre des opérations.
et permet des implémentations spécifiques au matériel.
Suivez ces consignes lors de l'implémentation de sync_timeline
:
- Fournissez des noms utiles pour tous les pilotes, les chronologies et les clôtures pour simplifier le débogage.
- Implémenter
timeline_value_str
etpt_value_str
dans les timelines pour faciliter la lecture des résultats de débogage. - Implémentez le remplissage
driver_data
pour fournir des bibliothèques d'espace utilisateur. comme la bibliothèque GL, et l'accès à des données temporelles privées, si vous le souhaitez.data_driver
permet aux fournisseurs de transmettre des informations sur l'objet immuablesync_fence
etsync_pts
pour créer des lignes de commande sur ces données. - N'autorisez pas l'espace utilisateur à créer ou signaler explicitement une clôture. Contenu explicite la création de signaux ou de clôtures entraîne une attaque par déni de service qui interrompt le fonctionnement du pipeline.
- Ne pas accéder à
sync_timeline
,sync_pt
ousync_fence
de manière explicite. L'API fournit toutes les informations fonctions.
synchronisation_pt
sync_pt
est une valeur ou un point unique sur un
sync_timeline
Un point
présente trois états : "actif", "signalé" et "erreur". Les points commencent à l'état actif
et passer aux états
signalés ou d'erreur. Par exemple, lorsqu'une image
le consommateur n'a plus besoin de tampon, un sync_pt
est signalé
afin qu'un producteur d'images sache
qu'il est acceptable d'écrire à nouveau dans le tampon.
cloisonnement
sync_fence
est une collection de valeurs sync_pt
.
aussi souvent
ont des parents sync_timeline
différents (par exemple, pour l'écran
le contrôleur et le GPU). sync_fence
, sync_pt
et
Les sync_timeline
sont les principales primitives des pilotes et de l'espace utilisateur.
utilisent pour communiquer
leurs dépendances. Lorsqu'une clôture est signalée,
les commandes émises avant la clôture sont garanties comme étant complètes, car le
le pilote du noyau ou le bloc matériel
exécute les commandes dans l’ordre.
Le framework de synchronisation permet à plusieurs
consommateurs ou producteurs de signaler
terminé d'utiliser un tampon, en communiquant les informations de dépendance avec une fonction
. Les clôtures reposent sur un descripteur de fichier et sont transmises
en espace utilisateur. Par exemple, une clôture peut contenir deux
Valeurs sync_pt
qui signifient que deux utilisateurs d'images distincts ont terminé
la lecture d'une mémoire tampon. Lorsque la clôture est signalée, les producteurs d'images savent que
les consommateurs ont fini de consommer.
Les clôtures, comme les valeurs sync_pt
, commencent à être actives et changent d'état en fonction
l'état de leurs points. Si toutes les valeurs sync_pt
sont signalées, le
sync_fence
est signalé. Si une sync_pt
tombe
en état d'erreur, l'ensemble de sync_fence
présente un état d'erreur.
L'appartenance à un sync_fence
ne peut pas être modifiée après la clôture
créé. Pour placer plusieurs points dans une clôture, la fusion est
par laquelle les points de deux clôtures distinctes sont ajoutés à une troisième clôture.
Si l'un de ces points a été signalé
dans la clôture d'origine et que l'autre ne l'était pas,
la troisième barrière ne sera pas non plus
à l'état signalé.
Pour implémenter la synchronisation explicite, fournissez les éléments suivants:
- Sous-système d'espace de noyau qui implémente le framework de synchronisation
pour un pilote matériel particulier. Les conducteurs qui doivent tenir compte de la clôture sont
généralement tout ce qui accède au Composer
du matériel ou qui communique avec lui.
Les fichiers de clé incluent:
<ph type="x-smartling-placeholder">
- </ph>
- Implémentation de base:
<ph type="x-smartling-placeholder">
- </ph>
kernel/common/include/linux/sync.h
kernel/common/drivers/base/sync.c
- Documentation sur
kernel/common/Documentation/sync.txt
- pour communiquer avec l'espace noyau
platform/system/core/libsync
- Implémentation de base:
<ph type="x-smartling-placeholder">
- Le fournisseur doit fournir la synchronisation appropriée
fences en tant que paramètres de
validateDisplay()
et FonctionspresentDisplay()
dans le HAL. - Deux extensions GL liées aux clôtures (
EGL_ANDROID_native_fence_sync
etEGL_ANDROID_wait_sync
) et la prise en charge du cloisonnement dans les éléments graphiques pilote.
Étude de cas: Implémenter un pilote d'affichage
Pour utiliser l'API prenant en charge la fonction de synchronisation,
développer un pilote d'affichage avec
une fonction de tampon d'affichage. Avant le
de synchronisation existant, cette fonction recevrait dma-buf
des objets, placez ces tampons sur l'écran et bloquez-les tant que le tampon était visible. Exemple :
/* * assumes buffer is ready to be displayed. returns when buffer is no longer on * screen. */ void display_buffer(struct dma_buf *buffer);
Avec le framework de synchronisation, la fonction display_buffer
est plus complexe. Lors de l'affichage d'un tampon, celui-ci est associé
avec une clôture qui indique à quel moment le tampon sera prêt. Vous pouvez ajouter
et commencer le travail
une fois la clôture levée.
La mise en file d'attente et le lancement du travail après la clôture de la clôture ne bloquent rien. Vous renvoyez immédiatement votre propre clôture, ce qui garantit que le tampon s'affiche à l'écran. Lorsque vous mettez des tampons en file d'attente, le noyau répertorie avec le framework de synchronisation:
/* * displays buffer when fence is signaled. returns immediately with a fence * that signals when buffer is no longer displayed. */ struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence *fence);
Intégration de la synchronisation
Cette section explique comment intégrer le framework de synchronisation de l'espace du noyau avec l'espace utilisateur du framework Android et les pilotes qui doivent communiquer les uns avec les autres. Les objets de l'espace du noyau sont représentés par des descripteurs de fichier dans de l'espace utilisateur.
Conventions d'intégration
Respectez les conventions de l'interface Android HAL:
- Si l'API fournit un descripteur de fichier qui fait référence à
sync_pt
, le pilote du fournisseur ou le HAL utilisant l'API doit fermer le descripteur de fichier. - Si le pilote du fournisseur ou le HAL transmet
un descripteur de fichier contenant
un
sync_pt
à une fonction d'API, le pilote du fournisseur ou le HAL ne doivent pas fermer le descripteur de fichier. - Pour continuer à utiliser le descripteur de fichier de cloisonnement, le pilote du fournisseur ou le HAL doit dupliquer le descripteur.
Un objet fence est renommé chaque fois qu'il passe par BufferQueue.
La prise en charge des clôtures de noyau permet d'avoir des chaînes pour les noms. La synchronisation
le framework utilise le nom de la fenêtre et l'index de tampon mis en file d'attente pour nommer
la clôture, par exemple SurfaceView:0
. Ce
est utile pour le débogage afin d'identifier la source d'un interblocage lorsque les noms apparaissent
dans la sortie de /d/sync
et dans les rapports de bugs.
Intégration d'ANativeWindow
ANativeWindow est compatible avec les cloisonnements. dequeueBuffer
,
queueBuffer
et cancelBuffer
comportent des paramètres de cloisonnement.
Intégration d'OpenGL ES
L'intégration de la synchronisation OpenGL ES repose sur deux extensions EGL:
EGL_ANDROID_native_fence_sync
permet de encapsuler ou créer des descripteurs de fichier de cloisonnement Android natifs dans ObjetsEGLSyncKHR
.EGL_ANDROID_wait_sync
autorise les blocages côté GPU plutôt que côté CPU, ce qui fait que le GPU attendEGLSyncKHR
. La L'extensionEGL_ANDROID_wait_sync
est identique à l'extension ExtensionEGL_KHR_wait_sync
.
Pour utiliser ces extensions de manière indépendante, implémentez la
EGL_ANDROID_native_fence_sync
et les composants associés
la compatibilité avec le noyau. Ensuite, activez EGL_ANDROID_wait_sync
.
dans votre pilote. EGL_ANDROID_native_fence_sync
extension se compose d'un objet EGLSyncKHR
de clôture natif distinct
de mots clés. Par conséquent, les extensions qui s'appliquent aux EGLSyncKHR
existants
les types d'objets ne s'appliquent pas nécessairement à EGL_ANDROID_native_fence
en évitant les interactions indésirables.
L'extension EGL_ANDROID_native_fence_sync
utilise un code natif correspondant
attribut de descripteur de fichier de cloisonnement qui ne peut être défini qu'au moment de la création
ne peuvent pas être interrogés directement à partir d'un objet de synchronisation existant. Cet attribut
peut être défini sur l'un des deux modes suivants:
- Un descripteur de fichier de cloisonnement valide encapsule un élément natif existant.
Descripteur de fichier de clôture Android dans un objet
EGLSyncKHR
. - -1 crée un descripteur de fichier de cloisonnement Android natif à partir d'un
EGLSyncKHR
.
Utilisez l'appel de fonction DupNativeFenceFD()
pour extraire la
EGLSyncKHR
du descripteur de fichier de clôture Android natif.
Cela produit le même résultat que d'interroger l'attribut set, mais respecte
la convention selon laquelle le destinataire ferme la clôture (d'où le double emploi
opération). Enfin, la destruction de l'objet EGLSyncKHR
ferme
l'attribut de clôture interne.
Intégration de Hardware Composer
Hardware Composer gère trois types de barrières de synchronisation:
- Les barrières d'acquisition sont transmises avec les tampons d'entrée pour
les appels
setLayerBuffer
etsetClientTarget
. Ils représentent une écriture en attente dans le tampon et doivent signaler avant l'événement SurfaceFlinger ou le HWC tente de lire le tampon associé effectuer la composition. - Les barrières de protection sont récupérées après l'appel de la fonction
presentDisplay
via l'appelgetReleaseFences
. Ils représentent une lecture en attente à partir du tampon précédent sur la même couche. A libère des signaux de cloisonnement lorsque le HWC n'utilise plus le tampon précédent car le tampon actuel a remplacé le tampon précédent sur l'écran. Les barrières de version sont renvoyées à l'application avec les tampons précédents qui sera remplacé pendant la composition actuelle. L'application doit attendre un libérez les signaux de cloisonnement avant d'écrire dans le tampon les nouveaux contenus leur a été rendue. - Les barrières actuelles sont renvoyées, une par image, dans le cadre de
l'appel à
presentDisplay
. Les clôtures actuelles représentent le moment où le la composition de cette image est terminée, ou inversement, lorsque la le résultat de composition du frame précédent n'est plus nécessaire. Périphériques s'affiche,presentDisplay
renvoie les barrières présentes lorsque le l'image actuelle apparaît à l'écran. Une fois les clôtures actuelles renvoyées, vous pouvez écrire à nouveau dans le tampon cible SurfaceFlinger, si applicables. Pour les écrans virtuels, les clôtures actuelles sont renvoyées lorsque en toute sécurité dans le tampon de sortie.