@vgpu/render 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +5 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/perf/frame-time-measure.d.ts +22 -0
  7. package/dist/perf/frame-time-measure.d.ts.map +1 -0
  8. package/dist/perf/frame-time-measure.js +91 -0
  9. package/dist/perf/frame-time-measure.js.map +1 -0
  10. package/dist/perf/gpu-frame-time.d.ts +49 -0
  11. package/dist/perf/gpu-frame-time.d.ts.map +1 -0
  12. package/dist/perf/gpu-frame-time.js +50 -0
  13. package/dist/perf/gpu-frame-time.js.map +1 -0
  14. package/dist/perf/index.d.ts +5 -0
  15. package/dist/perf/index.d.ts.map +1 -0
  16. package/dist/perf/index.js +3 -0
  17. package/dist/perf/index.js.map +1 -0
  18. package/dist/perf/pixel-diff.d.ts +27 -0
  19. package/dist/perf/pixel-diff.d.ts.map +1 -0
  20. package/dist/perf/pixel-diff.js +40 -0
  21. package/dist/perf/pixel-diff.js.map +1 -0
  22. package/dist/pipeline-descriptor.d.ts +35 -0
  23. package/dist/pipeline-descriptor.d.ts.map +1 -0
  24. package/dist/pipeline-descriptor.js +44 -0
  25. package/dist/pipeline-descriptor.js.map +1 -0
  26. package/dist/pipeline.d.ts +22 -33
  27. package/dist/pipeline.d.ts.map +1 -1
  28. package/dist/pipeline.js +30 -46
  29. package/dist/pipeline.js.map +1 -1
  30. package/dist/render-pass.d.ts.map +1 -1
  31. package/dist/render-pass.js +4 -0
  32. package/dist/render-pass.js.map +1 -1
  33. package/dist/storage-buffer.d.ts +81 -0
  34. package/dist/storage-buffer.d.ts.map +1 -0
  35. package/dist/storage-buffer.js +91 -0
  36. package/dist/storage-buffer.js.map +1 -0
  37. package/dist/uniform.d.ts +55 -0
  38. package/dist/uniform.d.ts.map +1 -0
  39. package/dist/uniform.js +64 -0
  40. package/dist/uniform.js.map +1 -0
  41. package/package.json +8 -3
  42. package/src/createRenderPipeline.docs.md +34 -0
  43. package/src/perf/perf.docs.md +45 -0
  44. package/src/storage-buffer.docs.md +102 -0
  45. package/src/uniform.docs.md +70 -0
package/dist/pipeline.js CHANGED
@@ -1,4 +1,5 @@
1
- import { Shader, VGPUError } from "@vgpu/core";
1
+ import { VGPUError } from "@vgpu/core";
2
+ import { toRenderPipelineDescriptor } from "./pipeline-descriptor.js";
2
3
  // Warn once per JS process. This keeps compatibility fallback visible without spamming
3
4
  // apps that intentionally warm up multiple pipelines on implementations without
4
5
  // GPUDevice.createRenderPipelineAsync().
@@ -7,64 +8,47 @@ export function createRenderPipeline(device, opts) {
7
8
  return device.gpu.createRenderPipeline(toRenderPipelineDescriptor(opts));
8
9
  }
9
10
  export async function createRenderPipelineAsync(device, opts) {
10
- const descriptor = toRenderPipelineDescriptor(opts);
11
+ return createPipelineAsync(device, toRenderPipelineDescriptor(opts), opts.fallback, "createRenderPipelineAsync");
12
+ }
13
+ /**
14
+ * Create a render pipeline from a raw, hand-built `GPURenderPipelineDescriptor`.
15
+ *
16
+ * @remarks
17
+ * Use this when you already own a native descriptor and only want VGPU's
18
+ * `Device` wrapper to forward it — no `RenderPipelineOptions` reshape. The
19
+ * descriptor is passed through unchanged.
20
+ */
21
+ export function createRenderPipelineFromDescriptor(device, descriptor) {
22
+ return device.gpu.createRenderPipeline(descriptor);
23
+ }
24
+ /**
25
+ * Async variant of {@link createRenderPipelineFromDescriptor} with the same
26
+ * async→sync compatibility fallback as {@link createRenderPipelineAsync}.
27
+ *
28
+ * @remarks
29
+ * The descriptor is forwarded unchanged. When `GPUDevice.createRenderPipelineAsync`
30
+ * is unavailable, the default `fallback: "sync"` emits a once-only diagnostic and
31
+ * calls the synchronous path; pass `fallback: "throw"` for a structured `VGPUError`.
32
+ */
33
+ export async function createRenderPipelineFromDescriptorAsync(device, descriptor, fallback) {
34
+ return createPipelineAsync(device, descriptor, fallback, "createRenderPipelineFromDescriptorAsync");
35
+ }
36
+ async function createPipelineAsync(device, descriptor, fallback, where) {
11
37
  const createAsync = device.gpu.createRenderPipelineAsync;
12
38
  if (typeof createAsync === "function") {
13
39
  return createAsync.call(device.gpu, descriptor);
14
40
  }
15
- if ((opts.fallback ?? "sync") === "throw") {
41
+ if ((fallback ?? "sync") === "throw") {
16
42
  throw new VGPUError({
17
43
  code: "VGPU-RENDER-PIPELINE-ASYNC-UNAVAILABLE",
18
44
  message: "GPUDevice.createRenderPipelineAsync is unavailable on this WebGPU implementation.",
19
45
  fix: "Use fallback: 'sync' for compatibility or call createRenderPipeline() explicitly during setup/warmup.",
20
- where: "createRenderPipelineAsync",
46
+ where,
21
47
  });
22
48
  }
23
49
  warnAsyncFallbackOnce();
24
50
  return device.gpu.createRenderPipeline(descriptor);
25
51
  }
26
- function toRenderPipelineDescriptor(opts) {
27
- const descriptor = {
28
- label: opts.label,
29
- layout: opts.layout ?? "auto",
30
- vertex: {
31
- module: stageModule(opts.vertex, opts.shader, "vertex"),
32
- entryPoint: stageEntryPoint(opts.vertex),
33
- constants: opts.vertex.constants,
34
- buffers: opts.vertex.buffers ? [...opts.vertex.buffers] : undefined,
35
- },
36
- primitive: opts.primitive,
37
- depthStencil: opts.depthStencil,
38
- multisample: opts.multisample,
39
- };
40
- if (opts.fragment) {
41
- descriptor.fragment = {
42
- module: stageModule(opts.fragment, opts.shader, "fragment"),
43
- entryPoint: stageEntryPoint(opts.fragment),
44
- constants: opts.fragment.constants,
45
- targets: [...opts.fragment.targets],
46
- };
47
- }
48
- return descriptor;
49
- }
50
- function stageModule(stage, fallback, stageName) {
51
- const module = stage.module ?? stage.shader ?? fallback;
52
- if (!module) {
53
- throw new VGPUError({
54
- code: "VGPU-RENDER-PIPELINE-MISSING-SHADER",
55
- message: `Missing shader module for ${stageName} stage.`,
56
- fix: "Pass options.shader for a shared module or pass vertex/fragment module or shader.",
57
- where: `createRenderPipeline.${stageName}`,
58
- });
59
- }
60
- return isShader(module) ? module.gpu : module;
61
- }
62
- function stageEntryPoint(stage) {
63
- return stage.entryPoint ?? stage.entry;
64
- }
65
- function isShader(input) {
66
- return input instanceof Shader;
67
- }
68
52
  export function __resetCreateRenderPipelineAsyncFallbackWarningForTests() {
69
53
  didWarnAboutAsyncFallback = false;
70
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAYtE,uFAAuF;AACvF,gFAAgF;AAChF,yCAAyC;AACzC,IAAI,yBAAyB,GAAG,KAAK,CAAC;AAItC,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,IAA2B;IAC9E,OAAO,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAc,EACd,IAA2B;IAE3B,OAAO,mBAAmB,CACxB,MAAM,EACN,0BAA0B,CAAC,IAAI,CAAC,EAChC,IAAI,CAAC,QAAQ,EACb,2BAA2B,CAC5B,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kCAAkC,CAChD,MAAc,EACd,UAAuC;IAEvC,OAAO,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,uCAAuC,CAC3D,MAAc,EACd,UAAuC,EACvC,QAAsC;IAEtC,OAAO,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,yCAAyC,CAAC,CAAC;AACtG,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,MAAc,EACd,UAAuC,EACvC,QAAiD,EACjD,KAAyB;IAEzB,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACzD,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,OAAO,EAAE,CAAC;QACrC,MAAM,IAAI,SAAS,CAAC;YAClB,IAAI,EAAE,wCAAwC;YAC9C,OAAO,EAAE,mFAAmF;YAC5F,GAAG,EAAE,uGAAuG;YAC5G,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAED,qBAAqB,EAAE,CAAC;IACxB,OAAO,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,uDAAuD;IACrE,yBAAyB,GAAG,KAAK,CAAC;AACpC,CAAC;AAED,SAAS,qBAAqB;IAC5B,IAAI,yBAAyB;QAAE,OAAO;IACtC,yBAAyB,GAAG,IAAI,CAAC;IACjC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,CACxB,yKAAyK,CAC1K,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"render-pass.d.ts","sourceRoot":"","sources":["../src/render-pass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAC;IACtD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IACzD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC;IACxC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,eAAe,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACrC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,wBAAwB,GAAG,SAAS,sBAAsB,EAAE,GAAG,WAAW,CAAC;AASvF,qBAAa,UAAU;IAKT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,WAAW,CAA8B;gBAEpB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB;IAQpE,IAAI,GAAG,IAAI,oBAAoB,CAS9B;IAED,WAAW,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAI9C,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,EAAE,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAIxG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,SAAI,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI;IAIpG,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI;IAIxD,IAAI,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAC1C,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;IAcrG,GAAG,IAAI,IAAI;IAQX,OAAO,IAAI,IAAI;CAGhB;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAGzH"}
1
+ {"version":3,"file":"render-pass.d.ts","sourceRoot":"","sources":["../src/render-pass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAC;IACtD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IACzD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC;IACxC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,eAAe,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACrC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,wBAAwB,GAAG,SAAS,sBAAsB,EAAE,GAAG,WAAW,CAAC;AASvF,qBAAa,UAAU;IAKT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,WAAW,CAA8B;gBAEpB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB;IAQpE,IAAI,GAAG,IAAI,oBAAoB,CAS9B;IAED,WAAW,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAI9C,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,EAAE,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI;IAQxG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,SAAI,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI;IAIpG,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI;IAIxD,IAAI,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAC1C,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;IAcrG,GAAG,IAAI,IAAI;IAQX,OAAO,IAAI,IAAI;CAGhB;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAGzH"}
@@ -28,6 +28,10 @@ export class RenderPass {
28
28
  this.gpu.setPipeline(pipeline);
29
29
  }
30
30
  setBindGroup(index, group, dynamicOffsets) {
31
+ if (dynamicOffsets === undefined) {
32
+ this.gpu.setBindGroup(index, group);
33
+ return;
34
+ }
31
35
  this.gpu.setBindGroup(index, group, dynamicOffsets);
32
36
  }
33
37
  setVertexBuffer(slot, buffer, offset = 0, size) {
@@ -1 +1 @@
1
- {"version":3,"file":"render-pass.js","sourceRoot":"","sources":["../src/render-pass.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render-pass.js","sourceRoot":"","sources":["../src/render-pass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAA6B,MAAM,YAAY,CAAC;AAE1E,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAyChD,MAAM,wBAAwB,GAAG,IAAI,OAAO,EAA8C,CAAC;AAE3F,MAAM,OAAO,UAAU;IAKQ;IAJZ,OAAO,CAAoB;IAC3B,WAAW,CAAU;IAC9B,WAAW,CAA8B;IAEjD,YAA6B,MAAc,EAAE,IAAuB;QAAvC,WAAM,GAAN,MAAM,CAAQ;QACzC,MAAM,MAAM,GAAG,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClD,wBAAwB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,IAAI,CAAC;QAC/C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,GAAG;QACL,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,SAAS,CAAC;gBAClB,IAAI,EAAE,wBAAwB;gBAC9B,OAAO,EAAE,gDAAgD;gBACzD,KAAK,EAAE,gBAAgB;aACxB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,WAAW,CAAC,QAA2B;QACrC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED,YAAY,CAAC,KAAa,EAAE,KAA0B,EAAE,cAAyC;QAC/F,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACpC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;IACtD,CAAC;IAED,eAAe,CAAC,IAAY,EAAE,MAAiC,EAAE,MAAM,GAAG,CAAC,EAAE,IAAgB;QAC3F,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC;IAED,cAAc,CAAC,OAAkC;QAC/C,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAID,IAAI,CAAC,oBAAoD,EAAE,aAAa,GAAG,CAAC,EAAE,WAAW,GAAG,CAAC,EAAE,aAAa,GAAG,CAAC;QAC9G,IAAI,OAAO,oBAAoB,KAAK,QAAQ,EAAE,CAAC;YAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,oBAAoB,CAAC,WAAW,EAChC,oBAAoB,CAAC,aAAa,IAAI,CAAC,EACvC,oBAAoB,CAAC,WAAW,IAAI,CAAC,EACrC,oBAAoB,CAAC,aAAa,IAAI,CAAC,CACxC,CAAC;IACJ,CAAC;IAED,GAAG;QACD,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,GAAG,EAAE,CAAC;QACX,IAAI,IAAI,CAAC,WAAW;YAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO;QACL,IAAI,CAAC,GAAG,EAAE,CAAC;IACb,CAAC;CACF;AAED,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,IAAuB,EAAE,OAA0B;IAC3G,wBAAwB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,OAAO,IAAI,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAuB;IACnD,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,eAAe,CAAC;QAC5D,sBAAsB,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,SAAS;KACtH,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,UAA2B;IAClD,OAAO;QACL,IAAI,EAAE,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC;QAClC,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,UAAU,EAAE,UAAU,CAAC,UAAU;KAClC,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,UAAkC;IAChE,OAAO;QACL,IAAI,EAAE,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC;QAClC,eAAe,EAAE,UAAU,CAAC,eAAe;QAC3C,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,aAAa,EAAE,UAAU,CAAC,aAAa;QACvC,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,aAAa,EAAE,UAAU,CAAC,aAAa;QACvC,cAAc,EAAE,UAAU,CAAC,cAAc;QACzC,eAAe,EAAE,UAAU,CAAC,eAAe;KAC5C,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAA8B;IACjD,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,SAAS,SAAS,CAAC,MAAiC;IAClD,OAAO,MAAM,YAAY,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AACxD,CAAC;AAED,SAAS,aAAa,CAAC,IAA8B;IACnD,OAAO,OAAO,CAAE,IAA2C,CAAC,YAAY,CAAC,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { Buffer, type Device } from "@vgpu/core";
2
+ export interface StorageBufferOptions {
3
+ /** Byte size of the storage buffer. Must be a positive number. Storage buffers may be far larger than uniforms (up to the adapter's `maxStorageBufferBindingSize`, typically 128 MiB). */
4
+ readonly size: number;
5
+ /** Optional debug label forwarded to the buffer, bind group layout, and bind group. */
6
+ readonly label?: string;
7
+ /**
8
+ * Whether the shader only reads the buffer (`"read"`, the default → `var<storage, read>`)
9
+ * or also writes it (`"read-write"` → `var<storage, read_write>`). This selects the
10
+ * bind group layout entry type (`"read-only-storage"` vs `"storage"`) and changes the
11
+ * default {@link StorageBufferOptions.visibility}.
12
+ */
13
+ readonly access?: "read" | "read-write";
14
+ /**
15
+ * Shader stages that access binding 0. Defaults to `FRAGMENT | COMPUTE` for both access modes —
16
+ * no `VERTEX`. Read-write storage is forbidden in the vertex stage; read-only storage is allowed
17
+ * there but `maxStorageBuffersInVertexStage` is 0 on many adapters (software/CI Vulkan, some
18
+ * mobile GPUs), so vertex-stage storage is opt-in: pass `visibility` explicitly and raise that
19
+ * limit via `requiredLimits`. Ignored when {@link StorageBufferOptions.bindGroupLayout} is provided.
20
+ */
21
+ readonly visibility?: GPUShaderStageFlags;
22
+ /**
23
+ * Reuse a pipeline-owned bind group layout instead of creating one.
24
+ * The layout's binding 0 must be a storage buffer compatible with `size` and `access`.
25
+ */
26
+ readonly bindGroupLayout?: GPUBindGroupLayout;
27
+ }
28
+ /**
29
+ * A single stable storage buffer for one render (or compute) pass, rewritten as needed.
30
+ *
31
+ * @remarks
32
+ * `StorageBuffer` is the storage-buffer counterpart to {@link Uniform}. Reach for it when
33
+ * the data is too large or too dynamic for a uniform: arrays, runtime-sized data, particle
34
+ * state, lookup tables. Storage buffers can be much bigger than uniforms (up to the adapter's
35
+ * `maxStorageBufferBindingSize`, typically 128 MiB, versus a uniform's 64 KiB) and can be
36
+ * written by the shader when `access: "read-write"`.
37
+ *
38
+ * Like `Uniform`, it owns exactly one buffer at binding 0 with a fixed (non-dynamic) offset,
39
+ * and the caller decides when to {@link StorageBuffer.write}. Unlike {@link UniformPool} — a
40
+ * dynamic-offset ring allocator for many small per-draw uniforms — there is no dynamic offset
41
+ * and the bind group never moves.
42
+ *
43
+ * `access` controls the layout entry type; both modes default to `FRAGMENT | COMPUTE` visibility:
44
+ * - `"read"` (default) → `var<storage, read>`, layout type `"read-only-storage"`.
45
+ * - `"read-write"` → `var<storage, read_write>`, layout type `"storage"`.
46
+ * Neither default includes `VERTEX`: read-write storage is forbidden in the vertex stage, and
47
+ * read-only storage — though legal there — needs `maxStorageBuffersInVertexStage > 0`, which is 0
48
+ * on many adapters (software/CI Vulkan, some mobile GPUs). For vertex-stage read-only storage, pass
49
+ * `visibility: VERTEX | …` explicitly and raise the limit via `requiredLimits`; do not rely on the default.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * // A read-only array the fragment shader samples (var<storage, read> values: array<f32>):
54
+ * const storage = new StorageBuffer(device, { size: 4 * count, label: "values" });
55
+ * storage.write(new Float32Array(values));
56
+ * pass.setBindGroup(0, storage.bindGroup);
57
+ *
58
+ * // A compute-written scratch buffer (var<storage, read_write> out: array<u32>):
59
+ * const scratch = new StorageBuffer(device, { size: 4 * count, access: "read-write" });
60
+ * ```
61
+ */
62
+ export declare class StorageBuffer {
63
+ readonly device: Device;
64
+ readonly size: number;
65
+ readonly access: "read" | "read-write";
66
+ readonly buffer: Buffer;
67
+ readonly bindGroupLayout: GPUBindGroupLayout;
68
+ readonly bindGroup: GPUBindGroup;
69
+ private destroyed;
70
+ constructor(device: Device, opts: StorageBufferOptions);
71
+ /** The underlying storage `GPUBuffer`. */
72
+ get gpu(): GPUBuffer;
73
+ /**
74
+ * Upload `data` to the buffer via `queue.writeBuffer`. No dynamic offset; the
75
+ * bind group is unchanged. Call only when the contents actually change.
76
+ */
77
+ write(data: BufferSource, offset?: number): void;
78
+ destroy(): void;
79
+ dispose(): void;
80
+ }
81
+ //# sourceMappingURL=storage-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-buffer.d.ts","sourceRoot":"","sources":["../src/storage-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAA0C,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,oBAAoB;IACnC,0LAA0L;IAC1L,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,kBAAkB,CAAC;CAC/C;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,aAAa;IAQZ,QAAQ,CAAC,MAAM,EAAE,MAAM;IAPnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,kBAAkB,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,OAAO,CAAC,SAAS,CAAS;gBAEL,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB;IAmB/D,0CAA0C;IAC1C,IAAI,GAAG,IAAI,SAAS,CAEnB;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,SAAI,GAAG,IAAI;IAI3C,OAAO,IAAI,IAAI;IAMf,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,91 @@
1
+ import { bind, createBindGroup, createBindGroupLayout } from "@vgpu/core";
2
+ // Both access modes default to FRAGMENT | COMPUTE (no VERTEX):
3
+ // - read-write storage is ILLEGAL in the vertex stage (WebGPU forbids it).
4
+ // - read-only storage IS legal in vertex, but maxStorageBuffersInVertexStage is 0 on many adapters
5
+ // (software/CI Vulkan, some mobile GPUs), so a VERTEX-visible default would silently invalidate
6
+ // the layout there (the draw no-ops). Vertex-stage read-only storage is opt-in: pass `visibility`
7
+ // explicitly AND raise the limit via requiredLimits when requesting the device.
8
+ const defaultVisibility = ((globalThis.GPUShaderStage?.FRAGMENT ?? 2) | (globalThis.GPUShaderStage?.COMPUTE ?? 4));
9
+ /**
10
+ * A single stable storage buffer for one render (or compute) pass, rewritten as needed.
11
+ *
12
+ * @remarks
13
+ * `StorageBuffer` is the storage-buffer counterpart to {@link Uniform}. Reach for it when
14
+ * the data is too large or too dynamic for a uniform: arrays, runtime-sized data, particle
15
+ * state, lookup tables. Storage buffers can be much bigger than uniforms (up to the adapter's
16
+ * `maxStorageBufferBindingSize`, typically 128 MiB, versus a uniform's 64 KiB) and can be
17
+ * written by the shader when `access: "read-write"`.
18
+ *
19
+ * Like `Uniform`, it owns exactly one buffer at binding 0 with a fixed (non-dynamic) offset,
20
+ * and the caller decides when to {@link StorageBuffer.write}. Unlike {@link UniformPool} — a
21
+ * dynamic-offset ring allocator for many small per-draw uniforms — there is no dynamic offset
22
+ * and the bind group never moves.
23
+ *
24
+ * `access` controls the layout entry type; both modes default to `FRAGMENT | COMPUTE` visibility:
25
+ * - `"read"` (default) → `var<storage, read>`, layout type `"read-only-storage"`.
26
+ * - `"read-write"` → `var<storage, read_write>`, layout type `"storage"`.
27
+ * Neither default includes `VERTEX`: read-write storage is forbidden in the vertex stage, and
28
+ * read-only storage — though legal there — needs `maxStorageBuffersInVertexStage > 0`, which is 0
29
+ * on many adapters (software/CI Vulkan, some mobile GPUs). For vertex-stage read-only storage, pass
30
+ * `visibility: VERTEX | …` explicitly and raise the limit via `requiredLimits`; do not rely on the default.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * // A read-only array the fragment shader samples (var<storage, read> values: array<f32>):
35
+ * const storage = new StorageBuffer(device, { size: 4 * count, label: "values" });
36
+ * storage.write(new Float32Array(values));
37
+ * pass.setBindGroup(0, storage.bindGroup);
38
+ *
39
+ * // A compute-written scratch buffer (var<storage, read_write> out: array<u32>):
40
+ * const scratch = new StorageBuffer(device, { size: 4 * count, access: "read-write" });
41
+ * ```
42
+ */
43
+ export class StorageBuffer {
44
+ device;
45
+ size;
46
+ access;
47
+ buffer;
48
+ bindGroupLayout;
49
+ bindGroup;
50
+ destroyed = false;
51
+ constructor(device, opts) {
52
+ this.device = device;
53
+ this.size = opts.size;
54
+ this.access = opts.access ?? "read";
55
+ this.buffer = device.createBuffer({ size: opts.size, usage: ["storage", "copy_dst"], label: opts.label });
56
+ const visibility = opts.visibility ?? defaultVisibility;
57
+ const entry = this.access === "read-write"
58
+ ? bind.storage(0, visibility, { minBindingSize: opts.size })
59
+ : bind.readonlyStorage(0, visibility, { minBindingSize: opts.size });
60
+ this.bindGroupLayout = opts.bindGroupLayout ?? createBindGroupLayout(device, {
61
+ label: opts.label ? `${opts.label}.bgl` : undefined,
62
+ entries: [entry],
63
+ });
64
+ this.bindGroup = createBindGroup(device, {
65
+ label: opts.label ? `${opts.label}.bg` : undefined,
66
+ layout: this.bindGroupLayout,
67
+ entries: [bind.resource(0, this.buffer)],
68
+ });
69
+ }
70
+ /** The underlying storage `GPUBuffer`. */
71
+ get gpu() {
72
+ return this.buffer.gpu;
73
+ }
74
+ /**
75
+ * Upload `data` to the buffer via `queue.writeBuffer`. No dynamic offset; the
76
+ * bind group is unchanged. Call only when the contents actually change.
77
+ */
78
+ write(data, offset = 0) {
79
+ this.buffer.write(data, offset);
80
+ }
81
+ destroy() {
82
+ if (this.destroyed)
83
+ return;
84
+ this.destroyed = true;
85
+ this.buffer.destroy();
86
+ }
87
+ dispose() {
88
+ this.destroy();
89
+ }
90
+ }
91
+ //# sourceMappingURL=storage-buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-buffer.js","sourceRoot":"","sources":["../src/storage-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAU,eAAe,EAAE,qBAAqB,EAAe,MAAM,YAAY,CAAC;AA6B/F,+DAA+D;AAC/D,2EAA2E;AAC3E,mGAAmG;AACnG,kGAAkG;AAClG,oGAAoG;AACpG,kFAAkF;AAClF,MAAM,iBAAiB,GAAG,CAAC,CAAC,UAAU,CAAC,cAAc,EAAE,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,EAAE,OAAO,IAAI,CAAC,CAAC,CAAwB,CAAC;AAE1I;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,OAAO,aAAa;IAQH;IAPZ,IAAI,CAAS;IACb,MAAM,CAAwB;IAC9B,MAAM,CAAS;IACf,eAAe,CAAqB;IACpC,SAAS,CAAe;IACzB,SAAS,GAAG,KAAK,CAAC;IAE1B,YAAqB,MAAc,EAAE,IAA0B;QAA1C,WAAM,GAAN,MAAM,CAAQ;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1G,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,iBAAiB,CAAC;QACxD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,KAAK,YAAY;YACxC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5D,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,qBAAqB,CAAC,MAAM,EAAE;YAC3E,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS;YACnD,OAAO,EAAE,CAAC,KAAK,CAAC;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,MAAM,EAAE;YACvC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS;YAClD,MAAM,EAAE,IAAI,CAAC,eAAe;YAC5B,OAAO,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IAED,0CAA0C;IAC1C,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAkB,EAAE,MAAM,GAAG,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAED,OAAO;QACL,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,55 @@
1
+ import { Buffer, type Device } from "@vgpu/core";
2
+ export interface UniformOptions {
3
+ /** Byte size of the uniform buffer. Must be a positive number. */
4
+ readonly size: number;
5
+ /** Optional debug label forwarded to the buffer, bind group layout, and bind group. */
6
+ readonly label?: string;
7
+ /**
8
+ * Shader stages that read binding 0. Defaults to `VERTEX | FRAGMENT`.
9
+ * Ignored when {@link UniformOptions.bindGroupLayout} is provided.
10
+ */
11
+ readonly visibility?: GPUShaderStageFlags;
12
+ /**
13
+ * Reuse a pipeline-owned bind group layout instead of creating one.
14
+ * The layout's binding 0 must be a uniform buffer compatible with `size`.
15
+ */
16
+ readonly bindGroupLayout?: GPUBindGroupLayout;
17
+ }
18
+ /**
19
+ * A single stable uniform buffer for one render pass, rewritten per frame.
20
+ *
21
+ * @remarks
22
+ * Unlike {@link UniformPool} (a dynamic-offset ring allocator built for many
23
+ * per-draw uniforms), `Uniform` owns exactly one uniform buffer at binding 0 with
24
+ * a fixed (non-dynamic) offset. The caller decides when to {@link Uniform.write}
25
+ * — typically gating on real changes — and the bind group never moves. This fits
26
+ * the "one camera/globals buffer per pass" case where a dynamic-offset binding
27
+ * would needlessly mark the layout `hasDynamicOffset` and re-upload every frame.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const uniform = new Uniform(device, { size: 64, label: "globals" });
32
+ * // per frame, only when inputs changed:
33
+ * uniform.write(globalsBytes);
34
+ * pass.setBindGroup(0, uniform.bindGroup);
35
+ * ```
36
+ */
37
+ export declare class Uniform {
38
+ readonly device: Device;
39
+ readonly size: number;
40
+ readonly buffer: Buffer;
41
+ readonly bindGroupLayout: GPUBindGroupLayout;
42
+ readonly bindGroup: GPUBindGroup;
43
+ private destroyed;
44
+ constructor(device: Device, opts: UniformOptions);
45
+ /** The underlying uniform `GPUBuffer`. */
46
+ get gpu(): GPUBuffer;
47
+ /**
48
+ * Upload `data` to the buffer via `queue.writeBuffer`. No dynamic offset; the
49
+ * bind group is unchanged. Call only when the uniform contents actually change.
50
+ */
51
+ write(data: BufferSource, offset?: number): void;
52
+ destroy(): void;
53
+ dispose(): void;
54
+ }
55
+ //# sourceMappingURL=uniform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uniform.d.ts","sourceRoot":"","sources":["../src/uniform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAA0C,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,kBAAkB,CAAC;CAC/C;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,OAAO;IAON,QAAQ,CAAC,MAAM,EAAE,MAAM;IANnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,kBAAkB,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,OAAO,CAAC,SAAS,CAAS;gBAEL,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc;IAczD,0CAA0C;IAC1C,IAAI,GAAG,IAAI,SAAS,CAEnB;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,SAAI,GAAG,IAAI;IAI3C,OAAO,IAAI,IAAI;IAMf,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,64 @@
1
+ import { bind, createBindGroup, createBindGroupLayout } from "@vgpu/core";
2
+ const defaultVisibility = ((globalThis.GPUShaderStage?.VERTEX ?? 1) | (globalThis.GPUShaderStage?.FRAGMENT ?? 2));
3
+ /**
4
+ * A single stable uniform buffer for one render pass, rewritten per frame.
5
+ *
6
+ * @remarks
7
+ * Unlike {@link UniformPool} (a dynamic-offset ring allocator built for many
8
+ * per-draw uniforms), `Uniform` owns exactly one uniform buffer at binding 0 with
9
+ * a fixed (non-dynamic) offset. The caller decides when to {@link Uniform.write}
10
+ * — typically gating on real changes — and the bind group never moves. This fits
11
+ * the "one camera/globals buffer per pass" case where a dynamic-offset binding
12
+ * would needlessly mark the layout `hasDynamicOffset` and re-upload every frame.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const uniform = new Uniform(device, { size: 64, label: "globals" });
17
+ * // per frame, only when inputs changed:
18
+ * uniform.write(globalsBytes);
19
+ * pass.setBindGroup(0, uniform.bindGroup);
20
+ * ```
21
+ */
22
+ export class Uniform {
23
+ device;
24
+ size;
25
+ buffer;
26
+ bindGroupLayout;
27
+ bindGroup;
28
+ destroyed = false;
29
+ constructor(device, opts) {
30
+ this.device = device;
31
+ this.size = opts.size;
32
+ this.buffer = device.createBuffer({ size: opts.size, usage: ["uniform", "copy_dst"], label: opts.label });
33
+ this.bindGroupLayout = opts.bindGroupLayout ?? createBindGroupLayout(device, {
34
+ label: opts.label ? `${opts.label}.bgl` : undefined,
35
+ entries: [bind.uniform(0, opts.visibility ?? defaultVisibility, { minBindingSize: opts.size })],
36
+ });
37
+ this.bindGroup = createBindGroup(device, {
38
+ label: opts.label ? `${opts.label}.bg` : undefined,
39
+ layout: this.bindGroupLayout,
40
+ entries: [bind.resource(0, this.buffer)],
41
+ });
42
+ }
43
+ /** The underlying uniform `GPUBuffer`. */
44
+ get gpu() {
45
+ return this.buffer.gpu;
46
+ }
47
+ /**
48
+ * Upload `data` to the buffer via `queue.writeBuffer`. No dynamic offset; the
49
+ * bind group is unchanged. Call only when the uniform contents actually change.
50
+ */
51
+ write(data, offset = 0) {
52
+ this.buffer.write(data, offset);
53
+ }
54
+ destroy() {
55
+ if (this.destroyed)
56
+ return;
57
+ this.destroyed = true;
58
+ this.buffer.destroy();
59
+ }
60
+ dispose() {
61
+ this.destroy();
62
+ }
63
+ }
64
+ //# sourceMappingURL=uniform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uniform.js","sourceRoot":"","sources":["../src/uniform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAU,eAAe,EAAE,qBAAqB,EAAe,MAAM,YAAY,CAAC;AAmB/F,MAAM,iBAAiB,GAAG,CAAC,CAAC,UAAU,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAwB,CAAC;AAEzI;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,OAAO;IAOG;IANZ,IAAI,CAAS;IACb,MAAM,CAAS;IACf,eAAe,CAAqB;IACpC,SAAS,CAAe;IACzB,SAAS,GAAG,KAAK,CAAC;IAE1B,YAAqB,MAAc,EAAE,IAAoB;QAApC,WAAM,GAAN,MAAM,CAAQ;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1G,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,qBAAqB,CAAC,MAAM,EAAE;YAC3E,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS;YACnD,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,IAAI,iBAAiB,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;SAChG,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,MAAM,EAAE;YACvC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS;YAClD,MAAM,EAAE,IAAI,CAAC,eAAe;YAC5B,OAAO,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IAED,0CAA0C;IAC1C,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAkB,EAAE,MAAM,GAAG,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAED,OAAO;QACL,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vgpu/render",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Render pipeline + render pass abstractions for vgpu.",
5
5
  "keywords": [
6
6
  "webgpu",
@@ -47,6 +47,10 @@
47
47
  "./passes": {
48
48
  "types": "./dist/passes/index.d.ts",
49
49
  "import": "./dist/passes/index.js"
50
+ },
51
+ "./perf": {
52
+ "types": "./dist/perf/index.d.ts",
53
+ "import": "./dist/perf/index.js"
50
54
  }
51
55
  },
52
56
  "files": [
@@ -58,14 +62,15 @@
58
62
  ],
59
63
  "dependencies": {
60
64
  "wgpu-matrix": "^3.4.2",
61
- "@vgpu/core": "0.0.6"
65
+ "@vgpu/core": "0.0.8"
62
66
  },
63
67
  "vgpuExportBundleBudgetsGzipBytes": {
64
68
  ".": 49152,
65
69
  "./inspect": 4096,
66
70
  "./utils": 2048,
67
71
  "./edit": 25600,
68
- "./passes": 3584
72
+ "./passes": 3584,
73
+ "./perf": 3072
69
74
  },
70
75
  "scripts": {
71
76
  "build": "tsc -b",
@@ -9,6 +9,8 @@ directly to native WebGPU, `RenderPass.setPipeline()`, or render-bundle recordin
9
9
  ```ts
10
10
  createRenderPipeline(device: Device, opts: RenderPipelineOptions): GPURenderPipeline
11
11
  createRenderPipelineAsync(device: Device, opts: RenderPipelineOptions): Promise<GPURenderPipeline>
12
+ createRenderPipelineFromDescriptor(device: Device, descriptor: GPURenderPipelineDescriptor): GPURenderPipeline
13
+ createRenderPipelineFromDescriptorAsync(device: Device, descriptor: GPURenderPipelineDescriptor, fallback?: RenderPipelineAsyncFallback): Promise<GPURenderPipeline>
12
14
  ```
13
15
 
14
16
  `createRenderPipelineAsync` calls `GPUDevice.createRenderPipelineAsync()` when it
@@ -18,6 +20,24 @@ calls `createRenderPipeline()` instead. Performance-critical warmup can pass
18
20
  `fallback: "throw"` to receive a structured `VGPUError` with code
19
21
  `VGPU-RENDER-PIPELINE-ASYNC-UNAVAILABLE` instead of accidentally blocking.
20
22
 
23
+ ## Raw descriptor entrypoints
24
+
25
+ If you already have a hand-built `GPURenderPipelineDescriptor`, pass it straight
26
+ through — do not reshape it into `RenderPipelineOptions` just to get the
27
+ async→sync fallback:
28
+
29
+ - `createRenderPipelineFromDescriptor(device, descriptor)` forwards the descriptor
30
+ to `GPUDevice.createRenderPipeline()` unchanged.
31
+ - `createRenderPipelineFromDescriptorAsync(device, descriptor, fallback?)` forwards
32
+ it to `GPUDevice.createRenderPipelineAsync()` with the exact same compatibility
33
+ fallback as `createRenderPipelineAsync` (default `"sync"`, or `"throw"` for a
34
+ structured `VGPUError`).
35
+
36
+ The descriptor is forwarded verbatim, so native WebGPU validation and lifecycle
37
+ rules remain the caller's responsibility. These are explicit, separately named
38
+ exports rather than an overload so a `RenderPipelineOptions` caller can never be
39
+ misread as passing a raw descriptor.
40
+
21
41
  VGPU does not cache pipelines: one helper call equals one WebGPU device call.
22
42
  Keep pipeline caches explicit and owned by the caller.
23
43
 
@@ -86,6 +106,20 @@ const pipeline = createRenderPipeline(device, {
86
106
  });
87
107
  ```
88
108
 
109
+ Existing raw `GPURenderPipelineDescriptor`, only wanting the async fallback:
110
+
111
+ ```ts
112
+ const descriptor: GPURenderPipelineDescriptor = {
113
+ label: "hero.pipeline",
114
+ layout: pipelineLayout,
115
+ vertex: { module: shaderModule, entryPoint: "vs_main", buffers },
116
+ fragment: { module: shaderModule, entryPoint: "fs_main", targets: [{ format }] },
117
+ primitive: { topology: "triangle-list" },
118
+ };
119
+
120
+ const pipeline = await createRenderPipelineFromDescriptorAsync(device, descriptor, "throw");
121
+ ```
122
+
89
123
  ## Raw escape hatch
90
124
 
91
125
  `Shader.gpu` is an intentional advanced escape hatch to the underlying
@@ -0,0 +1,45 @@
1
+ # @vgpu/render/perf
2
+
3
+ Measurement utilities for the optimize loop: confirm a shader change is still correct and actually
4
+ faster. **Tooling only — never call these on a live animation-frame path.** See the `measuring`
5
+ guide (`vgpu docs cat /guides/measuring.docs.md`) for the workflow.
6
+
7
+ ## gpuFrameTime
8
+
9
+ `gpuFrameTime(device, encode, options?)` measures median GPU time per frame for a render routine.
10
+
11
+ The `encode(frame, index)` callback records the frame's passes onto a vgpu `Frame` — the same body
12
+ you run in production. The harness owns warmup, the loop, submit, and timing. It uses GPU timestamp
13
+ queries when the device exposes `timestamp-query`, otherwise wall-clock timing via
14
+ `device.queue.flush()`.
15
+
16
+ ```ts
17
+ import { gpuFrameTime } from "@vgpu/render/perf";
18
+
19
+ const { medianMs, method } = await gpuFrameTime(device, (frame, i) => {
20
+ frame.renderPass(scenePass, (pass) => drawScene(pass, i));
21
+ frame.renderPass(floorPass, (pass) => drawFloor(pass, i));
22
+ });
23
+ ```
24
+
25
+ - `options.frames` (default 120), `options.warmup` (default 30), `options.batch` (wall-clock batch
26
+ size, default 8), `options.forceWallClock`, `options.label`.
27
+ - Returns `GpuFrameTimeResult`: `{ medianMs, meanMs, minMs, p95Ms, samples, method }` where `method`
28
+ is `"timestamp-query"` or `"wall-clock"`.
29
+ - Compare medians before vs after. For absolute numbers use a real-GPU device (`@vgpu/adapter-node`
30
+ Dawn or a browser); software backends give relative signal only.
31
+
32
+ ## pixelDiff
33
+
34
+ `pixelDiff(a, b)` compares two renders byte-for-byte. Pass two `Texture`s (read back via
35
+ `Texture.read()`) or two `Uint8Array`s.
36
+
37
+ ```ts
38
+ import { pixelDiff } from "@vgpu/render/perf";
39
+
40
+ const { maxByte } = await pixelDiff(before, after); // before/after are Texture or Uint8Array
41
+ ```
42
+
43
+ Returns `PixelDiffResult`: `{ maxByte, meanByte, changedBytes, totalBytes, changedFraction }`.
44
+ Interpret `maxByte` (max per-channel delta, 0–255): `0` bit-exact, `1–2` imperceptible
45
+ (driver-rounding floor), more is a real visual change. A length mismatch surfaces as `maxByte = 255`.