GPU ускорение

Mapbox GL JS построен на принципе полной отрисовки карты через GPU с использованием WebGL. Это означает, что практически весь графический конвейер — от обработки геометрии до финального композитинга слоёв — выполняется видеокартой, а не CPU.

Ключевая идея заключается в том, что карта рассматривается не как набор DOM-элементов или растровых изображений, а как сцена в 3D-графическом движке. Каждый слой карты преобразуется в набор графических примитивов, которые загружаются в GPU-память и обрабатываются параллельно тысячами потоков.


WebGL как основа рендеринга

WebGL выступает низкоуровневым интерфейсом между JavaScript и GPU. В Mapbox GL JS он используется для:

  • создания контекстов рендеринга;
  • управления буферами вершин (vertex buffers);
  • компиляции шейдеров (GLSL);
  • выполнения draw calls.

Конвейер рендеринга

Типичный цикл отрисовки кадра включает:

  1. Обновление состояния карты (позиция, zoom, pitch, bearing)
  2. Выбор тайлов, попадающих в viewport
  3. Декодирование векторных данных
  4. Преобразование геометрии в буферы GPU
  5. Запуск vertex shader
  6. Выполнение fragment shader
  7. Композитинг слоёв

Каждый этап оптимизирован под минимизацию CPU-операций и максимальную параллелизацию на GPU.


Векторные тайлы и их GPU-обработка

Векторные тайлы — основа производительности GPU-рендеринга.

Каждый тайл содержит:

  • линии (roads, boundaries)
  • полигоны (buildings, landuse)
  • точки (POI)
  • подписи и символы

Данные кодируются в формате protobuf и декодируются в Web Workers, чтобы не блокировать главный поток.

После декодирования происходит:

  • триангуляция полигонов
  • упрощение линий
  • подготовка атрибутов для шейдеров

Затем данные передаются в GPU через буферы:

  • Vertex Buffer Object (VBO)
  • Index Buffer Object (IBO)

Шейдерная модель рендеринга

GPU-ускорение в Mapbox GL JS полностью зависит от шейдеров GLSL.

Vertex Shader

Отвечает за:

  • преобразование координат из мировых в экранные
  • применение матриц камеры
  • интерполяцию атрибутов

Пример логики:

  • долгота/широта → mercator projection
  • масштабирование под zoom level
  • применение perspective matrix при наклоне карты

Fragment Shader

Отвечает за:

  • цвет пикселя
  • прозрачность
  • градиенты
  • текстуры (например, для заливки полигонов или иконок)

Именно здесь реализуются такие эффекты как:

  • прозрачность слоёв
  • стилизация дорог по классу
  • плавные переходы цвета при zoom interpolation

Система слоёв и GPU-композиция

Каждый слой карты — это отдельная GPU-операция. Слои делятся на типы:

  • fill (полигоны)
  • line (линии)
  • symbol (иконки и текст)
  • raster (тайловые изображения)
  • circle (точечные данные)

GPU позволяет рендерить их независимо, а затем выполнять композицию через blending:

  • alpha blending
  • additive blending
  • multiply blending

Композиция выполняется без участия CPU, что резко снижает нагрузку при большом количестве объектов.


Использование буферов и минимизация draw calls

Одним из ключевых факторов производительности является уменьшение количества draw calls.

GPU работает эффективнее, когда:

  • данные сгруппированы в крупные буферы
  • используется instancing
  • минимизируются переключения шейдеров

Mapbox GL JS применяет:

  • атласизацию символов (glyph atlas)
  • объединение геометрии одного типа
  • переиспользование буферов между кадрами

Тайловая система и кеширование на GPU

Рендеринг карты разбивается на тайлы (обычно 512×512 пикселей). Каждый тайл:

  • загружается асинхронно
  • декодируется в Web Worker
  • кешируется в памяти GPU

Кеширование позволяет:

  • избегать повторной загрузки данных при панорамировании
  • повторно использовать буферы при зуме
  • снижать нагрузку на CPU

GPU хранит уже подготовленные буферы до тех пор, пока тайл не выходит за пределы видимой области.


Символьные слои и текстовый рендеринг

Символьные слои являются наиболее сложными для GPU.

Основные этапы:

  1. Генерация подписей в layout engine
  2. Упаковка глифов в texture atlas
  3. Передача координат символов в vertex buffer
  4. Рендеринг через signed-distance fields (SDF)

SDF позволяет:

  • масштабировать текст без потери качества
  • применять обводку и тень на GPU
  • обеспечивать стабильную читаемость при зуме

Параллелизм через Web Workers

CPU-часть системы разгружена через Web Workers:

  • парсинг векторных тайлов
  • генерация геометрии
  • подготовка данных для шейдеров

Это критично, так как основной поток занят:

  • обработкой пользовательских событий
  • анимацией камеры
  • синхронизацией состояния карты

GPU получает уже готовые структуры данных, что минимизирует задержки.


Камера и матричные преобразования

GPU-ускорение тесно связано с моделью камеры.

Используются матрицы:

  • projection matrix
  • view matrix
  • model matrix

Они обеспечивают:

  • зумирование без перерисовки всей сцены
  • плавные наклоны (pitch)
  • вращение карты (bearing)

Каждое изменение камеры приводит не к пересборке геометрии, а к изменению uniform-переменных в шейдерах.


Оптимизация overdraw и прозрачности

Overdraw — ситуация, когда один пиксель перерисовывается несколько раз за кадр.

В GPU-рендеринге карты это частая проблема из-за:

  • перекрывающихся слоёв
  • полупрозрачных объектов
  • символов поверх линий и полигонов

Методы борьбы:

  • сортировка слоёв по depth
  • ранний discard в fragment shader
  • минимизация прозрачных регионов
  • использование stencil buffer

Производительность и ограничения GPU

Несмотря на высокую эффективность GPU-рендеринга, существуют ограничения:

  • ограничение видеопамяти
  • стоимость переключения шейдеров
  • перегрузка fragment shader при сложных стилях
  • падение производительности на слабых интегрированных GPU

Особенно критичны:

  • большое количество символов
  • сложные фильтры в стилях
  • частые пересоздания источников данных

Асинхронная отрисовка и requestAnimationFrame

Рендеринг синхронизирован с браузерным циклом через requestAnimationFrame.

Это позволяет:

  • избегать tearing
  • синхронизировать GPU с дисплеем
  • равномерно распределять нагрузку

Каждый кадр включает:

  • обновление состояния камеры
  • проверку dirty state слоёв
  • обновление GPU буферов при необходимости
  • финальный draw pass

Управление памятью GPU

Важная часть архитектуры — контроль видеопамяти.

Стратегии:

  • выгрузка неиспользуемых тайлов
  • LRU-кеширование буферов
  • переиспользование текстур
  • сжатие атласов

При переполнении GPU памяти система:

  • уменьшает кеш тайлов
  • снижает качество символов
  • освобождает старые ресурсы

Итеративная отрисовка и diff-подход

Mapbox GL JS не перерисовывает всю карту при каждом изменении.

Вместо этого используется diff-стратегия:

  • изменился стиль → пересчитать только затронутые слои
  • изменился zoom → обновить только геометрию с zoom-dependent свойствами
  • изменилось положение → обновить матрицу камеры

Это минимизирует количество GPU операций и снижает latency.


Роль compositing layer в финальном кадре

После выполнения всех draw calls GPU выполняет финальную композицию:

  • наложение слоёв в порядке z-index
  • применение blending modes
  • финальный вывод в framebuffer

Этот этап критически важен для визуальной целостности сцены, так как именно здесь формируется итоговое изображение карты, включая прозрачности, перекрытия и эффекты смешивания.