import type { FrameInfo, FrameSegment, GpuContext } from "./types.js"; export interface CreateContextOptions extends GPURequestAdapterOptions, Partial>, Pick { /** * Existing canvas to render into. One is created and appended to body * otherwise. */ canvas?: HTMLCanvasElement; /** CSS width. Defaults to the window size when creating a canvas. */ width?: number; /** CSS height. */ height?: number; /** * Physical pixels per CSS pixel. Defaults to 1. Bounded by the device's * maxTextureDimension2D; cost grows with its square. */ pixelRatio?: number; /** * Features to require on the device, eg. "timestamp-query". Unlike * requestDevice (which rejects), missing ones are skipped with a warning. */ requiredFeatures?: Iterable; /** * Features to take when the adapter offers them, skipped silently otherwise. * * For capabilities an app adapts to rather than depends on — notably the * compressed-texture families, where no single device has all three, so * requesting them as `requiredFeatures` would warn on every run. WebGPU only * reports a feature on the device if it was asked for at creation, so there * is no way to opt in later; read `device.features` afterwards to see what * was granted. */ optionalFeatures?: Iterable; /** * Limits to take up to what the adapter supports, clamped instead of * rejected. * * `requiredLimits` reaches requestDevice untouched, so an unsatisfiable value * rejects — what a hard dependency wants. These are best effort instead: * unknown keys are dropped, `max*` values clamp down to the adapter's and * `min*` alignments clamp up. `requiredLimits` wins on conflict; read * `device.limits` afterwards for what was granted. */ optionalLimits?: NonNullable; /** * Attach a context-managed depth buffer to canvas-targeting passes. Defaults * to true. */ depth?: boolean; /** * Include a stencil aspect in the canvas depth/stencil buffer. Defaults to * false. */ stencil?: boolean; /** * Explicit format for the canvas depth/stencil buffer, eg. "depth32float". * Overrides `depth`/`stencil`. */ depthStencilFormat?: GPUTextureFormat; /** * Keep the canvas's rendered content across frames instead of each frame * starting from undefined content (WebGPU gives canvas textures no such * guarantee — this restores the WebGL-era `preserveDrawingBuffer` * ergonomics). Implemented with a persistent backing texture copied into the * canvas after every frame, so it costs one extra texture-sized copy per * frame — leave it off unless a pass relies on `loadOp: "load"` carrying over * prior frames (eg. trail/feedback effects) or on reading back the canvas * without re-rendering it first. Defaults to false. Requires the canvas usage * to include `COPY_DST`, added automatically unless `usage` is set * explicitly. */ preserveDrawingBuffer?: boolean; } /** * Create a WebGPU context: adapter, device, and a configured canvas. `label` * names the device in browser error messages and tooling; `format` defaults to * getPreferredCanvasFormat(), eg. "rgba16float" for HDR. * * ```js * const ctx = await gpu.createContext({ width: 640, height: 480 }); * ``` */ export declare function createContext(options?: CreateContextOptions): Promise; /** * Set the canvas CSS size and physical drawing buffer size. Size-dependent * resources (depth textures, render targets) are the caller's to recreate — the * next frame reports `resized: true`. * * `ctx.pixelRatio` reports the ratio applied: the requested one, unless the * drawing buffer would exceed maxTextureDimension2D. */ export declare function resize(ctx: GpuContext, width: number, height: number, pixelRatio?: number): void; /** * Open a recording segment: creates a command encoder, acquires the canvas * texture and resets the per-frame uniform ring allocator. submit() and other * declarative commands are only valid between a beginFrame()/endFrame() pair. * * Unlike {@link frame}, this doesn't touch requestAnimationFrame — call it from * any driving loop (a manual rAF loop, a fixed-timestep export loop, an async * pump awaiting backpressure from something else). `frame()` is a thin * convenience wrapper implemented on top of this pair for the common * display-synced case; reach for beginFrame()/endFrame() directly when a * frame's timing isn't display-refresh-driven — eg. rendering for precise video * export, where every rendered frame must be captured regardless of vsync. * * Segments don't nest: call endFrame() before opening another one. * * ```js * const segment = gpu.beginFrame(ctx); * gpu.submit(ctx, drawCmd); * gpu.endFrame(ctx); * ``` */ export declare function beginFrame(ctx: GpuContext, label?: string): FrameSegment; /** * Submit the open segment's commands so far and continue it in a new command * buffer. A validation error fails only the command buffer it is in, so work * flushed this way survives anything invalid recorded after it. * * Not valid inside a pass scope. Returns the new encoder: one obtained before * the flush, eg. `FrameSegment.encoder`, is finished. */ export declare function flush(ctx: GpuContext): GPUCommandEncoder; /** * Close the segment opened by {@link beginFrame}: ends any pass left open, * flushes the uniform ring allocator, blits the preserveDrawingBuffer * backbuffer if enabled, and submits the encoder. Always submits — there's no * discard path, so every opened segment's work reaches the GPU. */ export declare function endFrame(ctx: GpuContext): void; export interface FrameOptions { /** * Frames allowed to be submitted but not yet finished before the loop waits. * Default 2. * * RequestAnimationFrame fires at display rate whether or not the GPU is * keeping up, so a frame costing more than the display interval would * otherwise queue work faster than it drains, without bound. That does not * degrade to a low frame rate — it degrades to the browser killing its GPU * process for not responding. Waiting on an older frame turns it back into * honest slowness. * * `Infinity` restores the unbounded behaviour, for a loop that wants to * measure or manage latency itself. */ maxFramesInFlight?: number; } /** * Render loop. Each frame is a {@link beginFrame}/{@link endFrame} segment synced * to requestAnimationFrame. Return `false` from the callback to stop the loop — * the stopping frame's work is still submitted. * * Paced: at most {@link FrameOptions.maxFramesInFlight} frames may be in flight, * so a scene the GPU cannot keep up with drops frames instead of accumulating * submissions. * * The callback can drive the encoder directly, submit() declarative commands, * or mix both. * * The callback may be async: the segment stays open until it settles and the * next frame is only requested then, so two ticks never share an encoder and * everything drawn still lands in one command buffer. Await CPU work only — the * swapchain texture is acquired when the segment opens, so yielding long enough * for the browser to present would invalidate it. * * ```js * gpu.frame(ctx, ({ time }) => { * gpu.submit(ctx, drawCmd); * }); * * gpu.frame(ctx, ({ encoder, canvasView }) => { * const pass = encoder.beginRenderPass({ colorAttachments: [{ view: canvasView, ... }] }); * // ... * pass.end(); * }); * * gpu.frame(ctx, async () => { * await renderer.render(); // one segment, one submit * gui.draw(); * }); * ``` */ export declare function frame(ctx: GpuContext, callback: (info: FrameInfo) => void | boolean | Promise, options?: FrameOptions): void; //# sourceMappingURL=context.d.ts.map