Dari WebGL ke WebGPU

François Beaufort
François Beaufort

Sebagai developer WebGL, Anda mungkin merasa terintimidasi dan bersemangat untuk mulai menggunakan WebGPU, penerus WebGL yang menghadirkan kemajuan API grafis modern ke web.

Mengetahui bahwa WebGL dan WebGPU memiliki banyak konsep inti yang sama. Kedua API tersebut memungkinkan Anda menjalankan program kecil yang disebut shader di GPU. WebGL mendukung shader verteks dan fragmen, sedangkan WebGPU juga mendukung shader komputasi. WebGL menggunakan OpenGL Shading Language (GLSL) sementara WebGPU menggunakan WebGPU Shading Language (WGSL). Meskipun kedua bahasa tersebut berbeda, konsep pokoknya sebagian besar sama.

Dengan mempertimbangkan hal tersebut, artikel ini menyoroti beberapa perbedaan antara WebGL dan WebGPU, untuk membantu Anda memulai.

Status global

WebGL memiliki banyak status global. Beberapa setelan berlaku untuk semua operasi rendering, seperti tekstur dan buffer yang terikat. Anda menyetel status global ini dengan memanggil berbagai fungsi API, dan status tersebut akan tetap berlaku hingga Anda mengubahnya. Status global di WebGL adalah sumber error utama, karena hal ini sering kali lupa dilakukan untuk mengubah setelan global. Selain itu, status global membuat berbagi kode menjadi sulit, karena developer harus berhati-hati agar tidak mengubah status global secara tidak sengaja dengan cara yang memengaruhi bagian lain dari kode.

WebGPU adalah API stateless, dan tidak mempertahankan status global. Sebagai gantinya, fitur ini menggunakan konsep pipeline untuk mengenkapsulasi semua status rendering yang bersifat global dalam WebGL. Pipeline berisi informasi seperti penggabungan, topologi, dan atribut yang akan digunakan. Pipeline tidak dapat diubah. Jika ingin mengubah beberapa setelan, Anda harus membuat pipeline lain. WebGPU juga menggunakan Encoder perintah untuk mengelompokkan perintah bersama-sama dan menjalankannya sesuai urutan yang direkam. Ini berguna dalam pemetaan bayangan misalnya, saat, dalam satu penerusan objek, aplikasi bisa merekam beberapa aliran perintah, satu untuk setiap peta bayangan cahaya.

Ringkasnya, karena model status global WebGL membuat pembuatan library dan aplikasi yang tangguh dan composable menjadi sulit dan rapuh, WebGPU secara signifikan mengurangi jumlah status yang perlu dilacak developer saat mengirimkan perintah ke GPU.

Sinkronkan tidak lagi

Pada GPU, biasanya tidak efisien untuk mengirim perintah dan menunggunya secara sinkron, karena hal ini dapat mengosongkan pipeline dan menyebabkan gelembung. Hal ini terutama berlaku di WebGPU dan WebGL, yang menggunakan arsitektur multiproses dengan driver GPU berjalan dalam proses yang terpisah dari JavaScript.

Misalnya, di WebGL, memanggil gl.getError() memerlukan IPC sinkron dari proses JavaScript ke proses GPU dan kembali. Hal ini dapat menyebabkan balon di sisi CPU saat kedua proses tersebut berkomunikasi.

Untuk menghindari balon ini, WebGPU dirancang untuk sepenuhnya asinkron. Model error dan semua operasi lainnya terjadi secara asinkron. Misalnya, saat Anda membuat tekstur, operasi akan segera berhasil, meskipun tekstur sebenarnya merupakan error. Anda hanya dapat menemukan error secara asinkron. Desain ini menjaga komunikasi lintas proses agar bebas gelembung (gelembung) dan memberikan performa yang andal pada aplikasi.

Shader komputasi

Shader komputasi adalah program yang berjalan di GPU untuk melakukan komputasi bertujuan umum. Konfigurasi tersebut hanya tersedia di WebGPU, bukan WebGL.

Tidak seperti shader verteks dan fragmen, shader ini tidak terbatas pada pemrosesan grafis, dan dapat digunakan untuk berbagai tugas, seperti machine learning, simulasi fisik, dan komputasi ilmiah. Shader komputasi dijalankan secara paralel oleh ratusan atau bahkan ribuan thread, yang membuatnya sangat efisien untuk memproses set data besar. Pelajari komputasi GPU dan detail selengkapnya dalam artikel lengkap tentang WebGPU.

Pemrosesan frame video

Memproses frame video menggunakan JavaScript dan WebAssembly memiliki beberapa kelemahan: biaya penyalinan data dari memori GPU ke memori CPU, dan paralelisme terbatas yang dapat dicapai dengan pekerja dan thread CPU. WebGPU tidak memiliki keterbatasan tersebut, sehingga sangat cocok untuk memproses frame video berkat integrasi yang erat dengan WebCodecs API.

Cuplikan kode berikut menunjukkan cara mengimpor VideoFrame sebagai tekstur eksternal di WebGPU dan memprosesnya. Anda dapat mencoba demo ini.

// 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
}

Portabilitas aplikasi secara default

WebGPU memaksa Anda untuk meminta limits. Secara default, requestDevice() menampilkan GPUDevice yang mungkin tidak sesuai dengan kemampuan hardware perangkat fisik, tetapi merupakan penyebut umum yang wajar dan terendah dari semua GPU. Dengan mengharuskan developer untuk meminta pembatasan perangkat, WebGPU memastikan bahwa aplikasi akan berjalan di sebanyak mungkin perangkat.

Penanganan kanvas

WebGL secara otomatis mengelola kanvas setelah Anda membuat konteks WebGL dan menyediakan atribut konteks seperti alfa, antialias, colorSpace, depth, keepDrawingBuffer, atau stensil.

Di sisi lain, WebGPU mengharuskan Anda untuk mengelola kanvas sendiri. Misalnya, untuk mencapai antialiasing di WebGPU, Anda akan membuat tekstur multisampel dan merendernya. Kemudian, Anda akan me-resolve tekstur multisampel menjadi tekstur biasa dan menggambar tekstur tersebut ke kanvas. Pengelolaan manual ini memungkinkan Anda menghasilkan output ke kanvas sebanyak yang Anda inginkan dari satu objek GPUDevice. Sebaliknya, WebGL hanya dapat membuat satu konteks per kanvas.

Lihat demo WebGPU Multiple Canvases.

Sebagai catatan, browser saat ini memiliki batas jumlah kanvas WebGL per halaman. Pada saat penulisan, Chrome dan Safari hanya dapat menggunakan hingga 16 kanvas WebGL secara bersamaan; Firefox dapat membuat hingga 200 kanvas. Di sisi lain, tidak ada batasan jumlah kanvas WebGPU per halaman.

Screenshot yang menampilkan jumlah maksimum kanvas WebGL di browser Safari, Chrome, dan Firefox
Jumlah maksimum kanvas WebGL di Safari, Chrome, dan Firefox (dari kiri ke kanan) - demo.

Pesan error yang berguna

WebGPU menyediakan stack panggilan untuk setiap pesan yang ditampilkan dari API. Ini berarti Anda dapat dengan cepat melihat tempat terjadinya error dalam kode, yang berguna untuk melakukan proses debug dan memperbaiki error.

Selain menyediakan stack panggilan, pesan error WebGPU juga mudah dipahami dan ditindaklanjuti. Pesan error biasanya mencakup deskripsi error dan saran tentang cara memperbaiki error tersebut.

WebGPU juga memungkinkan Anda menyediakan label kustom untuk setiap objek WebGPU. Label ini kemudian digunakan oleh browser dalam pesan GPUError, peringatan konsol, dan alat developer browser.

Dari nama hingga indeks

Di WebGL, banyak hal yang terhubung menggunakan nama. Misalnya, Anda dapat mendeklarasikan variabel seragam yang disebut myUniform dalam GLSL dan mendapatkan lokasinya menggunakan gl.getUniformLocation(program, 'myUniform'). Hal ini berguna saat Anda mendapatkan error jika Anda salah mengetik nama variabel uniform.

Di sisi lain, dalam WebGPU, semuanya sepenuhnya terhubung dengan offset byte atau indeks (sering disebut lokasi). Anda bertanggung jawab untuk menjaga sinkronisasi lokasi kode dalam WGSL dan JavaScript.

Pembuatan Mipmap

Di WebGL, Anda dapat membuat tekstur level 0 mip, lalu memanggil gl.generateMipmap(). WebGL kemudian akan membuat semua level mip lainnya untuk Anda.

Di WebGPU, Anda harus membuat mipmap sendiri. Tidak ada fungsi bawaan untuk melakukan ini. Lihat diskusi spesifikasi untuk mempelajari keputusan tersebut lebih lanjut. Anda dapat menggunakan library praktis seperti webgpu-utils untuk membuat mipmap atau mempelajari cara melakukannya sendiri.

Buffer penyimpanan dan tekstur penyimpanan

Buffering seragam didukung oleh WebGL dan WebGPU serta memungkinkan Anda meneruskan parameter konstan dengan ukuran terbatas ke shader. Buffer penyimpanan, yang sangat mirip dengan buffer uniform, hanya didukung oleh WebGPU serta lebih canggih dan fleksibel daripada buffer seragam.

  • Data buffer penyimpanan yang diteruskan ke shader bisa jauh lebih besar daripada buffer uniform. Meskipun spesifikasi menunjukkan bahwa binding buffer uniform dapat berukuran hingga 64 KB (lihat maxUniformBufferBindingSize) , ukuran maksimum binding buffer penyimpanan minimal adalah 128 MB dalam WebGPU (lihat maxStorageBufferBindingSize).

  • Buffer penyimpanan dapat ditulis, dan mendukung beberapa operasi atomik, sedangkan buffer uniform hanya bersifat hanya baca. Hal ini memungkinkan class algoritma baru untuk diimplementasikan.

  • Binding buffer penyimpanan mendukung array berukuran runtime untuk algoritma yang lebih fleksibel, sedangkan ukuran array buffer seragam harus disediakan dalam shader.

Tekstur penyimpanan hanya didukung di WebGPU, dan berfungsi untuk membentuk tekstur dari buffer penyimpanan dengan buffer seragam. Algoritma ini lebih fleksibel daripada tekstur biasa, yang mendukung penulisan akses acak (dan pembacaan juga pada masa mendatang).

Perubahan buffer dan tekstur

Di WebGL, Anda dapat membuat buffer atau tekstur, lalu mengubah ukurannya kapan saja dengan masing-masing gl.bufferData() dan gl.texImage2D().

Dalam WebGPU, buffer dan tekstur tidak dapat diubah. Artinya, Anda tidak dapat mengubah ukuran, penggunaan, atau formatnya setelah dibuat. Anda hanya dapat mengubah kontennya.

Perbedaan konvensi ruang

Di WebGL, rentang ruang klip Z adalah dari -1 hingga 1. Dalam WebGPU, rentang ruang klip Z adalah dari 0 hingga 1. Artinya, objek dengan nilai z 0 adalah objek yang paling dekat dengan kamera, sedangkan objek dengan nilai z 1 adalah yang terjauh.

Ilustrasi rentang ruang klip Z di WebGL dan WebGPU.
Rentang ruang klip Z di WebGL dan WebGPU.

WebGL menggunakan konvensi OpenGL, dengan sumbu Y berada di atas dan sumbu Z mengarah ke penampil. WebGPU menggunakan konvensi Metal, di mana sumbu Y berada di bawah dan sumbu Z berada di luar layar. Perhatikan bahwa arah sumbu Y turun dalam koordinat framebuffer, koordinat area pandang, dan koordinat fragmen/piksel. Di ruang klip, arah sumbu Y masih naik seperti di WebGL.

Ucapan terima kasih

Terima kasih kepada Corentin Wallez, Gregg Tavares, Stephen White, Ken Russell, dan Rachel Andrew yang telah membaca artikel ini.

Saya juga merekomendasikan WebGPUFundamentals.org untuk mempelajari perbedaan mendalam antara WebGPU dan WebGL.