/** * Uniform Buffer Cache * * Caches small uniform buffers by content hash to avoid repeated allocations. * WebLLM-inspired optimization: uniform buffers with identical contents are reused * across kernel dispatches instead of being created fresh and destroyed each time. */ interface UniformCacheEntry { buffer: GPUBuffer; bytes: Uint8Array; lastUsed: number; refCount: number; } export interface UniformCacheStats { hits: number; misses: number; evictions: number; currentSize: number; hitRate?: string; pendingDestruction?: number; } /** * Uniform Buffer Cache * * Provides content-addressed caching for uniform buffers. Buffers with * identical contents share the same GPU buffer, reducing allocation overhead. * * IMPORTANT: Evicted buffers are NOT destroyed immediately. They are queued * for deferred destruction to avoid use-after-destroy bugs when command * buffers reference cached uniforms that get evicted before submit. * Call flushPendingDestruction() after GPU work completes. */ export declare class UniformBufferCache { private cache: Map; private stats: UniformCacheStats; private pendingDestruction: GPUBuffer[]; private readonly maxEntries: number; private readonly maxAgeMs: number; constructor(maxEntries?: number, maxAgeMs?: number); /** * Get or create a uniform buffer with the given contents. * Returns a cached buffer if one exists with identical data. */ getOrCreate(data: ArrayBuffer | SharedArrayBuffer, label: string): GPUBuffer; /** * Release a reference to a cached buffer. * Buffer is NOT destroyed - it stays in cache for reuse. * Call this instead of buffer.destroy() for cached uniforms. */ release(buffer: GPUBuffer): void; /** * Clear all cached buffers. * Also flushes any pending destruction queue. */ clear(): void; /** * Destroy all buffers in the pending destruction queue. * Call this after GPU work completes (e.g., after onSubmittedWorkDone). * * This is critical for avoiding use-after-destroy bugs: when the uniform * cache evicts a buffer that's still referenced by a pending command buffer, * the buffer is queued here instead of being destroyed immediately. */ flushPendingDestruction(): number; /** * Check if a buffer is managed by this cache */ isCached(buffer: GPUBuffer): boolean; /** * Get cache statistics */ getStats(): UniformCacheStats & { hitRate: string; pendingDestruction: number }; } export function toUniformArrayBuffer(data: ArrayBuffer | ArrayBufferView): ArrayBuffer; /** * Release or destroy a uniform buffer appropriately. * If the buffer is cached, releases it back to the cache. * If not cached, destroys it directly. */ export function releaseUniformBuffer(buffer: GPUBuffer): void; /** * Get the global uniform buffer cache instance */ export function getUniformCache(): UniformBufferCache; /** * Get stats for the current global uniform cache without creating one. */ export function getUniformCacheStats(): (UniformCacheStats & { hitRate: string; pendingDestruction: number }) | null; /** * Reset the global uniform cache (useful for testing or device loss) */ export function resetUniformCache(): void;