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łączone w Chrome 121 na urządzeniach z Androidem 12 lub nowszym, które mają procesor graficzny Qualcomm lub ARM.

W najbliższej przyszłości będziemy stopniowo zwiększać liczbę obsługiwanych urządzeń z Androidem, w tym tych z Androidem 11. Rozszerzenie zależy od dalszych testów i optymalizacji, które mają zapewnić płynne działanie w szerszym zakresie konfiguracji sprzętowych. Zobacz problem chromium:1497815.

Zrzut ekranu pokazujący przykład WebGPU działający w Chrome na Androida.
Przykład WebGPU działający w Chrome na Androida.

Korzystanie z kompilacji shaderów DXC zamiast FXC w Windows

Chrome korzysta teraz z mocy DXC (kompilator DirectX) do kompilowania shaderów na maszynach z systemem Windows D3D12 wyposażonych w układ graficzny SM6+. Wcześniej WebGPU używało do kompilacji shaderów w Windowsie kompilatora FXC (FX Compiler). Chociaż był funkcjonalny, FXC nie miał zestawu funkcji i optymalizacji wydajności obecnych w DXC.

Wstępne testy wykazały, że przy użyciu DXC prędkość kompilacji shadera obliczeniowego jest średnio wyższa o 20% w porównaniu z FXC.

Sygnatury czasowe zapytań w przelotach obliczeniowych i renderowania

Zapytania o znacznik czasu umożliwiają aplikacjom WebGPU dokładne (z dokładnością do nanosekundy) pomiary czasu wykonywania przez polecenia GPU przejść obliczeniowych i renderowania. 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 wykonać te czynności:

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

Zobacz przykład poniżej i problem 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 ataki oparte na pomiarze czasu zapytania dotyczące sygnatury czasowej są kwantowane z rozdzielczością 100 mikrosekund, co zapewnia dobry kompromis między dokładnością a bezpieczeństwem. W przeglądarce Chrome możesz wyłączyć kwantyzację sygnatury czasowej, włączając opcję „Funkcje dla deweloperów WebGPU” na poziomie chrome://flags/#enable-webgpu-developer-features podczas tworzenia aplikacji. Więcej informacji znajdziesz w artykule Kwantyzacja zapytań z sygnaturą czasową.

Ponieważ procesory graficzne mogą od czasu do czasu resetować licznik sygnatur czasowych, co może powodować nieoczekiwane wartości, takie jak ujemne różnice między sygnaturami czasowymi, zalecam sprawdzenie zmian w pliku git diff, które dodają obsługę zapytań dotyczących sygnatur czasowych do tego przykładu Compute Boids.

Zrzut ekranu pokazujący przykładowy program Compute Boids z zapytaniem o sygnaturę czasową
Przykładowy program Compute Boids wykorzystujący zapytanie z sygnaturą czasową.

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

Aby ułatwić pracę deweloperom, możesz teraz pominąć entryPoint modułu shadera podczas tworzenia potoku obliczeniowego lub renderowania. Jeśli w kodzie shadera nie zostanie znaleziony żaden unikalny punkt wejścia dla etapu shadera, zostanie wywołany błąd GPUValidationError. Zobacz poniższy przykład i problem 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 GPUExternalTexture z filmów HDR za pomocą importExternalTexture() możesz teraz ustawić "display-p3" przestrzeń kolorów docelowych. Dowiedz się, jak WebGPU obsługuje przestrzenie barw. Zobacz ten przykład i problem chromium:1330250.

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

Informacje o pamięci na stercie

Aby pomóc Ci przewidzieć ograniczenia pamięci podczas przydzielania dużych ilości podczas tworzenia aplikacji, requestAdapterInfo() udostępnia teraz informacje memoryHeaps, takie jak rozmiar i typ stosów pamięci dostępnej na adapterze. Ta eksperymentalna funkcja jest dostępna tylko wtedy, gdy opcja „Funkcje dla programistów WebGPU” jest włączona na stronie chrome://flags/#enable-webgpu-developer-features. Zobacz poniższy 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 sterowniku karty graficznej.
Informacje o pamięci adaptera są wyświetlane na stronie https://webgpureport.org.

Aktualizacje świtu

Do metod HasWGSLLanguageFeatureEnumerateWGSLLanguageFeatureswgpu::Instance dodano obsługę funkcji językowych WGSL. Zobacz problem dawn:2260.

Niestandardowa funkcja wgpu::Feature::BufferMapExtendedUsages umożliwia tworzenie bufora GPU za pomocą wgpu::BufferUsage::MapRead lub wgpu::BufferUsage::MapWrite i dowolnego innego wgpu::BufferUsage. Zobacz ten przykład i problem 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);

Opisane zostały następujące funkcje: udostępnianie tekstur ANGLE, D3D11 multithread protected, implikatorna synchronizacja urządzeń, formaty tekstur Norm16, zapytanie o stemplę czasu w przesyłanych passach, lokalne miejsce na piksele, funkcje shaderaformaty wielopłaskie.

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

Obejmuje to tylko niektóre najważniejsze informacje. Zapoznaj się z pełną listą commitów.

Co nowego w WebGPU

Lista wszystkich tematów omawianych w cyklu Co nowego w WebGPU.

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