import { type CommandBuffer, type Result, RhiError, type RhiRenderPassEncoder } from '@forgeax/engine-rhi'; /** * Subset of `RhiDevice` consumed by the mipmap utility (charter F2: only * the methods the algorithm actually invokes; the dawn integration tests * pass a real `RhiDevice` and the unit cache tests pass a hand-rolled stub). * * Four entry-points (all synchronous Result): * - createSampler (default linear / linear / linear) * - createBindGroupLayout * - createPipelineLayout * - createRenderPipeline (per-format pipeline cache miss) * * Shader module is NOT an entry-point here; it is supplied by an injected * `MipmapShaderModuleFactory` (bug-20260518 D-1) so the utility does not * reach into the rhi-webgpu shim package from the runtime layer. * * Plus `createCommandEncoder` + `queue.submit` are added once the upload * call-site (T-M3-05) wires generateMipmaps in; the cache-only public hooks * exercised by T-M3-01 do not need them, so they live behind an extended * MipmapDeviceForBlit alias. */ export type MipmapDevice = { createSampler(desc?: any): Result; createBindGroupLayout(desc: any): Result; createPipelineLayout(desc: any): Result; createRenderPipeline(desc: any): Result; }; /** * Async shader-module factory injected through the call-chain * `createRenderer.ts` -> `AssetRegistry.configureGpuDevice` -> * `generateMipmaps` -> `getOrCreateMipmapPipeline` -> `ensureDeviceCache` * (bug-20260518 D-1 / D-4). * * Signature mirrors the top-level async `createShaderModule(device, desc)` * exposed by the rhi-webgpu shim (and the rhi-wgpu shim) so the * call-site in createRenderer can pass `pack.createShaderModule` directly * without a structural cast. The opaque module value is typed `unknown` * here -- callers do not introspect it; they hand the value back to * `createRenderPipeline` descriptors via the cached `MipmapPipelineCache`. */ export type MipmapShaderModuleFactory = (device: MipmapDevice, desc: { code: string; label?: string; }) => Promise>; /** * Compute mip-level count for a 2D texture (research F-1 SSOT formula). * * Spec-anchor: WebGPU ยง3.6 texture-creation says `mipLevelCount` defaults * to 1; the runtime utility opts AI users into a full chain via * `floor(log2(max(width, height))) + 1` -- the same formula greggman / * toji / webgpufundamentals all converge on. * * @example * numMipLevels({ width: 256, height: 256 }) // 9 * numMipLevels({ width: 1, height: 1 }) // 1 */ export declare function numMipLevels(size: { width: number; height: number; }): number; /** * Number of cached pipelines for the device (introspection hook used by * T-M3-01 (c) cache-hit / (d) per-device-isolation tests; charter P3 * explicit failure: a cache size of 0 on a fresh device is a witnessed * pre-condition rather than a swept-under hint). */ export declare function mipmapCacheSize(device: MipmapDevice): number; /** * Get the existing per-format render pipeline or build a fresh one. * * Per-device WeakMap + per-format `Map` * (greggman 36-44 + 119-122). The shared sampler / shader-module / * bind-group-layout are constructed lazily on the first cache miss for a * given device and reused across all formats on that device. */ export declare function getOrCreateMipmapPipeline(device: MipmapDevice, format: GPUTextureFormat, asyncCreateShaderModule: MipmapShaderModuleFactory): Promise>; /** * Extended device shape used by `generateMipmaps` (call-site T-M3-05). * Adds command-encoder + bind-group + texture-view + queue surfaces beyond * the cache-only `MipmapDevice` so the pipeline-cache unit tests still * compile against the smaller surface. */ export type MipmapBlitDevice = MipmapDevice & { createTexture(desc: any): Result; createBindGroup(desc: any): Result; createTextureView(texture: any, desc: any): Result; createCommandEncoder(desc?: any): Result; readonly queue: { submit(buffers: ReadonlyArray): Result; }; }; /** * A caller-owned mip transaction. Preparation records render passes into one * encoder but never finishes or submits it; the recovery owner decides when * the setup command buffer crosses its candidate generation boundary. */ export interface MipmapEncoderWork { readonly finish: () => Result; /** Close unsubmitted encoder work when its candidate transaction aborts. */ readonly discard: () => void; } /** * Prepare a prewarmed mip chain without creating a hidden submission. * `finish()` is the explicit transaction boundary and is intentionally * separate from `queue.submit()` so recovery can guard candidate ownership. */ export declare function prepareMipmaps(device: MipmapBlitDevice, texture: any, descriptor: { readonly format: GPUTextureFormat; readonly width: number; readonly height: number; readonly levels?: number; }): Result; /** * Per-mip render-pass blit-loop (research F-1 SSOT main template). * * For mip levels 1..levels-1: source view = previous mip {baseMipLevel:i-1, * mipLevelCount:1}; destination view = current mip {baseMipLevel:i, * mipLevelCount:1, usage: RENDER_ATTACHMENT}; oversized-triangle pipeline * draws 3 vertices, fragment shader samples source via linear sampler. * * Spec sRGB correctness (F-3): when format is `*-srgb`, both views inherit * the sRGB encoding so hardware decode -> bilinear in linear -> encode back * happens automatically; no special-casing required. * * `levels` defaults to `numMipLevels({ width, height })`. AI users that * already created the texture with explicit `mipLevelCount` should pass the * same value here. */ export declare function generateMipmaps(device: MipmapBlitDevice, texture: any, descriptor: { readonly format: GPUTextureFormat; readonly width: number; readonly height: number; readonly levels?: number; }, asyncCreateShaderModule: MipmapShaderModuleFactory): Promise>; /** * Synchronous sibling of `generateMipmaps` (feat-20260601-gpu-resource-store * -extraction D-9). Identical per-mip blit loop, but reads the per-format * pipeline + shared sampler / layout from the prewarmed device cache instead * of building them. The pipeline MUST already be present (via a prior * `getOrCreateMipmapPipeline` / `prewarmMipmapPipeline` async call) -- an * un-prewarmed device or format returns a structured `RhiError` rather than * awaiting a build, so the synchronous `draw(world)` frame contract is never * broken. The async build itself does not affect the written bytes (same * shader, same encoder sequence), so prewarm + sync blit reproduces the * pre-extraction async `generateMipmaps` byte-for-byte (D-9 sub-contract 5). */ export declare function blitMipmapsSync(device: MipmapBlitDevice, texture: any, descriptor: { readonly format: GPUTextureFormat; readonly width: number; readonly height: number; readonly levels?: number; }): Result; /** Encode one prewarmed mip level into a caller-owned graph render pass. */ export declare function encodeMipmapLevel(device: MipmapBlitDevice, pass: RhiRenderPassEncoder, sourceView: unknown, format: GPUTextureFormat): Result; //# sourceMappingURL=mipmap-generator.d.ts.map