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

Так что я решила устроить небольшой тест 2D-решений: посмотреть, на что они реально способны, понять, почему результаты местами вызывают большое удивление, и ответить себе (и вам) на вопрос: а WebGPU вообще зачем?

Спойлер: всё далеко не так очевидно, как кажется.

bouncing balls (svg, canvas, webgl, webgpu)
bouncing balls (svg, canvas, webgl, 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

Для удобства разделила на два графика:

Встроенная GPU, 1-1000 объектов
Встроенная GPU, 1-1000 объектов
Встроенная GPU, 10k-100k объектов
Встроенная GPU, 10k-100k объектов

Основные наблюдения

Во-первых — банальности, которые всё же приятно подтвердить:

  • 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

Дискретная GPU, 1-1000 объектов
Дискретная GPU, 1-1000 объектов
Дискретная GPU, 10k-100k объектов
Дискретная GPU, 10k-100k объектов

И… что это вообще было?

Этот тест, честно говоря, дал больше вопросов, чем ответов. Разберём ключевые:

  • Почему 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

Дискретная GPU, 1-1000 объектов, v2
Дискретная GPU, 1-1000 объектов, v2
Дискретная GPU, 10k-100k объектов, v2
Дискретная GPU, 10k-100k объектов, v2

Отлично! Это то, что нужно - теперь 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-графики — это не вопрос «что лучше», а вопрос «что подходит вашему сценарию». Все решения закрывают свои ниши, и каждый инструмент отлично справляется с задачами, для которых он был создан. Но если понимать ограничения и особенности каждого подхода, можно избежать множества проблем и сделать продукт не просто рабочим, а действительно оптимальным.

Комментарии (0)