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.

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ład WebGPU działający w Chrome na Androida.
Przykład 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 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). 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 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) zliczanie czasu wykonywania przez polecenia GPU przejść obliczeniowych i renderowania. Są one często wykorzystywane 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 w element GPUBuffer za pomocą 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 przykład 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ą.

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 program Compute Boids wykorzystujący zapytanie z sygnaturą czasową.

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

Aby ułatwić pracę programistom, 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. 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 GPUExternalTexture z filmów HDR za pomocą importExternalTexture() możesz teraz ustawić "display-p3" docelowa przestrzeń kolorów. 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 włączona jest flaga „Funkcje dla programistów WebGPU” na 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 o świcie

Metody HasWGSLLanguageFeature i EnumerateWGSLLanguageFeatures w systemie wgpu::Instance zostały dodane, aby obsługiwać funkcje języka 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 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);

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