vgpu/mock实战:确定性模拟适配器让GPU单元测试不依赖显卡
【免费下载链接】vgpuModular cross-runtime WebGPU library for shaders, 3D scenes, GPU tensors, neural networks, and math viz项目地址: https://gitcode.com/gh_mirrors/vgpu/vgpu
vgpu(@vgpu/adapter-mock)提供了一套纯 JavaScript 的确定性模拟 WebGPU 适配器,通过vgpu/mock入口即可启动一个"无显卡"的完整Gpu实例。你的单元测试从此不再需要真实 GPU、Dawn 或原生渲染库——缓冲区写入、纹理回读、资源创建次数全部可在内存中复现,字节级一致、随时可跑。
为什么 GPU 单元测试需要 mock
WebGPU 的测试天然面临三大难题:
- 环境依赖:CI 容器、无头服务器往往没有 GPU,也没有 Vulkan/Metal 驱动;
- 结果不确定:不同显卡的浮点精度、渲染时序都可能让"像素级断言"变得脆弱;
- 启动成本高:真实的 Node 端 WebGPU 依赖 Dawn 原生库,安装慢、版本漂移大。
vgpu/mock的解法很直接:用一个纯内存的假 GPU 设备替换硬件层。所有缓冲区都是Uint8Array,writeBuffer真的会拷贝字节,writeTexture真的按行偏移写入像素——所以"写进去再读出来"的往返测试在 mock 上与真机行为完全一致。
💡 官方文档的建议是:用
vgpu/mock跑确定性单元测试,只有在验证 Dawn/WebGPU 真实行为时才用vgpu/node。详见 docs/topics/browser-testing.docs.md。
三步完成无显卡测试环境
第1步:安装模拟适配器包
pnpm add -D @vgpu/adapter-mock包说明见 packages/adapter-mock/README.md。
第2步:用vgpu/mock入口启动
import { init, storage } from "vgpu/mock"; const gpu = await init(); const buffer = storage(gpu, 16); buffer.write(new Float32Array([1, 2, 3, 4])); await buffer.read(); // 字节级回读,无需显卡 gpu.dispose();入口实现非常薄:packages/vgpu-api/src/mock.ts 中init()只是把"mock"目标传给createGpu,其余 API(bundle、frame、compute、surface等)与真实入口完全同签名,切换测试环境不需要改一行业务代码。
第3步:断言行为而非像素
mock 设备自带计量器(instrumentation):每次createBuffer、createBindGroup、createCommandEncoder都会被计数并记录描述符。你可以在测试里直接断言"某段代码恰好创建了 2 个绑定组",这比截图对比稳定得多。
确定性从哪来:4个核心设计
📦内存缓冲区— packages/core/src/mock-gpu.ts 中createMockBuffer用Uint8Array承载数据,getMappedRange直接返回字节视图,回读路径与真实设备共用同一套readback代码。
🧾描述符全记录— 所有资源创建的描述符都被原样存档,测试可事后校验 usage 标志、label、尺寸等参数是否符合预期。
🎯特性开关可声明— packages/adapter-mock/src/index.ts 的createMockAdapter({ features })让你声明"这块假显卡支持哪些特性"。请求未声明的requiredFeatures会抛出VGPU-FEATURE-UNSUPPORTED,方便同时测试特性开启/关闭两条代码路径。
📊查询结果可预测—resolveQuerySet按index × index × 10⁶生成确定值:时间戳查询得到可区分的正差值,遮挡查询的索引 0 解码为"隐藏"、其余为"可见",两条解码路径都能端到端覆盖。
测试什么、不测什么
✅ 适合用vgpu/mock | ⚠️ 需要真实设备(vgpu/node或浏览器) |
|---|---|
| 缓冲区/纹理写入-回读往返 | 像素级渲染快照 |
| 资源创建调用序列与参数 | WGSL 着色器编译/着色输出 |
错误作用域(pushErrorScope)行为 | 真实性能与时序测量 |
| 生命周期管理(destroy 幂等性) | Dawn 特定的 WebGPU 行为 |
官方示例测试 packages/adapter-mock/tests/buffer-readback.test.ts 展示了典型写法:
const { device } = await init(); const data = new Float32Array([1, 2, 3, 4]); const buffer = device.createBuffer({ size: data.byteLength, usage: ["copy_dst", "copy_src", "storage"], }); buffer.write(data); const readback = new Float32Array(await buffer.read(data.byteLength)); expect(readback).toEqual(data); // 字节相等,确定性回读进阶:在 vgpu-api 测试中复用 mock
如果你正在开发依赖vgpu高层 API 的模块,仓库提供了现成的测试工具 packages/vgpu-api/test-utils/mock.ts:
createMockGpu(options)— 启动一个不加载 Dawn 的Gpu实例;getMockDeviceInstrumentation(gpu)— 拿到计量计数器,直接断言资源创建次数。
const gpu = await createMockGpu(); // ... 执行你的逻辑 ... const inst = getMockDeviceInstrumentation(gpu); expect(inst.calls.createBindGroup).toBe(2);这套组合让 GPU 代码的单元测试和 HTTP 服务一样:秒级启动、离线可跑、每次结果相同。把真实设备留给端到端与像素快照测试,把确定性回归交给vgpu/mock——这就是它作为"确定性模拟适配器"的核心价值。
【免费下载链接】vgpuModular cross-runtime WebGPU library for shaders, 3D scenes, GPU tensors, neural networks, and math viz项目地址: https://gitcode.com/gh_mirrors/vgpu/vgpu
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考