Dari WebGL ke WebGPU

Prancis 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.

Saya sangat yakin bahwa WebGL dan WebGPU memiliki banyak konsep inti yang sama. Kedua API memungkinkan Anda menjalankan program kecil yang disebut shader di GPU. WebGL mendukung shader fragmen dan vertex, 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 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, misalnya 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 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 kode lainnya.

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

Ringkasnya, karena model status global WebGL membuat pembuatan library dan aplikasi yang tangguh dan dapat disusun menjadi sulit dan rapuh, WebGPU secara signifikan mengurangi jumlah status yang perlu dilacak oleh developer saat mengirim 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 balon. 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 kembali. Hal ini dapat menyebabkan gelembung di sisi CPU saat kedua proses berkomunikasi.

Untuk menghindari balon tersebut, WebGPU dirancang agar sepenuhnya asinkron. Model error dan semua operasi lainnya terjadi secara asinkron. Misalnya, saat Anda membuat tekstur, operasi akan langsung berhasil meskipun tekstur tersebut sebenarnya merupakan error. Anda hanya dapat menemukan error secara asinkron. Desain ini membuat komunikasi lintas proses tidak terganggu dan memberikan performa yang andal pada aplikasi.

Shader komputasi

Compute shader adalah program yang berjalan di GPU untuk melakukan komputasi tujuan umum. Fitur tersebut hanya tersedia di WebGPU, bukan WebGL.

Tidak seperti vertex dan shader fragmen, keduanya tidak terbatas pada pemrosesan grafis, dan dapat digunakan untuk berbagai tugas, seperti machine learning, simulasi fisika, 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 penyalinan 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 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 cocok dengan kemampuan hardware perangkat fisik, tetapi merupakan penyebut umum terendah dan wajar dari semua GPU. Dengan mengharuskan developer 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 menjadi tekstur biasa dan menggambar tekstur tersebut ke kanvas. Pengelolaan manual ini memungkinkan Anda menghasilkan output ke kanvas sebanyak yang diinginkan dari satu objek GPUDevice. Sebaliknya, WebGL hanya dapat membuat satu konteks per kanvas.

Lihat Demo Multiple Canvas WebGPU.

Sebagai catatan, browser saat ini memiliki batasan 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 melihat tempat terjadinya error dalam kode dengan cepat, yang sangat berguna untuk proses debug dan perbaikan error.

Selain menyediakan stack panggilan, pesan error WebGPU juga mudah dipahami dan dapat ditindaklanjuti. Pesan error biasanya menyertakan deskripsi error dan saran cara memperbaikinya.

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

Dalam WebGL, banyak hal yang terhubung menggunakan 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 pesan error jika Anda salah mengetik nama variabel seragam.

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

Pembuatan Mipmap

Di WebGL, Anda dapat membuat tingkat tekstur 0 mip, lalu memanggil gl.generateMipmap(). Kemudian, WebGL 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

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

  • Data buffer penyimpanan yang diteruskan ke shader bisa jauh lebih besar daripada buffer seragam. Meskipun spesifikasi menyatakan binding buffer seragam dapat berukuran hingga 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, sementara buffer seragam bersifat hanya-baca. Hal ini memungkinkan kelas algoritma baru untuk diimplementasikan.

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

Tekstur penyimpanan hanya didukung di WebGPU, dan untuk tekstur seperti itu buffer penyimpanan bagi buffer seragam. Teks ini lebih fleksibel daripada tekstur biasa, karena mendukung penulisan akses acak (dan juga dapat dibaca 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(), misalnya.

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

Perbedaan konvensi ruang

Di WebGL, rentang ruang klip Z adalah dari -1 hingga 1. Di WebGPU, rentang ruang klip Z adalah dari 0 hingga 1. Ini berarti 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 di atas dan sumbu Z mengarah ke penampil. WebGPU menggunakan konvensi Metal, dengan sumbu Y berada di bawah dan sumbu Z berada di luar layar. Perhatikan bahwa arah sumbu Y menurun dalam koordinat framebuffer, koordinat area pandang, dan koordinat fragmen/piksel. Di 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 telah meninjau artikel ini.

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