Principales structures de données dans RenderingNG

Chris Harrelson
Chris Harrelson
Daniel Cheng
Daniel Cheng
Philip Rogers
Philip Rogers
Koji Ishi
Koji Ishi
Ian Kilpatrick
Ian Kilpatrick
Kyle Charbonneau
Kyle Charbonneau

Examinons les principales structures de données, qui sont les entrées et les sorties du pipeline de rendu.

Ces structures de données sont:

  • Les arborescences de frames sont composées de nœuds locaux et distants qui représentent les documents Web dans quel processus de rendu et quel moteur de rendu Blink.
  • L'arborescence de fragments immuables représente la sortie (et l'entrée) de l'algorithme de contrainte de contrainte de mise en page.
  • Les arborescences de propriétés représentent les hiérarchies de transformation, de clip, d'effet et de défilement d'un document Web. Ceux-ci sont utilisés tout au long du pipeline.
  • Les listes d'affichage et les morceaux de peinture sont les entrées des algorithmes de trame et de superposition.
  • Les cadres compositeurs encapsulent les surfaces, les surfaces de rendu et les tuiles de texture GPU utilisées pour dessiner à l'aide du GPU.

Avant de passer en revue ces structures de données, l'exemple suivant s'appuie sur celui de la vérification de l'architecture. Cet exemple est utilisé tout au long de ce document avec des démonstrations de la façon dont les structures de données s'y appliquent.

<!-- Example code -->
<html>
  <div style="overflow: hidden; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
      id="one" src="foo.com/etc"></iframe>
  </div>
  <iframe style="top:200px;
    transform: scale(1.1) translateX(200px)"
    id="two" src="bar.com"></iframe>
</html>

Encadrer des arbres

Chrome peut parfois choisir d'afficher un frame multi-origine dans un processus d'affichage différent de celui de son frame parent.

Dans l'exemple de code, il y a trois frames au total:

Un cadre parent foo.com, contenant deux iframes.

Avec l'isolation de sites, Chromium utilise deux processus d'affichage pour afficher cette page Web. Chaque processus de rendu possède sa propre représentation de l'arborescence des frames de cette page Web:

Deux arborescences de cadres représentant les deux processus de rendu.

Un frame rendu dans un processus différent est représenté sous la forme d'un frame distant. Un cadre distant contient les informations minimales nécessaires pour servir d'espace réservé dans le rendu, telles que ses dimensions. Sinon, l'image distante ne contient aucune information nécessaire à l'affichage de son contenu réel.

En revanche, une trame locale représente une trame qui passe par le pipeline de rendu standard. Le frame local contient toutes les informations nécessaires pour transformer les données de ce frame (telles que l'arborescence DOM et les données de style) en un élément pouvant être affiché et affiché.

Le pipeline de rendu opère sur la précision d'un fragment d'arborescence de frames locaux. Prenons un exemple plus complexe avec foo.com comme frame principal:

<iframe src="bar.com"></iframe>

Et le sous-cadre bar.com suivant:

<iframe src="foo.com/etc"></iframe>

Bien qu'il n'y ait toujours que deux moteurs de rendu, il existe désormais trois fragments d'arborescence de frames locaux, dont deux dans le processus de rendu pour foo.com et un dans le processus de rendu pour bar.com:

Représentation des deux rendus et de trois fragments d&#39;arborescence de frames.

Pour produire un cadre compositeur pour la page Web, Viz demande simultanément un cadre compositeur à partir du cadre racine de chacune des trois arborescences de cadres locaux, puis les agrège. Reportez-vous également à la section Cadres compositeurs.

Le frame principal foo.com et le sous-frame foo.com/other-page font partie de la même arborescence de frames et sont affichés dans le même processus. Cependant, les deux frames ont toujours des cycles de vie de documents indépendants, car ils font partie de fragments d'arborescence de frames locaux différents. Pour cette raison, il est impossible de générer une image de compositeur pour les deux en une seule mise à jour. Le processus de rendu ne dispose pas de suffisamment d'informations pour combiner le cadre du compositeur généré pour foo.com/other-page directement dans le cadre du compositeur du cadre principal foo.com. Par exemple, le cadre parent bar.com hors processus peut affecter l'affichage de l'iFrame foo.com/other-url, en le transformant avec CSS ou en masquant certaines parties de l'iFrame avec d'autres éléments dans son DOM.

Cascade de mise à jour des propriétés visuelles

Les propriétés visuelles telles que le facteur d'échelle de l'appareil et la taille de la fenêtre d'affichage affectent le résultat rendu et doivent être synchronisées entre les fragments d'arborescence de frames locaux. La racine de chaque fragment d'arborescence de frames locaux est associée à un objet widget. Les mises à jour des propriétés visuelles sont transmises au widget du frame principal avant d'être propagées de haut en bas dans les widgets restants.

Par exemple, lorsque la taille de la fenêtre d'affichage change:

Schéma du processus expliqué dans le texte précédent.

Ce processus n'est pas instantané. Par conséquent, les propriétés visuelles répliquées incluent également un jeton de synchronisation. Le compositeur Viz utilise ce jeton de synchronisation pour attendre que tous les fragments d'arborescence de frames locaux soumettent une trame de compositeur avec le jeton de synchronisation actuel. Ce processus évite de mélanger des images compositeur avec différentes propriétés visuelles.

Arborescence des fragments immuables

L'arborescence de fragments immuables est le résultat de l'étape de mise en page du pipeline de rendu. Elle représente la position et la taille de tous les éléments de la page (sans transformation appliquée).

Représentation des fragments dans chaque arborescence, avec un fragment marqué comme nécessitant une mise en page.

Chaque fragment représente une partie d'un élément DOM. En règle générale, il n'y a qu'un seul fragment par élément, mais il peut y en avoir plus s'il est divisé sur différentes pages lors de l'impression, ou dans des colonnes dans un contexte à plusieurs colonnes.

Après la mise en page, chaque fragment devient immuable et n'est plus jamais modifié. Il est important de noter que nous appliquons également quelques restrictions supplémentaires. Ce que nous ne faisons pas:

  • Autorisez toutes les références "up" dans l'arborescence. (Un enfant ne peut pas avoir de pointeur vers son parent.)
  • dans une "bulle" de données dans l'arborescence (un enfant ne lit que les informations de ses enfants, et non de celles de son parent).

Ces restrictions nous permettent de réutiliser un fragment pour une mise en page ultérieure. Sans ces restrictions, il nous faudrait souvent régénérer l'arborescence entière, ce qui est coûteux.

La plupart des mises en page sont généralement des mises à jour incrémentielles, par exemple une application Web qui met à jour une petite partie de l'interface utilisateur en réponse à un clic de l'utilisateur sur un élément. Idéalement, la mise en page ne devrait fonctionner que de manière proportionnelle à ce qui a réellement changé à l'écran. Pour ce faire, nous pouvons réutiliser autant de parties de l'arborescence précédente que possible. Cela signifie (généralement) que nous avons seulement besoin de reconstruire la colonne vertébrale de l'arbre.

À l'avenir, cette conception immuable pourrait nous permettre de faire des choses intéressantes, comme transmettre l'arborescence de fragments immuables au-delà des limites de thread si nécessaire (pour effectuer des phases ultérieures sur un thread différent), générer plusieurs arborescences pour une animation de mise en page fluide ou effectuer des mises en page spéculatives parallèles. Cela nous donne également le potentiel de la mise en page multithread elle-même.

Éléments de fragment intégrés

Le contenu intégré (principalement le texte avec style) utilise une représentation légèrement différente. Plutôt qu'une arborescence avec des cases et des pointeurs, nous représentons le contenu intégré dans une liste plate représentant l'arborescence. Le principal avantage est qu'une représentation sous forme de liste plate pour les éléments intégrés est rapide et utile pour inspecter ou interroger les structures de données intégrées, et elle est économe en mémoire. Cela est extrêmement important pour les performances de rendu Web, car le rendu du texte est très complexe et peut facilement devenir la partie la plus lente du pipeline s'il n'est pas hautement optimisé.

La liste plate est créée pour chaque contexte de mise en forme intégrée dans l'ordre d'une recherche axée sur la profondeur dans sa sous-arborescence de mise en page intégrée. Chaque entrée de la liste est un tuple de (objet, nombre de descendants). Prenons l'exemple du DOM suivant:

<div style="width: 0;">
  <span style="color: blue; position: relative;">Hi</span> <b>there</b>.
</div>

La propriété width est définie sur 0 afin que la ligne entre "Hi" et "here".

Lorsque le contexte de mise en forme intégrée pour cette situation est représenté sous forme d'arborescence, il se présente comme suit:

{
  "Line box": {
    "Box <span>": {
      "Text": "Hi"
    }
  },
  "Line box": {
    "Box <b>": {
      "Text": "There"
    }
  },
  {
    "Text": "."
  }
}

La liste plate se présente comme suit:

  • (Zone de ligne, 2)
  • (encadré <span>, 1)
  • (Texte "Bonjour", 0)
  • (Zone de ligne, 3)
  • (encadré <b>, 1)
  • (Envoie "Ici", 0)
  • (Texte ".", 0)

De nombreux utilisateurs de cette structure de données sont nombreux: les API d'accessibilité et les API de géométrie telles que getClientRects et contenteditable. Chacune d'elles présente des exigences différentes. Ces composants accèdent à la structure de données plate via un curseur pratique.

Le curseur comporte des API telles que MoveToNext, MoveToNextLine et CursorForChildren. Cette représentation du curseur est très efficace pour le contenu textuel, pour plusieurs raisons:

  • L'itération dans l'ordre de recherche axée sur la profondeur est très rapide. Il est utilisé très souvent parce qu'il est similaire aux mouvements du curseur de saisie. Comme il s'agit d'une liste plate, la recherche axée sur la profondeur ne fait qu'incrémenter le décalage du tableau, fournissant ainsi des itérations rapides et la localité de la mémoire.
  • Il fournit une recherche en portée, nécessaire lorsque, par exemple, peignez l'arrière-plan des lignes et des zones intégrées.
  • Le fait de connaître le nombre de descendants permet de passer rapidement au frère suivant (il suffit d'incrémenter le décalage du tableau en fonction de ce nombre).

Arbres immobiliers

Le DOM est une arborescence d'éléments (plus des nœuds de texte). CSS peut appliquer différents styles aux éléments.

Cela se présente de quatre façons:

  • Layout (Mise en page) : entrées de l'algorithme de contrainte de mise en page.
  • Paint:comment peindre et matriciel l'élément (mais pas ses descendants).
  • Visuel:effets de trame/de dessin appliqués à la sous-arborescence DOM, tels que des transformations, des filtres et des rognages.
  • Défilement:rognage et défilement des angles arrondis et alignés sur les axes de la sous-arborescence contenue.

Les arborescences de propriétés sont des structures de données qui expliquent comment les effets visuels et de défilement s'appliquent aux éléments DOM. Ils permettent de répondre à des questions telles que: où se trouve un élément DOM donné par rapport à l'écran, compte tenu de sa taille et de sa position de mise en page. Quelle séquence d'opérations GPU devez-vous utiliser pour appliquer des effets visuels et de défilement ?

Sur le Web, les effets visuels et de défilement sont très compliqués dans toute leur splendeur. Par conséquent, l'aspect le plus important des arborescences de propriétés est de convertir cette complexité en une seule structure de données qui représente précisément leur structure et leur signification, tout en éliminant le reste du DOM et du CSS. Cela nous permet d'implémenter des algorithmes pour la composition et le défilement avec beaucoup plus de confiance. En particulier :

  • Les géométries potentiellement sources d'erreurs et d'autres calculs peuvent être centralisés au même endroit.
  • La complexité de la création et de la mise à jour des arborescences de propriétés est isolée en une seule étape du pipeline de rendu.
  • Il est beaucoup plus facile et plus rapide d'envoyer des arborescences de propriétés à des threads et des processus différents qu'avec un état DOM complet, ce qui permet de les utiliser dans de nombreux cas d'utilisation.
  • Plus il y a de cas d'utilisation, plus nous pouvons tirer de bénéfices de la mise en cache des géométries construite au-dessus, car elles peuvent réutiliser les caches des autres.

RenderNG utilise les arborescences de propriétés à de nombreuses fins, y compris les suivantes:

  • Séparation de la composition de la peinture et du fil principal.
  • Déterminer une stratégie de composition / de dessin optimale.
  • Mesure de la géométrie IntersectionObserver.
  • Éviter d'utiliser des éléments hors écran et des tuiles de texture GPU.
  • Cette action permet d'invalider les peintures et les trames de manière efficace et précise.
  • Mesure des décalages de mise en page et des Largest Contentful Paint dans Core Web Vitals.

Chaque document Web comporte quatre arborescences de propriétés distinctes: transformation, clip, effet et défilement(*). L'arborescence de transformation représente les transformations CSS et le défilement. (Une transformation de défilement est représentée sous la forme d'une matrice de transformation 2D.) L'arborescence des extraits représente les extraits de type "overflow". L'arborescence des effets représente tous les autres effets visuels: opacité, filtres, masques, modes de combinaison et autres types de clips tels que le chemin de découpage. L'arborescence de défilement représente des informations sur le défilement, telles que la chaîne de défilements entre elles. Elle est nécessaire pour effectuer le défilement sur le thread du compositeur. Dans une arborescence de propriétés, chaque nœud représente un défilement ou un effet visuel appliqué par un élément DOM. Si des effets multiples sont appliqués, il peut y avoir plusieurs nœuds d'arborescence de propriétés dans chaque arborescence pour le même élément.

La topologie de chaque arbre est comme une représentation creuse du DOM. Par exemple, s'il existe trois éléments DOM avec des extraits de dépassement de limite, il y aura trois nœuds d'arborescence de découpage, et la structure de l'arborescence d'extraits suivra la relation de bloc conteneur entre les extraits de dépassement. Il existe également des liens entre les arbres. Ces liens indiquent la hiérarchie DOM relative, et donc l'ordre d'application, des nœuds. Par exemple, si une transformation appliquée à un élément DOM se trouve sous un autre élément DOM avec un filtre, la transformation s'applique bien sûr avant le filtre.

Chaque élément DOM possède un état d'arborescence de propriétés, qui correspond à un 4-tuple (transformer, rogner, effet, faire défiler) qui indique les nœuds écrasant, transformation et effet ancêtres les plus proches qui prennent effet sur cet élément. C'est très pratique, car ces informations nous permettent de connaître exactement la liste des extraits, transformations et effets qui s'appliquent à cet élément, ainsi que leur ordre. Cela nous indique où il se trouve à l'écran et comment le dessiner.

Exemple

(source)

<html>
  <div style="overflow: scroll; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
  id="one" srcdoc="iframe one"></iframe>
  </div>
  <iframe style="top:200px;
      transform: scale(1.1) translateX(200px)" id=two
      srcdoc="iframe two"></iframe>
</html>

Pour l'exemple précédent (qui est légèrement différent de celui de l'introduction), voici les éléments clés des arborescences de propriétés générées:

Exemple des différents éléments de l&#39;arborescence de propriétés.

Afficher des listes et des blocs de peinture

Un élément d'affichage contient des commandes de dessin de niveau inférieur (voir ici) qui peuvent être rastérisées avec Skia. Les éléments d'affichage sont généralement simples, avec seulement quelques commandes de dessin, comme dessiner une bordure ou un arrière-plan. L'arborescence de mise en page parcourt l'arborescence de mise en page et les fragments associés en fonction de l'ordre de peinture CSS pour générer une liste d'éléments d'affichage.

Exemple :

Boîte bleue avec les mots &quot;Hello world&quot; dans un rectangle vert.

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="blue" style="width:100px;
  height:100px; background:blue;
  position:absolute;
  top:0; left:0; z-index:-1;">
</div>

Ce code HTML et CSS génère la liste d'affichage suivante, dans laquelle chaque cellule est un élément d'affichage:

Arrière-plan de la vue #blue en arrière-plan #green en arrière-plan #green texte intégré
drawRect au format 800 x 600 et en blanc. drawRect avec une taille de 100 x 100 en position 0,0 et une couleur bleue. drawRect avec une taille 80 x 18 en position 8 et 8,et une couleur verte. drawTextBlob à la position 8 et 8 avec le texte "Hello world".

La liste des éléments à afficher est triée dans l'ordre chronologique. Dans l'exemple ci-dessus, le div vert se trouve avant le div bleu dans l'ordre DOM, mais l'ordre d'affichage CSS nécessite que le div bleu z-index négatif soit placé avant le div vert (étape 4.1) (étape 3). Les éléments d'affichage correspondent approximativement aux étapes atomiques de la spécification d'ordre de peinture CSS. Un seul élément DOM peut générer plusieurs éléments display, par exemple #green a un élément display pour l'arrière-plan et un autre élément display pour le texte intégré. Cette précision est importante pour représenter toute la complexité de la spécification de l'ordre de peinture CSS, comme l'entrelacement créé par la marge négative:

Rectangle vert avec une zone grise en partie superposée et le texte &quot;Hello world&quot;.

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="gray" style="width:35px; height:20px;
  background:gray;margin-top:-10px;"></div>

Vous obtenez la liste d'affichage suivante, dans laquelle chaque cellule est un élément d'affichage:

Arrière-plan de la vue #green en arrière-plan #gray en arrière-plan #green texte intégré
drawRect au format 800 x 600 et en blanc. drawRect avec une taille 80 x 18 en position 8 et 8,et une couleur verte. drawRect avec une taille 35 x 20 en position 8,16 et une couleur grise. drawTextBlob à la position 8 et 8 avec le texte "Hello world".

Cette liste est stockée et réutilisée par les mises à jour ultérieures. Si un objet de mise en page n'a pas changé pendant le parcours de l'arbre de peinture, ses éléments d'affichage sont copiés à partir de la liste précédente. Une optimisation supplémentaire repose sur une propriété de la spécification de l'ordre de peinture CSS : l'empilement des contextes est atomique. Si aucun objet de mise en page n'a changé dans un contexte d'empilement, l'arborescence de peinture ignore le contexte d'empilement et copie la séquence complète d'éléments d'affichage de la liste précédente.

L'état actuel de l'arborescence de propriétés est conservé pendant le parcours de l'arbre de propriété, et la liste des éléments d'affichage est regroupée par "morceaux" d'éléments display qui partagent le même état d'arborescence de propriétés. Ce processus est illustré dans l'exemple suivant:

Cadre rose avec un cadre orange incliné.

<div id="scroll" style="background:pink; width:100px;
   height:100px; overflow:scroll;
   position:absolute; top:0; left:0;">
    Hello world
    <div id="orange" style="width:75px; height:200px;
      background:orange; transform:rotateZ(25deg);">
        I'm falling
    </div>
</div>

Vous obtenez la liste d'affichage suivante, dans laquelle chaque cellule est un élément d'affichage:

Arrière-plan de la vue #scroll en arrière-plan #scroll texte intégré #orange en arrière-plan #orange texte intégré
drawRect au format 800 x 600 et en blanc. drawRect avec une taille de 100 x 100 en position 0,0 et une couleur rose. drawTextBlob avec la position 0,0 et le texte "Hello world". drawRect avec une taille 75 x 200 en position 0,0 et une couleur orange. drawTextBlob à la position 0,0 et le texte "I'm Falling" (Je tombe).

L'arborescence des propriétés de transformation et les morceaux de peinture seraient alors (simplifiés pour des raisons de concision):

Une image du tableau précédent, les deux premières cellules du bloc 1, la troisième du bloc 2, les deux dernières cellules du bloc 3.

La liste numérotée des fragments de peinture, qui sont des groupes d'éléments d'affichage et un état d'arborescence de propriétés, correspondent aux entrées de l'étape de superposition du pipeline de rendu. La liste complète des morceaux de peinture peut être fusionnée en une seule couche composite et rastérisée ensemble, mais cela nécessiterait une rastérisation coûteuse chaque fois que l'utilisateur fait défiler la page. Une couche composite peut être créée pour chaque fragment de peinture et rastérisée individuellement pour éviter toute nouvelle rastérisation, mais cela épuisera rapidement la mémoire GPU. L'étape de couche doit faire des compromis entre la mémoire GPU et réduire les coûts en cas de changement. Une bonne approche générale consiste à fusionner les fragments par défaut, et non à fusionner les fragments de peinture dont les états d'arborescence de propriétés sont susceptibles de changer sur le thread du compositeur, comme le défilement du thread du compositeur ou les animations de transformation du thread compositeur.

L'exemple précédent devrait idéalement produire deux couches composites:

  • Couche composite de 800 x 600 contenant les commandes de dessin :
    1. drawRect au format 800 x 600 et en blanc
    2. drawRect avec une taille de 100 x 100 en position 0,0 et une couleur rose
  • Couche composite de 144 x 224 contenant les commandes de dessin :
    1. drawTextBlob avec la position 0,0 et le texte "Hello world"
    2. traduire 0,18
    3. rotateZ(25deg)
    4. drawRect avec une taille 75 x 200 en position 0,0 et une couleur orange
    5. drawTextBlob avec la position 0,0 et le texte "I'm Falling"

Si l'utilisateur fait défiler #scroll, la deuxième couche composite est déplacée, mais aucune rastérisation n'est nécessaire.

Dans l'exemple de la section précédente sur les arborescences de propriétés, il existe six morceaux de peinture. Avec leurs états d'arborescence de propriétés (transformer, clip, effet, défilement), voici ce que vous pouvez faire:

  • Arrière-plan du document: défilement du document, clip, racine, défilement du document
  • Angles de défilement horizontal, vertical et de défilement pour l'élément DIV (trois morceaux de peinture distincts) : défilement du document, extrait de document, flou #one, défilement du document.
  • iFrame #one: rotation #one, défilement de l'extrait dépassé, flou #one, défilement div.
  • Iframe #two: échelle #two, clip de document, racine, défilement du document.

Cadres compositeurs: surfaces, surfaces de rendu et tuiles de texture GPU

Les processus de navigateur et de rendu gèrent la rastérisation du contenu, puis envoient des images compositeur au processus de visualisation pour les présenter à l'écran. Les images compositeur montrent comment assembler le contenu rastérisé et le dessiner efficacement à l'aide du GPU.

Cartes

En théorie, un processus de rendu ou un compositeur de processus de navigateur peut rastériser des pixels en une seule texture de la taille réelle de la fenêtre d'affichage du moteur de rendu et envoyer cette texture à Visualisation. Pour l'afficher, le compositeur d'affichage devrait simplement copier les pixels de cette texture unique dans la position appropriée dans le tampon du frame (par exemple, l'écran). Toutefois, si ce compositeur souhaite mettre à jour ne serait-ce qu'un seul pixel, il doit rerastériser toute la fenêtre d'affichage et envoyer une nouvelle texture à la visualisation.

Au lieu de cela, la fenêtre d'affichage est divisée en tuiles. Une tuile de texture GPU distincte sauvegarde chaque tuile avec les pixels rastérisés pour une partie de la fenêtre d'affichage. Le moteur de rendu peut ensuite mettre à jour des tuiles individuelles ou même simplement modifier la position à l'écran des tuiles existantes. Par exemple, lors du défilement d'un site Web, la position des tuiles existantes se décale vers le haut et, seulement de temps en temps, une nouvelle carte devra être rastérisée pour le contenu situé plus bas sur la page.

Quatre vignettes.
Cette image représente une journée ensoleillée avec quatre tuiles. Lorsqu'un défilement se produit, une cinquième vignette commence à apparaître. L'une des tuiles n'a qu'une seule couleur (bleu ciel), et une vidéo et un iFrame se trouvent en haut.

Quads et surfaces

Les tuiles de texture GPU sont un type particulier de quad, qui désigne simplement une catégorie de texture ou une autre. Un quad identifie la texture d'entrée et indique comment la transformer et lui appliquer des effets visuels. Par exemple, des tuiles de contenu normales ont une transformation indiquant leur position x et y dans la grille de tuiles.

Tuiles de texture GPU.

Ces tuiles rastérisées sont encapsulées dans une passe de rendu, qui est une liste de quads. La passe de rendu ne contient aucune information de pixel. Elle contient des instructions indiquant où et comment dessiner chaque quad pour produire la sortie de pixel souhaitée. Il existe un draw quad pour chaque tuile de texture GPU. Le compositeur d'affichage doit simplement parcourir la liste des quadrices, en dessinant chacune d'elles avec les effets visuels spécifiés, afin de produire la sortie de pixels souhaitée pour la passe de rendu. La composition des quads de dessin pour une passe de rendu peut être effectuée efficacement sur le GPU, car les effets visuels autorisés sont soigneusement sélectionnés pour correspondre directement aux caractéristiques du GPU.

Il existe d'autres types de quads en plus des tuiles rastérisées. Par exemple, il existe des quads de dessin de couleur unie qui ne reposent pas du tout sur une texture, ou des quads de dessin de texture pour les textures qui ne sont pas des tuiles, comme une vidéo ou un canevas.

Il est également possible pour une image de compositeur d'intégrer une autre image de compositeur. Par exemple, le compositeur de navigateur génère un cadre de compositeur avec l'interface utilisateur du navigateur, ainsi qu'un rectangle vide dans lequel le contenu du compositeur sera intégré. Autre exemple : les iFrames isolés au niveau du site. Cette représentation vectorielle continue s'effectue via des surfaces.

Lorsqu'un compositeur envoie une image du compositeur, elle est accompagnée d'un identifiant, appelé ID de surface, qui permet à d'autres cadres de compositeur de l'intégrer par référence. La toute dernière image de compositeur soumise avec un ID de surface particulier est stockée par Viz. Une autre image compositeur peut ensuite s'y référer ultérieurement via un quad de dessin de surface, et Viz sait donc quoi dessiner. Notez que les quads de dessin de surface ne contiennent que des ID de surface, et non des textures.

Passes de rendu intermédiaires

Certains effets visuels, tels que de nombreux filtres ou modes de fusion avancés, nécessitent que deux quads ou plus soient dessinés vers une texture intermédiaire. La texture intermédiaire est ensuite dessinée dans un tampon de destination sur le GPU (ou éventuellement une autre texture intermédiaire), ce qui applique l'effet visuel en même temps. Pour ce faire, un cadre compositeur contient en fait une liste de passes de rendu. Il existe toujours une passe de rendu racine, qui est dessinée en dernier et dont la destination correspond au tampon du frame. Il peut y en avoir plus.

La possibilité d'avoir plusieurs passes de rendu explique le nom de "passe de rendu". Chaque passe doit être exécutée de manière séquentielle sur le GPU, en plusieurs "passes", tandis qu'une seule passe peut être effectuée en un seul calcul GPU massivement parallèle.

Agrégation

Plusieurs images de compositeur sont envoyées à Visualisation et doivent être dessinées ensemble à l'écran. Cela est possible grâce à une phase d'agrégation qui les convertit en un seul frame de compositeur agrégé. L'agrégation remplace les quads de surface de dessin par les frames du compositeur qu'ils spécifient. C'est également l'occasion d'optimiser les textures intermédiaires inutiles ou le contenu hors écran. Par exemple, dans de nombreux cas, le frame compositeur d'un iFrame isolé de site n'a pas besoin de sa propre texture intermédiaire et peut être dessiné directement dans le tampon du frame via des quads de dessin appropriés. La phase d'agrégation détermine ces optimisations et les applique en fonction de connaissances globales non accessibles aux compositeurs de rendu individuels.

Exemple

Voici les cadres compositeurs qui représentent l'exemple du début de cet article.

  • Surface foo.com/index.html: id=0
    • Pass de rendu 0:dessine sur la sortie.
      • Passe de rendu quad: dessin avec un flou de 3 px et rognage dans la passe de rendu 0.
        • Passe de rendu 1:
          • Dessinez des quads pour le contenu des tuiles de l'iFrame #one, avec les positions x et y pour chacun.
      • Quadrillage du dessin de surface: ID 2, dessiné avec une mise à l'échelle et une transformation de translation.
  • Surface de l'UI du navigateur: ID=1
    • Pass de rendu 0:dessine sur la sortie.
      • Dessiner quadrillage pour l'interface utilisateur du navigateur (en mosaïque également)
  • Surface bar.com/index.html: ID=2
    • Pass de rendu 0:dessine sur la sortie.
      • Dessinez des quads pour le contenu de l'iFrame #two, avec les positions x et y pour chacun.

Illustrations d'Una Kravets.