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

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

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

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

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

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

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

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

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

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

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

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

  • Запросите GPUDevice с функцией "timestamp-query" .
  • Создайте GPUQuerySet типа "timestamp" .
  • Используйте GPUComputePassDescriptor.timestampWrites и GPURenderPassDescriptor.timestampWrites для определения места записи значений временных меток в GPUQuerySet .
  • Разрешите значения временных меток в GPUBuffer с помощью resolveQuerySet() .
  • Считывание значений временных меток путем копирования результатов из GPUBuffer в CPU.
  • Декодировать значения временных меток как 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 с запросом временной метки.
Пример вычисления 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 Developer Features» на странице 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 .

Обновления Dawn

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

Нестандартная функция wgpu::Feature::BufferMapExtendedUsages позволяет создавать буфер GPU с помощью 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» .

Хром 139

Хром 138

Хром 137

Хром 136

Хром 135

Хром 134

Хром 133

Хром 132

Хром 131

Хром 130

Хром 129

Хром 128

Хром 127

Хром 126

Хром 125

Хром 124

Хром 123

Хром 122

Хром 121

Хром 120

Хром 119

Хром 118

Хром 117

Хром 116

Хром 115

Хром 114

Хром 113