Architecture RenderingNG

Chris Harrelson
Chris Harrelson

Vous verrez ici comment le composant de RenderingNG sont configurés et comment le pipeline de rendu les traverse.

En commençant par le niveau le plus élevé, les tâches du rendu sont les suivantes:

  1. Rendez les contenus en pixels à l'écran.
  2. Animez les effets visuels sur le contenu en passant d'un état à un autre.
  3. Défilement en réponse à l'entrée.
  4. Acheminez les entrées efficacement vers les bons endroits afin que les scripts de développement et les autres sous-systèmes puissent répondre.

Le contenu à afficher est constitué d'une arborescence de cadres pour chaque onglet du navigateur, plus les de votre navigateur. Un flux d'événements d'entrée bruts provenant d'écrans tactiles les souris, claviers et autres périphériques matériels.

Chaque trame comprend les éléments suivants:

  • État du DOM
  • CSS
  • Canevas
  • Ressources externes, telles que des images, des vidéos, des polices et SVG

Un cadre est un document HTML et son URL. Une page web chargée dans un onglet de navigateur a un cadre de premier niveau, cadres enfants pour chaque iFrame inclus dans le document de niveau supérieur, et leurs descendants iFrame récursifs.

Un effet visuel est une opération graphique appliquée à un bitmap. comme le défilement, la transformation, l'extrait, le filtre, l'opacité ou la fusion.

Composants de l'architecture

Dans RenderingNG, ces tâches sont réparties logiquement entre plusieurs étapes et codes composants. Les composants se retrouvent dans divers processus CPU, threads et des sous-composants de ces threads. Chacune joue un rôle important pour atteindre fiabilité, performances évolutives et l'extensibilité de tous les contenus Web.

Structure du pipeline de rendu

<ph type="x-smartling-placeholder">
</ph> Schéma du pipeline de rendu.
Les flèches indiquent les entrées et les sorties de chaque étage. Étapes sont notés par couleur, pour démontrer le thread ou le processus qu'ils exécutent. Dans Dans certains cas, les étapes peuvent s'exécuter à plusieurs endroits, en fonction du circonstance, c'est pourquoi certains ont deux couleurs. Les étapes vertes affichent le thread principal. les compositeurs de processus de rendu, les étapes orange sont le processus de visualisation.

Le rendu s'effectue dans un pipeline avec un certain nombre d'étapes et d'artefacts créés en cours de route. Chaque étape représente du code qui exécute une tâche bien définie dans le rendu. Les artefacts sont des structures de données qui sont des entrées ou des sorties des étapes.

Les étapes sont les suivantes:

  1. Animation:modifie les styles calculés et modifie les arborescences de propriétés au fil du temps en fonction de chronologies déclaratives.
  2. Style:appliquez du code CSS au DOM et créez des styles calculés.
  3. Mise en page:déterminez la taille et la position des éléments DOM à l'écran. et créer une arborescence à fragments immuables.
  4. Pré-peindre:calculer des arborescences de propriétés et invalider les listes d'affichage et les tuiles de texture GPU existantes, le cas échéant.
  5. Défilement:modifiez le décalage de défilement des documents et des éléments DOM à faire défiler en modifiant les arborescences de propriétés.
  6. Paint:calcule une liste d'affichage décrivant comment matriciel des tuiles de texture GPU à partir du DOM.
  7. Commit:copie les arborescences de propriétés et la liste d'affichage dans le thread du compositeur.
  8. Layerize (Calques) : divisez la liste d'affichage en une liste de calques composites pour une rastérisation et une animation indépendantes.
  9. Worklets matriciel, de décodage et de peinture:transformez respectivement les listes d'affichage, les images encodées et le code du Worklet de peinture en Tuiles de texture GPU.
  10. Activer:créez un cadre compositeur représentant comment dessiner et positionner les tuiles GPU à l'écran, ainsi que des effets visuels.
  11. Agrégation:combine les cadres compositeurs issus de tous les cadres visibles du compositeur dans un seul cadre de compositeur global.
  12. Draw (Dessiner) : exécute l'image compositeur agrégée sur le GPU pour créer des pixels à l'écran.

Les étapes du pipeline de rendu peuvent être ignorées si elles ne sont pas nécessaires. Par exemple, les animations d'effets visuels et de défilement peuvent ignorer la mise en page, la pré-peinture et la peinture. C'est pourquoi l'animation et le défilement sont indiqués par des points jaunes et verts sur le diagramme. Si la mise en page, la pré-peinture et la peinture peuvent être ignorées pour les effets visuels, ils peuvent être exécutés entièrement sur le thread du compositeur et ignorer le thread principal.

Le rendu de l'UI du navigateur n'est pas représenté directement ici, mais il peut être considéré comme une version simplifiée de ce même pipeline (et son implémentation partage une grande partie du code). Vidéo (non représentée directement) effectue généralement un rendu avec un code indépendant qui décode les images en tuiles de texture GPU. qui sont ensuite branchés aux cadres du compositeur et à l'étape de dessin.

Structure des processus et des threads

Processus du processeur

L'utilisation de plusieurs processus CPU assure une isolation en termes de performances et de sécurité. entre les sites et selon l'état du navigateur, la stabilité et l'isolation de sécurité par rapport au matériel GPU.

Diagramme des différentes parties des processus du processeur

  • Le processus de rendu affiche, anime, fait défiler et achemine les entrées pour une une seule combinaison d'onglets et de sites. Il existe plusieurs processus de rendu.
  • Le processus du navigateur affiche, anime et achemine les entrées pour l'UI du navigateur (y compris la barre d'adresse, les titres des onglets et les icônes), et achemine tous les au processus de rendu approprié. Il existe un seul processus de navigateur.
  • Le processus Viz regroupe la composition de plusieurs processus de rendu ainsi que le processus du navigateur. Il crée des trames et dessine à l'aide du GPU. Il y a un seul processus de visualisation.

Des sites différents se retrouvent systématiquement dans différents processus de rendu.

En général, plusieurs onglets ou fenêtres de navigateur du même site s'affichent différemment processus, sauf si les onglets sont liés, par exemple en ouvrant l'autre. En cas de forte pression sur la mémoire sur ordinateur, Chromium peut placer plusieurs onglets du même site dans le même processus de rendu, même s'ils ne sont pas liés.

Dans un seul onglet de navigateur, les cadres de différents sites sont toujours dans des processus de rendu différents les uns des autres, mais les cadres d'un même site sont toujours dans le même processus d'affichage. Du point de vue du rendu, L'avantage de plusieurs processus d'affichage est que les iFrames intersites et onglets permettent une isolation des performances. les uns des autres. De plus, les origines peuvent activer une isolation encore plus importante.

Il existe exactement un processus de visualisation pour tout Chromium, car il n'y a généralement que un GPU et un écran de dessin.

Séparer Visualisation dans son propre processus est bon pour la stabilité face aux bogues dans les pilotes de GPU ou le matériel. C'est aussi bon pour l'isolation de sécurité, ce qui est important pour les API GPU telles que Vulkan et la sécurité en général.

Étant donné que le navigateur peut avoir de nombreux onglets et fenêtres, et ont tous des pixels d'interface utilisateur de navigateur à dessiner, vous vous demandez peut-être pourquoi il n'y a qu'un seul processus de navigateur. En effet, un seul d'entre eux est concentré à la fois ; En fait, les onglets non visibles du navigateur sont pour la plupart désactivés et suppriment toute leur mémoire GPU. Cependant, des fonctionnalités complexes de rendu de l'interface utilisateur sont de plus en plus souvent implémentées dans les processus de rendu (appelés WebUI). Ce n'est pas pour des raisons d'isolation des performances, mais pour profiter de la facilité d'utilisation du moteur de rendu Web de Chromium.

Sur les anciens appareils Android : le processus d'affichage et de navigateur est partagé lorsqu'il est utilisé dans une WebView. (cela ne s'applique pas en général à Chromium sur Android, mais uniquement à WebView). Sur WebView, le processus du navigateur est également partagé avec l'application d'intégration, et WebView n'a qu'un seul processus de rendu.

Parfois, un utilitaire permet également de décoder du contenu vidéo protégé. Ce processus n'est pas représenté dans les schémas précédents.

Threads

Les threads permettent d'isoler les performances et d'assurer la réactivité malgré la lenteur des tâches. parallélisation des pipelines et plusieurs mises en mémoire tampon.

Schéma du processus de rendu.

  • Le thread principal exécute les scripts, la boucle d'événements de rendu, le cycle de vie du document, les tests de positionnement, l'envoi d'événements de script et l'analyse de formats de données HTML, CSS et autres.
    • Les assistants de thread principaux effectuent des tâches telles que la création de bitmaps et de blobs d'image qui nécessitent un encodage ou un décodage.
    • Web Workers d'exécution du script et une boucle d'événements de rendu pour OffscreenCanvas.
  • Le thread du compositeur traite les événements d'entrée. effectue des défilements et des animations de contenu Web ; calcule la duplication optimale du contenu Web, et coordonne le décodage des images, les peinture et les tâches matricielles.
    • Les assistants de thread du compositeur coordonnent les tâches de trame Viz. et exécuter des tâches de décodage d'images, des worklets de peinture et un matricule de remplacement.
  • Décodage des threads multimédias, du démultiplexeur ou de la sortie audio traiter et synchroniser des flux vidéo et audio. N'oubliez pas que la vidéo s'exécute en parallèle du pipeline de rendu principal.

Il est essentiel de séparer les threads principaux et compositeurs et l'isolation des performances. d'animation et de défilement à partir du thread principal.

Il n'y a qu'un seul thread principal par processus de rendu. même si plusieurs onglets ou cadres d'un même site peuvent se retrouver dans le même processus. Toutefois, les performances sont isolées du travail effectué dans les différentes API de navigateur. Par exemple, la génération de bitmaps et de blobs d'image dans l'API Canvas s'exécute dans un thread d'assistance de thread principal.

De même, il n'y a qu'un seul thread compositeur par processus de rendu. Ce n'est généralement pas un problème s'il n'y en a qu'un, car toutes les opérations très coûteuses sur le thread du compositeur sont déléguées aux threads de travail du compositeur ou au processus de visualisation, en parallèle avec le routage des entrées, le défilement ou l'animation. Les threads de travail du compositeur coordonnent les tâches exécutées dans le processus de visualisation. mais l'accélération des GPU partout. peuvent échouer pour des raisons indépendantes de la volonté de Chromium, comme les bugs des conducteurs. Dans ces situations, le thread de travail effectue le travail en mode de secours sur le processeur.

Le nombre de threads de travail du compositeur dépend des capacités de l'appareil. Par exemple, les ordinateurs de bureau utilisent généralement plus de threads, car ils ont plus de cœurs de processeur et sont moins limités en batterie que les appareils mobiles. Dans cet exemple, à la hausse ou à la baisse.

L'architecture threading du processus de rendu est une application de trois méthodes différentes d'optimisation:

  • Fils de discussion d'aide: envoyez les tâches secondaires de longue durée à d'autres threads pour conserver le thread parent réagit à d'autres requêtes simultanées. Thread principal Les fils de discussion des assistants et des compositeurs sont de bons exemples de cette technique.
  • Mise en mémoire tampon multiple: afficher le contenu déjà affiché pendant le rendu du nouveau, pour masquer la latence d'affichage. Cette technique est utilisée par le fil de discussion du compositeur.
  • Parallélisation du pipeline:exécute le pipeline de rendu à plusieurs endroits. simultanément. C'est ainsi que le défilement et l'animation peuvent être rapides ; même si le rendu du thread principal est en cours, le défilement et l'animation qui s'exécutent en parallèle.

Processus du navigateur

Schéma du processus de navigateur montrant la relation entre le thread de rendu et de composition, et l&#39;assistant de thread de rendu et de composition.

  • Le thread de rendu et de composition répond aux entrées dans l'interface utilisateur du navigateur. achemine les autres entrées vers le processus de rendu approprié ; présente et peint l'interface du navigateur.
  • Les assistants de rendu et de composition des threads exécuter des tâches de décodage d'images et de matriciel de remplacement ou de décodage.

Le rendu du processus de navigateur et le thread de composition sont similaires au code et aux fonctionnalités d'un processus de rendu, sauf que le thread principal et le thread compositeur sont combinés en un seul. Un seul thread est nécessaire dans ce cas, car il n'est pas nécessaire à l'isolement des performances des longues tâches du thread principal, puisqu'il n'y en a pas par nature.

Processus de visualisation

Le processus de visualisation inclut le thread principal GPU et le thread du compositeur d&#39;affichage.

  • Les trames Thread principal du GPU affichent des listes et des images vidéo dans des tuiles de texture GPU. et dessine des cadres de compositeur à l'écran.
  • Le thread du compositeur display agrège et optimise la composition à partir de chaque processus de rendu. ainsi que le processus du navigateur, dans un seul cadre de compositeur pour la présentation à l'écran.

Les trames et les dessins s'effectuent généralement sur le même thread, car elles reposent toutes les deux sur les ressources GPU, et il est difficile d'utiliser le GPU de manière fiable (un accès multithread plus facile au GPU est l'une des motivations du développement de la norme Vulkan). Sur Android WebView, il existe un thread de rendu distinct au niveau de l'OS pour dessiner en raison de la façon dont les WebViews sont intégrés dans une application native. D'autres plates-formes seront susceptibles d'avoir ce type de fil à l'avenir.

Le compositeur d'affichage se trouve sur un thread différent, car il doit être réactif à tout moment. et ne bloque aucune source possible de ralentissement sur le thread principal GPU. L'une des causes de ralentissement sur le thread principal du GPU est les appels dans du code non-Chromium, comme les pilotes de GPU propres au fournisseur, qui peuvent être lents de manière difficile à prédire.

Structure des composants

Dans chaque thread principal ou compositeur d'un processus de rendu, des composants logiciels logiques interagissent les uns avec les autres de manière structurée.

Composants du thread principal du processus de rendu

Schéma du moteur de rendu Blink.

Dans le moteur de rendu Blink:

  • Le fragment d'arborescence de frames locaux représente l'arborescence des frames locaux et le DOM au sein des frames.
  • Le composant API DOM et Canvas contient des implémentations de toutes ces API.
  • L'exécuteur de cycle de vie des documents exécute les étapes du pipeline de rendu jusqu'à l'étape de commit (incluse).
  • Le composant input event testing and distribution exécute des tests de positionnement pour Identifier l'élément DOM ciblé par un événement et exécuter l'événement d'entrée des algorithmes de distribution et des comportements par défaut.

L'exécuteur et le planificateur de boucle d'événements de rendu décide quoi exécuter sur l'événement boucle et quand. Il planifie le rendu à un rythme correspondant à celui de l'appareil. l'écran.

Schéma de l&#39;arborescence des frames.

Les fragments d'arborescence de frames locaux sont un peu compliqués. Rappelez-vous qu'une arborescence de frames correspond à la page principale et à ses iFrames enfants, de manière récursive. Une image est locale dans un processus de rendu si elle est rendue au cours de ce processus. et sinon, à distance.

Vous pouvez imaginer la coloration des cadres en fonction de leur processus de rendu. Dans l'image précédente, les cercles verts sont tous des cadres d'un même processus de rendu. les oranges sont dans une seconde et les bleues dans une troisième.

Un fragment d'arborescence de frames local est un composant connecté de la même couleur dans une arborescence de frames. L'image comporte quatre arbres de cadre locaux: deux pour le site A, un pour le site B et un pour le site C. Chaque arborescence de frames locale dispose de son propre composant de moteur de rendu Blink. Le moteur de rendu Blink d'une arborescence locale peut se trouver dans le même processus de rendu ou non. que d'autres arborescences locales. Elle dépend de la façon dont les processus de rendu sont sélectionnés, comme décrit précédemment.

Structure de thread du compositeur du processus de rendu

Schéma illustrant les composants du compositeur du processus de rendu.

Les composants du compositeur du processus de rendu sont les suivants:

  • Gestionnaire de données qui gère une liste de calques composites, des listes d'affichage et des arborescences de propriétés.
  • Un exécuteur de cycle de vie qui exécute les fonctions d'animation, de défilement, de composite, de trame et décoder et activer les étapes du pipeline de rendu. N'oubliez pas que les animations et les défilements peuvent se produire à la fois dans le thread principal et dans le compositeur.
  • Un gestionnaire de test d'entrée et de positionnement effectue le traitement des entrées et des tests de positionnement à la résolution des couches composites. pour déterminer si des gestes de défilement peuvent être exécutés sur le thread du compositeur, et le processus de rendu à cibler par les tests de positionnement.

Exemple d'architecture en pratique

Cet exemple comporte trois onglets:

Onglet 1: foo.com

<html>
  <iframe id=one src="foo.com/other-url"></iframe>
  <iframe  id=two src="bar.com"></iframe>
</html>

Onglet 2: bar.com

<html>
 …
</html>

Onglet 3: baz.com html <html> … </html>

Le processus, le thread et la structure des composants de ces onglets se présentent comme suit:

Schéma du processus pour les onglets.

Examinons un exemple pour chacune des quatre tâches principales de rendu. Rappel:

  1. Rendez les contenus en pixels à l'écran.
  2. Animez des effets visuels sur le contenu en passant d'un état à un autre.
  3. Défilement en réponse à l'entrée.
  4. Acheminez efficacement les entrées aux bons endroits afin que les scripts de développement et les autres sous-systèmes puissent répondre.

Pour afficher le DOM modifié de l'onglet 1:

  1. Un script de développement modifie le DOM lors du processus de rendu de foo.com.
  2. Le moteur de rendu Blink indique au compositeur qu'un rendu est nécessaire.
  3. Le compositeur indique à Viz qu'un rendu est nécessaire.
  4. La visualisation indique au compositeur le début du rendu.
  5. Le compositeur transmet le signal de démarrage au moteur de rendu Blink.
  6. L'exécuteur de boucle d'événements de thread principal exécute le cycle de vie du document.
  7. Le thread principal envoie le résultat au thread du compositeur.
  8. L'exécuteur de boucle d'événements du compositeur exécute le cycle de vie de la composition.
  9. Toutes les tâches matricielles sont envoyées à Viz pour la trame (il y en a souvent plusieurs).
  10. Viz les contenus rasters sur le GPU.
  11. La visualisation confirme que la tâche matricielle est terminée. Remarque: Souvent, Chromium n'attend pas que la trame soit terminée, et utilise à la place ce qu'on appelle un jeton de synchronisation à résoudre par des tâches matricielles avant l'exécution de l'étape 15.
  12. Une image compositeur est envoyée à Viz.
  13. Viz agrège les images des compositeurs pour le processus de rendu de foo.com, le processus d'affichage iFrame de bar.com et l'UI du navigateur.
  14. Visualisation planifie un tirage au sort.
  15. Viz dessine le frame compositeur agrégé à l'écran.

Pour animer une transition de transformation CSS dans le deuxième onglet:

  1. Le thread du compositeur pour le processus de rendu bar.com fait tourner une animation dans sa boucle d'événements de compositeur en mutant les arborescences de propriétés existantes. Le cycle de vie du compositeur est ensuite réexécuté. (Des tâches de trame et de décodage peuvent se produire, mais elles ne sont pas décrites ici.)
  2. Une image compositeur est envoyée à Viz.
  3. Viz regroupe les images du compositeur pour le processus de rendu de foo.com, le processus de rendu bar.com et l'interface utilisateur du navigateur.
  4. Visualisation planifie un tirage au sort.
  5. Viz dessine le frame compositeur agrégé à l'écran.

Pour faire défiler la page Web dans le troisième onglet:

  1. Une séquence d'événements input (souris, écran tactile ou clavier) est transmise au processus du navigateur.
  2. Chaque événement est acheminé vers le thread du compositeur du processus de rendu de baz.com.
  3. Le compositeur détermine si le thread principal doit être informé de l'événement.
  4. L'événement est envoyé, si nécessaire, au thread principal.
  5. Le thread principal déclenche les écouteurs d'événements input (pointerdown, touchstar, pointermove, touchmove ou wheel) pour voir si les écouteurs appelleront preventDefault sur l'événement.
  6. Le thread principal indique si preventDefault a été appelé au compositeur.
  7. Sinon, l'événement d'entrée est renvoyé au processus du navigateur.
  8. Le processus du navigateur le convertit en geste de défilement en le combinant avec d'autres événements récents.
  9. Le geste de défilement est à nouveau envoyé au thread du compositeur du processus de rendu de baz.com,
  10. Le défilement est appliqué à cet emplacement, et le fil de discussion du compositeur pour bar.com le processus de rendu fait défiler une animation dans sa boucle d'événements du compositeur. Cette opération modifie ensuite le décalage de défilement dans les arborescences de propriétés et réexécute le cycle de vie du compositeur. Elle indique également au thread principal de déclencher un événement scroll (non représenté ici).
  11. Une image compositeur est envoyée à Viz.
  12. Viz agrège les images des compositeurs pour le processus de rendu de foo.com, le processus d'affichage bar.com et l'UI du navigateur.
  13. Visualisation planifie un tirage au sort.
  14. Viz dessine le frame compositeur agrégé à l'écran.

Pour acheminer un événement click sur un lien hypertexte dans l'iFrame #two dans l'onglet 1:

  1. Un événement input (souris, écran tactile ou clavier) est transmis au processus du navigateur. Il effectue un test de positionnement approximatif pour déterminer que le processus d'affichage iFrame de bar.com doit recevoir le clic, et l'envoie à cet emplacement.
  2. Le thread compositeur pour bar.com achemine l'événement click vers le thread principal. pour bar.com et planifie une tâche de boucle d'événements de rendu pour le traiter.
  3. Le processeur d'événements d'entrée pour les tests de hits du thread principal de bar.com doit déterminer quel Un clic a été enregistré sur l'élément DOM de l'iFrame et déclenche un événement click pour que les scripts soient surveillés. Si vous n'entendez pas de preventDefault, l'action permet d'accéder au lien hypertexte.
  4. Lors du chargement de la page de destination du lien hypertexte, le nouvel état s'affiche, avec des étapes semblables à l'opération "rendu DOM modifié" exemple précédent. (Les modifications ultérieures ne sont pas décrites ici.)

Plats à emporter

Il faut parfois beaucoup de temps pour mémoriser et intérioriser le fonctionnement de l'affichage.

Le point le plus important à retenir est que le pipeline de rendu, grâce à des la modularisation et le souci du détail, a été divisé en plusieurs composants autonomes. Ces composants ont ensuite été divisés en de processus et de threads afin d'optimiser des performances évolutives et d'extensibilité.

Chaque composant joue un rôle essentiel dans les performances et les fonctionnalités les applications Web modernes.

Poursuivez votre lecture sur les principales structures de données, qui sont tout aussi importantes pour RenderingNG que les composants de code.


Illustrations d'Una Kravets.