Но есть ещё одна большая часть технологии Servo, которая пока не вошла в состав Firefox Quantum, но скоро войдёт. Это WebRender, часть проекта Quantum Render.
WebRender известен своей исключительной скоростью. Но главная задача — не ускорить рендеринг, а сделать его более плавным.
При разработке WebRender мы поставили задачу, чтобы все приложения работали на 60 кадрах в секунду (FPS) или лучше, независимо от размера дисплея или от размера анимации. И это сработало. Страницы, которые пыхтят на 15 FPS в Chrome или нынешнем Firefox, летают на 60 FPS при запуске WebRender.
Как WebRender делает это? Он фундаментальным образом меняет принцип работы движка рендеринга, делая его более похожим на движок 3D-игры.
Разберёмся, что это значит. Но сначала…
Что делает рендерер?
В статье по Stylo я объясняла, как браузер переходит от разбора HTML и CSS к пикселям на экране, и как большинство браузеров делают это в пять этапов.
Эти пять этапов можно разделить на две части. Первая из них — это, по сути, составление плана. Для составления плана браузер разбирает HTML и CSS, учитывая информацию вроде размера области просмотра, чтобы точно выяснить, как должен выглядеть каждый элемент — его ширина, высота, цвет и т.д. Конечным результатом становится то, что называется «дерево фреймов» (frame tree) или «дерево визуализации» (render tree).
Во второй части — отрисовке и компоновке — вступает в работу рендерер. Он берёт этот план и превращает его в пиксели на экране.
Но браузеру недостаточно сделать это только один раз. Ему приходится снова и снова повторять операцию для одной и той же веб-страницы. Каждый раз, когда на странице что-то изменяется — например, открывается div по переключателю — браузеру приходится снова многократно проходить через все шаги.
Даже если на странице ничего не меняется — например, вы просто делаете прокрутку или выделяете текст — браузер всё равно должен выполнять операции рендеринга, чтобы нарисовать новые пиксели на экране.
Чтобы скроллинг и анимация были плавными, они должны обновляться на 60 кадрах в секунду.
Вы могли раньше слышать эту фразу — кадры в секунду (FPS) — будучи неуверенными, что она означает. Я представляю их как флипбук. Это как книжка со статичными картинками, которые можно быстро пролистать, так что создаётся иллюзия анимации.
Чтобы анимация в таком флипбуке выглядела плавной, нужно просматривать 60 страничек в секунду.
Странички во флипбуке сделаны из миллиметровки. Там много-много маленьких квадратиков, а каждый квадратик может содержать только один цвет.
Задача рендерера — заполнить квадратики в миллиметровке. Когда все они заполнены, то рендеринг фрейма закончен.
Конечно, в вашем компьютере нет настоящей миллиметровки. Вместо этого в компьютере есть область памяти под названием кадровый буфер. Каждый адрес памяти в кадровом буфере — это как квадратик на миллиметровке… он соответствует пикселю на экране. Браузер заполняет каждую ячейку числами, которые соответствуют значениям RGBA (красный, зелёный, синий и альфа).
Когда экрану нужно обновиться, он обращается к этой области памяти.
Большинство компьютерных дисплеев обновляются 60 раз в секунду. Вот почему браузеры стараются выдавать 60 кадров в секунду. Это значит, что у браузера есть всего 16,67 миллисекунды на всю работу: анализ стилей CSS, вёрстку, отрисовку — и заполнение всех слотов в кадровом буфере числами, которые соответствуют цветам. Этот промежуток времени между двумя фреймами (16,67 мс) называется бюджетом фрейма.
Вы могли слышать, как иногда люди упоминают пропущенные кадры. Пропущенный фрейм — это когда система не укладывается в бюджет. Дисплей пытается получить новый фрейм из кадрового буфера, прежде чем браузер закончил работу по его отображению. В этом случае дисплей снова показывает старую версию фрейма.
Пропущенные фреймы можно сравнить с вырванной страницей из флипбука. Анимация начинает замирать и дёргаться, потому что у вас потерялось промежуточное звено от предыдущей страницы к следующей.
Так что нужно успеть поместить все пиксели в кадровый буфер, прежде чем дисплей снова его проверит. Посмотрим, как браузеры раньше справлялись с этим и как технология изменялась со временем. Тогда мы сможем понять, как ускорить этот процесс.
Краткая история отрисовки и компоновки
Примечание. Отрисовка и компоновка — это та часть, где движки в рендеринга в браузерах сильнее всего отличаются друг от друга. Одноплатформенные браузеры (Edge и Safari) работают немного не так, как мультиплатформенные (Firefox и Chrome).
Даже в самых первых браузерах проводились некоторые оптимизации, чтобы ускорить рендеринг страниц. Например, при прокрутке страницы браузер пытался передвинуть уже отрендеренные части страницы, а затем отрисовать пиксели на освободившемся месте.
Процесс вычисления, что изменилось, а затем обновления только изменившихся элементов или пикселей, называется инвалидацией.
Со временем браузеры начали применять более продвинутые техники инвалидации, вроде инвалидации прямоугольников. Здесь вычисляется минимальный прямоугольник вокруг изменившейся области экрана, а затем обновляются только пиксели внутри этих прямоугольников.
Тут действительно сильно снижается объём вычислений, если на странице меняется лишь небольшое количество элементов… например, только мигающий курсор.
Но это не сильно помогает, если меняются большие части страницы. Для таких случаев пришлось придумать новые техники.
Появление слоёв и компоновки
Использование слоёв сильно помогает при изменении больших частей страницы… по крайней мере, в некоторых случаях.
Слои в браузерах похожи на слои в «Фотошопе» или слои тонкой гладкой бумаги, которую раньше использовали для рисования мультфильмов. В общем, различные элементы страницы вы рисуете на разных слоях. Затем помещаете эти слои друг над другом.
Долгое время в браузерах использовались слои, но они не всегда ускоряли рендеринг. Поначалу их использовали просто чтобы гарантировать правильную отрисовку элементов. Они осуществляли так называемый «позиционный контекст» (stacking context).
Например, если у вас на странице имеется полупрозрачный элемент, то он должен находиться в собственном позиционном контексте. Это значит, что у него есть свой слой, чтобы была возможность смешать его цвет с цветом нижележащего элемента. Эти слои отбрасывались, как только завершался рендеринг фрейма. На следующем кадре слои приходилось рисовать заново.
Но часть элементов на этих слоях не изменяется от кадра к кадру. Например, представьте обычную анимацию. Фон не меняется, даже если двигаются герои на переднем плане. Гораздо эффективнее сохранить слой с фоном и просто повторно использовать его.
Именно так поступили браузеры. Они начали сохранять слои, обновляя только изменившиеся. А в некоторых случаях слои вообще не менялись. Их нужно лишь слегка переместить — например, если анимация перемещается по экрану или в случае прокрутки элемента.
Такой процесс совместной расстановки слоёв называется компоновкой. Компоновщик работает со следующими объектами:
- исходные растровые изображения: фон (включая пустое окно, где должен прокручиваться контент) и сам прокручивающийся контент;
- целевое растровое изображение — то, что демонстрируется на экране.
Сначала компоновщик копирует фон на целевое растровое изображение.
Затем он должен выяснить, какую часть прокручивающегося контента нужно показать. Он скопирует эту часть поверх целевого растрового изображения.
Это снижает объём отрисовки в основном потоке. Но основной поток по-прежнему много времени тратит на компоновку. И есть много процессов, которые борются за ресурсы в основном потоке.
Я приводила такой пример раньше: основной поток похож на full-stack разработчика. Он отвечает за DOM, вёрстку и JavaScript. И он также отвечает за отрисовку и компоновку.
Каждая миллисекунда, потраченная в основном потоке на отрисовку и компоновку — это время, которое отняли у JavaScript или вёрстки.
Но у нас есть другое аппаратное обеспечение, которое сидит здесь и почти ничего не делает. И оно специально создано для графической обработки. Речь идёт о GPU, который игры с 90-х годов используют для быстрой отрисовки кадров. А с тех пор графические процессоры стали больше и мощнее.
Компоновка с аппаратным ускорением
Так что разработчики браузеров начали передавать работу GPU.
Теоретически, графическому ускорителю можно передать две задачи:
- Отрисовка слоёв.
- Компоновка слоёв друг с другом.
Отрисовку бывает сложно передать GPU. Так что обычно мультиплатформенные браузеры оставляют эту задачу на CPU.
Однако GPU может очень быстро выполнять компоновку, и эту задачу легко на него повесить.
Некоторые браузеры ещё больше форсируют параллелизм, добавляя поток компоновщика на CPU. Он становится менеджером всей работы по компоновке, которая выполняется на GPU. Это значит, что если основной поток чем-то занят (например, выполняет JavaScript), о поток компоновщика по-прежнему активен и выполняет работу, видимую для пользователя, типа прокрутки контента.
То есть вся работа по компоновке уходит из основного потока. Впрочем, там по-прежнему остаётся много всего. Каждый раз, когда нужно перерисовать слой, это делает основной поток, а затем передаёт слой в GPU.
Некоторые браузеры переместили и отрисовку в дополнительный поток (сейчас мы в Firefox тоже работаем над этим). Но быстрее будет передать и этот последний кусок вычислений — отрисовку — сразу на GPU.
Отрисовка с аппаратным ускорением
Итак, браузеры начали передавать на графический процессор и отрисовку тоже.
Этот переход всё ещё продолжается. Некоторые браузеры выполняют всю отрисовку на GPU, а в других такое возможно только на определённых платформах (например, только на Windows или только на мобильных устройствах).
Отрисовка на GPU привела к нескольким последствиям. Она позволила CPU уделять всё время задачам вроде JavaScript и вёрстки. К тому же, GPU гораздо быстрее рисуют пиксели, чем CPU, так что ускорился весь процесс отрисовки. Также уменьшилось количество данных, которые нужно передавать с CPU на GPU.
Но поддержание такого разделения между отрисовкой и компоновкой по-прежнему требует определённых расходов, даже если оба процесса выполняются на GPU. Это разделение ещё и ограничивает вас в вариантах оптимизаций для ускорения работы GPU.
Вот где вступает в дело WebRender. Он фундаментальным образом меняет способ рендеринга, нивелируя различие между отрисовкой и компоновкой. Это позволяет подогнать производительность рендерера к требованиям современного веба и подготовить его для ситуаций, которые появятся в будущем.
Другими словами, мы хотели не просто ускорить рендеринг фреймов… мы хотели, чтобы они рендерились более стабильно, без рывков и подтормаживаний. И даже если нужно отрисовать много пикселей, как в шлемах виртуальной реальности WebVR с разрешением 4K, мы по-прежнему хотим плавное воспроизведение.
Почему анимация так тормозит в современных браузерах?
Вышеупомянутые оптимизации помогли в некоторых случаях ускорить рендеринг. Когда на странице изменяется минимум элементов — например, только мигающий курсов — браузер делает минимально возможный объём работы.
После разбивки страниц на слои количество таких «идеальных» сценариев увеличилось. Если вы можете просто нарисовать несколько слоёв, а потом просто двигать их относительно друг друга, то архитектура «отрисовка + компоновка» отлично справляется.
Но у слоёв есть недостатки. Они занимают много памяти, а иногда могут замедлить рендеринг. Браузеры должны сочетать слои там, где это имеет смысл… но сложно определить точно, где это имеет смысл, а где нет.
Значит, если на странице двигается много разных объектов, придётся создавать кучу слоёв. Слои отнимают слишком много памяти, а передача в компоновщик отнимает слишком много времени.
В других случаях получается один слой там, где должно быть несколько. Этот единственный слой будет непрерывно перерисовываться и передаваться в компоновщик, который затем компонует его, ничего не меняя.
То есть усилия по отрисовке удаиваются: каждый пиксель обрабатывается дважды без какой-либо необходимости. Быстрее было бы просто напрямую рендерить страницу, минуя этап компоновки.
Есть много случаев, когда слои просто бесполезны. Например, если у вас анимированный фон, то весь слой всё равно придётся перерисовывать. Эти слои помогают только при небольшом количестве свойств CSS.
Даже если большинство фреймов вписываются в оптимальный сценарий — то есть отнимают только малую часть бюджета фрейма — движение объектов по-прежнему может остаться прерывистым. Чтобы воспринять на глаз рывки и подтормаживания, достаточно потери всего пары кадров, которые вписались в худший сценарий.
Эти сценарии называются обрывами производительности. Приложение работает как будто нормально, пока не столкнётся с одним из этих худших сценариев (вроде анимированного фона) — и фреймрейт внезапно падает до предела.
Но можно избавиться от таких обрывов.
Как это сделать? Последуем примеру игровых 3D-движков.
Использование GPU как игрового движка
Что если мы перестанем гадать, какие слои нам нужны? Что если удалить этот промежуточный этап между отрисовкой и компоновкой и просто вернуться к отрисовке каждого пикселя в каждом фрейме?
Может, это покажется нелепой идеей, но кое-где используется такая система. В современных видеоиграх перерисовывается каждый пиксель, и они держат уровень 60 кадров в секунду надёжнее, чем браузеры. Они делают это необычным способом… вместо создания этих прямоугольников для инвалидации и слоёв, которые минимизируют площадь для перерисовки, просто обновляется весь экран целиком.
Будет ли рендеринг веб-страницы таким способом намного медленнее?
Если мы делаем отрисовку на CPU, то да. Но GPU специально спроектированы для такой работы.
GPU построены с максимальным параллелизмом. Я рассказывала о параллелизме в своей последней статье о Stylo. Благодаря параллельной обработке компьютер выполняет несколько задач одновременно. Количество одновременно выполняемых задач ограничено количеством ядер в процессоре.
В CPU обычно от 2 до 8 ядер, а в GPU как минимум несколько сотен, а часто и больше 1000 ядер.
Впрочем, эти ядра работают немного иначе. Они не могут функционировать полностью независимо, как ядра CPU. Вместо этого они обычно выполняют какую-то совместную задачу, запуская одну инструкцию на разных фрагментах данных.
Это именно то, что нам нужно при заполнении пикселей. Все пиксели можно раздать разным ядрам. Поскольку GPU работает с сотнями пикселей одновременно, то заполнение пикселей он выполняет значительно быстрее, чем CPU… но только если все ядра загружены работой.
Поскольку ядра должны работать над одной задачей одновременно, у GPU довольно ограниченный набор шагов для выполнения, а их программные интерфейсы сильно ограничены. Посмотрим, как это работает.
Первым делом нужно указать GPU, что именно отрисовать. Это значит передать им формы объектов и инструкции по их заполнению.
Для этого следует разбить весь рисунок на простые формы (обычно треугольники). Эти формы находятся в 3D-пространстве, так что некоторые из них могут заслонять другие. Затем вы берёте вершины всех треугольников — и вносите в массив их координаты x, y, z.
Затем отправляете команду GPU на отрисовку этих форм (draw call).
С этого момента GPU начинает работать. Все ядра будут выполнять одну задачу одновременно. Они сделают следующее:
- Определят углы всех фигур. Это называется закрашиванием вершин (vertex shading).
- Установят линии, которые соединяют вершины. Теперь можно определить, какие пиксели включает в себя фигуры. Это называется растеризацией.
- Когда мы знаем, какие пиксели принадлежат каждой фигуре, можно пройтись по каждому пикселю и присвоить ему цвет. Это называется закрашиванием пикселей (pixel shading).
Последний шаг выполняется по-разному. Чтобы выдать конкретные инструкции, с GPU работает специальная программа, которая называется «пиксельный шейдер». Закрашивание пикселей — один из немногих элементов функциональности GPU, который вы можете программировать.
Некоторые пиксельные шейдеры очень простые. Например, если вся фигура закрашена одним цветом, то шейдер должен просто назначить этот цвет каждому пикселю фигуры.
Но бывают более сложные шейдеры, например, в фоновом изображении. Здесь придётся выяснить, какие части изображения соответствуют какому пикселю. Это можно сделать тем же способом, как художник масштабирует изображение, увеличивая или уменьшая его… поместите поверх картинки сетку с квадратиками для каждого пикселя. Затем возьмите образцы цветов внутри каждого квадратика — и определите итоговый цвет пикселя. Это называется наложением текстуры (texture mapping), поскольку здесь изображение (оно называется текстурой) накладывается на пиксели.
GPU будет обращаться к пиксельному шейдеру по поводу каждого пикселя. Разные ядра параллельно работают над разными пикселями, но всем им нужен один и тот же пиксельный шейдер. Когда вы инструктируете GPU отрисовать формы объектов, вы одновременно указываете, какой использовать пиксельный шейдер.
Почти для всех веб-страниц разным частям страницы требуются разные пиксельные шейдеры.
Поскольку шейдер работает для всех пикселей, указанных в команде на отрисовку, обычно нужно разбивать эти команды на несколько групп. Они называются пакетами. Чтобы максимально загрузить все ядра, нужно создать небольшое количество пакетов с большим количеством фигур в каждом из них.
Вот так GPU распределяет работу по сотням или тысячам ядер. Всё из-за исключительного параллелизма при рендеринге каждого фрейма. Но даже с таким исключительным параллелизмом по-прежнему остаётся много работы. К постановке задач нужно подходить с умом, чтобы добиться достойной производительности. Вот здесь вступает в дело WebRender…
Как WebRender работает с GPU
Давайте вспомним, какие шаги предпринимает браузер для рендеринга страницы. Здесь произошло два изменения.
- Больше нет разделения между отрисовкой и компоновкой… оба процесса выполняются на одном этапе. GPU делает их одновременно, руководствуясь полученными командами от графического API.
- Вёрстка теперь даёт нам для рендеринга другую структуру данных. Раньше это было нечто под названием дерева фреймов (или дерево визуализации в Chrome). А теперь она передаёт список отображения (display list).
Список отображения — это набор высокоуровневых инструкций отрисовки. Он указывает, что нужно отрисовать, не используя специфические инструкций для конкретного графического API.
Как только нужно отрисовать что-то новое, основной поток передаёт список отображения в RenderBackend — это код WebRender, работающий на CPU.
Задача RenderBackend — взять список высокоуровневых инструкций отрисовки и преобразовать его в команды для GPU, которые объединяются в пакеты для более быстрого выполнения.
Затем RenderBackend передаёт эти пакеты в поток компоновщика, которые передаёт их далее в GPU.
RenderBackend хочет, чтобы команды на отрисовку выполнялись на GPU с максимальной скоростью. Для этого применяется несколько разных техник.
Удаление лишних фигур из списка (ранняя выбраковка)
Лучший способ сэкономить время — вообще не работать.
Первым делом RenderBackend сокращает список отображения. Он определяет, какие элементы списка реально будут отображаться на экране. Для этого он смотрит, насколько далеко от окна в списке прокрутки находится элемент.
Если фигура попадает в пределы окна, её включают в список отображения. А если ни одна часть фигуры не попадает сюда, то её исключают из списка. Этот процесс называется ранней выбраковкой (early culling).
Минимизация количества промежуточных структур (дерево задач для рендеринга)
Теперь наше дерево содержит только нужные формы. Это дерево организовано в позиционных контекстах, о которых мы говорили ранее.
Эффекты вроде фильтров CSS и позиционные контексты несколько усложняют дело. Например, у вас есть элемент с прозрачностью 0,5, а у него есть дочерний элемент. Вы можете подумать, что все дочерние элементы тоже прозрачные… но в реальности прозрачна вся группа.
Из-за этого нужно сначала вывести группу на текстуру, с полной прозрачностью каждого квадрата. Затем, помещая её в родительский объект, можно изменить прозрачность всей текстуры.
Позиционные контексты могут быть вложены друг в друга… а родительский объект может принадлежать другому позиционному контексту. То есть его нужно будет отрисовать на ещё одной промежуточной текстуре, и так далее.
Выделение пространства для этих текстур дорого обходится. Мы хотели бы максимально вместить все объекты на одной и той же промежуточной структуре.
Чтобы помочь GPU справиться с задачей, создаём дерево задач для рендеринга. В нём указано, какие текстуры нужно создать раньше других текстур. Любые текстуры, независимые от других, могут быть созданы в первом проходе, то есть их можно потом объединить на одной промежуточной текстуре.
Так что в вышеупомянутом примере с полупрозрачными квадратами мы первым проходом раскрасили бы один угол квадрата. (На самом деле всё немного сложнее, но суть в этом).
Вторым проходом можем продублировать этот угол для всего квадрата и закрасить его. Затем выполнить рендеринг группы непрозрачных квадратов.
Наконец, осталось только изменить прозрачность текстуры и поместить её в соответствующее место итоговой текстуры, которая будет выведена на экран.
Построив дерево задач для рендеринга, мы выясняем минимальное возможное количество объектов рендеринга до вывода на экран. Это хорошо, ведь я упоминала, что выделение пространства для этих текстур дорого обходится.
Дерево задач также помогает объединять задачи в пакеты.
Группировка команд на отрисовку (пакетная обработка)
Как мы уже говорили, нужно создать небольшое количество пакетов с большим количеством фигур в каждом из них.
Тщательное формирование пакетов позволяет сильно ускорить рендеринг. Нужно втиснуть в пакет как можно больше объектов. Такое требование выдвигается по нескольким причинам.
Во-первых, когда бы CPU не отдавал GPU команду на отрисовку, у CPU всегда есть много других задач. Ему нужно заботиться о таких вещах, как настройка GPU, загрузка программы шейдера и проверка на разные аппаратные баги. Вся эта работа скапливается, и пока CPU её делает, GPU может простаивать.
Во-вторых, есть определённые расходы на изменение состояния. Скажем, между пакетами вам нужно изменить состояние шейдера. На обычном GPU придётся ждать, пока все ядра не закончат выполнение задания от текущего шейдера. Это называется очисткой конвейера (draining the pipeline). Пока конвейер не очищен, остальные ядра будут переведены в режим ожидания.
Из-за этого желательно набивать пакет как можно плотнее. Для обычного настольного ПК желательно оставить менее 100 команд отрисовки для каждого фрейма, а в каждую команду хорошо бы запихнуть тысячи вершин. Так выжимается максимум из параллелизма.
Смотрим на каждый проход в дереве задач для рендеринга и на то, какие из задач сгруппировать в один пакет.
В данное время каждому типу примитивов требуется разный шейдер. Например, есть шейдер границ, текстовый шейдер и шейдер изображений.
Мы считаем, можно объединить многие из этих шейдеров, что позволит создавать ещё бoльшие пакеты, хотя они и сейчас неплохо сгруппированы.
Задачи практически готовы для отправки в GPU. Но есть ещё немножко работы, от которой можно избавиться.
Уменьшение работы по закрашиванию пикселей с помощью проходов по непрозрачности и альфа-каналу (Z-выбраковка)
Большинство веб-страниц содержит много фигур, перекрывающих друг друга. Например, текстовое поле находится поверх div (с фоном), которое находится поверх body (с другим фоном).
При определении цвета пикселя GPU мог бы вычислить цвет пикселя в каждой фигуре. Но показан будет только верхний слой. Это называется перекрашивание (overdraw), пустая трата времени GPU.
Так что можно сначала рендерить верхний слой. Когда придёт очередь рендерить пиксель для следующей фигуры, мы проверяем, есть ли уже значение у этого пикселя. Если есть, то лишняя работа не выполняется.
Правда, тут небольшая проблемка. Если фигура полупрозрачная, то нужно смешать цвета двух фигур. И чтобы всё выглядело правильно, рендеринг следует проводить снизу вверх.
Так что мы разделяем работу на два прохода. Сначала проход по непрозрачности. Рендерим сверху вниз все непрозрачные фигуры. Пропускаем рендеринг всех пикселей, которые закрыты другими.
Затем приступаем к полупрозрачным фигурам. Они отрисовываются снизу вверх. Если полупрозрачный пиксель находится поверх непрозрачного, то их цвета смешиваются. Если он находится позади непрозрачного, то не рассчитывается.
Разделение на два прохода — по непрозрачности и альфа-каналу — с дальнейшим пропуском вычислений ненужных пикселей называется Z-выбраковкой (Z-culling).
Хотя это может показаться простой оптимизацией, здесь мы получаем большую выгоду. На типичной веб-странице значительно сокращается количество пикселей для обработки. Сейчас мы ищем способы переместить ещё больше задач в проход по непрозрачности.
В данный момент мы подготовили кадр. Мы сделали всё возможное, чтобы удалить лишнюю работу.
…И мы готовы к отрисовке!
Графический процессор готов к настройке и рендерингу пакетов.
Оговорка: у нас пока не всё ушло на GPU
CPU по-прежнему выполняет часть работы по отрисовке. Например, мы по-прежнему рендерим на CPU символы (они называются глифами) в текстовых блоках. Существует возможность делать это на GPU, но трудно добиться попиксельного соответствия с глифами, которые компьютер рендерит в других приложениях. Так что люди могут запутаться при рендеринге шрифтов на GPU. Мы экспериментируем с перемещением рендеринга глифов на GPU в рамках проекта Pathfinder.
Но сейчас эти вещи отрисовываются в растровые изображения на CPU. Затем они загружаются в текстурный кэш на GPU. Этот кэш сохраняется от фрейма к фрейму, потому что обычно в нём не происходит изменений.
Даже хотя такая отрисовка остаётся на CPU, всё равно есть потенциал для её ускорения. Например, при отрисовке символов шрифта мы распределяем различные символы по всем ядрам. Это делается с помощью такой же техники, которую использует Stylo для распараллеливания вычисления стилей… перехват работы.
Будущее WebRender
В 2018 году мы планируем внедрить WebRender в Firefox в составе Quantum Render, через несколько релизов после первоначального выпуска Firefox Quantum. После этого существующие веб-страницы станут работать плавнее. А браузер Firefox будет готов к новому поколению дисплеев высокого разрешения 4K, поскольку производительность рендеринга крайне важна при увеличении количества пикселей на экране.
Но WebRender полезен не только для Firefox. Он также необходим в нашей работе над WebVR, где нужно рендерить разные фреймы для каждого глаза со скоростью 90 FPS на разрешении 4K.
Первая версия WebRender уже доступна в Firefox, если вручную активировать соответствующий флаг. Работ по интеграции продолжается, так что производительность пока не настолько высока, как будет в финальном релизе. Если хотите наблюдать за разработкой WebRender, следите за репозиторием GitHub или за твиттером Firefox Nightly, где еженедельно публикуются новости по всему проекту Quantum Render.
Об авторе: Лин Кларк — инженер группы Mozilla Developer Relations. Она работает с JavaScript, WebAssembly, Rust и Servo и любит рисовать программисткие картинки.
Комментарии (74)
x512
16.10.2017 12:41overdraw — это не банковский термин (превышение лимита), а композиция двух слов over и draw, т.е перекрашивание
baldrs
16.10.2017 13:30Разве перекрашивание будет не repaint?
impwx
16.10.2017 14:00Repaint — это когда состояние объекта изменилось и его нужно заново отрисовать.
Overdraw — это когда пиксели приходится закрашивать повторно, потому что один объект перекрывает другой.
sibirier
16.10.2017 14:19слово «перекрашивание» может быть в двух значениях. одно «перекрашивание» — это красить слишком много (overdraw), а второе «перекрашивание» — это нарисовать заново (repaint)
masai
16.10.2017 15:31«перекрашивание» — это красить слишком много (overdraw)
К сожалению, в словарях это значения слова "перекрасить" не встречается, что и вводит читателей в заблуждение. Мне кажется лучше перевести "overdraw" как "избыточная отрисовка". (Впрочем, слово "отрисовка" тоже мне не очень нравится.)
mmacloud
16.10.2017 13:21а как включить?
splav_asv
16.10.2017 13:44+1- gfx.webrender.enabled = true
- gfx.webrendest.enabled = true
- gfx.webrender.layers-free = true
- gfx.webrender.blob-images = true
- если Linux, layers.acceleration.force-enabled = true
Обновления пишут в блоге mozillagfx.wordpress.com.
cleaner_it
16.10.2017 13:58Толково расписано. Было интересно почитать — что там внутри, и с какими сложностями сталкиваются. Внутренности — это всегда интересно)
DrZlodberg
16.10.2017 14:03Интересно, на сколько сильнее он теперь батарею жрать будет (при исп GPU бук начинает греться как ненормальный и сажать батарею на глазах). И насколько отжирать память GPU при использовании WebGL например.
lain8dono
16.10.2017 18:26+1В вашем ноутбуке два GPU. Совершенно не обязательно использовать «дискретный» GPU ради отрисовки 2d графики. Если всё окно занято WebGL-контекстом, то жрать память GPU не будет. Особо учитывая, что оная вообще не будет использоваться, но будет использоваться оперативка. Я могу быть немного не прав, но судя по всему в целом оно примерно так работает.
DrZlodberg
17.10.2017 08:26Я даже сначала обрадовался. Но нет, по прежнему одно встроенное. Дискретки стоят далеко не везде. И кстати да, я забыл, что жрать оно обычную оперативку будет на буке, т.к. там выделенной памяти для ускорителя нет.
Всё окно никогда (практически никогда) не бывает занято. Всегда что-то отрисовывается помимо GL, а часто и поверх него. Так что будет, никуда не денется.
Интересно, за что минусов так накидали?
lain8dono
16.10.2017 22:58Где-то тут говорится, что IGP скорее всего не будет ждать память GPU просто уже по той причине, что питается самой обычной RAM. Однако, что характерно, памяти должно выжираться меньше с WebRender. Или по крайней мере столько же. Ибо на слои память таки требуется. Но я не измерял.
Это говорит, что WebGL будет проще и быстрее. В относительно большой перспективе. Ещё там графики производительности в попугаях есть.
Интересно, на сколько
А на самом деле измерьте. На сколько попугаев стало лучше/хуже.
DrZlodberg
17.10.2017 08:35Питаться обычной RAM оно не может, т.к. GPU текстуры в RAM хранить не может. Для рендера они должны быть в его памяти, а гонять их каждый кадр накладно. А тем более выделять и освобождать её каждый кадр. Ну и само утверждение, что память GPU не используется и на CPU меньше — уже странно, т.к. где-то текстуры храниться должны.
Проще и быстрее — с этим никто не спорит. Вопрос конкретно в энергопотреблении. Кстати, что будет если GPU ему недоступен? Переключится на старый рендер или вообще не будет работать? WebGL периодически отваливается до перезапуска фоксы, а под линухом в какой-то момент вообще отвалился. Спец для шейдертоя приходилось оперу гонять пока он и там не отвалился почему-то :(
mayorovp
17.10.2017 09:07Встроенный GPU (почти) никакой "своей" памяти не имеет — он хранит все текстуры в ОЗУ. Если вы под виндой сидите, посмотрите в параметры графического адаптера — там должна быть картинка вроде вот такой:
Goury
17.10.2017 19:43А что мешает GPU хранить текстуры в RAM?
Даже в не его выделенной RAM ничего не мешает, через PCIe оно прекрасно адресуется и пропускной способности более чем достаточно для рендера вебни.DrZlodberg
17.10.2017 20:08Если честно, я не очень силён в данном вопросе. Не знаю как Vulcan, но OpenGl вроде не позволяет указывать, где их хранить. Через директ фокса вряд-ли работает. Решать это может только драйвер. С точки зрения производительности хранить их во внутренней памяти гораздо эффективнее. Она не только ближе, но и быстрее. Так что вряд-ли в обычной.
Goury
17.10.2017 21:11Да всё просто: по дефолту хранятся в выделенной памяти, когда выделенная заканчивается — хранятся в общей.
Нормально получается.DrZlodberg
17.10.2017 21:15когда выделенная заканчивается
Это как раз и есть ответ на один из изначальных вопросов :)
Но вообще это сильно зависит от конкретного драйвера.
kovserg
16.10.2017 17:18Рисоваться будет быстро, а загружаться будет еще дольше чем сейчас?
Halt
17.10.2017 06:26Нет. Посмотрите видео. Например, вот это:
Dee3
16.10.2017 17:37А у Edge сколько FPS? У него реализован офигительно приятный и плавный скроллинг. Перепробовал кучу плагинов, но не удалось такого достичь в Chrome.
В целом когда работать действительно приятнее, когда у интерфейса нет лаговHalt
17.10.2017 06:20Edge так же как и Safari — платформозависимые броузеры, которые договорились с ОС. Хром и Лиса вынуждены играть по общим правилам.
EviGL
16.10.2017 17:53Забавно как вначале "вы, наверное, не понимаете, что такое FPS" а потом дикий хардкор с подробностями отрисовки начинается :) Тот, кто правда не знал, что такое FPS, поседел бы.
mefikru
16.10.2017 18:43Попробовал я включить stylo ещё с первой статейки, месяц назад, или где-то так. Так вот оно после загрузки страницы жуть как тормозит, на секунду замирает всё. Это раздажало. Выключил. Других изменений не заметил.
splav_asv
16.10.2017 21:57В бете текущей со Quantum CSS (aka Stylo) ао умолчанию никаких подтормаживаний нет. Может допилили привязку, может что-то еще.
Alexey2005
16.10.2017 20:48Да дело не в движке рендеринга. А в том, что разработчики всё никак не могут отвязать UI от парсинга страниц и выполнения JS.
Это совершенно не дело, когда на восьмиядерном процессоре в момент загрузки странички подлагивает переключение вкладок (переключаются не в момент нажатия, а через 0.3-0.5 сек примерно) или скроллинг в соседней вкладке.splav_asv
16.10.2017 21:58Опять же в текущей бете (Firefox Quantum) стало с этим намного лучше. Прямо в разы.
firk
16.10.2017 23:34У меня бывает и через 5 сек, причём оно не виснет а как будто ставит уже принятый клик по вкладке в какую-то очередь.
ExplosiveZ
17.10.2017 11:38Firefox 56, где-то с 54 версии вкладка не тормозит весь браузер.
Если вкладка тормозит, то так же тормозят кнопки расширений, но ничего больше не тормозит и не зависает. С нетерпением жду firefox 57, жаль, что некоторые расширения отвалятся.(cookiemanager+ и downthemall)sumanai
17.10.2017 16:03жаль, что некоторые расширения отвалятся.(cookiemanager+ и downthemall)
Вам везёт, что так мало. У меня больше 30 штук имеют пометку «Устарело», и большая часть из них обновляться принципиально не будет.ExplosiveZ
18.10.2017 07:04У 6 расширений пометка Legacy, примерно половина перейдет на WebExtenstions вместе с релизом ff 57. Там им чего-то не хватает.
grey_rat
16.10.2017 23:08Сижу интереса ради на альфе 58.
Конфиг компа:
Конфиг компаnForce4, процессор 2 ядра 939 сокет, DDR400 в два канала, 4гиг оперативки (1*4 планки), видеокарта GTX260 (DirectX10), 64 бит Win7 и браузер.
Лиса работает очень быстро и плавно даже без веб-рендера. Но при условии, что включено Direct2D.
Так в about:support пишет следующее:
Многопроцессные окна 2/2 (Включены по умолчанию)
Stylo</b> true (включено по умолчанию)
Композитинг Direct3D 11 (Advanced Layers)
Асинхронное панорамирование/зум включён ввод колесиком; включён драг полосы прокрутки; клавиатура включена; автопрокрутка включена
WebGL 1 — Визуализатор драйвера Google Inc. — ANGLE (NVIDIA GeForce GTX 260 Direct3D11 vs_4_0 ps_4_0)
Direct2D true
Прорисовка вне основного потока активирована true
DirectWrite</i> true (6.2.9200.16492)
AzureCanvasBackend Direct2D 1.1
AzureContentBackend Direct2D 1.1
ADVANCED_LAYERS available by user: Enabled for Windows 7 via user-preference
+ Аппаратное ускорение видео H.264 (этот пункт почему-то пропал из about:support)
и не работающее
WEBRENDER opt-in by default: WebRender is an opt-in feature
NO_CONSTANT_BUFFER_OFFSETTING Unsupported by driver
Видеокартой обробатывается практически всё что можно. Ну разве что WebGL отвалился и на http://www.ro.me/ показывает зелёный экран.
Не совсем понятно, какие минимальные системные требования будут нужны для работы веб-рендера?
Так например, много графических адаптеров с поддержкой DirectX9, но и в них есть отличия, с поддержкой шейдеров 2 и 3 версий. Видеокарта с поддержкой только DirectX 10 в Firefox работает как с DirectX11 и т.д.splav_asv
17.10.2017 00:11webrender использует opengl es 3.0. На Windows работать будет через ANGLE. ANGLE умеет ES 3.0 поверх Direct3D 11. С 9 не получится. Соответственно под Windows минимальные требования — DX11.
kivsiak
17.10.2017 09:18Ну я конечно понимаю что ночной билд, но пока я такую цену платить не хочу:
nidalee
17.10.2017 09:33А я — такую (картинка из гугла, но мысль ясна)
walkman7
17.10.2017 11:54Для большинства расширений это не проблема, так как их версии для Chromium-подобных 99% совместими с последними версиями Firefox.
nidalee
17.10.2017 11:57Возможно. Но я пока не вижу причин начинать переход на новую версию и искать замену установленным у меня дополнениям (потому что большая часть из них до сих пор legacy). Прирост скорости на данный момент незначителен.
sumanai
17.10.2017 16:05+1Суть в том, что версий многих ФФшных дополнений для хрома просто нет, и быть не может из-за ограничений API.
AVX
17.10.2017 10:01Интересные технологии… Но что касаемо рендера текста, который (как я понял) переводится в текстуру, типа, не меняется и не анимируется при просмотре страницы, у меня родился вопрос: А как поведёт себя браузер на смартфоне, когда включен автоповорот, и размеры экрана стали другими, ширина объектов с текстом изменилась, текст весь сдвигается и т.д.?
Ведь если он (текст) был в виде текстуры, то при повороте нужно будет их все пересоздавать заново, а это заметные тормоза (особенно на мобильных устройствах). Они и сейчас почти на всех устройствах заметны при повороте, а не будет ли ещё хуже?domix32
17.10.2017 11:12В мобильные версии оно вроде не скоро попадет ибо пока не сильно ясно что там с энергопотреблением.
Vayshya
17.10.2017 20:21У меня телефон двое суток под максимальной нагрузкой работает, мне кажется это устаревшая проблема значительного количества телефонов, надо нормальные телефоны покупать.
domix32
17.10.2017 22:25Ну, вот как-то так для 90% людей с ненормальными телефонами браузер и пилится.
А вообще возможно там есть какие-то траблы с портированием кода/наличием драйверов под устройства/свой вариант.
xjesus666christx
17.10.2017 11:54Хорошая статья, для домохозяек. Особенно понравилось про использование GPU как игрового движка.
Firestalk
17.10.2017 20:21Вот бы еще подвисать перестал, а то периодически его даже прибить не получается.
ganzmavag
17.10.2017 20:21Как-то так сложилось, что я не фанат Firefox (из лагеря Opera), но очень радуют такие новости про оптимизацию движка, который не Blink! Все-таки необходима в этой сфере конкуренция, да простят меня фронтенд-разработчики.
krab90
17.10.2017 20:21Вы только взгляните на рендеринг шрифта i.imgur.com/CjVYrwS.png
splav_asv
17.10.2017 21:31Ну, как бы, разработка еще не завершена. Он сейчас в Firefox в статусе alpha.
Beholder
18.10.2017 11:52Данный скриншот, вероятно, сделан на ноутбуке, на котором матрица BGR, поэтому с мониторов RGB он сразу выглядит плохо. Но вообще да, рендеринг шрифтов в Firefox удручает. Для предотвращения замыливания можно отключить «аппаратное ускорение» и рендерер Skia.
phponelove
17.10.2017 20:21При разработке WebRender мы поставили задачу, чтобы все приложения работали на 60 кадрах в секунду (FPS) или лучше, независимо от размера дисплея или от размера анимации. И это сработало. Страницы, которые пыхтят на 15 FPS в Chrome или нынешнем Firefox, летают на 60 FPS при запуске WebRender.
Это же явный подлог. Начиная с того, что какой-то отдельный бенчмарк — это явно не «все приложения».
В остальном. Мой chromium выдаёт так же 60фпс и я не знаю откуда взялись эти 15. Это явное враньё. Далее, я скачал это серво и запустил. Получил 60фпс(поверим, что это реальные), при этом я так же получил
1) артефакты, которые(на первый взгляд) так же видны на видео, которое ОЧЕНЬ хренового качества, почему? Совпадение?
2) нагрузка на цпу идентична хромиуму, а вот нагрузка на гпу выше.
3) У серво мало того, что артефакты, так ещё и визуальное качество рендеринга явно хуже.
4) Добавление банального box-shadow ломает полностью серво и все эти 60фпс пропадают.
5) Да что там box-shadow — даже банальное opacity уже не даёт 60фпс, а в хромиуме ничего не меняется и те же 60фпс.
6) графики в --debug wr-stats — врут. Я добавил банальный подсчёт максимального времени кадра на базе разницы между вызовами raf и что серво, что хромиум просаживаются до 30мс( в моём случае). Чего в графиках, конечно же, нет.
В конечном итоге, что мы имеем? Да ничего мы не имеем.splav_asv
17.10.2017 21:444,5) Есть известные баги на эту тему в webrender.
6) wr-stats учитывает только время отрисовки кадра(ибо это рендер, он про внешние запросы ничего не знает). Накладные расходы на обвязку и js сюда не входят, естественно. С точки зрения пользователя вы правы. Но сам процесс отрисовки в webrender во многих случаях значительно быстрее, чем без него, что открывает возможности для дальнейших оптимизаций.
В общем, вы пессимистично настроены. Вероятно вы во многом правы, но технология еще сырая и после сглаживания всех шероховатостей может привести к значительному росту производительности браузера в целом.phponelove
18.10.2017 13:004,5) Есть известные баги на эту тему в webrender.
Ну какие же это баги. 90% недоработка является багом? Голословные утверждения являются багом? Это лишь то, что я за пару минут проверил. То, что мне первое пришло в голову. И это самое простое.
6) wr-stats учитывает только время отрисовки кадра(ибо это рендер, он про внешние запросы ничего не знает).
Это не накладные расходы. raf вызывается перед рендерингом кадра и если он вызывается через х2 после предыдущего — это явная просадка.
Но сам процесс отрисовки в webrender во многих случаях значительно быстрее, чем без него, что открывает возможности для дальнейших оптимизаций.
Это манипуляции. Там написано не «он кое как работает и быстрее нашего дефолтного, тормазного, рендеринга в firefox», а «в хроме 15фпс, у нас 60фпс — самый быстрый».
Если вы претендуете на оптимизацию аутсайдера, то это не дает вас быстрым. Если вы претендуете на «быстро» — сравнивайте с быстрыми. А именно с хромом.
А так это маркетинговый булшит уровня «самый шоколадный* *из всех наших продуктов» и что он делает тут — не ясно.
По поводу случаев. Их пока нет, либо по крайней мере я их не видел. Я вижу только подтасовку и пустые заявления.
В общем, вы пессимистично настроены. Вероятно вы во многом правы, но технология еще сырая и после сглаживания всех шероховатостей может привести к значительному росту производительности браузера в целом.
Понимаете в чём штука. Зачем заниматься подобными манипуляциями, если у нас что-то действительно есть? Зачем всё это про «самый быстрый/быстрый» и прочее? Почему не «возможно потом что-то да будет». Я не вижу этого — я вижу заявления, которые не соответствуют действительно.
Мне не нравится когда меня обманывают и считают за идиота. Я таким проектам не верю, таким людям не верю. И это правильно. И это не первое проявление.
Я могу рассказать краткую историю этого «движка». Вначале была параллельность. Мы придумали новый язык, который на это заточен и это должен был быть супер-параллельный движок. Потом как-то всё заглохло и вся параллельность превратилось в заспавн тысяч тредов и зависание через пару минут работы. Между тем в хромиуме есть многопоточный рендеринг и что-то я не вижу подобной желтухи и громких заявлений. И он есть и он работает.
Сейчас я вижу новую историю. Производительность с цпу мы не получили — теперь у нас новая идея — получить её с гпу. При этом казалось бы — причём тут раст, но вот так вот. И все эти рассуждения про «принципиально новое» — действительно. Верю. В гугле работают идиоты и до таких «инновационных» решений не доросли. При этом ладно, раньше было объяснение про «на расте проще писать многопоточные программы — поэтому мы даём фору хрому», но сейчас это не работает.
И естественно с «гпу» у нас работает 2-3% css, но мы уже всех побеждаем. Мы специально подбиваем под нас бенчмарки( которые на самом деле не бенчмарки, а фейк). Это не баги. Это подтасовка. Почему автор бенчмарка не написал там opacity? Знал что оно показывает 30фпс? Почему в видео специально зарезано качество? Чтобы люди не видели артефактов и качества рендера? Почему в видео содержится деза про 15фпс? В надежде что читатель не проверит?
И разве где-то в тексте это написано? Нет, это умалчивается. Опять же — мне не нравиться то, когда меня считают за идиота. Т.е. вам это нравиться и вы согласны с тем, что те, кто играют в подобные игры вам дадут хороший продукт?
Да и с технической части статья желтушная на 95%. Как будет у меня время я разберу её поподробнее. Возможно, кого-то это спасёт от слепой веры.
В любом случае. Тут плохо даже не всё это — тут плохо то, что подобное вгоняет комьюнити данного языка в средневековье. У нас везде победы, всё это враньё и желтуха затмевает нам разум. Всё это развивается в в сторону полного неадеквата семимильными шагами. И это плохо.
Примеры не заставляют себе долго ждать. Мои полностью объективные замечания минусуют. Хотя казалось бы — там нет ничего с чем можно соглашаться, либо не соглашаться. Там факты из реального мира. Отрицание этого — отрицание реальности. Именно в этом проблема.splav_asv
18.10.2017 13:5590% недоработка является багом?
«гпу» у нас работает 2-3% css
Объективные цифры с потолка? Есть какие-то более предметные оценки, ссылки, аргументация?
raf вызывается перед рендерингом кадра и если он вызывается через х2 после предыдущего — это явная просадка.
Просадка в FPS анимации, но не обязательно проблема в рендере. Рендер может быть за 1 мс всё отрисовал, а еще 29 пришлось на другие участки кода между вызовами. Точных цифр не знаю, но до 50% вне рендера допускаю.
Это манипуляции. Там написано не «он кое как работает и быстрее нашего дефолтного, тормазного, рендеринга в firefox», а «в хроме 15фпс, у нас 60фпс — самый быстрый».
Да, в тех условиях самый быстрый. Или вы с этим тоже спорите? Это признак гордости, демонстрация потенциала. Не нравится формулировка — ваше право. Мне тоже не совсем нравится.
Я могу рассказать краткую историю этого «движка». Вначале была параллельность. Мы придумали новый язык, который на это заточен и это должен был быть супер-параллельный движок. Потом как-то всё заглохло и вся параллельность превратилось в заспавн тысяч тредов и зависание через пару минут работы.
Движок собственно Servo очень даже параллельный. И более менее допиленные части весьма быстры. Откуда информация про тысячи нитей, пару минут работы, что всё заглохло?
Почему автор бенчмарка не написал там opacity? Знал что оно показывает 30фпс?
Если бы вы знали историю WebRender, то знали бы, что этот бенчмарк довольно старый, простой и создан специально для проверки потенциала нового движка. Когда еще WebRender был на уровне «прототип для проверки концепции». С тех пор многое изменилось. Но бенчмарк остался показательным.
Сейчас я вижу новую историю. Производительность с цпу мы не получили — теперь у нас новая идея — получить её с гпу. При этом казалось бы — причём тут раст, но вот так вот. И все эти рассуждения про «принципиально новое» — действительно. Верю. В гугле работают идиоты и до таких «инновационных» решений не доросли. При этом ладно, раньше было объяснение про «на расте проще писать многопоточные программы — поэтому мы даём фору хрому», но сейчас это не работает.
Производительность тех частей, что остались на CPU получили. Stylo тому пример. На Rust кстати, да. Рендер было решено попробовать вынести с CPU на GPU, поскольку многие сценарии a) CPU-bound b) GPU делает многие вещи в рамках рендера быстрее. (Кстати пилится прототип растеризатора шрифтов на GPU).
При чём тут Rust — данные для GPU надо еще подготовить, очевидно же. И желательно параллельно в несколько потоков.
Да и с технической части статья желтушная на 95%.
Она не желтушная, она рекламно-айтишно-популярная. Ключавые особенности простыми словами. Упрощённо. Сознательно упрощённо. Если нужны технические статьи — есть технические блоги.
В любом случае. Тут плохо даже не всё это — тут плохо то, что подобное вгоняет комьюнити данного языка в средневековье. У нас везде победы, всё это враньё и желтуха затмевает нам разум. Всё это развивается в в сторону полного неадеквата семимильными шагами. И это плохо.
Победы есть, есть неудачи. Просто про них меньше пишут, но пишут. Всё враньё — так уж и всё? Что именно вы считаете полным неадекватом?
Мои полностью объективные замечания минусуют.
Не смотря на во многом верность ваших замечаний, факты тоже верны, но вот их интерпретация очень безапелляционная(помните, «полностью объективные»), слегка однобокая (и из-за этого недостаточно аргументированая). Не соглашаются именно с подачей и интерпретацией, как мне кажется.
P.S. я ни плюсов ни минисов ставить не могу по объективным техническим причинам, так что минисовал не я.
P.P.S. видите дату 3 мар. 2016 на видео демо? Это просто демонстрация возможностей раннего прототипа, а не коммерческие материалы. И Хром там той давности. Там и было 15 fps.
boriselec
17.10.2017 20:22Круто, конечно.
Но не стоит всех отломанных расширений. Буду сидеть на постепенно разваливающемся 54, что дальше — не знаю.
kashey
18.10.2017 09:54Эх, все зло и тормоза от Альфы. Каких только технологий не придумали чтобы сделать жизнь чуть чуть лучше, но до победы далеко.
А самое главное, что любая полупрозрачность (текст) требует активного режима смешивания который просто сразу в два раза все просаживает.
В свое время пытался рендерить различные сущьности в отдельные текстуры, чтобы потом в шейдере сразу все склеить. TMU сейчас ой как много.
От сюда и вопрос — а как ФФ склеивает слои? glBlend не предлагать.splav_asv
18.10.2017 10:08
sshmakov
На хабре есть перевод "Внутри супер-быстрого CSS-движка: Quantum CSS (aka Stylo)" azymohliad