/** * The **experimental** WebGPU renderer. * * The asynchronous bootstrap — `getContext("webgpu")` at construction, then * adapter/device negotiation and canvas configuration in * {@link WebGPURenderer#init} (the reason {@link Application#init} is * asynchronous at all) — plus the core 2D frame pipeline: one command * encoder and one render pass per frame, opened by {@link * WebGPURenderer#clear} and submitted by {@link WebGPURenderer#flush}, with * a `depth24plus-stencil8` attachment carried from day one (the stencil * half serves masks; the depth half is reserved for the mesh path). * * It is **opt-in only**: `renderer: video.WEBGPU` (or the `#webgpu` URI * fragment). `video.AUTO` never selects it, and will not until it reaches * feature parity with the WebGL backend. * @augments Renderer * @category Rendering */ export default class WebGPURenderer extends Renderer { /** * @param {ApplicationSettings} options - The renderer parameters */ constructor(options: ApplicationSettings); /** * The WebGPU adapter, set once {@link WebGPURenderer#init} resolves. * @type {GPUAdapter|undefined} * @readonly */ readonly adapter: GPUAdapter | undefined; /** * The WebGPU device, set once {@link WebGPURenderer#init} resolves. * @type {GPUDevice|undefined} * @readonly */ readonly device: GPUDevice | undefined; /** * The WebGPU canvas context * @type {GPUCanvasContext} */ context: GPUCanvasContext; /** * The preferred canvas texture format reported by the platform, * set once {@link WebGPURenderer#init} resolves. * @type {string|undefined} * @readonly */ readonly preferredFormat: string | undefined; cache: TextureCache; currentTransform: Matrix3d; onGameReset: () => void; onCanvasResize: () => void; GPUVendor: string | undefined; stubTextureView: GPUTextureView | null | undefined; /** * Restrict rendering to a sub-rectangle of the canvas — the split-screen * camera surface (`Camera2d`/`Camera3d._setupNonDefaultProjection`). * Callers pass GL-convention rects with a BOTTOM-left origin (the flip is * baked into the camera code, which the GL backend depends on); WebGPU * viewports are top-left, so it is un-flipped here. The rect applies to * canvas passes only — offscreen post-effect targets always render full * size, like the GL pool path re-viewporting per target. * @param {number} x - viewport x (pixels) * @param {number} y - viewport y, bottom-left origin (pixels) * @param {number} width - viewport width (pixels) * @param {number} height - viewport height (pixels) * @override */ override setViewport(x: number, y: number, width: number, height: number): void; /** * Capture the current frame — everything drawn to the active target so * far — into a {@link Texture2d}, entirely on the GPU (an encoder-ordered * `copyTextureToTexture`; no readback round-trip). Same contract as the * WebGL backend's `toFrameTexture`: a shared, renderer-owned slot by * default, `target: null` for a fresh caller-owned capture, or a prior * capture as `target` to refresh it in place; `options.region` captures * a sub-region (framebuffer pixels, bottom-left origin — converted to * this backend's top-left copy origin internally). * * Two documented divergences from the GL capture: * - alpha is preserved (the GL path captures into an opaque RGB texture) * - row 0 of the capture is the TOP of the frame (matching `screen_uv`), * where the GL capture is bottom-up — GLSL bodies sampling a capture * flip with `1.0 - uv.y`; their WGSL twins must not. * @param {object} [options] * @param {Texture2d|null} [options.target] - omit for the shared renderer * slot; a prior capture to refresh it in place; `null` to mint a fresh, * caller-owned capture (`destroy()` it yourself when done) * @param {Bounds|{x: number, y: number, width: number, height: number}} [options.region] - capture * only this sub-region; defaults to the whole frame * @returns {Texture2d|null} a GPU-resident texture holding the captured * frame, or null when no device is available */ toFrameTexture(options?: { target?: Texture2d | null; region?: Bounds | { x: number; y: number; width: number; height: number; } | undefined; }): Texture2d | null; /** * Draw a pooled render target through an effect's pipeline as a * screen-space quad — the compositing primitive of the post-effect * chain. Blending is disabled for camera blits (the target is fully * composited) and kept for per-sprite blits (transparent texels must * not overwrite the scene). * @param {import("../rendertarget/webgpurendertarget.js").default} source - the target to sample * @param {number} x - destination x * @param {number} y - destination y * @param {number} width - destination width * @param {number} height - destination height * @param {ShaderEffect} effect - the effect to composite with * @param {boolean} [keepBlend=false] - keep the current blend mode * @override */ override blitEffect(source: import("../rendertarget/webgpurendertarget.js").default, x: number, y: number, width: number, height: number, effect: ShaderEffect, keepBlend?: boolean): void; /** * Clear the current clip region with the given color — a full-viewport * triangle clipped by the active scissor, drawn with blending replaced * (WebGPU has no scissored clear operation). Used mid-frame by * ColorLayer and Container backgrounds. * * Deliberate divergence from the GL backend: because this is a draw, * it honors an active stencil mask (GL's `gl.clear` ignores stencil and * clears the whole scissor region) — under a mask, the clear fills the * mask window only, which is the behavior masks actually promise. * @param {Color|string} [color="#000000"] - css color * @param {boolean} [opaque=false] - allow transparency or not * @override */ override clearColor(color?: Color | string, opaque?: boolean): void; /** * Erase the pixels in the given rectangular area by setting them to * transparent black (rgba(0,0,0,0)). * @param {number} x - x axis of the coordinate for the rectangle starting point. * @param {number} y - y axis of the coordinate for the rectangle starting point. * @param {number} width - The rectangle's width. * @param {number} height - The rectangle's height. * @override */ override clearRect(x: number, y: number, width: number, height: number): void; /** * Draw a TMX tile layer: WGSL-eligible layers (`renderMode === * "shader"`) draw through the GPU tile path — one quad per tileset, * GID lookup in a per-layer index texture; everything else falls * through to the base per-tile loop. * @param {object} layer - the TMXLayer to draw * @param {object} rect - the visible region in world coords * @override */ override drawTileLayer(layer: object, rect: object): void; /** * Add a batcher to this renderer. * @param {WebGPUBatcher} batcher - a batcher instance * @param {string} [name="default"] - the batcher name * @param {boolean} [activate=false] - true to set this batcher as the active one */ addBatcher(batcher: WebGPUBatcher, name?: string, activate?: boolean): void; /** * Set the active batcher for this renderer — flush + unbind the * outgoing one, bind the incoming. Unlike the GL backend there is no * projection re-sync: the projection lives in the shared frame-globals * bind group, not in per-program uniforms. * @param {string} [name="default"] - a batcher name * @returns {WebGPUBatcher} the now-active batcher */ setBatcher(name?: string): WebGPUBatcher; drawMesh(mesh: any, modelMatrix: any): void; instancedEffectWarned: boolean | undefined; /** * Release any retained geometry held for the given mesh (called from * `Mesh.onDeactivateEvent` / `Mesh.destroy`). * @param {object} mesh - the mesh whose GPU geometry should be freed */ deleteMeshGeometry(mesh: object): void; /** * Multiply the given matrix (or 2D affine components) into the current * transformation matrix * @param {Matrix2d|Matrix3d|number} a - a matrix, or the a component * @param {number} [b] - the b component * @param {number} [c] - the c component * @param {number} [d] - the d component * @param {number} [e] - the e component * @param {number} [f] - the f component */ transform(a: Matrix2d | Matrix3d | number, b?: number, c?: number, d?: number, e?: number, f?: number): void; /** * Reset then multiply the transformation matrix * @param {Matrix2d|Matrix3d|number} a - a matrix, or the a component * @param {number} [b] - the b component * @param {number} [c] - the c component * @param {number} [d] - the d component * @param {number} [e] - the e component * @param {number} [f] - the f component */ setTransform(a: Matrix2d | Matrix3d | number, b?: number, c?: number, d?: number, e?: number, f?: number): void; /** * Return the global alpha * @returns {number} global alpha value */ getGlobalAlpha(): number; /** * set the current blend mode for this renderer.
* Both GPU renderers support the full set — the Canvas fallback supports * every mode below except `"none"`:
* - "normal" : draws new content on top of the existing content
*
* - "add", "additive", or "lighter" : color values are added together
*
* - "multiply" : pixels are multiplied, resulting in a darker picture
*
* - "screen" : pixels are inverted, multiplied, and inverted again (opposite of multiply)
*
* - "darken" : retains the darkest pixels of both layers
*
* - "lighten" : retains the lightest pixels of both layers
*
* - "overlay" : multiplies or screens, depending on the backdrop
*
* - "hard-light" : overlay with the layers swapped — a harsh spotlight
*
* - "soft-light" : a diffused spotlight, gentler than hard-light
*
* - "color-dodge" : brightens the backdrop to reflect the source
*
* - "color-burn" : darkens the backdrop to reflect the source
*
* - "difference" : the absolute difference of the two layers
*
* - "exclusion" : like difference, but lower in contrast
*
* - "none" : blending disabled — the source replaces the destination * outright, alpha included
* A few draw types cannot honour every mode — 3D meshes, and fills using * a {@link Gradient} — and fall back to "normal" with a one-time console * warning. `setBlendMode` returns what it actually applied, so comparing * the result against your request detects that case. * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation * @param {string} [mode="normal"] - blend mode * @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha (affects the source blend factor) * @returns {string} the blend mode actually applied (may differ if the requested mode is unsupported) */ setBlendMode(mode?: string, premultipliedAlpha?: boolean): string; /** * Draw an image onto the frame (Canvas-compatible 3/5/9-argument forms). * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|ImageBitmap|OffscreenCanvas|VideoFrame} image - the source image * @param {number} sx - source x (or destination x in the 3/5-arg forms) * @param {number} sy - source y (or destination y in the 3/5-arg forms) * @param {number} [sw] - source width * @param {number} [sh] - source height * @param {number} [dx] - destination x * @param {number} [dy] - destination y * @param {number} [dw] - destination width * @param {number} [dh] - destination height */ drawImage(image: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | OffscreenCanvas | VideoFrame, sx: number, sy: number, sw?: number, sh?: number, dx?: number, dy?: number, dw?: number, dh?: number): void; /** * The compressed-texture families this device supports, in the same * shape as the GL backend (one key per family; supported families hold * an object of WebGL format constants — the values the loader parsers * emit — unsupported ones are null, so the shared * hasSupportedCompressedFormats works unchanged). PVRTC has no WebGPU * equivalent and stays null. * @returns {object} one key per extension family * @override */ override getSupportedCompressedTextureFormats(): object; supportedCompressedFormats: { astc: { COMPRESSED_RGBA_ASTC_4x4_KHR: number; COMPRESSED_RGBA_ASTC_5x4_KHR: number; COMPRESSED_RGBA_ASTC_5x5_KHR: number; COMPRESSED_RGBA_ASTC_6x5_KHR: number; COMPRESSED_RGBA_ASTC_6x6_KHR: number; COMPRESSED_RGBA_ASTC_8x5_KHR: number; COMPRESSED_RGBA_ASTC_8x6_KHR: number; COMPRESSED_RGBA_ASTC_8x8_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: number; COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: number; } | null; bptc: { COMPRESSED_RGBA_BPTC_UNORM_EXT: number; } | null; s3tc: { COMPRESSED_RGB_S3TC_DXT1_EXT: number; COMPRESSED_RGBA_S3TC_DXT3_EXT: number; COMPRESSED_RGBA_S3TC_DXT5_EXT: number; } | null; s3tc_srgb: { COMPRESSED_SRGB_S3TC_DXT1_EXT: number; COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: number; COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: number; COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: number; } | null; pvrtc: null; etc1: { COMPRESSED_RGB_ETC1_WEBGL: number; } | null; etc2: { COMPRESSED_RGB8_ETC2: number; COMPRESSED_SRGB8_ETC2: number; COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: number; COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: number; COMPRESSED_RGBA8_ETC2_EAC: number; COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: number; COMPRESSED_R11_EAC: number; COMPRESSED_SIGNED_R11_EAC: number; COMPRESSED_RG11_EAC: number; COMPRESSED_SIGNED_RG11_EAC: number; } | null; } | undefined; /** * Pack the active 2D lights and hand the std140 block to the lit * batcher — the WebGPU realization of the backend-neutral lighting * contract (Camera2d calls this once per camera per frame). * @param {Set|Array} lights - active lights * @param {Color} ambient - the ambient lighting floor * @param {number} [translateX=0] - camera translate x * @param {number} [translateY=0] - camera translate y * @override */ override setLightUniforms(lights: Set | Array, ambient: Color, translateX?: number, translateY?: number): void; lightUniformsScratch: import("../webgl/lighting/pack.ts").LightUniformScratch | undefined; /** * Draw a Light2d glow quad through the radial-gradient effect's * single-effect fast path — the light's color and intensity ride the * per-vertex tint, so back-to-back lights share the same pipeline. * @param {Light2d} light - the light to draw * @override */ override drawLight(light: Light2d): void; lightShader: RadialGradientEffect | undefined; lightAtlas: TextureAtlas | undefined; /** * Draw a pattern within the given rectangle. * @param {TextureAtlas} pattern - pattern object returned by {@link WebGPURenderer#createPattern} * @param {number} x - x position where to draw the pattern * @param {number} y - y position where to draw the pattern * @param {number} width - width of the pattern * @param {number} height - height of the pattern */ drawPattern(pattern: TextureAtlas, x: number, y: number, width: number, height: number): void; /** * Create a pattern with the specified repetition * @param {HTMLImageElement|SVGImageElement|HTMLVideoElement|HTMLCanvasElement|ImageBitmap|OffscreenCanvas|VideoFrame} image - source image * @param {string} [repeat="no-repeat"] - one of `"repeat"` / `"repeat-x"` / `"repeat-y"` / `"no-repeat"` * @returns {TextureAtlas} the patterned texture created */ createPattern(image: HTMLImageElement | SVGImageElement | HTMLVideoElement | HTMLCanvasElement | ImageBitmap | OffscreenCanvas | VideoFrame, repeat?: string): TextureAtlas; savedBlendMode: string | undefined; /** * A mask limits rendering elements to the shape and position of the * given mask object — realized on the stencil half of the pass's * depth-stencil attachment, exactly like the GL backend: a write * phase increments the stencil under the mask shape (color writes * off), then the render phase only passes fragments where the stencil * equals the current mask level (or 0 when inverted). * * Entering the first mask level clears the stencil, which WebGPU can * only do at a pass boundary — the frame's pass is broken and * restarted with `stencilLoadOp: "clear"` (color preserved). * (Note: masks are not preserved through save/restore and need to be * manually cleared, same as the other backends.) * @param {Rect|RoundRect|Polygon|Line|Ellipse} [mask] - the shape defining the mask to be applied * @param {boolean} [invert=false] - either the given shape should define what is visible (default) or the opposite */ setMask(mask?: Rect | RoundRect | Polygon | Line | Ellipse, invert?: boolean): void; maskDepthWarned: boolean | undefined; /** * Stroke an arc at the specified coordinates with given radius, start and end points * @param {number} x - arc center point x-axis * @param {number} y - arc center point y-axis * @param {number} radius - arc radius * @param {number} start - start angle in radians * @param {number} end - end angle in radians * @param {boolean} [antiClockwise=false] - draw arc anti-clockwise * @param {boolean} [fill=false] - also fill the shape with the current color if true */ strokeArc(x: number, y: number, radius: number, start: number, end: number, antiClockwise?: boolean, fill?: boolean): void; /** * Fill an arc at the specified coordinates with given radius, start and end points * @param {number} x - arc center point x-axis * @param {number} y - arc center point y-axis * @param {number} radius - arc radius * @param {number} start - start angle in radians * @param {number} end - end angle in radians * @param {boolean} [antiClockwise=false] - draw arc anti-clockwise */ fillArc(x: number, y: number, radius: number, start: number, end: number, antiClockwise?: boolean): void; /** * Fill a line between the given two points * @param {number} startX - the start x coordinate * @param {number} startY - the start y coordinate * @param {number} endX - the end x coordinate * @param {number} endY - the end y coordinate */ fillLine(startX: number, startY: number, endX: number, endY: number): void; /** * Stroke a Polygon on the screen with the current color * @param {Polygon} poly - the shape to draw * @param {boolean} [fill=false] - also fill the shape with the current color if true */ strokePolygon(poly: Polygon, fill?: boolean): void; /** * Fill a Polygon on the screen * @param {Polygon} poly - the shape to draw */ fillPolygon(poly: Polygon): void; /** * Stroke a rounded rectangle at the specified coordinates * @param {number} x - x axis of the coordinate for the rounded rectangle starting point * @param {number} y - y axis of the coordinate for the rounded rectangle starting point * @param {number} width - the rounded rectangle's width * @param {number} height - the rounded rectangle's height * @param {number} radius - the rounded corner's radius * @param {boolean} [fill=false] - also fill the shape with the current color if true */ strokeRoundRect(x: number, y: number, width: number, height: number, radius: number, fill?: boolean): void; /** * Draw a rounded filled rectangle at the specified coordinates * @param {number} x - x axis of the coordinate for the rounded rectangle starting point * @param {number} y - y axis of the coordinate for the rounded rectangle starting point * @param {number} width - the rounded rectangle's width * @param {number} height - the rounded rectangle's height * @param {number} radius - the rounded corner's radius */ fillRoundRect(x: number, y: number, width: number, height: number, radius: number): void; /** * Stroke a Point at the specified coordinates * @param {number} x - x axis of the coordinate for the point * @param {number} y - y axis of the coordinate for the point */ strokePoint(x: number, y: number): void; /** * Draw a point at the specified coordinates * @param {number} x - x axis of the coordinate for the point * @param {number} y - y axis of the coordinate for the point */ fillPoint(x: number, y: number): void; /** * starts a new path by emptying the list of sub-paths */ beginPath(): void; /** * begins a new sub-path at the point specified by the given (x, y) coordinates * @param {number} x - the x axis of the point * @param {number} y - the y axis of the point */ moveTo(x: number, y: number): void; /** * adds a straight line to the current sub-path * @param {number} x - the x axis of the point * @param {number} y - the y axis of the point */ lineTo(x: number, y: number): void; /** * Adds a quadratic Bezier curve to the current sub-path. * @param {number} cpx - the x-axis coordinate of the control point * @param {number} cpy - the y-axis coordinate of the control point * @param {number} x - the x-axis coordinate of the end point * @param {number} y - the y-axis coordinate of the end point */ quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void; /** * Adds a cubic Bezier curve to the current sub-path. * @param {number} cp1x - the x-axis coordinate of the first control point * @param {number} cp1y - the y-axis coordinate of the first control point * @param {number} cp2x - the x-axis coordinate of the second control point * @param {number} cp2y - the y-axis coordinate of the second control point * @param {number} x - the x-axis coordinate of the end point * @param {number} y - the y-axis coordinate of the end point */ bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void; /** * Adds a circular arc to the current sub-path, using the given control points and radius. * @param {number} x1 - the x-axis coordinate of the first control point * @param {number} y1 - the y-axis coordinate of the first control point * @param {number} x2 - the x-axis coordinate of the second control point * @param {number} y2 - the y-axis coordinate of the second control point * @param {number} radius - the arc's radius; must be non-negative */ arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void; /** * creates a rectangular path whose starting point is at (x, y) * @param {number} x - the x axis of the coordinate for the rectangle starting point * @param {number} y - the y axis of the coordinate for the rectangle starting point * @param {number} width - the rectangle's width * @param {number} height - the rectangle's height */ rect(x: number, y: number, width: number, height: number): void; /** * adds a rounded rectangle to the current path * @param {number} x - the x axis of the coordinate for the rectangle starting point * @param {number} y - the y axis of the coordinate for the rectangle starting point * @param {number} width - the rectangle's width * @param {number} height - the rectangle's height * @param {number} radii - the corner radius */ roundRect(x: number, y: number, width: number, height: number, radii: number): void; /** * add a straight line from the current point to the start of the current sub-path */ closePath(): void; /** * stroke the given shape or the current defined path * @param {Rect|RoundRect|Polygon|Line|Ellipse|Bounds} [shape] - a shape object to stroke * @param {boolean} [fill=false] - fill the shape with the current color if true */ stroke(shape?: Rect | RoundRect | Polygon | Line | Ellipse | Bounds, fill?: boolean): void; /** * fill the given shape or the current defined path * @param {Rect|RoundRect|Polygon|Line|Ellipse|Bounds} [shape] - a shape object to fill */ fill(shape?: Rect | RoundRect | Polygon | Line | Ellipse | Bounds): void; /** * Returns the WebGPU canvas context * @returns {GPUCanvasContext} the WebGPU canvas context */ getContext(): GPUCanvasContext; } import Renderer from "../renderer.js"; import OrthogonalTMXLayerGPURenderer from "./renderers/tmxlayer/orthogonal.js"; import TextureCache from "../texture/cache.js"; import { Matrix3d } from "../../math/matrix3d.ts"; import { Bounds } from "../../physics/bounds.ts"; import WebGPUPipelineCache from "./pipeline/cache.js"; import WebGPUBufferArena from "./buffer/arena.js"; import WebGPUUniformRing from "./buffer/uniformring.js"; import WebGPUTextureStore from "./texture/store.js"; import WebGPURenderTarget from "../rendertarget/webgpurendertarget.js"; import BlendEffect from "../effects/blendEffect.js"; import { Color } from "../../math/color.ts"; import WebGPUBatcher from "./batchers/webgpu_batcher.js"; import RadialGradientEffect from "../effects/radialGradient.js"; import { TextureAtlas } from "../texture/atlas.js"; //# sourceMappingURL=webgpu_renderer.d.ts.map