@vgpu/renderAdvanced5 symbolsView source ↗

Symbols in this topic

@vgpu/render/perf

WebGPU verification helpers for the optimize loop. These utilities live under @vgpu/render/perf; they are not meant for runtime use.


gpuFrameTime

Measures GPU frame time statistics for a render routine. The harness handles warmup, command encoding, submission, and timing (timestamp queries when available, wall clock otherwise).

Import

TypeScript
1
import { gpuFrameTime } from "@vgpu/render/perf";

Signature

TypeScript
1
2
3
4
5
export function gpuFrameTime(
  device: Device,
  encode: GpuFrameEncoder,
  options?: GpuFrameTimeOptions,
): Promise<GpuFrameTimeResult>;

Parameters

ParamTypeRequiredDefaultNotes
deviceDeviceSource device used to create command encoders, submit work, and flush the queue. Must expose timestamp-query if you want GPU timestamps.
encodeGpuFrameEncoderCallback invoked per frame with a fresh GPUCommandEncoder; record passes exactly as in production.
optionsGpuFrameTimeOptions{}Tunables for warmup, sample count, and measurement mode.
options.framesnumber120Measured frames after warmup. Values below 1 are clamped to 1.
options.warmupnumber30Throws away the first N frames so shader compilation and lazy allocations settle.
options.batchnumber8Frames per batch when falling back to wall-clock. Ignored for timestamp queries.
options.forceWallClockbooleanfalseForces the wall-clock path even if timestamp-query is available. Useful when you intentionally want queue-submit timings.
options.labelstring"vgpu-gpuFrameTime"Assigns encoder labels and buffer names to make debugging captures easier.

Returns: Promise<GpuFrameTimeResult> — resolves with median, mean, min, p95, sample count, and the measurement method ("timestamp-query" or "wall-clock").

Throws: Propagates any error from the encoder callback, queue submission, or timestamp buffer mapping. Timestamp-specific errors automatically fall back to wall-clock before surfacing.

Examples

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { gpuFrameTime } from "@vgpu/render/perf";
import { createMockAdapter } from "@vgpu/adapter-mock";
 
async function bench(): Promise<void> {
  const adapter = createMockAdapter();
  const device = await adapter.requestDevice();
  const renderPassDescriptor: GPURenderPassDescriptor = { colorAttachments: [{ view: {} as GPUTextureView, loadOp: "clear", storeOp: "store" }] };
  const pipeline = device.gpu.createRenderPipeline({
    layout: "auto",
    vertex: { module: device.gpu.createShaderModule({ code: "@vertex fn vs_main() -> @builtin(position) vec4f { return vec4f(); }" }), entryPoint: "vs_main" },
    fragment: { module: device.gpu.createShaderModule({ code: "@fragment fn fs_main() -> @location(0) vec4f { return vec4f(1.0); }" }), entryPoint: "fs_main", targets: [{ format: "bgra8unorm" }] },
    primitive: { topology: "triangle-list" },
  });
 
  const result = await gpuFrameTime(device, (encoder) => {
    const pass = encoder.beginRenderPass(renderPassDescriptor);
    pass.setPipeline(pipeline);
    pass.draw(3);
    pass.end();
  }, { frames: 60, warmup: 10 });
 
  console.log(result.method, result.medianMs);
}
 
bench().catch((error) => {
  console.error(error);
});

Notes

  • Timestamp queries run only when the device exposes the timestamp-query feature; otherwise wall-clock timings use device.queue.flush() to amortize submit latency via batching.
  • Warmup still submits commands; budget time for shader compilation before measuring.
  • Always compare two runs with identical options; medianMs is the headline figure for relative regressions.
  • See also: pixelDiff

GpuFrameTimeOptions

Optional configuration passed to gpuFrameTime.

Fields

FieldTypeRequiredDefaultNotes
framesnumber120Number of measured frames (post-warmup). Clamped to at least 1.
warmupnumber30Frames to submit and discard before measuring.
batchnumber8Wall-clock batch size; ignored for timestamp mode.
forceWallClockbooleanfalseSkip timestamp queries even when supported.
labelstring"vgpu-gpuFrameTime"Label used for encoders and buffers created internally.

GpuFrameTimeResult

Return type for gpuFrameTime.

Fields

FieldTypeRequiredDefaultNotes
medianMsnumber50th percentile frame time, the main number to compare across builds.
meanMsnumberArithmetic mean of collected samples.
minMsnumberFastest observed frame.
p95Msnumber95th percentile; highlights long tails.
samplesnumberCount of valid samples captured.
method"timestamp-query" | "wall-clock"Measurement backend used.

pixelDiff

Compares two renders byte-for-byte. Accepts either Texture instances (will call read()) or already read Uint8Arrays.

Import

TypeScript
1
import { pixelDiff } from "@vgpu/render/perf";

Signature

TypeScript
1
2
3
4
export function pixelDiff(
  a: Texture | Uint8Array,
  b: Texture | Uint8Array,
): Promise<PixelDiffResult>;

Parameters

ParamTypeRequiredDefaultNotes
aTexture | Uint8ArrayFirst render; when a Texture, it is read via Texture.read().
bTexture | Uint8ArraySecond render to compare against a.

Returns: Promise<PixelDiffResult> — contains maxByte, meanByte, changedBytes, totalBytes, and changedFraction.

Throws: Propagates any error while reading textures (e.g., unreadable usage flags) or when the inputs cannot be read.

Examples

TypeScript
1
2
3
4
5
6
7
8
9
import { pixelDiff } from "@vgpu/render/perf";
import type { Texture } from "@vgpu/core";
 
async function assertVisualParity(before: Texture, after: Texture): Promise<void> {
  const result = await pixelDiff(before, after);
  if (result.maxByte > 2) {
    throw new Error(`Visual regression detected (max delta ${result.maxByte})`);
  }
}

Notes

  • A length mismatch forces maxByte to 255; inspect totalBytes before trusting small maxByte values.
  • Treat maxByte <= 2 as driver rounding noise on most devices; higher values indicate true visual changes.
  • When comparing multiple frames, feed already-read Uint8Arrays to avoid repeated GPU readbacks.
  • See also: gpuFrameTime

PixelDiffResult

Shape returned by pixelDiff.

Fields

FieldTypeRequiredDefaultNotes
maxBytenumberLargest absolute per-byte difference (0–255). Use this as the headline regression metric.
meanBytenumberMean absolute per-byte difference across compared buffers.
changedBytesnumberCount of bytes whose value differs at all.
totalBytesnumberNumber of bytes compared (min of both buffer lengths).
changedFractionnumberchangedBytes / totalBytes; near-zero fractions with low maxByte typically indicate harmless rounding noise.