vgpu1 symbolView source ↗

Symbols in this topic

Gpu

The main API (vgpu) context returned by init(). It owns device lifetime and the frame clock; every resource — canvas surfaces, offscreen targets, render, compute, storage, uniforms, samplers, and bundles — is created by a free function that takes the Gpu as its first argument.

Import

TypeScript
1
2
import type { Gpu } from "vgpu";
import { init } from "vgpu/mock";

Signature

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
28
29
30
31
32
import type { Bundle, BundleOptions, BundleRecorder, Clock, Compute, ComputeOptions, Draw, DrawOptions, Effect, EffectOptions, Frame, FrameLoopHandle, FrameLoopOptions, Geometry, GeometryOptions, GeometryRecipe, GpuErrorListener, PingPongStorage, PingPongTargets, SharedUniforms, StorageAccess, StorageBuffer, StorageOptions, Surface, SurfaceOptions, Target, TargetOptions, TargetTextureOptions, Timer, Visibility, VisibilityOptions } from "vgpu";
import type { Device } from "vgpu/core";
import type { ShaderSource } from "vgpu";
 
interface Gpu {
  readonly device: Device;
  readonly gpu: GPUDevice;
  /** True once `dispose()` ran. Reads stay legal; new work does not. */
  readonly disposed: boolean;
  dispose(): void;
  onError(cb: GpuErrorListener): () => void;
  settled(): Promise<void>;
}
 
// The creation API: named exports of `vgpu`, `vgpu/node` and `vgpu/mock`, all gpu-first.
declare function surface(gpu: Gpu, canvas: HTMLCanvasElement | OffscreenCanvas, opts?: SurfaceOptions): Surface;
declare function effect(gpu: Gpu, source: string | ShaderSource, opts?: EffectOptions): Effect;
declare function draw(gpu: Gpu, opts: DrawOptions): Draw;
declare function target(gpu: Gpu, opts: TargetOptions): Target;
declare function frame(gpu: Gpu, cb?: (frame: Frame) => void): Frame;
declare function frameLoop(gpu: Gpu, cb: (frame: Frame) => void, opts?: FrameLoopOptions): FrameLoopHandle;
declare function sampler(gpu: Gpu, desc?: GPUSamplerDescriptor): GPUSampler;
declare function geometry(gpu: Gpu, input: GeometryOptions | GeometryRecipe): Geometry;
declare function compute(gpu: Gpu, source: string | ShaderSource, opts?: ComputeOptions): Compute;
declare function storage(gpu: Gpu, bytes: number, access?: StorageAccess | StorageOptions): StorageBuffer;
declare function timer(gpu: Gpu): Timer;
declare function visibility(gpu: Gpu, options?: VisibilityOptions): Visibility;
declare function pingPong(gpu: Gpu, width: number, height: number, opts?: TargetTextureOptions): PingPongTargets;
declare function pingPongStorage(gpu: Gpu, bytes: number): PingPongStorage;
declare function uniforms<T extends Record<string, unknown>>(gpu: Gpu, values: T): SharedUniforms<T>;
declare function bundle(gpu: Gpu, opts: BundleOptions, record: (recorder: BundleRecorder) => void): Bundle;
declare function clock(gpu: Gpu): Clock;

Parameters

Gpu is an object, not a callable constructor: it carries no creation methods. Every factory below takes it as gpu, its first argument.

ParamTypeRequiredDefaultNotes
surface.canvasHTMLCanvasElement | OffscreenCanvasCanvas-like object with a webgpu context. A canvas may have one live Surface.
surface.optsSurfaceOptions{}Per-surface canvas format, size, DPR, and auto-resize behavior.
effect.sourcestring | ShaderSourceWGSL string or loader-produced ShaderSource { version: 1, wgsl }.
effect.optsEffectOptions{}label defaults to "effect"; set defaults to no initial bindings.
draw.optsDrawOptionsIncludes required shader; see DrawOptions.
target.optsTargetOptionsOffscreen target options. size is required.
frame.cb(frame: Frame) => voidundefinedIf provided, submits automatically in finally; if omitted, caller must call frame.submit().
sampler.descGPUSamplerDescriptorundefinedCached by descriptor. sampler(gpu) is the canonical default sampler.
geometry.input`GeometryOptions \GeometryRecipe`
compute.sourcestring | ShaderSourceWGSL string or ShaderSource. Must contain a @compute entry point.
compute.optsComputeOptions{}label defaults to "compute"; set defaults to no initial bindings.
storage.bytesnumberByte size for a main API (vgpu) storage buffer.
storage.accessStorageAccess | StorageOptions"read-write"Access string, or a StorageOptions bag { access?, indirect? }. See Compute for storage buffer semantics, including { indirect: true } for GPU-driven draw/dispatch arguments.
timerNo parameters. GPU pass timing; needs the "timestamp-query" device feature. See Timer for feature gating, spans, and result delivery.
visibility.optionsVisibilityOptions{}Occlusion queries for visibility culling — core WebGPU, no device feature required. See Visibility for capacity and handle semantics.
pingPong.widthnumberFloored and clamped to at least 1.
pingPong.heightnumberFloored and clamped to at least 1.
pingPong.optsTargetTextureOptions{}Texture/attachment options only; size comes from positional width/height.
pingPongStorage.bytesnumberCreates two "read-write" storage buffers.
uniforms.valuesRecord<string, unknown>Cloned initial JS values; WGSL layout is adopted when first bound.
bundle.optsBundleOptionsRequires a target or target signature.
bundle.cb(recorder: BundleRecorder) => voidRecords bundle commands immediately.
onError.cbGpuErrorListenerReceives asynchronous vgpu errors; returns an unsubscribe function.
clockNo parameters. The frame clock of this gpu: { time, deltaTime, frameCount, advance(dtSeconds) }, one instance per gpu. See Clock.

Returns: each factory returns the resource named in its signature. dispose() and frame/pass callbacks return void.

Throws: VGPU-GPU-DISPOSED when any factory (or clock(gpu)) runs after gpu.dispose() — the device and everything it owned are gone, so the handle it would return could only fail later; create resources before disposing, or init() a new gpu; VGPU-GPU-FOREIGN when the first argument was not created by init() (a plain object, a GPUDevice, a gpu from another library): it carries no vgpu kernel, so pass the object returned by init() from vgpu, vgpu/node or vgpu/mock; VGPU-LIMIT-STORAGE-VERTEX / VGPU-LIMIT-STORAGE-FRAGMENT when a selected render entry exceeds its granted storage-buffer limit. The structured detail reports stage, entryPoint, count, limit, and each counted binding's name, group, and binding; request a supported limit or reduce/move the data; VGPU-SHADER-SOURCE-INVALID for malformed ShaderSource; VGPU-SET-TEXTURE-FILTERABILITY when a known facade texture format cannot satisfy an ordinarily sampled float binding (detail reports format, texture binding/name/label, and paired sampler identity); VGPU-RING1-UNSUPPORTED for unsupported effect/compute/target cases; VGPU-TARGET-REQUIRED when one-shot drawing needs an explicit target; VGPU-TARGET-SIZE-REQUIRED for runtime JS calls to target(gpu) without size; VGPU-SURFACE-* errors from surface(), surface resize, surface readback, or using disposed surfaces; plus method-specific VGPU-R1-*, VGPU-R3-*, and VGPU-R4-* errors documented on Effect, Draw, Compute, Frame, Bundle, Target, and SharedUniforms.

Examples

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { init, draw, frame, target } from "vgpu/mock";
 
const gpu = await init();
const colorTarget = target(gpu, { size: [128, 128], depth: true });
const drawable = draw(gpu, {
  shader: `
    @vertex fn vs_main(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {
      var p = array<vec2f, 3>(vec2f(-1, -1), vec2f(3, -1), vec2f(-1, 3));
      return vec4f(p[vi], 0, 1);
    }
    @fragment fn fs_main() -> @location(0) vec4f { return vec4f(1, 0, 1, 1); }
  `,
  // optional sync pre-warm; `await draw.compile(target)` is preferred during browser load
  targets: [colorTarget],
});
 
frame(gpu, (currentFrame) => {
  currentFrame.pass({ target: colorTarget, clear: [0, 0, 0, 1] }, (pass) => pass.draw(drawable));
});
TypeScript
1
2
3
4
5
6
7
8
9
10
11
import { init, effect, frameLoop, surface } from "vgpu";
 
declare const canvas: HTMLCanvasElement;
 
const gpu = await init();
const canvasSurface = surface(gpu, canvas, { dpr: [1, 2] });
const wave = effect(gpu, `@fragment fn fs_main() -> @location(0) vec4f { return vec4f(0.2, 0.4, 1.0, 1.0); }`);
 
frameLoop(gpu, (frame) => {
  frame.pass({ target: canvasSurface }, (pass) => pass.draw(wave));
});

Error delivery

gpu.onError(cb) subscribes to asynchronous vgpu errors and returns an unsubscribe function. Listeners run in subscription order; removing one stops future deliveries; a throwing listener is reported to console.error without stopping the rest. If no listener is registered, vgpu reports the error to console.error by default.

gpu.settled() resolves after the current snapshot of pending error deliveries and in-flight pipeline work settles. It never rejects, so it is safe for deterministic tests and teardown.

Notes

  • There is no implicit screen property and no implicit default target. Pass target explicitly to frame passes and one-shot draws.
  • Canvas-specific size, dpr, and autoResize live on surface(gpu, canvas, opts), not on init().
  • Time is explicit JS state, and it lives on the clock, not on the context: read clock(gpu).time / .deltaTime / .frameCount and pass them through set() or SharedUniforms when shaders need them.
  • Every factory rejects a disposed gpu with VGPU-GPU-DISPOSED, and an object vgpu did not create with VGPU-GPU-FOREIGN. Both are thrown synchronously, from the call that made the mistake.
  • See also: init, Clock, Surface, Effect, Draw, Compute, Frame, Target, Bundle, SharedUniforms, Timer, Visibility.

Sampled float texture layouts

vgpu infers sampled-texture layouts per selected WGSL entry point. A non-multisampled texture_*<f32> used by textureSample* or textureGather* with an ordinary sampler receives WebGPU sampleType: "float"; a texture used only by textureLoad remains "unfilterable-float". Calls through helper functions are included.

The WGSL f32 scalar type does not make every concrete texture format filterable. In particular, r32float, rg32float, and rgba32float require the device's float32-filterable feature for ordinary sampling. Use a filterable format, request that feature when supported, or use textureLoad without a sampler.