Что нового в WebGPU (Chrome 121)

Франсуа Бофор
François Beaufort

Поддержка WebGPU на Android

Команда Chrome рада сообщить, что WebGPU теперь включен по умолчанию в Chrome 121 на устройствах под управлением Android 12 и более поздних версий, оснащенных графическими процессорами Qualcomm и ARM.

В ближайшем будущем поддержка будет постепенно расширяться и охватывать более широкий спектр устройств Android, в том числе работающих на Android 11. Это расширение будет зависеть от дальнейшего тестирования и оптимизации, чтобы обеспечить бесперебойную работу в более широком диапазоне аппаратных конфигураций. См. выпуск chromium:1497815 .

Снимок экрана с примером WebGPU, работающим в Chrome для Android.
Пример WebGPU, работающий в Chrome для Android.

Используйте DXC вместо FXC для компиляции шейдеров в Windows.

Chrome теперь использует возможности DXC (компилятор DirectX) для компиляции шейдеров на компьютерах Windows D3D12, оснащенных графическим оборудованием SM6+. Раньше WebGPU использовал FXC (FX Compiler) для компиляции шейдеров в Windows. Несмотря на свою функциональность, FXC не имел набора функций и оптимизации производительности, присутствующих в DXC.

Первоначальное тестирование показывает среднее увеличение скорости компиляции вычислительных шейдеров на 20 % при использовании DXC по сравнению с FXC.

Запросы меток времени в проходах вычислений и рендеринга

Запросы временных меток позволяют приложениям WebGPU точно измерять (с точностью до наносекунды), сколько времени требуется их командам графического процессора для выполнения проходов вычислений и рендеринга. Они активно используются для получения информации о производительности и поведении рабочих нагрузок графического процессора.

Когда в GPUAdapter доступна функция "timestamp-query" , вы можете делать следующие вещи:

  • Запросите GPUDevice с помощью функции "timestamp-query" .
  • Создайте GPUQuerySet типа "timestamp" .
  • Используйте GPUComputePassDescriptor.timestampWrites и GPURenderPassDescriptor.timestampWrites , чтобы определить, куда записывать значения метки времени в GPUQuerySet .
  • Преобразуйте значения временных меток в GPUBuffer с помощью resolveQuerySet() .
  • Считайте значения временных меток обратно, скопировав результаты из GPUBuffer в ЦП.
  • Декодируйте значения временных меток как BigInt64Array .

См. следующий пример и выполните команду Dawn:1800 .

const adapter = await navigator.gpu.requestAdapter();
if (!adapter.features.has("timestamp-query")) {
  throw new Error("Timestamp query feature is not available");
}
// Explicitly request timestamp query feature.
const device = await adapter.requestDevice({
  requiredFeatures: ["timestamp-query"],
});
const commandEncoder = device.createCommandEncoder();

// Create a GPUQuerySet which holds 2 timestamp query results: one for the
// beginning and one for the end of compute pass execution.
const querySet = device.createQuerySet({ type: "timestamp", count: 2 });
const timestampWrites = {
  querySet,
  beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins.
  endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends.
};
const passEncoder = commandEncoder.beginComputePass({ timestampWrites });
// TODO: Set pipeline, bind group, and dispatch work to be performed.
passEncoder.end();

// Resolve timestamps in nanoseconds as a 64-bit unsigned integer into a GPUBuffer.
const size = 2 * BigInt64Array.BYTES_PER_ELEMENT;
const resolveBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
});
commandEncoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);

// Read GPUBuffer memory.
const resultBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
});
commandEncoder.copyBufferToBuffer(resolveBuffer, 0, resultBuffer, 0, size);

// Submit commands to the GPU.
device.queue.submit([commandEncoder.finish()]);

// Log compute pass duration in nanoseconds.
await resultBuffer.mapAsync(GPUMapMode.READ);
const times = new BigInt64Array(resultBuffer.getMappedRange());
console.log(`Compute pass duration: ${Number(times[1] - times[0])}ns`);
resultBuffer.unmap();

Из-за проблем с временными атаками запросы меток времени квантуются с разрешением 100 микросекунд, что обеспечивает хороший компромисс между точностью и безопасностью. В браузере Chrome вы можете отключить квантование временных меток, включив флаг «Функции разработчика WebGPU» на chrome://flags/#enable-webgpu-developer-features во время разработки вашего приложения. Дополнительную информацию см. в разделе Квантование запросов временных меток .

Поскольку графические процессоры могут время от времени сбрасывать счетчик меток времени, что может привести к получению неожиданных значений, таких как отрицательные дельты между метками времени, я рекомендую вам ознакомиться с изменениями git diff , которые добавляют поддержку запросов меток времени в следующий пример Compute Boids .

Снимок экрана: пример Compute Boids с запросом метки времени.
Пример Compute Boids с запросом метки времени.

Точки входа по умолчанию в шейдерные модули

Чтобы улучшить взаимодействие с разработчиком, теперь вы можете опустить entryPoint в модуле шейдера при создании конвейера вычислений или рендеринга. Если в коде шейдера не найдена уникальная точка входа для этапа шейдера, будет вызвана ошибка GPUValidationError . См. следующий пример и выполните команду Dawn:2254 .

const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
const module = myDevice.createShaderModule({ code });
const format = navigator.gpu.getPreferredCanvasFormat();
const pipeline = await myDevice.createRenderPipelineAsync({
  layout: "auto",
  vertex: { module, entryPoint: "vertexMain" },
  fragment: { module, entryPoint: "fragmentMain", targets: [{ format }] },
  vertex: { module },
  fragment: { module, targets: [{ format }] },
});

Поддержка display-p3 как цветового пространства GPUExternalTexture.

Теперь вы можете установить цветовое пространство назначения "display-p3" при импорте GPUExternalTexture из HDR-видео с помощью importExternalTexture() . Узнайте, как WebGPU обрабатывает цветовые пространства . См. следующий пример и введите chromium:1330250 .

// Create texture from HDR video.
const video = document.querySelector("video");
const texture = myDevice.importExternalTexture({
  source: video,
  colorSpace: "display-p3",
});

Информация о кучах памяти

Чтобы помочь вам предвидеть ограничения памяти при выделении больших объемов во время разработки вашего приложения, requestAdapterInfo() теперь предоставляет информацию memoryHeaps такую ​​как размер и тип кучи памяти, доступной на адаптере. Эта экспериментальная функция доступна только в том случае, если включен флаг «Функции разработчика WebGPU» в chrome://flags/#enable-webgpu-developer-features . См. следующий пример и выполните команду Dawn:2249 .

const adapter = await navigator.gpu.requestAdapter();
const adapterInfo = await adapter.requestAdapterInfo();

for (const { size, properties } of adapterInfo.memoryHeaps) {
  console.log(size); // memory heap size in bytes
  if (properties & GPUHeapProperty.DEVICE_LOCAL)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_VISIBLE)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_COHERENT) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_UNCACHED) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_CACHED)   { /* ... */ }
}
Снимок экрана https://webgpureport.org, на котором показаны кучи памяти в информации об адаптере.
Кучи памяти с информацией об адаптере показаны на https://webgpureport.org .

Обновления рассвета

Для обработки функций языка WGSL были добавлены методы HasWGSLLanguageFeature и EnumerateWGSLLanguageFeatures в wgpu::Instance . См. выпуск Dawn:2260 .

Нестандартная wgpu::Feature::BufferMapExtendedUsages позволяет создавать буфер графического процессора с помощью wgpu::BufferUsage::MapRead или wgpu::BufferUsage::MapWrite и любого другого wgpu::BufferUsage . См. следующий пример и выполните команду Dawn:2204 .

wgpu::BufferDescriptor descriptor = {
  .size = 128,
  .usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::Uniform
};
wgpu::Buffer uniformBuffer = device.CreateBuffer(&descriptor);

uniformBuffer.MapAsync(wgpu::MapMode::Write, 0, 128,
   [](WGPUBufferMapAsyncStatus status, void* userdata)
   {
      wgpu::Buffer* buffer = static_cast<wgpu::Buffer*>(userdata);
      memcpy(buffer->GetMappedRange(), data, sizeof(data));
   },
   &uniformBuffer);

Были задокументированы следующие функции: общий доступ к текстурам ANGLE , многопоточная защита D3D11 , неявная синхронизация устройств , форматы текстур Norm16 , запросы временных меток внутри проходов , локальное хранилище пикселей , функции шейдеров и многоплоскостные форматы .

Команда Chrome создала официальный репозиторий GitHub для Dawn .

Это касается только некоторых ключевых моментов. Ознакомьтесь с исчерпывающим списком коммитов .

Что нового в WebGPU

Список всего, что было описано в серии «Что нового в WebGPU» .

Хром 131

Хром 130

Хром 129

Хром 128

Хром 127

Хром 126

Хром 125

Хром 124

Хром 123

Хром 122

Хром 121

Хром 120

Хром 119

Хром 118

Хром 117

Хром 116

Хром 115

Хром 114

Хром 113