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.

Anda dapat merasa tenang karena 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 vertex dan fragmen, sedangkan WebGPU juga mendukung shader komputasi. WebGL menggunakan OpenGL Shading Language (GLSL) sedangkan WebGPU menggunakan WebGPU Shading Language (WGSL). Meskipun kedua bahasa tersebut berbeda, konsep yang mendasarinya 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 buffering yang terikat. Anda menetapkan status global ini dengan memanggil berbagai fungsi API, dan status ini tetap berlaku hingga Anda mengubahnya. Status global di WebGL adalah sumber utama error, karena mudah lupa untuk mengubah setelan global. Selain itu, status global mempersulit berbagi kode, karena developer harus berhati-hati agar tidak mengubah status global secara tidak sengaja dengan cara yang memengaruhi bagian kode lainnya.

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

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

Tidak lagi menyinkronkan

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

Di WebGL, misalnya, memanggil gl.getError() memerlukan IPC sinkron dari proses JavaScript ke proses GPU dan sebaliknya. Hal ini dapat menyebabkan bubble di sisi CPU saat kedua proses 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 tampaknya langsung berhasil, meskipun tekstur sebenarnya merupakan error. Anda hanya dapat menemukan error secara asinkron. Desain ini membuat komunikasi lintas proses bebas dari bubble dan memberikan performa yang andal pada aplikasi.

Shader komputasi

Shader komputasi adalah program yang berjalan di GPU untuk melakukan komputasi umum. Fitur ini 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, sehingga sangat efisien untuk memproses set data besar. Pelajari komputasi GPU dan detail selengkapnya dalam artikel lengkap tentang WebGPU ini.

Pemrosesan frame video

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

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 mewajibkan developer untuk meminta batas 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 mengelola kanvas sendiri. Misalnya, untuk mencapai antialiasing di WebGPU, Anda akan membuat tekstur multisampel dan merendernya. Kemudian, Anda akan me-resolve tekstur multisampel ke tekstur reguler 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 tambahan, 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 bermanfaat

WebGPU menyediakan stack panggilan untuk setiap pesan yang ditampilkan dari API. Artinya, Anda dapat dengan cepat melihat tempat terjadinya error dalam kode, yang berguna untuk men-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 dengan nama. Misalnya, Anda dapat mendeklarasikan variabel seragam yang disebut myUniform di GLSL dan mendapatkan lokasinya menggunakan gl.getUniformLocation(program, 'myUniform'). Hal ini berguna saat Anda mendapatkan error jika salah mengetik nama variabel seragam.

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

Pembuatan mipmap

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

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

Buffer penyimpanan dan tekstur penyimpanan

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

  • Data buffering penyimpanan yang diteruskan ke shader dapat jauh lebih besar daripada buffering seragam. Meskipun spesifikasi menyatakan bahwa ukuran binding buffer seragam dapat mencapai 64 KB (lihat maxUniformBufferBindingSize) , ukuran maksimum binding buffer penyimpanan minimal 128 MB di WebGPU (lihat maxStorageBufferBindingSize).

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

  • Binding buffer penyimpanan mendukung array berukuran runtime untuk algoritma yang lebih fleksibel, sedangkan ukuran array buffer seragam harus disediakan di 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 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 yang paling dekat dengan kamera, sedangkan objek dengan nilai z 1 adalah yang paling jauh.

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

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

Ucapan terima kasih

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

Saya juga merekomendasikan WebGPUFundamentals.org untuk mengetahui perbedaan mendetail antara WebGPU dan WebGL.