Jako programista WebGL możesz być zaskoczony i podekscytowany, że możesz zacząć używać WebGPU, czyli następcy WebGL, który wprowadza do sieci nowe funkcje interfejsów API grafiki.
Warto wiedzieć, że WebGL i WebGPU mają wiele wspólnych podstawowych koncepcji. Oba interfejsy API umożliwiają uruchamianie na GPU małych programów zwanych shaderami. WebGL obsługuje shadery wierzchołkowe i fragmentowe, a WebGPU także shadery obliczeniowe. WebGL używa języka cieniowania OpenGL (GLSL), a WebGPU – języka cieniowania WebGPU (WGSL). Chociaż te dwa języki są różne, ich podstawy są w dużej mierze takie same.
Z tego względu w tym artykule omówiliśmy różnice między WebGL a WebGPU, aby ułatwić Ci rozpoczęcie pracy.
Stan globalny
WebGL ma wiele stanów globalnych. Niektóre ustawienia dotyczą wszystkich operacji renderowania, np. które tekstury i bufory są powiązane. Ten stan globalny ustawiasz, wywołując różne funkcje interfejsu API. Stan ten pozostaje w zbiorze do czasu jego zmiany. Stan globalny w WebGL jest głównym źródłem błędów, ponieważ łatwo można zapomnieć o zmianie ustawienia globalnego. Stan globalny utrudnia też udostępnianie kodu, ponieważ deweloperzy muszą uważać, aby nie zmieniać go przypadkowo w sposób, który wpłynie na inne części kodu.
WebGPU to interfejs API bezstanowy, który nie obsługuje stanu globalnego. Zamiast tego używa ona koncepcji rury, aby ująć wszystkie stany renderowania, które były globalne w WebGL. Proces zawiera informacje o tym, jakiego rodzaju mieszania, topologii i atrybutów użyć. Pliku nie można zmienić. Jeśli chcesz zmienić niektóre ustawienia, musisz utworzyć kolejny potok. WebGPU używa też koderów poleceń do grupowania poleceń i wykonywaniu ich w kolejności, w jakiej zostały zarejestrowane. Jest to przydatne np. w przypadku mapowania cieni, gdy w ramach jednego przejścia przez obiekty aplikacja może rejestrować wiele strumieni poleceń, po jednym dla każdej mapy cieni światła.
Podsumowując, model globalnego stanu WebGL utrudniał tworzenie niezawodnych, modułowych bibliotek i aplikacji, a WebGPU znacznie zmniejszył ilość stanu, którą deweloperzy musieli śledzić podczas wysyłania poleceń do GPU.
Nie synchronizuj
Na kartach graficznych wysyłanie poleceń i czekanie na nie w sposób synchroniczny jest zwykle nieefektywne, ponieważ może to spowodować wyczyszczenie potoku i wywołać bąble. Jest to szczególnie ważne w przypadku WebGPU i WebGL, które korzystają z wiele procesowej architektury, w której sterownik GPU działa w oddzielnym procesie od JavaScript.
Na przykład w WebGL wywołanie gl.getError()
wymaga synchronicznego IPC z procesu JavaScript do procesu GPU i z powrotem. Może to spowodować powstanie bąbla po stronie procesora, ponieważ 2 procesy będą ze sobą współpracować.
Aby uniknąć tych bań, WebGPU zostało zaprojektowane tak, aby było całkowicie asynchroniczne. Model błędów i wszystkie inne operacje są wykonywane asynchronicznie. Na przykład podczas tworzenia tekstury operacja wydaje się być natychmiastowa, nawet jeśli tekstura jest w rzeczywistości błędna. Błąd można wykryć tylko asynchronicznie. Dzięki temu komunikacji między procesami nie towarzyszy żadna bańka, a aplikacje działają niezawodnie.
Shadery obliczeniowe
Shadery obliczeniowe to programy, które działają na GPU w celu wykonywania obliczeń ogólnego przeznaczenia. Są one dostępne tylko w WebGPU, a nie w WebGL.
W przeciwieństwie do shaderów wierzchołkowych i fragmentowych nie są one ograniczone do przetwarzania grafiki. Można ich używać do wykonywania różnych zadań, takich jak uczenie maszynowe, symulacja fizyki i obliczenia naukowe. Shadery obliczeniowe są wykonywane równolegle przez setki, a nawet tysiące wątków, co sprawia, że są bardzo wydajne w przypadku przetwarzania dużych zbiorów danych. Więcej informacji o przetwarzaniu na procesorze graficznym znajdziesz w tym obszernym artykule o WebGPU.
Przetwarzanie klatek wideo
Przetwarzanie klatek wideo za pomocą JavaScript i WebAssembly ma pewne wady: koszt kopiowania danych z pamięci GPU do pamięci procesora oraz ograniczone równoległość, której można osiągnąć za pomocą wątków roboczych i procesora. WebGPU nie ma tych ograniczeń, dzięki czemu świetnie nadaje się do przetwarzania klatek wideo dzięki ścisłej integracji z interfejsem WebCodecs API.
Ten fragment kodu pokazuje, jak zaimportować ramkę wideo jako zewnętrzną teksturę w WebGPU i ją przetworzyć. Możesz wypróbować tę wersję demonstracyjną.
// Init WebGPU device and pipeline...
// Configure canvas context...
// Feed camera stream to video...
(function render() {
const videoFrame = new VideoFrame(video);
applyFilter(videoFrame);
requestAnimationFrame(render);
})();
function applyFilter(videoFrame) {
const texture = device.importExternalTexture({ source: videoFrame });
const bindgroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: texture }],
});
// Finally, submit commands to GPU
}
Domyślna przenośność aplikacji
WebGPU wymaga przesłania żądania limits
. Domyślnie funkcja requestDevice()
zwraca GPUDevice, który może nie odpowiadać możliwościom sprzętowym fizycznego urządzenia, ale raczej rozsądnemu i najniższemu wspólnemu mianownikowi wszystkich GPU. Wymagając od deweloperów, aby prosili o limity urządzeń, WebGPU zapewnia, że aplikacje będą działać na jak największej liczbie urządzeń.
Obsługa Canvas
WebGL automatycznie zarządza płótnem po utworzeniu kontekstu WebGL i podaniu atrybutów kontekstu takich jak alpha, antialias, colorSpace, depth, preserveDrawingBuffer czy stencil.
Z drugiej strony WebGPU wymaga samodzielnego zarządzania płótnem. Na przykład, aby uzyskać wygładzanie krawędzi w WebGPU, utwórz teksturę wielopróbkową i renderuj ją. Następnie przekształcasz wielopróbkową teksturę w zwykłą i rysujesz ją na płótnie. Dzięki temu ręcznemu zarządzaniu możesz wyprowadzać dane na dowolną liczbę kanw z jednego obiektu GPUDevice. W przypadku WebGL można utworzyć tylko 1 kontekst na 1 płótno.
Obejrzyj prezentację WebGPU dotyczące wielu kanałów.
Pamiętaj, że przeglądarki mają obecnie limit liczby kanw WebGL na stronę. W momencie pisania tego artykułu Chrome i Safari mogą jednocześnie używać tylko 16 płót WebGL; Firefox może utworzyć ich do 200. Z drugiej strony nie ma limitu liczby kanw WebGPU na stronę.

Przydatne komunikaty o błędach
WebGPU udostępnia stos wywołań dla każdej wiadomości zwracanej przez interfejs API. Dzięki temu możesz szybko sprawdzić, gdzie w kodzie wystąpił błąd, co jest przydatne podczas debugowania i naprawiania błędów.
Oprócz informacji o zbiorze wywołań komunikaty o błędach WebGPU są też łatwe do zrozumienia i działania. Komunikaty o błędach zwykle zawierają opis błędu i sugestie dotyczące jego naprawienia.
WebGPU umożliwia też podanie niestandardowego label
dla każdego obiektu WebGPU. Ta etykieta jest następnie używana przez przeglądarkę w wiadomościach GPUError, ostrzeżeniach w konsoli i narzędziach dla programistów przeglądarki.
Od nazw do indeksów
W WebGL wiele elementów jest połączonych nazwami. Możesz na przykład zadeklarować w GLSL zmienną o nazwie myUniform
i uzyskać jej lokalizację za pomocą funkcji gl.getUniformLocation(program, 'myUniform')
. Jest to przydatne, ponieważ w przypadku błędnego wpisania nazwy zmiennej uniform wystąpi błąd.
Z kolei w WebGPU wszystko jest połączone za pomocą przesunięcia bajtów lub indeksu (często nazywanego lokalizacją). Twoim obowiązkiem jest dbanie o to, aby lokalizacje kodu w WGSL i JavaScript były zsynchronizowane.
Generowanie mapy MIP-ów
W WebGL możesz utworzyć teksturę na poziomie 0 mip, a potem wywołać funkcję gl.generateMipmap()
. WebGL wygeneruje dla Ciebie wszystkie pozostałe poziomy MIP.
W WebGPU musisz samodzielnie wygenerować mipmapy. Nie ma wbudowanej funkcji, która umożliwiałaby to zrobienie. Aby dowiedzieć się więcej o tej decyzji, zapoznaj się z dyskusją na temat specyfikacji. Aby wygenerować mapy MIP, możesz użyć przydatnych bibliotek, takich jak webgpu-utils, lub dowiedzieć się, jak zrobić to samodzielnie.
bufory i tekstury pamięci masowej,
Zbiory jednolite są obsługiwane zarówno przez WebGL, jak i WebGPU i umożliwiają przekazywanie do shaderów stałych parametrów o ograniczonym rozmiarze. Bufory pamięci, które wyglądają bardzo podobnie do buforów jednolitych, są obsługiwane tylko przez WebGPU. Są one bardziej wydajne i elastyczne niż bufory jednolite.
Dane buforów pamięci przekazywane do shaderów mogą być znacznie większe niż bufory jednolite. Według specyfikacji rozmiary wiązań buforów jednolitych mogą wynosić do 64 KB (patrz
maxUniformBufferBindingSize
) , ale w WebGPU maksymalny rozmiar wiązania bufora pamięci wynosi co najmniej 128 MB (patrzmaxStorageBufferBindingSize
).Bufory pamięci są buforami do zapisu i obsługują niektóre operacje atomowe, podczas gdy bufory jednolite są tylko do odczytu. Umożliwia to wdrażanie nowych klas algorytmów.
Powiązania buforów pamięci obsługują tablice o rozmiarze zdefiniowanym w czasie wykonywania, co umożliwia większą elastyczność algorytmów, podczas gdy rozmiary tablic jednolitych buforów muszą być podawane w shaderze.
Tekstury pamięci masowej są obsługiwane tylko w WebGPU i są dla tekstur tym, czym dla buforów jednolitych są bufory pamięci masowej. Są bardziej elastyczne niż zwykłe tekstury i obsługują zapis (a w przyszłości także odczyt) z dostępem losowym.
Zmiany bufora i tekstury
W WebGL możesz utworzyć bufor lub teksturę, a potem w dowolnym momencie zmienić ich rozmiar za pomocą funkcji gl.bufferData()
i gl.texImage2D()
.
W WebGPU bufory i tekstury są niezmienne. Oznacza to, że po utworzeniu nie można zmienić ich rozmiaru, sposobu użycia ani formatu. Możesz tylko zmienić ich zawartość.
Różnice w konwencji dotyczącej przestrzeni
W WebGL zakres przestrzeni klipu Z wynosi od –1 do 1. W WebGPU zakres przestrzeni ograniczeń Z wynosi od 0 do 1. Oznacza to, że obiekty o wartości z równej 0 są najbliżej kamery, a obiekty o wartości z równej 1 są najdalej.
WebGL używa konwencji OpenGL, w której oś Y jest skierowana w górę, a oś Z – w kierunku widza. WebGPU używa konwencji Metal, w której oś Y jest skierowana w dół, a oś Z – poza ekran. Pamiętaj, że oś Y w współrzędnych framebuffera, współrzędnych widocznego obszaru i współrzędnych fragmentu/piksela jest skierowana w dół. W przestrzeni klipu kierunek osi Y jest nadal skierowany w górę, tak jak w WebGL.
Podziękowania
Dziękujemy Corentin Wallez, Gregg Tavares, Stephen White, Ken Russell i Rachel Andrew za sprawdzenie tego artykułu.
Aby dowiedzieć się więcej o różnicach między WebGPU a WebGL, warto też odwiedzić stronę WebGPUFundamentals.org.