WebGPU Compute Shaders實戰:瀏覽器端GPU計算入門與優化
WebGPU Compute Shaders:被忽視的GPU計算殺手鐧
當大多數人談論WebGPU時,第一反應總是「WebGL的替代品」。但如果你只把WebGPU當成新一代圖形API來用,那就大錯特錯了——Compute Shader才是WebGPU真正的殺手鐧。
WebGPU的Compute Shader讓瀏覽器首次擁有了通用GPU計算(GPGPU)的原生能力,這不是漸進式改進,而是範式轉換。
WebGL時代要做GPGPU,只能把資料塞進紋理,用片段著色器模擬計算,再把結果讀回CPU。WebGPU的Compute Shader直接打破了這一限制。
WGSL著色器語言核心語法
WebGPU引入了全新的著色器語言WGSL,取代了GLSL。來看核心語法:
@group(0) @binding(0) var<storage, read> inputData: array<f32>;
@group(0) @binding(1) var<storage, read_write> outputData: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let idx = global_id.x;
if (idx >= arrayLength(&inputData)) { return; }
outputData[idx] = inputData[idx] * 2.0;
}
Workgroup Size建議
| 硬體 | 建議大小 | 說明 |
|---|---|---|
| NVIDIA | 128-256 | Warp大小為32 |
| AMD | 64-128 | Wavefront大小為64 |
| Intel | 32-64 | 子群組大小較小 |
| 通用安全值 | 64 | 相容所有硬體 |
Compute Shader vs WebGL Transform Feedback
| 維度 | WebGL TF | WebGPU Compute |
|---|---|---|
| 程式設計模型 | 偽裝成渲染管線的計算 | 原生通用計算 |
| 資料傳遞 | 紋理/VBO | Storage Buffer |
| 執行緒控制 | 頂點數模擬 | 精確的dispatch控制 |
| 資料回讀 | readPixels極慢 | mapAsync高效 |
| 隨機寫入 | 不支援 | 原子操作+隨機寫入 |
| 共用記憶體 | 無 | Workgroup Shared Memory |
實戰:Compute Shader實現影像高斯模糊
JavaScript處理一張1080p影像的高斯模糊需要約450ms,而Compute Shader可以在約5ms內完成——快了約50倍。
@group(0) @binding(0) var srcTexture: texture_2d<f32>;
@group(0) @binding(1) var dstTexture: texture_storage_2d<rgba8unorm, write>;
@group(0) @binding(2) var<uniform> params: Params;
struct Params {
width: u32,
height: u32,
radius: f32,
}
@compute @workgroup_size(16, 16)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let pixel_coords = vec2<u32>(global_id.x, global_id.y);
if (pixel_coords.x >= params.width || pixel_coords.y >= params.height) { return; }
let sigma = params.radius / 3.0;
var color = vec4<f32>(0.0);
var total_weight = 0.0;
let radius_i = i32(params.radius);
for (var dx: i32 = -radius_i; dx <= radius_i; dx++) {
for (var dy: i32 = -radius_i; dy <= radius_i; dy++) {
let weight = exp(-(f32(dx)*f32(dx) + f32(dy)*f32(dy)) / (2.0*sigma*sigma));
let sx = clamp(i32(pixel_coords.x) + dx, 0, i32(params.width) - 1);
let sy = clamp(i32(pixel_coords.y) + dy, 0, i32(params.height) - 1);
color += textureLoad(srcTexture, vec2<u32>(sx, sy), 0) * weight;
total_weight += weight;
}
}
textureStore(dstTexture, pixel_coords, color / total_weight);
}
效能對比
| 方案 | 1080p (r=10) | 4K (r=10) |
|---|---|---|
| JavaScript | ~450ms | ~1800ms |
| Web Worker (4執行緒) | ~130ms | ~520ms |
| WebGL片段著色器 | ~12ms | ~45ms |
| WebGPU Compute | ~5ms | ~18ms |
實戰:大規模粒子模擬(10萬粒子60fps)
10萬個粒子每幀需要更新位置、速度、碰撞偵測,CPU根本無法負荷。
struct Particle {
pos: vec2<f32>,
vel: vec2<f32>,
color: vec4<f32>,
life: f32,
}
@group(0) @binding(0) var<storage, read_write> particles: array<Particle>;
@compute @workgroup_size(256)
fn updateParticles(@builtin(global_invocation_id) global_id: vec3<u32>) {
let idx = global_id.x;
if (idx >= arrayLength(&particles)) { return; }
var p = particles[idx];
p.vel.y += -9.8 * 0.016;
p.vel *= 0.999;
p.pos += p.vel * 0.016;
if (p.pos.y < 0.0) { p.pos.y = 0.0; p.vel.y *= -0.7; }
p.life -= 0.016;
if (p.life <= 0.0) {
p.pos = vec2<f32>(0.5, 0.8);
p.life = 3.0;
}
particles[idx] = p;
}
關鍵技巧:同一個buffer同時作為STORAGE | VERTEX使用,實現Compute→Render零拷貝。
瀏覽器相容性
| 瀏覽器 | 支援狀態 | 版本 |
|---|---|---|
| Chrome | ✅ 完整支援 | 113+ |
| Edge | ✅ 完整支援 | 113+ |
| Firefox | ⚠️ 實驗性 | Nightly |
| Safari | ⚠️ 部分支援 | 17.4+ |
與Web Worker + SharedArrayBuffer的協作模式
主執行緒 (WebGPU Compute) → mapAsync → SharedArrayBuffer → Web Worker (邏輯處理)
這種模式特別適合「GPU做重計算,CPU做邏輯決策」的場景,例如物理模擬中GPU算碰撞,CPU做遊戲邏輯。
總結
WebGPU Compute Shader為Web平台帶來了真正的GPU通用計算能力。2026年的今天,Chrome 113+已經穩定支援,生態工具鏈也在快速成熟。下一步值得關注WebGPU Subgroups和Ray Tracing提案。
本站提供瀏覽器本地工具,免註冊即可試用 →
#WebGPU#Compute Shader#GPU计算#WGSL#并行计算