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 będzie stopniowo rozszerzana 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 z przykładową aplikacją WebGPU działającą w Chrome na Androida.
Przykładowa aplikacja WebGPU działająca w Chrome na Androida.

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

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

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

Zapytania o sygnaturę czasową w przepustkach obliczeniowych i renderujących

Zapytania o sygnaturę czasową umożliwiają aplikacjom WebGPU dokładne (z dokładnością do nanosekundy) pomiar czasu wykonywania przez polecenia GPU obliczeń i przejść 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 teraz wykonywać te 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 mają być zapisywane wartości sygnatur czasowych.
  • 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.

Przyjrzyj się temu przykładowi 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 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 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ładem Compute Boids z zapytaniem o sygnaturę czasową.
Przykładowe zapytanie Compute Boids z sygnaturą czasową.

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

Aby zwiększyć komfort pracy programistów, 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 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 przewidzieć 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 typ stert pamięci dostępnych w adapterze. Ta eksperymentalna funkcja jest dostępna tylko wtedy, gdy włączona jest flaga „Funkcje deweloperskie WebGPU” chrome://flags/#enable-webgpu-developer-features. Zapoznaj się z tym przykładem i problemem 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 ze strony https://webgpureport.org z informacjami o stertach pamięci w informacjach o adapterze.
Informacje o pamięci adaptera wyświetlane na stronie https://webgpureport.org.

Aktualizacje Dawn

Dodano metody HasWGSLLanguageFeature i EnumerateWGSLLanguageFeatures w wgpu::Instance, aby obsługiwać funkcje 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 zgłoś 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);

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

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

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

Co nowego w WebGPU

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

Chrome 155–156

Chrome 153–154

Chrome 151–152

Chrome 149-150

Chrome 147–148

Chrome 146

Chrome 145

Chrome 144

Chrome 143

Chrome 142

Chrome 141

Chrome 140

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