WebGPU: odblokowywanie dostępu do nowoczesnego GPU w przeglądarce

Dowiedz się, jak WebGPU wykorzystuje możliwości karty graficznej, aby przyspieszyć działanie systemów uczących się i poprawić renderowanie grafiki.

Nowy interfejs WebGPU API zapewnia ogromne wzrosty wydajności w przypadku obciążeń związanych z grafiką i uczeniem maszynowym. Z tego artykułu dowiesz się, dlaczego WebGPU jest lepszym rozwiązaniem niż obecne WebGL, a także co nowego pojawi się w przyszłości. Najpierw jednak wyjaśnimy, dlaczego powstało WebGPU.

Kontekst WebGPU

WebGL pojawił się w Chrome w 2011 roku. Dzięki temu, że WebGL umożliwia aplikacjom internetowym korzystanie z kart graficznych, w internecie można uzyskać niesamowite wrażenia – od Google Earth po interaktywne teledyski, a także prezentacje nieruchomości w 3D. WebGL opiera się na rodzinie interfejsów API OpenGL, która została po raz pierwszy opracowana w 1992 r. To było dawno temu. Od tego czasu sprzęt GPU znacznie się rozwinął.

Aby nadążyć za tą ewolucją, opracowaliśmy nowe interfejsy API, które umożliwiają bardziej efektywną współpracę z nowoczesnym sprzętem GPU. interfejsy API, takie jak Direct3D 12, MetalVulkan; Te nowe interfejsy API obsługują nowe i wymagające przypadki użycia programowania na GPU, takie jak gwałtowny rozwój uczenia maszynowego i ulepszanie algorytmów renderowania. WebGPU jest następcą WebGL i wprowadza do sieci nową klasę nowoczesnych interfejsów API.

WebGPU otwiera wiele nowych możliwości programowania GPU w przeglądarce. Lepiej odzwierciedla ono działanie nowoczesnego sprzętu GPU, a zarazem tworzy podstawę dla bardziej zaawansowanych funkcji GPU w przyszłości. Interfejs API jest rozwijany od 2017 r. w ramach grupy W3C „GPU for the Web”, w której współpracują m.in. firmy Apple, Google, Mozilla, Microsoft i Intel. Po 6 latach pracy możemy w końcu ogłosić, że jedna z największych nowości na platformie internetowej jest już dostępna.

WebGPU jest już dostępne w Chrome 113 na systemach ChromeOS, macOS i Windows, a wkrótce pojawi się na innych platformach. Dziękujemy wszystkim, którzy przyczynili się do rozwoju Chromium, a w szczególności firmie Intel.

Przyjrzyjmy się teraz kilku ekscytujących zastosowaniach WebGPU.

Odblokuj nowe obciążenia GPU do renderowania

Funkcje WebGPU, takie jak shadery obliczeniowe, umożliwiają przenoszenie nowych klas algorytmów na GPU. Na przykład algorytmy, które mogą dodawać więcej dynamicznych szczegółów do scen, symulować zjawiska fizyczne i tak dalej. Niektóre zadania, które wcześniej można było wykonywać tylko w JavaScript, można teraz przenieść na procesor graficzny.

Ten film pokazuje, jak algorytm marching cubes służy do triangulacji powierzchni tych metakul. W pierwszych 20 sekundach filmu algorytm, gdy działa w JavaScript, ma problemy z nadążaniem za stroną, która działa z prędkością tylko 8 FPS, co powoduje niepłynną animację. Aby zachować wydajność w JavaScript, musielibyśmy znacznie obniżyć poziom szczegółów.

Przejście z tego samego algorytmu na shader obliczeniowy to różnica jak dzień i noc. W filmie można to zobaczyć po 20 sekundach. Strona działa teraz znacznie płynniej, ponieważ wyświetla się z płynną częstotliwością 60 FPS, a pozostało jeszcze sporo miejsca na inne efekty. Poza tym główna pętla JavaScriptu strony jest całkowicie dostępna dla innych zadań, co zapewnia płynne działanie interakcji ze stroną.

Demonstracja metaballs

WebGPU umożliwia też tworzenie złożonych efektów wizualnych, które wcześniej nie były możliwe. W poniższym przykładzie, stworzonym w popularnej bibliotece Babylon.js, powierzchnia oceanu jest symulowana całkowicie na karcie graficznej. Realistyczna dynamika powstaje dzięki dodawaniu do siebie wielu niezależnych fal. Symulowanie każdej fali bezpośrednio byłoby jednak zbyt kosztowne.

Prezentacja demo oceanu

Dlatego w demo używamy zaawansowanego algorytmu o nazwie szybka transformacja Fouriera. Zamiast przedstawiania wszystkich fal jako złożonych danych pozycyjnych, używa danych spektralnych, które są znacznie wydajniejsze do wykonywania obliczeń. Następnie w każdym ujęciu wykorzystuje się transformację Fouriera do przekształcenia danych widmowych na dane pozycyjne, które reprezentują wysokość fal.

Szybsze wnioskowanie ML

WebGPU jest też przydatne do przyspieszania uczenia maszynowego, które w ostatnich latach stało się głównym zastosowaniem procesorów GPU.

Od dawna twórcy treści korzystają z interfejsu API do renderowania WebGL do wykonywania operacji innych niż renderowanie, takich jak obliczenia systemów uczących się. Wymaga to jednak rysowania pikseli trójkątów w celu zainicjowania obliczeń oraz starannego pakowania i rozpakowywania danych tensora w teksturze zamiast ogólnego dostępu do pamięci.

Ilustracja nieefektywności pojedynczego operatora ML podczas wykonywania za pomocą WebGL, w tym zbędne wczytywanie pamięci, zbędne obliczenia i niewiele wartości zapisywanych na wątku.
Jednokrotne wykonanie operatora ML za pomocą WebGL.

Korzystanie z WebGL w taki sposób wymaga od deweloperów dostosowania kodu do wymagań interfejsu API zaprojektowanego tylko do rysowania. W połączeniu z brakiem podstawowych funkcji, takich jak dostęp do wspólnej pamięci między obliczeniami, prowadzi to do powielania pracy i nieoptymalnej wydajności.

Shadery obliczeniowe to główna nowa funkcja WebGPU, która rozwiązuje te problemy. Shadery obliczeniowe zapewniają bardziej elastyczny model programowania, który wykorzystuje potencjał równoległy GPU, nie będąc ograniczony ścisłą strukturą operacji renderowania.

Różne zwiększenia wydajności w shaderach obliczeniowych WebGPU, w tym ładowanie współdzielonej pamięci, współdzielone obliczenia i elastyczne zapisywanie danych do pamięci.
Efektywność shaderów obliczeniowych WebGPU.

Shadery obliczeniowe dają więcej możliwości udostępniania danych i wyników obliczeń w ramach grup shaderów, co zwiększa wydajność. Może to przynieść znaczne korzyści w porównaniu z wcześniejszymi próbami użycia WebGL do tego samego celu.

Jako przykład wzrostu wydajności, jaki może to przynieść, początkowe przeniesienie modelu dyfuzji obrazu do TensorFlow.js pokazuje 3-krotny wzrost wydajności na różnych urządzeniach po przeniesieniu z WebGL do WebGPU. Na niektórych testowanych urządzeniach obraz został wyrenderowany w mniej niż 10 sekund. Ponieważ był to wczesny port, uważamy, że można jeszcze bardziej ulepszyć zarówno WebGPU, jak i TensorFlow.js. Przeczytaj artykuł Co nowego w ML w internecie w 2023 r.? Sesja na konferencji Google I/O.

WebGPU to jednak nie tylko udostępnianie funkcji GPU w internecie.

Zaprojektowane z myślą o JavaScript

Funkcje umożliwiające te zastosowania są od jakiegoś czasu dostępne dla deweloperów platform na komputery i urządzenia mobilne. Naszym wyzwaniem było udostępnienie ich w sposób, który sprawia wrażenie naturalnego elementu platformy internetowej.

WebGPU zostało opracowane z uwzględnieniem doświadczeń deweloperów, którzy od ponad 10 lat wykonują niesamowite rzeczy z użyciem WebGL. Udało nam się zebrać informacje o problemach, z którymi się spotkali, o wąskich gardłach, na które natrafili, i o problemach, które zgłosili, i przekazać je w ramach tego nowego interfejsu API.

Zauważyliśmy, że model globalnego stanu WebGL utrudnia i utrudnia tworzenie niezawodnych, składanych bibliotek i aplikacji. WebGPU znacznie zmniejsza ilość stanu, który deweloperzy muszą śledzić podczas wysyłania poleceń GPU.

Zdajemy sobie sprawę, że debugowanie aplikacji WebGL jest uciążliwe, dlatego WebGPU zawiera bardziej elastyczne mechanizmy obsługi błędów, które nie pogarszają wydajności. Dołożyliśmy wszelkich starań, aby każda wiadomość z interfejsu API była zrozumiała i użyteczna.

Zauważyliśmy też, że w przypadku złożonych aplikacji WebGL często wąskim gardłem jest nadmierna liczba wywołań JavaScript. W rezultacie interfejs WebGPU API jest mniej „gadatliwy”, więc możesz osiągnąć więcej przy mniejszym wykorzystaniu wywołań funkcji. Skupiamy się na przeprowadzaniu kompleksowej weryfikacji na wstępie, aby pętla rysowania była jak najbardziej zwięzła. Oferujemy też nowe interfejsy API, takie jak Render Bundles, które umożliwiają wcześniejsze rejestrowanie dużej liczby poleceń rysowania i odtwarzanie ich za pomocą jednego wywołania.

Aby pokazać, jak wielką różnicę może zrobić funkcja taka jak renderowanie pakietów, przedstawiamy kolejne demo z Babylon.js. Jego procesor graficzny WebGL 2 może wykonywać wszystkie wywołania JavaScriptu, aby renderować tę scenę galerii sztuki około 500 razy na sekundę. To całkiem nieźle.

Galeria sztuki

Ich procesor graficzny WebGPU umożliwia jednak funkcję, którą nazywają renderowaniem migawki. Ta funkcja oparta na pakietach renderowania WebGPU pozwala przesyłać tę samą scenę ponad 10 razy szybciej. Dzięki temu znacznie zmniejszony nakład pozwala WebGPU na renderowanie bardziej złożonych scen, a także umożliwia aplikacjom równoległe wykonywanie większej liczby zadań w języku JavaScript.

Nowoczesne interfejsy API grafiki mają opinię skomplikowanych, ponieważ rezygnują z prostoty na rzecz możliwości ekstremalnej optymalizacji. WebGPU skupia się natomiast na kompatybilności między platformami i w większości przypadków automatycznie obsługuje tradycyjnie trudne tematy, takie jak synchronizacja zasobów.

Ma to przyjemny efekt uboczny, ponieważ WebGPU jest łatwy do nauczenia i użycia. Korzysta z dotychczasowych funkcji platformy internetowej do wykonywania takich czynności jak wczytywanie obrazów i filmów oraz wykorzystuje znane wzorce JavaScriptu, takie jak obietnice (ang. promise) do wykonywania operacji asynchronicznych. Dzięki temu ograniczysz do minimum ilość stałego kodu. Pierwszy trójkąt na ekranie możesz uzyskać za pomocą mniej niż 50 wierszy kodu.

<canvas id="canvas" width="512" height="512"></canvas>
<script type="module">
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();

  const context = canvas.getContext("webgpu");
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({ device, format });

  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 shaderModule = device.createShaderModule({ code });
  const pipeline = device.createRenderPipeline({
    layout: "auto",
    vertex: {
      module: shaderModule,
      entryPoint: "vertexMain",
    },
    fragment: {
      module: shaderModule,
      entryPoint: "fragmentMain",
      targets: [{ format }],
    },
  });
  const commandEncoder = device.createCommandEncoder();
  const colorAttachments = [
    {
      view: context.getCurrentTexture().createView(),
      loadOp: "clear",
      storeOp: "store",
    },
  ];
  const passEncoder = commandEncoder.beginRenderPass({ colorAttachments });
  passEncoder.setPipeline(pipeline);
  passEncoder.draw(3);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
</script>

Podsumowanie

Cieszymy się, że WebGPU otwiera przed nami nowe możliwości na platformie internetowej. Z niecierpliwością czekamy na wszystkie nowe zastosowania WebGPU, które wymyślicie.

Wokół WebGL powstał bogaty ekosystem bibliotek i ramek, który chętnie przyjmie WebGPU. Obsługa WebGPU jest w trakcie implementacji lub już zakończona w wielu popularnych bibliotekach Javascript WebGL, a w niektórych przypadkach korzystanie z zalet WebGPU może być tak proste jak zmiana pojedynczej flagi.

Babylon.js, Construct 3, Google Earth, Google Meet, PlayCanvas, Sketchfab, Three.JS, TensorFlow.js i Unity.
Platformy, aplikacje i biblioteki z gotowymi lub jeszcze w trakcie opracowywania portami WebGPU.

Pierwsza wersja w Chrome 113 to dopiero początek. Chociaż nasza pierwsza wersja jest przeznaczona dla systemów Windows, ChromeOS i macOS, wkrótce planujemy udostępnić WebGPU na pozostałych platformach, takich jak Android i Linux.

Nie tylko zespół Chrome pracował nad wprowadzeniem WebGPU. Wdrożenia są też w trakcie w przypadku przeglądarek Firefox i WebKit.

W W3C opracowywane są też nowe funkcje, które można udostępnić, gdy będą dostępne w sprzęcie. Na przykład w Chrome planujemy wkrótce udostępnić obsługę 16-bitowych liczb zmiennoprzecinkowych w shaderach oraz klasę instrukcji DP4a, aby jeszcze bardziej zwiększyć wydajność uczenia maszynowego.

WebGPU to rozbudowany interfejs API, który zapewnia niesamowitą wydajność, jeśli zainwestujesz w niego. Dzisiaj omówiliśmy tylko ogólnie zalety WebGPU, ale jeśli chcesz zacząć korzystać z tej technologii, zapoznaj się z wprowadzającym Codelab Twoja pierwsza aplikacja WebGPU. W tym Codelab utworzysz wersję klasycznej gry Conwaya „Game of Life” wykorzystującą GPU. To ćwiczenie programistyczne zawiera omówienie procesu krok po kroku, dzięki czemu możesz je wypróbować, nawet jeśli po raz pierwszy zajmujesz się programowaniem na procesor GPU.

Aby zapoznać się z interfejsem API, możesz też skorzystać z próbek WebGPU. Są to tradycyjne „trójkąty powitalne” i bardziej kompleksowe przepływy renderowania i przetwarzania, które demonstrują różne techniki. Zapoznaj się też z naszą pozostałą pomocą.