webgpu-forge
v1.1.0
Published
WGSL-aware WebGPU binding memory layout and ArrayBuffer writing utilities.
Maintainers
Readme
webgpu-forge
一个面向 WebGPU 的工具库,当前重点是 WGSL 兼容的 binding memory layout 解析 和 ArrayBuffer 数据写入。
当前状态
BufferBindingMemory 是目前正在持续完善的核心 API 之一,已经覆盖以下基础流程:
- 解析 WGSL 中的
@group(...) @binding(...) var<uniform|storage>资源声明 - 计算正确的布局、对齐、偏移和 padding
- 创建大小正确的
ArrayBuffer - 把普通 JavaScript 对象 / 数组 / TypedArray 写入 buffer
下面的示例重点展示当前 API 的作用和使用方式。后续随着功能继续增加,公开 API 和文档内容还会继续扩展。
安装
npm install webgpu-forgeBufferBindingMemory
源码位置:lib/bindingMemory/BufferBindingMemory.ts
这个 API 是做什么的
BufferBindingMemory 的作用是:把一段 WGSL buffer 声明当成“可写入的内存模板”。
你只需要提供 WGSL 源码,再传入普通 JavaScript 数据,就可以得到一个已经按 WGSL 布局规则正确写好的 ArrayBuffer,不需要手动计算
offset、stride 和 padding。
主要能力
- 解析 WGSL 中的 uniform / storage buffer 声明
- 创建大小正确的
ArrayBuffer - 支持定长布局和 runtime-sized array
- 支持 scalar / vector / matrix / struct / array 写入
- 支持普通数组和 TypedArray 作为输入
- 支持在 Node 终端或浏览器 canvas 中可视化 binding memory 布局
API 总览
new BufferBindingMemory(shaderCode)
用一段 WGSL 源码创建内存辅助对象。
构造函数会解析其中的 @group/@binding buffer 声明,并建立后续调用 set 时需要使用的 layout 信息。
set(groupBindingName, data, options?)
set() 是主要的写入 API。
它会根据解析出的 WGSL binding layout 创建大小正确的 ArrayBuffer,再按照布局规则把你传入的 JavaScript 数据写进去,最后返回这个已经写好的
buffer。
如果你希望直接通过 WGSL + JS 数据拿到一个可用的 ArrayBuffer,优先使用 set()。
对于 runtime-sized array,需要在 options 中提供以下之一:
runtimeArrayCountbyteLength
createLayoutSnapshot(groupBindingName)
createLayoutSnapshot() 是查看 / 调试 binding memory 布局的可视化 API。
它会先构建一份结构化的 layout snapshot,然后根据当前运行环境自动选择渲染方式:
- Node.js:自动输出带颜色、会根据终端宽度裁剪的终端可视化
- Web / 浏览器:生成 canvas 版 memory board,并放到
snapshot.image上 - 未知环境:只返回结构化 snapshot,不做渲染
返回的 snapshot 里会包含这些信息:
- binding 名称
- address space
- 总大小和对齐
- validation 结果与 issues
- 递归布局树(
snapshot.root) - 当前识别到的环境(
snapshot.environment) - Web 环境下可选的 canvas 图像(
snapshot.image)
当你想检查 offset、padding、stride、数组展开结果,或者快速定位 validation 错误时,优先使用这个 API。
示例 1:定长 storage buffer
import {BufferBindingMemory} from "webgpu-forge";
const shaderCode = `
struct Material {
color: vec3f,
intensity: f32,
weights: array<f32, 2>,
transform: mat2x3f,
}
@group(0) @binding(0) var<storage> material: Material;
`;
const memory = new BufferBindingMemory(shaderCode);
const arrayBuffer = memory.set("material", {
color: [1, 2, 3],
intensity: 4,
weights: [5, 6],
transform: [7, 8, 9, 10, 11, 12],
});
const float32 = new Float32Array(arrayBuffer);
console.log(Array.from(float32));
// [
// 1, 2, 3, 4,
// 5, 6, 0, 0,
// 7, 8, 9, 0,
// 10, 11, 12, 0,
// ]这个例子说明了什么
你只需要传普通 JS 数据,API 会自动处理 WGSL 要求的 padding。
示例 2:runtime-sized array
import {BufferBindingMemory} from "webgpu-forge";
const shaderCode = `
struct PointLight {
position: vec3f,
color: vec3f,
}
struct LightStorage {
pointCount: u32,
point: array<PointLight>,
}
@group(0) @binding(1) var<storage> lights: LightStorage;
`;
const memory = new BufferBindingMemory(shaderCode);
const arrayBuffer = memory.set(
"lights",
{
pointCount: 2,
point: [
{
position: [1, 2, 3],
color: [4, 5, 6],
},
{
position: [7, 8, 9],
color: [10, 11, 12],
},
],
},
{runtimeArrayCount: 2},
);
console.log(arrayBuffer.byteLength); // 80重要说明
对于 runtime-sized array,BufferBindingMemory 无法自动推断最终尾部长度。
你必须通过 runtimeArrayCount 或 byteLength 告诉它目标大小。
示例 3:Node 端终端可视化
import {BufferBindingMemory} from "webgpu-forge";
const shaderCode = `
struct Camera {
scale: f32,
offset: vec3f,
projection: mat4x4f,
}
@group(0) @binding(0) var<uniform> camera: Camera;
`;
const memory = new BufferBindingMemory(shaderCode);
const snapshot = memory.createLayoutSnapshot("camera");
console.log(snapshot.environment); // "node"
// 创建 snapshot 时会自动把终端可视化打印出来。这个场景适合 CLI 工具、Node 脚本、服务端调试,能直接看出字节范围、padding 和 validation 问题。
下面是一个终端输出片段示例:
WGSL Binding Memory Snapshot
binding : camera
address-space : uniform
environment : node
size : 96B
align : 16
validation : ok
memory layout:
tree label kind offset end size align type details path
---- ---------- ------- ------ --- ---- ----- ------- ----------------- -----------------
root camera struct 0 96 96B 16 Camera — camera
├─ scale builtin 0 4 4B 4 f32 — camera.scale
├─ <padding> padding 4 16 12B — — reason=struct-gap —
├─ offset builtin 16 28 12B 16 vec3f — camera.offset
├─ <padding> padding 28 32 4B — — reason=struct-gap —
└─ projection builtin 32 96 64B 16 mat4x4f — camera.projection示例 4:Web 端 canvas 可视化
import {BufferBindingMemory} from "webgpu-forge";
const shaderCode = `
struct Camera {
scale: f32,
offset: vec3f,
projection: mat4x4f,
}
@group(0) @binding(0) var<uniform> camera: Camera;
`;
const memory = new BufferBindingMemory(shaderCode);
const snapshot = memory.createLayoutSnapshot("camera");
if (snapshot.image instanceof HTMLCanvasElement) {
document.body.appendChild(snapshot.image);
}在浏览器里,snapshot.image 会是一张 memory-board 风格的 canvas,可用来直观看字段色带、offset、padding,以及数组 / 矩阵展开后的布局。
下面是一张 Web 端 canvas 可视化截图:
典型用法
const memory = new BufferBindingMemory(shaderCode);
const arrayBuffer = memory.set(groupBindingName, data, options);在大多数场景里,这就是最主要的使用方式。
当前支持的数据输入形式
当前支持的输入大致包括:
- WGSL struct -> 普通对象
- WGSL array -> 数组 / TypedArray
- vector / matrix -> 数组 / TypedArray
- 标量类型,如
i32、u32、f32、f16 - 原子标量写入,如
atomic<u32>
Vec
源码位置:lib/vector.ts
Vec 是一组基于 Float32Array 的轻量向量工具,主要面向 2D / 3D / 4D 向量计算,不引入额外封装类。
导入方式
import {Vec} from "webgpu-forge";约定
- 向量底层都是普通
Float32Array - 只支持
vec2、vec3、vec4 - 输出参数
out可选;不传时会分配新向量 - 大多数二元运算要求两边维度一致
normalize()会把非常小的向量当作零向量处理
主要 API
- 构造:
vec2、vec3、vec4 - 按分量运算:
copy、add、sub、mul、div、scale、negate、min、max、clamp、lerp - 标量 / 几何运算:
dot、lengthSq、length、distanceSq、distance、normalize、equals - 仅 3D:
cross
示例
import {Vec} from "webgpu-forge";
const a = Vec.vec3(1, 2, 3);
const b = Vec.vec3(4, 5, 6);
const added = Vec.add(a, b);
const unit = Vec.normalize(a);
const normal = Vec.cross(a, b);Mat
源码位置:lib/mat.ts
Mat 提供基于 Float32Array 的轻量矩阵工具,采用列主序存储,当前重点支持 3x3 和 4x4 变换相关矩阵。
导入方式
import {Mat} from "webgpu-forge";约定
- 矩阵底层都是普通
Float32Array - 存储顺序是列主序(column-major)
mat3x3()生成长度为9的矩阵,mat4x4()生成长度为16的矩阵identity()不传out时默认返回4x4translation()只生成4x4scaling()、rotationX()、rotationY()、rotationZ()、rotation()会根据out的长度写入3x3或4x4
主要 API
- 创建:
mat3x3、mat4x4、identity - 变换:
translation、scaling、rotationX、rotationY、rotationZ、rotation - 矩阵运算:
copy、add、sub、scale、transpose、multiply - 矩阵乘向量:
multiplyVector
rotation() 的输入对象
rotation() 现在只接收下面两种对象之一:
- 欧拉角对象:
{ x, y, z, order? } - 四元数对象:
{ x, y, z, w }
说明:
- 欧拉角单位是弧度
order支持:xyz、xzy、yxz、yzx、zxy、zyx- 四元数会在内部先归一化,再转换成矩阵
示例
import {Mat, Vec} from "webgpu-forge";
const model = Mat.rotation({x: 0, y: Math.PI / 2, z: 0});
const translated = Mat.translation(4, 5, 6);
const combined = Mat.multiply(translated, model);
const position = Vec.vec4(1, 2, 3, 1);
const worldPosition = Mat.multiplyVector(combined, position);开发
npm install
npm run dev
npm run typecheck
npm run test:run
npm run build发布检查清单
- 更新
package.json中的name/version - 运行
npm run build,并确认dist/中包含.js、.cjs、.d.ts - 发布包
