WGSL (WebGPU Shading Language): Memprogram GPU Anda Langsung di Browser
1. Pendahuluan
Pernahkah Anda membayangkan bisa memprogram GPU (Graphics Processing Unit) langsung dari browser web Anda? Memanfaatkan kekuatan komputasi paralel yang luar biasa untuk grafis 3D yang memukau, pemrosesan data masif, atau bahkan model AI lokal? Dengan kedatangan WebGPU, mimpi itu menjadi kenyataan. Namun, untuk benar-benar mendalami potensi WebGPU, kita perlu memahami bahasa rahasia yang digunakannya: WGSL (WebGPU Shading Language).
WGSL adalah bahasa pemrograman khusus yang dirancang untuk menulis shader – program kecil yang berjalan di GPU. Jika WebGPU adalah “API baru untuk mengakses GPU dari web”, maka WGSL adalah “bahasa yang Anda gunakan untuk berbicara dengan GPU melalui API itu”. Ini adalah fondasi di balik semua visual canggih dan komputasi performa tinggi yang bisa Anda bangun dengan WebGPU.
Mengapa topik ini penting bagi developer web Indonesia?
- Performa Maksimal: GPU jauh lebih efisien untuk tugas-tugas paralel dibandingkan CPU. Dengan WGSL, Anda bisa memindahkan beban komputasi berat ke GPU, membuat aplikasi web Anda jauh lebih responsif dan cepat.
- Grafis Generasi Berikutnya: Dari game 3D, visualisasi data kompleks, hingga efek pasca-pemrosesan gambar/video yang canggih, WGSL membuka pintu untuk pengalaman visual yang belum pernah ada sebelumnya di web.
- Inovasi AI/ML: WGSL memungkinkan implementasi model Machine Learning atau pemrosesan data besar secara lokal di browser, mengurangi ketergantungan pada server dan meningkatkan privasi pengguna.
- Masa Depan Web: WebGPU dan WGSL adalah standar masa depan untuk komputasi grafis dan paralel di web. Menguasainya berarti Anda selangkah lebih maju dalam membangun aplikasi web yang inovatif.
Di artikel ini, kita akan menyelami WGSL: memahami apa itu, bagaimana sintaks dasarnya, dan bagaimana kita bisa mulai menulis shader sederhana untuk memprogram GPU langsung dari browser.
2. Memahami Peran Shader di WebGPU
Sebelum kita masuk ke sintaks WGSL, mari kita pahami dulu di mana posisi shader dalam pipeline WebGPU. Bayangkan WebGPU sebagai sebuah “pabrik” yang memproses data untuk menghasilkan gambar atau hasil komputasi. Shader adalah “instruksi” yang Anda berikan kepada pekerja di pabrik tersebut.
Ada dua jenis shader utama dalam konteks grafis 3D:
- Vertex Shader: Ini adalah program yang berjalan untuk setiap vertex (titik) dalam model 3D Anda. Tugas utamanya adalah mengubah posisi vertex dari ruang model ke ruang layar (proyeksi), dan meneruskan informasi lain seperti warna atau koordinat tekstur ke shader berikutnya.
- Fragment Shader (sering disebut juga Pixel Shader): Ini adalah program yang berjalan untuk setiap fragment (potongan piksel potensial) yang akan digambar di layar. Tugasnya adalah menentukan warna akhir dari piksel tersebut, berdasarkan informasi yang diteruskan dari vertex shader, tekstur, atau input lainnya.
Selain itu, WebGPU juga mendukung:
- Compute Shader: Ini adalah program yang dirancang murni untuk tujuan komputasi paralel, tanpa terkait langsung dengan grafis. Compute shader dapat memproses array data besar, melakukan simulasi fisika, atau bahkan melatih bagian dari model AI. Ini adalah kekuatan sejati GPU di luar rendering grafis.
WGSL digunakan untuk menulis ketiga jenis shader ini. Jadi, Anda akan menulis kode WGSL yang akan dikompilasi dan dijalankan langsung di GPU.
3. WGSL 101: Sintaks Dasar
WGSL memiliki sintaks yang mirip dengan C, Rust, atau GLSL (pendahulu shader di OpenGL/WebGL), tetapi dengan beberapa karakteristik modern dan spesifik untuk WebGPU.
Tipe Data Dasar
WGSL memiliki tipe data yang familiar:
- Integer:
i32(signed 32-bit integer),u32(unsigned 32-bit integer). - Floating-point:
f32(32-bit float),f16(16-bit float, opsional untuk performa). - Boolean:
bool.
Vektor dan Matriks
GPU sangat efisien dalam memproses data dalam bentuk vektor dan matriks. WGSL mendukung ini secara built-in:
- Vektor:
vec2<f32>,vec3<i32>,vec4<u32>, dll. Angka setelahvecmenunjukkan jumlah komponen (2, 3, atau 4), dan<type>menunjukkan tipe data komponennya.- Anda bisa mengakses komponen dengan
.x,.y,.z,.watau.r,.g,.b,.a. - Swizzling juga didukung:
my_vec.xy = another_vec.zw;
- Anda bisa mengakses komponen dengan
- Matriks:
mat2x2<f32>,mat3x4<f32>, dll.matCxR<type>berarti matriks dengan C kolom dan R baris.
Struktur (Structs)
Anda bisa mendefinisikan tipe data kustom menggunakan struct, mirip dengan bahasa C:
struct VertexInput {
[[location(0)]] position: vec4<f32>,
[[location(1)]] color: vec4<f32>,
};
struct Uniforms {
model_view_projection_matrix: mat4x4<f32>,
time: f32,
};
📌 Perhatikan atribut [[location(X)]] yang akan kita bahas nanti. Ini penting untuk menghubungkan input/output shader dengan data dari CPU.
Variabel dan Konstanta
Deklarasi variabel menggunakan var dan konstanta menggunakan const. Tipe data dapat disimpulkan atau dideklarasikan secara eksplisit.
const PI: f32 = 3.14159;
var my_color: vec4<f32> = vec4<f32>(1.0, 0.0, 0.0, 1.0); // Merah
var position = vec3<f32>(0.0, 0.0, 0.0); // Tipe disimpulkan
Fungsi (Functions)
Fungsi didefinisikan dengan fn. Setiap shader harus memiliki fungsi main atau fungsi yang ditandai dengan [[stage(vertex)]], [[stage(fragment)]], atau [[stage(compute)]].
fn add_vectors(a: vec3<f32>, b: vec3<f32>) -> vec3<f32> {
return a + b;
}
4. Input/Output Shader: Atribut, Varying, dan Binding
Bagaimana data bisa masuk ke shader dan keluar dari shader? WGSL menggunakan beberapa mekanisme penting:
Atribut Input (Vertex Shader)
Data yang masuk ke vertex shader untuk setiap vertex (misalnya posisi, warna, normal) disebut atribut. Anda mendeklarasikannya di struct input vertex shader dengan atribut [[location(X)]]. X adalah indeks lokasi yang harus cocok dengan konfigurasi buffer di WebGPU API.
// Input untuk Vertex Shader
struct VertexInput {
[[location(0)]] position: vec4<f32>, // Posisi vertex
[[location(1)]] color: vec4<f32>, // Warna vertex
};
Varying (Komunikasi Vertex ke Fragment Shader)
Data yang dihitung di vertex shader dan perlu diteruskan ke fragment shader disebut “varying” (karena nilainya bervariasi antar fragment). Data ini akan di-interpolasi secara otomatis oleh GPU di antara vertex-vertex. Anda mendeklarasikannya di struct output vertex shader dan struct input fragment shader, juga dengan [[location(X)]].
// Output dari Vertex Shader, Input untuk Fragment Shader
struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>, // Posisi akhir di layar (built-in)
[[location(0)]] interpolated_color: vec4<f32>, // Warna yang diinterpolasi
};
📌 [[builtin(position)]] adalah atribut khusus untuk output posisi vertex. WebGPU membutuhkan ini agar tahu di mana harus menggambar. Ada banyak [[builtin]] lainnya seperti vertex_index, instance_index, frag_depth, dll.
Binding (Uniforms, Textures, Buffers)
Untuk data yang tidak berubah per vertex atau per fragment, seperti matriks transformasi (model-view-projection), tekstur, atau buffer data umum, kita menggunakan [[group(X), binding(Y)]].
[[group(X)]]: Menentukan grup binding (misalnya, grup 0 untuk data global, grup 1 untuk data material).[[binding(Y)]]: Menentukan indeks binding di dalam grup tersebut. Ini harus cocok dengan indeks yang Anda atur diGPUBindGroupLayoutWebGPU API.
// Uniform Buffer (data yang sama untuk semua vertex/fragment dalam satu draw call)
@group(0) @binding(0)
var<uniform> uniforms: Uniforms; // `Uniforms` adalah struct yang kita definisikan sebelumnya
// Texture
@group(0) @binding(1)
var my_texture: texture_2d<f32>;
// Sampler (cara membaca tekstur)
@group(0) @binding(2)
var my_sampler: sampler;
// Storage Buffer (untuk compute shader, bisa dibaca/ditulis)
@group(1) @binding(0)
var<storage, read_write> data_buffer: array<f32>;
⚠️ var<uniform> berarti data hanya-baca. var<storage, read_write> berarti data bisa dibaca dan ditulis (umumnya untuk compute shader).
5. Fungsi dan Kontrol Aliran
WGSL mendukung struktur kontrol aliran yang Anda kenal:
- Kondisional:
if,else if,else - Perulangan:
for,while - Switch:
switch
fn calculate_light(normal: vec3<f32>, light_dir: vec3<f32>) -> f32 {
let dot_product = dot(normal, light_dir);
if dot_product > 0.0 {
return dot_product;
} else {
return 0.0;
}
}
WGSL juga memiliki banyak fungsi built-in untuk matematika vektor/matriks (seperti dot, cross, normalize, length), fungsi trigonometri (sin, cos, tan), dan fungsi umum lainnya yang sangat berguna dalam grafis.
6. Contoh Praktis: Shader Sederhana (Segitiga Berwarna)
Mari kita buat shader WGSL yang paling dasar untuk menggambar segitiga berwarna. Ini akan melibatkan satu vertex shader dan satu fragment shader.
Vertex Data (JavaScript/TypeScript)
Pertama, kita siapkan data vertex di sisi JavaScript. Anggap kita punya segitiga dengan 3 vertex, masing-masing punya posisi dan warna.
// Ini contoh data yang akan kita kirim ke GPU
const vertices = new Float32Array([
// Posisi (x, y, z, w) | Warna (r, g, b, a)
0.0, 0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, // Top vertex: Merah
-0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, // Left vertex: Hijau
0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, // Right vertex: Biru
]);
// Nanti di WebGPU API, kita akan mengkonfigurasi buffer ini
// agar posisi masuk ke location(0) dan warna ke location(1)
WGSL Vertex Shader (shader.wgsl)
// Mendefinisikan struktur input untuk vertex shader
// [[location(0)]] akan menerima posisi vertex dari buffer
// [[location(1)]] akan menerima warna vertex dari buffer
struct VertexInput {
[[location(0)]] position: vec4<f32>,
[[location(1)]] color: vec4<f32>,
};
// Mendefinisikan struktur output dari vertex shader
// Ini juga akan menjadi input untuk fragment shader (varying)
struct VertexOutput {
// [[builtin(position)]] adalah output wajib yang menentukan posisi akhir di layar
[[builtin(position)]] clip_position: vec4<f32>,
// [[location(0)]] adalah output warna yang akan diinterpolasi
[[location(0)]] interpolated_color: vec4<f32>,
};
// Fungsi utama vertex shader
// [[stage(vertex)]] menandakan ini adalah vertex shader
fn main(input: VertexInput) -> VertexOutput {
var output: VertexOutput;
output.clip_position = input.position; // Cukup terusan posisi mentah untuk contoh 2D sederhana
output.interpolated_color = input.color; // Meneruskan warna ke fragment shader
return output;
}
💡 Di sini, kita hanya meneruskan posisi dan warna. Dalam aplikasi 3D nyata, input.position akan dikalikan dengan matriks model-view-projection di sini.
WGSL Fragment Shader (shader.wgsl)
// Mendefinisikan struktur input untuk fragment shader
// Ini sama dengan struktur output dari vertex shader
struct FragmentInput {
[[builtin(position)]] frag_coord: vec4<f32>, // Koordinat piksel di layar (built-in)
[[location(0)]] interpolated_color: vec4<f32>, // Warna yang diinterpolasi dari vertex shader
};
// Fungsi utama fragment shader
// [[stage(fragment)]] menandakan ini adalah fragment shader
// -> vec4<f32> adalah warna akhir piksel (RGBA)
fn main(input: FragmentInput) -> [[location(0)]] vec4<f32> {
// Cukup gunakan warna yang sudah diinterpolasi dari vertex shader
return input.interpolated_color;
}
✅ Tips: Untuk memulai, selalu coba dengan warna solid (return vec4<f32>(1.0, 0.0, 0.0, 1.0);) di fragment shader untuk memastikan pipeline rendering Anda berfungsi sebelum menambahkan kompleksitas.
Dengan shader-shader ini, dan kode WebGPU API yang sesuai untuk mengatur pipeline rendering, Anda akan melihat segitiga dengan gradasi warna dari merah ke hijau ke biru di layar!
Kesimpulan
WGSL adalah pintu gerbang menuju kekuatan penuh GPU di web. Sebagai bahasa shader yang modern dan efisien, WGSL memungkinkan developer web untuk menciptakan pengalaman visual yang kaya, melakukan komputasi paralel yang intensif, dan mendorong batas-batas performa aplikasi web.
Memulai dengan WGSL mungkin terasa seperti belajar bahasa baru yang asing, tetapi dengan sintaks yang terstruktur dan konsep yang jelas mengenai bagaimana data mengalir melalui GPU, Anda akan segera mampu menulis shader yang mengubah cara aplikasi web Anda berinteraksi dengan hardware. Ini bukan hanya tentang grafis 3D; ini tentang membuka dimensi baru performa dan kemampuan di browser. Jadi, mulailah bereksperimen, tulis shader pertama Anda, dan saksikan GPU Anda bekerja!
🔗 Baca Juga
- WebGPU: Revolusi Grafis dan Komputasi Berkinerja Tinggi di Browser Anda
- Mengoptimalkan Komputasi Berat di Web: Memadukan WebAssembly dan Web Workers untuk Performa Maksimal
- WebGPU untuk Komputasi Paralel di Browser: Memanfaatkan Kekuatan GPU untuk Data Processing
- WebXR: Membangun Pengalaman Augmented Reality dan Virtual Reality Langsung di Browser Anda