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

Dowiedz się, jak WebGPU wykorzystuje moc GPU, aby zapewnić szybsze działanie systemów uczących się i lepsze renderowanie grafiki.

Nowy interfejs WebGPU API zapewnia ogromny wzrost wydajności w przypadku zadań związanych z grafiką i systemami uczącymi się. W tym artykule pokazujemy, jak technologia WebGPU jest ulepszona w porównaniu z obecnym rozwiązaniem WebGL. Zapowiadamy też obserwowanie przyszłych zmian w tej technologii. Najpierw jednak omówimy, dlaczego opracowaliśmy model WebGPU.

Kontekst w WebGPU

WebGL pojawił się w Chrome w 2011 r. Pozwalając aplikacjom internetowym korzystać z układów GPU, WebGL umożliwia niesamowite wrażenia w sieci – od Google Earth, przez interaktywne teledyski, po wycieczki po nieruchomościach 3D i wiele innych. Interfejs WebGL był oparty na interfejsach API OpenGL, które opracowano po raz pierwszy w 1992 r. To dawno temu! Można sobie wyobrazić, że od tego czasu znacznie się zmieniło w sprzęcie GPU.

Aby nadążyć za tym ewolucją, opracowano nowy rodzaj interfejsów API, które pozwalają wydajniej współpracować z nowoczesnym sprzętem GPU. Interfejsy API takie jak Direct3D 12, Metal i Vulkan. Te nowe interfejsy API obsługiwały nowe i wymagające przypadki użycia w programowaniu GPU, takie jak eksplozja w obszarze uczenia maszynowego i postęp w algorytmach renderowania. WebGPU to następca WebGL, który wprowadza do internetu innowacje tej nowej klasy nowoczesnych interfejsów API.

WebGPU otwiera wiele nowych możliwości programowania GPU w przeglądarce. Lepiej odzwierciedla to, jak działa nowoczesny sprzęt z GPU, a jednocześnie tworzy podstawy dla bardziej zaawansowanych układów GPU w przyszłości. Interfejs API powstał w ramach grupy GPU for the Web firmy W3C od 2017 roku i jest wynikiem współpracy wielu firm, takich jak Apple, Google, Mozilla, Microsoft i Intel. Z przyjemnością informujemy, że po 6 latach pracy została wprowadzona jedna z największych funkcji platformy internetowej.

Procesor graficzny WebGPU jest obecnie dostępny w Chrome 113 w systemach ChromeOS, macOS i Windows. Wkrótce wprowadzimy też inne platformy. Bardzo dziękujemy innym współtwórcom Chromium, a zwłaszcza Intelowi, którzy pomogli nam to osiągnąć.

Przyjrzyjmy się teraz kilku ciekawym przypadkom użycia, które umożliwia WebGPU.

Odblokuj nowe zadania GPU na potrzeby renderowania

Funkcje WebGPU, takie jak cieniowanie obliczeniowe, umożliwiają przenoszenie nowych klas algorytmów do GPU. Są to na przykład algorytmy, które mogą dodawać bardziej dynamiczne szczegóły do scen lub symulować zjawiska fizyczne. Istnieją nawet zadania, które wcześniej można było wykonywać tylko przy użyciu JavaScriptu, a teraz można przenieść je do GPU.

W filmie poniżej widać algorytm kostki maszerujących, który trianguluje powierzchnię tych metakul. W pierwszych 20 sekundach filmu algorytm, który działa w języku JavaScript, ciężko nadąża za tym, że strona działa z szybkością tylko 8 FPS, co powoduje zacinanie animacji. Aby utrzymać wysoką wydajność w JavaScript, musimy znacznie obniżyć poziom szczegółów.

Gdy przenosimy ten sam algorytm do cieniowania obliczeniowego, który jest widoczny na filmie po 20 sekundach, powstaje różnica w dniu i nocy. Wydajność znacznie się poprawia, ponieważ strona działa teraz z płynną szybkością 60 FPS, a nadal jest sporo miejsca na nowe efekty. Oprócz tego główna pętla JavaScript na stronie zostaje całkowicie uwolniona na inne zadania, dzięki czemu interakcje ze stroną pozostają elastyczne.

. Demonstracja gry metaballs
.

WebGPU umożliwia również korzystanie ze złożonych efektów wizualnych, które wcześniej nie były praktyczne. W poniższym przykładzie utworzonym w popularnej bibliotece Babylon.js powierzchnia oceanu jest w całości symulowana przez GPU. Realistyczna dynamika powstaje na podstawie połączonych ze sobą wielu niezależnych fal. Bezpośrednia symulacja każdej fali byłaby jednak zbyt kosztowna.

. Ocean – wersja demonstracyjna
.

Dlatego wersja demonstracyjna wykorzystuje zaawansowany algorytm o nazwie szybka transformata Fouriera. Zamiast przedstawiać wszystkie fale jako złożone dane pozycjonowania, w procesie wykorzystuje się dane widmowe, które znacznie przydają się przy wykonywaniu obliczeń. Następnie każda klatka wykorzystuje transformatę Fouriera do konwersji danych widmowych na dane pozycjonowania reprezentujące wysokość fal.

Szybsze wnioskowanie ML

WebGPU przydaje się też do przyspieszania działania systemów uczących się, które w ostatnich latach stało się głównym zastosowaniem układów GPU.

Od dawna programiści kreacji używali interfejsu API renderowania WebGL do wykonywania operacji niezwiązanych z renderowaniem, takich jak obliczenia systemów uczących się. Wymaga to jednak rysowania pikseli trójkątów jako sposobu inicjowania obliczeń oraz ostrożnego pakowania i rozpakowywania danych tensorów w teksturze, a nie korzystania z bardziej ogólnego przeznaczenia dostępu do pamięci.

Ilustracja przedstawiająca nieefektywność w przypadku wykonania pojedynczego operatora ML z użyciem WebGL, w tym nadmiarowe wczytywanie pamięci, nadmiarowe obliczenia i kilka wartości zapisanych w wątku.
Jedno wykonanie operatora ML w WebGL.

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

Cieniowanie Compute to główna nowa funkcja WebGPU, która eliminuje te problemy. Moduły do cieniowania Compute to bardziej elastyczny model programowania, który wykorzystuje bardzo równoległą naturę GPU i nie jest ograniczany przez ścisłą strukturę operacji renderowania.

Różne wzrosty wydajności w cieniowaniach obliczeniowych WebGPU, w tym współdzielone obciążenia pamięci, wspólne obliczenia i elastyczne zapisy w pamięci.
Wydajność programu do cieniowania obliczeń WebGPU.

Moduły do cieniowania Compute dają większe możliwości udostępniania danych i wyników obliczeń w grupach zadań do cieniowania, aby zwiększyć wydajność. Może to prowadzić do poprawy wyników w porównaniu z wcześniejszymi próbami wykorzystania WebGL w tym samym celu.

Przykładem korzyści w tym zakresie jest to, że po przejściu z WebGPU z WebGPU na WebGL początkowy port modelu dyfuzji obrazów w TensorFlow.js wykazuje 3-krotny wzrost wydajności na różnych urządzeniach. Na niektórych testowanych sprzętach obraz został wyrenderowany w czasie krótszym niż 10 sekund. A ponieważ była to wczesna wersja, sądzimy, że zarówno WebGPU, jak i TensorFlow.js można jeszcze ulepszyć. Sprawdź, co nowego w Web ML w 2023 roku. sesji Google I/O.

Jednak w WebGPU nie chodzi tylko o udostępnianie w internecie funkcji GPU.

Zaprojektowane przede wszystkim z myślą o języku JavaScript

Funkcje, które to umożliwiają, są już od jakiegoś czasu dostępne dla deweloperów aplikacji na komputery i urządzenia mobilne, a naszym wyzwaniem jest zaprezentowanie ich w sposób najbardziej naturalny dla naszej platformy internetowej.

Opracowano go, korzystając z danych uzyskanych od ponad 10 lat programistów pracujących nad WebGL. Mogliśmy wziąć pod uwagę napotkane przez nich problemy, wąskie gardła i zgłoszone przez nich problemy oraz przełożyć wszystkie te opinie w nowy interfejs API.

Widzieliśmy, że globalny model stanowy WebGL sprawił, że tworzenie solidnych, kompozycyjnych bibliotek i aplikacji stało się trudne i kruche. WebGPU znacznie zmniejsza ilość stanu, który deweloperzy muszą śledzić podczas wysyłania poleceń GPU.

Słyszeliśmy, że debugowanie aplikacji WebGL jest uciążliwe, dlatego WebGPU udostępnia bardziej elastyczne mechanizmy obsługi błędów, które zmniejszają wydajność. Dołożyliśmy wszelkich starań, aby każda wiadomość wysyłana przez Ciebie z interfejsu API była łatwa do zrozumienia i podejmowania działań.

Zaobserwowaliśmy też, że koszty związane ze zbyt dużą liczbą wywołań JavaScript są wąskim gardłem złożonych aplikacji WebGL. Dzięki temu interfejs WebGPU API jest mniej dopracowany, a Ty możesz osiągnąć więcej przy mniejszej liczbie wywołań funkcji. Skupiamy się na weryfikacji za pomocą dużego obciążenia na samym początku, starając się zachować jak najmniejszą pętlę danych. Dostępne są też nowe interfejsy API, takie jak pakiety renderowania, które pozwalają z wyprzedzeniem zarejestrować dużą liczbę poleceń rysowania i ponownie je odtwarzać w ramach jednego wywołania.

Aby zademonstrować istotną różnicę w działaniu funkcji takich jak pakiety renderowania, oto kolejna wersja demonstracyjna z Babilon.js. Jej mechanizm renderowania WebGL 2 może wykonywać wszystkie wywołania JavaScriptu, by wyrenderować scenę z galerii sztuki mniej więcej 500 razy na sekundę. Co jest całkiem nieźle!

. Galeria sztuki
.

Mechanizm renderowania WebGPU włącza jednak funkcję wywoływania Snapshot Rendering. Wykorzystuje ona pakiety renderowania WebGPU i umożliwia ponad 10 razy szybsze przesyłanie tej samej sceny. Dzięki temu znacznie zmniejszone nakłady pracy pozwalają WebGPU renderować bardziej złożone sceny, a jednocześnie pozwalają aplikacjom pracować równolegle z użyciem JavaScriptu.

Nowoczesne interfejsy API grafiki cieszą się reputacją ze złożoności i prostej w zamian za możliwości optymalizacji. Z kolei WebGPU koncentruje się na zgodności z wieloma platformami i w większości przypadków obsługuje trudne tematy, takie jak automatyczna synchronizacja zasobów.

Ma to przyjemny efekt uboczny, ponieważ interfejs WebGPU jest łatwy do opanowania i używania. Opiera się on na dotychczasowych funkcjach platformy internetowej na potrzeby wczytywania obrazów i filmów, a w przypadku operacji asynchronicznych wykorzystuje dobrze znane wzorce JavaScript, takie jak obietnice. Pomaga to ograniczyć do minimum ilość potrzebnego kodu. Pierwszy trójkąt na ekranie może mieć 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

Nowe możliwości, jakie daje WebGPU, są bardzo ekscytujące. Czekamy na nowe, ciekawe przypadki użycia, które znajdziesz w WebGPU.

Wokół WebGL opiera się tętniący życiem ekosystem bibliotek i platform, który chętnie wykorzystuje procesory WebGPU. Obsługa WebGPU jest w trakcie opracowywania lub jest już ukończona w wielu popularnych bibliotekach JavaScriptu. W niektórych przypadkach wykorzystanie zalet WebGPU może wymagać po prostu zmiany jednej flagi.

Babylon.js, Construct 3, Google Earth, Google Meet, PlayCanvas, Sketchfab, Three.JS, TensorFlow.js i Unity.
Frameworks, aplikacje i biblioteki z zakończonymi lub aktywnymi portami WebGPU.

Ta pierwsza wersja w Chrome 113 to dopiero początek. Choć pierwotna wersja jest przeznaczona dla systemów Windows, ChromeOS i macOS, w najbliższej przyszłości planujemy wprowadzić WebGPU na pozostałych platformach, takich jak Android i Linux.

Nie tylko zespół Chrome pracował nad wprowadzeniem WebGPU. Trwają także implementacje w przeglądarkach Firefox i WebKit.

Co więcej, nowe funkcje są już projektowane w W3C i będzie można je udostępnić, jeśli będą dostępne na sprzęcie. Na przykład: niedługo planujemy w Chrome włączyć obsługę 16-bitowych liczb zmiennoprzecinkowych w cieniowaniu oraz klasę instrukcji DP4a, aby jeszcze bardziej zwiększyć wydajność systemów uczących się.

WebGPU to rozbudowany interfejs API, który zapewnia niesamowitą wydajność, jeśli w nie zainwestujesz. Dzisiaj możemy tylko ogólnie omówić jego zalety, ale jeśli chcesz zacząć korzystać z WebGPU, zapoznaj się z podstawowym ćwiczeniem z programowania: Twoja pierwsza aplikacja WebGPU. W ramach tego ćwiczenia w programie utworzysz wersję GPU klasycznej gry w życie Conwaya. Dzięki temu ćwiczeniu w Codelabs dowiesz się, jak wygląda ten proces krok po kroku, dzięki czemu możesz wypróbować tę usługę, nawet jeśli po raz pierwszy zajmujesz się programowaniem GPU.

Aby dobrze poznać działanie interfejsu API, warto też zapoznać się z przykładami WebGPU. Mogą to być tradycyjne „trójkąt powitalny” co pozwala na pełniejsze renderowanie i obliczanie potoków, co pokazuje różne techniki. Na koniec zapoznaj się z naszymi innymi materiałami.