Бинарные форматы данных

Бинарные данные в контексте WebGL представляют собой основной механизм передачи геометрии и атрибутов на GPU. В отличие от объектных структур JavaScript, где данные хранятся в виде массивов и объектов, WebGL и библиотеки визуализации поверх него опираются на строго типизированные буферы фиксированного размера. В экосистеме Deck.gl этот подход доведён до уровня архитектурного принципа: производительность достигается за счёт минимизации преобразований данных в runtime и максимального использования бинарных представлений.

JavaScript предоставляет набор структур, известных как Typed Arrays. Они позволяют работать с сырыми бинарными данными в памяти:

  • ArrayBuffer — низкоуровневый контейнер фиксированного размера
  • Float32Array — массив 32-битных чисел с плавающей точкой
  • Uint16Array / Uint32Array — целочисленные массивы без знака
  • Int8Array / Uint8Array — байтовые представления

В контексте графики Float32Array становится основным форматом для координат, так как GPU оперирует именно 32-битными float значениями.

Ключевая особенность Typed Arrays заключается в отсутствии накладных расходов на структуру объектов. Доступ к элементам происходит напрямую через смещение в памяти, что критично при обработке миллионов вершин.

Колонковое представление данных

В системах визуализации существует два базовых способа организации данных:

Интерливинг (interleaved)

Все атрибуты одной вершины хранятся подряд:

[x, y, z, r, g, b]
[x, y, z, r, g, b]

Такой формат удобен для чтения человеком и локальной обработки, но менее эффективен для GPU-шейдеров при выборочном доступе к атрибутам.

Колонковый формат (columnar)

Каждый атрибут хранится отдельно:

positions = [x1, y1, z1, x2, y2, z2, ...]
colors    = [r1, g1, b1, r2, g2, b2, ...]

Deck.gl использует преимущественно колонковый подход, так как он оптимизирует:

  • кэширование GPU
  • обновление отдельных атрибутов
  • передачу данных по шине CPU → GPU
  • частичные обновления без пересоздания всех буферов

Атрибутная модель Deck.gl

В основе Deck.gl лежит система атрибутов (attributes), которая напрямую отображается на буферы WebGL. Каждый слой (Layer) определяет набор атрибутов, которые затем преобразуются в GPU buffers.

Типичный пример атрибутов:

  • position
  • color
  • normal
  • size
  • offset

Каждый атрибут хранится в Typed Array и привязывается к конкретному location в шейдере.

Binary props и генерация атрибутов

Deck.gl позволяет определять данные не только как готовые массивы, но и как функции преобразования:

  • getPosition
  • getColor
  • getRadius
  • getFillColor

Эти функции используются для генерации бинарных буферов на этапе подготовки данных.

Пример логики преобразования:

  • вход: массив объектов
  • выход: Float32Array для каждой сущности

При этом важный принцип заключается в том, что вычисления происходят один раз при обновлении данных, а не на каждом кадре рендеринга.

GPU буферы и связь с WebGL

После подготовки бинарных данных они передаются в GPU через WebGLBuffer. Deck.gl абстрагирует этот процесс, но внутри происходит следующая цепочка:

  1. Создание Typed Array
  2. Передача в WebGL через bufferData
  3. Привязка к attribute location в shader program
  4. Использование в vertex shader

Важно, что GPU работает исключительно с непрерывными блоками памяти, поэтому любые JavaScript-объекты должны быть преобразованы в бинарный формат до рендеринга.

Instanced rendering и бинарная эффективность

Одной из ключевых оптимизаций Deck.gl является instanced rendering. Вместо отрисовки каждой геометрии отдельно используется шаблон (geometry), который повторяется с различными атрибутами.

Бинарные данные в этом случае разделяются на:

  • геометрию (static buffers)
  • инстанс-атрибуты (dynamic buffers)

Пример:

  • одна модель куба
  • тысячи позиций и цветов
  • GPU рендерит тысячи экземпляров одной геометрии

Это резко снижает нагрузку на CPU и уменьшает объём передаваемых данных.

Columnar attributes в реализации слоёв

Внутренняя архитектура Deck.gl строится вокруг класса AttributeManager. Он отвечает за:

  • создание buffer’ов
  • обновление данных
  • dirty-checking
  • синхронизацию с GPU

Каждый слой описывает генераторы атрибутов:

getPosition → Float32Array(3 * N)
getColor → Uint8Array(4 * N)

AttributeManager анализирует изменения входных данных и пересобирает только изменившиеся буферы.

Типы бинарных преобразований

При подготовке данных используются разные стратегии:

1. Direct mapping

Когда входные данные уже представлены в виде Typed Array.

2. Computed attributes

Когда значения вычисляются из объектов:

{x, y, z} → position buffer

3. Derived attributes

Когда один атрибут зависит от другого:

radius → size scaling
category → color mapping

Interleaved vs columnar в GPU контексте

Хотя интерливинг может показаться компактнее, колонковый формат выигрывает в WebGL по нескольким причинам:

  • доступ к одному атрибуту без загрузки лишних данных
  • лучшая совместимость с vertex shader inputs
  • эффективное использование vertex attribute pointers
  • меньшая фрагментация кеша GPU

Interleaved формат может использоваться в специфических случаях, но Deck.gl оптимизирован под columnar модель.

Работа с большими наборами данных

При работе с миллионами точек ключевую роль играет минимизация операций копирования памяти. Deck.gl применяет следующие подходы:

  • переиспользование буферов
  • частичное обновление атрибутов
  • ленивые вычисления (lazy evaluation)
  • мемоизация результатов get* функций

Особенно важно избегать создания промежуточных JavaScript массивов, так как они приводят к лишним аллокациям и GC pressure.

Связь с loaders.gl и бинарным парсингом

В экосистеме Deck.gl часто используется loaders.gl, который преобразует внешние форматы (CSV, GeoJSON, Shapefile, binary formats) в Typed Arrays.

Типичный pipeline:

  • загрузка файла
  • парсинг в структурированные данные
  • преобразование в columnar binary format
  • передача в Deck.gl layer

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

Оптимизация памяти и производительности

Работа с бинарными данными требует строгого контроля памяти:

  • избегание копирования Float32Array
  • использование subarray вместо slice при возможности
  • контроль alignment данных
  • минимизация пересоздания buffer objects

Особенно критично поведение GC при частых обновлениях данных: даже небольшие временные массивы могут приводить к фризам рендеринга.

Атрибутные обновления и updateTriggers

Deck.gl использует механизм updateTriggers для контроля пересчёта бинарных атрибутов. Это позволяет избежать ненужных преобразований данных.

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

  • изменение цвета → пересчёт color buffer
  • изменение позиции → пересчёт position buffer
  • изменение визуальных параметров → частичное обновление

Таким образом достигается баланс между гибкостью API и производительностью GPU pipeline.

Бинарные данные и shader pipeline

На уровне шейдеров бинарные данные становятся входными атрибутами:

attribute vec3 positions;
attribute vec4 colors;

Vertex shader получает уже готовые значения, исключая любые вычисления на CPU. Это ключевой момент архитектуры: вся тяжёлая работа переносится в этап подготовки бинарных буферов, а не в runtime отрисовки.

Итоговая архитектурная роль бинарного формата

Бинарные данные в Deck.gl являются не просто форматом хранения, а центральным элементом всей системы рендеринга. Они связывают:

  • JavaScript-уровень (данные и логика)
  • GPU-уровень (шейдеры и буферы)
  • слой абстракции (AttributeManager и Layers)

Эта модель позволяет обрабатывать огромные объёмы пространственных данных с минимальными накладными расходами и предсказуемым поведением производительности.