В последние годы спрос на 2D/3D-инструменты в веб-сервисах растет довольно стремительно, технологии развиваются, появляются новые подходы и библиотеки — а вместе с ними растёт и путаница: что где использовать, где грань между похожими решениями и почему у разработчиков часто возникают противоположные мнения?
Так что я решила устроить небольшой тест 2D-решений: посмотреть, на что они реально способны, понять, почему результаты местами вызывают большое удивление, и ответить себе (и вам) на вопрос: а WebGPU вообще зачем?
Спойлер: всё далеко не так очевидно, как кажется.

Привет, меня зовут Даша. Я занимаюсь веб-разработкой уже больше 5 лет, и последние 2–3 года мои проекты всё чаще касаются веб-сервисов, активно использующих 2D-графику. А чем сложнее становятся сервисы, тем глубже приходится нырять в специфику инструментов и технологий. И когда только приходилось углубляться в это - возникало много вопросов по типу “почему бы не использовать WebGL сразу?”, “почему некоторые сервисы используют svg в редакторе вместо canvas”, “зачем вообще этот ваш WebGPU нужен” и прочее.
Теперь, когда WebGPU активно расширяет поддержку, мне захотелось проверить: а насколько оно вообще разумно для 2D-графики? Поэтому я решила провести полноценный тест, расставить все точки над i и заодно посмотреть на уже устоявшиеся подходы. И вот я тут — делюсь результатами.
Что тестируем-то?
Думаю, стоит начать с наших сегодняшних героев. Вот они слева направо:
Canvas — де-факто стандарт 2D графики. Прост в изучении, библиотек — вагон, поддерживается даже на тапочке.
SVG — особых представлений не требует, но когда-то меня сильно удивило, что его используют не только в анимациях.
WebGL — технология, позволяющая запускать графические шейдеры прямо в браузере. Отлично масштаби��уется и снимает нагрузку с CPU.
WebGPU — новый стандарт, пришедший на смену WebGL. Быстрее, мощнее, перспективнее, но пока ещё не везде поддерживается.
А как тестируем?
Мы будем сравнивать простую анимацию с шариками, отбивающимися от стен. Код писался при участии Claude и ChatGPT; исходники лежат тут: https://github.com/daashuun/bouncing-balls-test.
Моё окружение:
ОС: Windows 10
Браузер: Chrome 140.0.7339.127 (vsync отключён — не пугайтесь 8k+ fps, всё так и задумано)
CPU: Intel Core i7-13620H
GPU встроенная: Intel UHD Graphics
GPU дискретная: NVIDIA GeForce RTX 4070
Что измеряем:
FPS
CPU usage (старт, среднее, пик)
GPU usage (старт, среднее, пик)
Количество объектов:
1, 100, 1000, 10000, 20000, 30000, 50000, и для WebGL/WebGPU — 100000.
Почему тесты проводятся на двух видеокартах? Потому что Chrome на устройствах с двумя GPU (обычно ноутбуки) по умолчанию использует встроенную графику, а обычный пользователь редко лезет менять настройки под какой-то ваш сервис. Но для чистоты эксперимента хотелось посмотреть и максимальную мощность которая мне была доступна.
Встроенная GPU
Куча таблиц
Canvas:
кол-во шаров |
1 |
100 |
1000 |
10000 |
20000 |
30000 |
50000 |
fps |
6700 |
4900 |
650 |
67 |
34 |
23 |
13 |
cpu |
55 |
42 |
33 |
29 |
28 |
28 |
26 |
gpu |
100 |
100 |
100 |
100 |
100 |
100 |
100 |
пик cpu |
60 |
47 |
36 |
32 |
32 |
31 |
31 |
пик gpu |
100 |
100 |
100 |
100 |
100 |
100 |
100 |
при открытии cpu |
87 |
64 |
61 |
63 |
54 |
47 |
52 |
при открытии gpu |
100 |
100 |
100 |
100 |
100 |
100 |
100 |
Svg:
кол-во шаров |
1 |
100 |
1000 |
10000 |
20000 |
30000 |
50000 |
fps |
8200 |
1020 |
293 |
29 |
14 |
10 |
6 |
cpu |
52 |
35 |
28 |
24 |
24 |
23 |
24 |
gpu |
90 |
92 |
97 |
71 |
80 |
78 |
72 |
пик cpu |
62 |
42 |
37 |
32 |
29 |
26 |
27 |
пик gpu |
100 |
100 |
100 |
86 |
90 |
91 |
78 |
при открытии cpu |
72 |
63 |
47 |
47 |
38 |
50 |
43 |
при открытии gpu |
100 |
97 |
90 |
65 |
70 |
66 |
52 |
WebGL:
кол-во шаров |
1 |
100 |
1000 |
10000 |
20000 |
30000 |
50000 |
100000 |
fps |
3300 |
1350 |
775 |
94 |
57 |
39 |
24 |
12 |
cpu |
33 |
26 |
35 |
17 |
18 |
18 |
20 |
20 |
gpu |
70 |
51 |
82 |
86 |
76 |
45 |
34 |
47 |
пик cpu |
52 |
34 |
39 |
24 |
23 |
21 |
26 |
21 |
пик gpu |
92 |
70 |
100 |
100 |
83 |
67 |
70 |
68 |
при открытии cpu |
71 |
73 |
68 |
62 |
45 |
38 |
48 |
53 |
при открытии gpu |
76 |
49 |
82 |
82 |
77 |
48 |
34 |
32 |
WebGPU:
кол-во шаров |
1 |
100 |
1000 |
10000 |
20000 |
30000 |
50000 |
100000 |
fps |
4350 |
4100 |
1805 |
250 |
130 |
87 |
55 |
27 |
cpu |
53 |
62 |
36 |
26 |
27 |
27 |
27 |
28 |
gpu |
93 |
95 |
100 |
100 |
100 |
100 |
99 |
100 |
пик cpu |
58 |
70 |
38 |
30 |
31 |
43 |
29 |
30 |
пик gpu |
96 |
98 |
100 |
100 |
100 |
100 |
100 |
100 |
при открытии cpu |
75 |
87 |
63 |
50 |
55 |
52 |
56 |
55 |
при открытии gpu |
98 |
98 |
100 |
100 |
100 |
100 |
100 |
100 |
Для удобства разделила на два графика:


Основные наблюдения
Во-первых — банальности, которые всё же приятно подтвердить:
Canvas после ~10k объектов перестаёт быть эффективным.
WebGPU заметно лучше использует видеокарту по сравнению с WebGL.
Во-вторых — немного неожиданный факт:
SVG при небольшом количестве объектов (<100) оказался существенно эффективнее Canvas, причём нагружает CPU и GPU значительно меньше. Ожидалось, что они будут приблизительно одинаковы.
Зная реальные запросы, могу уверенно сказать: у большинства use-cases количество объектов редко превышает сотню. Так что SVG — весьма хороший выбор. Но если вы строите полноценный редактор или рассчитываете на динамическое ко��ичество элементов, будьте осторожны: тест был упрощен, без взаимодействия с пользователем, и в реальности будут проседания.
Дискретная GPU
Переходим к RTX 4070.
Сразу заметила, что для Canvas и SVG разница с встроенной GPU была менее 1%, поэтому для них отдельные замеры не проводились.
Вторая куча таблиц
WebGL:
кол-во шаров |
1 |
100 |
1000 |
10000 |
20000 |
30000 |
50000 |
100000 |
|---|---|---|---|---|---|---|---|---|
fps |
8750 |
8450 |
2870 |
324 |
169 |
112 |
69 |
34 |
cpu |
62 |
65 |
52 |
33 |
32 |
31 |
30 |
30 |
gpu |
50 |
72 |
49 |
29 |
26 |
28 |
31 |
32 |
пик cpu |
65 |
67 |
54 |
35 |
35 |
36 |
37 |
34 |
пик gpu |
57 |
74 |
58 |
30 |
33 |
29 |
31 |
33 |
при открытии cpu |
90 |
80 |
84 |
59 |
64 |
78 |
65 |
55 |
при открытии gpu |
52 |
73 |
54 |
27 |
24 |
24 |
24 |
25 |
WebGPU:
кол-во шаров |
1 |
100 |
1000 |
10000 |
20000 |
30000 |
50000 |
100000 |
fps |
4900 |
4500 |
2150 |
316 |
152 |
99 |
62 |
30 |
cpu |
69 |
54 |
40 |
21 |
19 |
19 |
19 |
18 |
gpu |
68 |
73 |
74 |
28 |
17 |
18 |
20 |
23 |
пик cpu |
72 |
57 |
44 |
25 |
26 |
23 |
72 |
24 |
пик gpu |
71 |
74 |
74 |
28 |
19 |
21 |
22 |
25 |
при открытии cpu |
62 |
63 |
70 |
42 |
53 |
46 |
59 |
37 |
при открытии gpu |
65 |
70 |
74 |
27 |
13 |
11 |
17 |
11 |


И… что это вообще было?
Этот тест, честно говоря, дал больше вопросов, чем ответов. Разберём ключевые:
Почему WebGL оказался быстрее WebGPU?
Почему увеличение FPS при переходе на дискретную GPU у WebGPU едва достигает 10–15%, тогда как WebGL вырастает в разы?
Понаблюдав за нагрузкой, нашлась причина: в WebGPU при смене видеокарты снизилась нагрузка и на CPU, и на GPU, а это плохо — оба простаивают, значит есть “бутылочное горлышко”. В WebGL же CPU стал загружен сильнее, а GPU — меньше, что логично: видеокарта утыкается в CPU.
Разобравшись, выяснилось: самая большая проблема — запись данных в буфер каждый кадр.
Решение: переписать вычисления на compute-shader, чтобы не перезаписывать буфер.
Получаем:
И еще немного таблиц
кол-во шаров |
1 |
100 |
1000 |
10000 |
20000 |
30000 |
50000 |
100000 |
500000 |
fps |
5550 |
5600 |
5650 |
3166 |
1736 |
1196 |
736 |
375 |
76 |
cpu |
67 |
58 |
55 |
42 |
31 |
24 |
22 |
18 |
17 |
gpu |
45 |
30 |
25 |
100 |
100 |
100 |
100 |
100 |
100 |
пик cpu |
71 |
62 |
59 |
57 |
35 |
28 |
25 |
22 |
23 |
пик gpu |
48 |
40 |
43 |
100 |
100 |
100 |
100 |
100 |
100 |
при открытии cpu |
78 |
81 |
68 |
62 |
43 |
50 |
47 |
48 |
42 |
при открытии gpu |
189 |
29 |
27 |
100 |
100 |
100 |
100 |
100 |
100 |


Отлично! Это то, что нужно - теперь WebGPU действительно дал понять на что он способен. После оптимизации даже пришлось поднять максимальное число шаров до 500 тысяч, чтобы FPS опустился к разумным 76.
Важное наблюдение
При малом числе объектов WebGPU с compute-шейдерами работает медленнее — потому что моя видеокарта имеет 5888 вычислительных блоков. Пока количество задач меньше этого числа, GPU фактически простаивает. Но когда объекты наконец «заполняют» все блоки — начинается магия (теоретически можно добиться ещё лучших результатов, подбирая количество объектов, кратное числу блоков, но в рамках эксперимента это не требовалось.)
Итоги
Мы тестировали максимально простую логику без пользовательского взаимодействия и без логики реального приложения. Фреймворки тоже не использовались — поэтому в реальности показатели будут хуже, в рекомендациях учтен этот момент.
Если объектов до 50
→ SVG
Лучший вариант для большинства анимаций, интерфейсов и редакторов, ограничивающих количество элементов.
Но если количество объектов задаёт пользователь — это риск.
Если объектов до 5000
→ Canvas
Покрывает 80–90% бизнес-кейсов.
Широчайшая поддержка, куча библиотек, готовых решений и документации. Если кейс не специфический — берите Canvas, не прогадаете.
Если объектов больше
→ WebGL
Сложнее Canvas, но проще и стабильнее WebGPU.
Приложения уровня Figma и Miro чаще всего используют WebGL, и, думаю, мне не нужно рассказывать, насколько хорошо они работают при большом количестве объектов.
Если кейс специфический (симуляции, сложная математика, ML, 3D…)
→ WebGPU
Это ваш выбор.
Такие пользователи обычно технически подкованы и в случае необходимости смогут разобраться и переключить видеокарту.
Также выбирайте WebGPU, если:
вам подходит WebGL,
проект разрабатывается год+,
старые браузеры поддерживать не нужно.
К моменту релиза вашего приложения WebGPU вполне вероятно будет поддерживаться повсеместно (сейчас ещё есть проблемы на некоторых мобильных устройствах и в Linux).
Вывод
В итоге можно сказать, что выбор технологии для 2D-графики — это не вопрос «что лучше», а вопрос «что подходит вашему сценарию». Все решения закрывают свои ниши, и каждый инструмент отлично справляется с задачами, для которых он был создан. Но если понимать ограничения и особенности каждого подхода, можно избежать множества проблем и сделать продукт не просто рабочим, а действительно оптимальным.