import type { TextureSource } from "./types.js"; export interface TextureCacheOptions { /** * GL_TEXTURE_MIN_FILTER. Defaults to `LINEAR_MIPMAP_LINEAR` when * `generateMipmaps` is true, else `LINEAR`. Effects libraries that * sample neighbours (not LOD) typically want `LINEAR` without mipmaps. */ minFilter?: GLenum; /** GL_TEXTURE_MAG_FILTER. Defaults to `LINEAR`. */ magFilter?: GLenum; /** GL_TEXTURE_WRAP_S. Defaults to `CLAMP_TO_EDGE`. */ wrapS?: GLenum; /** GL_TEXTURE_WRAP_T. Defaults to `CLAMP_TO_EDGE`. */ wrapT?: GLenum; /** * Whether to call `gl.generateMipmap` after each upload. Required when * `minFilter` is a mipmapped enum. Defaults to true. */ generateMipmaps?: boolean; /** UNPACK_FLIP_Y_WEBGL. Defaults to true. */ flipY?: boolean; /** UNPACK_PREMULTIPLY_ALPHA_WEBGL. Defaults to false. */ premultiplyAlpha?: boolean; /** * Maximum number of URL-keyed entries (from `resolveAsync(url)`) to * retain. When exceeded, least-recently-used entries are evicted: the * GL texture is deleted and the cache entry dropped. Defaults to * `Infinity` (no eviction — preserves prior behavior). * * Only applies to URL inputs. DOM-source entries * (`HTMLImageElement`, `HTMLCanvasElement`, etc.) are not subject to * LRU eviction — they're cleaned up naturally when the source object * is garbage collected (entries are stored in a WeakMap). * * Typical use: lazy-loading slideshows / flipbooks that page through * many images and only need a small window resident on the GPU. */ maxUrlEntries?: number; } /** * Lazy GPU texture uploader keyed on source identity (WeakMap). Mutable * sources (video, canvas, OffscreenCanvas, RawPixels) re-upload on every * `resolve()` because their pixels change frame-to-frame. Immutable * sources (HTMLImageElement, ImageBitmap) upload once and reuse the * cached upload. * * Raw `WebGLTexture` sources bypass the cache entirely — the caller * already owns the GPU-side data. `RawPixels` (`{ pixels, width, * height }`) sources are keyed by the wrapper object's identity: * reuse the wrapper across frames to reuse the underlying GL texture. * * **Binding side effect:** `resolve()` binds the resulting texture to * `gl.TEXTURE_2D` on the currently-active texture unit. When juggling * multiple sources across multiple sampler units, resolve **all** sources * before any `gl.activeTexture` + `gl.bindTexture` calls — otherwise a * later resolve() will clobber a previously-bound unit. */ export declare class TextureCache { private cache; /** * URL-keyed cache. `Map` insertion order doubles as LRU order: every * cache hit re-inserts the entry at the end so `entries().next()` * yields the least-recently-used when we need to evict. */ private urlCache; /** Strong refs to every owned texture so `dispose()` can free them. */ private owned; private gl; private minFilter; private magFilter; private wrapS; private wrapT; private generateMipmaps; private flipY; private premultiplyAlpha; private maxUrlEntries; /** * @param gl Owning WebGL2 context. * @param options Sampler defaults applied to every uploaded texture * (filters, wrap modes, mipmap generation, flip-Y, * premultiplied alpha). All defaults match what most * image-style consumers want. */ constructor(gl: WebGL2RenderingContext, options?: TextureCacheOptions); /** * Look up (or create) a `WebGLTexture` for `source` and ensure its * latest pixels are on the GPU. The returned texture is bound to * `gl.TEXTURE_2D` on the active unit as a side effect — see the * class-level note on bind ordering. * * - `WebGLTexture` source → returned as-is (caller already owns GPU * data; no upload). * - `SizedTexture` source (`{ texture, width, height }`) → inner * texture returned as-is, dimensions are forward-compat metadata. * - Mutable source (`HTMLVideoElement`, ``, `OffscreenCanvas`, * `RawPixels`) → re-uploaded every call so animated sources stay * current. * - Immutable source (`HTMLImageElement`, `ImageBitmap`) → uploaded * once on first call; subsequent calls only rebind. */ resolve(source: TextureSource): WebGLTexture; /** * Sanity-check a RawPixels wrapper on first sight so callers see a * clear error instead of a downstream `INVALID_OPERATION` from WebGL * when the buffer is too small for the declared dimensions. */ private validateRawPixels; /** * Async sibling of `resolve()`. Accepts either an existing * `TextureSource` (synchronous fast path — delegates to `resolve()` * and wraps in `Promise.resolve`) **or** a URL string, which fetches + * decodes + uploads on first call and caches by URL on subsequent * calls. * * URL inputs: * - Resolved via `fetch()` + `createImageBitmap()`, then uploaded. * - Cached by URL string. Concurrent calls with the same URL share * one in-flight promise (request deduplication). * - Subject to LRU eviction if `maxUrlEntries` was set on construction. * - Cross-origin URLs require correct CORS headers (`Access-Control- * Allow-Origin`) — same as any other WebGL texture source. Document * this in your library's README / Next.js guide. * - If the fetch fails or decode throws, the cache entry is removed * so a subsequent `resolveAsync(url)` call retries cleanly. * * **Binding side effect:** same as `resolve()` — the returned texture * is bound to `gl.TEXTURE_2D` on the active unit. Resolve all sources * before any `activeTexture` + `bindTexture` calls. */ resolveAsync(source: TextureSource | string): Promise; /** * Synchronous lookup of a URL-keyed texture. Returns the cached * `WebGLTexture` if the URL has been fully resolved by a prior * `resolveAsync(url)` call, otherwise `undefined`. * * Designed for per-frame render loops where the caller has already * pre-loaded URLs via `resolveAsync(url)` (or a wrapper's `preload()` * helper) and wants synchronous access without re-awaiting promises. * * Returns `undefined` for in-flight loads (promise still pending) * AND for never-requested URLs. Distinguish via the cache's external * loading state if you need to. * * Touches LRU order so the entry stays warm in lazy-loading scenarios. */ getUrlTexture(url: string): WebGLTexture | undefined; /** * Manually evict a single cache entry. Returns true if anything was * released, false if the source/URL wasn't cached. * * - URL string: removes the URL entry and deletes the GL texture (if * already loaded; pending loads are dropped from the index but the * promise still resolves for any in-flight callers). * - DOM source: removes the WeakMap entry and deletes the GL texture. * - Raw `WebGLTexture` / `SizedTexture`: never cached, returns false. * Caller owns the underlying GL texture. * * Used by lazy-loading slideshows / flipbooks to release textures * that have scrolled out of the preload window. */ release(source: TextureSource | string): boolean; /** * Fetch + decode + upload a URL to a fresh GL texture. The returned * texture is owned by the cache (tracked in `this.owned`, freed on * `dispose()`). */ private loadUrlAsTexture; /** * Create a new GL texture, configure its sampler state, and upload * the source's pixels. The texture is added to `this.owned` so * `dispose()` can free it. Does NOT touch any cache — caller is * responsible for storing the returned texture wherever it tracks * its entries. * * Same binding side effect as `resolve()`: the new texture is bound * to `gl.TEXTURE_2D` on the active unit. */ private uploadAsNewTexture; /** * Drop oldest URL entries until we're at or below `maxUrlEntries`. * Eviction order is insertion order in `this.urlCache` (which we * keep aligned with LRU order by re-inserting on every hit). */ private evictIfOverLimit; /** * Free every texture this cache has uploaded. Call at teardown when * you want pixels freed *before* the GL context goes away (e.g. * tearing down a long-lived editor surface). After dispose(), * `resolve()` will allocate fresh textures on next call. * * The source-keyed `WeakMap` itself is dropped — entries for sources * that are still GC-reachable will be re-uploaded on next `resolve()`. * URL cache is also fully cleared. */ dispose(): void; } //# sourceMappingURL=texture-cache.d.ts.map