@motion-core/motion-gpu 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/dist/advanced.js +3 -1
- package/dist/core/advanced.js +3 -1
- package/dist/core/compute-shader.d.ts +87 -0
- package/dist/core/compute-shader.d.ts.map +1 -0
- package/dist/core/compute-shader.js +205 -0
- package/dist/core/compute-shader.js.map +1 -0
- package/dist/core/error-report.d.ts +1 -1
- package/dist/core/error-report.d.ts.map +1 -1
- package/dist/core/error-report.js +63 -0
- package/dist/core/error-report.js.map +1 -1
- package/dist/core/frame-registry.d.ts.map +1 -1
- package/dist/core/frame-registry.js +1 -1
- package/dist/core/frame-registry.js.map +1 -1
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/material-preprocess.d.ts.map +1 -1
- package/dist/core/material-preprocess.js +5 -3
- package/dist/core/material-preprocess.js.map +1 -1
- package/dist/core/material.d.ts +22 -6
- package/dist/core/material.d.ts.map +1 -1
- package/dist/core/material.js +30 -3
- package/dist/core/material.js.map +1 -1
- package/dist/core/render-graph.d.ts +7 -3
- package/dist/core/render-graph.d.ts.map +1 -1
- package/dist/core/render-graph.js +22 -6
- package/dist/core/render-graph.js.map +1 -1
- package/dist/core/renderer.d.ts.map +1 -1
- package/dist/core/renderer.js +418 -23
- package/dist/core/renderer.js.map +1 -1
- package/dist/core/runtime-loop.d.ts +2 -2
- package/dist/core/runtime-loop.d.ts.map +1 -1
- package/dist/core/runtime-loop.js +49 -1
- package/dist/core/runtime-loop.js.map +1 -1
- package/dist/core/shader.d.ts +9 -1
- package/dist/core/shader.d.ts.map +1 -1
- package/dist/core/shader.js +21 -2
- package/dist/core/shader.js.map +1 -1
- package/dist/core/storage-buffers.d.ts +37 -0
- package/dist/core/storage-buffers.d.ts.map +1 -0
- package/dist/core/storage-buffers.js +95 -0
- package/dist/core/storage-buffers.js.map +1 -0
- package/dist/core/texture-loader.d.ts.map +1 -1
- package/dist/core/texture-loader.js +4 -0
- package/dist/core/texture-loader.js.map +1 -1
- package/dist/core/textures.d.ts +12 -0
- package/dist/core/textures.d.ts.map +1 -1
- package/dist/core/textures.js +7 -2
- package/dist/core/textures.js.map +1 -1
- package/dist/core/types.d.ts +146 -4
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/passes/ComputePass.d.ts +83 -0
- package/dist/passes/ComputePass.d.ts.map +1 -0
- package/dist/passes/ComputePass.js +92 -0
- package/dist/passes/ComputePass.js.map +1 -0
- package/dist/passes/PingPongComputePass.d.ts +104 -0
- package/dist/passes/PingPongComputePass.d.ts.map +1 -0
- package/dist/passes/PingPongComputePass.js +132 -0
- package/dist/passes/PingPongComputePass.js.map +1 -0
- package/dist/passes/ShaderPass.d.ts.map +1 -1
- package/dist/passes/ShaderPass.js +2 -1
- package/dist/passes/ShaderPass.js.map +1 -1
- package/dist/passes/index.d.ts +2 -0
- package/dist/passes/index.d.ts.map +1 -1
- package/dist/passes/index.js +3 -1
- package/dist/react/FragCanvas.d.ts +2 -2
- package/dist/react/FragCanvas.d.ts.map +1 -1
- package/dist/react/FragCanvas.js.map +1 -1
- package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -1
- package/dist/react/MotionGPUErrorOverlay.js +123 -20
- package/dist/react/MotionGPUErrorOverlay.js.map +1 -1
- package/dist/react/advanced.js +3 -1
- package/dist/react/index.d.ts +5 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +3 -1
- package/dist/svelte/FragCanvas.svelte +2 -2
- package/dist/svelte/FragCanvas.svelte.d.ts +2 -2
- package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -1
- package/dist/svelte/MotionGPUErrorOverlay.svelte +137 -7
- package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -1
- package/dist/svelte/advanced.js +3 -1
- package/dist/svelte/index.d.ts +5 -2
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +3 -1
- package/package.json +1 -1
- package/src/lib/core/compute-shader.ts +326 -0
- package/src/lib/core/error-report.ts +129 -0
- package/src/lib/core/frame-registry.ts +2 -1
- package/src/lib/core/index.ts +18 -1
- package/src/lib/core/material-preprocess.ts +17 -6
- package/src/lib/core/material.ts +101 -20
- package/src/lib/core/render-graph.ts +39 -9
- package/src/lib/core/renderer.ts +655 -41
- package/src/lib/core/runtime-loop.ts +82 -3
- package/src/lib/core/shader.ts +45 -2
- package/src/lib/core/storage-buffers.ts +142 -0
- package/src/lib/core/texture-loader.ts +6 -0
- package/src/lib/core/textures.ts +24 -2
- package/src/lib/core/types.ts +165 -4
- package/src/lib/passes/ComputePass.ts +136 -0
- package/src/lib/passes/PingPongComputePass.ts +180 -0
- package/src/lib/passes/ShaderPass.ts +2 -1
- package/src/lib/passes/index.ts +6 -0
- package/src/lib/react/FragCanvas.tsx +3 -3
- package/src/lib/react/MotionGPUErrorOverlay.tsx +137 -5
- package/src/lib/react/index.ts +18 -1
- package/src/lib/svelte/FragCanvas.svelte +2 -2
- package/src/lib/svelte/MotionGPUErrorOverlay.svelte +137 -7
- package/src/lib/svelte/index.ts +18 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.js","names":[],"sources":["../../src/lib/core/renderer.ts"],"sourcesContent":["import { buildRenderTargetSignature, resolveRenderTargetDefinitions } from './render-targets.js';\nimport { planRenderGraph, type RenderGraphPlan } from './render-graph.js';\nimport {\n\tbuildShaderSourceWithMap,\n\tformatShaderSourceLocation,\n\ttype ShaderLineMap\n} from './shader.js';\nimport {\n\tattachShaderCompilationDiagnostics,\n\ttype ShaderCompilationRuntimeContext\n} from './error-diagnostics.js';\nimport {\n\tgetTextureMipLevelCount,\n\tnormalizeTextureDefinitions,\n\tresolveTextureUpdateMode,\n\tresolveTextureSize,\n\ttoTextureData\n} from './textures.js';\nimport { packUniformsInto } from './uniforms.js';\nimport type {\n\tRenderPass,\n\tRenderPassInputSlot,\n\tRenderPassOutputSlot,\n\tRenderMode,\n\tRenderTarget,\n\tRenderer,\n\tRendererOptions,\n\tTextureSource,\n\tTextureUpdateMode,\n\tTextureValue\n} from './types.js';\n\n/**\n * Binding index for frame uniforms (`time`, `delta`, `resolution`).\n */\nconst FRAME_BINDING = 0;\n\n/**\n * Binding index for material uniform buffer.\n */\nconst UNIFORM_BINDING = 1;\n\n/**\n * First binding index used for texture sampler/texture pairs.\n */\nconst FIRST_TEXTURE_BINDING = 2;\n\n/**\n * Runtime texture binding state associated with a single texture key.\n */\ninterface RuntimeTextureBinding {\n\tkey: string;\n\tsamplerBinding: number;\n\ttextureBinding: number;\n\tsampler: GPUSampler;\n\tfallbackTexture: GPUTexture;\n\tfallbackView: GPUTextureView;\n\ttexture: GPUTexture | null;\n\tview: GPUTextureView;\n\tsource: TextureSource | null;\n\twidth: number | undefined;\n\theight: number | undefined;\n\tmipLevelCount: number;\n\tformat: GPUTextureFormat;\n\tcolorSpace: 'srgb' | 'linear';\n\tdefaultColorSpace: 'srgb' | 'linear';\n\tflipY: boolean;\n\tdefaultFlipY: boolean;\n\tgenerateMipmaps: boolean;\n\tdefaultGenerateMipmaps: boolean;\n\tpremultipliedAlpha: boolean;\n\tdefaultPremultipliedAlpha: boolean;\n\tupdate: TextureUpdateMode;\n\tdefaultUpdate?: TextureUpdateMode;\n\tlastToken: TextureValue;\n}\n\n/**\n * Runtime render target allocation metadata.\n */\ninterface RuntimeRenderTarget {\n\ttexture: GPUTexture;\n\tview: GPUTextureView;\n\twidth: number;\n\theight: number;\n\tformat: GPUTextureFormat;\n}\n\n/**\n * Cached pass properties used to validate render-graph cache correctness.\n */\ninterface RenderGraphPassSnapshot {\n\tpass: RenderPass;\n\tenabled: RenderPass['enabled'];\n\tneedsSwap: RenderPass['needsSwap'];\n\tinput: RenderPass['input'];\n\toutput: RenderPass['output'];\n\tclear: RenderPass['clear'];\n\tpreserve: RenderPass['preserve'];\n\thasClearColor: boolean;\n\tclearColor0: number;\n\tclearColor1: number;\n\tclearColor2: number;\n\tclearColor3: number;\n}\n\n/**\n * Returns sampler/texture binding slots for a texture index.\n */\nfunction getTextureBindings(index: number): {\n\tsamplerBinding: number;\n\ttextureBinding: number;\n} {\n\tconst samplerBinding = FIRST_TEXTURE_BINDING + index * 2;\n\treturn {\n\t\tsamplerBinding,\n\t\ttextureBinding: samplerBinding + 1\n\t};\n}\n\n/**\n * Resizes canvas backing store to match client size and DPR.\n */\nfunction resizeCanvas(\n\tcanvas: HTMLCanvasElement,\n\tdprInput: number,\n\tcssSize?: { width: number; height: number }\n): { width: number; height: number } {\n\tconst dpr = Number.isFinite(dprInput) && dprInput > 0 ? dprInput : 1;\n\tconst rect = cssSize ? null : canvas.getBoundingClientRect();\n\tconst cssWidth = Math.max(0, cssSize?.width ?? rect?.width ?? 0);\n\tconst cssHeight = Math.max(0, cssSize?.height ?? rect?.height ?? 0);\n\tconst width = Math.max(1, Math.floor((cssWidth || 1) * dpr));\n\tconst height = Math.max(1, Math.floor((cssHeight || 1) * dpr));\n\n\tif (canvas.width !== width || canvas.height !== height) {\n\t\tcanvas.width = width;\n\t\tcanvas.height = height;\n\t}\n\n\treturn { width, height };\n}\n\n/**\n * Throws when a shader module contains WGSL compilation errors.\n */\nasync function assertCompilation(\n\tmodule: GPUShaderModule,\n\toptions?: {\n\t\tlineMap?: ShaderLineMap;\n\t\tfragmentSource?: string;\n\t\tincludeSources?: Record<string, string>;\n\t\tdefineBlockSource?: string;\n\t\tmaterialSource?: {\n\t\t\tcomponent?: string;\n\t\t\tfile?: string;\n\t\t\tline?: number;\n\t\t\tcolumn?: number;\n\t\t\tfunctionName?: string;\n\t\t} | null;\n\t\truntimeContext?: ShaderCompilationRuntimeContext;\n\t}\n): Promise<void> {\n\tconst info = await module.getCompilationInfo();\n\tconst errors = info.messages.filter((message: GPUCompilationMessage) => message.type === 'error');\n\n\tif (errors.length === 0) {\n\t\treturn;\n\t}\n\n\tconst diagnostics = errors.map((message: GPUCompilationMessage) => ({\n\t\tgeneratedLine: message.lineNum,\n\t\tmessage: message.message,\n\t\tlinePos: message.linePos,\n\t\tlineLength: message.length,\n\t\tsourceLocation: options?.lineMap?.[message.lineNum] ?? null\n\t}));\n\n\tconst summary = diagnostics\n\t\t.map((diagnostic) => {\n\t\t\tconst sourceLabel = formatShaderSourceLocation(diagnostic.sourceLocation);\n\t\t\tconst generatedLineLabel =\n\t\t\t\tdiagnostic.generatedLine > 0 ? `generated WGSL line ${diagnostic.generatedLine}` : null;\n\t\t\tconst contextLabel = [sourceLabel, generatedLineLabel].filter((value) => Boolean(value));\n\t\t\tif (contextLabel.length === 0) {\n\t\t\t\treturn diagnostic.message;\n\t\t\t}\n\n\t\t\treturn `[${contextLabel.join(' | ')}] ${diagnostic.message}`;\n\t\t})\n\t\t.join('\\n');\n\tconst error = new Error(`WGSL compilation failed:\\n${summary}`);\n\tthrow attachShaderCompilationDiagnostics(error, {\n\t\tkind: 'shader-compilation',\n\t\tdiagnostics,\n\t\tfragmentSource: options?.fragmentSource ?? '',\n\t\tincludeSources: options?.includeSources ?? {},\n\t\t...(options?.defineBlockSource !== undefined\n\t\t\t? { defineBlockSource: options.defineBlockSource }\n\t\t\t: {}),\n\t\tmaterialSource: options?.materialSource ?? null,\n\t\t...(options?.runtimeContext !== undefined ? { runtimeContext: options.runtimeContext } : {})\n\t});\n}\n\nfunction toSortedUniqueStrings(values: string[]): string[] {\n\treturn Array.from(new Set(values)).sort((a, b) => a.localeCompare(b));\n}\n\nfunction buildPassGraphSnapshot(\n\tpasses: RenderPass[] | undefined\n): NonNullable<ShaderCompilationRuntimeContext['passGraph']> {\n\tconst declaredPasses = passes ?? [];\n\tlet enabledPassCount = 0;\n\tconst inputs: string[] = [];\n\tconst outputs: string[] = [];\n\n\tfor (const pass of declaredPasses) {\n\t\tif (pass.enabled === false) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tenabledPassCount += 1;\n\t\tconst needsSwap = pass.needsSwap ?? true;\n\t\tconst input = pass.input ?? 'source';\n\t\tconst output = pass.output ?? (needsSwap ? 'target' : 'source');\n\t\tinputs.push(input);\n\t\toutputs.push(output);\n\t}\n\n\treturn {\n\t\tpassCount: declaredPasses.length,\n\t\tenabledPassCount,\n\t\tinputs: toSortedUniqueStrings(inputs),\n\t\toutputs: toSortedUniqueStrings(outputs)\n\t};\n}\n\nfunction buildShaderCompilationRuntimeContext(\n\toptions: RendererOptions\n): ShaderCompilationRuntimeContext {\n\tconst passList = options.getPasses?.() ?? options.passes;\n\tconst renderTargetMap = options.getRenderTargets?.() ?? options.renderTargets;\n\n\treturn {\n\t\t...(options.materialSignature ? { materialSignature: options.materialSignature } : {}),\n\t\tpassGraph: buildPassGraphSnapshot(passList),\n\t\tactiveRenderTargets: Object.keys(renderTargetMap ?? {}).sort((a, b) => a.localeCompare(b))\n\t};\n}\n\n/**\n * Creates a 1x1 white fallback texture used before user textures become available.\n */\nfunction createFallbackTexture(device: GPUDevice, format: GPUTextureFormat): GPUTexture {\n\tconst texture = device.createTexture({\n\t\tsize: { width: 1, height: 1, depthOrArrayLayers: 1 },\n\t\tformat,\n\t\tusage:\n\t\t\tGPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT\n\t});\n\n\tconst pixel = new Uint8Array([255, 255, 255, 255]);\n\tdevice.queue.writeTexture(\n\t\t{ texture },\n\t\tpixel,\n\t\t{ offset: 0, bytesPerRow: 4, rowsPerImage: 1 },\n\t\t{ width: 1, height: 1, depthOrArrayLayers: 1 }\n\t);\n\n\treturn texture;\n}\n\n/**\n * Creates an offscreen canvas used for CPU mipmap generation.\n */\nfunction createMipmapCanvas(width: number, height: number): OffscreenCanvas | HTMLCanvasElement {\n\tif (typeof OffscreenCanvas !== 'undefined') {\n\t\treturn new OffscreenCanvas(width, height);\n\t}\n\n\tconst canvas = document.createElement('canvas');\n\tcanvas.width = width;\n\tcanvas.height = height;\n\treturn canvas;\n}\n\n/**\n * Creates typed descriptor for `copyExternalImageToTexture`.\n */\nfunction createExternalCopySource(\n\tsource: CanvasImageSource,\n\toptions: { flipY?: boolean; premultipliedAlpha?: boolean }\n): GPUCopyExternalImageSourceInfo {\n\tconst descriptor = {\n\t\tsource,\n\t\t...(options.flipY ? { flipY: true } : {}),\n\t\t...(options.premultipliedAlpha ? { premultipliedAlpha: true } : {})\n\t};\n\n\treturn descriptor as GPUCopyExternalImageSourceInfo;\n}\n\n/**\n * Uploads source content to a GPU texture and optionally generates mip chain on CPU.\n */\nfunction uploadTexture(\n\tdevice: GPUDevice,\n\ttexture: GPUTexture,\n\tbinding: Pick<RuntimeTextureBinding, 'flipY' | 'premultipliedAlpha' | 'generateMipmaps'>,\n\tsource: TextureSource,\n\twidth: number,\n\theight: number,\n\tmipLevelCount: number\n): void {\n\tdevice.queue.copyExternalImageToTexture(\n\t\tcreateExternalCopySource(source, {\n\t\t\tflipY: binding.flipY,\n\t\t\tpremultipliedAlpha: binding.premultipliedAlpha\n\t\t}),\n\t\t{ texture, mipLevel: 0 },\n\t\t{ width, height, depthOrArrayLayers: 1 }\n\t);\n\n\tif (!binding.generateMipmaps || mipLevelCount <= 1) {\n\t\treturn;\n\t}\n\n\tlet previousSource: CanvasImageSource = source;\n\tlet previousWidth = width;\n\tlet previousHeight = height;\n\n\tfor (let level = 1; level < mipLevelCount; level += 1) {\n\t\tconst nextWidth = Math.max(1, Math.floor(previousWidth / 2));\n\t\tconst nextHeight = Math.max(1, Math.floor(previousHeight / 2));\n\t\tconst canvas = createMipmapCanvas(nextWidth, nextHeight);\n\t\tconst context = canvas.getContext('2d');\n\t\tif (!context) {\n\t\t\tthrow new Error('Unable to create 2D context for mipmap generation');\n\t\t}\n\n\t\tcontext.drawImage(\n\t\t\tpreviousSource,\n\t\t\t0,\n\t\t\t0,\n\t\t\tpreviousWidth,\n\t\t\tpreviousHeight,\n\t\t\t0,\n\t\t\t0,\n\t\t\tnextWidth,\n\t\t\tnextHeight\n\t\t);\n\n\t\tdevice.queue.copyExternalImageToTexture(\n\t\t\tcreateExternalCopySource(canvas, {\n\t\t\t\tpremultipliedAlpha: binding.premultipliedAlpha\n\t\t\t}),\n\t\t\t{ texture, mipLevel: level },\n\t\t\t{ width: nextWidth, height: nextHeight, depthOrArrayLayers: 1 }\n\t\t);\n\n\t\tpreviousSource = canvas;\n\t\tpreviousWidth = nextWidth;\n\t\tpreviousHeight = nextHeight;\n\t}\n}\n\n/**\n * Creates bind group layout entries for frame/uniform buffers plus texture bindings.\n */\nfunction createBindGroupLayoutEntries(\n\ttextureBindings: RuntimeTextureBinding[]\n): GPUBindGroupLayoutEntry[] {\n\tconst entries: GPUBindGroupLayoutEntry[] = [\n\t\t{\n\t\t\tbinding: FRAME_BINDING,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\tbuffer: { type: 'uniform', minBindingSize: 16 }\n\t\t},\n\t\t{\n\t\t\tbinding: UNIFORM_BINDING,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\tbuffer: { type: 'uniform' }\n\t\t}\n\t];\n\n\tfor (const binding of textureBindings) {\n\t\tentries.push({\n\t\t\tbinding: binding.samplerBinding,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\tsampler: { type: 'filtering' }\n\t\t});\n\n\t\tentries.push({\n\t\t\tbinding: binding.textureBinding,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\ttexture: {\n\t\t\t\tsampleType: 'float',\n\t\t\t\tviewDimension: '2d',\n\t\t\t\tmultisampled: false\n\t\t\t}\n\t\t});\n\t}\n\n\treturn entries;\n}\n\n/**\n * Maximum gap (in floats) between two dirty ranges that triggers merge.\n *\n * Set to 4 (16 bytes) which covers one vec4f alignment slot.\n */\nconst DIRTY_RANGE_MERGE_GAP = 4;\n\n/**\n * Computes dirty float ranges between two uniform snapshots.\n *\n * Adjacent dirty ranges separated by a gap smaller than or equal to\n * {@link DIRTY_RANGE_MERGE_GAP} are merged to reduce `writeBuffer` calls.\n */\nexport function findDirtyFloatRanges(\n\tprevious: Float32Array,\n\tnext: Float32Array,\n\tmergeGapThreshold = DIRTY_RANGE_MERGE_GAP\n): Array<{ start: number; count: number }> {\n\tconst ranges: Array<{ start: number; count: number }> = [];\n\tlet start = -1;\n\n\tfor (let index = 0; index < next.length; index += 1) {\n\t\tif (previous[index] !== next[index]) {\n\t\t\tif (start === -1) {\n\t\t\t\tstart = index;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (start !== -1) {\n\t\t\tranges.push({ start, count: index - start });\n\t\t\tstart = -1;\n\t\t}\n\t}\n\n\tif (start !== -1) {\n\t\tranges.push({ start, count: next.length - start });\n\t}\n\n\tif (ranges.length <= 1) {\n\t\treturn ranges;\n\t}\n\n\tconst merged: Array<{ start: number; count: number }> = [ranges[0]!];\n\tfor (let index = 1; index < ranges.length; index += 1) {\n\t\tconst prev = merged[merged.length - 1]!;\n\t\tconst curr = ranges[index]!;\n\t\tconst gap = curr.start - (prev.start + prev.count);\n\n\t\tif (gap <= mergeGapThreshold) {\n\t\t\tprev.count = curr.start + curr.count - prev.start;\n\t\t} else {\n\t\t\tmerged.push(curr);\n\t\t}\n\t}\n\n\treturn merged;\n}\n\n/**\n * Determines whether shader output should perform linear-to-sRGB conversion.\n */\nfunction shouldConvertLinearToSrgb(\n\toutputColorSpace: 'srgb' | 'linear',\n\tcanvasFormat: GPUTextureFormat\n): boolean {\n\tif (outputColorSpace !== 'srgb') {\n\t\treturn false;\n\t}\n\n\treturn !canvasFormat.endsWith('-srgb');\n}\n\n/**\n * WGSL shader used to blit an offscreen texture to the canvas.\n */\nfunction createFullscreenBlitShader(): string {\n\treturn `\nstruct MotionGPUVertexOut {\n\t@builtin(position) position: vec4f,\n\t@location(0) uv: vec2f,\n};\n\n@group(0) @binding(0) var motiongpuBlitSampler: sampler;\n@group(0) @binding(1) var motiongpuBlitTexture: texture_2d<f32>;\n\n@vertex\nfn motiongpuBlitVertex(@builtin(vertex_index) index: u32) -> MotionGPUVertexOut {\n\tvar positions = array<vec2f, 3>(\n\t\tvec2f(-1.0, -3.0),\n\t\tvec2f(-1.0, 1.0),\n\t\tvec2f(3.0, 1.0)\n\t);\n\n\tlet position = positions[index];\n\tvar out: MotionGPUVertexOut;\n\tout.position = vec4f(position, 0.0, 1.0);\n\tout.uv = (position + vec2f(1.0, 1.0)) * 0.5;\n\treturn out;\n}\n\n@fragment\nfn motiongpuBlitFragment(in: MotionGPUVertexOut) -> @location(0) vec4f {\n\treturn textureSample(motiongpuBlitTexture, motiongpuBlitSampler, in.uv);\n}\n`;\n}\n\n/**\n * Allocates a render target texture with usage flags suitable for passes/blits.\n */\nfunction createRenderTexture(\n\tdevice: GPUDevice,\n\twidth: number,\n\theight: number,\n\tformat: GPUTextureFormat\n): RuntimeRenderTarget {\n\tconst texture = device.createTexture({\n\t\tsize: { width, height, depthOrArrayLayers: 1 },\n\t\tformat,\n\t\tusage:\n\t\t\tGPUTextureUsage.TEXTURE_BINDING |\n\t\t\tGPUTextureUsage.RENDER_ATTACHMENT |\n\t\t\tGPUTextureUsage.COPY_DST |\n\t\t\tGPUTextureUsage.COPY_SRC\n\t});\n\n\treturn {\n\t\ttexture,\n\t\tview: texture.createView(),\n\t\twidth,\n\t\theight,\n\t\tformat\n\t};\n}\n\n/**\n * Destroys a render target texture if present.\n */\nfunction destroyRenderTexture(target: RuntimeRenderTarget | null): void {\n\ttarget?.texture.destroy();\n}\n\n/**\n * Creates the WebGPU renderer used by `FragCanvas`.\n *\n * @param options - Renderer creation options resolved from material/context state.\n * @returns Renderer instance with `render` and `destroy`.\n * @throws {Error} On WebGPU unavailability, shader compilation issues, or runtime setup failures.\n */\nexport async function createRenderer(options: RendererOptions): Promise<Renderer> {\n\tif (!navigator.gpu) {\n\t\tthrow new Error('WebGPU is not available in this browser');\n\t}\n\n\tconst context = options.canvas.getContext('webgpu') as GPUCanvasContext | null;\n\tif (!context) {\n\t\tthrow new Error('Canvas does not support webgpu context');\n\t}\n\n\tconst format = navigator.gpu.getPreferredCanvasFormat();\n\tconst adapter = await navigator.gpu.requestAdapter(options.adapterOptions);\n\tif (!adapter) {\n\t\tthrow new Error('Unable to acquire WebGPU adapter');\n\t}\n\n\tconst device = await adapter.requestDevice(options.deviceDescriptor);\n\tlet isDestroyed = false;\n\tlet deviceLostMessage: string | null = null;\n\tlet uncapturedErrorMessage: string | null = null;\n\tconst initializationCleanups: Array<() => void> = [];\n\tlet acceptInitializationCleanups = true;\n\n\tconst registerInitializationCleanup = (cleanup: () => void): void => {\n\t\tif (!acceptInitializationCleanups) {\n\t\t\treturn;\n\t\t}\n\t\toptions.__onInitializationCleanupRegistered?.();\n\t\tinitializationCleanups.push(cleanup);\n\t};\n\n\tconst runInitializationCleanups = (): void => {\n\t\tfor (let index = initializationCleanups.length - 1; index >= 0; index -= 1) {\n\t\t\ttry {\n\t\t\t\tinitializationCleanups[index]?.();\n\t\t\t} catch {\n\t\t\t\t// Best-effort cleanup on failed renderer initialization.\n\t\t\t}\n\t\t}\n\t\tinitializationCleanups.length = 0;\n\t};\n\n\tvoid device.lost.then((info) => {\n\t\tif (isDestroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst reason = info.reason ? ` (${info.reason})` : '';\n\t\tconst details = info.message?.trim();\n\t\tdeviceLostMessage = details\n\t\t\t? `WebGPU device lost: ${details}${reason}`\n\t\t\t: `WebGPU device lost${reason}`;\n\t});\n\n\tconst handleUncapturedError = (event: GPUUncapturedErrorEvent): void => {\n\t\tif (isDestroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst message =\n\t\t\tevent.error instanceof Error\n\t\t\t\t? event.error.message\n\t\t\t\t: String((event.error as { message?: string })?.message ?? event.error);\n\t\tuncapturedErrorMessage = `WebGPU uncaptured error: ${message}`;\n\t};\n\n\tdevice.addEventListener('uncapturederror', handleUncapturedError);\n\ttry {\n\t\tconst runtimeContext = buildShaderCompilationRuntimeContext(options);\n\t\tconst convertLinearToSrgb = shouldConvertLinearToSrgb(options.outputColorSpace, format);\n\t\tconst builtShader = buildShaderSourceWithMap(\n\t\t\toptions.fragmentWgsl,\n\t\t\toptions.uniformLayout,\n\t\t\toptions.textureKeys,\n\t\t\t{\n\t\t\t\tconvertLinearToSrgb,\n\t\t\t\tfragmentLineMap: options.fragmentLineMap\n\t\t\t}\n\t\t);\n\t\tconst shaderModule = device.createShaderModule({ code: builtShader.code });\n\t\tawait assertCompilation(shaderModule, {\n\t\t\tlineMap: builtShader.lineMap,\n\t\t\tfragmentSource: options.fragmentSource,\n\t\t\tincludeSources: options.includeSources,\n\t\t\t...(options.defineBlockSource !== undefined\n\t\t\t\t? { defineBlockSource: options.defineBlockSource }\n\t\t\t\t: {}),\n\t\t\tmaterialSource: options.materialSource ?? null,\n\t\t\truntimeContext\n\t\t});\n\n\t\tconst normalizedTextureDefinitions = normalizeTextureDefinitions(\n\t\t\toptions.textureDefinitions,\n\t\t\toptions.textureKeys\n\t\t);\n\t\tconst textureBindings = options.textureKeys.map((key, index): RuntimeTextureBinding => {\n\t\t\tconst config = normalizedTextureDefinitions[key];\n\t\t\tif (!config) {\n\t\t\t\tthrow new Error(`Missing texture definition for \"${key}\"`);\n\t\t\t}\n\n\t\t\tconst { samplerBinding, textureBinding } = getTextureBindings(index);\n\t\t\tconst sampler = device.createSampler({\n\t\t\t\tmagFilter: config.filter,\n\t\t\t\tminFilter: config.filter,\n\t\t\t\tmipmapFilter: config.generateMipmaps ? config.filter : 'nearest',\n\t\t\t\taddressModeU: config.addressModeU,\n\t\t\t\taddressModeV: config.addressModeV,\n\t\t\t\tmaxAnisotropy: config.filter === 'linear' ? config.anisotropy : 1\n\t\t\t});\n\t\t\tconst fallbackTexture = createFallbackTexture(device, config.format);\n\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\tfallbackTexture.destroy();\n\t\t\t});\n\t\t\tconst fallbackView = fallbackTexture.createView();\n\n\t\t\tconst runtimeBinding: RuntimeTextureBinding = {\n\t\t\t\tkey,\n\t\t\t\tsamplerBinding,\n\t\t\t\ttextureBinding,\n\t\t\t\tsampler,\n\t\t\t\tfallbackTexture,\n\t\t\t\tfallbackView,\n\t\t\t\ttexture: null,\n\t\t\t\tview: fallbackView,\n\t\t\t\tsource: null,\n\t\t\t\twidth: undefined,\n\t\t\t\theight: undefined,\n\t\t\t\tmipLevelCount: 1,\n\t\t\t\tformat: config.format,\n\t\t\t\tcolorSpace: config.colorSpace,\n\t\t\t\tdefaultColorSpace: config.colorSpace,\n\t\t\t\tflipY: config.flipY,\n\t\t\t\tdefaultFlipY: config.flipY,\n\t\t\t\tgenerateMipmaps: config.generateMipmaps,\n\t\t\t\tdefaultGenerateMipmaps: config.generateMipmaps,\n\t\t\t\tpremultipliedAlpha: config.premultipliedAlpha,\n\t\t\t\tdefaultPremultipliedAlpha: config.premultipliedAlpha,\n\t\t\t\tupdate: config.update ?? 'once',\n\t\t\t\tlastToken: null\n\t\t\t};\n\n\t\t\tif (config.update !== undefined) {\n\t\t\t\truntimeBinding.defaultUpdate = config.update;\n\t\t\t}\n\n\t\t\treturn runtimeBinding;\n\t\t});\n\n\t\tconst bindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: createBindGroupLayoutEntries(textureBindings)\n\t\t});\n\t\tconst pipelineLayout = device.createPipelineLayout({\n\t\t\tbindGroupLayouts: [bindGroupLayout]\n\t\t});\n\n\t\tconst pipeline = device.createRenderPipeline({\n\t\t\tlayout: pipelineLayout,\n\t\t\tvertex: {\n\t\t\t\tmodule: shaderModule,\n\t\t\t\tentryPoint: 'motiongpuVertex'\n\t\t\t},\n\t\t\tfragment: {\n\t\t\t\tmodule: shaderModule,\n\t\t\t\tentryPoint: 'motiongpuFragment',\n\t\t\t\ttargets: [{ format }]\n\t\t\t},\n\t\t\tprimitive: {\n\t\t\t\ttopology: 'triangle-list'\n\t\t\t}\n\t\t});\n\n\t\tconst blitShaderModule = device.createShaderModule({\n\t\t\tcode: createFullscreenBlitShader()\n\t\t});\n\t\tawait assertCompilation(blitShaderModule);\n\n\t\tconst blitBindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: [\n\t\t\t\t{\n\t\t\t\t\tbinding: 0,\n\t\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\t\tsampler: { type: 'filtering' }\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 1,\n\t\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\t\ttexture: {\n\t\t\t\t\t\tsampleType: 'float',\n\t\t\t\t\t\tviewDimension: '2d',\n\t\t\t\t\t\tmultisampled: false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t});\n\t\tconst blitPipelineLayout = device.createPipelineLayout({\n\t\t\tbindGroupLayouts: [blitBindGroupLayout]\n\t\t});\n\t\tconst blitPipeline = device.createRenderPipeline({\n\t\t\tlayout: blitPipelineLayout,\n\t\t\tvertex: { module: blitShaderModule, entryPoint: 'motiongpuBlitVertex' },\n\t\t\tfragment: {\n\t\t\t\tmodule: blitShaderModule,\n\t\t\t\tentryPoint: 'motiongpuBlitFragment',\n\t\t\t\ttargets: [{ format }]\n\t\t\t},\n\t\t\tprimitive: {\n\t\t\t\ttopology: 'triangle-list'\n\t\t\t}\n\t\t});\n\t\tconst blitSampler = device.createSampler({\n\t\t\tmagFilter: 'linear',\n\t\t\tminFilter: 'linear',\n\t\t\taddressModeU: 'clamp-to-edge',\n\t\t\taddressModeV: 'clamp-to-edge'\n\t\t});\n\t\tlet blitBindGroupByView = new WeakMap<GPUTextureView, GPUBindGroup>();\n\n\t\tconst frameBuffer = device.createBuffer({\n\t\t\tsize: 16,\n\t\t\tusage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n\t\t});\n\t\tregisterInitializationCleanup(() => {\n\t\t\tframeBuffer.destroy();\n\t\t});\n\n\t\tconst uniformBuffer = device.createBuffer({\n\t\t\tsize: options.uniformLayout.byteLength,\n\t\t\tusage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n\t\t});\n\t\tregisterInitializationCleanup(() => {\n\t\t\tuniformBuffer.destroy();\n\t\t});\n\t\tconst frameScratch = new Float32Array(4);\n\t\tconst uniformScratch = new Float32Array(options.uniformLayout.byteLength / 4);\n\t\tconst uniformPrevious = new Float32Array(options.uniformLayout.byteLength / 4);\n\t\tlet hasUniformSnapshot = false;\n\n\t\t/**\n\t\t * Rebuilds bind group using current texture views.\n\t\t */\n\t\tconst createBindGroup = (): GPUBindGroup => {\n\t\t\tconst entries: GPUBindGroupEntry[] = [\n\t\t\t\t{ binding: FRAME_BINDING, resource: { buffer: frameBuffer } },\n\t\t\t\t{ binding: UNIFORM_BINDING, resource: { buffer: uniformBuffer } }\n\t\t\t];\n\n\t\t\tfor (const binding of textureBindings) {\n\t\t\t\tentries.push({\n\t\t\t\t\tbinding: binding.samplerBinding,\n\t\t\t\t\tresource: binding.sampler\n\t\t\t\t});\n\t\t\t\tentries.push({\n\t\t\t\t\tbinding: binding.textureBinding,\n\t\t\t\t\tresource: binding.view\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn device.createBindGroup({\n\t\t\t\tlayout: bindGroupLayout,\n\t\t\t\tentries\n\t\t\t});\n\t\t};\n\n\t\t/**\n\t\t * Synchronizes one runtime texture binding with incoming texture value.\n\t\t *\n\t\t * @returns `true` when bind group must be rebuilt.\n\t\t */\n\t\tconst updateTextureBinding = (\n\t\t\tbinding: RuntimeTextureBinding,\n\t\t\tvalue: TextureValue,\n\t\t\trenderMode: RenderMode\n\t\t): boolean => {\n\t\t\tconst nextData = toTextureData(value);\n\n\t\t\tif (!nextData) {\n\t\t\t\tif (binding.source === null && binding.texture === null) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tbinding.texture?.destroy();\n\t\t\t\tbinding.texture = null;\n\t\t\t\tbinding.view = binding.fallbackView;\n\t\t\t\tbinding.source = null;\n\t\t\t\tbinding.width = undefined;\n\t\t\t\tbinding.height = undefined;\n\t\t\t\tbinding.lastToken = null;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst source = nextData.source;\n\t\t\tconst colorSpace = nextData.colorSpace ?? binding.defaultColorSpace;\n\t\t\tconst format = colorSpace === 'linear' ? 'rgba8unorm' : 'rgba8unorm-srgb';\n\t\t\tconst flipY = nextData.flipY ?? binding.defaultFlipY;\n\t\t\tconst premultipliedAlpha = nextData.premultipliedAlpha ?? binding.defaultPremultipliedAlpha;\n\t\t\tconst generateMipmaps = nextData.generateMipmaps ?? binding.defaultGenerateMipmaps;\n\t\t\tconst update = resolveTextureUpdateMode({\n\t\t\t\tsource,\n\t\t\t\t...(nextData.update !== undefined ? { override: nextData.update } : {}),\n\t\t\t\t...(binding.defaultUpdate !== undefined ? { defaultMode: binding.defaultUpdate } : {})\n\t\t\t});\n\t\t\tconst { width, height } = resolveTextureSize(nextData);\n\t\t\tconst mipLevelCount = generateMipmaps ? getTextureMipLevelCount(width, height) : 1;\n\t\t\tconst sourceChanged = binding.source !== source;\n\t\t\tconst tokenChanged = binding.lastToken !== value;\n\t\t\tconst requiresReallocation =\n\t\t\t\tbinding.texture === null ||\n\t\t\t\tbinding.width !== width ||\n\t\t\t\tbinding.height !== height ||\n\t\t\t\tbinding.mipLevelCount !== mipLevelCount ||\n\t\t\t\tbinding.format !== format;\n\n\t\t\tif (!requiresReallocation) {\n\t\t\t\tconst shouldUpload =\n\t\t\t\t\tsourceChanged ||\n\t\t\t\t\tupdate === 'perFrame' ||\n\t\t\t\t\t(update === 'onInvalidate' && (renderMode !== 'always' || tokenChanged));\n\n\t\t\t\tif (shouldUpload && binding.texture) {\n\t\t\t\t\tbinding.flipY = flipY;\n\t\t\t\t\tbinding.generateMipmaps = generateMipmaps;\n\t\t\t\t\tbinding.premultipliedAlpha = premultipliedAlpha;\n\t\t\t\t\tbinding.colorSpace = colorSpace;\n\t\t\t\t\tuploadTexture(device, binding.texture, binding, source, width, height, mipLevelCount);\n\t\t\t\t}\n\n\t\t\t\tbinding.source = source;\n\t\t\t\tbinding.width = width;\n\t\t\t\tbinding.height = height;\n\t\t\t\tbinding.mipLevelCount = mipLevelCount;\n\t\t\t\tbinding.update = update;\n\t\t\t\tbinding.lastToken = value;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst texture = device.createTexture({\n\t\t\t\tsize: { width, height, depthOrArrayLayers: 1 },\n\t\t\t\tformat,\n\t\t\t\tmipLevelCount,\n\t\t\t\tusage:\n\t\t\t\t\tGPUTextureUsage.TEXTURE_BINDING |\n\t\t\t\t\tGPUTextureUsage.COPY_DST |\n\t\t\t\t\tGPUTextureUsage.RENDER_ATTACHMENT\n\t\t\t});\n\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\ttexture.destroy();\n\t\t\t});\n\n\t\t\tbinding.flipY = flipY;\n\t\t\tbinding.generateMipmaps = generateMipmaps;\n\t\t\tbinding.premultipliedAlpha = premultipliedAlpha;\n\t\t\tbinding.colorSpace = colorSpace;\n\t\t\tbinding.format = format;\n\t\t\tuploadTexture(device, texture, binding, source, width, height, mipLevelCount);\n\n\t\t\tbinding.texture?.destroy();\n\t\t\tbinding.texture = texture;\n\t\t\tbinding.view = texture.createView();\n\t\t\tbinding.source = source;\n\t\t\tbinding.width = width;\n\t\t\tbinding.height = height;\n\t\t\tbinding.mipLevelCount = mipLevelCount;\n\t\t\tbinding.update = update;\n\t\t\tbinding.lastToken = value;\n\t\t\treturn true;\n\t\t};\n\n\t\tfor (const binding of textureBindings) {\n\t\t\tconst defaultSource = normalizedTextureDefinitions[binding.key]?.source ?? null;\n\t\t\tupdateTextureBinding(binding, defaultSource, 'always');\n\t\t}\n\n\t\tlet bindGroup = createBindGroup();\n\t\tlet sourceSlotTarget: RuntimeRenderTarget | null = null;\n\t\tlet targetSlotTarget: RuntimeRenderTarget | null = null;\n\t\tlet renderTargetSignature = '';\n\t\tlet renderTargetSnapshot: Readonly<Record<string, RenderTarget>> = {};\n\t\tlet renderTargetKeys: string[] = [];\n\t\tlet cachedGraphPlan: RenderGraphPlan | null = null;\n\t\tlet cachedGraphRenderTargetSignature = '';\n\t\tconst cachedGraphClearColor: [number, number, number, number] = [NaN, NaN, NaN, NaN];\n\t\tconst cachedGraphPasses: RenderGraphPassSnapshot[] = [];\n\t\tlet contextConfigured = false;\n\t\tlet configuredWidth = 0;\n\t\tlet configuredHeight = 0;\n\t\tconst runtimeRenderTargets = new Map<string, RuntimeRenderTarget>();\n\t\tconst activePasses: RenderPass[] = [];\n\t\tconst lifecyclePreviousSet = new Set<RenderPass>();\n\t\tconst lifecycleNextSet = new Set<RenderPass>();\n\t\tconst lifecycleUniquePasses: RenderPass[] = [];\n\t\tlet lifecyclePassesRef: RenderPass[] | null = null;\n\t\tlet passWidth = 0;\n\t\tlet passHeight = 0;\n\n\t\t/**\n\t\t * Resolves active render pass list for current frame.\n\t\t */\n\t\tconst resolvePasses = (): RenderPass[] => {\n\t\t\treturn options.getPasses?.() ?? options.passes ?? [];\n\t\t};\n\n\t\t/**\n\t\t * Resolves active render target declarations for current frame.\n\t\t */\n\t\tconst resolveRenderTargets = () => {\n\t\t\treturn options.getRenderTargets?.() ?? options.renderTargets;\n\t\t};\n\n\t\t/**\n\t\t * Checks whether cached render-graph plan can be reused for this frame.\n\t\t */\n\t\tconst isGraphPlanCacheValid = (\n\t\t\tpasses: RenderPass[],\n\t\t\tclearColor: [number, number, number, number]\n\t\t): boolean => {\n\t\t\tif (!cachedGraphPlan) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (cachedGraphRenderTargetSignature !== renderTargetSignature) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tcachedGraphClearColor[0] !== clearColor[0] ||\n\t\t\t\tcachedGraphClearColor[1] !== clearColor[1] ||\n\t\t\t\tcachedGraphClearColor[2] !== clearColor[2] ||\n\t\t\t\tcachedGraphClearColor[3] !== clearColor[3]\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (cachedGraphPasses.length !== passes.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor (let index = 0; index < passes.length; index += 1) {\n\t\t\t\tconst pass = passes[index];\n\t\t\t\tconst snapshot = cachedGraphPasses[index];\n\t\t\t\tif (!pass || !snapshot || snapshot.pass !== pass) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tsnapshot.enabled !== pass.enabled ||\n\t\t\t\t\tsnapshot.needsSwap !== pass.needsSwap ||\n\t\t\t\t\tsnapshot.input !== pass.input ||\n\t\t\t\t\tsnapshot.output !== pass.output ||\n\t\t\t\t\tsnapshot.clear !== pass.clear ||\n\t\t\t\t\tsnapshot.preserve !== pass.preserve\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst passClearColor = pass.clearColor;\n\t\t\t\tconst hasPassClearColor = passClearColor !== undefined;\n\t\t\t\tif (snapshot.hasClearColor !== hasPassClearColor) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (passClearColor) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tsnapshot.clearColor0 !== passClearColor[0] ||\n\t\t\t\t\t\tsnapshot.clearColor1 !== passClearColor[1] ||\n\t\t\t\t\t\tsnapshot.clearColor2 !== passClearColor[2] ||\n\t\t\t\t\t\tsnapshot.clearColor3 !== passClearColor[3]\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t};\n\n\t\t/**\n\t\t * Updates render-graph cache with current pass set.\n\t\t */\n\t\tconst updateGraphPlanCache = (\n\t\t\tpasses: RenderPass[],\n\t\t\tclearColor: [number, number, number, number],\n\t\t\tgraphPlan: RenderGraphPlan\n\t\t): void => {\n\t\t\tcachedGraphPlan = graphPlan;\n\t\t\tcachedGraphRenderTargetSignature = renderTargetSignature;\n\t\t\tcachedGraphClearColor[0] = clearColor[0];\n\t\t\tcachedGraphClearColor[1] = clearColor[1];\n\t\t\tcachedGraphClearColor[2] = clearColor[2];\n\t\t\tcachedGraphClearColor[3] = clearColor[3];\n\t\t\tcachedGraphPasses.length = passes.length;\n\n\t\t\tlet index = 0;\n\t\t\tfor (const pass of passes) {\n\t\t\t\tconst passClearColor = pass.clearColor;\n\t\t\t\tconst hasPassClearColor = passClearColor !== undefined;\n\t\t\t\tconst snapshot = cachedGraphPasses[index];\n\t\t\t\tif (!snapshot) {\n\t\t\t\t\tcachedGraphPasses[index] = {\n\t\t\t\t\t\tpass,\n\t\t\t\t\t\tenabled: pass.enabled,\n\t\t\t\t\t\tneedsSwap: pass.needsSwap,\n\t\t\t\t\t\tinput: pass.input,\n\t\t\t\t\t\toutput: pass.output,\n\t\t\t\t\t\tclear: pass.clear,\n\t\t\t\t\t\tpreserve: pass.preserve,\n\t\t\t\t\t\thasClearColor: hasPassClearColor,\n\t\t\t\t\t\tclearColor0: passClearColor?.[0] ?? 0,\n\t\t\t\t\t\tclearColor1: passClearColor?.[1] ?? 0,\n\t\t\t\t\t\tclearColor2: passClearColor?.[2] ?? 0,\n\t\t\t\t\t\tclearColor3: passClearColor?.[3] ?? 0\n\t\t\t\t\t};\n\t\t\t\t\tindex += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tsnapshot.pass = pass;\n\t\t\t\tsnapshot.enabled = pass.enabled;\n\t\t\t\tsnapshot.needsSwap = pass.needsSwap;\n\t\t\t\tsnapshot.input = pass.input;\n\t\t\t\tsnapshot.output = pass.output;\n\t\t\t\tsnapshot.clear = pass.clear;\n\t\t\t\tsnapshot.preserve = pass.preserve;\n\t\t\t\tsnapshot.hasClearColor = hasPassClearColor;\n\t\t\t\tsnapshot.clearColor0 = passClearColor?.[0] ?? 0;\n\t\t\t\tsnapshot.clearColor1 = passClearColor?.[1] ?? 0;\n\t\t\t\tsnapshot.clearColor2 = passClearColor?.[2] ?? 0;\n\t\t\t\tsnapshot.clearColor3 = passClearColor?.[3] ?? 0;\n\t\t\t\tindex += 1;\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Synchronizes pass lifecycle callbacks and resize notifications.\n\t\t */\n\t\tconst syncPassLifecycle = (passes: RenderPass[], width: number, height: number): void => {\n\t\t\tconst resized = passWidth !== width || passHeight !== height;\n\t\t\tif (!resized && lifecyclePassesRef === passes && passes.length === activePasses.length) {\n\t\t\t\tlet isSameOrder = true;\n\t\t\t\tfor (let index = 0; index < passes.length; index += 1) {\n\t\t\t\t\tif (activePasses[index] !== passes[index]) {\n\t\t\t\t\t\tisSameOrder = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isSameOrder) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlifecycleNextSet.clear();\n\t\t\tlifecycleUniquePasses.length = 0;\n\t\t\tfor (const pass of passes) {\n\t\t\t\tif (lifecycleNextSet.has(pass)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlifecycleNextSet.add(pass);\n\t\t\t\tlifecycleUniquePasses.push(pass);\n\t\t\t}\n\t\t\tlifecyclePreviousSet.clear();\n\t\t\tfor (const pass of activePasses) {\n\t\t\t\tlifecyclePreviousSet.add(pass);\n\t\t\t}\n\n\t\t\tfor (const pass of activePasses) {\n\t\t\t\tif (!lifecycleNextSet.has(pass)) {\n\t\t\t\t\tpass.dispose?.();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const pass of lifecycleUniquePasses) {\n\t\t\t\tif (resized || !lifecyclePreviousSet.has(pass)) {\n\t\t\t\t\tpass.setSize?.(width, height);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tactivePasses.length = 0;\n\t\t\tfor (const pass of lifecycleUniquePasses) {\n\t\t\t\tactivePasses.push(pass);\n\t\t\t}\n\t\t\tlifecyclePassesRef = passes;\n\t\t\tpassWidth = width;\n\t\t\tpassHeight = height;\n\t\t};\n\n\t\t/**\n\t\t * Ensures internal ping-pong slot texture matches current canvas size/format.\n\t\t */\n\t\tconst ensureSlotTarget = (\n\t\t\tslot: RenderPassInputSlot,\n\t\t\twidth: number,\n\t\t\theight: number\n\t\t): RuntimeRenderTarget => {\n\t\t\tconst current = slot === 'source' ? sourceSlotTarget : targetSlotTarget;\n\t\t\tif (\n\t\t\t\tcurrent &&\n\t\t\t\tcurrent.width === width &&\n\t\t\t\tcurrent.height === height &&\n\t\t\t\tcurrent.format === format\n\t\t\t) {\n\t\t\t\treturn current;\n\t\t\t}\n\n\t\t\tdestroyRenderTexture(current);\n\t\t\tconst next = createRenderTexture(device, width, height, format);\n\t\t\tif (slot === 'source') {\n\t\t\t\tsourceSlotTarget = next;\n\t\t\t} else {\n\t\t\t\ttargetSlotTarget = next;\n\t\t\t}\n\n\t\t\treturn next;\n\t\t};\n\n\t\t/**\n\t\t * Creates/updates runtime render targets and returns immutable pass snapshot.\n\t\t */\n\t\tconst syncRenderTargets = (\n\t\t\tcanvasWidth: number,\n\t\t\tcanvasHeight: number\n\t\t): Readonly<Record<string, RenderTarget>> => {\n\t\t\tconst resolvedDefinitions = resolveRenderTargetDefinitions(\n\t\t\t\tresolveRenderTargets(),\n\t\t\t\tcanvasWidth,\n\t\t\t\tcanvasHeight,\n\t\t\t\tformat\n\t\t\t);\n\t\t\tconst nextSignature = buildRenderTargetSignature(resolvedDefinitions);\n\n\t\t\tif (nextSignature !== renderTargetSignature) {\n\t\t\t\tconst activeKeys = new Set(resolvedDefinitions.map((definition) => definition.key));\n\n\t\t\t\tfor (const [key, target] of runtimeRenderTargets.entries()) {\n\t\t\t\t\tif (!activeKeys.has(key)) {\n\t\t\t\t\t\ttarget.texture.destroy();\n\t\t\t\t\t\truntimeRenderTargets.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const definition of resolvedDefinitions) {\n\t\t\t\t\tconst current = runtimeRenderTargets.get(definition.key);\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrent &&\n\t\t\t\t\t\tcurrent.width === definition.width &&\n\t\t\t\t\t\tcurrent.height === definition.height &&\n\t\t\t\t\t\tcurrent.format === definition.format\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrent?.texture.destroy();\n\t\t\t\t\truntimeRenderTargets.set(\n\t\t\t\t\t\tdefinition.key,\n\t\t\t\t\t\tcreateRenderTexture(device, definition.width, definition.height, definition.format)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\trenderTargetSignature = nextSignature;\n\t\t\t\tconst nextSnapshot: Record<string, RenderTarget> = {};\n\t\t\t\tconst nextKeys: string[] = [];\n\t\t\t\tfor (const definition of resolvedDefinitions) {\n\t\t\t\t\tconst target = runtimeRenderTargets.get(definition.key);\n\t\t\t\t\tif (!target) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tnextKeys.push(definition.key);\n\t\t\t\t\tnextSnapshot[definition.key] = {\n\t\t\t\t\t\ttexture: target.texture,\n\t\t\t\t\t\tview: target.view,\n\t\t\t\t\t\twidth: target.width,\n\t\t\t\t\t\theight: target.height,\n\t\t\t\t\t\tformat: target.format\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\trenderTargetSnapshot = nextSnapshot;\n\t\t\t\trenderTargetKeys = nextKeys;\n\t\t\t}\n\n\t\t\treturn renderTargetSnapshot;\n\t\t};\n\n\t\t/**\n\t\t * Blits a texture view to the current canvas texture.\n\t\t */\n\t\tconst blitToCanvas = (\n\t\t\tcommandEncoder: GPUCommandEncoder,\n\t\t\tsourceView: GPUTextureView,\n\t\t\tcanvasView: GPUTextureView,\n\t\t\tclearColor: [number, number, number, number]\n\t\t): void => {\n\t\t\tlet bindGroup = blitBindGroupByView.get(sourceView);\n\t\t\tif (!bindGroup) {\n\t\t\t\tbindGroup = device.createBindGroup({\n\t\t\t\t\tlayout: blitBindGroupLayout,\n\t\t\t\t\tentries: [\n\t\t\t\t\t\t{ binding: 0, resource: blitSampler },\n\t\t\t\t\t\t{ binding: 1, resource: sourceView }\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t\tblitBindGroupByView.set(sourceView, bindGroup);\n\t\t\t}\n\n\t\t\tconst pass = commandEncoder.beginRenderPass({\n\t\t\t\tcolorAttachments: [\n\t\t\t\t\t{\n\t\t\t\t\t\tview: canvasView,\n\t\t\t\t\t\tclearValue: {\n\t\t\t\t\t\t\tr: clearColor[0],\n\t\t\t\t\t\t\tg: clearColor[1],\n\t\t\t\t\t\t\tb: clearColor[2],\n\t\t\t\t\t\t\ta: clearColor[3]\n\t\t\t\t\t\t},\n\t\t\t\t\t\tloadOp: 'clear',\n\t\t\t\t\t\tstoreOp: 'store'\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t});\n\n\t\t\tpass.setPipeline(blitPipeline);\n\t\t\tpass.setBindGroup(0, bindGroup);\n\t\t\tpass.draw(3);\n\t\t\tpass.end();\n\t\t};\n\n\t\t/**\n\t\t * Executes a full frame render.\n\t\t */\n\t\tconst render: Renderer['render'] = ({\n\t\t\ttime,\n\t\t\tdelta,\n\t\t\trenderMode,\n\t\t\tuniforms,\n\t\t\ttextures,\n\t\t\tcanvasSize\n\t\t}) => {\n\t\t\tif (deviceLostMessage) {\n\t\t\t\tthrow new Error(deviceLostMessage);\n\t\t\t}\n\n\t\t\tif (uncapturedErrorMessage) {\n\t\t\t\tconst message = uncapturedErrorMessage;\n\t\t\t\tuncapturedErrorMessage = null;\n\t\t\t\tthrow new Error(message);\n\t\t\t}\n\n\t\t\tconst { width, height } = resizeCanvas(options.canvas, options.getDpr(), canvasSize);\n\n\t\t\tif (!contextConfigured || configuredWidth !== width || configuredHeight !== height) {\n\t\t\t\tcontext.configure({\n\t\t\t\t\tdevice,\n\t\t\t\t\tformat,\n\t\t\t\t\talphaMode: 'premultiplied'\n\t\t\t\t});\n\t\t\t\tcontextConfigured = true;\n\t\t\t\tconfiguredWidth = width;\n\t\t\t\tconfiguredHeight = height;\n\t\t\t}\n\n\t\t\tframeScratch[0] = time;\n\t\t\tframeScratch[1] = delta;\n\t\t\tframeScratch[2] = width;\n\t\t\tframeScratch[3] = height;\n\t\t\tdevice.queue.writeBuffer(\n\t\t\t\tframeBuffer,\n\t\t\t\t0,\n\t\t\t\tframeScratch.buffer as ArrayBuffer,\n\t\t\t\tframeScratch.byteOffset,\n\t\t\t\tframeScratch.byteLength\n\t\t\t);\n\n\t\t\tpackUniformsInto(uniforms, options.uniformLayout, uniformScratch);\n\t\t\tif (!hasUniformSnapshot) {\n\t\t\t\tdevice.queue.writeBuffer(\n\t\t\t\t\tuniformBuffer,\n\t\t\t\t\t0,\n\t\t\t\t\tuniformScratch.buffer as ArrayBuffer,\n\t\t\t\t\tuniformScratch.byteOffset,\n\t\t\t\t\tuniformScratch.byteLength\n\t\t\t\t);\n\t\t\t\tuniformPrevious.set(uniformScratch);\n\t\t\t\thasUniformSnapshot = true;\n\t\t\t} else {\n\t\t\t\tconst dirtyRanges = findDirtyFloatRanges(uniformPrevious, uniformScratch);\n\t\t\t\tfor (const range of dirtyRanges) {\n\t\t\t\t\tconst byteOffset = range.start * 4;\n\t\t\t\t\tconst byteLength = range.count * 4;\n\t\t\t\t\tdevice.queue.writeBuffer(\n\t\t\t\t\t\tuniformBuffer,\n\t\t\t\t\t\tbyteOffset,\n\t\t\t\t\t\tuniformScratch.buffer as ArrayBuffer,\n\t\t\t\t\t\tuniformScratch.byteOffset + byteOffset,\n\t\t\t\t\t\tbyteLength\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (dirtyRanges.length > 0) {\n\t\t\t\t\tuniformPrevious.set(uniformScratch);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet bindGroupDirty = false;\n\t\t\tfor (const binding of textureBindings) {\n\t\t\t\tconst nextTexture =\n\t\t\t\t\ttextures[binding.key] ?? normalizedTextureDefinitions[binding.key]?.source ?? null;\n\t\t\t\tif (updateTextureBinding(binding, nextTexture, renderMode)) {\n\t\t\t\t\tbindGroupDirty = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bindGroupDirty) {\n\t\t\t\tbindGroup = createBindGroup();\n\t\t\t}\n\n\t\t\tconst commandEncoder = device.createCommandEncoder();\n\t\t\tconst passes = resolvePasses();\n\t\t\tconst clearColor = options.getClearColor();\n\t\t\tsyncPassLifecycle(passes, width, height);\n\t\t\tconst runtimeTargets = syncRenderTargets(width, height);\n\t\t\tconst graphPlan = isGraphPlanCacheValid(passes, clearColor)\n\t\t\t\t? cachedGraphPlan!\n\t\t\t\t: (() => {\n\t\t\t\t\t\tconst nextPlan = planRenderGraph(passes, clearColor, renderTargetKeys);\n\t\t\t\t\t\tupdateGraphPlanCache(passes, clearColor, nextPlan);\n\t\t\t\t\t\treturn nextPlan;\n\t\t\t\t\t})();\n\t\t\tconst canvasTexture = context.getCurrentTexture();\n\t\t\tconst canvasSurface: RenderTarget = {\n\t\t\t\ttexture: canvasTexture,\n\t\t\t\tview: canvasTexture.createView(),\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tformat\n\t\t\t};\n\t\t\tconst slots =\n\t\t\t\tgraphPlan.steps.length > 0\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tsource: ensureSlotTarget('source', width, height),\n\t\t\t\t\t\t\ttarget: ensureSlotTarget('target', width, height),\n\t\t\t\t\t\t\tcanvas: canvasSurface\n\t\t\t\t\t\t}\n\t\t\t\t\t: null;\n\t\t\tconst sceneOutput = slots ? slots.source : canvasSurface;\n\n\t\t\tconst scenePass = commandEncoder.beginRenderPass({\n\t\t\t\tcolorAttachments: [\n\t\t\t\t\t{\n\t\t\t\t\t\tview: sceneOutput.view,\n\t\t\t\t\t\tclearValue: {\n\t\t\t\t\t\t\tr: clearColor[0],\n\t\t\t\t\t\t\tg: clearColor[1],\n\t\t\t\t\t\t\tb: clearColor[2],\n\t\t\t\t\t\t\ta: clearColor[3]\n\t\t\t\t\t\t},\n\t\t\t\t\t\tloadOp: 'clear',\n\t\t\t\t\t\tstoreOp: 'store'\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t});\n\n\t\t\tscenePass.setPipeline(pipeline);\n\t\t\tscenePass.setBindGroup(0, bindGroup);\n\t\t\tscenePass.draw(3);\n\t\t\tscenePass.end();\n\n\t\t\tif (slots) {\n\t\t\t\tconst resolveStepSurface = (\n\t\t\t\t\tslot: RenderPassInputSlot | RenderPassOutputSlot\n\t\t\t\t): RenderTarget => {\n\t\t\t\t\tif (slot === 'source') {\n\t\t\t\t\t\treturn slots.source;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (slot === 'target') {\n\t\t\t\t\t\treturn slots.target;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (slot === 'canvas') {\n\t\t\t\t\t\treturn slots.canvas;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst named = runtimeTargets[slot];\n\t\t\t\t\tif (!named) {\n\t\t\t\t\t\tthrow new Error(`Render graph references unknown runtime target \"${slot}\".`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn named;\n\t\t\t\t};\n\n\t\t\t\tfor (const step of graphPlan.steps) {\n\t\t\t\t\tconst input = resolveStepSurface(step.input);\n\t\t\t\t\tconst output = resolveStepSurface(step.output);\n\n\t\t\t\t\tstep.pass.render({\n\t\t\t\t\t\tdevice,\n\t\t\t\t\t\tcommandEncoder,\n\t\t\t\t\t\tsource: slots.source,\n\t\t\t\t\t\ttarget: slots.target,\n\t\t\t\t\t\tcanvas: slots.canvas,\n\t\t\t\t\t\tinput,\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\ttargets: runtimeTargets,\n\t\t\t\t\t\ttime,\n\t\t\t\t\t\tdelta,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\theight,\n\t\t\t\t\t\tclear: step.clear,\n\t\t\t\t\t\tclearColor: step.clearColor,\n\t\t\t\t\t\tpreserve: step.preserve,\n\t\t\t\t\t\tbeginRenderPass: (passOptions) => {\n\t\t\t\t\t\t\tconst clear = passOptions?.clear ?? step.clear;\n\t\t\t\t\t\t\tconst clearColor = passOptions?.clearColor ?? step.clearColor;\n\t\t\t\t\t\t\tconst preserve = passOptions?.preserve ?? step.preserve;\n\n\t\t\t\t\t\t\treturn commandEncoder.beginRenderPass({\n\t\t\t\t\t\t\t\tcolorAttachments: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tview: passOptions?.view ?? output.view,\n\t\t\t\t\t\t\t\t\t\tclearValue: {\n\t\t\t\t\t\t\t\t\t\t\tr: clearColor[0],\n\t\t\t\t\t\t\t\t\t\t\tg: clearColor[1],\n\t\t\t\t\t\t\t\t\t\t\tb: clearColor[2],\n\t\t\t\t\t\t\t\t\t\t\ta: clearColor[3]\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tloadOp: clear ? 'clear' : 'load',\n\t\t\t\t\t\t\t\t\t\tstoreOp: preserve ? 'store' : 'discard'\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif (step.needsSwap) {\n\t\t\t\t\t\tconst previousSource = slots.source;\n\t\t\t\t\t\tslots.source = slots.target;\n\t\t\t\t\t\tslots.target = previousSource;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (graphPlan.finalOutput !== 'canvas') {\n\t\t\t\t\tconst finalSurface = resolveStepSurface(graphPlan.finalOutput);\n\t\t\t\t\tblitToCanvas(commandEncoder, finalSurface.view, slots.canvas.view, clearColor);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdevice.queue.submit([commandEncoder.finish()]);\n\t\t};\n\n\t\tacceptInitializationCleanups = false;\n\t\tinitializationCleanups.length = 0;\n\t\treturn {\n\t\t\trender,\n\t\t\tdestroy: () => {\n\t\t\t\tisDestroyed = true;\n\t\t\t\tdevice.removeEventListener('uncapturederror', handleUncapturedError);\n\t\t\t\tframeBuffer.destroy();\n\t\t\t\tuniformBuffer.destroy();\n\t\t\t\tdestroyRenderTexture(sourceSlotTarget);\n\t\t\t\tdestroyRenderTexture(targetSlotTarget);\n\t\t\t\tfor (const target of runtimeRenderTargets.values()) {\n\t\t\t\t\ttarget.texture.destroy();\n\t\t\t\t}\n\t\t\t\truntimeRenderTargets.clear();\n\t\t\t\tfor (const pass of activePasses) {\n\t\t\t\t\tpass.dispose?.();\n\t\t\t\t}\n\t\t\t\tactivePasses.length = 0;\n\t\t\t\tlifecyclePassesRef = null;\n\t\t\t\tfor (const binding of textureBindings) {\n\t\t\t\t\tbinding.texture?.destroy();\n\t\t\t\t\tbinding.fallbackTexture.destroy();\n\t\t\t\t}\n\t\t\t\tblitBindGroupByView = new WeakMap();\n\t\t\t\tcachedGraphPlan = null;\n\t\t\t\tcachedGraphPasses.length = 0;\n\t\t\t\trenderTargetSnapshot = {};\n\t\t\t\trenderTargetKeys = [];\n\t\t\t}\n\t\t};\n\t} catch (error) {\n\t\tisDestroyed = true;\n\t\tacceptInitializationCleanups = false;\n\t\tdevice.removeEventListener('uncapturederror', handleUncapturedError);\n\t\trunInitializationCleanups();\n\t\tthrow error;\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderer.js","names":[],"sources":["../../src/lib/core/renderer.ts"],"sourcesContent":["import { buildRenderTargetSignature, resolveRenderTargetDefinitions } from './render-targets.js';\nimport { planRenderGraph, type RenderGraphPlan } from './render-graph.js';\nimport {\n\tbuildShaderSourceWithMap,\n\tformatShaderSourceLocation,\n\ttype ShaderLineMap\n} from './shader.js';\nimport {\n\tattachShaderCompilationDiagnostics,\n\ttype ShaderCompilationRuntimeContext\n} from './error-diagnostics.js';\nimport {\n\tgetTextureMipLevelCount,\n\tnormalizeTextureDefinitions,\n\tresolveTextureUpdateMode,\n\tresolveTextureSize,\n\ttoTextureData\n} from './textures.js';\nimport { packUniformsInto } from './uniforms.js';\nimport {\n\tbuildComputeShaderSource,\n\tbuildPingPongComputeShaderSource,\n\textractWorkgroupSize,\n\tstorageTextureSampleScalarType\n} from './compute-shader.js';\nimport { normalizeStorageBufferDefinition } from './storage-buffers.js';\nimport type {\n\tAnyPass,\n\tRenderPass,\n\tRenderPassInputSlot,\n\tRenderPassOutputSlot,\n\tRenderMode,\n\tRenderTarget,\n\tRenderer,\n\tRendererOptions,\n\tStorageBufferAccess,\n\tStorageBufferType,\n\tTextureSource,\n\tTextureUpdateMode,\n\tTextureValue\n} from './types.js';\n\n/**\n * Binding index for frame uniforms (`time`, `delta`, `resolution`).\n */\nconst FRAME_BINDING = 0;\n\n/**\n * Binding index for material uniform buffer.\n */\nconst UNIFORM_BINDING = 1;\n\n/**\n * First binding index used for texture sampler/texture pairs.\n */\nconst FIRST_TEXTURE_BINDING = 2;\n\n/**\n * Runtime texture binding state associated with a single texture key.\n */\ninterface RuntimeTextureBinding {\n\tkey: string;\n\tsamplerBinding: number;\n\ttextureBinding: number;\n\tsampler: GPUSampler;\n\tfallbackTexture: GPUTexture;\n\tfallbackView: GPUTextureView;\n\ttexture: GPUTexture | null;\n\tview: GPUTextureView;\n\tsource: TextureSource | null;\n\twidth: number | undefined;\n\theight: number | undefined;\n\tmipLevelCount: number;\n\tformat: GPUTextureFormat;\n\tcolorSpace: 'srgb' | 'linear';\n\tdefaultColorSpace: 'srgb' | 'linear';\n\tflipY: boolean;\n\tdefaultFlipY: boolean;\n\tgenerateMipmaps: boolean;\n\tdefaultGenerateMipmaps: boolean;\n\tpremultipliedAlpha: boolean;\n\tdefaultPremultipliedAlpha: boolean;\n\tupdate: TextureUpdateMode;\n\tdefaultUpdate?: TextureUpdateMode;\n\tlastToken: TextureValue;\n}\n\n/**\n * Runtime render target allocation metadata.\n */\ninterface RuntimeRenderTarget {\n\ttexture: GPUTexture;\n\tview: GPUTextureView;\n\twidth: number;\n\theight: number;\n\tformat: GPUTextureFormat;\n}\n\n/**\n * Runtime ping-pong storage textures for a single logical target key.\n */\ninterface PingPongTexturePair {\n\ttarget: string;\n\tformat: GPUTextureFormat;\n\twidth: number;\n\theight: number;\n\ttextureA: GPUTexture;\n\tviewA: GPUTextureView;\n\ttextureB: GPUTexture;\n\tviewB: GPUTextureView;\n\tbindGroupLayout: GPUBindGroupLayout;\n}\n\n/**\n * Cached pass properties used to validate render-graph cache correctness.\n */\ninterface RenderGraphPassSnapshot {\n\tpass: AnyPass;\n\tenabled: RenderPass['enabled'];\n\tneedsSwap: RenderPass['needsSwap'];\n\tinput: RenderPass['input'];\n\toutput: RenderPass['output'];\n\tclear: RenderPass['clear'];\n\tpreserve: RenderPass['preserve'];\n\thasClearColor: boolean;\n\tclearColor0: number;\n\tclearColor1: number;\n\tclearColor2: number;\n\tclearColor3: number;\n}\n\n/**\n * Returns sampler/texture binding slots for a texture index.\n */\nfunction getTextureBindings(index: number): {\n\tsamplerBinding: number;\n\ttextureBinding: number;\n} {\n\tconst samplerBinding = FIRST_TEXTURE_BINDING + index * 2;\n\treturn {\n\t\tsamplerBinding,\n\t\ttextureBinding: samplerBinding + 1\n\t};\n}\n\n/**\n * Maps WGSL scalar texture type to WebGPU sampled texture bind-group sample type.\n */\nfunction toGpuTextureSampleType(type: 'f32' | 'u32' | 'i32'): GPUTextureSampleType {\n\tif (type === 'u32') {\n\t\treturn 'uint';\n\t}\n\tif (type === 'i32') {\n\t\treturn 'sint';\n\t}\n\treturn 'float';\n}\n\n/**\n * Resizes canvas backing store to match client size and DPR.\n */\nfunction resizeCanvas(\n\tcanvas: HTMLCanvasElement,\n\tdprInput: number,\n\tcssSize?: { width: number; height: number }\n): { width: number; height: number } {\n\tconst dpr = Number.isFinite(dprInput) && dprInput > 0 ? dprInput : 1;\n\tconst rect = cssSize ? null : canvas.getBoundingClientRect();\n\tconst cssWidth = Math.max(0, cssSize?.width ?? rect?.width ?? 0);\n\tconst cssHeight = Math.max(0, cssSize?.height ?? rect?.height ?? 0);\n\tconst width = Math.max(1, Math.floor((cssWidth || 1) * dpr));\n\tconst height = Math.max(1, Math.floor((cssHeight || 1) * dpr));\n\n\tif (canvas.width !== width || canvas.height !== height) {\n\t\tcanvas.width = width;\n\t\tcanvas.height = height;\n\t}\n\n\treturn { width, height };\n}\n\n/**\n * Throws when a shader module contains WGSL compilation errors.\n */\nasync function assertCompilation(\n\tmodule: GPUShaderModule,\n\toptions?: {\n\t\tlineMap?: ShaderLineMap;\n\t\tfragmentSource?: string;\n\t\tincludeSources?: Record<string, string>;\n\t\tdefineBlockSource?: string;\n\t\tmaterialSource?: {\n\t\t\tcomponent?: string;\n\t\t\tfile?: string;\n\t\t\tline?: number;\n\t\t\tcolumn?: number;\n\t\t\tfunctionName?: string;\n\t\t} | null;\n\t\truntimeContext?: ShaderCompilationRuntimeContext;\n\t}\n): Promise<void> {\n\tconst info = await module.getCompilationInfo();\n\tconst errors = info.messages.filter((message: GPUCompilationMessage) => message.type === 'error');\n\n\tif (errors.length === 0) {\n\t\treturn;\n\t}\n\n\tconst diagnostics = errors.map((message: GPUCompilationMessage) => ({\n\t\tgeneratedLine: message.lineNum,\n\t\tmessage: message.message,\n\t\tlinePos: message.linePos,\n\t\tlineLength: message.length,\n\t\tsourceLocation: options?.lineMap?.[message.lineNum] ?? null\n\t}));\n\n\tconst summary = diagnostics\n\t\t.map((diagnostic) => {\n\t\t\tconst sourceLabel = formatShaderSourceLocation(diagnostic.sourceLocation);\n\t\t\tconst generatedLineLabel =\n\t\t\t\tdiagnostic.generatedLine > 0 ? `generated WGSL line ${diagnostic.generatedLine}` : null;\n\t\t\tconst contextLabel = [sourceLabel, generatedLineLabel].filter((value) => Boolean(value));\n\t\t\tif (contextLabel.length === 0) {\n\t\t\t\treturn diagnostic.message;\n\t\t\t}\n\n\t\t\treturn `[${contextLabel.join(' | ')}] ${diagnostic.message}`;\n\t\t})\n\t\t.join('\\n');\n\tconst error = new Error(`WGSL compilation failed:\\n${summary}`);\n\tthrow attachShaderCompilationDiagnostics(error, {\n\t\tkind: 'shader-compilation',\n\t\tdiagnostics,\n\t\tfragmentSource: options?.fragmentSource ?? '',\n\t\tincludeSources: options?.includeSources ?? {},\n\t\t...(options?.defineBlockSource !== undefined\n\t\t\t? { defineBlockSource: options.defineBlockSource }\n\t\t\t: {}),\n\t\tmaterialSource: options?.materialSource ?? null,\n\t\t...(options?.runtimeContext !== undefined ? { runtimeContext: options.runtimeContext } : {})\n\t});\n}\n\nfunction toSortedUniqueStrings(values: string[]): string[] {\n\treturn Array.from(new Set(values)).sort((a, b) => a.localeCompare(b));\n}\n\nfunction buildPassGraphSnapshot(\n\tpasses: AnyPass[] | undefined\n): NonNullable<ShaderCompilationRuntimeContext['passGraph']> {\n\tconst declaredPasses = passes ?? [];\n\tlet enabledPassCount = 0;\n\tconst inputs: string[] = [];\n\tconst outputs: string[] = [];\n\n\tfor (const pass of declaredPasses) {\n\t\tif (pass.enabled === false) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tenabledPassCount += 1;\n\t\tif ('isCompute' in pass && (pass as { isCompute?: boolean }).isCompute === true) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst rp = pass as RenderPass;\n\t\tconst needsSwap = rp.needsSwap ?? true;\n\t\tconst input = rp.input ?? 'source';\n\t\tconst output = rp.output ?? (needsSwap ? 'target' : 'source');\n\t\tinputs.push(input);\n\t\toutputs.push(output);\n\t}\n\n\treturn {\n\t\tpassCount: declaredPasses.length,\n\t\tenabledPassCount,\n\t\tinputs: toSortedUniqueStrings(inputs),\n\t\toutputs: toSortedUniqueStrings(outputs)\n\t};\n}\n\nfunction buildShaderCompilationRuntimeContext(\n\toptions: RendererOptions\n): ShaderCompilationRuntimeContext {\n\tconst passList = options.getPasses?.() ?? options.passes;\n\tconst renderTargetMap = options.getRenderTargets?.() ?? options.renderTargets;\n\n\treturn {\n\t\t...(options.materialSignature ? { materialSignature: options.materialSignature } : {}),\n\t\tpassGraph: buildPassGraphSnapshot(passList),\n\t\tactiveRenderTargets: Object.keys(renderTargetMap ?? {}).sort((a, b) => a.localeCompare(b))\n\t};\n}\n\n/**\n * Creates a 1x1 white fallback texture used before user textures become available.\n */\nfunction createFallbackTexture(device: GPUDevice, format: GPUTextureFormat): GPUTexture {\n\tconst texture = device.createTexture({\n\t\tsize: { width: 1, height: 1, depthOrArrayLayers: 1 },\n\t\tformat,\n\t\tusage:\n\t\t\tGPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT\n\t});\n\n\tconst pixel = new Uint8Array([255, 255, 255, 255]);\n\tdevice.queue.writeTexture(\n\t\t{ texture },\n\t\tpixel,\n\t\t{ offset: 0, bytesPerRow: 4, rowsPerImage: 1 },\n\t\t{ width: 1, height: 1, depthOrArrayLayers: 1 }\n\t);\n\n\treturn texture;\n}\n\n/**\n * Creates an offscreen canvas used for CPU mipmap generation.\n */\nfunction createMipmapCanvas(width: number, height: number): OffscreenCanvas | HTMLCanvasElement {\n\tif (typeof OffscreenCanvas !== 'undefined') {\n\t\treturn new OffscreenCanvas(width, height);\n\t}\n\n\tconst canvas = document.createElement('canvas');\n\tcanvas.width = width;\n\tcanvas.height = height;\n\treturn canvas;\n}\n\n/**\n * Creates typed descriptor for `copyExternalImageToTexture`.\n */\nfunction createExternalCopySource(\n\tsource: CanvasImageSource,\n\toptions: { flipY?: boolean; premultipliedAlpha?: boolean }\n): GPUCopyExternalImageSourceInfo {\n\tconst descriptor = {\n\t\tsource,\n\t\t...(options.flipY ? { flipY: true } : {}),\n\t\t...(options.premultipliedAlpha ? { premultipliedAlpha: true } : {})\n\t};\n\n\treturn descriptor as GPUCopyExternalImageSourceInfo;\n}\n\n/**\n * Uploads source content to a GPU texture and optionally generates mip chain on CPU.\n */\nfunction uploadTexture(\n\tdevice: GPUDevice,\n\ttexture: GPUTexture,\n\tbinding: Pick<RuntimeTextureBinding, 'flipY' | 'premultipliedAlpha' | 'generateMipmaps'>,\n\tsource: TextureSource,\n\twidth: number,\n\theight: number,\n\tmipLevelCount: number\n): void {\n\tdevice.queue.copyExternalImageToTexture(\n\t\tcreateExternalCopySource(source, {\n\t\t\tflipY: binding.flipY,\n\t\t\tpremultipliedAlpha: binding.premultipliedAlpha\n\t\t}),\n\t\t{ texture, mipLevel: 0 },\n\t\t{ width, height, depthOrArrayLayers: 1 }\n\t);\n\n\tif (!binding.generateMipmaps || mipLevelCount <= 1) {\n\t\treturn;\n\t}\n\n\tlet previousSource: CanvasImageSource = source;\n\tlet previousWidth = width;\n\tlet previousHeight = height;\n\n\tfor (let level = 1; level < mipLevelCount; level += 1) {\n\t\tconst nextWidth = Math.max(1, Math.floor(previousWidth / 2));\n\t\tconst nextHeight = Math.max(1, Math.floor(previousHeight / 2));\n\t\tconst canvas = createMipmapCanvas(nextWidth, nextHeight);\n\t\tconst context = canvas.getContext('2d');\n\t\tif (!context) {\n\t\t\tthrow new Error('Unable to create 2D context for mipmap generation');\n\t\t}\n\n\t\tcontext.drawImage(\n\t\t\tpreviousSource,\n\t\t\t0,\n\t\t\t0,\n\t\t\tpreviousWidth,\n\t\t\tpreviousHeight,\n\t\t\t0,\n\t\t\t0,\n\t\t\tnextWidth,\n\t\t\tnextHeight\n\t\t);\n\n\t\tdevice.queue.copyExternalImageToTexture(\n\t\t\tcreateExternalCopySource(canvas, {\n\t\t\t\tpremultipliedAlpha: binding.premultipliedAlpha\n\t\t\t}),\n\t\t\t{ texture, mipLevel: level },\n\t\t\t{ width: nextWidth, height: nextHeight, depthOrArrayLayers: 1 }\n\t\t);\n\n\t\tpreviousSource = canvas;\n\t\tpreviousWidth = nextWidth;\n\t\tpreviousHeight = nextHeight;\n\t}\n}\n\n/**\n * Creates bind group layout entries for frame/uniform buffers plus texture bindings.\n */\nfunction createBindGroupLayoutEntries(\n\ttextureBindings: RuntimeTextureBinding[]\n): GPUBindGroupLayoutEntry[] {\n\tconst entries: GPUBindGroupLayoutEntry[] = [\n\t\t{\n\t\t\tbinding: FRAME_BINDING,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\tbuffer: { type: 'uniform', minBindingSize: 16 }\n\t\t},\n\t\t{\n\t\t\tbinding: UNIFORM_BINDING,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\tbuffer: { type: 'uniform' }\n\t\t}\n\t];\n\n\tfor (const binding of textureBindings) {\n\t\tentries.push({\n\t\t\tbinding: binding.samplerBinding,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\tsampler: { type: 'filtering' }\n\t\t});\n\n\t\tentries.push({\n\t\t\tbinding: binding.textureBinding,\n\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\ttexture: {\n\t\t\t\tsampleType: 'float',\n\t\t\t\tviewDimension: '2d',\n\t\t\t\tmultisampled: false\n\t\t\t}\n\t\t});\n\t}\n\n\treturn entries;\n}\n\n/**\n * Maximum gap (in floats) between two dirty ranges that triggers merge.\n *\n * Set to 4 (16 bytes) which covers one vec4f alignment slot.\n */\nconst DIRTY_RANGE_MERGE_GAP = 4;\n\n/**\n * Computes dirty float ranges between two uniform snapshots.\n *\n * Adjacent dirty ranges separated by a gap smaller than or equal to\n * {@link DIRTY_RANGE_MERGE_GAP} are merged to reduce `writeBuffer` calls.\n */\nexport function findDirtyFloatRanges(\n\tprevious: Float32Array,\n\tnext: Float32Array,\n\tmergeGapThreshold = DIRTY_RANGE_MERGE_GAP\n): Array<{ start: number; count: number }> {\n\tconst ranges: Array<{ start: number; count: number }> = [];\n\tlet start = -1;\n\n\tfor (let index = 0; index < next.length; index += 1) {\n\t\tif (previous[index] !== next[index]) {\n\t\t\tif (start === -1) {\n\t\t\t\tstart = index;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (start !== -1) {\n\t\t\tranges.push({ start, count: index - start });\n\t\t\tstart = -1;\n\t\t}\n\t}\n\n\tif (start !== -1) {\n\t\tranges.push({ start, count: next.length - start });\n\t}\n\n\tif (ranges.length <= 1) {\n\t\treturn ranges;\n\t}\n\n\tconst merged: Array<{ start: number; count: number }> = [ranges[0]!];\n\tfor (let index = 1; index < ranges.length; index += 1) {\n\t\tconst prev = merged[merged.length - 1]!;\n\t\tconst curr = ranges[index]!;\n\t\tconst gap = curr.start - (prev.start + prev.count);\n\n\t\tif (gap <= mergeGapThreshold) {\n\t\t\tprev.count = curr.start + curr.count - prev.start;\n\t\t} else {\n\t\t\tmerged.push(curr);\n\t\t}\n\t}\n\n\treturn merged;\n}\n\n/**\n * Determines whether shader output should perform linear-to-sRGB conversion.\n */\nfunction shouldConvertLinearToSrgb(\n\toutputColorSpace: 'srgb' | 'linear',\n\tcanvasFormat: GPUTextureFormat\n): boolean {\n\tif (outputColorSpace !== 'srgb') {\n\t\treturn false;\n\t}\n\n\treturn !canvasFormat.endsWith('-srgb');\n}\n\n/**\n * WGSL shader used to blit an offscreen texture to the canvas.\n */\nfunction createFullscreenBlitShader(): string {\n\treturn `\nstruct MotionGPUVertexOut {\n\t@builtin(position) position: vec4f,\n\t@location(0) uv: vec2f,\n};\n\n@group(0) @binding(0) var motiongpuBlitSampler: sampler;\n@group(0) @binding(1) var motiongpuBlitTexture: texture_2d<f32>;\n\n@vertex\nfn motiongpuBlitVertex(@builtin(vertex_index) index: u32) -> MotionGPUVertexOut {\n\tvar positions = array<vec2f, 3>(\n\t\tvec2f(-1.0, -3.0),\n\t\tvec2f(-1.0, 1.0),\n\t\tvec2f(3.0, 1.0)\n\t);\n\n\tlet position = positions[index];\n\tvar out: MotionGPUVertexOut;\n\tout.position = vec4f(position, 0.0, 1.0);\n\tout.uv = (position + vec2f(1.0, 1.0)) * 0.5;\n\treturn out;\n}\n\n@fragment\nfn motiongpuBlitFragment(in: MotionGPUVertexOut) -> @location(0) vec4f {\n\treturn textureSample(motiongpuBlitTexture, motiongpuBlitSampler, in.uv);\n}\n`;\n}\n\n/**\n * Allocates a render target texture with usage flags suitable for passes/blits.\n */\nfunction createRenderTexture(\n\tdevice: GPUDevice,\n\twidth: number,\n\theight: number,\n\tformat: GPUTextureFormat\n): RuntimeRenderTarget {\n\tconst texture = device.createTexture({\n\t\tsize: { width, height, depthOrArrayLayers: 1 },\n\t\tformat,\n\t\tusage:\n\t\t\tGPUTextureUsage.TEXTURE_BINDING |\n\t\t\tGPUTextureUsage.RENDER_ATTACHMENT |\n\t\t\tGPUTextureUsage.COPY_DST |\n\t\t\tGPUTextureUsage.COPY_SRC\n\t});\n\n\treturn {\n\t\ttexture,\n\t\tview: texture.createView(),\n\t\twidth,\n\t\theight,\n\t\tformat\n\t};\n}\n\n/**\n * Destroys a render target texture if present.\n */\nfunction destroyRenderTexture(target: RuntimeRenderTarget | null): void {\n\ttarget?.texture.destroy();\n}\n\n/**\n * Creates the WebGPU renderer used by `FragCanvas`.\n *\n * @param options - Renderer creation options resolved from material/context state.\n * @returns Renderer instance with `render` and `destroy`.\n * @throws {Error} On WebGPU unavailability, shader compilation issues, or runtime setup failures.\n */\nexport async function createRenderer(options: RendererOptions): Promise<Renderer> {\n\tif (!navigator.gpu) {\n\t\tthrow new Error('WebGPU is not available in this browser');\n\t}\n\n\tconst context = options.canvas.getContext('webgpu') as GPUCanvasContext | null;\n\tif (!context) {\n\t\tthrow new Error('Canvas does not support webgpu context');\n\t}\n\n\tconst format = navigator.gpu.getPreferredCanvasFormat();\n\tconst adapter = await navigator.gpu.requestAdapter(options.adapterOptions);\n\tif (!adapter) {\n\t\tthrow new Error('Unable to acquire WebGPU adapter');\n\t}\n\n\tconst device = await adapter.requestDevice(options.deviceDescriptor);\n\tlet isDestroyed = false;\n\tlet deviceLostMessage: string | null = null;\n\tlet uncapturedErrorMessage: string | null = null;\n\tconst initializationCleanups: Array<() => void> = [];\n\tlet acceptInitializationCleanups = true;\n\n\tconst registerInitializationCleanup = (cleanup: () => void): void => {\n\t\tif (!acceptInitializationCleanups) {\n\t\t\treturn;\n\t\t}\n\t\toptions.__onInitializationCleanupRegistered?.();\n\t\tinitializationCleanups.push(cleanup);\n\t};\n\n\tconst runInitializationCleanups = (): void => {\n\t\tfor (let index = initializationCleanups.length - 1; index >= 0; index -= 1) {\n\t\t\ttry {\n\t\t\t\tinitializationCleanups[index]?.();\n\t\t\t} catch {\n\t\t\t\t// Best-effort cleanup on failed renderer initialization.\n\t\t\t}\n\t\t}\n\t\tinitializationCleanups.length = 0;\n\t};\n\n\tvoid device.lost.then((info) => {\n\t\tif (isDestroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst reason = info.reason ? ` (${info.reason})` : '';\n\t\tconst details = info.message?.trim();\n\t\tdeviceLostMessage = details\n\t\t\t? `WebGPU device lost: ${details}${reason}`\n\t\t\t: `WebGPU device lost${reason}`;\n\t});\n\n\tconst handleUncapturedError = (event: GPUUncapturedErrorEvent): void => {\n\t\tif (isDestroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst message =\n\t\t\tevent.error instanceof Error\n\t\t\t\t? event.error.message\n\t\t\t\t: String((event.error as { message?: string })?.message ?? event.error);\n\t\tuncapturedErrorMessage = `WebGPU uncaptured error: ${message}`;\n\t};\n\n\tdevice.addEventListener('uncapturederror', handleUncapturedError);\n\ttry {\n\t\tconst runtimeContext = buildShaderCompilationRuntimeContext(options);\n\t\tconst convertLinearToSrgb = shouldConvertLinearToSrgb(options.outputColorSpace, format);\n\t\tconst builtShader = buildShaderSourceWithMap(\n\t\t\toptions.fragmentWgsl,\n\t\t\toptions.uniformLayout,\n\t\t\toptions.textureKeys,\n\t\t\t{\n\t\t\t\tconvertLinearToSrgb,\n\t\t\t\tfragmentLineMap: options.fragmentLineMap,\n\t\t\t\t...(options.storageBufferKeys !== undefined\n\t\t\t\t\t? { storageBufferKeys: options.storageBufferKeys }\n\t\t\t\t\t: {}),\n\t\t\t\t...(options.storageBufferDefinitions !== undefined\n\t\t\t\t\t? { storageBufferDefinitions: options.storageBufferDefinitions }\n\t\t\t\t\t: {})\n\t\t\t}\n\t\t);\n\t\tconst shaderModule = device.createShaderModule({ code: builtShader.code });\n\t\tawait assertCompilation(shaderModule, {\n\t\t\tlineMap: builtShader.lineMap,\n\t\t\tfragmentSource: options.fragmentSource,\n\t\t\tincludeSources: options.includeSources,\n\t\t\t...(options.defineBlockSource !== undefined\n\t\t\t\t? { defineBlockSource: options.defineBlockSource }\n\t\t\t\t: {}),\n\t\t\tmaterialSource: options.materialSource ?? null,\n\t\t\truntimeContext\n\t\t});\n\n\t\tconst normalizedTextureDefinitions = normalizeTextureDefinitions(\n\t\t\toptions.textureDefinitions,\n\t\t\toptions.textureKeys\n\t\t);\n\t\tconst storageBufferKeys = options.storageBufferKeys ?? [];\n\t\tconst storageBufferDefinitions = options.storageBufferDefinitions ?? {};\n\t\tconst storageTextureKeys = options.storageTextureKeys ?? [];\n\t\tconst storageTextureKeySet = new Set(storageTextureKeys);\n\t\tconst textureBindings = options.textureKeys.map((key, index): RuntimeTextureBinding => {\n\t\t\tconst config = normalizedTextureDefinitions[key];\n\t\t\tif (!config) {\n\t\t\t\tthrow new Error(`Missing texture definition for \"${key}\"`);\n\t\t\t}\n\n\t\t\tconst { samplerBinding, textureBinding } = getTextureBindings(index);\n\t\t\tconst sampler = device.createSampler({\n\t\t\t\tmagFilter: config.filter,\n\t\t\t\tminFilter: config.filter,\n\t\t\t\tmipmapFilter: config.generateMipmaps ? config.filter : 'nearest',\n\t\t\t\taddressModeU: config.addressModeU,\n\t\t\t\taddressModeV: config.addressModeV,\n\t\t\t\tmaxAnisotropy: config.filter === 'linear' ? config.anisotropy : 1\n\t\t\t});\n\t\t\t// Storage textures use a safe fallback format — the fallback is never\n\t\t\t// sampled because storage textures are eagerly allocated with their\n\t\t\t// real format/dimensions. Non-storage textures use their own format.\n\t\t\tconst fallbackFormat = config.storage ? 'rgba8unorm' : config.format;\n\t\t\tconst fallbackTexture = createFallbackTexture(device, fallbackFormat);\n\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\tfallbackTexture.destroy();\n\t\t\t});\n\t\t\tconst fallbackView = fallbackTexture.createView();\n\n\t\t\tconst runtimeBinding: RuntimeTextureBinding = {\n\t\t\t\tkey,\n\t\t\t\tsamplerBinding,\n\t\t\t\ttextureBinding,\n\t\t\t\tsampler,\n\t\t\t\tfallbackTexture,\n\t\t\t\tfallbackView,\n\t\t\t\ttexture: null,\n\t\t\t\tview: fallbackView,\n\t\t\t\tsource: null,\n\t\t\t\twidth: undefined,\n\t\t\t\theight: undefined,\n\t\t\t\tmipLevelCount: 1,\n\t\t\t\tformat: config.format,\n\t\t\t\tcolorSpace: config.colorSpace,\n\t\t\t\tdefaultColorSpace: config.colorSpace,\n\t\t\t\tflipY: config.flipY,\n\t\t\t\tdefaultFlipY: config.flipY,\n\t\t\t\tgenerateMipmaps: config.generateMipmaps,\n\t\t\t\tdefaultGenerateMipmaps: config.generateMipmaps,\n\t\t\t\tpremultipliedAlpha: config.premultipliedAlpha,\n\t\t\t\tdefaultPremultipliedAlpha: config.premultipliedAlpha,\n\t\t\t\tupdate: config.update ?? 'once',\n\t\t\t\tlastToken: null\n\t\t\t};\n\n\t\t\tif (config.update !== undefined) {\n\t\t\t\truntimeBinding.defaultUpdate = config.update;\n\t\t\t}\n\n\t\t\t// Storage textures: eagerly create GPU texture with explicit dimensions\n\t\t\tif (config.storage && config.width && config.height) {\n\t\t\t\tconst storageUsage =\n\t\t\t\t\tGPUTextureUsage.TEXTURE_BINDING |\n\t\t\t\t\tGPUTextureUsage.STORAGE_BINDING |\n\t\t\t\t\tGPUTextureUsage.COPY_DST;\n\t\t\t\tconst storageTexture = device.createTexture({\n\t\t\t\t\tsize: { width: config.width, height: config.height, depthOrArrayLayers: 1 },\n\t\t\t\t\tformat: config.format,\n\t\t\t\t\tusage: storageUsage\n\t\t\t\t});\n\t\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\t\tstorageTexture.destroy();\n\t\t\t\t});\n\t\t\t\truntimeBinding.texture = storageTexture as unknown as GPUTexture;\n\t\t\t\truntimeBinding.view = storageTexture.createView();\n\t\t\t\truntimeBinding.width = config.width;\n\t\t\t\truntimeBinding.height = config.height;\n\t\t\t}\n\n\t\t\treturn runtimeBinding;\n\t\t});\n\n\t\tconst bindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: createBindGroupLayoutEntries(textureBindings)\n\t\t});\n\t\tconst fragmentStorageBindGroupLayout =\n\t\t\tstorageBufferKeys.length > 0\n\t\t\t\t? device.createBindGroupLayout({\n\t\t\t\t\t\tentries: storageBufferKeys.map((_, index) => ({\n\t\t\t\t\t\t\tbinding: index,\n\t\t\t\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\t\t\t\tbuffer: { type: 'read-only-storage' as GPUBufferBindingType }\n\t\t\t\t\t\t}))\n\t\t\t\t\t})\n\t\t\t\t: null;\n\t\tconst pipelineLayout = device.createPipelineLayout({\n\t\t\tbindGroupLayouts: fragmentStorageBindGroupLayout\n\t\t\t\t? [bindGroupLayout, fragmentStorageBindGroupLayout]\n\t\t\t\t: [bindGroupLayout]\n\t\t});\n\n\t\tconst pipeline = device.createRenderPipeline({\n\t\t\tlayout: pipelineLayout,\n\t\t\tvertex: {\n\t\t\t\tmodule: shaderModule,\n\t\t\t\tentryPoint: 'motiongpuVertex'\n\t\t\t},\n\t\t\tfragment: {\n\t\t\t\tmodule: shaderModule,\n\t\t\t\tentryPoint: 'motiongpuFragment',\n\t\t\t\ttargets: [{ format }]\n\t\t\t},\n\t\t\tprimitive: {\n\t\t\t\ttopology: 'triangle-list'\n\t\t\t}\n\t\t});\n\n\t\tconst blitShaderModule = device.createShaderModule({\n\t\t\tcode: createFullscreenBlitShader()\n\t\t});\n\t\tawait assertCompilation(blitShaderModule);\n\n\t\tconst blitBindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: [\n\t\t\t\t{\n\t\t\t\t\tbinding: 0,\n\t\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\t\tsampler: { type: 'filtering' }\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 1,\n\t\t\t\t\tvisibility: GPUShaderStage.FRAGMENT,\n\t\t\t\t\ttexture: {\n\t\t\t\t\t\tsampleType: 'float',\n\t\t\t\t\t\tviewDimension: '2d',\n\t\t\t\t\t\tmultisampled: false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t});\n\t\tconst blitPipelineLayout = device.createPipelineLayout({\n\t\t\tbindGroupLayouts: [blitBindGroupLayout]\n\t\t});\n\t\tconst blitPipeline = device.createRenderPipeline({\n\t\t\tlayout: blitPipelineLayout,\n\t\t\tvertex: { module: blitShaderModule, entryPoint: 'motiongpuBlitVertex' },\n\t\t\tfragment: {\n\t\t\t\tmodule: blitShaderModule,\n\t\t\t\tentryPoint: 'motiongpuBlitFragment',\n\t\t\t\ttargets: [{ format }]\n\t\t\t},\n\t\t\tprimitive: {\n\t\t\t\ttopology: 'triangle-list'\n\t\t\t}\n\t\t});\n\t\tconst blitSampler = device.createSampler({\n\t\t\tmagFilter: 'linear',\n\t\t\tminFilter: 'linear',\n\t\t\taddressModeU: 'clamp-to-edge',\n\t\t\taddressModeV: 'clamp-to-edge'\n\t\t});\n\t\tlet blitBindGroupByView = new WeakMap<GPUTextureView, GPUBindGroup>();\n\n\t\t// ── Storage buffer allocation ────────────────────────────────────────\n\t\tconst storageBufferMap = new Map<string, GPUBuffer>();\n\t\tconst pingPongTexturePairs = new Map<string, PingPongTexturePair>();\n\n\t\tfor (const key of storageBufferKeys) {\n\t\t\tconst definition = storageBufferDefinitions[key];\n\t\t\tif (!definition) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst normalized = normalizeStorageBufferDefinition(definition);\n\t\t\tconst buffer = device.createBuffer({\n\t\t\t\tsize: normalized.size,\n\t\t\t\tusage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC\n\t\t\t});\n\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\tbuffer.destroy();\n\t\t\t});\n\t\t\tif (definition.initialData) {\n\t\t\t\tconst data = definition.initialData;\n\t\t\t\tdevice.queue.writeBuffer(\n\t\t\t\t\tbuffer,\n\t\t\t\t\t0,\n\t\t\t\t\tdata.buffer as ArrayBuffer,\n\t\t\t\t\tdata.byteOffset,\n\t\t\t\t\tdata.byteLength\n\t\t\t\t);\n\t\t\t}\n\t\t\tstorageBufferMap.set(key, buffer);\n\t\t}\n\t\tconst fragmentStorageBindGroup =\n\t\t\tfragmentStorageBindGroupLayout && storageBufferKeys.length > 0\n\t\t\t\t? device.createBindGroup({\n\t\t\t\t\t\tlayout: fragmentStorageBindGroupLayout,\n\t\t\t\t\t\tentries: storageBufferKeys.map((key, index) => {\n\t\t\t\t\t\t\tconst buffer = storageBufferMap.get(key);\n\t\t\t\t\t\t\tif (!buffer) {\n\t\t\t\t\t\t\t\tthrow new Error(`Storage buffer \"${key}\" not allocated.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn { binding: index, resource: { buffer } };\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t: null;\n\n\t\tconst ensurePingPongTexturePair = (target: string): PingPongTexturePair => {\n\t\t\tconst existing = pingPongTexturePairs.get(target);\n\t\t\tif (existing) {\n\t\t\t\treturn existing;\n\t\t\t}\n\n\t\t\tconst config = normalizedTextureDefinitions[target];\n\t\t\tif (!config || !config.storage) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`PingPongComputePass target \"${target}\" must reference a texture declared with storage:true.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!config.width || !config.height) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`PingPongComputePass target \"${target}\" requires explicit texture width and height.`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst usage =\n\t\t\t\tGPUTextureUsage.TEXTURE_BINDING |\n\t\t\t\tGPUTextureUsage.STORAGE_BINDING |\n\t\t\t\tGPUTextureUsage.COPY_DST;\n\t\t\tconst textureA = device.createTexture({\n\t\t\t\tsize: { width: config.width, height: config.height, depthOrArrayLayers: 1 },\n\t\t\t\tformat: config.format,\n\t\t\t\tusage\n\t\t\t});\n\t\t\tconst textureB = device.createTexture({\n\t\t\t\tsize: { width: config.width, height: config.height, depthOrArrayLayers: 1 },\n\t\t\t\tformat: config.format,\n\t\t\t\tusage\n\t\t\t});\n\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\ttextureA.destroy();\n\t\t\t});\n\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\ttextureB.destroy();\n\t\t\t});\n\n\t\t\tconst sampleScalarType = storageTextureSampleScalarType(config.format);\n\t\t\tconst sampleType = toGpuTextureSampleType(sampleScalarType);\n\t\t\tconst bindGroupLayout = device.createBindGroupLayout({\n\t\t\t\tentries: [\n\t\t\t\t\t{\n\t\t\t\t\t\tbinding: 0,\n\t\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\t\ttexture: {\n\t\t\t\t\t\t\tsampleType,\n\t\t\t\t\t\t\tviewDimension: '2d',\n\t\t\t\t\t\t\tmultisampled: false\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tbinding: 1,\n\t\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\t\tstorageTexture: {\n\t\t\t\t\t\t\taccess: 'write-only' as GPUStorageTextureAccess,\n\t\t\t\t\t\t\tformat: config.format as GPUTextureFormat,\n\t\t\t\t\t\t\tviewDimension: '2d'\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t});\n\n\t\t\tconst pair: PingPongTexturePair = {\n\t\t\t\ttarget,\n\t\t\t\tformat: config.format as GPUTextureFormat,\n\t\t\t\twidth: config.width,\n\t\t\t\theight: config.height,\n\t\t\t\ttextureA,\n\t\t\t\tviewA: textureA.createView(),\n\t\t\t\ttextureB,\n\t\t\t\tviewB: textureB.createView(),\n\t\t\t\tbindGroupLayout\n\t\t\t};\n\t\t\tpingPongTexturePairs.set(target, pair);\n\t\t\treturn pair;\n\t\t};\n\n\t\t// ── Compute pipeline setup ──────────────────────────────────────────\n\t\tinterface ComputePipelineEntry {\n\t\t\tpipeline: GPUComputePipeline;\n\t\t\tbindGroup: GPUBindGroup;\n\t\t\tworkgroupSize: [number, number, number];\n\t\t\tcomputeSource: string;\n\t\t}\n\t\tconst computePipelineCache = new Map<string, ComputePipelineEntry>();\n\n\t\tconst buildComputePipelineEntry = (buildOptions: {\n\t\t\tcomputeSource: string;\n\t\t\tpingPongTarget?: string;\n\t\t\tpingPongFormat?: GPUTextureFormat;\n\t\t}): ComputePipelineEntry => {\n\t\t\tconst cacheKey =\n\t\t\t\tbuildOptions.pingPongTarget && buildOptions.pingPongFormat\n\t\t\t\t\t? `pingpong:${buildOptions.pingPongTarget}:${buildOptions.pingPongFormat}:${buildOptions.computeSource}`\n\t\t\t\t\t: `compute:${buildOptions.computeSource}`;\n\t\t\tconst cached = computePipelineCache.get(cacheKey);\n\t\t\tif (cached) {\n\t\t\t\treturn cached;\n\t\t\t}\n\n\t\t\tconst storageBufferDefs: Record<\n\t\t\t\tstring,\n\t\t\t\t{ type: StorageBufferType; access: StorageBufferAccess }\n\t\t\t> = {};\n\t\t\tfor (const key of storageBufferKeys) {\n\t\t\t\tconst def = storageBufferDefinitions[key];\n\t\t\t\tif (def) {\n\t\t\t\t\tconst norm = normalizeStorageBufferDefinition(def);\n\t\t\t\t\tstorageBufferDefs[key] = { type: norm.type, access: norm.access };\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst storageTextureDefs: Record<string, { format: GPUTextureFormat }> = {};\n\t\t\tfor (const key of storageTextureKeys) {\n\t\t\t\tconst texDef = options.textureDefinitions[key];\n\t\t\t\tif (texDef?.format) {\n\t\t\t\t\tstorageTextureDefs[key] = { format: texDef.format };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst isPingPongPipeline = Boolean(\n\t\t\t\tbuildOptions.pingPongTarget && buildOptions.pingPongFormat\n\t\t\t);\n\t\t\tconst shaderCode = isPingPongPipeline\n\t\t\t\t? buildPingPongComputeShaderSource({\n\t\t\t\t\t\tcompute: buildOptions.computeSource,\n\t\t\t\t\t\tuniformLayout: options.uniformLayout,\n\t\t\t\t\t\tstorageBufferKeys,\n\t\t\t\t\t\tstorageBufferDefinitions: storageBufferDefs,\n\t\t\t\t\t\ttarget: buildOptions.pingPongTarget!,\n\t\t\t\t\t\ttargetFormat: buildOptions.pingPongFormat!\n\t\t\t\t\t})\n\t\t\t\t: buildComputeShaderSource({\n\t\t\t\t\t\tcompute: buildOptions.computeSource,\n\t\t\t\t\t\tuniformLayout: options.uniformLayout,\n\t\t\t\t\t\tstorageBufferKeys,\n\t\t\t\t\t\tstorageBufferDefinitions: storageBufferDefs,\n\t\t\t\t\t\tstorageTextureKeys,\n\t\t\t\t\t\tstorageTextureDefinitions: storageTextureDefs\n\t\t\t\t\t});\n\n\t\t\tconst computeShaderModule = device.createShaderModule({ code: shaderCode });\n\t\t\tconst workgroupSize = extractWorkgroupSize(buildOptions.computeSource);\n\n\t\t\t// Compute bind group layout: group(0)=uniforms, group(1)=storage buffers, group(2)=storage textures\n\t\t\tconst computeUniformBGL = device.createBindGroupLayout({\n\t\t\t\tentries: [\n\t\t\t\t\t{\n\t\t\t\t\t\tbinding: FRAME_BINDING,\n\t\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\t\tbuffer: { type: 'uniform', minBindingSize: 16 }\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tbinding: UNIFORM_BINDING,\n\t\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\t\tbuffer: { type: 'uniform' }\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t});\n\n\t\t\tconst storageBGLEntries: GPUBindGroupLayoutEntry[] = storageBufferKeys.map((key, index) => {\n\t\t\t\tconst def = storageBufferDefinitions[key];\n\t\t\t\tconst access = def?.access ?? 'read-write';\n\t\t\t\tconst bufferType: GPUBufferBindingType =\n\t\t\t\t\taccess === 'read' ? 'read-only-storage' : 'storage';\n\t\t\t\treturn {\n\t\t\t\t\tbinding: index,\n\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\tbuffer: { type: bufferType }\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst storageBGL =\n\t\t\t\tstorageBGLEntries.length > 0\n\t\t\t\t\t? device.createBindGroupLayout({ entries: storageBGLEntries })\n\t\t\t\t\t: null;\n\n\t\t\tconst storageTextureBGLEntries: GPUBindGroupLayoutEntry[] = isPingPongPipeline\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbinding: 0,\n\t\t\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\t\t\ttexture: {\n\t\t\t\t\t\t\t\tsampleType: toGpuTextureSampleType(\n\t\t\t\t\t\t\t\t\tstorageTextureSampleScalarType(buildOptions.pingPongFormat!)\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tviewDimension: '2d',\n\t\t\t\t\t\t\t\tmultisampled: false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbinding: 1,\n\t\t\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\t\t\tstorageTexture: {\n\t\t\t\t\t\t\t\taccess: 'write-only' as GPUStorageTextureAccess,\n\t\t\t\t\t\t\t\tformat: buildOptions.pingPongFormat!,\n\t\t\t\t\t\t\t\tviewDimension: '2d'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t: storageTextureKeys.map((key, index) => {\n\t\t\t\t\t\tconst texDef = options.textureDefinitions[key];\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tbinding: index,\n\t\t\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\t\t\tstorageTexture: {\n\t\t\t\t\t\t\t\taccess: 'write-only' as GPUStorageTextureAccess,\n\t\t\t\t\t\t\t\tformat: (texDef?.format ?? 'rgba8unorm') as GPUTextureFormat,\n\t\t\t\t\t\t\t\tviewDimension: '2d'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t});\n\t\t\tconst storageTextureBGL =\n\t\t\t\tstorageTextureBGLEntries.length > 0\n\t\t\t\t\t? device.createBindGroupLayout({ entries: storageTextureBGLEntries })\n\t\t\t\t\t: null;\n\n\t\t\t// Bind group layout indices must match shader @group() indices:\n\t\t\t// group(0) = uniforms, group(1) = storage buffers, group(2) = storage textures.\n\t\t\t// When a group is unused, insert an empty placeholder to keep indices aligned.\n\t\t\tconst bindGroupLayouts: GPUBindGroupLayout[] = [computeUniformBGL];\n\t\t\tif (storageBGL || storageTextureBGL) {\n\t\t\t\tbindGroupLayouts.push(storageBGL ?? device.createBindGroupLayout({ entries: [] }));\n\t\t\t}\n\t\t\tif (storageTextureBGL) {\n\t\t\t\tbindGroupLayouts.push(storageTextureBGL);\n\t\t\t}\n\n\t\t\tconst computePipelineLayout = device.createPipelineLayout({ bindGroupLayouts });\n\t\t\tconst pipeline = device.createComputePipeline({\n\t\t\t\tlayout: computePipelineLayout,\n\t\t\t\tcompute: {\n\t\t\t\t\tmodule: computeShaderModule,\n\t\t\t\t\tentryPoint: 'compute'\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Build uniform bind group for compute (group 0)\n\t\t\tconst computeUniformBindGroup = device.createBindGroup({\n\t\t\t\tlayout: computeUniformBGL,\n\t\t\t\tentries: [\n\t\t\t\t\t{ binding: FRAME_BINDING, resource: { buffer: frameBuffer } },\n\t\t\t\t\t{ binding: UNIFORM_BINDING, resource: { buffer: uniformBuffer } }\n\t\t\t\t]\n\t\t\t});\n\n\t\t\tconst entry: ComputePipelineEntry = {\n\t\t\t\tpipeline,\n\t\t\t\tbindGroup: computeUniformBindGroup,\n\t\t\t\tworkgroupSize,\n\t\t\t\tcomputeSource: buildOptions.computeSource\n\t\t\t};\n\t\t\tcomputePipelineCache.set(cacheKey, entry);\n\t\t\treturn entry;\n\t\t};\n\n\t\t// Helper to get the storage bind group for dispatch\n\t\tconst getComputeStorageBindGroup = (): GPUBindGroup | null => {\n\t\t\tif (storageBufferKeys.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Rebuild bind group with current storage buffers\n\t\t\tconst storageBGLEntries: GPUBindGroupLayoutEntry[] = storageBufferKeys.map((key, index) => {\n\t\t\t\tconst def = storageBufferDefinitions[key];\n\t\t\t\tconst access = def?.access ?? 'read-write';\n\t\t\t\tconst bufferType: GPUBufferBindingType =\n\t\t\t\t\taccess === 'read' ? 'read-only-storage' : 'storage';\n\t\t\t\treturn {\n\t\t\t\t\tbinding: index,\n\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\tbuffer: { type: bufferType }\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst storageBGL = device.createBindGroupLayout({ entries: storageBGLEntries });\n\t\t\tconst storageEntries: GPUBindGroupEntry[] = storageBufferKeys.map((key, index) => {\n\t\t\t\tconst buffer = storageBufferMap.get(key);\n\t\t\t\tif (!buffer) {\n\t\t\t\t\tthrow new Error(`Storage buffer \"${key}\" not allocated.`);\n\t\t\t\t}\n\t\t\t\treturn { binding: index, resource: { buffer } };\n\t\t\t});\n\t\t\treturn device.createBindGroup({\n\t\t\t\tlayout: storageBGL,\n\t\t\t\tentries: storageEntries\n\t\t\t});\n\t\t};\n\n\t\t// Helper to get the storage texture bind group for compute dispatch (group 2)\n\t\tconst getComputeStorageTextureBindGroup = (): GPUBindGroup | null => {\n\t\t\tif (storageTextureKeys.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst entries: GPUBindGroupLayoutEntry[] = storageTextureKeys.map((key, index) => {\n\t\t\t\tconst texDef = options.textureDefinitions[key];\n\t\t\t\treturn {\n\t\t\t\t\tbinding: index,\n\t\t\t\t\tvisibility: GPUShaderStage.COMPUTE,\n\t\t\t\t\tstorageTexture: {\n\t\t\t\t\t\taccess: 'write-only' as GPUStorageTextureAccess,\n\t\t\t\t\t\tformat: (texDef?.format ?? 'rgba8unorm') as GPUTextureFormat,\n\t\t\t\t\t\tviewDimension: '2d' as GPUTextureViewDimension\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst bgl = device.createBindGroupLayout({ entries });\n\n\t\t\tconst bgEntries: GPUBindGroupEntry[] = storageTextureKeys.map((key, index) => {\n\t\t\t\tconst binding = textureBindings.find((b) => b.key === key);\n\t\t\t\tif (!binding || !binding.texture) {\n\t\t\t\t\tthrow new Error(`Storage texture \"${key}\" not allocated.`);\n\t\t\t\t}\n\t\t\t\treturn { binding: index, resource: binding.view };\n\t\t\t});\n\n\t\t\treturn device.createBindGroup({ layout: bgl, entries: bgEntries });\n\t\t};\n\n\t\t// Helper to get ping-pong storage texture bind group for compute dispatch (group 2)\n\t\tconst getPingPongStorageTextureBindGroup = (\n\t\t\ttarget: string,\n\t\t\treadFromA: boolean\n\t\t): GPUBindGroup => {\n\t\t\tconst pair = ensurePingPongTexturePair(target);\n\t\t\tconst readView = readFromA ? pair.viewA : pair.viewB;\n\t\t\tconst writeView = readFromA ? pair.viewB : pair.viewA;\n\t\t\treturn device.createBindGroup({\n\t\t\t\tlayout: pair.bindGroupLayout,\n\t\t\t\tentries: [\n\t\t\t\t\t{ binding: 0, resource: readView },\n\t\t\t\t\t{ binding: 1, resource: writeView }\n\t\t\t\t]\n\t\t\t});\n\t\t};\n\n\t\tconst frameBuffer = device.createBuffer({\n\t\t\tsize: 16,\n\t\t\tusage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n\t\t});\n\t\tregisterInitializationCleanup(() => {\n\t\t\tframeBuffer.destroy();\n\t\t});\n\n\t\tconst uniformBuffer = device.createBuffer({\n\t\t\tsize: options.uniformLayout.byteLength,\n\t\t\tusage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST\n\t\t});\n\t\tregisterInitializationCleanup(() => {\n\t\t\tuniformBuffer.destroy();\n\t\t});\n\t\tconst frameScratch = new Float32Array(4);\n\t\tconst uniformScratch = new Float32Array(options.uniformLayout.byteLength / 4);\n\t\tconst uniformPrevious = new Float32Array(options.uniformLayout.byteLength / 4);\n\t\tlet hasUniformSnapshot = false;\n\n\t\t/**\n\t\t * Rebuilds bind group using current texture views.\n\t\t */\n\t\tconst createBindGroup = (): GPUBindGroup => {\n\t\t\tconst entries: GPUBindGroupEntry[] = [\n\t\t\t\t{ binding: FRAME_BINDING, resource: { buffer: frameBuffer } },\n\t\t\t\t{ binding: UNIFORM_BINDING, resource: { buffer: uniformBuffer } }\n\t\t\t];\n\n\t\t\tfor (const binding of textureBindings) {\n\t\t\t\tentries.push({\n\t\t\t\t\tbinding: binding.samplerBinding,\n\t\t\t\t\tresource: binding.sampler\n\t\t\t\t});\n\t\t\t\tentries.push({\n\t\t\t\t\tbinding: binding.textureBinding,\n\t\t\t\t\tresource: binding.view\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn device.createBindGroup({\n\t\t\t\tlayout: bindGroupLayout,\n\t\t\t\tentries\n\t\t\t});\n\t\t};\n\n\t\t/**\n\t\t * Synchronizes one runtime texture binding with incoming texture value.\n\t\t *\n\t\t * @returns `true` when bind group must be rebuilt.\n\t\t */\n\t\tconst updateTextureBinding = (\n\t\t\tbinding: RuntimeTextureBinding,\n\t\t\tvalue: TextureValue,\n\t\t\trenderMode: RenderMode\n\t\t): boolean => {\n\t\t\tconst nextData = toTextureData(value);\n\n\t\t\tif (!nextData) {\n\t\t\t\tif (binding.source === null && binding.texture === null) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tbinding.texture?.destroy();\n\t\t\t\tbinding.texture = null;\n\t\t\t\tbinding.view = binding.fallbackView;\n\t\t\t\tbinding.source = null;\n\t\t\t\tbinding.width = undefined;\n\t\t\t\tbinding.height = undefined;\n\t\t\t\tbinding.lastToken = null;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst source = nextData.source;\n\t\t\tconst colorSpace = nextData.colorSpace ?? binding.defaultColorSpace;\n\t\t\tconst format = colorSpace === 'linear' ? 'rgba8unorm' : 'rgba8unorm-srgb';\n\t\t\tconst flipY = nextData.flipY ?? binding.defaultFlipY;\n\t\t\tconst premultipliedAlpha = nextData.premultipliedAlpha ?? binding.defaultPremultipliedAlpha;\n\t\t\tconst generateMipmaps = nextData.generateMipmaps ?? binding.defaultGenerateMipmaps;\n\t\t\tconst update = resolveTextureUpdateMode({\n\t\t\t\tsource,\n\t\t\t\t...(nextData.update !== undefined ? { override: nextData.update } : {}),\n\t\t\t\t...(binding.defaultUpdate !== undefined ? { defaultMode: binding.defaultUpdate } : {})\n\t\t\t});\n\t\t\tconst { width, height } = resolveTextureSize(nextData);\n\t\t\tconst mipLevelCount = generateMipmaps ? getTextureMipLevelCount(width, height) : 1;\n\t\t\tconst sourceChanged = binding.source !== source;\n\t\t\tconst tokenChanged = binding.lastToken !== value;\n\t\t\tconst requiresReallocation =\n\t\t\t\tbinding.texture === null ||\n\t\t\t\tbinding.width !== width ||\n\t\t\t\tbinding.height !== height ||\n\t\t\t\tbinding.mipLevelCount !== mipLevelCount ||\n\t\t\t\tbinding.format !== format;\n\n\t\t\tif (!requiresReallocation) {\n\t\t\t\tconst shouldUpload =\n\t\t\t\t\tsourceChanged ||\n\t\t\t\t\tupdate === 'perFrame' ||\n\t\t\t\t\t(update === 'onInvalidate' && (renderMode !== 'always' || tokenChanged));\n\n\t\t\t\tif (shouldUpload && binding.texture) {\n\t\t\t\t\tbinding.flipY = flipY;\n\t\t\t\t\tbinding.generateMipmaps = generateMipmaps;\n\t\t\t\t\tbinding.premultipliedAlpha = premultipliedAlpha;\n\t\t\t\t\tbinding.colorSpace = colorSpace;\n\t\t\t\t\tuploadTexture(device, binding.texture, binding, source, width, height, mipLevelCount);\n\t\t\t\t}\n\n\t\t\t\tbinding.source = source;\n\t\t\t\tbinding.width = width;\n\t\t\t\tbinding.height = height;\n\t\t\t\tbinding.mipLevelCount = mipLevelCount;\n\t\t\t\tbinding.update = update;\n\t\t\t\tbinding.lastToken = value;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tlet textureUsage =\n\t\t\t\tGPUTextureUsage.TEXTURE_BINDING |\n\t\t\t\tGPUTextureUsage.COPY_DST |\n\t\t\t\tGPUTextureUsage.RENDER_ATTACHMENT;\n\t\t\tif (storageTextureKeySet.has(binding.key)) {\n\t\t\t\ttextureUsage |= GPUTextureUsage.STORAGE_BINDING;\n\t\t\t}\n\t\t\tconst texture = device.createTexture({\n\t\t\t\tsize: { width, height, depthOrArrayLayers: 1 },\n\t\t\t\tformat,\n\t\t\t\tmipLevelCount,\n\t\t\t\tusage: textureUsage\n\t\t\t});\n\t\t\tregisterInitializationCleanup(() => {\n\t\t\t\ttexture.destroy();\n\t\t\t});\n\n\t\t\tbinding.flipY = flipY;\n\t\t\tbinding.generateMipmaps = generateMipmaps;\n\t\t\tbinding.premultipliedAlpha = premultipliedAlpha;\n\t\t\tbinding.colorSpace = colorSpace;\n\t\t\tbinding.format = format;\n\t\t\tuploadTexture(device, texture, binding, source, width, height, mipLevelCount);\n\n\t\t\tbinding.texture?.destroy();\n\t\t\tbinding.texture = texture;\n\t\t\tbinding.view = texture.createView();\n\t\t\tbinding.source = source;\n\t\t\tbinding.width = width;\n\t\t\tbinding.height = height;\n\t\t\tbinding.mipLevelCount = mipLevelCount;\n\t\t\tbinding.update = update;\n\t\t\tbinding.lastToken = value;\n\t\t\treturn true;\n\t\t};\n\n\t\tfor (const binding of textureBindings) {\n\t\t\t// Skip storage textures — they are eagerly allocated and not source-driven\n\t\t\tif (storageTextureKeySet.has(binding.key)) continue;\n\t\t\tconst defaultSource = normalizedTextureDefinitions[binding.key]?.source ?? null;\n\t\t\tupdateTextureBinding(binding, defaultSource, 'always');\n\t\t}\n\n\t\tlet bindGroup = createBindGroup();\n\t\tlet sourceSlotTarget: RuntimeRenderTarget | null = null;\n\t\tlet targetSlotTarget: RuntimeRenderTarget | null = null;\n\t\tlet renderTargetSignature = '';\n\t\tlet renderTargetSnapshot: Readonly<Record<string, RenderTarget>> = {};\n\t\tlet renderTargetKeys: string[] = [];\n\t\tlet cachedGraphPlan: RenderGraphPlan | null = null;\n\t\tlet cachedGraphRenderTargetSignature = '';\n\t\tconst cachedGraphClearColor: [number, number, number, number] = [NaN, NaN, NaN, NaN];\n\t\tconst cachedGraphPasses: RenderGraphPassSnapshot[] = [];\n\t\tlet contextConfigured = false;\n\t\tlet configuredWidth = 0;\n\t\tlet configuredHeight = 0;\n\t\tconst runtimeRenderTargets = new Map<string, RuntimeRenderTarget>();\n\t\tconst activePasses: AnyPass[] = [];\n\t\tconst lifecyclePreviousSet = new Set<AnyPass>();\n\t\tconst lifecycleNextSet = new Set<AnyPass>();\n\t\tconst lifecycleUniquePasses: AnyPass[] = [];\n\t\tlet lifecyclePassesRef: AnyPass[] | null = null;\n\t\tlet passWidth = 0;\n\t\tlet passHeight = 0;\n\n\t\t/**\n\t\t * Resolves active render pass list for current frame.\n\t\t */\n\t\tconst resolvePasses = (): AnyPass[] => {\n\t\t\treturn options.getPasses?.() ?? options.passes ?? [];\n\t\t};\n\n\t\t/**\n\t\t * Resolves active render target declarations for current frame.\n\t\t */\n\t\tconst resolveRenderTargets = () => {\n\t\t\treturn options.getRenderTargets?.() ?? options.renderTargets;\n\t\t};\n\n\t\t/**\n\t\t * Checks whether cached render-graph plan can be reused for this frame.\n\t\t */\n\t\tconst isGraphPlanCacheValid = (\n\t\t\tpasses: AnyPass[],\n\t\t\tclearColor: [number, number, number, number]\n\t\t): boolean => {\n\t\t\tif (!cachedGraphPlan) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (cachedGraphRenderTargetSignature !== renderTargetSignature) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tcachedGraphClearColor[0] !== clearColor[0] ||\n\t\t\t\tcachedGraphClearColor[1] !== clearColor[1] ||\n\t\t\t\tcachedGraphClearColor[2] !== clearColor[2] ||\n\t\t\t\tcachedGraphClearColor[3] !== clearColor[3]\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (cachedGraphPasses.length !== passes.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor (let index = 0; index < passes.length; index += 1) {\n\t\t\t\tconst pass = passes[index];\n\t\t\t\tconst rp = pass as Partial<RenderPass>;\n\t\t\t\tconst snapshot = cachedGraphPasses[index];\n\t\t\t\tif (!pass || !snapshot || snapshot.pass !== pass) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tsnapshot.enabled !== pass.enabled ||\n\t\t\t\t\tsnapshot.needsSwap !== rp.needsSwap ||\n\t\t\t\t\tsnapshot.input !== rp.input ||\n\t\t\t\t\tsnapshot.output !== rp.output ||\n\t\t\t\t\tsnapshot.clear !== rp.clear ||\n\t\t\t\t\tsnapshot.preserve !== rp.preserve\n\t\t\t\t) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst passClearColor = rp.clearColor;\n\t\t\t\tconst hasPassClearColor = passClearColor !== undefined;\n\t\t\t\tif (snapshot.hasClearColor !== hasPassClearColor) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (passClearColor) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tsnapshot.clearColor0 !== passClearColor[0] ||\n\t\t\t\t\t\tsnapshot.clearColor1 !== passClearColor[1] ||\n\t\t\t\t\t\tsnapshot.clearColor2 !== passClearColor[2] ||\n\t\t\t\t\t\tsnapshot.clearColor3 !== passClearColor[3]\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t};\n\n\t\t/**\n\t\t * Updates render-graph cache with current pass set.\n\t\t */\n\t\tconst updateGraphPlanCache = (\n\t\t\tpasses: AnyPass[],\n\t\t\tclearColor: [number, number, number, number],\n\t\t\tgraphPlan: RenderGraphPlan\n\t\t): void => {\n\t\t\tcachedGraphPlan = graphPlan;\n\t\t\tcachedGraphRenderTargetSignature = renderTargetSignature;\n\t\t\tcachedGraphClearColor[0] = clearColor[0];\n\t\t\tcachedGraphClearColor[1] = clearColor[1];\n\t\t\tcachedGraphClearColor[2] = clearColor[2];\n\t\t\tcachedGraphClearColor[3] = clearColor[3];\n\t\t\tcachedGraphPasses.length = passes.length;\n\n\t\t\tlet index = 0;\n\t\t\tfor (const pass of passes) {\n\t\t\t\tconst rp = pass as Partial<RenderPass>;\n\t\t\t\tconst passClearColor = rp.clearColor;\n\t\t\t\tconst hasPassClearColor = passClearColor !== undefined;\n\t\t\t\tconst snapshot = cachedGraphPasses[index];\n\t\t\t\tif (!snapshot) {\n\t\t\t\t\tcachedGraphPasses[index] = {\n\t\t\t\t\t\tpass,\n\t\t\t\t\t\tenabled: pass.enabled,\n\t\t\t\t\t\tneedsSwap: rp.needsSwap,\n\t\t\t\t\t\tinput: rp.input,\n\t\t\t\t\t\toutput: rp.output,\n\t\t\t\t\t\tclear: rp.clear,\n\t\t\t\t\t\tpreserve: rp.preserve,\n\t\t\t\t\t\thasClearColor: hasPassClearColor,\n\t\t\t\t\t\tclearColor0: passClearColor?.[0] ?? 0,\n\t\t\t\t\t\tclearColor1: passClearColor?.[1] ?? 0,\n\t\t\t\t\t\tclearColor2: passClearColor?.[2] ?? 0,\n\t\t\t\t\t\tclearColor3: passClearColor?.[3] ?? 0\n\t\t\t\t\t};\n\t\t\t\t\tindex += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tsnapshot.pass = pass;\n\t\t\t\tsnapshot.enabled = pass.enabled;\n\t\t\t\tsnapshot.needsSwap = rp.needsSwap;\n\t\t\t\tsnapshot.input = rp.input;\n\t\t\t\tsnapshot.output = rp.output;\n\t\t\t\tsnapshot.clear = rp.clear;\n\t\t\t\tsnapshot.preserve = rp.preserve;\n\t\t\t\tsnapshot.hasClearColor = hasPassClearColor;\n\t\t\t\tsnapshot.clearColor0 = passClearColor?.[0] ?? 0;\n\t\t\t\tsnapshot.clearColor1 = passClearColor?.[1] ?? 0;\n\t\t\t\tsnapshot.clearColor2 = passClearColor?.[2] ?? 0;\n\t\t\t\tsnapshot.clearColor3 = passClearColor?.[3] ?? 0;\n\t\t\t\tindex += 1;\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Synchronizes pass lifecycle callbacks and resize notifications.\n\t\t */\n\t\tconst syncPassLifecycle = (passes: AnyPass[], width: number, height: number): void => {\n\t\t\tconst resized = passWidth !== width || passHeight !== height;\n\t\t\tif (!resized && lifecyclePassesRef === passes && passes.length === activePasses.length) {\n\t\t\t\tlet isSameOrder = true;\n\t\t\t\tfor (let index = 0; index < passes.length; index += 1) {\n\t\t\t\t\tif (activePasses[index] !== passes[index]) {\n\t\t\t\t\t\tisSameOrder = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isSameOrder) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlifecycleNextSet.clear();\n\t\t\tlifecycleUniquePasses.length = 0;\n\t\t\tfor (const pass of passes) {\n\t\t\t\tif (lifecycleNextSet.has(pass)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlifecycleNextSet.add(pass);\n\t\t\t\tlifecycleUniquePasses.push(pass);\n\t\t\t}\n\t\t\tlifecyclePreviousSet.clear();\n\t\t\tfor (const pass of activePasses) {\n\t\t\t\tlifecyclePreviousSet.add(pass);\n\t\t\t}\n\n\t\t\tfor (const pass of activePasses) {\n\t\t\t\tif (!lifecycleNextSet.has(pass)) {\n\t\t\t\t\tpass.dispose?.();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const pass of lifecycleUniquePasses) {\n\t\t\t\tif (resized || !lifecyclePreviousSet.has(pass)) {\n\t\t\t\t\tpass.setSize?.(width, height);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tactivePasses.length = 0;\n\t\t\tfor (const pass of lifecycleUniquePasses) {\n\t\t\t\tactivePasses.push(pass);\n\t\t\t}\n\t\t\tlifecyclePassesRef = passes;\n\t\t\tpassWidth = width;\n\t\t\tpassHeight = height;\n\t\t};\n\n\t\t/**\n\t\t * Ensures internal ping-pong slot texture matches current canvas size/format.\n\t\t */\n\t\tconst ensureSlotTarget = (\n\t\t\tslot: RenderPassInputSlot,\n\t\t\twidth: number,\n\t\t\theight: number\n\t\t): RuntimeRenderTarget => {\n\t\t\tconst current = slot === 'source' ? sourceSlotTarget : targetSlotTarget;\n\t\t\tif (\n\t\t\t\tcurrent &&\n\t\t\t\tcurrent.width === width &&\n\t\t\t\tcurrent.height === height &&\n\t\t\t\tcurrent.format === format\n\t\t\t) {\n\t\t\t\treturn current;\n\t\t\t}\n\n\t\t\tdestroyRenderTexture(current);\n\t\t\tconst next = createRenderTexture(device, width, height, format);\n\t\t\tif (slot === 'source') {\n\t\t\t\tsourceSlotTarget = next;\n\t\t\t} else {\n\t\t\t\ttargetSlotTarget = next;\n\t\t\t}\n\n\t\t\treturn next;\n\t\t};\n\n\t\t/**\n\t\t * Creates/updates runtime render targets and returns immutable pass snapshot.\n\t\t */\n\t\tconst syncRenderTargets = (\n\t\t\tcanvasWidth: number,\n\t\t\tcanvasHeight: number\n\t\t): Readonly<Record<string, RenderTarget>> => {\n\t\t\tconst resolvedDefinitions = resolveRenderTargetDefinitions(\n\t\t\t\tresolveRenderTargets(),\n\t\t\t\tcanvasWidth,\n\t\t\t\tcanvasHeight,\n\t\t\t\tformat\n\t\t\t);\n\t\t\tconst nextSignature = buildRenderTargetSignature(resolvedDefinitions);\n\n\t\t\tif (nextSignature !== renderTargetSignature) {\n\t\t\t\tconst activeKeys = new Set(resolvedDefinitions.map((definition) => definition.key));\n\n\t\t\t\tfor (const [key, target] of runtimeRenderTargets.entries()) {\n\t\t\t\t\tif (!activeKeys.has(key)) {\n\t\t\t\t\t\ttarget.texture.destroy();\n\t\t\t\t\t\truntimeRenderTargets.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const definition of resolvedDefinitions) {\n\t\t\t\t\tconst current = runtimeRenderTargets.get(definition.key);\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrent &&\n\t\t\t\t\t\tcurrent.width === definition.width &&\n\t\t\t\t\t\tcurrent.height === definition.height &&\n\t\t\t\t\t\tcurrent.format === definition.format\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrent?.texture.destroy();\n\t\t\t\t\truntimeRenderTargets.set(\n\t\t\t\t\t\tdefinition.key,\n\t\t\t\t\t\tcreateRenderTexture(device, definition.width, definition.height, definition.format)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\trenderTargetSignature = nextSignature;\n\t\t\t\tconst nextSnapshot: Record<string, RenderTarget> = {};\n\t\t\t\tconst nextKeys: string[] = [];\n\t\t\t\tfor (const definition of resolvedDefinitions) {\n\t\t\t\t\tconst target = runtimeRenderTargets.get(definition.key);\n\t\t\t\t\tif (!target) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tnextKeys.push(definition.key);\n\t\t\t\t\tnextSnapshot[definition.key] = {\n\t\t\t\t\t\ttexture: target.texture,\n\t\t\t\t\t\tview: target.view,\n\t\t\t\t\t\twidth: target.width,\n\t\t\t\t\t\theight: target.height,\n\t\t\t\t\t\tformat: target.format\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\trenderTargetSnapshot = nextSnapshot;\n\t\t\t\trenderTargetKeys = nextKeys;\n\t\t\t}\n\n\t\t\treturn renderTargetSnapshot;\n\t\t};\n\n\t\t/**\n\t\t * Blits a texture view to the current canvas texture.\n\t\t */\n\t\tconst blitToCanvas = (\n\t\t\tcommandEncoder: GPUCommandEncoder,\n\t\t\tsourceView: GPUTextureView,\n\t\t\tcanvasView: GPUTextureView,\n\t\t\tclearColor: [number, number, number, number]\n\t\t): void => {\n\t\t\tlet bindGroup = blitBindGroupByView.get(sourceView);\n\t\t\tif (!bindGroup) {\n\t\t\t\tbindGroup = device.createBindGroup({\n\t\t\t\t\tlayout: blitBindGroupLayout,\n\t\t\t\t\tentries: [\n\t\t\t\t\t\t{ binding: 0, resource: blitSampler },\n\t\t\t\t\t\t{ binding: 1, resource: sourceView }\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t\tblitBindGroupByView.set(sourceView, bindGroup);\n\t\t\t}\n\n\t\t\tconst pass = commandEncoder.beginRenderPass({\n\t\t\t\tcolorAttachments: [\n\t\t\t\t\t{\n\t\t\t\t\t\tview: canvasView,\n\t\t\t\t\t\tclearValue: {\n\t\t\t\t\t\t\tr: clearColor[0],\n\t\t\t\t\t\t\tg: clearColor[1],\n\t\t\t\t\t\t\tb: clearColor[2],\n\t\t\t\t\t\t\ta: clearColor[3]\n\t\t\t\t\t\t},\n\t\t\t\t\t\tloadOp: 'clear',\n\t\t\t\t\t\tstoreOp: 'store'\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t});\n\n\t\t\tpass.setPipeline(blitPipeline);\n\t\t\tpass.setBindGroup(0, bindGroup);\n\t\t\tpass.draw(3);\n\t\t\tpass.end();\n\t\t};\n\n\t\t/**\n\t\t * Executes a full frame render.\n\t\t */\n\t\tconst render: Renderer['render'] = ({\n\t\t\ttime,\n\t\t\tdelta,\n\t\t\trenderMode,\n\t\t\tuniforms,\n\t\t\ttextures,\n\t\t\tcanvasSize,\n\t\t\tpendingStorageWrites\n\t\t}) => {\n\t\t\tif (deviceLostMessage) {\n\t\t\t\tthrow new Error(deviceLostMessage);\n\t\t\t}\n\n\t\t\tif (uncapturedErrorMessage) {\n\t\t\t\tconst message = uncapturedErrorMessage;\n\t\t\t\tuncapturedErrorMessage = null;\n\t\t\t\tthrow new Error(message);\n\t\t\t}\n\n\t\t\tconst { width, height } = resizeCanvas(options.canvas, options.getDpr(), canvasSize);\n\n\t\t\tif (!contextConfigured || configuredWidth !== width || configuredHeight !== height) {\n\t\t\t\tcontext.configure({\n\t\t\t\t\tdevice,\n\t\t\t\t\tformat,\n\t\t\t\t\talphaMode: 'premultiplied'\n\t\t\t\t});\n\t\t\t\tcontextConfigured = true;\n\t\t\t\tconfiguredWidth = width;\n\t\t\t\tconfiguredHeight = height;\n\t\t\t}\n\n\t\t\tframeScratch[0] = time;\n\t\t\tframeScratch[1] = delta;\n\t\t\tframeScratch[2] = width;\n\t\t\tframeScratch[3] = height;\n\t\t\tdevice.queue.writeBuffer(\n\t\t\t\tframeBuffer,\n\t\t\t\t0,\n\t\t\t\tframeScratch.buffer as ArrayBuffer,\n\t\t\t\tframeScratch.byteOffset,\n\t\t\t\tframeScratch.byteLength\n\t\t\t);\n\n\t\t\tpackUniformsInto(uniforms, options.uniformLayout, uniformScratch);\n\t\t\tif (!hasUniformSnapshot) {\n\t\t\t\tdevice.queue.writeBuffer(\n\t\t\t\t\tuniformBuffer,\n\t\t\t\t\t0,\n\t\t\t\t\tuniformScratch.buffer as ArrayBuffer,\n\t\t\t\t\tuniformScratch.byteOffset,\n\t\t\t\t\tuniformScratch.byteLength\n\t\t\t\t);\n\t\t\t\tuniformPrevious.set(uniformScratch);\n\t\t\t\thasUniformSnapshot = true;\n\t\t\t} else {\n\t\t\t\tconst dirtyRanges = findDirtyFloatRanges(uniformPrevious, uniformScratch);\n\t\t\t\tfor (const range of dirtyRanges) {\n\t\t\t\t\tconst byteOffset = range.start * 4;\n\t\t\t\t\tconst byteLength = range.count * 4;\n\t\t\t\t\tdevice.queue.writeBuffer(\n\t\t\t\t\t\tuniformBuffer,\n\t\t\t\t\t\tbyteOffset,\n\t\t\t\t\t\tuniformScratch.buffer as ArrayBuffer,\n\t\t\t\t\t\tuniformScratch.byteOffset + byteOffset,\n\t\t\t\t\t\tbyteLength\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (dirtyRanges.length > 0) {\n\t\t\t\t\tuniformPrevious.set(uniformScratch);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet bindGroupDirty = false;\n\t\t\tfor (const binding of textureBindings) {\n\t\t\t\t// Storage textures are managed by compute passes, skip source-driven updates\n\t\t\t\tif (storageTextureKeySet.has(binding.key)) continue;\n\t\t\t\tconst nextTexture =\n\t\t\t\t\ttextures[binding.key] ?? normalizedTextureDefinitions[binding.key]?.source ?? null;\n\t\t\t\tif (updateTextureBinding(binding, nextTexture, renderMode)) {\n\t\t\t\t\tbindGroupDirty = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bindGroupDirty) {\n\t\t\t\tbindGroup = createBindGroup();\n\t\t\t}\n\n\t\t\t// Apply pending storage buffer writes\n\t\t\tif (pendingStorageWrites) {\n\t\t\t\tfor (const write of pendingStorageWrites) {\n\t\t\t\t\tconst buffer = storageBufferMap.get(write.name);\n\t\t\t\t\tif (buffer) {\n\t\t\t\t\t\tconst data = write.data;\n\t\t\t\t\t\tdevice.queue.writeBuffer(\n\t\t\t\t\t\t\tbuffer,\n\t\t\t\t\t\t\twrite.offset,\n\t\t\t\t\t\t\tdata.buffer as ArrayBuffer,\n\t\t\t\t\t\t\tdata.byteOffset,\n\t\t\t\t\t\t\tdata.byteLength\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst commandEncoder = device.createCommandEncoder();\n\t\t\tconst passes = resolvePasses();\n\t\t\tconst clearColor = options.getClearColor();\n\t\t\tsyncPassLifecycle(passes, width, height);\n\t\t\tconst runtimeTargets = syncRenderTargets(width, height);\n\t\t\tconst graphPlan = isGraphPlanCacheValid(passes, clearColor)\n\t\t\t\t? cachedGraphPlan!\n\t\t\t\t: (() => {\n\t\t\t\t\t\tconst nextPlan = planRenderGraph(passes, clearColor, renderTargetKeys);\n\t\t\t\t\t\tupdateGraphPlanCache(passes, clearColor, nextPlan);\n\t\t\t\t\t\treturn nextPlan;\n\t\t\t\t\t})();\n\t\t\tconst canvasTexture = context.getCurrentTexture();\n\t\t\tconst canvasSurface: RenderTarget = {\n\t\t\t\ttexture: canvasTexture,\n\t\t\t\tview: canvasTexture.createView(),\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tformat\n\t\t\t};\n\t\t\tconst slots =\n\t\t\t\tgraphPlan.steps.length > 0\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tsource: ensureSlotTarget('source', width, height),\n\t\t\t\t\t\t\ttarget: ensureSlotTarget('target', width, height),\n\t\t\t\t\t\t\tcanvas: canvasSurface\n\t\t\t\t\t\t}\n\t\t\t\t\t: null;\n\t\t\tconst sceneOutput = slots ? slots.source : canvasSurface;\n\n\t\t\t// Dispatch compute passes BEFORE scene render so storage textures\n\t\t\t// and buffers are up-to-date when the fragment shader samples them.\n\t\t\tif (slots) {\n\t\t\t\tfor (const step of graphPlan.steps) {\n\t\t\t\t\tif (step.kind !== 'compute') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst computePass = step.pass as {\n\t\t\t\t\t\tisCompute?: boolean;\n\t\t\t\t\t\tgetCompute?: () => string;\n\t\t\t\t\t\tresolveDispatch?: (ctx: {\n\t\t\t\t\t\t\twidth: number;\n\t\t\t\t\t\t\theight: number;\n\t\t\t\t\t\t\ttime: number;\n\t\t\t\t\t\t\tdelta: number;\n\t\t\t\t\t\t\tworkgroupSize: [number, number, number];\n\t\t\t\t\t\t}) => [number, number, number];\n\t\t\t\t\t\tgetWorkgroupSize?: () => [number, number, number];\n\t\t\t\t\t\tisPingPong?: boolean;\n\t\t\t\t\t\tgetTarget?: () => string;\n\t\t\t\t\t\tgetCurrentOutput?: () => string;\n\t\t\t\t\t\tgetIterations?: () => number;\n\t\t\t\t\t\tadvanceFrame?: () => void;\n\t\t\t\t\t};\n\t\t\t\t\tif (\n\t\t\t\t\t\tcomputePass.getCompute &&\n\t\t\t\t\t\tcomputePass.resolveDispatch &&\n\t\t\t\t\t\tcomputePass.getWorkgroupSize\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst computeSource = computePass.getCompute();\n\t\t\t\t\t\tconst pingPongTarget =\n\t\t\t\t\t\t\tcomputePass.isPingPong && computePass.getTarget ? computePass.getTarget() : undefined;\n\t\t\t\t\t\tif (computePass.isPingPong && !pingPongTarget) {\n\t\t\t\t\t\t\tthrow new Error('PingPongComputePass must provide a target texture key.');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst pingPongPair = pingPongTarget ? ensurePingPongTexturePair(pingPongTarget) : null;\n\t\t\t\t\t\tconst pipelineEntry = buildComputePipelineEntry({\n\t\t\t\t\t\t\tcomputeSource,\n\t\t\t\t\t\t\t...(pingPongPair\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tpingPongTarget: pingPongPair.target,\n\t\t\t\t\t\t\t\t\t\tpingPongFormat: pingPongPair.format\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {})\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst workgroupSize = computePass.getWorkgroupSize();\n\t\t\t\t\t\tconst storageBindGroup = getComputeStorageBindGroup();\n\t\t\t\t\t\tconst storageTextureBindGroup = getComputeStorageTextureBindGroup();\n\t\t\t\t\t\tconst iterations =\n\t\t\t\t\t\t\tcomputePass.isPingPong && computePass.getIterations ? computePass.getIterations() : 1;\n\t\t\t\t\t\tconst currentOutput =\n\t\t\t\t\t\t\tcomputePass.isPingPong && computePass.getCurrentOutput\n\t\t\t\t\t\t\t\t? computePass.getCurrentOutput()\n\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\tconst readFromAAtIterationZero =\n\t\t\t\t\t\t\tpingPongPair && currentOutput ? currentOutput !== `${pingPongPair.target}B` : true;\n\n\t\t\t\t\t\tfor (let iter = 0; iter < iterations; iter += 1) {\n\t\t\t\t\t\t\tconst dispatch = computePass.resolveDispatch({\n\t\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t\t\theight,\n\t\t\t\t\t\t\t\ttime,\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tworkgroupSize\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst cPass = commandEncoder.beginComputePass();\n\t\t\t\t\t\t\tcPass.setPipeline(pipelineEntry.pipeline);\n\t\t\t\t\t\t\tcPass.setBindGroup(0, pipelineEntry.bindGroup);\n\t\t\t\t\t\t\tif (storageBindGroup) {\n\t\t\t\t\t\t\t\tcPass.setBindGroup(1, storageBindGroup);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (pingPongPair) {\n\t\t\t\t\t\t\t\tconst readFromA =\n\t\t\t\t\t\t\t\t\titer % 2 === 0 ? readFromAAtIterationZero : !readFromAAtIterationZero;\n\t\t\t\t\t\t\t\tcPass.setBindGroup(\n\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\tgetPingPongStorageTextureBindGroup(pingPongPair.target, readFromA)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else if (storageTextureBindGroup) {\n\t\t\t\t\t\t\t\tcPass.setBindGroup(2, storageTextureBindGroup);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcPass.dispatchWorkgroups(dispatch[0], dispatch[1], dispatch[2]);\n\t\t\t\t\t\t\tcPass.end();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (computePass.isPingPong && computePass.advanceFrame) {\n\t\t\t\t\t\t\tcomputePass.advanceFrame();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst scenePass = commandEncoder.beginRenderPass({\n\t\t\t\tcolorAttachments: [\n\t\t\t\t\t{\n\t\t\t\t\t\tview: sceneOutput.view,\n\t\t\t\t\t\tclearValue: {\n\t\t\t\t\t\t\tr: clearColor[0],\n\t\t\t\t\t\t\tg: clearColor[1],\n\t\t\t\t\t\t\tb: clearColor[2],\n\t\t\t\t\t\t\ta: clearColor[3]\n\t\t\t\t\t\t},\n\t\t\t\t\t\tloadOp: 'clear',\n\t\t\t\t\t\tstoreOp: 'store'\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t});\n\n\t\t\tscenePass.setPipeline(pipeline);\n\t\t\tscenePass.setBindGroup(0, bindGroup);\n\t\t\tif (fragmentStorageBindGroup) {\n\t\t\t\tscenePass.setBindGroup(1, fragmentStorageBindGroup);\n\t\t\t}\n\t\t\tscenePass.draw(3);\n\t\t\tscenePass.end();\n\n\t\t\tif (slots) {\n\t\t\t\tconst resolveStepSurface = (\n\t\t\t\t\tslot: RenderPassInputSlot | RenderPassOutputSlot\n\t\t\t\t): RenderTarget => {\n\t\t\t\t\tif (slot === 'source') {\n\t\t\t\t\t\treturn slots.source;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (slot === 'target') {\n\t\t\t\t\t\treturn slots.target;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (slot === 'canvas') {\n\t\t\t\t\t\treturn slots.canvas;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst named = runtimeTargets[slot];\n\t\t\t\t\tif (!named) {\n\t\t\t\t\t\tthrow new Error(`Render graph references unknown runtime target \"${slot}\".`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn named;\n\t\t\t\t};\n\n\t\t\t\tfor (const step of graphPlan.steps) {\n\t\t\t\t\t// Compute passes already dispatched above\n\t\t\t\t\tif (step.kind === 'compute') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst input = resolveStepSurface(step.input);\n\t\t\t\t\tconst output = resolveStepSurface(step.output);\n\n\t\t\t\t\t(step.pass as RenderPass).render({\n\t\t\t\t\t\tdevice,\n\t\t\t\t\t\tcommandEncoder,\n\t\t\t\t\t\tsource: slots.source,\n\t\t\t\t\t\ttarget: slots.target,\n\t\t\t\t\t\tcanvas: slots.canvas,\n\t\t\t\t\t\tinput,\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\ttargets: runtimeTargets,\n\t\t\t\t\t\ttime,\n\t\t\t\t\t\tdelta,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\theight,\n\t\t\t\t\t\tclear: step.clear,\n\t\t\t\t\t\tclearColor: step.clearColor,\n\t\t\t\t\t\tpreserve: step.preserve,\n\t\t\t\t\t\tbeginRenderPass: (passOptions?: {\n\t\t\t\t\t\t\tclear?: boolean;\n\t\t\t\t\t\t\tclearColor?: [number, number, number, number];\n\t\t\t\t\t\t\tpreserve?: boolean;\n\t\t\t\t\t\t\tview?: GPUTextureView;\n\t\t\t\t\t\t}) => {\n\t\t\t\t\t\t\tconst clear = passOptions?.clear ?? step.clear;\n\t\t\t\t\t\t\tconst clearColor = passOptions?.clearColor ?? step.clearColor;\n\t\t\t\t\t\t\tconst preserve = passOptions?.preserve ?? step.preserve;\n\n\t\t\t\t\t\t\treturn commandEncoder.beginRenderPass({\n\t\t\t\t\t\t\t\tcolorAttachments: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tview: passOptions?.view ?? output.view,\n\t\t\t\t\t\t\t\t\t\tclearValue: {\n\t\t\t\t\t\t\t\t\t\t\tr: clearColor[0],\n\t\t\t\t\t\t\t\t\t\t\tg: clearColor[1],\n\t\t\t\t\t\t\t\t\t\t\tb: clearColor[2],\n\t\t\t\t\t\t\t\t\t\t\ta: clearColor[3]\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tloadOp: clear ? 'clear' : 'load',\n\t\t\t\t\t\t\t\t\t\tstoreOp: preserve ? 'store' : 'discard'\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif (step.needsSwap) {\n\t\t\t\t\t\tconst previousSource = slots.source;\n\t\t\t\t\t\tslots.source = slots.target;\n\t\t\t\t\t\tslots.target = previousSource;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (graphPlan.finalOutput !== 'canvas') {\n\t\t\t\t\tconst finalSurface = resolveStepSurface(graphPlan.finalOutput);\n\t\t\t\t\tblitToCanvas(commandEncoder, finalSurface.view, slots.canvas.view, clearColor);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdevice.queue.submit([commandEncoder.finish()]);\n\t\t};\n\n\t\tacceptInitializationCleanups = false;\n\t\tinitializationCleanups.length = 0;\n\t\treturn {\n\t\t\trender,\n\t\t\tgetStorageBuffer: (name: string): GPUBuffer | undefined => {\n\t\t\t\treturn storageBufferMap.get(name);\n\t\t\t},\n\t\t\tgetDevice: (): GPUDevice => {\n\t\t\t\treturn device;\n\t\t\t},\n\t\t\tdestroy: () => {\n\t\t\t\tisDestroyed = true;\n\t\t\t\tdevice.removeEventListener('uncapturederror', handleUncapturedError);\n\t\t\t\tframeBuffer.destroy();\n\t\t\t\tuniformBuffer.destroy();\n\t\t\t\tfor (const buffer of storageBufferMap.values()) {\n\t\t\t\t\tbuffer.destroy();\n\t\t\t\t}\n\t\t\t\tstorageBufferMap.clear();\n\t\t\t\tfor (const pair of pingPongTexturePairs.values()) {\n\t\t\t\t\tpair.textureA.destroy();\n\t\t\t\t\tpair.textureB.destroy();\n\t\t\t\t}\n\t\t\t\tpingPongTexturePairs.clear();\n\t\t\t\tcomputePipelineCache.clear();\n\t\t\t\tdestroyRenderTexture(sourceSlotTarget);\n\t\t\t\tdestroyRenderTexture(targetSlotTarget);\n\t\t\t\tfor (const target of runtimeRenderTargets.values()) {\n\t\t\t\t\ttarget.texture.destroy();\n\t\t\t\t}\n\t\t\t\truntimeRenderTargets.clear();\n\t\t\t\tfor (const pass of activePasses) {\n\t\t\t\t\tpass.dispose?.();\n\t\t\t\t}\n\t\t\t\tactivePasses.length = 0;\n\t\t\t\tlifecyclePassesRef = null;\n\t\t\t\tfor (const binding of textureBindings) {\n\t\t\t\t\tbinding.texture?.destroy();\n\t\t\t\t\tbinding.fallbackTexture.destroy();\n\t\t\t\t}\n\t\t\t\tblitBindGroupByView = new WeakMap();\n\t\t\t\tcachedGraphPlan = null;\n\t\t\t\tcachedGraphPasses.length = 0;\n\t\t\t\trenderTargetSnapshot = {};\n\t\t\t\trenderTargetKeys = [];\n\t\t\t}\n\t\t};\n\t} catch (error) {\n\t\tisDestroyed = true;\n\t\tacceptInitializationCleanups = false;\n\t\tdevice.removeEventListener('uncapturederror', handleUncapturedError);\n\t\trunInitializationCleanups();\n\t\tthrow error;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import type { CurrentReadable, CurrentWritable } from './current-value.js';
|
|
|
3
3
|
import { type FragMaterial } from './material.js';
|
|
4
4
|
import { type MotionGPUErrorReport } from './error-report.js';
|
|
5
5
|
import type { FrameRegistry } from './frame-registry.js';
|
|
6
|
-
import type { FrameInvalidationToken, OutputColorSpace,
|
|
6
|
+
import type { AnyPass, FrameInvalidationToken, OutputColorSpace, RenderTargetDefinitionMap } from './types.js';
|
|
7
7
|
export interface MotionGPURuntimeLoopOptions {
|
|
8
8
|
canvas: HTMLCanvasElement;
|
|
9
9
|
registry: FrameRegistry;
|
|
@@ -15,7 +15,7 @@ export interface MotionGPURuntimeLoopOptions {
|
|
|
15
15
|
maxDelta: CurrentReadable<number>;
|
|
16
16
|
getMaterial: () => FragMaterial;
|
|
17
17
|
getRenderTargets: () => RenderTargetDefinitionMap;
|
|
18
|
-
getPasses: () =>
|
|
18
|
+
getPasses: () => AnyPass[];
|
|
19
19
|
getClearColor: () => [number, number, number, number];
|
|
20
20
|
getOutputColorSpace: () => OutputColorSpace;
|
|
21
21
|
getAdapterOptions: () => GPURequestAdapterOptions | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-loop.d.ts","sourceRoot":"","sources":["../../src/lib/core/runtime-loop.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAmB,KAAK,YAAY,EAAyB,MAAM,eAAe,CAAC;AAC1F,OAAO,EAGN,KAAK,oBAAoB,EACzB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EACX,sBAAsB,EACtB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"runtime-loop.d.ts","sourceRoot":"","sources":["../../src/lib/core/runtime-loop.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAmB,KAAK,YAAY,EAAyB,MAAM,eAAe,CAAC;AAC1F,OAAO,EAGN,KAAK,oBAAoB,EACzB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EACX,OAAO,EACP,sBAAsB,EACtB,gBAAgB,EAGhB,yBAAyB,EAMzB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,2BAA2B;IAC3C,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,eAAe,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC7B,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,YAAY,CAAC;IAChC,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;IAClD,SAAS,EAAE,MAAM,OAAO,EAAE,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;IAC5C,iBAAiB,EAAE,MAAM,wBAAwB,GAAG,SAAS,CAAC;IAC9D,mBAAmB,EAAE,MAAM,mBAAmB,GAAG,SAAS,CAAC;IAC3D,UAAU,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACvE,WAAW,EAAE,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3D,oBAAoB,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAChD,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,oBAAoB,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAClF,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,KAAK,IAAI,CAAC;CAC/D;AAED,MAAM,WAAW,oBAAoB;IACpC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACrD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACpB;AAMD,wBAAgB,0BAA0B,CACzC,OAAO,EAAE,2BAA2B,GAClC,oBAAoB,CA8dtB"}
|
|
@@ -36,6 +36,10 @@ function createMotionGPURuntimeLoop(options) {
|
|
|
36
36
|
width: 0,
|
|
37
37
|
height: 0
|
|
38
38
|
};
|
|
39
|
+
let storageBufferKeys = [];
|
|
40
|
+
let storageBufferKeySet = /* @__PURE__ */ new Set();
|
|
41
|
+
let storageBufferDefinitions = {};
|
|
42
|
+
const pendingStorageWrites = [];
|
|
39
43
|
let shouldContinueAfterFrame = false;
|
|
40
44
|
let activeErrorKey = null;
|
|
41
45
|
let errorHistory = [];
|
|
@@ -127,6 +131,9 @@ function createMotionGPURuntimeLoop(options) {
|
|
|
127
131
|
textureKeys = materialState.textureKeys;
|
|
128
132
|
uniformKeySet = new Set(uniformKeys);
|
|
129
133
|
textureKeySet = new Set(textureKeys);
|
|
134
|
+
storageBufferKeys = materialState.storageBufferKeys;
|
|
135
|
+
storageBufferKeySet = new Set(storageBufferKeys);
|
|
136
|
+
storageBufferDefinitions = options.getMaterial().storageBuffers ?? {};
|
|
130
137
|
resetRuntimeMaps();
|
|
131
138
|
resetRenderPayloadMaps();
|
|
132
139
|
activeMaterialSignature = materialState.signature;
|
|
@@ -145,6 +152,41 @@ function createMotionGPURuntimeLoop(options) {
|
|
|
145
152
|
if (!textureKeySet.has(name)) throw new Error(`Unknown texture "${name}". Declare it in material.textures first.`);
|
|
146
153
|
runtimeTextures[name] = value;
|
|
147
154
|
};
|
|
155
|
+
const writeStorageBuffer = (name, data, writeOptions) => {
|
|
156
|
+
if (!storageBufferKeySet.has(name)) throw new Error(`Unknown storage buffer "${name}". Declare it in material.storageBuffers first.`);
|
|
157
|
+
const definition = storageBufferDefinitions[name];
|
|
158
|
+
if (!definition) throw new Error(`Missing definition for storage buffer "${name}".`);
|
|
159
|
+
const offset = writeOptions?.offset ?? 0;
|
|
160
|
+
if (offset < 0 || offset + data.byteLength > definition.size) throw new Error(`Storage buffer "${name}" write out of bounds: offset=${offset}, dataSize=${data.byteLength}, bufferSize=${definition.size}.`);
|
|
161
|
+
pendingStorageWrites.push({
|
|
162
|
+
name,
|
|
163
|
+
data,
|
|
164
|
+
offset
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
const readStorageBuffer = (name) => {
|
|
168
|
+
if (!storageBufferKeySet.has(name)) throw new Error(`Unknown storage buffer "${name}". Declare it in material.storageBuffers first.`);
|
|
169
|
+
if (!renderer) return Promise.reject(/* @__PURE__ */ new Error(`Cannot read storage buffer "${name}": renderer not initialized.`));
|
|
170
|
+
const gpuBuffer = renderer.getStorageBuffer?.(name);
|
|
171
|
+
if (!gpuBuffer) return Promise.reject(/* @__PURE__ */ new Error(`Storage buffer "${name}" not allocated on GPU.`));
|
|
172
|
+
const device = renderer.getDevice?.();
|
|
173
|
+
if (!device) return Promise.reject(/* @__PURE__ */ new Error("Cannot read storage buffer: GPU device unavailable."));
|
|
174
|
+
const definition = storageBufferDefinitions[name];
|
|
175
|
+
if (!definition) return Promise.reject(/* @__PURE__ */ new Error(`Missing definition for storage buffer "${name}".`));
|
|
176
|
+
const stagingBuffer = device.createBuffer({
|
|
177
|
+
size: definition.size,
|
|
178
|
+
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
|
|
179
|
+
});
|
|
180
|
+
const commandEncoder = device.createCommandEncoder();
|
|
181
|
+
commandEncoder.copyBufferToBuffer(gpuBuffer, 0, stagingBuffer, 0, definition.size);
|
|
182
|
+
device.queue.submit([commandEncoder.finish()]);
|
|
183
|
+
return stagingBuffer.mapAsync(GPUMapMode.READ).then(() => {
|
|
184
|
+
const result = stagingBuffer.getMappedRange().slice(0);
|
|
185
|
+
stagingBuffer.unmap();
|
|
186
|
+
stagingBuffer.destroy();
|
|
187
|
+
return result;
|
|
188
|
+
});
|
|
189
|
+
};
|
|
148
190
|
const renderFrame = (timestamp) => {
|
|
149
191
|
frameId = null;
|
|
150
192
|
if (isDisposed) return;
|
|
@@ -188,6 +230,9 @@ function createMotionGPURuntimeLoop(options) {
|
|
|
188
230
|
uniformLayout: materialState.uniformLayout,
|
|
189
231
|
textureKeys: materialState.textureKeys,
|
|
190
232
|
textureDefinitions: materialState.textures,
|
|
233
|
+
storageBufferKeys: materialState.storageBufferKeys,
|
|
234
|
+
storageBufferDefinitions,
|
|
235
|
+
storageTextureKeys: materialState.storageTextureKeys,
|
|
191
236
|
getRenderTargets: options.getRenderTargets,
|
|
192
237
|
getPasses: options.getPasses,
|
|
193
238
|
outputColorSpace,
|
|
@@ -241,6 +286,8 @@ function createMotionGPURuntimeLoop(options) {
|
|
|
241
286
|
delta,
|
|
242
287
|
setUniform,
|
|
243
288
|
setTexture,
|
|
289
|
+
writeStorageBuffer,
|
|
290
|
+
readStorageBuffer,
|
|
244
291
|
invalidate,
|
|
245
292
|
advance,
|
|
246
293
|
renderMode: registry.getRenderMode(),
|
|
@@ -266,7 +313,8 @@ function createMotionGPURuntimeLoop(options) {
|
|
|
266
313
|
renderMode: registry.getRenderMode(),
|
|
267
314
|
uniforms: renderUniforms,
|
|
268
315
|
textures: renderTextures,
|
|
269
|
-
canvasSize
|
|
316
|
+
canvasSize,
|
|
317
|
+
...pendingStorageWrites.length > 0 ? { pendingStorageWrites: pendingStorageWrites.splice(0) } : {}
|
|
270
318
|
});
|
|
271
319
|
}
|
|
272
320
|
clearError();
|