Beschleunigtes Rendering in Chrome

Ebenenmodell

Tom Wiltzius
Tom Wiltzius

Einführung

Für die meisten Webentwickler ist das DOM. Das Rendering ist der oft unklare Prozess, bei dem diese Darstellung einer Seite in ein Bild auf dem Bildschirm umgewandelt wird. Moderne Browser haben in den letzten Jahren die Funktionsweise des Renderings verändert, um die Vorteile von Grafikkarten zu nutzen. Dies wird oft nur vage als „Hardwarebeschleunigung“ bezeichnet. Wenn es um eine normale Webseite (d.h. nicht Canvas2D oder WebGL) geht, was bedeutet dieser Begriff wirklich? In diesem Artikel wird das Grundmodell des hardwarebeschleunigten Renderings von Webinhalten in Chrome erläutert.

Große Vorbehalte

Wir sprechen hier über WebKit und insbesondere über den Chromium-Port von WebKit. In diesem Artikel geht es um die Implementierung von Chrome, nicht um die Funktionen der Webplattform. Diese Detailgenauigkeit wird von der Webplattform und den Standards nicht vorgegeben. Daher gibt es keine Garantien, dass in diesem Artikel auch andere Browser verwendet werden. Internes Wissen kann jedoch für eine erweiterte Fehlerbehebung und Leistungsoptimierung nützlich sein.

In diesem Artikel geht es um ein Kernelement der Rendering-Architektur von Chrome, das sich sehr schnell verändert. In diesem Artikel möchten wir auf Inhalte eingehen, die sich wahrscheinlich nicht ändern werden. Es kann jedoch nicht garantiert werden, dass dies auch in sechs Monaten der Fall ist.

Es ist wichtig zu verstehen, dass es in Chrome seit geraumer Zeit zwei verschiedene Renderingpfade gibt: den hardwarebeschleunigten Pfad und den älteren Softwarepfad. Zum Zeitpunkt der Abfassung dieses Artikels folgen alle Seiten dem hardwarebeschleunigten Pfad unter Windows, ChromeOS und Chrome für Android. Auf Mac- und Linux-Computern durchlaufen nur Seiten, die für einen Teil des Inhalts erstellt werden müssen, den beschleunigten Pfad (weitere Informationen dazu, was eine Compositing-Funktion erfordern würde). Bald werden jedoch auch alle Seiten den beschleunigten Pfad durchlaufen.

Und zu guter Letzt sehen wir uns noch genauer an, was die Rendering-Engine ausmacht und welche Funktionen sie einen großen Einfluss auf die Leistung haben. Wenn Sie versuchen, die Leistung Ihrer eigenen Website zu verbessern, kann es hilfreich sein, das Ebenenmodell zu verstehen. Es ist aber auch einfach, sich selbst ins Gedächtnis zu rufen: Ebenen sind nützliche Konstrukte. Wenn Sie jedoch viele davon erstellen, kann dies zu Mehraufwand im gesamten Grafik-Stack führen. Betrachten Sie sich vorgewarnt!

Vom DOM zum Bildschirm

Jetzt neu: Ebenen

Sobald eine Seite geladen und geparst wurde, wird sie im Browser als eine Struktur dargestellt, mit der viele Webentwickler bereits vertraut sind: DOM. Beim Rendern einer Seite verfügt der Browser jedoch über eine Reihe von Zwischendarstellungen, die den Entwicklern nicht direkt angezeigt werden. Die wichtigste dieser Strukturen ist eine Schicht.

In Chrome gibt es eigentlich verschiedene Arten von Ebenen: RenderLayers, die für Unterstrukturen des DOMs verantwortlich sind, und GraphicsLayers, die für Unterstrukturen von RenderLayers verantwortlich sind. Letzteres ist für uns hier am interessantesten, da GraphicsLayers das sind, was als Texturen in die GPU hochgeladen wird. Ich sage ab jetzt nur „Layer“, um GraphicsLayer zu meinen.

Kurze Zusammenfassung der GPU-Terminologie: Was ist eine Textur? Es ist wie eine Bitmapgrafik, die vom Hauptspeicher (RAM) in den Videospeicher (z. B. VRAM auf der GPU) verschoben wird. Sobald es sich auf der GPU befindet, können Sie es einer Mesh-Geometrie zuordnen. In Videospielen oder CAD-Programmen wird diese Technik verwendet, um 3D-Skelettmodellen ein „Skin“ zu verleihen. Chrome nutzt Texturen, um Blöcke mit Webseiteninhalten auf die GPU zu übertragen. Texturen lassen sich kostengünstig verschiedenen Positionen und Transformationen zuordnen, indem sie auf ein einfaches rechteckiges Netz angewendet werden. So funktioniert 3D-CSS und eignet sich auch hervorragend für schnelles Scrollen – mehr dazu später.

Sehen wir uns einige Beispiele an, um das Ebenenkonzept zu veranschaulichen.

Ein sehr nützliches Tool beim Analysieren von Ebenen in Chrome ist die Option "Rahmenlinien für zusammengesetzte Ebenen anzeigen" in den Einstellungen (d.h. das kleine Zahnrad-Symbol) unter der Überschrift "Rendering". Sie hebt ganz einfach hervor, wo sich die Ebenen auf dem Bildschirm befinden. Aktivieren wir die Funktion. Diese Screenshots und Beispiele stammen alle aus der neuesten Chrome Canary-Version, Chrome 27 zum Zeitpunkt der Veröffentlichung dieses Artikels.

Abbildung 1: Eine einschichtige Seite

<!doctype html>
<html>
<body>
  <div>I am a strange root.</div>
</body>
</html>
Screenshot der Rendering-Rahmen einer zusammengesetzten Ebene um die Basisebene der Seite
Screenshot des Renderingrahmens einer zusammengesetzten Ebene um die Basisebene der Seite

Diese Seite hat nur eine Ebene. Das blaue Raster stellt Kacheln dar, die Sie sich als Untereinheiten einer Ebene vorstellen können, die Chrome verwendet, um Teile einer großen Ebene gleichzeitig auf die GPU hochzuladen. Sie sind hier nicht wirklich wichtig.

Abbildung 2: Ein Element in seiner eigenen Ebene

<!doctype html>
<html>
<body>
  <div style="transform: rotateY(30deg) rotateX(-30deg); width: 200px;">
    I am a strange root.
  </div>
</body>
</html>
Screenshot der Rendering-Rahmen einer gedrehten Ebene
Screenshot der gedrehten Ebenenrahmen-Renderingrahmen

Indem wir dem <div> eine CSS-Eigenschaft in 3D hinzufügen, die es dreht, können wir sehen, wie es aussieht, wenn ein Element eine eigene Ebene erhält. Beachten Sie den orangefarbenen Rahmen, der eine Ebene in dieser Ansicht umrandet.

Kriterien zur Ebenenerstellung

Was erhält noch eine eigene Ebene? Die Heuristiken von Chrome haben sich im Laufe der Zeit weiterentwickelt, aber derzeit wird jede der folgenden Triggerebenen erstellt:

  • CSS-Eigenschaften für 3D- oder Perspektivtransformationen
  • <video>-Elemente mit beschleunigter Videodecodierung
  • <canvas>-Elemente mit einem 3D-Kontext (WebGL) oder beschleunigtem 2D-Kontext
  • Zusammengesetzte Plug-ins (z.B. Flash)
  • Elemente mit CSS-Animation für ihre Deckkraft oder Verwendung einer animierten Transformation
  • Elemente mit beschleunigten CSS-Filtern
  • Das Element hat ein untergeordnetes Element mit einer zusammengesetzte Ebene (d. h., das Element hat ein untergeordnetes Element, das sich in seiner eigenen Ebene befindet)
  • Das Element hat ein gleichgeordnetes Element mit einem niedrigeren Z-Index, das über eine zusammengesetzte Ebene verfügt (mit anderen Worten, es wird über einer zusammengesetzten Ebene gerendert).

Praktische Auswirkungen: Animation

Wir können auch Ebenen verschieben, was sie für Animationen sehr nützlich macht.

Abbildung 3: Animierte Ebenen

<!doctype html>
<html>
<head>
  <style>
  div {
    animation-duration: 5s;
    animation-name: slide;
    animation-iteration-count: infinite;
    animation-direction: alternate;
    width: 200px;
    height: 200px;
    margin: 100px;
    background-color: gray;
  }
  @keyframes slide {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(120deg);
    }
  }
  </style>
</head>
<body>
  <div>I am a strange root.</div>
</body>
</html>

Wie bereits erwähnt, sind Ebenen sehr nützlich für das Verschieben von statischen Webinhalten. Im Grundfall zeichnet Chrome den Inhalt einer Ebene in eine Software-Bitmap, bevor er sie als Textur auf die GPU hochlädt. Wenn sich diese Inhalte in Zukunft nicht ändern, müssen sie nicht neu gezeichnet werden. Das ist eine gute Sache: Die Neugestaltung erfordert Zeit, die für andere Dinge, wie das Ausführen von JavaScript, aufgewendet werden kann, und wenn der Paint sehr lang ist, kommt es bei Animationen zu Störungen oder Verzögerungen.

Sehen Sie sich zum Beispiel diese Ansicht der Zeitachse der Entwicklertools an: Es gibt keine Paint-Vorgänge, während diese Ebene hin und her rotiert.

<ph type="x-smartling-placeholder">
</ph> Screenshot der Entwicklertools-Zeitachse während der Animation
Screenshot der Entwicklertools-Zeitachse während der Animation

Ungültig! Neuanstrich

Wenn sich der Inhalt der Ebene jedoch ändert, muss sie neu gezeichnet werden.

Abbildung 4: Übermalen von Ebenen

<!doctype html>
<html>
<head>
  <style>
  div {
    animation-duration: 5s;
    animation-name: slide;
    animation-iteration-count: infinite;
    animation-direction: alternate;
    width: 200px;
    height: 200px;
    margin: 100px;
    background-color: gray;
  }
  @keyframes slide {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(120deg);
    }
  }
  </style>
</head>
<body>
  <div id="foo">I am a strange root.</div>
  <input id="paint" type="button" value="repaint">
  <script>
    var w = 200;
    document.getElementById('paint').onclick = function() {
      document.getElementById('foo').style.width = (w++) + 'px';
    }
  </script>
</body>
</html>

Bei jedem Klick auf das Eingabeelement wird das rotierende Element um 1 Pixel breiter. Dies führt zu einer Neugestaltung des Layouts und der Darstellung des gesamten Elements, in diesem Fall eine ganze Ebene.

Eine gute Möglichkeit, um zu sehen, was gezeichnet wird, ist das Tool „Farbkorrekturen anzeigen“ in den Entwicklertools, das sich in den Einstellungen der Entwicklertools unter der Überschrift „Rendering“ befindet. Nachdem Sie die Funktion aktiviert haben, blinken sowohl das animierte Element als auch die Schaltfläche rot, wenn auf die Schaltfläche geklickt wird.

<ph type="x-smartling-placeholder">
</ph> Screenshot des Kästchens für die Anzeige von Paint-Rects
Screenshot des Kästchens für die Schaltfläche „Bilder anzeigen“

Die Paint-Ereignisse werden auch in der Zeitachse der Entwicklertools angezeigt. Leser mit scharfen Augen bemerken möglicherweise, dass es dort zwei Paint-Ereignisse gibt: eines für die Ebene und eines für die Schaltfläche selbst, die neu gezeichnet wird, wenn sie den niederdrückten Zustand wechselt oder wieder wechselt.

<ph type="x-smartling-placeholder">
</ph> Screenshot der Zeitachse der Entwicklertools zum Übermalen einer Ebene
Screenshot der Zeitachse der Entwicklertools zum Aktualisieren einer Ebene

Beachten Sie, dass Chrome nicht immer die gesamte Ebene neu gestalten muss. Es wird versucht, nur den Teil des DOMs neu zu gestalten, der ungültig gemacht wurde. In diesem Fall ist das geänderte DOM-Element die Größe der gesamten Ebene. Aber in vielen anderen Fällen gibt es viele DOM-Elemente in einer Ebene.

Die nächste offensichtliche Frage ist, was eine Entwertung verursacht und eine Aktualisierung erzwingt. Es ist schwierig, diese Frage umfassend zu beantworten, da es viele Grenzfälle gibt, die Entwertungen erzwingen können. Die häufigste Ursache ist die Verschmutzung des DOM durch Manipulation von CSS-Stilen oder eine Layoutänderung. Tony Gentilcore hat einen großartigen Blogpost über die Ursachen von Layout-Neulayouts veröffentlicht und Stoyan Stefanov hat einen Artikel über das Malen im Detail (aber es endet mit Malen und nicht mit dieser aufwendigen Modellerstellung).

Die beste Möglichkeit herauszufinden, ob es sich auf etwas, an dem Sie arbeiten, auswirkt, besteht darin, die Entwicklertools-Zeitachse und die Tools zum Anzeigen von Farbecken zu verwenden, um zu sehen, ob Sie Bilder neu zeichnen, wenn Sie es nicht wären. Versuchen Sie dann zu ermitteln, wo Sie das DOM direkt vor dieser Neugestaltung/Bilderstellung beschmutzt haben. Wenn das Painting unvermeidlich ist, aber unverhältnismäßig lange dauert, lesen Sie den Artikel von Eberhard Gräther über den Modus „Kontinuierliches Malen“ in den Entwicklertools.

In Kombination: DOM to Screen

Wie macht Chrome also DOM in ein Bildschirmbild? Konzeptionell betrachtet:

  1. Teilt das DOM in Ebenen auf
  2. Zeichnet jede dieser Ebenen unabhängig in Software-Bitmaps auf.
  3. Lädt sie als Texturen auf die GPU hoch.
  4. Kombiniert die verschiedenen Ebenen zum endgültigen Bildschirmbild.

All das muss passieren, wenn Chrome zum ersten Mal einen Frame einer Webseite erstellt. Für zukünftige Frames können jedoch einige Tastenkombinationen erforderlich sein:

  1. Wenn sich bestimmte CSS-Eigenschaften ändern, ist es nicht erforderlich, alles neu zu gestalten. Chrome kann einfach die vorhandenen Ebenen, die sich bereits auf der GPU befinden, als Texturen kombinieren, jedoch mit anderen Zusammensetzungseigenschaften, z.B. an verschiedenen Positionen oder mit unterschiedlicher Deckkraft.
  2. Wenn ein Teil einer Ebene ungültig wird, wird er neu gezeichnet und hochgeladen. Wenn der Inhalt gleich bleibt, sich aber die zusammengesetzten Attribute ändern (z.B. wenn er übersetzt wird oder sich seine Deckkraft ändert), kann Chrome ihn auf der GPU belassen und neu zusammensetzen, um einen neuen Frame zu erstellen.

Wie jetzt klar sein sollte, hat das schichtbasierte Modell tiefgreifende Auswirkungen auf die Rendering-Leistung. Das Zusammensetzen ist vergleichsweise günstig, wenn nichts gezeichnet werden muss. Daher ist die Vermeidung von Übermalungen von Ebenen ein gutes Gesamtziel, wenn Sie versuchen, eine Rendering-Leistung zu debuggen. Erfahrene Entwickler sehen sich die Liste der Compositing-Trigger oben an und erkennen, dass es einfach möglich ist, das Erstellen von Ebenen zu erzwingen. Aber seien Sie vorsichtig, wenn Sie sie erstellen, da sie nicht kostenlos sind: Sie belegen Arbeitsspeicher im System-RAM und auf der GPU (besonders begrenzt bei Mobilgeräten) und wenn viele davon vorhanden sind, kann dies zu einem anderen Aufwand führen, da die Logik weiß, welche davon sichtbar sind. Viele Ebenen können die Zeit für das Rastern sogar erhöhen, wenn sie groß sind und sich stark überlappen, was zuvor nicht als „Überzeichnung“ bezeichnet wurde. Setzen Sie Ihr Wissen also mit Bedacht ein!

Das ist im Moment erstmal alles. Demnächst finden Sie weitere Artikel zu den praktischen Auswirkungen des Ebenenmodells.

Zusätzliche Ressourcen