我们的数据可视化平台遇到过一堵墙:一张散点图上叠了120万个数据点,再加时间轴回放,Canvas2D的拖拽帧率一路跌到十五六帧。试过降采样、分块绘制、离屏画布加Worker,能续命,但救不了根。最终痛下决心迁移WebGPU,过程比预想的曲折,这里把最值得警惕的几个坑记录下来。
第一关是数据上传。CPU侧的Float32Array一次性灌进GPU缓冲是对的,千万别在每帧重建数据。真正咬人的是内存对齐:uniform buffer里的成员要按16字节对齐,一个mat4后面紧跟一个float,偏移量不按规则补齐,着色器读到的就是随机数,而且不报任何错,排查起来非常耗时。结论是先封一层安全的缓冲写入工具,再写业务。
第二关是渲染管线本身。百万级散点的正确姿势是实例化绘制:一个三角形实例化一百万次,点的位置、大小、颜色计算全部下放到顶点着色器,颜色查一张调色板纹理。CPU每帧只需要更新一个矩阵。听起来简单,前提是习惯了管线对象、绑定组这套显式声明的写法——WebGL时代全局状态随手设的写法在这里寸步难行。
第三个坑最隐蔽:半透明点的视觉错误。Canvas2D里大量半透明点叠在一起看个大概就行,WebGPU的混合默认按绘制顺序合成,实例化顺序是任意的,密集区域的颜色会随帧跳动。我们的解法是把Alpha预乘,同时接受“密度示意”而非“精确叠色”,并在产品上把单点透明度调高,视觉上立刻稳定。
还有两个平台级陷阱。一是设备像素比与窗口resize,画布尺寸变了没有重建深度缓冲,画面会直接黑屏或错位,这类低级错误在三个端上各复现了一次才长记性。二是部分移动设备对单个绑定组里的存储缓冲上限有硬性约束,我们的大点集不得不按上限拆成多段缓冲,绘制时分批提交,拆分逻辑一旦忘了处理余数,就会莫名丢点。
交互层面,拾取从遍历变成了架构问题。JS里循环一百万个点找“鼠标点到了谁”,帧率直接被吃光。可行方案有二:GPU拾取,把点ID渲染到离屏纹理再读回;或者更务实,先在CPU维护一棵R树,把候选集从百万压到千位再精判。回放动画的进度条拖拽同理,时间索引预建比每帧现算快两个数量级。
收益是实打实的:同等数据量下稳定60帧,CPU占用从九成降到两成,风扇安静了,页面其他部分也不再卡顿。但我想给准备迁移的同行泼两盆冷水:第一,先测量再迁移,相当一部分Canvas图表配合离屏渲染和脏矩形就能活,不必全员上WebGPU;第二,迁移等于重写,请按图表类型灰度切换,保留自动回退到Canvas的能力,因为WebGPU在个别旧设备上的可用性,仍然需要在运行时探测,而不是写在需求文档里假设成立。
A5创业网 版权所有