真实场景痛点分析:
技术选型对比:
graph LR
A[计算密集型任务] --> B[WebAssembly]
C[图形渲染任务] --> D[WebGPU]
B --> E[共享内存]
D --> E
# 启用Chrome实验特性
chrome://flags/#enable-unsafe-webgpu
// 检测WebGPU支持
if (!navigator.gpu) {
throw new Error("WebGPU not supported!");
}
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
# Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
rayon = "1.5" # 并行计算库
# 安装wasm-pack
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
# 编译命令
wasm-pack build --target web --release
sequenceDiagram
Main Thread->>+Worker: 初始化命令
Worker->>+WASM: 创建粒子系统(1,000,000)
WASM-->>-Worker: 内存指针
loop 每帧循环
Worker->>WASM: 调用update(dt)
WASM->>GPU: 通过共享内存更新
Worker->>GPU: 提交渲染指令
end
// Rust端导出内存
#[wasm_bindgen]
pub fn get_memory_buffer() -> JsValue {
let memory = wasm_bindgen::memory();
memory
}
// JavaScript端访问
const wasmMemory = new WebAssembly.Memory({ initial: 256 });
const positions = new Float32Array(wasmMemory.buffer, 0, 1000000 * 3);
const velocities = new Float32Array(wasmMemory.buffer, 1000000 * 12, 1000000 * 3);
// 创建GPU缓冲
const gpuBuffer = device.createBuffer({
size: positions.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
mappedAtCreation: true
});
// 直接内存映射
const arrayBuffer = gpuBuffer.getMappedRange();
new Uint8Array(arrayBuffer).set(new Uint8Array(wasmMemory.buffer));
gpuBuffer.unmap();
use rayon::prelude::*;
fn update_particles(positions: &mut [f32], velocities: &mut [f32], dt: f32) {
positions.par_chunks_mut(3)
.zip(velocities.par_chunks_mut(3))
.for_each(|(pos, vel)| {
// SIMD加速计算
vel[1] -= 9.8 * dt;
pos[0] += vel[0] * dt;
pos[1] += vel[1] * dt;
pos[2] += vel[2] * dt;
});
}
// 着色器代码
struct VertexOutput {
[[builtin(position)]] Position : vec4;
[[location(0)]] color : vec4;
};
[[group(0), binding(0)] var particles : array>;
[[stage(vertex)]]
fn vs_main([[builtin(instance_index)]] instance : u32) -> VertexOutput {
let position = particles[instance].xyz;
return VertexOutput(
vec4(position, 1.0),
vec4(0.9, 0.2, 0.4, 1.0)
);
}
// 标记性能时间线
performance.mark("simulation-start");
// ... 计算代码 ...
performance.mark("simulation-end");
performance.measure("Simulation", "simulation-start", "simulation-end");
const commandEncoder = device.createCommandEncoder();
// ... 渲染指令 ...
const commands = commandEncoder.finish();
// 注入查询
const querySet = device.createQuerySet({
type: 'timestamp',
count: 2
});
commandEncoder.writeTimestamp(querySet, 0);
// ... 渲染代码 ...
commandEncoder.writeTimestamp(querySet, 1);
const memory = window.performance.memory;
console.log(`JS heap: ${memory.usedJSHeapSize / 1024 / 1024}MB`);
线程安全陷阱
// 错误示例:直接传递TypedArray
worker.postMessage(positions); // 导致内存复制
// 正确方式:共享内存
worker.postMessage({buffer: wasmMemory.buffer}, [wasmMemory.buffer]);
精度问题
// 使用全精度计算
[[stage(fragment)]]
fn fs_main() -> [[location(0)]] vec4 {
return vec4(0.9, 0.2, 0.4, 1.0);
}
设备兼容方案
// 自动降级逻辑
async function initRenderer() {
try {
return await initWebGPU();
} catch {
return await initWebGL();
}
}
fn compute_density(particles: &mut [Particle]) {
particles.par_iter_mut().for_each(|pi| {
let mut density = 0.0;
for pj in particles.iter() {
let r = (pi.position - pj.position).norm();
density += KERNEL(r, h);
}
pi.density = density;
});
}
[[stage(vertex)]]
fn vs_main([[location(0)]] pos: vec3) -> [[builtin(position)]] vec4 {
let new_pos = 2.0 * pos - prev_pos + acceleration * dt * dt;
return vec4(new_pos, 1.0);
}
const lodConfig = {
0: { distance: 100, resolution: 1024 },
1: { distance: 500, resolution: 512 },
2: { distance: 1000, resolution: 256 }
};
粒子数量 | WASM计算时间 | GPU渲染时间 | 总帧时间 |
---|---|---|---|
100,000 | 2.1ms | 4.3ms | 6.4ms |
500,000 | 8.7ms | 6.1ms | 14.8ms |
1,000,000 | 14.2ms | 8.9ms | 23.1ms |
测试设备:M1 MacBook Pro / Chrome 105
/webgpu-wasm-demo
├── src
│ ├── lib.rs # WASM核心逻辑
│ ├── renderer.js # WebGPU渲染器
│ └── worker.js # 工作线程控制
├── assets
│ └── shaders # WGSL着色器集合
└── benchmarks
└── stress-test # 压力测试场景
浏览器 | WebGPU支持 | WASM线程支持 |
---|---|---|
Chrome 105+ | ✅ | ✅ |
Edge 105+ | ✅ | ✅ |
Firefox | Flag启用 | ✅ |
Safari | 开发中 | ✅ |
掌握这套混合方案,你不仅可以实现: