@vgpu/render 0.0.5 → 0.0.7
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.
- package/README.md +94 -5
- package/dist/frame.d.ts +19 -0
- package/dist/frame.d.ts.map +1 -0
- package/dist/frame.js +50 -0
- package/dist/frame.js.map +1 -0
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/perf/frame-time-measure.d.ts +22 -0
- package/dist/perf/frame-time-measure.d.ts.map +1 -0
- package/dist/perf/frame-time-measure.js +91 -0
- package/dist/perf/frame-time-measure.js.map +1 -0
- package/dist/perf/gpu-frame-time.d.ts +49 -0
- package/dist/perf/gpu-frame-time.d.ts.map +1 -0
- package/dist/perf/gpu-frame-time.js +50 -0
- package/dist/perf/gpu-frame-time.js.map +1 -0
- package/dist/perf/index.d.ts +5 -0
- package/dist/perf/index.d.ts.map +1 -0
- package/dist/perf/index.js +3 -0
- package/dist/perf/index.js.map +1 -0
- package/dist/perf/pixel-diff.d.ts +27 -0
- package/dist/perf/pixel-diff.d.ts.map +1 -0
- package/dist/perf/pixel-diff.js +40 -0
- package/dist/perf/pixel-diff.js.map +1 -0
- package/dist/pipeline-descriptor.d.ts +35 -0
- package/dist/pipeline-descriptor.d.ts.map +1 -0
- package/dist/pipeline-descriptor.js +44 -0
- package/dist/pipeline-descriptor.js.map +1 -0
- package/dist/pipeline.d.ts +24 -14
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +58 -7
- package/dist/pipeline.js.map +1 -1
- package/dist/render-bundle.d.ts +24 -0
- package/dist/render-bundle.d.ts.map +1 -0
- package/dist/render-bundle.js +39 -0
- package/dist/render-bundle.js.map +1 -0
- package/dist/render-pass.d.ts +16 -1
- package/dist/render-pass.d.ts.map +1 -1
- package/dist/render-pass.js +44 -7
- package/dist/render-pass.js.map +1 -1
- package/dist/storage-buffer.d.ts +81 -0
- package/dist/storage-buffer.d.ts.map +1 -0
- package/dist/storage-buffer.js +91 -0
- package/dist/storage-buffer.js.map +1 -0
- package/dist/uniform.d.ts +55 -0
- package/dist/uniform.d.ts.map +1 -0
- package/dist/uniform.js +64 -0
- package/dist/uniform.js.map +1 -0
- package/package.json +8 -3
- package/src/Frame.docs.md +79 -0
- package/src/RenderPass.docs.md +6 -3
- package/src/createRenderPipeline.docs.md +113 -19
- package/src/perf/perf.docs.md +45 -0
- package/src/rapid-renderer.docs.md +15 -1
- package/src/render-bundle.docs.md +46 -0
- package/src/render-target/render-target-canvas.docs.md +15 -0
- package/src/storage-buffer.docs.md +102 -0
- package/src/uniform.docs.md +70 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @vgpu/render
|
|
2
2
|
|
|
3
|
-
> 0.0.
|
|
3
|
+
> 0.0.7 — early preview
|
|
4
4
|
|
|
5
|
-
`@vgpu/render` is the small rendering layer on top of `@vgpu/core`. It
|
|
5
|
+
`@vgpu/render` is the small rendering layer on top of `@vgpu/core`. It focuses on explicit WebGPU-style control: create pipelines, encode standalone render passes, or build one frame command encoder with multiple user-ordered passes.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -13,15 +13,23 @@ pnpm add @vgpu/render
|
|
|
13
13
|
## Exports
|
|
14
14
|
|
|
15
15
|
### Runtime
|
|
16
|
-
- `createRenderPipeline`
|
|
16
|
+
- `createRenderPipeline` / `createRenderPipelineAsync`
|
|
17
17
|
- `RenderPass`
|
|
18
|
+
- `beginFrame` / `Frame`
|
|
19
|
+
- `createRenderBundle` / `RenderBundleRecorder`
|
|
20
|
+
- `RapidRenderer`
|
|
18
21
|
|
|
19
22
|
### Types
|
|
20
23
|
- `RenderPipelineOptions`
|
|
21
24
|
- `ColorAttachment`
|
|
25
|
+
- `DepthStencilAttachment`
|
|
22
26
|
- `RenderPassOptions`
|
|
27
|
+
- `RenderPassDrawOptions`
|
|
28
|
+
- `RenderPassDynamicOffsets`
|
|
29
|
+
- `FrameOptions`
|
|
30
|
+
- `RenderBundleOptions`
|
|
23
31
|
|
|
24
|
-
##
|
|
32
|
+
## Standalone pass
|
|
25
33
|
|
|
26
34
|
```ts
|
|
27
35
|
import { App } from "@vgpu/core";
|
|
@@ -47,9 +55,90 @@ const pass = new RenderPass(device, {
|
|
|
47
55
|
});
|
|
48
56
|
pass.setPipeline(pipeline);
|
|
49
57
|
pass.draw(3);
|
|
50
|
-
pass.end();
|
|
58
|
+
pass.end(); // finishes and submits this one-shot pass
|
|
51
59
|
```
|
|
52
60
|
|
|
61
|
+
## Rapid renderer
|
|
62
|
+
|
|
63
|
+
`RapidRenderer` is available for examples and simple one-draw submissions:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { RapidRenderer } from "@vgpu/render";
|
|
67
|
+
|
|
68
|
+
const renderer = new RapidRenderer(device);
|
|
69
|
+
material.writeUniforms({ viewProjection, model, cameraPosition, light });
|
|
70
|
+
await renderer.draw({ material, mesh, target, depthTarget });
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For homepage-grade hot paths, do not resolve shaders or rebuild pipelines inside
|
|
74
|
+
the animation-frame path. If shader source truly changes dynamically, resolve and
|
|
75
|
+
create the replacement pipeline outside the frame loop, then stage or
|
|
76
|
+
double-buffer the swap so a completed pipeline is installed at a frame boundary.
|
|
77
|
+
|
|
78
|
+
## Explicit multipass frame
|
|
79
|
+
|
|
80
|
+
Render bundles are setup-time reusable draw packets, not hidden passes or a render graph:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { beginFrame, createRenderBundle } from "@vgpu/render";
|
|
84
|
+
|
|
85
|
+
const bundle = createRenderBundle(device, {
|
|
86
|
+
label: "hero.light-sources.bundle",
|
|
87
|
+
colorFormats: ["rgba8unorm"],
|
|
88
|
+
depthStencilFormat: "depth24plus",
|
|
89
|
+
sampleCount: 1,
|
|
90
|
+
record(bundle) {
|
|
91
|
+
bundle.setPipeline(lightPipeline);
|
|
92
|
+
bundle.setBindGroup(0, lightBindGroup);
|
|
93
|
+
bundle.draw(lightVertexCount);
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Native WebGPU multipass code uses one command encoder, explicit pass begin/end calls, then one finish/submit:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const encoder = device.gpu.createCommandEncoder({ label: "hero.frame" });
|
|
102
|
+
|
|
103
|
+
const lightPass = encoder.beginRenderPass(lightPassDescriptor);
|
|
104
|
+
lightPass.executeBundles([bundle]);
|
|
105
|
+
lightPass.end();
|
|
106
|
+
|
|
107
|
+
encoder.writeTimestamp(querySet, 0);
|
|
108
|
+
encoder.copyBufferToBuffer(srcBuffer, 0, dstBuffer, 0, byteLength);
|
|
109
|
+
|
|
110
|
+
const compositePass = encoder.beginRenderPass(compositePassDescriptor);
|
|
111
|
+
compositePass.setPipeline(compositePipeline);
|
|
112
|
+
compositePass.setBindGroup(0, compositeBindGroup);
|
|
113
|
+
compositePass.draw(3);
|
|
114
|
+
compositePass.end();
|
|
115
|
+
|
|
116
|
+
device.queue.gpu.submit([encoder.finish()]);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
With VGPU `Frame`, the lifecycle is the same but pass end and final submission are harder to get wrong:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const frame = beginFrame(device, { label: "hero.frame" });
|
|
123
|
+
frame.renderPass(lightPassDescriptor, (pass) => {
|
|
124
|
+
pass.executeBundles([bundle]);
|
|
125
|
+
});
|
|
126
|
+
frame.gpu.writeTimestamp(querySet, 0);
|
|
127
|
+
frame.copyBufferToBuffer(srcBuffer, dstBuffer, byteLength);
|
|
128
|
+
frame.renderPass(compositePassDescriptor, (pass) => {
|
|
129
|
+
pass.setPipeline(compositePipeline);
|
|
130
|
+
pass.setBindGroup(0, compositeBindGroup);
|
|
131
|
+
pass.draw(3);
|
|
132
|
+
});
|
|
133
|
+
frame.submit(); // finishes once and submits once
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`Frame` preserves authored ordering and exposes its raw `GPUCommandEncoder` as `frame.gpu` for advanced commands. Direct raw encoder calls follow WebGPU behavior; VGPU helper methods guard use after `submit()` with `VGPU-FRAME-SUBMITTED`.
|
|
137
|
+
|
|
138
|
+
For homepage-grade hot paths, create pipelines (sync or async), buffers, bind groups, and render bundles during setup/warmup or resize, then keep per-frame code to command encoding and one queue submit. `createRenderPipelineAsync()` defaults to `fallback: "sync"` with a once-only diagnostic when native async creation is unavailable; use `fallback: "throw"` if warmup must fail rather than block. Avoid runtime `resolveShader()`/shader creation in frame loops; dynamically changing shader source should be resolved and pipelined off the frame path, with staged or double-buffered swaps at frame boundaries.
|
|
139
|
+
|
|
140
|
+
Raw `.gpu` properties such as `device.gpu`, `queue.gpu`, `buffer.gpu`, `texture.gpu`, `shader.gpu`, `frame.gpu`, and `RenderBundleRecorder.gpu` are intentional advanced escape hatches to native WebGPU objects and are treated as semver-protected public API. Native WebGPU validation and lifecycle rules still apply when using them directly.
|
|
141
|
+
|
|
53
142
|
## License
|
|
54
143
|
|
|
55
144
|
MIT.
|
package/dist/frame.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Buffer, type Device } from "@vgpu/core";
|
|
2
|
+
import { type RenderPass, type RenderPassOptions } from "./render-pass.ts";
|
|
3
|
+
export interface FrameOptions {
|
|
4
|
+
readonly label?: string;
|
|
5
|
+
}
|
|
6
|
+
export type FrameRenderPassCallback = (pass: RenderPass) => void;
|
|
7
|
+
export declare class Frame {
|
|
8
|
+
private readonly device;
|
|
9
|
+
readonly gpu: GPUCommandEncoder;
|
|
10
|
+
private submitted;
|
|
11
|
+
constructor(device: Device, opts?: FrameOptions);
|
|
12
|
+
renderPass(opts: RenderPassOptions, record: FrameRenderPassCallback): void;
|
|
13
|
+
copyBufferToBuffer(source: Buffer | GPUBuffer, destination: Buffer | GPUBuffer, size: GPUSize64, sourceOffset?: number, destinationOffset?: number): void;
|
|
14
|
+
submit(): void;
|
|
15
|
+
dispose(): void;
|
|
16
|
+
private assertOpen;
|
|
17
|
+
}
|
|
18
|
+
export declare function beginFrame(device: Device, opts?: FrameOptions): Frame;
|
|
19
|
+
//# sourceMappingURL=frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../src/frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAA6B,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEtG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,uBAAuB,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;AAEjE,qBAAa,KAAK;IAIJ,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,SAAS,CAAS;gBAEG,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB;IAIpE,UAAU,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,uBAAuB,GAAG,IAAI;IAU1E,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,SAAI,EAAE,iBAAiB,SAAI,GAAG,IAAI;IAK/I,MAAM,IAAI,IAAI;IAMd,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,UAAU;CAQnB;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,KAAK,CAEzE"}
|
package/dist/frame.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Buffer, VGPUError } from "@vgpu/core";
|
|
2
|
+
import { createRenderPassOnEncoder } from "./render-pass.js";
|
|
3
|
+
export class Frame {
|
|
4
|
+
device;
|
|
5
|
+
gpu;
|
|
6
|
+
submitted = false;
|
|
7
|
+
constructor(device, opts = {}) {
|
|
8
|
+
this.device = device;
|
|
9
|
+
this.gpu = device.gpu.createCommandEncoder({ label: opts.label });
|
|
10
|
+
}
|
|
11
|
+
renderPass(opts, record) {
|
|
12
|
+
this.assertOpen("Frame.renderPass");
|
|
13
|
+
const pass = createRenderPassOnEncoder(this.device, opts, this.gpu);
|
|
14
|
+
try {
|
|
15
|
+
record(pass);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
pass.end();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
copyBufferToBuffer(source, destination, size, sourceOffset = 0, destinationOffset = 0) {
|
|
22
|
+
this.assertOpen("Frame.copyBufferToBuffer");
|
|
23
|
+
this.gpu.copyBufferToBuffer(gpuBuffer(source), sourceOffset, gpuBuffer(destination), destinationOffset, size);
|
|
24
|
+
}
|
|
25
|
+
submit() {
|
|
26
|
+
this.assertOpen("Frame.submit");
|
|
27
|
+
this.submitted = true;
|
|
28
|
+
this.device.queue.gpu.submit([this.gpu.finish()]);
|
|
29
|
+
}
|
|
30
|
+
dispose() {
|
|
31
|
+
if (!this.submitted)
|
|
32
|
+
this.submit();
|
|
33
|
+
}
|
|
34
|
+
assertOpen(where) {
|
|
35
|
+
if (!this.submitted)
|
|
36
|
+
return;
|
|
37
|
+
throw new VGPUError({
|
|
38
|
+
code: "VGPU-FRAME-SUBMITTED",
|
|
39
|
+
message: "Frame cannot encode or submit after submit().",
|
|
40
|
+
where,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function beginFrame(device, opts = {}) {
|
|
45
|
+
return new Frame(device, opts);
|
|
46
|
+
}
|
|
47
|
+
function gpuBuffer(buffer) {
|
|
48
|
+
return buffer instanceof Buffer ? buffer.gpu : buffer;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame.js","sourceRoot":"","sources":["../src/frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAA2C,MAAM,kBAAkB,CAAC;AAQtG,MAAM,OAAO,KAAK;IAIa;IAHpB,GAAG,CAAoB;IACxB,SAAS,GAAG,KAAK,CAAC;IAE1B,YAA6B,MAAc,EAAE,OAAqB,EAAE;QAAvC,WAAM,GAAN,MAAM,CAAQ;QACzC,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,UAAU,CAAC,IAAuB,EAAE,MAA+B;QACjE,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACpE,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,GAAG,EAAE,CAAC;QACb,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,MAA0B,EAAE,WAA+B,EAAE,IAAe,EAAE,YAAY,GAAG,CAAC,EAAE,iBAAiB,GAAG,CAAC;QACtI,IAAI,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,WAAW,CAAC,EAAE,iBAAiB,EAAE,IAAI,CAAC,CAAC;IAChH,CAAC;IAED,MAAM;QACJ,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IACrC,CAAC;IAEO,UAAU,CAAC,KAAa;QAC9B,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,MAAM,IAAI,SAAS,CAAC;YAClB,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,+CAA+C;YACxD,KAAK;SACN,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,OAAqB,EAAE;IAChE,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,SAAS,CAAC,MAA0B;IAC3C,OAAO,MAAM,YAAY,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AACxD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { beginFrame, Frame } from "./frame.ts";
|
|
2
|
+
export { createRenderBundle, RenderBundleRecorder } from "./render-bundle.ts";
|
|
3
|
+
export { createRenderPipeline, createRenderPipelineAsync, createRenderPipelineFromDescriptor, createRenderPipelineFromDescriptorAsync } from "./pipeline.ts";
|
|
2
4
|
export { RenderPass } from "./render-pass.ts";
|
|
3
5
|
export { RapidRenderer } from "./rapid-renderer.ts";
|
|
6
|
+
export { StorageBuffer } from "./storage-buffer.ts";
|
|
7
|
+
export { Uniform } from "./uniform.ts";
|
|
4
8
|
export { UniformPool } from "./uniform-pool.ts";
|
|
5
|
-
export type {
|
|
9
|
+
export type { FrameOptions, FrameRenderPassCallback } from "./frame.ts";
|
|
10
|
+
export type { RenderBundleOptions } from "./render-bundle.ts";
|
|
11
|
+
export type { RenderPipelineAsyncFallback, RenderPipelineFragmentOptions, RenderPipelineOptions, RenderPipelineShaderInput, RenderPipelineStageOptions, RenderPipelineVertexOptions, } from "./pipeline.ts";
|
|
6
12
|
export type { DrawSpec } from "./rapid-renderer.ts";
|
|
13
|
+
export type { StorageBufferOptions } from "./storage-buffer.ts";
|
|
14
|
+
export type { UniformOptions } from "./uniform.ts";
|
|
7
15
|
export type { UniformLayout, UniformPoolOptions, UniformSlot } from "./uniform-pool-types.ts";
|
|
8
|
-
export type { ColorAttachment, RenderPassDrawOptions, RenderPassDynamicOffsets, RenderPassOptions, } from "./render-pass.ts";
|
|
16
|
+
export type { ColorAttachment, DepthStencilAttachment, RenderPassDrawOptions, RenderPassDynamicOffsets, RenderPassOptions, } from "./render-pass.ts";
|
|
9
17
|
export { box, capsule, cone, cylinder, degToRad, disk, dodecahedron, fullscreenQuad, getMaterialDeclarations, icosahedron, icosphere, material, Mesh, octahedron, orthographicCamera, perspectiveCamera, plane, ring, sampler, sphere, srgb, tetrahedron, torus, wgslDeclarations } from "./domain/index.ts";
|
|
10
18
|
export type { BoxSpec, Camera, CapsuleSpec, ConeSpec, CylinderSpec, DiskSpec, FullscreenQuadSpec, IcosphereSpec, Material, MaterialSamplerSpec, MaterialSpec, MaterialTextureSpec, MaterialUniformValue, Mat4, MeshGpu, MeshPrimitive, PlaneSpec, PolyhedronSpec, RingSpec, Sampler, SamplerSpec, SphereSpec, TextureKind, TextureSpec, TextureValue, TorusSpec, Vec3, VertexAttributes, VertexLayoutKind, WgslUniformType, WriteTextureValues } from "./domain/index.ts";
|
|
11
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kCAAkC,EAAE,uCAAuC,EAAE,MAAM,eAAe,CAAC;AAC7J,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACxE,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EACV,2BAA2B,EAC3B,6BAA6B,EAC7B,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC9F,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,cAAc,EAAE,uBAAuB,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC7S,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,aAAa,EAAE,QAAQ,EAAE,mBAAmB,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { beginFrame, Frame } from "./frame.js";
|
|
2
|
+
export { createRenderBundle, RenderBundleRecorder } from "./render-bundle.js";
|
|
3
|
+
export { createRenderPipeline, createRenderPipelineAsync, createRenderPipelineFromDescriptor, createRenderPipelineFromDescriptorAsync } from "./pipeline.js";
|
|
2
4
|
export { RenderPass } from "./render-pass.js";
|
|
3
5
|
export { RapidRenderer } from "./rapid-renderer.js";
|
|
6
|
+
export { StorageBuffer } from "./storage-buffer.js";
|
|
7
|
+
export { Uniform } from "./uniform.js";
|
|
4
8
|
export { UniformPool } from "./uniform-pool.js";
|
|
5
9
|
export { box, capsule, cone, cylinder, degToRad, disk, dodecahedron, fullscreenQuad, getMaterialDeclarations, icosahedron, icosphere, material, Mesh, octahedron, orthographicCamera, perspectiveCamera, plane, ring, sampler, sphere, srgb, tetrahedron, torus, wgslDeclarations } from "./domain/index.js";
|
|
6
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kCAAkC,EAAE,uCAAuC,EAAE,MAAM,eAAe,CAAC;AAC7J,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAsBhD,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,cAAc,EAAE,uBAAuB,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Device } from "@vgpu/core";
|
|
2
|
+
import { type Frame } from "../frame.ts";
|
|
3
|
+
export type GpuFrameEncoder = (frame: Frame, index: number) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Wall-clock fallback: record one sample per frame while batching only the
|
|
6
|
+
* queue flush cadence. This keeps `samples` aligned with requested frames,
|
|
7
|
+
* matching the timestamp-query path and public docs.
|
|
8
|
+
*/
|
|
9
|
+
export declare function measureWallClock(device: Device, encode: GpuFrameEncoder, frames: number, batch: number, label: string): Promise<number[]>;
|
|
10
|
+
/**
|
|
11
|
+
* GPU-only timing via timestamp queries. Writes a begin/end timestamp around
|
|
12
|
+
* each frame's passes, then resolves all pairs in one read at the end. Throws
|
|
13
|
+
* if timestamp writes are unavailable so the caller can fall back to wall-clock.
|
|
14
|
+
*/
|
|
15
|
+
export declare function measureTimestamp(device: Device, encode: GpuFrameEncoder, frames: number, label: string): Promise<number[]>;
|
|
16
|
+
export declare function summarize(ms: number[]): {
|
|
17
|
+
medianMs: number;
|
|
18
|
+
meanMs: number;
|
|
19
|
+
minMs: number;
|
|
20
|
+
p95Ms: number;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=frame-time-measure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-time-measure.d.ts","sourceRoot":"","sources":["../../src/perf/frame-time-measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAKrD,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAenB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAgDnB;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAaA"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { beginFrame } from "../frame.js";
|
|
2
|
+
const MS_PER_NS = 1 / 1_000_000;
|
|
3
|
+
const MAP_READ = 1; // GPUMapMode.READ
|
|
4
|
+
/**
|
|
5
|
+
* Wall-clock fallback: record one sample per frame while batching only the
|
|
6
|
+
* queue flush cadence. This keeps `samples` aligned with requested frames,
|
|
7
|
+
* matching the timestamp-query path and public docs.
|
|
8
|
+
*/
|
|
9
|
+
export async function measureWallClock(device, encode, frames, batch, label) {
|
|
10
|
+
const samples = [];
|
|
11
|
+
for (let i = 0; i < frames;) {
|
|
12
|
+
const n = Math.min(batch, frames - i);
|
|
13
|
+
for (let k = 0; k < n; k++) {
|
|
14
|
+
const start = performance.now();
|
|
15
|
+
const frame = beginFrame(device, { label });
|
|
16
|
+
encode(frame, i + k);
|
|
17
|
+
frame.submit();
|
|
18
|
+
samples.push(performance.now() - start);
|
|
19
|
+
}
|
|
20
|
+
await device.queue.flush();
|
|
21
|
+
i += n;
|
|
22
|
+
}
|
|
23
|
+
return samples;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* GPU-only timing via timestamp queries. Writes a begin/end timestamp around
|
|
27
|
+
* each frame's passes, then resolves all pairs in one read at the end. Throws
|
|
28
|
+
* if timestamp writes are unavailable so the caller can fall back to wall-clock.
|
|
29
|
+
*/
|
|
30
|
+
export async function measureTimestamp(device, encode, frames, label) {
|
|
31
|
+
const gpu = device.gpu;
|
|
32
|
+
const querySet = gpu.createQuerySet({ type: "timestamp", count: frames * 2 });
|
|
33
|
+
const resolve = device.createBuffer({
|
|
34
|
+
size: frames * 2 * 8,
|
|
35
|
+
usage: ["query_resolve", "copy_src"],
|
|
36
|
+
label: `${label}-ts-resolve`,
|
|
37
|
+
});
|
|
38
|
+
const read = device.createBuffer({
|
|
39
|
+
size: frames * 2 * 8,
|
|
40
|
+
usage: ["map_read", "copy_dst"],
|
|
41
|
+
label: `${label}-ts-read`,
|
|
42
|
+
});
|
|
43
|
+
try {
|
|
44
|
+
for (let i = 0; i < frames; i++) {
|
|
45
|
+
const frame = beginFrame(device, { label });
|
|
46
|
+
const enc = frame.gpu;
|
|
47
|
+
if (typeof enc.writeTimestamp !== "function") {
|
|
48
|
+
throw new Error("GPUCommandEncoder.writeTimestamp unavailable");
|
|
49
|
+
}
|
|
50
|
+
enc.writeTimestamp(querySet, i * 2);
|
|
51
|
+
encode(frame, i);
|
|
52
|
+
enc.writeTimestamp(querySet, i * 2 + 1);
|
|
53
|
+
frame.submit();
|
|
54
|
+
}
|
|
55
|
+
const enc = gpu.createCommandEncoder({ label: `${label}-ts-resolve` });
|
|
56
|
+
enc.resolveQuerySet(querySet, 0, frames * 2, resolve.gpu, 0);
|
|
57
|
+
enc.copyBufferToBuffer(resolve.gpu, 0, read.gpu, 0, frames * 2 * 8);
|
|
58
|
+
gpu.queue.submit([enc.finish()]);
|
|
59
|
+
await read.gpu.mapAsync(MAP_READ);
|
|
60
|
+
const ticks = new BigUint64Array(read.gpu.getMappedRange().slice(0));
|
|
61
|
+
read.gpu.unmap();
|
|
62
|
+
const samples = [];
|
|
63
|
+
for (let i = 0; i < frames; i++) {
|
|
64
|
+
const dt = Number(ticks[i * 2 + 1] - ticks[i * 2]) * MS_PER_NS;
|
|
65
|
+
if (Number.isFinite(dt) && dt > 0)
|
|
66
|
+
samples.push(dt);
|
|
67
|
+
}
|
|
68
|
+
if (samples.length === 0)
|
|
69
|
+
throw new Error("no valid timestamp samples");
|
|
70
|
+
return samples;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
querySet.destroy();
|
|
74
|
+
resolve.dispose();
|
|
75
|
+
read.dispose();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export function summarize(ms) {
|
|
79
|
+
if (ms.length === 0) {
|
|
80
|
+
return { medianMs: 0, meanMs: 0, minMs: 0, p95Ms: 0 };
|
|
81
|
+
}
|
|
82
|
+
const sorted = [...ms].sort((a, b) => a - b);
|
|
83
|
+
const at = (q) => sorted[Math.min(sorted.length - 1, Math.max(0, Math.floor(q * sorted.length)))];
|
|
84
|
+
return {
|
|
85
|
+
medianMs: at(0.5),
|
|
86
|
+
meanMs: sorted.reduce((s, v) => s + v, 0) / sorted.length,
|
|
87
|
+
minMs: sorted[0],
|
|
88
|
+
p95Ms: at(0.95),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=frame-time-measure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-time-measure.js","sourceRoot":"","sources":["../../src/perf/frame-time-measure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Device } from "@vgpu/core";
|
|
2
|
+
import { type Frame } from "../frame.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Options for {@link gpuFrameTime}. All have sensible defaults; the common call passes only the
|
|
5
|
+
* device and an encode callback.
|
|
6
|
+
*/
|
|
7
|
+
export interface GpuFrameTimeOptions {
|
|
8
|
+
/** Measured frames (after warmup). Default 120. */
|
|
9
|
+
readonly frames?: number;
|
|
10
|
+
/** Warmup frames discarded before measuring (shader compile + lazy allocs settle). Default 30. */
|
|
11
|
+
readonly warmup?: number;
|
|
12
|
+
/** Frames per wall-clock batch (amortizes submit/drain latency). Ignored for timestamp-query. Default 8. */
|
|
13
|
+
readonly batch?: number;
|
|
14
|
+
/** Force the wall-clock path even when timestamp-query is available. Default false. */
|
|
15
|
+
readonly forceWallClock?: boolean;
|
|
16
|
+
readonly label?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface GpuFrameTimeResult {
|
|
19
|
+
/** Median per-frame time in milliseconds — the headline number for before/after comparisons. */
|
|
20
|
+
readonly medianMs: number;
|
|
21
|
+
readonly meanMs: number;
|
|
22
|
+
readonly minMs: number;
|
|
23
|
+
readonly p95Ms: number;
|
|
24
|
+
/** Per-frame samples behind the stats. */
|
|
25
|
+
readonly samples: number;
|
|
26
|
+
/**
|
|
27
|
+
* How the time was obtained. `timestamp-query` is GPU-only (excludes submit/drain) and needs the
|
|
28
|
+
* device feature; `wall-clock` (queue.flush) is the robust fallback and works everywhere.
|
|
29
|
+
*/
|
|
30
|
+
readonly method: "timestamp-query" | "wall-clock";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Measures GPU time per frame for a render routine, for before/after optimization comparisons.
|
|
34
|
+
*
|
|
35
|
+
* The `encode` callback records the frame's passes onto a vgpu {@link Frame} — the SAME body you
|
|
36
|
+
* run in production. The harness owns warmup, the loop, submit, and timing, so you don't hand-roll
|
|
37
|
+
* a bench. It prefers GPU timestamp queries when the device supports them (`timestamp-query`) and
|
|
38
|
+
* otherwise falls back to wall-clock timing via `device.queue.flush()`.
|
|
39
|
+
*
|
|
40
|
+
* Tooling only — never call this on a live animation-frame path.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const { medianMs, method } = await gpuFrameTime(device, (frame, i) => {
|
|
44
|
+
* frame.renderPass(scenePass, (pass) => drawScene(pass, i));
|
|
45
|
+
* frame.renderPass(floorPass, (pass) => drawFloor(pass, i));
|
|
46
|
+
* });
|
|
47
|
+
*/
|
|
48
|
+
export declare function gpuFrameTime(device: Device, encode: (frame: Frame, index: number) => void, options?: GpuFrameTimeOptions): Promise<GpuFrameTimeResult>;
|
|
49
|
+
//# sourceMappingURL=gpu-frame-time.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpu-frame-time.d.ts","sourceRoot":"","sources":["../../src/perf/gpu-frame-time.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAGrD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,kGAAkG;IAClG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,4GAA4G;IAC5G,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC;CACnD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,EAC7C,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAwB7B"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { beginFrame } from "../frame.js";
|
|
2
|
+
import { measureTimestamp, measureWallClock, summarize } from "./frame-time-measure.js";
|
|
3
|
+
/**
|
|
4
|
+
* Measures GPU time per frame for a render routine, for before/after optimization comparisons.
|
|
5
|
+
*
|
|
6
|
+
* The `encode` callback records the frame's passes onto a vgpu {@link Frame} — the SAME body you
|
|
7
|
+
* run in production. The harness owns warmup, the loop, submit, and timing, so you don't hand-roll
|
|
8
|
+
* a bench. It prefers GPU timestamp queries when the device supports them (`timestamp-query`) and
|
|
9
|
+
* otherwise falls back to wall-clock timing via `device.queue.flush()`.
|
|
10
|
+
*
|
|
11
|
+
* Tooling only — never call this on a live animation-frame path.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const { medianMs, method } = await gpuFrameTime(device, (frame, i) => {
|
|
15
|
+
* frame.renderPass(scenePass, (pass) => drawScene(pass, i));
|
|
16
|
+
* frame.renderPass(floorPass, (pass) => drawFloor(pass, i));
|
|
17
|
+
* });
|
|
18
|
+
*/
|
|
19
|
+
export async function gpuFrameTime(device, encode, options = {}) {
|
|
20
|
+
const frames = Math.max(1, Math.floor(options.frames ?? 120));
|
|
21
|
+
const warmup = Math.max(0, Math.floor(options.warmup ?? 30));
|
|
22
|
+
const batch = Math.max(1, Math.floor(options.batch ?? 8));
|
|
23
|
+
const label = options.label ?? "vgpu-gpuFrameTime";
|
|
24
|
+
await warmupFrames(device, encode, warmup, label);
|
|
25
|
+
let perFrameMs = null;
|
|
26
|
+
let method = "wall-clock";
|
|
27
|
+
if (!options.forceWallClock && device.features.has("timestamp-query")) {
|
|
28
|
+
try {
|
|
29
|
+
perFrameMs = await measureTimestamp(device, encode, frames, label);
|
|
30
|
+
method = "timestamp-query";
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
perFrameMs = null; // any timestamp hiccup → fall back to the robust path
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (!perFrameMs || perFrameMs.length === 0) {
|
|
37
|
+
perFrameMs = await measureWallClock(device, encode, frames, batch, label);
|
|
38
|
+
method = "wall-clock";
|
|
39
|
+
}
|
|
40
|
+
return { ...summarize(perFrameMs), samples: perFrameMs.length, method };
|
|
41
|
+
}
|
|
42
|
+
async function warmupFrames(device, encode, warmup, label) {
|
|
43
|
+
for (let i = 0; i < warmup; i++) {
|
|
44
|
+
const frame = beginFrame(device, { label });
|
|
45
|
+
encode(frame, i);
|
|
46
|
+
frame.submit();
|
|
47
|
+
}
|
|
48
|
+
await device.queue.flush();
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=gpu-frame-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpu-frame-time.js","sourceRoot":"","sources":["../../src/perf/gpu-frame-time.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAiCxF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAc,EACd,MAA6C,EAC7C,UAA+B,EAAE;IAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,mBAAmB,CAAC;IAEnD,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAElD,IAAI,UAAU,GAAoB,IAAI,CAAC;IACvC,IAAI,MAAM,GAAiC,YAAY,CAAC;IACxD,IAAI,CAAC,OAAO,CAAC,cAAc,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACtE,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YACnE,MAAM,GAAG,iBAAiB,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,GAAG,IAAI,CAAC,CAAC,sDAAsD;QAC3E,CAAC;IACH,CAAC;IACD,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3C,UAAU,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC1E,MAAM,GAAG,YAAY,CAAC;IACxB,CAAC;IAED,OAAO,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;AAC1E,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,MAAc,EACd,MAA6C,EAC7C,MAAc,EACd,KAAa;IAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACjB,KAAK,CAAC,MAAM,EAAE,CAAC;IACjB,CAAC;IACD,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { gpuFrameTime } from "./gpu-frame-time.ts";
|
|
2
|
+
export type { GpuFrameTimeOptions, GpuFrameTimeResult } from "./gpu-frame-time.ts";
|
|
3
|
+
export { pixelDiff } from "./pixel-diff.ts";
|
|
4
|
+
export type { PixelDiffResult } from "./pixel-diff.ts";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/perf/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/perf/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Texture } from "@vgpu/core";
|
|
2
|
+
export interface PixelDiffResult {
|
|
3
|
+
/** Largest absolute per-byte difference (0–255). The headline: ≤1–2 is driver-rounding noise. */
|
|
4
|
+
readonly maxByte: number;
|
|
5
|
+
/** Mean absolute per-byte difference. */
|
|
6
|
+
readonly meanByte: number;
|
|
7
|
+
/** Bytes that differ at all. */
|
|
8
|
+
readonly changedBytes: number;
|
|
9
|
+
readonly totalBytes: number;
|
|
10
|
+
/** changedBytes / totalBytes. A tiny fraction with maxByte ≤ ~2 means "imperceptible". */
|
|
11
|
+
readonly changedFraction: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Compares two renders byte-for-byte — the verify half of measure-before-keeping. Pass two
|
|
15
|
+
* `Texture`s (read back via {@link Texture.read}) or two already-read `Uint8Array`s. Use it to
|
|
16
|
+
* confirm an optimization is bit-exact (maxByte 0) or imperceptible (maxByte ≤ ~2 on a small
|
|
17
|
+
* fraction) before keeping it.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const before = await renderInto(target); // baseline texture
|
|
21
|
+
* applyOptimization();
|
|
22
|
+
* const after = await renderInto(target);
|
|
23
|
+
* const { maxByte } = await pixelDiff(before, after);
|
|
24
|
+
* expect(maxByte).toBeLessThanOrEqual(2);
|
|
25
|
+
*/
|
|
26
|
+
export declare function pixelDiff(a: Texture | Uint8Array, b: Texture | Uint8Array): Promise<PixelDiffResult>;
|
|
27
|
+
//# sourceMappingURL=pixel-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixel-diff.d.ts","sourceRoot":"","sources":["../../src/perf/pixel-diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,0FAA0F;IAC1F,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAC7B,CAAC,EAAE,OAAO,GAAG,UAAU,EACvB,CAAC,EAAE,OAAO,GAAG,UAAU,GACtB,OAAO,CAAC,eAAe,CAAC,CAwB1B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compares two renders byte-for-byte — the verify half of measure-before-keeping. Pass two
|
|
3
|
+
* `Texture`s (read back via {@link Texture.read}) or two already-read `Uint8Array`s. Use it to
|
|
4
|
+
* confirm an optimization is bit-exact (maxByte 0) or imperceptible (maxByte ≤ ~2 on a small
|
|
5
|
+
* fraction) before keeping it.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const before = await renderInto(target); // baseline texture
|
|
9
|
+
* applyOptimization();
|
|
10
|
+
* const after = await renderInto(target);
|
|
11
|
+
* const { maxByte } = await pixelDiff(before, after);
|
|
12
|
+
* expect(maxByte).toBeLessThanOrEqual(2);
|
|
13
|
+
*/
|
|
14
|
+
export async function pixelDiff(a, b) {
|
|
15
|
+
const da = a instanceof Uint8Array ? a : await a.read();
|
|
16
|
+
const db = b instanceof Uint8Array ? b : await b.read();
|
|
17
|
+
const total = Math.min(da.length, db.length);
|
|
18
|
+
let maxByte = 0;
|
|
19
|
+
let sum = 0;
|
|
20
|
+
let changed = 0;
|
|
21
|
+
for (let i = 0; i < total; i++) {
|
|
22
|
+
const d = Math.abs((da[i] ?? 0) - (db[i] ?? 0));
|
|
23
|
+
if (d > 0)
|
|
24
|
+
changed++;
|
|
25
|
+
if (d > maxByte)
|
|
26
|
+
maxByte = d;
|
|
27
|
+
sum += d;
|
|
28
|
+
}
|
|
29
|
+
// A length mismatch is itself a difference; surface it rather than silently comparing a prefix.
|
|
30
|
+
if (da.length !== db.length)
|
|
31
|
+
maxByte = Math.max(maxByte, 255);
|
|
32
|
+
return {
|
|
33
|
+
maxByte,
|
|
34
|
+
meanByte: total === 0 ? 0 : sum / total,
|
|
35
|
+
changedBytes: changed,
|
|
36
|
+
totalBytes: total,
|
|
37
|
+
changedFraction: total === 0 ? 0 : changed / total,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=pixel-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixel-diff.js","sourceRoot":"","sources":["../../src/perf/pixel-diff.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,CAAuB,EACvB,CAAuB;IAEvB,MAAM,EAAE,GAAG,CAAC,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,EAAE,GAAG,CAAC,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAExD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,OAAO;YAAE,OAAO,GAAG,CAAC,CAAC;QAC7B,GAAG,IAAI,CAAC,CAAC;IACX,CAAC;IACD,gGAAgG;IAChG,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM;QAAE,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAE9D,OAAO;QACL,OAAO;QACP,QAAQ,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK;QACvC,YAAY,EAAE,OAAO;QACrB,UAAU,EAAE,KAAK;QACjB,eAAe,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK;KACnD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Shader } from "@vgpu/core";
|
|
2
|
+
export type RenderPipelineShaderInput = Shader | GPUShaderModule;
|
|
3
|
+
export interface RenderPipelineStageOptions {
|
|
4
|
+
/** VGPU Shader or raw GPUShaderModule for this stage. Defaults to RenderPipelineOptions.shader. */
|
|
5
|
+
readonly shader?: RenderPipelineShaderInput;
|
|
6
|
+
/** Descriptor-like alias for shader. */
|
|
7
|
+
readonly module?: RenderPipelineShaderInput;
|
|
8
|
+
/** Entry-point name. Kept for backwards compatibility with the first render helper API. */
|
|
9
|
+
readonly entry?: string;
|
|
10
|
+
/** Descriptor-like entry-point name. */
|
|
11
|
+
readonly entryPoint?: string;
|
|
12
|
+
readonly constants?: Record<string, GPUPipelineConstantValue>;
|
|
13
|
+
}
|
|
14
|
+
export interface RenderPipelineVertexOptions extends RenderPipelineStageOptions {
|
|
15
|
+
readonly buffers?: readonly (GPUVertexBufferLayout | null)[];
|
|
16
|
+
}
|
|
17
|
+
export interface RenderPipelineFragmentOptions extends RenderPipelineStageOptions {
|
|
18
|
+
readonly targets: readonly (GPUColorTargetState | null)[];
|
|
19
|
+
}
|
|
20
|
+
export interface RenderPipelineOptions {
|
|
21
|
+
/** Optional shared shader module used by vertex/fragment stages that do not provide their own module. */
|
|
22
|
+
readonly shader?: RenderPipelineShaderInput;
|
|
23
|
+
readonly vertex: RenderPipelineVertexOptions;
|
|
24
|
+
readonly fragment?: RenderPipelineFragmentOptions;
|
|
25
|
+
readonly primitive?: GPUPrimitiveState;
|
|
26
|
+
readonly depthStencil?: GPUDepthStencilState;
|
|
27
|
+
readonly multisample?: GPUMultisampleState;
|
|
28
|
+
readonly layout?: GPUPipelineLayout | "auto";
|
|
29
|
+
readonly label?: string;
|
|
30
|
+
/** createRenderPipelineAsync fallback when GPUDevice.createRenderPipelineAsync is unavailable. Defaults to "sync". */
|
|
31
|
+
readonly fallback?: RenderPipelineAsyncFallback;
|
|
32
|
+
}
|
|
33
|
+
export type RenderPipelineAsyncFallback = "sync" | "throw";
|
|
34
|
+
export declare function toRenderPipelineDescriptor(opts: RenderPipelineOptions): GPURenderPipelineDescriptor;
|
|
35
|
+
//# sourceMappingURL=pipeline-descriptor.d.ts.map
|