跳转到主内容
◆ 文章 · Article

WebGPU vs TypeGPU 交互式对比

通过可交互的实时演示,直观对比两者在 GPU 执行性能、开发体验与类型安全性上的真实差异——性能完全一致,差距全在工程效率。

WebGPU TypeGPU WGSL 交互演示
[ 00 ]

目录

按章节顺序排列,点击直接跳转。

  • 7 个章节

需要 Chrome 113+ / Edge 113+ / Safari 17+ 才能体验 GPU 实时演示;内存布局、代码对比与性能图表在不支持 WebGPU 时也可正常交互。

[ 01 ]

关键洞察

GPU 执行性能完全一致,真正的差异在开发效率、类型安全与内存布局管理。

TypeGPU 是 WebGPU 的上层类型安全封装,两者在 GPU 上的 执行性能完全一致——因为 TypeGPU 在构建时把 TypeScript 编译为 WGSL, 运行时直接调用原生 WebGPU API。真正的差异体现在开发效率、类型安全和内存布局管理上。 本页所有演示均在浏览器中实时运行,你可以拖动滑块、切换模式亲手验证。

关键洞察:两者 GPU 执行性能完全一致,差异在开发效率、类型安全与内存布局管理。
[ 02 ]

实时渲染对比

拖动滑块、切换演示模式,两侧画布用同一套粒子系统并行渲染,读数逐帧刷新。

LIVE GPU 同一份 Particle 结构体 · 两侧独立画布
50,000
5x
演示模式
原生 WebGPU 手动 WGSL + 手动布局
60
FPS
0.8
GPU 时间 · ms / frame
2.1
CPU 开销 · ms / frame
12
显存占用 · MB
TypeGPU TypeScript + 自动布局
60
FPS
0.8
GPU 时间 · ms / frame
0.4
CPU 开销 · ms / frame
12
显存占用 · MB
[ 03 ]

内存布局对比

同一份 Particle 结构体:一边手动计算 offset 与 stride,一边由 typed-binary 自动对齐。

INTERACTIVE 点击按钮切换字段顺序,观察手动布局的偏移量如何失效

点击按钮修改结构体字段顺序,观察手动布局如何容易出错。 vec3f 实际占 16 字节(含 4 字节填充)!

WebGPU:手动计算偏移量
position (vec3f)
color (vec3f)
velocity (vec2f)
padding (浪费)
TypeGPU:声明式自动布局
position (vec3f)
color (vec3f)
velocity (vec2f)
padding (自动优化)
布局始终正确! TypeGPU 的 typed-binary 自动计算所有 offset、stride 和 padding,WGSL 结构体定义同步生成。修改 Schema 一处,全项目自动更新。
  • [*]WGSL 结构体手写字符串 / 类型生成
  • [*]offset 与 stride手动计算 / 自动推导
  • [*]vec3f 对齐16 bytes(含填充)
  • [*]字段顺序变更改 3 处 / 改 1 处
  • [*]错误发现时机运行时异常 / 编译时报错
[ 04 ]

代码复杂度实时对比

同一功能的两种写法:着色器、管线配置与内存布局三处并排对照。

INTERACTIVE 标签页切换只替换面板内容,不重新创建演示

相同功能:原生 WebGPU 约 142 行有效代码,TypeGPU 约 48 行。 切换标签页查看着色器、管线配置与内存布局三处的写法差异。

WebGPU 实现 ~142 行有效代码
TypeGPU 实现 ~48 行有效代码
同等功能的有效代码行数 142 → 48 ▼ 66%
开发效率提升 3× ▲ 3.0×
需要手动维护的 offset 3 → 0 −3
[ 05 ]

GPU 执行性能历史(证明两者性能一致)

粒子数量增加时,WebGPU 与 TypeGPU 的 GPU 执行时间曲线完全重合。

LIVE 曲线由页面实时采样绘制

随着粒子数量增加,WebGPU 和 TypeGPU 的 GPU 执行时间曲线完全重合, 证明 TypeGPU 的运行时性能与原生 WebGPU 相同。差异仅体现在 CPU 侧的开发效率上。

吞吐与开销

RATIO
GPU 执行时间 · WebGPU 0.8 ms / frame
GPU 执行时间 · TypeGPU 0.8 ms / frame
CPU 开销 · WebGPU 2.1 ms / frame
CPU 开销 · TypeGPU 0.4 ms / frame
GPU 执行时间 · 两侧一致 0.8 ms ≈ 0
CPU 开销 ms / frame 2.1 → 0.4 ▼ 81%
[ 06 ]

着色器代码走查

页面上实时运行的着色器:WebGPU 侧手写 WGSL,TypeGPU 侧由 TypeScript 编译出同一份 WGSL。

wgsl particle.compute.wgsl

      struct Particle {  pos: vec2f, vel: vec2f, color: vec3f, life: f32,}; @binding(0) @group(0) var<storage, read_write> particles: array<Particle>;@binding(1) @group(0) var<uniform> params: vec4f; @compute @workgroup_size(64)fn computeMain(@builtin(global_invocation_id) id: vec3u) {  let idx = id.x; let count = u32(params.x);  if (idx >= count) { return; }  var p = particles[idx];  let dt = params.y; let load = u32(params.z); let mode = u32(params.w);  if (mode == 0u) {    p.pos = p.pos + p.vel * dt;    p.vel.y = p.vel.y - 0.5 * dt;    if (p.pos.y < -1.0) { p.pos.y = -1.0; p.vel.y = p.vel.y * -0.8; }    if (p.pos.x < -1.0 || p.pos.x > 1.0) { p.vel.x = p.vel.x * -0.9; p.pos.x = clamp(p.pos.x, -1.0, 1.0); }  } else if (mode == 1u) {    let dir = vec2f(0.0, 0.0) - p.pos;    let dist = length(dir);    if (dist > 0.01) { p.vel = p.vel + normalize(dir) * 3.0 * dt; }    p.pos = p.pos + p.vel * dt; p.vel = p.vel * 0.995;  } else {    p.pos = p.pos + p.vel * dt; p.vel = p.vel * 0.999;    if (length(p.pos) > 1.0) { p.vel = p.vel * -0.95; p.pos = normalize(p.pos) * 0.98; }  }  var dummy = 0.0;  for (var i = 0u; i < load; i = i + 1u) { dummy = dummy + sin(f32(i) * 0.01 + p.pos.x) * 0.0001; }  p.pos.x = p.pos.x + dummy;  p.life = p.life - dt * 0.15;  if (p.life <= 0.0) {    p.life = 1.0; let seed = f32(idx);    p.pos = vec2f(fract(sin(seed * 12.9898) * 43758.5453) * 2.0 - 1.0, fract(sin(seed * 78.233) * 43758.5453) * 2.0 - 1.0);    p.vel = vec2f(fract(sin(seed * 43.123) * 23421.0) * 2.0 - 1.0, fract(sin(seed * 91.456) * 12345.0) * 2.0 - 1.0) * 0.5;  }  particles[idx] = p;}
  
wgsl particle.render.wgsl

      struct VertexOut {  @builtin(position) pos: vec4f,  @location(0) color: vec3f,  @location(1) life: f32,}; @vertexfn vertexMain(@location(0) pos: vec2f, @location(1) vel: vec2f, @location(2) color: vec3f, @location(3) life: f32) -> VertexOut {  var out: VertexOut; out.pos = vec4f(pos, 0.0, 1.0); out.color = color; out.life = life; return out;} @fragmentfn fragmentMain(@location(0) color: vec3f, @location(1) life: f32) -> @location(0) vec4f {  let alpha = smoothstep(0.0, 0.2, life); return vec4f(color * (0.5 + life * 0.5), alpha * 0.9);}
  
  • [*]particle buffer32 bytes / vertex
  • [*]attributespos · vel · color · life
  • [*]workgroup64 invocations
  • [*]compute pass1 dispatch / frame
  • [*]topologypoint-list
[ 07 ]

核心结论

性能一致、类型前移、效率三倍——差距全部落在工程侧。

GPU 性能:完全一致

TypeGPU 在构建时将 TypeScript 编译为 WGSL,运行时直接调用原生 WebGPU API。GPU 执行性能与原生 WebGPU 完全一致,无额外开销。上图中的双曲线重合证明了这一点。

类型安全:编译时捕获

TypeGPU 消除了 JS 与 WGSL 之间的类型断层。缓冲区类型、着色器参数、内存布局在编译时即被验证,错误在代码编写阶段就被捕获,而不是在运行时以奇怪的画面异常呈现。

开发效率:提升 3 倍

相同功能下 TypeGPU 代码量减少 60% 以上。无需手动计算偏移量、无需维护 WGSL 字符串、无需担心内存对齐陷阱。团队中的任何 TypeScript 开发者都能参与 GPU 编程。

评论区 留下您的想法
教程