Co nowego w WebGPU (Chrome 121)

François Beaufort
François Beaufort

Obsługa WebGPU na Androidzie

Zespół Chrome z przyjemnością informuje, że WebGPU jest teraz domyślnie włączony w Chrome 121 na urządzeniach z Androidem 12 lub nowszym, które są wyposażone w procesory graficzne Qualcomm i ARM.

W najbliższej przyszłości obsługa zostanie stopniowo rozszerzona na większą liczbę urządzeń z Androidem, w tym na urządzenia z Androidem 11. Wprowadzenie tej funkcji na większą skalę będzie zależeć od dalszych testów i optymalizacji, które zapewnią płynne działanie na szerszej gamie konfiguracji sprzętowych. Zobacz problem chromium:1497815.

Zrzut ekranu przedstawiający przykład WebGPU działający w Chrome na Androida.
Przykładowa aplikacja WebGPU uruchomiona w Chrome na Androida.

Używanie DXC zamiast FXC do kompilacji shaderów w systemie Windows

Chrome korzysta teraz z DXC (DirectX Compiler) do kompilowania shaderów na komputerach z systemem Windows D3D12 wyposażonych w sprzęt graficzny SM6+. Wcześniej WebGPU korzystało z FXC (FX Compiler) do kompilacji shaderów w systemie Windows. FXC działał, ale nie miał zestawu funkcji i optymalizacji wydajności dostępnych w DXC.

Wstępne testy pokazują, że w przypadku używania DXC szybkość kompilacji cieniowania obliczeniowego wzrasta średnio o 20% w porównaniu z FXC.

Zapytania dotyczące sygnatur czasowych w przepustach obliczeniowych i renderowania

Zapytania o znaczniki czasu umożliwiają aplikacjom WebGPU precyzyjne (z dokładnością do nanosekundy) pomiary czasu wykonywania przez GPU poleceń obliczeniowych i renderujących. Są one często używane do uzyskiwania informacji o wydajności i zachowaniu zadań GPU.

Gdy funkcja "timestamp-query" jest dostępna w GPUAdapter, możesz teraz wykonywać te czynności:

  • Poproś o GPUDevice z funkcją "timestamp-query".
  • Utwórz GPUQuerySet typu "timestamp".
  • Użyj znaków GPUComputePassDescriptor.timestampWritesGPURenderPassDescriptor.timestampWrites, aby określić, gdzie w GPUQuerySet mają być zapisywane wartości sygnatury czasowej.
  • Rozwiąż wartości sygnatury czasowej w GPUBuffer za pomocą resolveQuerySet().
  • Odczytaj wartości sygnatur czasowych, kopiując wyniki z GPUBuffer do procesora.
  • Dekoduj wartości sygnatury czasowej jako BigInt64Array.

Zapoznaj się z tym przykładem i wydaj polecenie 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();

Ze względu na obawy związane z atakami czasowymi zapytania o sygnatury czasowe są kwantyzowane z rozdzielczością 100 mikrosekund, co stanowi dobry kompromis między precyzją a bezpieczeństwem. W przeglądarce Chrome możesz wyłączyć kwantyzację sygnatur czasowych, włączając flagę „Funkcje deweloperskie WebGPU” w chrome://flags/#enable-webgpu-developer-features podczas tworzenia aplikacji. Więcej informacji znajdziesz w sekcji Kwantyzacja zapytań o sygnatury czasowe.

Procesory GPU mogą od czasu do czasu resetować licznik sygnatur czasowych, co może powodować nieoczekiwane wartości, np. ujemne różnice między sygnaturami czasowymi. Dlatego zalecam zapoznanie się ze zmianami w git diff, które dodają obsługę zapytań o sygnatury czasowe do tego przykładu Compute Boids.

Zrzut ekranu z przykładowym zapytaniem Compute Boids zawierającym zapytanie o sygnaturę czasową.
Przykładowe zapytanie Compute Boids z sygnaturą czasową.

Domyślne punkty wejścia do modułów cieniowania

Aby ułatwić pracę programistom, podczas tworzenia potoku obliczeniowego lub renderowania możesz teraz pominąć entryPoint modułu cieniowania. Jeśli w kodzie shadera nie zostanie znaleziony unikalny punkt wejścia dla etapu shadera, zostanie wywołany błąd GPUValidationError. Zapoznaj się z tym przykładem i problemem 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 }] },
});

Obsługa przestrzeni kolorów display-p3 jako przestrzeni kolorów GPUExternalTexture

Podczas importowania elementu GPUExternalTexture z filmów HDR z importExternalTexture() możesz teraz ustawić "display-p3" docelową przestrzeń kolorów. Dowiedz się, jak WebGPU obsługuje przestrzenie kolorów. Zapoznaj się z tym przykładem i problemem chromium:1330250.

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

Informacje o stertach pamięci

Aby pomóc Ci przewidywać ograniczenia pamięci podczas przydzielania dużych ilości pamięci w trakcie tworzenia aplikacji, requestAdapterInfo() udostępnia teraz informacje o memoryHeaps, takie jak rozmiar i rodzaj stert pamięci dostępnych w adapterze. Ta eksperymentalna funkcja jest dostępna tylko wtedy, gdy włączona jest flaga „Funkcje deweloperskie WebGPU” na stronie chrome://flags/#enable-webgpu-developer-features. Zobacz ten przykład i problem 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)   { /* ... */ }
}
Zrzut ekranu strony https://webgpureport.org z informacjami o stertach pamięci w informacjach o adapterze.
Stosy pamięci informacji o adapterze widoczne na stronie https://webgpureport.org.

Aktualizacje o świcie

Metody HasWGSLLanguageFeatureEnumerateWGSLLanguageFeatureswgpu::Instance zostały dodane w celu obsługi funkcji języka WGSL. Zobacz problem dawn:2260.

Niestandardowa funkcja wgpu::Feature::BufferMapExtendedUsages umożliwia utworzenie bufora GPU z wartościami wgpu::BufferUsage::MapRead lub wgpu::BufferUsage::MapWrite oraz dowolnymi innymi wartościami wgpu::BufferUsage. Zapoznaj się z tym przykładem i wyślij 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);

Udokumentowano te funkcje: ANGLE Texture Sharing, D3D11 multithread protected, Implicit Device Synchronization, Norm16 texture formats, Timestamp Query Inside Passes, Pixel Local Storage, Shader FeaturesMulti Planar Formats.

Zespół Chrome utworzył oficjalne repozytorium GitHub dla Dawn.

Obejmuje to tylko niektóre z najważniejszych informacji. Zapoznaj się z pełną listą zatwierdzeń.

Nowości w WebGPU

Lista wszystkich tematów omówionych w serii Nowości w WebGPU.

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