Как разработчик WebGL, вы можете испытывать одновременно страх и восторг от начала использования WebGPU, преемника WebGL, который привносит в Интернет преимущества современных графических API.
Отрадно знать, что WebGL и WebGPU имеют много общих базовых концепций. Оба API позволяют запускать небольшие программы, называемые шейдерами, на графическом процессоре. WebGL поддерживает вершинные и фрагментные шейдеры, а WebGPU — также вычислительные шейдеры. WebGL использует язык шейдеров OpenGL (GLSL), а WebGPU — язык шейдеров WebGPU (WGSL). Хотя эти два языка различаются, базовые концепции в целом совпадают.
Учитывая это, в данной статье рассматриваются некоторые различия между WebGL и WebGPU, которые помогут вам приступить к работе.
Глобальное государство
WebGL имеет множество глобальных состояний . Некоторые настройки применяются ко всем операциям рендеринга, например, какие текстуры и буферы привязаны. Вы задаёте это глобальное состояние, вызывая различные функции API, и оно действует до тех пор, пока вы его не измените. Глобальное состояние в WebGL — основной источник ошибок , поскольку легко забыть изменить глобальный параметр. Кроме того, глобальное состояние затрудняет совместное использование кода, поскольку разработчикам нужно быть осторожными, чтобы случайно не изменить глобальное состояние так, чтобы это повлияло на другие части кода.
WebGPU — это API без сохранения состояния, не поддерживающее глобальное состояние. Вместо этого он использует концепцию конвейера для инкапсуляции всего состояния рендеринга, которое было глобальным в WebGL. Конвейер содержит информацию, такую как используемое смешивание, топология и атрибуты. Конвейер неизменяем. Если вы хотите изменить некоторые настройки, необходимо создать другой конвейер. WebGPU также использует кодировщики команд для пакетной обработки команд и их выполнения в порядке их записи. Это полезно, например, при наложении теней, когда за один проход по объектам приложение может записать несколько потоков команд, по одному для каждой карты теней источника света.
Подводя итог, можно сказать, что глобальная модель состояний WebGL затрудняла и делала ненадежным создание надежных, компонуемых библиотек и приложений, а WebGPU значительно сократил объем состояний, которые разработчикам необходимо отслеживать при отправке команд в графический процессор.
Синхронизации больше нет
На графических процессорах (GPU) обычно неэффективно отправлять команды и ожидать их синхронно, поскольку это может привести к переполнению конвейера и появлению пузырей . Это особенно актуально для WebGPU и WebGL, которые используют многопроцессную архитектуру с драйвером GPU, работающим в отдельном процессе от JavaScript.
Например, в WebGL вызов gl.getError()
требует синхронного межпроцессного взаимодействия (IPC) между процессом JavaScript и процессом графического процессора и обратно. Это может привести к «пузырю» на стороне центрального процессора при взаимодействии двух процессов.
Чтобы избежать этих «пузырей», WebGPU спроектирован полностью асинхронно . Модель ошибок и все остальные операции выполняются асинхронно. Например, при создании текстуры операция выполняется сразу же, даже если текстура на самом деле является ошибкой. Обнаружить ошибку можно только асинхронно. Такая архитектура предотвращает возникновение «пузырей» при межпроцессном взаимодействии и обеспечивает стабильную производительность приложений.
Вычислительные шейдеры
Вычислительные шейдеры — это программы, работающие на графическом процессоре для выполнения вычислений общего назначения. Они доступны только в WebGPU, но не в WebGL.
В отличие от вершинных и фрагментных шейдеров, их применение не ограничивается обработкой графики и может быть использовано для самых разных задач, таких как машинное обучение, физическое моделирование и научные вычисления. Вычислительные шейдеры выполняются параллельно сотнями или даже тысячами потоков, что делает их очень эффективными для обработки больших наборов данных. Узнайте больше о вычислениях на GPU и о других аспектах в этой подробной статье о WebGPU .
Обработка видеокадров
Обработка видеокадров с помощью JavaScript и WebAssembly имеет ряд недостатков: затраты на копирование данных из памяти графического процессора в память центрального процессора и ограниченный параллелизм, достигаемый с помощью рабочих потоков и потоков центрального процессора. WebGPU лишен этих ограничений, что делает его отличным инструментом для обработки видеокадров благодаря тесной интеграции с API WebCodecs .
Следующий фрагмент кода показывает, как импортировать VideoFrame как внешнюю текстуру в WebGPU и обработать её. Вы можете попробовать эту демоверсию .
// Init WebGPU device and pipeline...
// Configure canvas context...
// Feed camera stream to video...
(function render() {
const videoFrame = new VideoFrame(video);
applyFilter(videoFrame);
requestAnimationFrame(render);
})();
function applyFilter(videoFrame) {
const texture = device.importExternalTexture({ source: videoFrame });
const bindgroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: texture }],
});
// Finally, submit commands to GPU
}
Переносимость приложений по умолчанию
WebGPU заставляет вас запрашивать limits
. По умолчанию requestDevice()
возвращает GPUDevice, который может не соответствовать аппаратным возможностям физического устройства, но представляет собой разумный и наименьший общий знаменатель для всех графических процессоров. Требуя от разработчиков запрашивать ограничения устройств, WebGPU гарантирует, что приложения будут работать на максимально возможном количестве устройств.
Обработка холста
WebGL автоматически управляет холстом после создания контекста WebGL и предоставления атрибутов контекста , таких как альфа, сглаживание, colorSpace, глубина, conservationDrawingBuffer или трафарет.
С другой стороны, WebGPU требует от вас самостоятельного управления холстом. Например, для достижения сглаживания в WebGPU необходимо создать мультисэмплированную текстуру и выполнить рендеринг на ней. Затем мультисэмплированная текстура преобразуется в обычную текстуру и отображается на холсте. Такое ручное управление позволяет выводить изображение на любое количество холстов из одного объекта GPUDevice . В отличие от этого, WebGL может создавать только один контекст для каждого холста.
Ознакомьтесь с демонстрацией WebGPU Multiple Canvases .
Кстати, в настоящее время в браузерах существует ограничение на количество холстов WebGL на странице. На момент написания статьи Chrome и Safari могут использовать до 16 холстов WebGL одновременно; Firefox может создавать до 200 таких холстов. С другой стороны, ограничений на количество холстов WebGPU на странице нет.

Полезные сообщения об ошибках
WebGPU предоставляет стек вызовов для каждого сообщения, возвращаемого API. Это позволяет быстро определить, где в коде произошла ошибка, что полезно для отладки и исправления ошибок.
Помимо предоставления стека вызовов, сообщения об ошибках WebGPU также просты для понимания и содержат рекомендации по их устранению. Сообщения об ошибках обычно содержат описание ошибки и рекомендации по её устранению.
WebGPU также позволяет назначить каждому объекту WebGPU собственную label
. Эта метка затем используется браузером в сообщениях об ошибках GPUError, предупреждениях консоли и инструментах разработчика браузера.
От имен к индексам
В WebGL многие вещи связаны именами. Например, можно объявить uniform-переменную myUniform
в GLSL и получить её местоположение с помощью gl.getUniformLocation(program, 'myUniform')
. Это удобно, поскольку при неправильном вводе имени uniform-переменной возникает ошибка.
С другой стороны, в WebGPU всё полностью связано байтовым смещением или индексом (часто называемым местоположением ). Вы несёте ответственность за синхронизацию местоположений кода в WGSL и JavaScript.
Генерация MIP-текстур
В WebGL вы можете создать MIP-уровень текстуры 0, а затем вызвать gl.generateMipmap()
. После этого WebGL сгенерирует все остальные MIP-уровни автоматически.
В WebGPU вам необходимо генерировать MIP-текстуры самостоятельно. Встроенной функции для этого нет. Подробнее об этом решении см. в обсуждении спецификации . Вы можете использовать удобные библиотеки, такие как webgpu-utils , для генерации MIP-текстур или научиться делать это самостоятельно .
Буферы хранения и текстуры хранения
Унифицированные буферы поддерживаются как WebGL, так и WebGPU и позволяют передавать шейдерам постоянные параметры ограниченного размера. Буферы хранения, которые очень похожи на унифицированные буферы, поддерживаются только WebGPU и являются более мощными и гибкими, чем унифицированные буферы.
Данные буферов хранения, передаваемые шейдерам, могут быть значительно больше, чем данные унифицированных буферов. Хотя в спецификации указано, что привязки унифицированных буферов могут иметь размер до 64 КБ (см.
maxUniformBufferBindingSize
), максимальный размер привязки буфера хранения в WebGPU составляет не менее 128 МБ (см.maxStorageBufferBindingSize
).Буферы хранения доступны для записи и поддерживают некоторые атомарные операции, в то время как однородные буферы доступны только для чтения. Это позволяет реализовывать новые классы алгоритмов.
Привязки буферов хранения поддерживают массивы размером со время выполнения для более гибких алгоритмов, в то время как в шейдере необходимо обеспечить единообразные размеры массивов буферов.
Текстуры хранилища поддерживаются только в WebGPU и играют для текстур ту же роль, что буферы хранилища для унифицированных буферов. Они более гибкие, чем обычные текстуры, и поддерживают произвольную запись (а в будущем и чтение).
Изменения буфера и текстуры
В WebGL вы можете создать буфер или текстуру, а затем изменить ее размер в любое время, например, с помощью gl.bufferData()
и gl.texImage2D()
соответственно.
В WebGPU буферы и текстуры неизменяемы. Это означает, что вы не можете изменить их размер, назначение или формат после их создания. Вы можете изменить только их содержимое.
Различия в космических соглашениях
В WebGL диапазон пространства отсечения Z составляет от -1 до 1. В WebGPU диапазон пространства отсечения Z составляет от 0 до 1. Это означает, что объекты со значением z 0 находятся ближе всего к камере, а объекты со значением z 1 находятся дальше всего.
WebGL использует соглашение OpenGL, где ось Y направлена вверх, а ось Z — к зрителю. WebGPU использует соглашение Metal, где ось Y направлена вниз, а ось Z — за пределы экрана. Обратите внимание, что ось Y направлена вниз в координатах буфера кадра, области просмотра и фрагмента/пикселя. В пространстве клипа ось Y по-прежнему направлена вверх, как и в WebGL.
Благодарности
Благодарим Корентина Валлеза, Грегга Тавареса, Стивена Уайта, Кена Рассела и Рэйчел Эндрю за рецензирование этой статьи.
Я также рекомендую сайт WebGPUFundamentals.org для глубокого изучения различий между WebGPU и WebGL.