- PVSM.RU - https://www.pvsm.ru -
Для большинства веб-разработчиков фундаментальным представлением веб-странницы является DOM. В то время как процесс преобразования этого представления в изображение на экране (далее рендеринг) часто покрыто пеленой непонимания. В последние годы разработчики браузеров активно оптимизируют этот процесс, перекладывая часть работы на плечи графических процессоров: то что называется “аппаратным ускорением (hardware acceleration)”. Мы рассмотрим рендеринг в контексте обычных страниц, исключая Canvas2D и WebGL. Эта статья попытается пролить свет на фундаментальную концепцию использования аппаратного ускорения при генерации изображения веб-контента в браузере Chrome.
Мы здесь будем говорить только о движке WebKit, а если быть более точным о его форке в Chromium’е. Эта статья покрывает детали реализации в Chrome’е, которые не коем образом не задокументированы в стандартах. Поэтому нет гарантий в том, что, что-либо описанное в этой статье будет применимо к другим браузерам. Тем не менее, знание этих тонкостей поможет вам провести тонкую отладку и повысить производительность.
Также, примите во внимание, что движок рендеринга в Chrome’е развивается стремительными шагами. И нет гарантий в том, что всё здесь описанное будет справедливо так же через полгода.
Важно иметь в виду, что на данный момент Chrome поддерживает два механизма рендеринга: аппаратный и старый программный. На момент написания этой статьи все страницы рендерятся с привлечением аппаратного ускорения в Windows’е, ChromeOS и Chrome’е на Android. В MacOS и Linux только страницы, содержащие композиционные элементы сваливаются в этот режим (ниже мы поговорим об этом), но совсем скоро это исправят.
В конечном счёте мы рассмотрим лишь верхушку движка рендерера, уделяя внимания тем вещам, которые призваны существенно повысить производительность. Практика на вашем собственном сайте поможет вам лучше понять модель слоёв. Но не стоит бездумно плодить их количество, это может внести лишние накладные расходы на весь графический стек.
Когда страница загружена и обработана в браузере, она превращается в то, что всем известно как DOM. Процесс рендеринга страницы протекает через серию промежуточных преобразований непосредственно недоступных разработчику. Важнейшая из порождаемых в процессе структур — слой.
Слои в Chrom’е бывают двух типов: Слои Преобразования (RenderLayers), которые содержат поддеревья DOM, и Графические Слои (GraphicsLayers), которые содержат поддеревья предыдущих. Сейчас последние для нас представляют больший интерес, так как Графические Слои это то что отправляется графическому процессору в качестве текстур. Далее по тексту везде, где встречается слово “слой”, я подразумеваю именно Графический Слой.
Слегка отвлечёмся на GPU терминологию и попробуем разобраться, что такое текстура?
Думайте о ней как о порции битового отображения графического объекта (bitmap), которая передаётся из основной памяти (RAM) в память графического процессора (VRAM). Когда текстура попадает в руки GPU, он может натянуть её на полигональную сетку — в видео играх это техника используется для натяжки “кожи” на трёхмерные объекты. Chrome использует текстуры для передачи порций контента страницы графическому процессору, что бы тот впоследствии мог наложить их на простую квадратную сетку и вытворять с ней любые трёхмерные преобразования. Именно так работает 3D CSS и также это прекрасно сказывается на производительности прокрутки страницы — но обо всём по порядку.
Давайте рассмотрим пару примеров для более наглядной демонстрации концепции слоёв.
Есть очень полезный инструмент для понимания слоёв в Chrome’е — опция “show composited layer borders” в разделе “rendering” окна настроек панели инструментов разработчика. Эта опция просто подсвечивает границы расположения слоёв на экране оранжевым цветом. Давайте её включим. Все скриншоты для примеров были сделаны в Chrome Canary, Chrome 27 на момент написания данной статьи.
<html>
<body>
<div>I am a strange root.</div>
</body>
</html>
Эта страница имеет единственный слой. Голубая сетка представляет собой границы тайлов — частей слоя, которые Chrome использует для разбивки большого слоя и отправки их GPU. Сейчас они не представляют для нас большого интереса.
<html>
<body>
<div style="-webkit-transform: rotateY(30deg) rotateX(-30deg); width: 200px;">
I am a strange root.
</div>
</body>
</html>
Задавая 3D CSS свойство элементу, которое поворачивает его, мы можем видеть, что ему выделяется его собственный слой: обратите внимание на оранжевую рамку, которая оборачивает его на скриншоте выше. (Это делается для того, что бы можно было рендерить каждый слой независимо от других)
Какие ещё элементы могут заполучить свой слой? Эвристика Chrome’а развивается в этом направление последнее время, но в настоящий момент любое из следующих условий приводит к созданию слоя:
<video>
использующий аппаратное ускорение при декодировании видео<canvas>
в 3D(WebGL) контексте или ускоренном 2DМы знаем, что посредством анимации CSS трансформации элемент свалится в свой собственный слой. А слои очень хороши для анимации.
<html>
<head>
<style type="text/css">
div {
-webkit-animation-duration: 5s;
-webkit-animation-name: slide;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@-webkit-keyframes slide {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div>I am a strange root.</div>
</body>
</html>
В простейшем случае Chrome’е программно отрисует содержимое слоя и отправит его на отмашку графическому процессору в качестве текстуры. Если это содержимое не будет изменяться в будущем, то нет нужды его перерисовывать. И это хорошо: перерисовка отнимает время, которое может быть потрачено, например, на отработку скриптов. И если перерисовка занимает много времени, это может привести к досадным дефектам в виде падения частоты кадров и задержек в анимации.
Можете убедится, что на временной шкале панели разработчиков нет ни каких операций перерисовки, пока слой вращается туда — сюда.
Но если содержимое слоя изменить, это приведёт к его перерисовке.
<html>
<head>
<style type="text/css">
div {
-webkit-animation-duration: 5s;
-webkit-animation-name: slide;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@-webkit-keyframes slide {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div id="foo">I am a strange root.</div>
<input id="paint" type="button" onclick="" value=”repaint”>
<script>
var w = 200;
document.getElementById('paint').onclick = function() {
document.getElementById('foo').style.width = (w++) + 'px';
}
</script>
</body>
</html>
Каждый раз, когда кнопка будет нажата, вращающийся элемент будет прибавлять пиксель в ширине. Это приведёт к перерисовке всего элемента, который в данном случае находится в отдельном слое.
Простой способ, увидеть какие части страницы перерисовываются включить опцию “show paint rects” всё в том же разделе “Rendering” окна настроек панели разработчиков. После включения обратите внимание как анимированный элемент, и кнопка мерцают красным при клике по кнопке.
События перерисовки можно также заметить на временной шкале. Зоркий глаз заметит сдвоение событий перерисовки: одно собственно для слоя, другое для смены отображения состояния кнопки.
Заметьте, что Chrome’е не всегда перерисовывает слой полностью. Он пытается быть выборочным и перерисовывать только те фрагменты слоя (те самые тайлы отмеченные голубыми границами) в которых DOM подвергся изменению. В нашем случае только один элемент на весь слой, но в большинстве реальных проектов элементов на слой приходится гораздо больше.
Напрашивается следующий вопрос: что приводит к устареванию DOM’а и его перерисовке? Сложно в нескольких предложения охватить все случаи, которые могут привести к невалидности DOM’а. В большинстве случаев это порча DOM’а посредством изменения CSS стилей и динамическая генерация видимого контента в рантайме. Тони Гентилкор описывал их в своём блоге [5], также Стоян Стояноф писал очень детализированную статью [6], но она ограничивается описанием перерисовки без деталей этой новой штуки, о которой мы пытаемся говорить — композиционирование посредством видео подсистемы.
Так как же Chrome’е превращает DOM в изображение на экране? Концептуально можно выделить следующие шаги:
Это то, что происходит при прорисовке первого кадра страницы. Но есть несколько способов сократить накладные расходы на рендеринг каждого следующего кадра:
Как нам должно было стать понятным, основанная на слоях композиционная модель даёт большое преимущество для производительности рендеринга. Композиционирование более недорогой способ рендеринга в сравнение с полной перерисовкой. Поэтому попытка избежать перерисовки слоя, дёргая только композиционные свойства элементов — неплохой способ оптимизации производительности. Здравомыслящие разработчики возьмут на заметку список свойств активирующих композиционирование, что бы в подходящий момент мочь форсировать создание слоёв. Но будьте аккуратны в создание слоёв — это не бесплатно: им нужна системная память и память видео подсистемы (которая ограниченна на мобильных устройствах).
На этом всё!
Автор: lolenko
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/48478
Ссылки в тексте:
[1] страница: http://www.html5rocks.com/en/tutorials/speed/layers/basic.html
[2] Пример 2: http://www.html5rocks.com/en/tutorials/speed/layers/onelayer.html
[3] Пример 3: http://www.html5rocks.com/en/tutorials/speed/layers/animatedlayer.html
[4] Пример 4: http://www.html5rocks.com/en/tutorials/speed/layers/animatedinvalidation.html
[5] блоге: http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html
[6] статью: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
[7] Источник: http://habrahabr.ru/post/202358/
Нажмите здесь для печати.