Класс Buffer и типизированные массивы

В основе производительности PixiJS лежит прямое взаимодействие с API WebGL. Видеокарта принимает данные в виде бинарных буферов — последовательностей чисел фиксированного типа. Именно поэтому ключевую роль в низкоуровневой части библиотеки играет класс Buffer, который инкапсулирует работу с типизированными массивами и синхронизацию данных с GPU.

Класс Buffer используется во всех системах геометрии: при создании Mesh, Geometry, пользовательских шейдеров и атрибутов вершин.


Типизированные массивы в JavaScript

Типизированные массивы — это структуры данных, позволяющие хранить числовые значения в бинарном формате с фиксированной разрядностью. В отличие от обычных массивов Jav * aScript:

  • хранят данные в непрерывном участке памяти;
  • имеют строго определённый тип элементов;
  • совместимы с бинарными API, такими как WebGL.

Основные типы

Тип Размер Описание
Float32Array 4 байта Числа с плавающей точкой
Uint16Array 2 байта Беззнаковые 16-битные целые
Uint32Array 4 байта Беззнаковые 32-битные целые
Int16Array 2 байта Знаковые 16-битные
Uint8Array 1 байт Байтовые данные

Для вершинной геометрии чаще всего используются:

  • Float32Array — координаты, UV, нормали;
  • Uint16Array или Uint32Array — индексы.

Назначение класса Buffer в PixiJS

Класс Buffer служит связующим звеном между:

  1. типизированным массивом в оперативной памяти,
  2. объектом буфера в WebGL,
  3. системой обновлений PixiJS.

Его задачи:

  • хранение ссылки на типизированный массив;
  • отслеживание изменений данных;
  • управление загрузкой в GPU;
  • выбор типа WebGL-буфера (вершинный или индексный).

Создание Buffer

Базовый пример:

import { Buffer } from 'pixi.js';

const data = new Float32Array([
    0, 0,
    100, 0,
    100, 100,
    0, 100
]);

const buffer = new Buffer(data);

После создания:

  • data хранится в CPU-памяти;
  • при первой отрисовке буфер будет передан в WebGL;
  • дальнейшие изменения можно синхронизировать вручную.

Параметры конструктора

new Buffer(data, options)

data

Типизированный массив.

options

Объект с параметрами:

Свойство Назначение
usage Тип использования (STATIC, DYNAMIC, STREAM)
label Отладочная метка
shrinkToFit Оптимизация размера

Режимы usage

Эти значения соответствуют режимам WebGL:

  • STATIC_DRAW — данные редко изменяются;
  • DYNAMIC_DRAW — периодически обновляются;
  • STREAM_DRAW — обновляются каждый кадр.

Выбор режима влияет на стратегию оптимизации GPU.


Обновление данных

Изменение массива

data[0] = 50;

После изменения необходимо уведомить систему:

buffer.update();

Метод update():

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

Свойство data

buffer.data — это ссылка на исходный типизированный массив. Замена массива возможна:

buffer.data = new Float32Array([...]);
buffer.update();

PixiJS не копирует массив автоматически. Работа происходит с переданной ссылкой.


Индексные буферы

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

const indices = new Uint16Array([
    0, 1, 2,
    0, 2, 3
]);

const indexBuffer = new Buffer(indices);

Он используется совместно с Geometry для определения треугольников.

Выбор между Uint16Array и Uint32Array зависит от количества вершин:

  • до 65535 — Uint16Array;
  • больше — Uint32Array (при поддержке расширений WebGL).

Взаимодействие Buffer и Geometry

Geometry агрегирует несколько буферов:

  • позиции;
  • UV-координаты;
  • цвета;
  • индексы.

Пример:

geometry.addAttribute('aPosition', buffer, 2);

Здесь:

  • 'aPosition' — имя атрибута в шейдере;
  • buffer — экземпляр Buffer;
  • 2 — размерность (x, y).

Частичное обновление данных

PixiJS поддерживает обновление части массива:

buffer.update(data, offset);

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

  • минимизировать передачу данных в GPU;
  • оптимизировать анимацию вершин;
  • эффективно работать с динамической геометрией.

Внутренний механизм синхронизации

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

  • _updateID — версия данных;
  • флаг изменения;
  • ссылки на WebGL-объекты.

При рендеринге:

  1. система сравнивает версии;
  2. при несоответствии вызывает gl.bufferSubData или gl.bufferData;
  3. данные передаются в виде бинарного блока.

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

Работа с буферами требует учёта:

  • количества пересозданий массива;
  • частоты вызова update();
  • объёма передаваемых данных.

Оптимизационные рекомендации:

  • избегать создания новых массивов каждый кадр;
  • использовать DYNAMIC_DRAW для часто обновляемых данных;
  • изменять существующий массив вместо его замены;
  • минимизировать размер буфера.

Связь с Mesh

Mesh использует Geometry, а та — Buffer. Поток данных выглядит так:

TypedArray → Buffer → Geometry → Shader → WebGL → GPU

Таким образом, Buffer — фундаментальный элемент всей системы отрисовки.


ShrinkToFit

Опция shrinkToFit управляет поведением при уменьшении массива:

  • если true, GPU-буфер пересоздаётся;
  • если false, сохраняется предыдущий размер.

Это влияет на:

  • количество аллокаций;
  • стабильность производительности;
  • использование видеопамяти.

Различия между Buffer и обычным массивом

Обычный массив Buffer
Динамический тип Строгий бинарный формат
Не совместим с WebGL напрямую Непосредственно используется GPU
Автоматическое расширение Фиксированный размер
Высокий оверхед Минимальные накладные расходы

Работа с interleaved-данными

PixiJS поддерживает чередование атрибутов:

// x, y, u, v
new Float32Array([
  0, 0, 0, 0,
  100, 0, 1, 0,
  ...
]);

Один буфер может хранить:

  • позицию,
  • UV,
  • цвет.

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


Контроль жизненного цикла

Буфер можно уничтожить:

buffer.destroy();

Это:

  • освобождает ссылки;
  • помечает объект для очистки GPU-ресурсов;
  • предотвращает утечки памяти.

Роль Buffer в расширяемости PixiJS

При создании:

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

необходима прямая работа с Buffer.

Глубокое понимание:

  • бинарных форматов,
  • принципов работы GPU,
  • различий между STATIC и DYNAMIC режимами,

позволяет проектировать высокопроизводительные графические системы.


Ключевые выводы

  • Buffer — абстракция над WebGL-буферами.
  • Основан на типизированных массивах.
  • Отвечает за синхронизацию CPU ↔︎ GPU.
  • Является базовым строительным элементом Geometry.
  • Критичен для производительности сложных сцен.