Skia Graphite : Le nouveau moteur graphique de Chrome qui redéfinit la fluidité et la vitesse

Skia Graphite : Le nouveau moteur graphique de Chrome qui redéfinit la fluidité et la vitesse
Skia Graphite : Le nouveau moteur graphique de Chrome qui redéfinit la fluidité et la vitesse

Google Chrome vient de franchir une étape cruciale pour son avenir graphique avec le déploiement de Skia Graphite, son nouveau backend de rastérisation. Initialement lancé sur les Mac équipés de puces Apple Silicon, cette innovation majeure promet non seulement des performances visuelles époustouflantes, comme en témoignent les scores records sur Motionmark 1.3, mais ouvre également la voie à une multitude d’améliorations graphiques futures pour le navigateur.

Une plongée dans l’histoire graphique de Chrome

Depuis ses débuts, Chrome s’appuie sur Skia pour transformer les commandes de « peinture » (issues de Blink et de l’interface utilisateur) en pixels affichés sur votre écran – un processus connu sous le nom de rastérisation. Ce partenariat historique, remontant aux premiers jours du navigateur, a été mis à l’épreuve par l’évolution constante et la complexité croissante du web. Face à ces défis de performance, Chrome et Skia ont investi dans un backend de rastérisation accéléré par GPU : Ganesh.

Au fil des ans, Ganesh a mûri pour devenir une solution robuste et performante, permettant la rastérisation GPU sur toutes les plateformes via GL (et ANGLE sur Windows D3D9/11). Cependant, sa conception restait profondément ancrée dans l’univers GL, avec des chemins de code trop spécialisés. L’équipe a fini par se heurter à un mur, incapable d’implémenter des optimisations tirant pleinement parti des API graphiques modernes de manière cohérente.

Cette impasse a été le catalyseur d’une refonte complète de la rastérisation GPU, donnant naissance à Graphite. Dès sa conception, Graphite a été pensé pour être « principled », avec moins de chemins de code et une meilleure compréhensibilité. Cette architecture avant-gardiste permet d’exploiter pleinement les API graphiques de nouvelle génération comme Vulkan, Metal et D3D12, ainsi que des paradigmes modernes tels que la rastérisation de chemins basée sur le calcul GPU, le tout étant multithreadé par défaut. Un véritable bond de géant pour la gestion des pixels !

Des résultats concrets et une fluidité accrue

Avec l’intégration de Graphite dans Chrome, les chiffres parlent d’eux-mêmes : les scores sur le benchmark Motionmark 1.3 ont bondi de près de 15% sur un MacBook Pro M3. Mais au-delà des benchmarks, ce sont les métriques du monde réel qui bénéficient le plus de cette avancée. On observe une nette amélioration de l’INP (Interaction to Next Paint time), du LCP (Largest Contentful Paint), de la fluidité graphique (réduction des frames perdues), de l’utilisation de la mémoire du processus GPU, et bien d’autres.

« En pratique, cela se traduit par des interactions sensiblement plus fluides, des défilements sans la moindre saccade et un temps d’attente réduit pour l’affichage des sites web, » explique l’équipe de développement. Fini les micro-freezes qui gâchent l’expérience utilisateur, le web n’a jamais été aussi réactif sous Chrome.

Graphite vs. Ganesh : les différences fondamentales

Des API graphiques modernes enfin exploitées

Ganesh, à l’origine, reposait sur OpenGL ES, une API avec un support minimal pour le multithreading et les capacités de calcul GPU (« compute shaders »). Depuis, les API graphiques modernes comme Vulkan, Metal et D3D12 ont évolué pour exploiter pleinement le multithreading et exposer de nouvelles capacités GPU. Elles offrent aux applications un contrôle bien plus fin sur l’exécution et la planification des tâches coûteuses (comme l’allocation de ressources GPU), optimisant ainsi l’utilisation du CPU et du GPU.

Bien que des adaptations aient été faites pour permettre à Ganesh de prendre en charge ces nouvelles API, sa « dette technique » accumulée le rendait incapable d’exploiter pleinement le multithreading et les capacités de calcul GPU. Pour Graphite, l’équipe Chrome a fait un choix stratégique : utiliser Dawn, l’implémentation WebGPU de Chrome, comme couche d’abstraction. Cette approche réduit considérablement la charge de maintenance à long terme en tirant parti des backends natifs matures et bien testés de Dawn, plutôt que de tout réimplémenter à partir de zéro.

La profondeur en 2D : une optimisation inattendue

Un élément clé du pipeline de rendu GPU est le test de profondeur (ou « depth testing »), qui permet de réduire ou d’éliminer le « surdessin » (overdraw) en affichant les objets opaques de l’avant vers l’arrière, puis les objets translucides de l’arrière vers l’avant. L’overdraw, ce rendu inutile des mêmes pixels plusieurs fois, impacte négativement les performances et l’autonomie, surtout sur les appareils mobiles.

Ganesh, conçu pour l’accélération 2D et non 3D, n’a jamais utilisé les capacités de test de profondeur des cartes graphiques. Il souffrait donc d’un surdessin significatif, contraint par l’ordre strict des « peintres » pour tous les objets.

Graphite étend le rendu GPU de Skia pour tirer parti de ce test de profondeur. Chaque opération de dessin se voit attribuer une valeur « z » définissant son indice d’ordre. Si les effets transparents doivent toujours être rendus de l’arrière vers l’avant, les objets opaques au premier plan peuvent désormais éliminer automatiquement le surdessin. Cela permet de réorganiser les opérations de dessin opaques pour minimiser les changements d’état GPU coûteux, tout en garantissant un rendu correct grâce au tampon de profondeur.

Le test de profondeur est également utilisé par Graphite pour la gestion des « clips » (zones de découpe). Plutôt que de maintenir une pile de clips complexe comme Ganesh, Graphite traite les formes de clip comme des dessins de profondeur uniquement. Outre la réduction de la complexité algorithmique, l’avantage majeur est que le programme shader nécessaire au rendu d’une opération de dessin ne dépend plus de l’état de la pile de clips.

Le multithreading, clé de la réactivité

Chromium est une application multiprocessus complexe : les processus de rendu émettent des commandes vers un processus GPU partagé, responsable de l’affichage de tout le contenu web, des onglets et de l’interface du navigateur. Le thread principal du processus GPU est le moteur de tout le travail de rendu, là où toutes les commandes GPU sont émises.

En raison de la nature monothread de Ganesh et d’OpenGL, seule une partie limitée du travail pouvait être déléguée à d’autres threads, surchargeant facilement le thread principal et provoquant saccades et latence, au détriment de l’expérience utilisateur.

À l’inverse, l’API de Graphite a été conçue pour tirer parti des capacités multithread des API graphiques modernes. Sa nouvelle API centrale s’articule autour de « Recorders » indépendants, capables de produire des « Recordings » sur plusieurs threads avec un besoin minimal de synchronisation. Même si les « Recordings » sont finalement soumis au GPU sur le thread principal, le travail coûteux est déplacé vers d’autres threads lors de leur production, libérant ainsi le thread principal du GPU. Une vraie symphonie de threads pour une fluidité maximale !

Fin des « falaises de performance » et compilation optimisée

À l’époque où Ganesh a été implémenté, les capacités programmables des cartes graphiques étaient très limitées, et les embranchements (branching) en particulier étaient coûteux. Pour contourner cela, Ganesh utilisait de nombreux pipelines de shaders spécialisés pour gérer les cas courants. Ces spécialisations étaient difficiles à prévoir et dépendaient d’une multitude de facteurs pour chaque opération de dessin, entraînant une « explosion » de pipelines différents pour un contenu de page finalement similaire.

Comme chaque pipeline devait être compilé, cela fonctionnait mal pour le contenu web moderne, où effets et animations peuvent déclencher de nouveaux pipelines à tout moment, causant des saccades perceptibles. La philosophie de conception de Graphite est diamétralement opposée : consolider autant que possible le nombre de pipelines de rendu tout en préservant les performances.

Cette approche réduit le nombre de pipelines à compiler et permet à Chrome de s’assurer qu’ils sont pré-compilés au démarrage, évitant ainsi d’interrompre la navigation active. Les « falaises de performance » (performance cliffs) surprenantes de Ganesh, où un contenu simple était bien géré mais une légère complexité entraînait une chute drastique des performances, sont également éliminées. Avec Graphite, le contenu complexe peut être rendu aussi efficacement que le contenu simple.

Le futur est déjà là : les prochaines étapes de Graphite

Rastérisation multithread poussée

Actuellement, Graphite est intégré à Chromium avec deux « Recorders » : l’un gère les tuiles de contenu web et Canvas2D sur le thread principal, l’autre est dédié au compositing. Mais ce modèle ouvre des perspectives passionnantes pour pousser encore plus loin les performances de Chrome. Au lieu de saturer le thread GPU principal avec les tâches de chaque processus de rendu, la rastérisation pourra être répartie sur plusieurs threads, promettant une fluidité encore jamais atteinte.

Réduction de la mémoire GPU pour le contenu simple

Les « Recordings » de Graphite peuvent être réutilisés sur le GPU avec certaines modifications dynamiques, comme la translation. Ceci peut accélérer le défilement en éliminant le travail inutile de réémission des commandes de rendu. Cela permettra de réduire automatiquement la quantité de mémoire GPU requise pour cacher le contenu web sous forme de tuiles. Si le contenu est suffisamment simple, la différence de performance entre dessiner une image en cache et re-rendre son contenu à chaque frame peut justifier de ne pas allouer une tuile dédiée.

La rastérisation de chemins basée sur le calcul GPU

Dans le paysage du rendu graphique 2D, la rastérisation de chemins basée sur le calcul GPU est très en vogue, avec des implémentations récentes comme Pathfinder et Vello. L’équipe souhaite implémenter ces concepts dans Skia, potentiellement via une approche hybride. Actuellement, Graphite s’appuie sur le MSAA (Multisample Anti-Aliasing) lorsque cela est possible, mais cela pose des problèmes de performance sur les GPU intégrés plus anciens ou de consommation mémoire élevée sur les GPU non-tiling. Dans ces cas, il faut revenir à la rastérisation CPU avec un atlas de cache. La rastérisation basée sur le calcul GPU permettrait d’améliorer la qualité visuelle (souvent limitée à 4 échantillons par pixel avec MSAA) et les performances de la rastérisation CPU. Une avancée majeure pour des graphiques toujours plus nets et rapides !

Ces axes sont les prochaines directions que l’équipe Chrome Graphics compte explorer, et l’excitation est palpable quant aux limites qu’ils pourront repousser pour offrir une expérience web toujours plus immersive et réactive.

Mots-clés : Skia, Graphite, Chrome, GPU, Performance

Source : Article original

Retour en haut