Что нового в 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.

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

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

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

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

Запросы с использованием временных меток позволяют приложениям WebGPU точно (с точностью до наносекунды) измерять время, необходимое для выполнения вычислительных и рендеринговых проходов с помощью команд GPU. Они широко используются для получения информации о производительности и поведении рабочих нагрузок 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 Developer Features" по адресу chrome://flags/#enable-webgpu-developer-features во время разработки вашего приложения. Подробнее см. раздел "Квантование запросов с временными метками" .

Поскольку графические процессоры могут время от времени сбрасывать счетчик временных меток, что может привести к неожиданным значениям, таким как отрицательная разница между временными метками, я рекомендую вам ознакомиться с изменениями в репозитории Git , которые добавляют поддержку запросов по временным меткам в следующий пример 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 .

Утренние обновления

Для обработки языковых особенностей WGSL добавлены методы HasWGSLLanguageFeature и EnumerateWGSLLanguageFeatures в wgpu::Instance . См. проблему 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 создала официальный репозиторий Dawn на GitHub .

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

Что нового в WebGPU?

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

Хром 144

Хром 143

Хром 142

Хром 141

Хром 140

Хром 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