Co nowego w WebGPU (Chrome 121)

François Beaufort
François Beaufort

Obsługa WebGPU na Androidzie

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

Stopniowo będziemy rozszerzać tę obsługę na większą liczbę urządzeń z Androidem, w tym na urządzenia z Androidem 11. To rozszerzenie będzie zależeć od dalszych testów i optymalizacji, aby zapewnić bezproblemową obsługę w większej gamie konfiguracji sprzętowych. Zobacz problem chromium:1497815.

Zrzut ekranu pokazujący przykładową platformę WebGPU działającą w Chrome na Androida.
Przykładowy procesor WebGPU działający w Chrome na Androida.

Używaj DXC zamiast FXC do kompilowania danych do cieniowania w systemie Windows

Chrome korzysta teraz z technologii DXC (DirectX Compiler) do kompilowania cieniowania na komputerach z systemem Windows D3D12 i sprzętem graficznym SM6+. Wcześniej do kompilowania cieniowania w systemie Windows rozwiązanie WebGPU opierało się na FXC (FX Compiler). Choć pakiet FXC działał sprawnie, brakowało mu zestawu funkcji i optymalizacji wydajności, jakie pojawiły się w wersji DXC.

Wstępne testy pokazują średnio o 20% większą szybkość kompilowania kodu cieniowania obliczeniowego w przypadku korzystania z DXC w porównaniu z FXC.

Zapytania dotyczące sygnatur czasowych w przebiegach operacji obliczeniowych i renderowania

Zapytania dotyczące sygnatury czasowej pozwalają aplikacjom WebGPU dokładnie mierzyć (z dokładnością do nanosekundy) czas, jaki polecenia GPU potrzebują na wykonanie obliczeń i renderowania przebiegów. Są one intensywnie używane do uzyskiwania wglądu w wydajność i zachowanie zadań GPU.

Gdy funkcja "timestamp-query" będzie dostępna w GPUAdapter, będziesz mieć możliwość wykonywania tych czynności:

  • Poproś o GPUDevice z funkcją "timestamp-query".
  • Utwórz GPUQuerySet typu "timestamp".
  • Użyj GPUComputePassDescriptor.timestampWrites i GPURenderPassDescriptor.timestampWrites, aby określić, gdzie w GPUQuerySet zapisywać wartości sygnatury czasowej.
  • Przekształć wartości sygnatury czasowej na GPUBuffer za pomocą funkcji resolveQuerySet().
  • Odczytuj wartości sygnatur czasowych z powrotem, kopiując wyniki z urządzenia GPUBuffer do procesora.
  • Dekoduj wartości sygnatury czasowej jako BigInt64Array.

Zobacz ten przykład i problem dawny: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 problemy związane z czasem ataku zapytania dotyczące sygnatury czasowej są poddawane kwantyzacji z dokładnością do 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 „Funkcje dla programistów WebGPU”. flag na chrome://flags/#enable-webgpu-developer-features. Więcej informacji znajdziesz w sekcji Kwantyzacja zapytań dotyczących sygnatury czasowej.

Procesory graficzne mogą od czasu do czasu resetować licznik sygnatur czasowych, co może prowadzić do nieoczekiwanych wartości, takich jak ujemne delta między sygnaturami czasowymi, dlatego zalecamy zapoznanie się z zmianami git diff, które dodaje obsługę zapytań dotyczących sygnatury czasowej do poniższego przykładu Compute Boids.

Zrzut ekranu pokazujący przykładową zawartość Compute Boids z zapytaniem o sygnaturę czasową.
Przykładowy plik Compute Boids z zapytaniem o sygnaturę czasową.

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

Aby zwiększyć wygodę programistów, podczas tworzenia potoku obliczeniowego lub renderowania możesz teraz pominąć element entryPoint modułu cieniowania. Jeśli w kodzie algorytmu cieniowania nie ma unikalnego punktu wejścia dla etapu cieniowania, wywoływany jest błąd GPUValidationError. Zobacz ten przykład i problem świt: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ługuj display-p3 jako przestrzeń kolorów GPUExternalTexture

Podczas importowania tekstu GPUExternalTexture z filmów HDR za pomocą importExternalTexture() możesz teraz ustawić docelową przestrzeń kolorów "display-p3". Zobacz, jak WebGPU obsługuje przestrzenie kolorów. Zobacz ten przykład i problem z 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 przewidzieć ograniczenia pamięci podczas przydzielania dużych ilości danych podczas tworzenia aplikacji, requestAdapterInfo() udostępnia teraz informacje memoryHeaps, takie jak rozmiar i typ stosu pamięci dostępne w adapterze. Ta eksperymentalna funkcja jest dostępna tylko wtedy, gdy „Funkcje dla programistów WebGPU” flaga na chrome://flags/#enable-webgpu-developer-features jest włączona. Zobacz ten przykład i problem świt: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 przedstawiający sterty pamięci w informacjach o adapterze.
Stosy pamięci informacji o karcie są widoczne na stronie https://webgpureport.org.

Aktualizacje o świcie

Metody HasWGSLLanguageFeature i EnumerateWGSLLanguageFeatures w systemie wgpu::Instance zostały dodane, aby obsługiwać funkcje języka WGSL. Zapoznaj się z problemem dawnych:2260.

Niestandardowa funkcja wgpu::Feature::BufferMapExtendedUsages pozwala utworzyć bufor GPU za pomocą tagów wgpu::BufferUsage::MapRead lub wgpu::BufferUsage::MapWrite i dowolnych innych elementów wgpu::BufferUsage. Zobacz ten przykład i problem dawny: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);

Udokumentowaliśmy te funkcje: udostępnianie tekstur w ANGLE, zabezpieczona wielowątkowo funkcja D3D11, pośrednia synchronizacja urządzenia, formaty tekstur Norm16, Sygnatury czasowe zapytania w kartach, pamięć lokalna Pixela, funkcje shader i formaty multiplanar.

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

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

Co nowego w WebGPU

Lista wszystkiego, co zostało omówione w serii Co nowego w WebGPU.

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