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

François Beaufort
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 на Windows использовался FXC (FX Compiler). FXC работает, но в нем нет функций и оптимизаций, которые есть в DXC.

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

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

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

Если в 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 с запросом временной метки.
Пример вычисления стаи птиц с запросом временной метки

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

Чтобы упростить работу разработчиков, теперь при создании вычислительного или графического конвейера можно опускать 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

Теперь при импорте GPUExternalTexture из HDR-видео с помощью importExternalTexture() можно задать целевое цветовое пространство "display-p3". Узнайте, как 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.

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

В класс wgpu::Instance добавлены методы HasWGSLLanguageFeature и EnumerateWGSLLanguageFeatures для работы с функциями языка WGSL. См. проблему 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 Texture Sharing, D3D11 multithread protected, Implicit Device Synchronization, Norm16 texture formats, Timestamp Query Inside Passes, Pixel Local Storage, Shader Features и Multi Planar Formats.

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

Это лишь некоторые из основных изменений. Ознакомьтесь с полным списком коммитов.

Что нового в WebGPU

Список всех тем, которые были рассмотрены в серии статей Что нового в WebGPU.

Chrome 155–156

Chrome 153–154

Chrome 151–152

Chrome 149–150

Chrome 147–148

Chrome 146

Chrome 145

Chrome 144

Chrome 143

Chrome 142

Chrome 141

Chrome 140

Chrome 139

Chrome 138

Chrome 137

Chrome 136

Chrome 135

Chrome 134

Chrome 133

Chrome 132

Chrome 131

Chrome 130

Chrome 129

Chrome 128

Chrome 127

Chrome 126

Chrome 125

Chrome 124

Chrome 123

Chrome 122

Chrome 121

Chrome 120

Chrome 119

Chrome 118

Chrome 117

Chrome 116

Chrome 115

Chrome 114

Chrome 113