@zephyr3d/editor 0.3.0 → 0.3.1

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.
Files changed (48) hide show
  1. package/README.md +143 -0
  2. package/dist/assets/{index-BaUzUcND.js → index-IISR7uQv.js} +1 -1
  3. package/dist/assistant/zephyr-types-index.json +1 -1
  4. package/dist/index.html +2 -2
  5. package/dist/modules/zephyr3d_backend-webgpu.js.map +1 -1
  6. package/dist/modules/zephyr3d_imgui.js +3 -3
  7. package/dist/modules/zephyr3d_imgui.js.map +1 -1
  8. package/dist/modules/zephyr3d_scene.js +1439 -1439
  9. package/dist/modules/zephyr3d_scene.js.map +1 -1
  10. package/dist/vendor/zephyr3d/backend-webgpu/dist/bindgroup_webgpu.js.map +1 -1
  11. package/dist/vendor/zephyr3d/backend-webgpu/dist/buffer_webgpu.js.map +1 -1
  12. package/dist/vendor/zephyr3d/backend-webgpu/dist/commandqueue.js.map +1 -1
  13. package/dist/vendor/zephyr3d/backend-webgpu/dist/uploadringbuffer.js.map +1 -1
  14. package/dist/vendor/zephyr3d/imgui/dist/imgui_impl.js.map +1 -1
  15. package/dist/vendor/zephyr3d/imgui/dist/renderer.js +3 -3
  16. package/dist/vendor/zephyr3d/imgui/dist/renderer.js.map +1 -1
  17. package/dist/vendor/zephyr3d/scene/dist/animation/animationset.js +135 -135
  18. package/dist/vendor/zephyr3d/scene/dist/animation/animationset.js.map +1 -1
  19. package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics/controller.js +146 -146
  20. package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics/controller.js.map +1 -1
  21. package/dist/vendor/zephyr3d/scene/dist/animation/spring/spring_system.js +75 -75
  22. package/dist/vendor/zephyr3d/scene/dist/animation/spring/spring_system.js.map +1 -1
  23. package/dist/vendor/zephyr3d/scene/dist/camera/camera.js +184 -184
  24. package/dist/vendor/zephyr3d/scene/dist/camera/camera.js.map +1 -1
  25. package/dist/vendor/zephyr3d/scene/dist/material/material.js +288 -288
  26. package/dist/vendor/zephyr3d/scene/dist/material/material.js.map +1 -1
  27. package/dist/vendor/zephyr3d/scene/dist/render/rendergraph/history_resource_manager.js +93 -93
  28. package/dist/vendor/zephyr3d/scene/dist/render/rendergraph/history_resource_manager.js.map +1 -1
  29. package/dist/vendor/zephyr3d/scene/dist/render/rendergraph/history_resources.js +3 -3
  30. package/dist/vendor/zephyr3d/scene/dist/render/rendergraph/history_resources.js.map +1 -1
  31. package/dist/vendor/zephyr3d/scene/dist/render/rendergraph/types.js +22 -22
  32. package/dist/vendor/zephyr3d/scene/dist/render/rendergraph/types.js.map +1 -1
  33. package/dist/vendor/zephyr3d/scene/dist/utility/blueprint/material/ir.js +489 -489
  34. package/dist/vendor/zephyr3d/scene/dist/utility/blueprint/material/ir.js.map +1 -1
  35. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/animation.js.map +1 -1
  36. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/camera.js.map +1 -1
  37. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/common.js.map +1 -1
  38. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/light.js.map +1 -1
  39. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/material.js.map +1 -1
  40. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/mesh.js.map +1 -1
  41. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/node.js.map +1 -1
  42. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/particle.js.map +1 -1
  43. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/primitive.js.map +1 -1
  44. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/scene.js.map +1 -1
  45. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/terrain.js.map +1 -1
  46. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/types.js +4 -4
  47. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/types.js.map +1 -1
  48. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"material.js","sources":["../../src/material/material.ts"],"sourcesContent":["import type { AbstractDevice, BindGroup, GPUProgram, RenderStateSet } from '@zephyr3d/device';\nimport { ProgramBuilder } from '@zephyr3d/device';\nimport type { Primitive } from '../render/primitive';\nimport type { DrawContext } from '../render/drawable';\nimport { QUEUE_OPAQUE } from '../values';\nimport { RenderBundleWrapper } from '../render/renderbundle_wrapper';\nimport { Disposable } from '@zephyr3d/base';\nimport type { Clonable, IDisposable, Nullable } from '@zephyr3d/base';\nimport { getEngine } from '../app/api';\n\ntype MaterialState = {\n program: GPUProgram;\n bindGroup: Nullable<BindGroup>;\n bindGroupTag: string;\n renderStateSet: RenderStateSet;\n materialTag: number;\n};\n\n/**\n * Base class for all materials.\n *\n * Responsibilities:\n * - Defines a multi-pass rendering interface (`numPasses`, `apply`, `bind`, `draw`, `drawPrimitive`).\n * - Builds and caches GPU shader programs per pass and per-render-context hash.\n * - Manages a per-material bind group (typically at index 2) for uniforms and resources.\n * - Updates render states per pass (`updateRenderStates`) and uploads uniforms (`_applyUniforms`).\n * - Tracks \"option\" changes that affect shader variant hashing and render bundles.\n *\n * Caching and hashing:\n * - `createHash(pass)` produces a stable hash representing shader variant options for a pass.\n * Override `_createHash()` in subclasses to encode feature toggles (defines, keywords, macros).\n * - The global hash used to key `MaterialState` also includes `ctx.materialFlags` and\n * `ctx.renderPassHash`, allowing context-sensitive variants (e.g., MSAA, MRT layout).\n * - GPU programs are additionally memoized in a global static `_programCache` across materials\n * by `constructor.name` + hash, to avoid recompilation of identical variants.\n *\n * Bind groups and uniforms:\n * - If a program declares a bind group layout at index 2 (i.e., `bindGroupLayouts.length > 2`),\n * `apply()` will allocate the group and keep it in the state. Subclasses should fill it in\n * `_applyUniforms()`.\n * - `applyUniforms()` only calls `_applyUniforms()` when `needUpdate` is true, based on\n * `_optionTag` changes (see `optionChanged()`).\n *\n * Lifecycle:\n * - Constructed materials register a persistent ID into a global registry for serialization.\n * - `apply(ctx)` prepares all passes: creates/gets state, programs, bind groups, render states,\n * and uploads uniforms as needed.\n * - `bind(device, pass)` binds the program, bind group (index 2), and render states.\n * - `draw(primitive, ctx, numInstances)` runs all passes, calling `bind()` and `drawPrimitive()`.\n * - `onDispose()` releases bind groups and registry entries.\n *\n * Extending:\n * - Override `_createProgram(pb, ctx, pass)` to build a shader.\n * - Override `_applyUniforms(bindGroup, ctx, pass)` to upload uniforms and resources.\n * - Override `updateRenderStates(pass, renderStates, ctx)` to set depth, blend, cull, etc.\n * - Override `_createHash()` to encode options that affect program compilation.\n * - Override `supportLighting`, `supportInstancing`, `isTransparentPass`, `getQueueType`, etc.\n *\n * Thread-safety:\n * - Intended for main-thread use in a renderer driving WebGPU/WebGL-like devices.\n *\n * @public\n */\nexport class Material extends Disposable implements Clonable<Material>, IDisposable {\n /**\n * Monotonic instance ID counter.\n * @internal\n */\n private static _nextId = 0;\n /**\n * Global program cache keyed by global hash\n */\n private static _programCache: { [hash: string]: GPUProgram } = {};\n /**\n * Per-material state cache keyed by global hash (material + context + pass).\n * @internal\n */\n private _states: { [hash: string]: MaterialState };\n /**\n * Number of rendering passes.\n * Subclasses can increase this to implement multi-pass rendering.\n * @internal\n */\n protected _numPasses: number;\n /**\n * Per-pass hash cached results. Length scales with `numPasses`.\n * @internal\n */\n protected _hash: Nullable<string>[];\n /**\n * Incremented each time options change (via `optionChanged`), used to decide whether\n * uniforms need update on next `apply()`.\n * @internal\n */\n private _optionTag: number;\n /**\n * Unique runtime instance ID.\n * @internal\n */\n protected readonly _id: number;\n /**\n * Latest computed global hash per pass, set during `apply()`, read in `bind()`.\n * @internal\n */\n private _currentHash: string[];\n /**\n * Incremented when material states affecting render bundles change (e.g., bind group id changes\n * or `optionChanged(true)`), used to trigger re-recording of render bundles.\n * @internal\n */\n private _changeTag: number;\n /**\n * Unique program id counter for naming compiled programs.\n * @internal\n */\n private _nextProgramId = 0;\n /**\n * Create a new material instance.\n *\n * - Initializes one pass by default.\n * - Prepares per-pass hash storage and change tracking.\n * - Registers a persistent ID in the global registry.\n */\n constructor() {\n super();\n this._id = ++Material._nextId;\n this._nextProgramId = 0;\n this._states = {};\n this._numPasses = 1;\n this._hash = [null];\n this._optionTag = 0;\n this._changeTag = 0;\n this._currentHash = [];\n }\n /**\n * Create a shallow clone of this material.\n *\n * Note: The base implementation returns a base `Material`. Subclasses should\n * override to return their own type and copy custom fields.\n */\n clone() {\n const other = new Material();\n other.copyFrom(this);\n return other;\n }\n /**\n * Copy basic properties from another material.\n *\n * Disposes existing bind groups/states, copies `numPasses`. Subclasses should\n * extend this to copy their own fields and call `optionChanged(true)` if\n * shader-affecting options differ.\n *\n * @param other - Source material.\n */\n copyFrom(other: this) {\n this.clearCache();\n this._numPasses = other._numPasses;\n getEngine().resourceManager.setAssetId(this, getEngine().resourceManager.getAssetId(other.coreMaterial));\n }\n /**\n * Incremented when the material’s GPU-relevant state changes and render bundles\n * may need to be rebuilt.\n */\n get changeTag() {\n return this._changeTag;\n }\n /**\n * Runtime-unique numeric identifier for the material instance.\n */\n get instanceId() {\n return this._id;\n }\n /**\n * Number of rendering passes this material uses.\n *\n * Increasing this will expand the per-pass hash cache; make sure to implement\n * `createHash(pass)`, `_createProgram(pb, ctx, pass)`, and `updateRenderStates(pass, ...)`\n * accordingly for each pass.\n */\n get numPasses() {\n return this._numPasses;\n }\n set numPasses(val) {\n while (this._hash.length < val) {\n this._hash.push(null);\n }\n this._numPasses = val;\n }\n /**\n * Get or compute the per-pass shader hash used for program caching.\n *\n * Calls `createHash(pass)` lazily and caches the result.\n * @internal\n */\n protected getHash(pass: number) {\n if (this._hash[pass] === null) {\n this._hash[pass] = this.createHash(pass);\n }\n return this._hash[pass];\n }\n /**\n * Return the queue type to which this material belongs.\n *\n * Override this in transparent or special materials (e.g., post-process).\n */\n getQueueType(): number {\n return QUEUE_OPAQUE;\n }\n /**\n * Whether the given pass is transparent.\n *\n * Used to place draw calls into appropriate render queues and set blending states.\n */\n isTransparentPass(_pass: number): boolean {\n return false;\n }\n /**\n * Whether this material's shading is affected by scene lights.\n *\n * Override and return `false` for unlit materials.\n */\n supportLighting(): boolean {\n return true;\n }\n /**\n * Whether this material supports hardware instancing.\n *\n * Override and return `false` if per-instance data is not supported in the shader.\n */\n supportInstancing(): boolean {\n return true;\n }\n /** Returns true if this is a instance of material */\n isBatchable(): boolean {\n return false;\n }\n\n /**\n * Whether this material requires the scene color texture (e.g., for refraction).\n */\n needSceneColor(): boolean {\n return false;\n }\n /**\n * Whether this material requires the linear scene depth texture (e.g., for depth-aware effects).\n */\n needSceneDepth(): boolean {\n return false;\n }\n /**\n * Create a material instance (instance-uniform-driven variant).\n *\n * Base returns `null`. Subclasses that support instancing can return a lightweight instance.\n */\n createInstance(): this {\n throw new Error('Abstract function call');\n }\n /**\n * Returns the core material that owns GPU state.\n *\n * Instances may delegate to a shared core to reuse compiled programs and caches.\n * @public\n */\n get coreMaterial(): this {\n return this;\n }\n /**\n * Prepare the material for drawing across all passes for the given draw context.\n *\n * Steps per pass:\n * - Compute global hash (material variant + context).\n * - Retrieve or build the GPU program, cache in `_programCache`.\n * - Create per-material bind group (index 2) if the program exposes it.\n * - Update uniforms if `_optionTag` indicates changes since last apply.\n * - Update and cache render states for the pass.\n * - Detect bind group GPU ID changes to bump `changeTag` and notify `RenderBundleWrapper`.\n *\n * @param ctx - Draw context (device, flags, pass hash, instance data, etc.).\n * @returns `true` if successful; `false` if any pass lacks a valid program.\n */\n apply(ctx: DrawContext) {\n for (let pass = 0; pass < this._numPasses; pass++) {\n const hash = this.calcGlobalHash(ctx, pass);\n let state = this._states[hash];\n if (!state) {\n let program = Material._programCache[hash];\n if (!program) {\n program = this.createProgram(ctx, pass) ?? null;\n program.name = `@${this.constructor.name}_program_${this._nextProgramId++}`;\n Material._programCache[hash] = program;\n }\n const bindGroup =\n program.bindGroupLayouts.length > 2\n ? ctx.device.createBindGroup(program.bindGroupLayouts[2])\n : null;\n state = {\n program,\n bindGroup,\n bindGroupTag: bindGroup?.getGPUId() ?? '',\n renderStateSet: ctx.device.createRenderStateSet(),\n materialTag: -1\n };\n this._states[hash] = state;\n }\n if (!state.program) {\n return false;\n }\n if (state.bindGroup) {\n this.applyUniforms(state.bindGroup, ctx, state.materialTag !== this._optionTag, pass);\n }\n state.materialTag = this._optionTag;\n this.updateRenderStates(pass, state.renderStateSet, ctx);\n this._currentHash[pass] = hash;\n if (state.bindGroup) {\n const id = state.bindGroup.getGPUId();\n if (id !== state.bindGroupTag) {\n state.bindGroupTag = id;\n this._changeTag++;\n RenderBundleWrapper.materialChanged(this.coreMaterial);\n }\n }\n }\n return true;\n }\n /**\n * Bind the program, bind group, and render states for the specified pass.\n *\n * Must be called after `apply(ctx)` for the same pass.\n *\n * @param device - Rendering device.\n * @param pass - Pass index to bind.\n * @returns `true` on success; `false` if state or program missing.\n * @internal\n */\n bind(device: AbstractDevice, pass: number) {\n const hash = this._currentHash[pass];\n const state = this._states[hash];\n if (!state) {\n console.error('Material.bind() failed: state not found');\n return false;\n }\n if (!state.program) {\n return false;\n }\n device.setProgram(state.program);\n if (state.bindGroup) {\n device.setBindGroup(2, state.bindGroup);\n }\n device.setRenderStates(state.renderStateSet);\n return true;\n }\n /**\n * Compute the global hash for the given pass and draw context.\n *\n * Includes:\n * - Per-pass material hash from `getHash(pass)`.\n * - `ctx.materialFlags` for context-dependent toggles.\n * - `ctx.renderPassHash` for framebuffer/attachment layout variants.\n * @internal\n */\n private calcGlobalHash(ctx: DrawContext, pass: number) {\n return `${this.getHash(pass)}:${ctx.materialFlags}:${ctx.renderPassHash}`;\n }\n /**\n * Draw a primitive for all passes using this material.\n *\n * Calls `bind()` then `drawPrimitive()` per pass. If `numInstances` is zero,\n * and `ctx.instanceData` exists, uses `ctx.instanceData.numInstances`.\n *\n * @param primitive - Geometry to draw.\n * @param ctx - Draw context.\n * @param numInstances - Instance count; 0 means auto-detect from context.\n * @internal\n */\n draw(primitive: Primitive, ctx: DrawContext, numInstances = 0) {\n for (let pass = 0; pass < this._numPasses; pass++) {\n this.bind(ctx.device, pass);\n this.drawPrimitive(pass, primitive, ctx, numInstances);\n }\n }\n /**\n * Conditionally update uniforms/resources into the material bind group.\n *\n * Delegates to `_applyUniforms()` when `needUpdate` is true (based on `_optionTag` check).\n *\n * @param bindGroup - Material bind group at index 2 (may be `null` if program has no layout).\n * @param ctx - Draw context.\n * @param needUpdate - Whether uniforms need to be refreshed.\n * @param pass - Pass index.\n */\n applyUniforms(bindGroup: BindGroup, ctx: DrawContext, needUpdate: boolean, pass: number) {\n if (needUpdate) {\n this._applyUniforms(bindGroup, ctx, pass);\n }\n }\n /**\n * Notify the material that some option changed.\n *\n * - Always increments `_optionTag`. This will trigger uniforms update on next `apply()`.\n * - If `changeHash` is true, clears per-pass hashes so programs/states will be rebuilt,\n * increments `_changeTag`, and notifies `RenderBundleWrapper` to regenerate recorded bundles.\n *\n * @param changeHash - Set true if the change affects shader compilation or render states.\n * @internal\n */\n optionChanged(changeHash: boolean) {\n this._optionTag++;\n if (changeHash) {\n for (let i = 0; i < this._numPasses; i++) {\n this._hash[i] = null;\n }\n this._changeTag++;\n RenderBundleWrapper.materialChanged(this.coreMaterial);\n }\n }\n clearCache() {\n for (const k in this._states) {\n this._states[k]?.bindGroup?.dispose();\n Material._programCache[k]?.dispose();\n delete Material._programCache[k];\n }\n this._states = {};\n }\n /**\n * Convert a pass index to a hash seed string.\n *\n * Subclasses may override to encode per-pass role (e.g., \"depth\", \"forward\", \"shadow\").\n *\n * @param pass - Pass number.\n * @returns String used when building full hash.\n */\n passToHash(pass: number) {\n return String(pass);\n }\n /**\n * Build the material hash for a pass (excluding context-dependent parts).\n *\n * Default formula: `${constructor.name}|${pass}|${_createHash()}`\n *\n * @param pass - Pass number.\n * @returns Hash string used in program caching.\n * @internal\n */\n createHash(pass: number) {\n return `${this.constructor.name}|${pass}|${this._createHash()}`;\n }\n /**\n * Issue the actual draw call for a pass.\n *\n * Override for custom per-pass draw behavior if necessary. The default implementation:\n * - Draws instanced if `numInstances > 0`.\n * - Else uses `ctx.instanceData.numInstances` if available.\n * - Else issues a non-instanced draw.\n *\n * @param pass - Pass number.\n * @param primitive - Primitive to draw.\n * @param ctx - Draw context.\n * @param numInstances - Explicit instance count (0 = auto).\n */\n drawPrimitive(pass: number, primitive: Primitive, ctx: DrawContext, numInstances: number) {\n if (numInstances > 0) {\n primitive.drawInstanced(numInstances);\n } else if (ctx.instanceData) {\n primitive.drawInstanced(ctx.instanceData.numInstances);\n } else {\n primitive.draw();\n }\n }\n /**\n * Dispose the material and release GPU-side resource references.\n *\n * - Unregisters from the global registry.\n * - Disposes the per-material bind groups kept in `_states`.\n */\n protected onDispose() {\n super.onDispose();\n this.clearCache();\n }\n /**\n * Build the GPU program for a pass.\n *\n * Default creates a `ProgramBuilder` and calls `_createProgram(pb, ctx, pass)`.\n * Subclasses should override `_createProgram` instead of this method unless\n * they need to replace builder instantiation.\n *\n * @param ctx - Draw context.\n * @param pass - Pass number.\n * @returns The compiled `GPUProgram`, or `null` on failure.\n * @internal\n */\n protected createProgram(ctx: DrawContext, pass: number) {\n const pb = new ProgramBuilder(ctx.device);\n return this._createProgram(pb, ctx, pass);\n }\n /**\n * Create and compile the shader program for this material/pass.\n *\n * Implement in subclasses:\n * - Define shader stages, entry points, macros/defines, and resource layouts.\n * - Return a compiled `GPUProgram`.\n *\n * @param pb - Program builder.\n * @param ctx - Draw context.\n * @param _pass - Pass number.\n * @returns The created program, or `null` on failure.\n */\n protected _createProgram(_pb: ProgramBuilder, _ctx: DrawContext, _pass: number): GPUProgram {\n throw new Error('Abstract function call');\n }\n /**\n * Upload uniforms and bind resources to the per-material bind group (index 2).\n *\n * Implement in subclasses to:\n * - Write uniform buffers/textures/samplers to the `bindGroup`.\n * - Respect the current `pass` and `ctx`.\n *\n * @param _bindGroup - The bind group to populate.\n * @param _ctx - Draw context.\n * @param _pass - Pass number.\n */\n protected _applyUniforms(_bindGroup: BindGroup, _ctx: DrawContext, _pass: number) {}\n /**\n * Update render states (depth/stencil, blending, rasterization) for the pass.\n *\n * Implement in subclasses based on transparency, double-sidedness, depth writes/tests,\n * color mask, stencil ops, etc., and any context flags in `ctx`.\n *\n * @param _pass - Current pass index.\n * @param _renderStates - Render state set to mutate.\n * @param _ctx - Draw context.\n */\n protected updateRenderStates(_pass: number, _renderStates: RenderStateSet, _ctx: DrawContext) {}\n /**\n * Compute the material-specific portion of the shader hash for the current options.\n *\n * Subclasses should override to include macro/define sets that influence program compilation.\n * Example return: `\"USE_NORMALMAP=1;ALPHA_MODE=BLEND;RECEIVE_SHADOWS=1\"`.\n *\n * @returns Hash fragment string (no context/pass info).\n */\n protected _createHash() {\n return '';\n }\n /**\n * Whether this is a lightweight instance of a core material.\n *\n * Instances typically share GPU programs with a core and only override instance uniforms.\n * @internal\n */\n get $isInstance(): boolean {\n return false;\n }\n /**\n * Instance-uniform buffer for material instances, if supported.\n *\n * Returned as a typed Float32 view over a backing ArrayBuffer.\n * @internal\n */\n get $instanceUniforms(): Float32Array<ArrayBuffer> {\n throw new Error('Abstract function call');\n }\n}\n"],"names":["Material","Disposable","_nextId","_programCache","_nextProgramId","_id","_states","_numPasses","_hash","_optionTag","_changeTag","_currentHash","clone","other","copyFrom","clearCache","getEngine","resourceManager","setAssetId","getAssetId","coreMaterial","changeTag","instanceId","numPasses","val","length","push","getHash","pass","createHash","getQueueType","QUEUE_OPAQUE","isTransparentPass","_pass","supportLighting","supportInstancing","isBatchable","needSceneColor","needSceneDepth","createInstance","Error","apply","ctx","hash","calcGlobalHash","state","program","createProgram","name","bindGroup","bindGroupLayouts","device","createBindGroup","bindGroupTag","getGPUId","renderStateSet","createRenderStateSet","materialTag","applyUniforms","updateRenderStates","id","RenderBundleWrapper","materialChanged","bind","console","error","setProgram","setBindGroup","setRenderStates","materialFlags","renderPassHash","draw","primitive","numInstances","drawPrimitive","needUpdate","_applyUniforms","optionChanged","changeHash","i","k","dispose","passToHash","String","_createHash","drawInstanced","instanceData","onDispose","pb","ProgramBuilder","_createProgram","_pb","_ctx","_bindGroup","_renderStates","$isInstance","$instanceUniforms"],"mappings":"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"}
1
+ {"version":3,"file":"material.js","sources":["../../src/material/material.ts"],"sourcesContent":["import type { AbstractDevice, BindGroup, GPUProgram, RenderStateSet } from '@zephyr3d/device';\r\nimport { ProgramBuilder } from '@zephyr3d/device';\r\nimport type { Primitive } from '../render/primitive';\r\nimport type { DrawContext } from '../render/drawable';\r\nimport { QUEUE_OPAQUE } from '../values';\r\nimport { RenderBundleWrapper } from '../render/renderbundle_wrapper';\r\nimport { Disposable } from '@zephyr3d/base';\r\nimport type { Clonable, IDisposable, Nullable } from '@zephyr3d/base';\r\nimport { getEngine } from '../app/api';\r\n\r\ntype MaterialState = {\r\n program: GPUProgram;\r\n bindGroup: Nullable<BindGroup>;\r\n bindGroupTag: string;\r\n renderStateSet: RenderStateSet;\r\n materialTag: number;\r\n};\r\n\r\n/**\r\n * Base class for all materials.\r\n *\r\n * Responsibilities:\r\n * - Defines a multi-pass rendering interface (`numPasses`, `apply`, `bind`, `draw`, `drawPrimitive`).\r\n * - Builds and caches GPU shader programs per pass and per-render-context hash.\r\n * - Manages a per-material bind group (typically at index 2) for uniforms and resources.\r\n * - Updates render states per pass (`updateRenderStates`) and uploads uniforms (`_applyUniforms`).\r\n * - Tracks \"option\" changes that affect shader variant hashing and render bundles.\r\n *\r\n * Caching and hashing:\r\n * - `createHash(pass)` produces a stable hash representing shader variant options for a pass.\r\n * Override `_createHash()` in subclasses to encode feature toggles (defines, keywords, macros).\r\n * - The global hash used to key `MaterialState` also includes `ctx.materialFlags` and\r\n * `ctx.renderPassHash`, allowing context-sensitive variants (e.g., MSAA, MRT layout).\r\n * - GPU programs are additionally memoized in a global static `_programCache` across materials\r\n * by `constructor.name` + hash, to avoid recompilation of identical variants.\r\n *\r\n * Bind groups and uniforms:\r\n * - If a program declares a bind group layout at index 2 (i.e., `bindGroupLayouts.length > 2`),\r\n * `apply()` will allocate the group and keep it in the state. Subclasses should fill it in\r\n * `_applyUniforms()`.\r\n * - `applyUniforms()` only calls `_applyUniforms()` when `needUpdate` is true, based on\r\n * `_optionTag` changes (see `optionChanged()`).\r\n *\r\n * Lifecycle:\r\n * - Constructed materials register a persistent ID into a global registry for serialization.\r\n * - `apply(ctx)` prepares all passes: creates/gets state, programs, bind groups, render states,\r\n * and uploads uniforms as needed.\r\n * - `bind(device, pass)` binds the program, bind group (index 2), and render states.\r\n * - `draw(primitive, ctx, numInstances)` runs all passes, calling `bind()` and `drawPrimitive()`.\r\n * - `onDispose()` releases bind groups and registry entries.\r\n *\r\n * Extending:\r\n * - Override `_createProgram(pb, ctx, pass)` to build a shader.\r\n * - Override `_applyUniforms(bindGroup, ctx, pass)` to upload uniforms and resources.\r\n * - Override `updateRenderStates(pass, renderStates, ctx)` to set depth, blend, cull, etc.\r\n * - Override `_createHash()` to encode options that affect program compilation.\r\n * - Override `supportLighting`, `supportInstancing`, `isTransparentPass`, `getQueueType`, etc.\r\n *\r\n * Thread-safety:\r\n * - Intended for main-thread use in a renderer driving WebGPU/WebGL-like devices.\r\n *\r\n * @public\r\n */\r\nexport class Material extends Disposable implements Clonable<Material>, IDisposable {\r\n /**\r\n * Monotonic instance ID counter.\r\n * @internal\r\n */\r\n private static _nextId = 0;\r\n /**\r\n * Global program cache keyed by global hash\r\n */\r\n private static _programCache: { [hash: string]: GPUProgram } = {};\r\n /**\r\n * Per-material state cache keyed by global hash (material + context + pass).\r\n * @internal\r\n */\r\n private _states: { [hash: string]: MaterialState };\r\n /**\r\n * Number of rendering passes.\r\n * Subclasses can increase this to implement multi-pass rendering.\r\n * @internal\r\n */\r\n protected _numPasses: number;\r\n /**\r\n * Per-pass hash cached results. Length scales with `numPasses`.\r\n * @internal\r\n */\r\n protected _hash: Nullable<string>[];\r\n /**\r\n * Incremented each time options change (via `optionChanged`), used to decide whether\r\n * uniforms need update on next `apply()`.\r\n * @internal\r\n */\r\n private _optionTag: number;\r\n /**\r\n * Unique runtime instance ID.\r\n * @internal\r\n */\r\n protected readonly _id: number;\r\n /**\r\n * Latest computed global hash per pass, set during `apply()`, read in `bind()`.\r\n * @internal\r\n */\r\n private _currentHash: string[];\r\n /**\r\n * Incremented when material states affecting render bundles change (e.g., bind group id changes\r\n * or `optionChanged(true)`), used to trigger re-recording of render bundles.\r\n * @internal\r\n */\r\n private _changeTag: number;\r\n /**\r\n * Unique program id counter for naming compiled programs.\r\n * @internal\r\n */\r\n private _nextProgramId = 0;\r\n /**\r\n * Create a new material instance.\r\n *\r\n * - Initializes one pass by default.\r\n * - Prepares per-pass hash storage and change tracking.\r\n * - Registers a persistent ID in the global registry.\r\n */\r\n constructor() {\r\n super();\r\n this._id = ++Material._nextId;\r\n this._nextProgramId = 0;\r\n this._states = {};\r\n this._numPasses = 1;\r\n this._hash = [null];\r\n this._optionTag = 0;\r\n this._changeTag = 0;\r\n this._currentHash = [];\r\n }\r\n /**\r\n * Create a shallow clone of this material.\r\n *\r\n * Note: The base implementation returns a base `Material`. Subclasses should\r\n * override to return their own type and copy custom fields.\r\n */\r\n clone() {\r\n const other = new Material();\r\n other.copyFrom(this);\r\n return other;\r\n }\r\n /**\r\n * Copy basic properties from another material.\r\n *\r\n * Disposes existing bind groups/states, copies `numPasses`. Subclasses should\r\n * extend this to copy their own fields and call `optionChanged(true)` if\r\n * shader-affecting options differ.\r\n *\r\n * @param other - Source material.\r\n */\r\n copyFrom(other: this) {\r\n this.clearCache();\r\n this._numPasses = other._numPasses;\r\n getEngine().resourceManager.setAssetId(this, getEngine().resourceManager.getAssetId(other.coreMaterial));\r\n }\r\n /**\r\n * Incremented when the material’s GPU-relevant state changes and render bundles\r\n * may need to be rebuilt.\r\n */\r\n get changeTag() {\r\n return this._changeTag;\r\n }\r\n /**\r\n * Runtime-unique numeric identifier for the material instance.\r\n */\r\n get instanceId() {\r\n return this._id;\r\n }\r\n /**\r\n * Number of rendering passes this material uses.\r\n *\r\n * Increasing this will expand the per-pass hash cache; make sure to implement\r\n * `createHash(pass)`, `_createProgram(pb, ctx, pass)`, and `updateRenderStates(pass, ...)`\r\n * accordingly for each pass.\r\n */\r\n get numPasses() {\r\n return this._numPasses;\r\n }\r\n set numPasses(val) {\r\n while (this._hash.length < val) {\r\n this._hash.push(null);\r\n }\r\n this._numPasses = val;\r\n }\r\n /**\r\n * Get or compute the per-pass shader hash used for program caching.\r\n *\r\n * Calls `createHash(pass)` lazily and caches the result.\r\n * @internal\r\n */\r\n protected getHash(pass: number) {\r\n if (this._hash[pass] === null) {\r\n this._hash[pass] = this.createHash(pass);\r\n }\r\n return this._hash[pass];\r\n }\r\n /**\r\n * Return the queue type to which this material belongs.\r\n *\r\n * Override this in transparent or special materials (e.g., post-process).\r\n */\r\n getQueueType(): number {\r\n return QUEUE_OPAQUE;\r\n }\r\n /**\r\n * Whether the given pass is transparent.\r\n *\r\n * Used to place draw calls into appropriate render queues and set blending states.\r\n */\r\n isTransparentPass(_pass: number): boolean {\r\n return false;\r\n }\r\n /**\r\n * Whether this material's shading is affected by scene lights.\r\n *\r\n * Override and return `false` for unlit materials.\r\n */\r\n supportLighting(): boolean {\r\n return true;\r\n }\r\n /**\r\n * Whether this material supports hardware instancing.\r\n *\r\n * Override and return `false` if per-instance data is not supported in the shader.\r\n */\r\n supportInstancing(): boolean {\r\n return true;\r\n }\r\n /** Returns true if this is a instance of material */\r\n isBatchable(): boolean {\r\n return false;\r\n }\r\n\r\n /**\r\n * Whether this material requires the scene color texture (e.g., for refraction).\r\n */\r\n needSceneColor(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Whether this material requires the linear scene depth texture (e.g., for depth-aware effects).\r\n */\r\n needSceneDepth(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Create a material instance (instance-uniform-driven variant).\r\n *\r\n * Base returns `null`. Subclasses that support instancing can return a lightweight instance.\r\n */\r\n createInstance(): this {\r\n throw new Error('Abstract function call');\r\n }\r\n /**\r\n * Returns the core material that owns GPU state.\r\n *\r\n * Instances may delegate to a shared core to reuse compiled programs and caches.\r\n * @public\r\n */\r\n get coreMaterial(): this {\r\n return this;\r\n }\r\n /**\r\n * Prepare the material for drawing across all passes for the given draw context.\r\n *\r\n * Steps per pass:\r\n * - Compute global hash (material variant + context).\r\n * - Retrieve or build the GPU program, cache in `_programCache`.\r\n * - Create per-material bind group (index 2) if the program exposes it.\r\n * - Update uniforms if `_optionTag` indicates changes since last apply.\r\n * - Update and cache render states for the pass.\r\n * - Detect bind group GPU ID changes to bump `changeTag` and notify `RenderBundleWrapper`.\r\n *\r\n * @param ctx - Draw context (device, flags, pass hash, instance data, etc.).\r\n * @returns `true` if successful; `false` if any pass lacks a valid program.\r\n */\r\n apply(ctx: DrawContext) {\r\n for (let pass = 0; pass < this._numPasses; pass++) {\r\n const hash = this.calcGlobalHash(ctx, pass);\r\n let state = this._states[hash];\r\n if (!state) {\r\n let program = Material._programCache[hash];\r\n if (!program) {\r\n program = this.createProgram(ctx, pass) ?? null;\r\n program.name = `@${this.constructor.name}_program_${this._nextProgramId++}`;\r\n Material._programCache[hash] = program;\r\n }\r\n const bindGroup =\r\n program.bindGroupLayouts.length > 2\r\n ? ctx.device.createBindGroup(program.bindGroupLayouts[2])\r\n : null;\r\n state = {\r\n program,\r\n bindGroup,\r\n bindGroupTag: bindGroup?.getGPUId() ?? '',\r\n renderStateSet: ctx.device.createRenderStateSet(),\r\n materialTag: -1\r\n };\r\n this._states[hash] = state;\r\n }\r\n if (!state.program) {\r\n return false;\r\n }\r\n if (state.bindGroup) {\r\n this.applyUniforms(state.bindGroup, ctx, state.materialTag !== this._optionTag, pass);\r\n }\r\n state.materialTag = this._optionTag;\r\n this.updateRenderStates(pass, state.renderStateSet, ctx);\r\n this._currentHash[pass] = hash;\r\n if (state.bindGroup) {\r\n const id = state.bindGroup.getGPUId();\r\n if (id !== state.bindGroupTag) {\r\n state.bindGroupTag = id;\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n }\r\n }\r\n return true;\r\n }\r\n /**\r\n * Bind the program, bind group, and render states for the specified pass.\r\n *\r\n * Must be called after `apply(ctx)` for the same pass.\r\n *\r\n * @param device - Rendering device.\r\n * @param pass - Pass index to bind.\r\n * @returns `true` on success; `false` if state or program missing.\r\n * @internal\r\n */\r\n bind(device: AbstractDevice, pass: number) {\r\n const hash = this._currentHash[pass];\r\n const state = this._states[hash];\r\n if (!state) {\r\n console.error('Material.bind() failed: state not found');\r\n return false;\r\n }\r\n if (!state.program) {\r\n return false;\r\n }\r\n device.setProgram(state.program);\r\n if (state.bindGroup) {\r\n device.setBindGroup(2, state.bindGroup);\r\n }\r\n device.setRenderStates(state.renderStateSet);\r\n return true;\r\n }\r\n /**\r\n * Compute the global hash for the given pass and draw context.\r\n *\r\n * Includes:\r\n * - Per-pass material hash from `getHash(pass)`.\r\n * - `ctx.materialFlags` for context-dependent toggles.\r\n * - `ctx.renderPassHash` for framebuffer/attachment layout variants.\r\n * @internal\r\n */\r\n private calcGlobalHash(ctx: DrawContext, pass: number) {\r\n return `${this.getHash(pass)}:${ctx.materialFlags}:${ctx.renderPassHash}`;\r\n }\r\n /**\r\n * Draw a primitive for all passes using this material.\r\n *\r\n * Calls `bind()` then `drawPrimitive()` per pass. If `numInstances` is zero,\r\n * and `ctx.instanceData` exists, uses `ctx.instanceData.numInstances`.\r\n *\r\n * @param primitive - Geometry to draw.\r\n * @param ctx - Draw context.\r\n * @param numInstances - Instance count; 0 means auto-detect from context.\r\n * @internal\r\n */\r\n draw(primitive: Primitive, ctx: DrawContext, numInstances = 0) {\r\n for (let pass = 0; pass < this._numPasses; pass++) {\r\n this.bind(ctx.device, pass);\r\n this.drawPrimitive(pass, primitive, ctx, numInstances);\r\n }\r\n }\r\n /**\r\n * Conditionally update uniforms/resources into the material bind group.\r\n *\r\n * Delegates to `_applyUniforms()` when `needUpdate` is true (based on `_optionTag` check).\r\n *\r\n * @param bindGroup - Material bind group at index 2 (may be `null` if program has no layout).\r\n * @param ctx - Draw context.\r\n * @param needUpdate - Whether uniforms need to be refreshed.\r\n * @param pass - Pass index.\r\n */\r\n applyUniforms(bindGroup: BindGroup, ctx: DrawContext, needUpdate: boolean, pass: number) {\r\n if (needUpdate) {\r\n this._applyUniforms(bindGroup, ctx, pass);\r\n }\r\n }\r\n /**\r\n * Notify the material that some option changed.\r\n *\r\n * - Always increments `_optionTag`. This will trigger uniforms update on next `apply()`.\r\n * - If `changeHash` is true, clears per-pass hashes so programs/states will be rebuilt,\r\n * increments `_changeTag`, and notifies `RenderBundleWrapper` to regenerate recorded bundles.\r\n *\r\n * @param changeHash - Set true if the change affects shader compilation or render states.\r\n * @internal\r\n */\r\n optionChanged(changeHash: boolean) {\r\n this._optionTag++;\r\n if (changeHash) {\r\n for (let i = 0; i < this._numPasses; i++) {\r\n this._hash[i] = null;\r\n }\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n }\r\n clearCache() {\r\n for (const k in this._states) {\r\n this._states[k]?.bindGroup?.dispose();\r\n Material._programCache[k]?.dispose();\r\n delete Material._programCache[k];\r\n }\r\n this._states = {};\r\n }\r\n /**\r\n * Convert a pass index to a hash seed string.\r\n *\r\n * Subclasses may override to encode per-pass role (e.g., \"depth\", \"forward\", \"shadow\").\r\n *\r\n * @param pass - Pass number.\r\n * @returns String used when building full hash.\r\n */\r\n passToHash(pass: number) {\r\n return String(pass);\r\n }\r\n /**\r\n * Build the material hash for a pass (excluding context-dependent parts).\r\n *\r\n * Default formula: `${constructor.name}|${pass}|${_createHash()}`\r\n *\r\n * @param pass - Pass number.\r\n * @returns Hash string used in program caching.\r\n * @internal\r\n */\r\n createHash(pass: number) {\r\n return `${this.constructor.name}|${pass}|${this._createHash()}`;\r\n }\r\n /**\r\n * Issue the actual draw call for a pass.\r\n *\r\n * Override for custom per-pass draw behavior if necessary. The default implementation:\r\n * - Draws instanced if `numInstances > 0`.\r\n * - Else uses `ctx.instanceData.numInstances` if available.\r\n * - Else issues a non-instanced draw.\r\n *\r\n * @param pass - Pass number.\r\n * @param primitive - Primitive to draw.\r\n * @param ctx - Draw context.\r\n * @param numInstances - Explicit instance count (0 = auto).\r\n */\r\n drawPrimitive(pass: number, primitive: Primitive, ctx: DrawContext, numInstances: number) {\r\n if (numInstances > 0) {\r\n primitive.drawInstanced(numInstances);\r\n } else if (ctx.instanceData) {\r\n primitive.drawInstanced(ctx.instanceData.numInstances);\r\n } else {\r\n primitive.draw();\r\n }\r\n }\r\n /**\r\n * Dispose the material and release GPU-side resource references.\r\n *\r\n * - Unregisters from the global registry.\r\n * - Disposes the per-material bind groups kept in `_states`.\r\n */\r\n protected onDispose() {\r\n super.onDispose();\r\n this.clearCache();\r\n }\r\n /**\r\n * Build the GPU program for a pass.\r\n *\r\n * Default creates a `ProgramBuilder` and calls `_createProgram(pb, ctx, pass)`.\r\n * Subclasses should override `_createProgram` instead of this method unless\r\n * they need to replace builder instantiation.\r\n *\r\n * @param ctx - Draw context.\r\n * @param pass - Pass number.\r\n * @returns The compiled `GPUProgram`, or `null` on failure.\r\n * @internal\r\n */\r\n protected createProgram(ctx: DrawContext, pass: number) {\r\n const pb = new ProgramBuilder(ctx.device);\r\n return this._createProgram(pb, ctx, pass);\r\n }\r\n /**\r\n * Create and compile the shader program for this material/pass.\r\n *\r\n * Implement in subclasses:\r\n * - Define shader stages, entry points, macros/defines, and resource layouts.\r\n * - Return a compiled `GPUProgram`.\r\n *\r\n * @param pb - Program builder.\r\n * @param ctx - Draw context.\r\n * @param _pass - Pass number.\r\n * @returns The created program, or `null` on failure.\r\n */\r\n protected _createProgram(_pb: ProgramBuilder, _ctx: DrawContext, _pass: number): GPUProgram {\r\n throw new Error('Abstract function call');\r\n }\r\n /**\r\n * Upload uniforms and bind resources to the per-material bind group (index 2).\r\n *\r\n * Implement in subclasses to:\r\n * - Write uniform buffers/textures/samplers to the `bindGroup`.\r\n * - Respect the current `pass` and `ctx`.\r\n *\r\n * @param _bindGroup - The bind group to populate.\r\n * @param _ctx - Draw context.\r\n * @param _pass - Pass number.\r\n */\r\n protected _applyUniforms(_bindGroup: BindGroup, _ctx: DrawContext, _pass: number) {}\r\n /**\r\n * Update render states (depth/stencil, blending, rasterization) for the pass.\r\n *\r\n * Implement in subclasses based on transparency, double-sidedness, depth writes/tests,\r\n * color mask, stencil ops, etc., and any context flags in `ctx`.\r\n *\r\n * @param _pass - Current pass index.\r\n * @param _renderStates - Render state set to mutate.\r\n * @param _ctx - Draw context.\r\n */\r\n protected updateRenderStates(_pass: number, _renderStates: RenderStateSet, _ctx: DrawContext) {}\r\n /**\r\n * Compute the material-specific portion of the shader hash for the current options.\r\n *\r\n * Subclasses should override to include macro/define sets that influence program compilation.\r\n * Example return: `\"USE_NORMALMAP=1;ALPHA_MODE=BLEND;RECEIVE_SHADOWS=1\"`.\r\n *\r\n * @returns Hash fragment string (no context/pass info).\r\n */\r\n protected _createHash() {\r\n return '';\r\n }\r\n /**\r\n * Whether this is a lightweight instance of a core material.\r\n *\r\n * Instances typically share GPU programs with a core and only override instance uniforms.\r\n * @internal\r\n */\r\n get $isInstance(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Instance-uniform buffer for material instances, if supported.\r\n *\r\n * Returned as a typed Float32 view over a backing ArrayBuffer.\r\n * @internal\r\n */\r\n get $instanceUniforms(): Float32Array<ArrayBuffer> {\r\n throw new Error('Abstract function call');\r\n }\r\n}\r\n"],"names":["Material","Disposable","_nextId","_programCache","_nextProgramId","_id","_states","_numPasses","_hash","_optionTag","_changeTag","_currentHash","clone","other","copyFrom","clearCache","getEngine","resourceManager","setAssetId","getAssetId","coreMaterial","changeTag","instanceId","numPasses","val","length","push","getHash","pass","createHash","getQueueType","QUEUE_OPAQUE","isTransparentPass","_pass","supportLighting","supportInstancing","isBatchable","needSceneColor","needSceneDepth","createInstance","Error","apply","ctx","hash","calcGlobalHash","state","program","createProgram","name","bindGroup","bindGroupLayouts","device","createBindGroup","bindGroupTag","getGPUId","renderStateSet","createRenderStateSet","materialTag","applyUniforms","updateRenderStates","id","RenderBundleWrapper","materialChanged","bind","console","error","setProgram","setBindGroup","setRenderStates","materialFlags","renderPassHash","draw","primitive","numInstances","drawPrimitive","needUpdate","_applyUniforms","optionChanged","changeHash","i","k","dispose","passToHash","String","_createHash","drawInstanced","instanceData","onDispose","pb","ProgramBuilder","_createProgram","_pb","_ctx","_bindGroup","_renderStates","$isInstance","$instanceUniforms"],"mappings":"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"}
@@ -1,47 +1,47 @@
1
- /**
2
- * Manages cross-frame history resources that can be imported into a render graph.
3
- *
4
- * History resources are textures that persist across frames for temporal effects
5
- * like TAA, motion blur, or temporal upscaling. Previous-frame textures can be
6
- * imported into a {@link RenderGraph}, and current-frame textures are committed
7
- * only after graph execution succeeds.
8
- *
9
- * Usage:
10
- * ```ts
11
- * const historyMgr = new HistoryResourceManager(allocator);
12
- * historyMgr.beginFrame();
13
- * const prev = historyMgr.importPrevious(graph, 'taaColor');
14
- * // declare builder.read(prev) if non-null
15
- * historyMgr.bindImportedTextures(executor);
16
- * // after successful execution:
17
- * historyMgr.commitFrame();
18
- * ```
19
- *
20
- * @typeParam TTexture - The concrete texture type (e.g. `Texture2D`).
21
- * @public
1
+ /**
2
+ * Manages cross-frame history resources that can be imported into a render graph.
3
+ *
4
+ * History resources are textures that persist across frames for temporal effects
5
+ * like TAA, motion blur, or temporal upscaling. Previous-frame textures can be
6
+ * imported into a {@link RenderGraph}, and current-frame textures are committed
7
+ * only after graph execution succeeds.
8
+ *
9
+ * Usage:
10
+ * ```ts
11
+ * const historyMgr = new HistoryResourceManager(allocator);
12
+ * historyMgr.beginFrame();
13
+ * const prev = historyMgr.importPrevious(graph, 'taaColor');
14
+ * // declare builder.read(prev) if non-null
15
+ * historyMgr.bindImportedTextures(executor);
16
+ * // after successful execution:
17
+ * historyMgr.commitFrame();
18
+ * ```
19
+ *
20
+ * @typeParam TTexture - The concrete texture type (e.g. `Texture2D`).
21
+ * @public
22
22
  */ class HistoryResourceManager {
23
23
  _resources = new Map();
24
24
  _allocator;
25
25
  _pendingImports = new Map();
26
26
  _pendingCommits = new Map();
27
27
  _readScopeStack = [];
28
- /**
29
- * Create a new history resource manager.
30
- *
31
- * @param allocator - Texture allocator for creating history textures.
28
+ /**
29
+ * Create a new history resource manager.
30
+ *
31
+ * @param allocator - Texture allocator for creating history textures.
32
32
  */ constructor(allocator){
33
33
  this._allocator = allocator;
34
34
  }
35
- /**
36
- * Get the previous-frame texture resolved by the current render graph pass.
37
- *
38
- * The resource must have been imported with {@link HistoryResourceManager.importPrevious} or
39
- * {@link HistoryResourceManager.importPreviousIfCompatible}, declared as a pass read, and bound with
40
- * {@link HistoryResourceManager.beginReadScope} before this method is called.
41
- *
42
- * @param name - Name of the history resource.
43
- * @returns The graph-resolved previous-frame texture.
44
- * @throws If no read scope is active for the resource.
35
+ /**
36
+ * Get the previous-frame texture resolved by the current render graph pass.
37
+ *
38
+ * The resource must have been imported with {@link HistoryResourceManager.importPrevious} or
39
+ * {@link HistoryResourceManager.importPreviousIfCompatible}, declared as a pass read, and bound with
40
+ * {@link HistoryResourceManager.beginReadScope} before this method is called.
41
+ *
42
+ * @param name - Name of the history resource.
43
+ * @returns The graph-resolved previous-frame texture.
44
+ * @throws If no read scope is active for the resource.
45
45
  */ getPrevious(name) {
46
46
  const scoped = this._getScopedRead(name);
47
47
  if (scoped) {
@@ -49,32 +49,32 @@
49
49
  }
50
50
  throw new Error(`History resource '${name}' is not available in the current render graph read scope. ` + `Import it and declare a pass read before accessing it.`);
51
51
  }
52
- /**
53
- * Check whether a valid history resource exists and matches the descriptor.
54
- *
55
- * @param name - Name of the history resource.
56
- * @param desc - Expected texture descriptor.
57
- * @param size - Expected resolved size.
58
- * @returns True if the resource exists, is valid, and matches.
52
+ /**
53
+ * Check whether a valid history resource exists and matches the descriptor.
54
+ *
55
+ * @param name - Name of the history resource.
56
+ * @param desc - Expected texture descriptor.
57
+ * @param size - Expected resolved size.
58
+ * @returns True if the resource exists, is valid, and matches.
59
59
  */ isCompatible(name, desc, size) {
60
60
  const resource = this._resources.get(name);
61
61
  return !!resource?.valid && this._matches(resource, desc, size);
62
62
  }
63
- /**
64
- * Start collecting graph imports and deferred commits for a new frame.
63
+ /**
64
+ * Start collecting graph imports and deferred commits for a new frame.
65
65
  */ beginFrame() {
66
66
  this.discardFrame();
67
67
  this._pendingImports.clear();
68
68
  this._readScopeStack.length = 0;
69
69
  }
70
- /**
71
- * Import the latest committed texture for a history resource into the graph.
72
- *
73
- * Returns null when the resource has no valid previous frame.
74
- *
75
- * @param graph - Render graph to import into.
76
- * @param name - History resource name.
77
- * @returns Imported graph handle, or null when no valid previous texture exists.
70
+ /**
71
+ * Import the latest committed texture for a history resource into the graph.
72
+ *
73
+ * Returns null when the resource has no valid previous frame.
74
+ *
75
+ * @param graph - Render graph to import into.
76
+ * @param name - History resource name.
77
+ * @returns Imported graph handle, or null when no valid previous texture exists.
78
78
  */ importPrevious(graph, name) {
79
79
  const resource = this._resources.get(name);
80
80
  const texture = resource?.valid ? resource.textures[resource.currentIndex] : null;
@@ -85,34 +85,34 @@
85
85
  this._pendingImports.set(handle, texture);
86
86
  return handle;
87
87
  }
88
- /**
89
- * Import the latest committed texture only when it matches the expected shape.
90
- *
91
- * This is the preferred API for effects that can declare their history reads
92
- * while building the graph: incompatible history is treated as absent, so the
93
- * pass does not declare stale reads after resize or format changes.
94
- *
95
- * @param graph - Render graph to import into.
96
- * @param name - History resource name.
97
- * @param desc - Expected texture descriptor.
98
- * @param size - Expected resolved size.
99
- * @returns Imported graph handle, or null when no compatible history exists.
88
+ /**
89
+ * Import the latest committed texture only when it matches the expected shape.
90
+ *
91
+ * This is the preferred API for effects that can declare their history reads
92
+ * while building the graph: incompatible history is treated as absent, so the
93
+ * pass does not declare stale reads after resize or format changes.
94
+ *
95
+ * @param graph - Render graph to import into.
96
+ * @param name - History resource name.
97
+ * @param desc - Expected texture descriptor.
98
+ * @param size - Expected resolved size.
99
+ * @returns Imported graph handle, or null when no compatible history exists.
100
100
  */ importPreviousIfCompatible(graph, name, desc, size) {
101
101
  return this.isCompatible(name, desc, size) ? this.importPrevious(graph, name) : null;
102
102
  }
103
- /**
104
- * Bind all history imports created for this frame to the executor.
105
- *
106
- * @param executor - Render graph executor for the current frame.
103
+ /**
104
+ * Bind all history imports created for this frame to the executor.
105
+ *
106
+ * @param executor - Render graph executor for the current frame.
107
107
  */ bindImportedTextures(executor) {
108
108
  for (const [handle, texture] of this._pendingImports){
109
109
  executor.setImportedTexture(handle, texture);
110
110
  }
111
111
  }
112
- /**
113
- * Make resolved history textures available to code executing inside a pass.
114
- *
115
- * @param bindings - History name to resolved texture bindings.
112
+ /**
113
+ * Make resolved history textures available to code executing inside a pass.
114
+ *
115
+ * @param bindings - History name to resolved texture bindings.
116
116
  */ beginReadScope(bindings) {
117
117
  const scope = new Map();
118
118
  for (const binding of bindings){
@@ -120,22 +120,22 @@
120
120
  }
121
121
  this._readScopeStack.push(scope);
122
122
  }
123
- /**
124
- * End the most recent history read scope.
123
+ /**
124
+ * End the most recent history read scope.
125
125
  */ endReadScope() {
126
126
  this._readScopeStack.pop();
127
127
  }
128
- /**
129
- * Queue a current-frame texture to become the next previous-frame history.
130
- *
131
- * The texture is committed only when {@link HistoryResourceManager.commitFrame} is called. If the
132
- * frame fails, {@link HistoryResourceManager.discardFrame} releases owned pending textures instead.
133
- *
134
- * @param name - History resource name.
135
- * @param desc - Texture descriptor.
136
- * @param size - Resolved texture size.
137
- * @param texture - Texture produced by the current frame.
138
- * @param ownsTexture - Whether this manager should release the texture later.
128
+ /**
129
+ * Queue a current-frame texture to become the next previous-frame history.
130
+ *
131
+ * The texture is committed only when {@link HistoryResourceManager.commitFrame} is called. If the
132
+ * frame fails, {@link HistoryResourceManager.discardFrame} releases owned pending textures instead.
133
+ *
134
+ * @param name - History resource name.
135
+ * @param desc - Texture descriptor.
136
+ * @param size - Resolved texture size.
137
+ * @param texture - Texture produced by the current frame.
138
+ * @param ownsTexture - Whether this manager should release the texture later.
139
139
  */ queueCommit(name, desc, size, texture, ownsTexture = true) {
140
140
  const existing = this._pendingCommits.get(name);
141
141
  if (existing?.ownsTexture) {
@@ -152,8 +152,8 @@
152
152
  ownsTexture
153
153
  });
154
154
  }
155
- /**
156
- * Commit all current-frame history writes.
155
+ /**
156
+ * Commit all current-frame history writes.
157
157
  */ commitFrame() {
158
158
  for (const [name, pending] of this._pendingCommits){
159
159
  let resource = this._resources.get(name);
@@ -200,8 +200,8 @@
200
200
  this._pendingImports.clear();
201
201
  this._readScopeStack.length = 0;
202
202
  }
203
- /**
204
- * Discard all uncommitted frame history writes.
203
+ /**
204
+ * Discard all uncommitted frame history writes.
205
205
  */ discardFrame() {
206
206
  for (const pending of this._pendingCommits.values()){
207
207
  if (pending.ownsTexture) {
@@ -212,10 +212,10 @@
212
212
  this._pendingImports.clear();
213
213
  this._readScopeStack.length = 0;
214
214
  }
215
- /**
216
- * Release all history resources and clear the manager.
217
- *
218
- * Call this when disposing the render context or when history is no longer needed.
215
+ /**
216
+ * Release all history resources and clear the manager.
217
+ *
218
+ * Call this when disposing the render context or when history is no longer needed.
219
219
  */ dispose() {
220
220
  this.discardFrame();
221
221
  for (const resource of this._resources.values()){
@@ -1 +1 @@
1
- {"version":3,"file":"history_resource_manager.js","sources":["../../../src/render/rendergraph/history_resource_manager.ts"],"sourcesContent":["import type { Texture2D } from '@zephyr3d/device';\nimport type { RenderGraph } from './rendergraph';\nimport type { RenderGraphExecutor } from './executor';\nimport type { RGHandle, RGTextureAllocator, RGTextureDesc, RGResolvedSize } from './types';\n\ninterface HistoryResource<TTexture> {\n desc: RGTextureDesc;\n size: RGResolvedSize;\n textures: [TTexture | null, TTexture | null];\n ownsTexture: [boolean, boolean];\n currentIndex: number;\n valid: boolean;\n}\n\ninterface PendingHistoryCommit<TTexture> {\n desc: RGTextureDesc;\n size: RGResolvedSize;\n texture: TTexture;\n ownsTexture: boolean;\n}\n\n/**\n * Manages cross-frame history resources that can be imported into a render graph.\n *\n * History resources are textures that persist across frames for temporal effects\n * like TAA, motion blur, or temporal upscaling. Previous-frame textures can be\n * imported into a {@link RenderGraph}, and current-frame textures are committed\n * only after graph execution succeeds.\n *\n * Usage:\n * ```ts\n * const historyMgr = new HistoryResourceManager(allocator);\n * historyMgr.beginFrame();\n * const prev = historyMgr.importPrevious(graph, 'taaColor');\n * // declare builder.read(prev) if non-null\n * historyMgr.bindImportedTextures(executor);\n * // after successful execution:\n * historyMgr.commitFrame();\n * ```\n *\n * @typeParam TTexture - The concrete texture type (e.g. `Texture2D`).\n * @public\n */\nexport class HistoryResourceManager<TTexture = Texture2D> {\n private _resources: Map<string, HistoryResource<TTexture>> = new Map();\n private _allocator: RGTextureAllocator<TTexture>;\n private _pendingImports: Map<RGHandle, TTexture> = new Map();\n private _pendingCommits: Map<string, PendingHistoryCommit<TTexture>> = new Map();\n private _readScopeStack: Array<Map<string, TTexture>> = [];\n\n /**\n * Create a new history resource manager.\n *\n * @param allocator - Texture allocator for creating history textures.\n */\n constructor(allocator: RGTextureAllocator<TTexture>) {\n this._allocator = allocator;\n }\n\n /**\n * Get the previous-frame texture resolved by the current render graph pass.\n *\n * The resource must have been imported with {@link HistoryResourceManager.importPrevious} or\n * {@link HistoryResourceManager.importPreviousIfCompatible}, declared as a pass read, and bound with\n * {@link HistoryResourceManager.beginReadScope} before this method is called.\n *\n * @param name - Name of the history resource.\n * @returns The graph-resolved previous-frame texture.\n * @throws If no read scope is active for the resource.\n */\n getPrevious(name: string): TTexture {\n const scoped = this._getScopedRead(name);\n if (scoped) {\n return scoped;\n }\n throw new Error(\n `History resource '${name}' is not available in the current render graph read scope. ` +\n `Import it and declare a pass read before accessing it.`\n );\n }\n\n /**\n * Check whether a valid history resource exists and matches the descriptor.\n *\n * @param name - Name of the history resource.\n * @param desc - Expected texture descriptor.\n * @param size - Expected resolved size.\n * @returns True if the resource exists, is valid, and matches.\n */\n isCompatible(name: string, desc: RGTextureDesc, size: RGResolvedSize): boolean {\n const resource = this._resources.get(name);\n return !!resource?.valid && this._matches(resource, desc, size);\n }\n\n /**\n * Start collecting graph imports and deferred commits for a new frame.\n */\n beginFrame(): void {\n this.discardFrame();\n this._pendingImports.clear();\n this._readScopeStack.length = 0;\n }\n\n /**\n * Import the latest committed texture for a history resource into the graph.\n *\n * Returns null when the resource has no valid previous frame.\n *\n * @param graph - Render graph to import into.\n * @param name - History resource name.\n * @returns Imported graph handle, or null when no valid previous texture exists.\n */\n importPrevious(graph: RenderGraph, name: string): RGHandle | null {\n const resource = this._resources.get(name);\n const texture = resource?.valid ? resource.textures[resource.currentIndex] : null;\n if (!texture) {\n return null;\n }\n const handle = graph.importTexture(`history:${name}:previous`);\n this._pendingImports.set(handle, texture);\n return handle;\n }\n\n /**\n * Import the latest committed texture only when it matches the expected shape.\n *\n * This is the preferred API for effects that can declare their history reads\n * while building the graph: incompatible history is treated as absent, so the\n * pass does not declare stale reads after resize or format changes.\n *\n * @param graph - Render graph to import into.\n * @param name - History resource name.\n * @param desc - Expected texture descriptor.\n * @param size - Expected resolved size.\n * @returns Imported graph handle, or null when no compatible history exists.\n */\n importPreviousIfCompatible(\n graph: RenderGraph,\n name: string,\n desc: RGTextureDesc,\n size: RGResolvedSize\n ): RGHandle | null {\n return this.isCompatible(name, desc, size) ? this.importPrevious(graph, name) : null;\n }\n\n /**\n * Bind all history imports created for this frame to the executor.\n *\n * @param executor - Render graph executor for the current frame.\n */\n bindImportedTextures(executor: Pick<RenderGraphExecutor<TTexture>, 'setImportedTexture'>): void {\n for (const [handle, texture] of this._pendingImports) {\n executor.setImportedTexture(handle, texture);\n }\n }\n\n /**\n * Make resolved history textures available to code executing inside a pass.\n *\n * @param bindings - History name to resolved texture bindings.\n */\n beginReadScope(bindings: Array<{ name: string; texture: TTexture }>): void {\n const scope = new Map<string, TTexture>();\n for (const binding of bindings) {\n scope.set(binding.name, binding.texture);\n }\n this._readScopeStack.push(scope);\n }\n\n /**\n * End the most recent history read scope.\n */\n endReadScope(): void {\n this._readScopeStack.pop();\n }\n\n /**\n * Queue a current-frame texture to become the next previous-frame history.\n *\n * The texture is committed only when {@link HistoryResourceManager.commitFrame} is called. If the\n * frame fails, {@link HistoryResourceManager.discardFrame} releases owned pending textures instead.\n *\n * @param name - History resource name.\n * @param desc - Texture descriptor.\n * @param size - Resolved texture size.\n * @param texture - Texture produced by the current frame.\n * @param ownsTexture - Whether this manager should release the texture later.\n */\n queueCommit(\n name: string,\n desc: RGTextureDesc,\n size: RGResolvedSize,\n texture: TTexture,\n ownsTexture = true\n ): void {\n const existing = this._pendingCommits.get(name);\n if (existing?.ownsTexture) {\n this._allocator.release(existing.texture);\n }\n this._pendingCommits.set(name, {\n desc: { ...desc },\n size: { ...size },\n texture,\n ownsTexture\n });\n }\n\n /**\n * Commit all current-frame history writes.\n */\n commitFrame(): void {\n for (const [name, pending] of this._pendingCommits) {\n let resource = this._resources.get(name);\n if (resource && !this._matches(resource, pending.desc, pending.size)) {\n this._releaseResource(resource);\n this._resources.delete(name);\n resource = undefined;\n }\n if (!resource) {\n resource = {\n desc: { ...pending.desc },\n size: { ...pending.size },\n textures: [null, null],\n ownsTexture: [false, false],\n currentIndex: 0,\n valid: false\n };\n this._resources.set(name, resource);\n }\n\n const writeIndex = resource.valid ? 1 - resource.currentIndex : resource.currentIndex;\n this._releaseSlot(resource, writeIndex);\n resource.textures[writeIndex] = pending.texture;\n resource.ownsTexture[writeIndex] = pending.ownsTexture;\n resource.desc = { ...pending.desc };\n resource.size = { ...pending.size };\n resource.currentIndex = writeIndex;\n resource.valid = true;\n }\n this._pendingCommits.clear();\n this._pendingImports.clear();\n this._readScopeStack.length = 0;\n }\n\n /**\n * Discard all uncommitted frame history writes.\n */\n discardFrame(): void {\n for (const pending of this._pendingCommits.values()) {\n if (pending.ownsTexture) {\n this._allocator.release(pending.texture);\n }\n }\n this._pendingCommits.clear();\n this._pendingImports.clear();\n this._readScopeStack.length = 0;\n }\n\n /**\n * Release all history resources and clear the manager.\n *\n * Call this when disposing the render context or when history is no longer needed.\n */\n dispose(): void {\n this.discardFrame();\n for (const resource of this._resources.values()) {\n this._releaseResource(resource);\n }\n this._resources.clear();\n }\n\n /** @internal */\n private _getScopedRead(name: string): TTexture | null {\n for (let i = this._readScopeStack.length - 1; i >= 0; i--) {\n const texture = this._readScopeStack[i].get(name);\n if (texture) {\n return texture;\n }\n }\n return null;\n }\n\n /** @internal */\n private _matches(resource: HistoryResource<TTexture>, desc: RGTextureDesc, size: RGResolvedSize): boolean {\n return (\n resource.desc.format === desc.format &&\n (resource.desc.mipLevels ?? 1) === (desc.mipLevels ?? 1) &&\n resource.size.width === size.width &&\n resource.size.height === size.height\n );\n }\n\n /** @internal */\n private _releaseResource(resource: HistoryResource<TTexture>): void {\n this._releaseSlot(resource, 0);\n this._releaseSlot(resource, 1);\n resource.valid = false;\n }\n\n /** @internal */\n private _releaseSlot(resource: HistoryResource<TTexture>, index: number): void {\n const texture = resource.textures[index];\n if (!texture) {\n return;\n }\n const otherIndex = 1 - index;\n if (resource.ownsTexture[index] && resource.textures[otherIndex] !== texture) {\n this._allocator.release(texture);\n }\n resource.textures[index] = null;\n resource.ownsTexture[index] = false;\n }\n}\n"],"names":["HistoryResourceManager","_resources","Map","_allocator","_pendingImports","_pendingCommits","_readScopeStack","allocator","getPrevious","name","scoped","_getScopedRead","Error","isCompatible","desc","size","resource","get","valid","_matches","beginFrame","discardFrame","clear","length","importPrevious","graph","texture","textures","currentIndex","handle","importTexture","set","importPreviousIfCompatible","bindImportedTextures","executor","setImportedTexture","beginReadScope","bindings","scope","binding","push","endReadScope","pop","queueCommit","ownsTexture","existing","release","commitFrame","pending","_releaseResource","delete","undefined","writeIndex","_releaseSlot","values","dispose","i","format","mipLevels","width","height","index","otherIndex"],"mappings":"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"}
1
+ {"version":3,"file":"history_resource_manager.js","sources":["../../../src/render/rendergraph/history_resource_manager.ts"],"sourcesContent":["import type { Texture2D } from '@zephyr3d/device';\r\nimport type { RenderGraph } from './rendergraph';\r\nimport type { RenderGraphExecutor } from './executor';\r\nimport type { RGHandle, RGTextureAllocator, RGTextureDesc, RGResolvedSize } from './types';\r\n\r\ninterface HistoryResource<TTexture> {\r\n desc: RGTextureDesc;\r\n size: RGResolvedSize;\r\n textures: [TTexture | null, TTexture | null];\r\n ownsTexture: [boolean, boolean];\r\n currentIndex: number;\r\n valid: boolean;\r\n}\r\n\r\ninterface PendingHistoryCommit<TTexture> {\r\n desc: RGTextureDesc;\r\n size: RGResolvedSize;\r\n texture: TTexture;\r\n ownsTexture: boolean;\r\n}\r\n\r\n/**\r\n * Manages cross-frame history resources that can be imported into a render graph.\r\n *\r\n * History resources are textures that persist across frames for temporal effects\r\n * like TAA, motion blur, or temporal upscaling. Previous-frame textures can be\r\n * imported into a {@link RenderGraph}, and current-frame textures are committed\r\n * only after graph execution succeeds.\r\n *\r\n * Usage:\r\n * ```ts\r\n * const historyMgr = new HistoryResourceManager(allocator);\r\n * historyMgr.beginFrame();\r\n * const prev = historyMgr.importPrevious(graph, 'taaColor');\r\n * // declare builder.read(prev) if non-null\r\n * historyMgr.bindImportedTextures(executor);\r\n * // after successful execution:\r\n * historyMgr.commitFrame();\r\n * ```\r\n *\r\n * @typeParam TTexture - The concrete texture type (e.g. `Texture2D`).\r\n * @public\r\n */\r\nexport class HistoryResourceManager<TTexture = Texture2D> {\r\n private _resources: Map<string, HistoryResource<TTexture>> = new Map();\r\n private _allocator: RGTextureAllocator<TTexture>;\r\n private _pendingImports: Map<RGHandle, TTexture> = new Map();\r\n private _pendingCommits: Map<string, PendingHistoryCommit<TTexture>> = new Map();\r\n private _readScopeStack: Array<Map<string, TTexture>> = [];\r\n\r\n /**\r\n * Create a new history resource manager.\r\n *\r\n * @param allocator - Texture allocator for creating history textures.\r\n */\r\n constructor(allocator: RGTextureAllocator<TTexture>) {\r\n this._allocator = allocator;\r\n }\r\n\r\n /**\r\n * Get the previous-frame texture resolved by the current render graph pass.\r\n *\r\n * The resource must have been imported with {@link HistoryResourceManager.importPrevious} or\r\n * {@link HistoryResourceManager.importPreviousIfCompatible}, declared as a pass read, and bound with\r\n * {@link HistoryResourceManager.beginReadScope} before this method is called.\r\n *\r\n * @param name - Name of the history resource.\r\n * @returns The graph-resolved previous-frame texture.\r\n * @throws If no read scope is active for the resource.\r\n */\r\n getPrevious(name: string): TTexture {\r\n const scoped = this._getScopedRead(name);\r\n if (scoped) {\r\n return scoped;\r\n }\r\n throw new Error(\r\n `History resource '${name}' is not available in the current render graph read scope. ` +\r\n `Import it and declare a pass read before accessing it.`\r\n );\r\n }\r\n\r\n /**\r\n * Check whether a valid history resource exists and matches the descriptor.\r\n *\r\n * @param name - Name of the history resource.\r\n * @param desc - Expected texture descriptor.\r\n * @param size - Expected resolved size.\r\n * @returns True if the resource exists, is valid, and matches.\r\n */\r\n isCompatible(name: string, desc: RGTextureDesc, size: RGResolvedSize): boolean {\r\n const resource = this._resources.get(name);\r\n return !!resource?.valid && this._matches(resource, desc, size);\r\n }\r\n\r\n /**\r\n * Start collecting graph imports and deferred commits for a new frame.\r\n */\r\n beginFrame(): void {\r\n this.discardFrame();\r\n this._pendingImports.clear();\r\n this._readScopeStack.length = 0;\r\n }\r\n\r\n /**\r\n * Import the latest committed texture for a history resource into the graph.\r\n *\r\n * Returns null when the resource has no valid previous frame.\r\n *\r\n * @param graph - Render graph to import into.\r\n * @param name - History resource name.\r\n * @returns Imported graph handle, or null when no valid previous texture exists.\r\n */\r\n importPrevious(graph: RenderGraph, name: string): RGHandle | null {\r\n const resource = this._resources.get(name);\r\n const texture = resource?.valid ? resource.textures[resource.currentIndex] : null;\r\n if (!texture) {\r\n return null;\r\n }\r\n const handle = graph.importTexture(`history:${name}:previous`);\r\n this._pendingImports.set(handle, texture);\r\n return handle;\r\n }\r\n\r\n /**\r\n * Import the latest committed texture only when it matches the expected shape.\r\n *\r\n * This is the preferred API for effects that can declare their history reads\r\n * while building the graph: incompatible history is treated as absent, so the\r\n * pass does not declare stale reads after resize or format changes.\r\n *\r\n * @param graph - Render graph to import into.\r\n * @param name - History resource name.\r\n * @param desc - Expected texture descriptor.\r\n * @param size - Expected resolved size.\r\n * @returns Imported graph handle, or null when no compatible history exists.\r\n */\r\n importPreviousIfCompatible(\r\n graph: RenderGraph,\r\n name: string,\r\n desc: RGTextureDesc,\r\n size: RGResolvedSize\r\n ): RGHandle | null {\r\n return this.isCompatible(name, desc, size) ? this.importPrevious(graph, name) : null;\r\n }\r\n\r\n /**\r\n * Bind all history imports created for this frame to the executor.\r\n *\r\n * @param executor - Render graph executor for the current frame.\r\n */\r\n bindImportedTextures(executor: Pick<RenderGraphExecutor<TTexture>, 'setImportedTexture'>): void {\r\n for (const [handle, texture] of this._pendingImports) {\r\n executor.setImportedTexture(handle, texture);\r\n }\r\n }\r\n\r\n /**\r\n * Make resolved history textures available to code executing inside a pass.\r\n *\r\n * @param bindings - History name to resolved texture bindings.\r\n */\r\n beginReadScope(bindings: Array<{ name: string; texture: TTexture }>): void {\r\n const scope = new Map<string, TTexture>();\r\n for (const binding of bindings) {\r\n scope.set(binding.name, binding.texture);\r\n }\r\n this._readScopeStack.push(scope);\r\n }\r\n\r\n /**\r\n * End the most recent history read scope.\r\n */\r\n endReadScope(): void {\r\n this._readScopeStack.pop();\r\n }\r\n\r\n /**\r\n * Queue a current-frame texture to become the next previous-frame history.\r\n *\r\n * The texture is committed only when {@link HistoryResourceManager.commitFrame} is called. If the\r\n * frame fails, {@link HistoryResourceManager.discardFrame} releases owned pending textures instead.\r\n *\r\n * @param name - History resource name.\r\n * @param desc - Texture descriptor.\r\n * @param size - Resolved texture size.\r\n * @param texture - Texture produced by the current frame.\r\n * @param ownsTexture - Whether this manager should release the texture later.\r\n */\r\n queueCommit(\r\n name: string,\r\n desc: RGTextureDesc,\r\n size: RGResolvedSize,\r\n texture: TTexture,\r\n ownsTexture = true\r\n ): void {\r\n const existing = this._pendingCommits.get(name);\r\n if (existing?.ownsTexture) {\r\n this._allocator.release(existing.texture);\r\n }\r\n this._pendingCommits.set(name, {\r\n desc: { ...desc },\r\n size: { ...size },\r\n texture,\r\n ownsTexture\r\n });\r\n }\r\n\r\n /**\r\n * Commit all current-frame history writes.\r\n */\r\n commitFrame(): void {\r\n for (const [name, pending] of this._pendingCommits) {\r\n let resource = this._resources.get(name);\r\n if (resource && !this._matches(resource, pending.desc, pending.size)) {\r\n this._releaseResource(resource);\r\n this._resources.delete(name);\r\n resource = undefined;\r\n }\r\n if (!resource) {\r\n resource = {\r\n desc: { ...pending.desc },\r\n size: { ...pending.size },\r\n textures: [null, null],\r\n ownsTexture: [false, false],\r\n currentIndex: 0,\r\n valid: false\r\n };\r\n this._resources.set(name, resource);\r\n }\r\n\r\n const writeIndex = resource.valid ? 1 - resource.currentIndex : resource.currentIndex;\r\n this._releaseSlot(resource, writeIndex);\r\n resource.textures[writeIndex] = pending.texture;\r\n resource.ownsTexture[writeIndex] = pending.ownsTexture;\r\n resource.desc = { ...pending.desc };\r\n resource.size = { ...pending.size };\r\n resource.currentIndex = writeIndex;\r\n resource.valid = true;\r\n }\r\n this._pendingCommits.clear();\r\n this._pendingImports.clear();\r\n this._readScopeStack.length = 0;\r\n }\r\n\r\n /**\r\n * Discard all uncommitted frame history writes.\r\n */\r\n discardFrame(): void {\r\n for (const pending of this._pendingCommits.values()) {\r\n if (pending.ownsTexture) {\r\n this._allocator.release(pending.texture);\r\n }\r\n }\r\n this._pendingCommits.clear();\r\n this._pendingImports.clear();\r\n this._readScopeStack.length = 0;\r\n }\r\n\r\n /**\r\n * Release all history resources and clear the manager.\r\n *\r\n * Call this when disposing the render context or when history is no longer needed.\r\n */\r\n dispose(): void {\r\n this.discardFrame();\r\n for (const resource of this._resources.values()) {\r\n this._releaseResource(resource);\r\n }\r\n this._resources.clear();\r\n }\r\n\r\n /** @internal */\r\n private _getScopedRead(name: string): TTexture | null {\r\n for (let i = this._readScopeStack.length - 1; i >= 0; i--) {\r\n const texture = this._readScopeStack[i].get(name);\r\n if (texture) {\r\n return texture;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /** @internal */\r\n private _matches(resource: HistoryResource<TTexture>, desc: RGTextureDesc, size: RGResolvedSize): boolean {\r\n return (\r\n resource.desc.format === desc.format &&\r\n (resource.desc.mipLevels ?? 1) === (desc.mipLevels ?? 1) &&\r\n resource.size.width === size.width &&\r\n resource.size.height === size.height\r\n );\r\n }\r\n\r\n /** @internal */\r\n private _releaseResource(resource: HistoryResource<TTexture>): void {\r\n this._releaseSlot(resource, 0);\r\n this._releaseSlot(resource, 1);\r\n resource.valid = false;\r\n }\r\n\r\n /** @internal */\r\n private _releaseSlot(resource: HistoryResource<TTexture>, index: number): void {\r\n const texture = resource.textures[index];\r\n if (!texture) {\r\n return;\r\n }\r\n const otherIndex = 1 - index;\r\n if (resource.ownsTexture[index] && resource.textures[otherIndex] !== texture) {\r\n this._allocator.release(texture);\r\n }\r\n resource.textures[index] = null;\r\n resource.ownsTexture[index] = false;\r\n }\r\n}\r\n"],"names":["HistoryResourceManager","_resources","Map","_allocator","_pendingImports","_pendingCommits","_readScopeStack","allocator","getPrevious","name","scoped","_getScopedRead","Error","isCompatible","desc","size","resource","get","valid","_matches","beginFrame","discardFrame","clear","length","importPrevious","graph","texture","textures","currentIndex","handle","importTexture","set","importPreviousIfCompatible","bindImportedTextures","executor","setImportedTexture","beginReadScope","bindings","scope","binding","push","endReadScope","pop","queueCommit","ownsTexture","existing","release","commitFrame","pending","_releaseResource","delete","undefined","writeIndex","_releaseSlot","values","dispose","i","format","mipLevels","width","height","index","otherIndex"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- /**
2
- * Resource names for render graph history resources.
3
- * @public
1
+ /**
2
+ * Resource names for render graph history resources.
3
+ * @public
4
4
  */ const RGHistoryResources = {
5
5
  TAA_COLOR: 'taaColor',
6
6
  TAA_MOTION_VECTOR: 'taaMotionVector'
@@ -1 +1 @@
1
- {"version":3,"file":"history_resources.js","sources":["../../../src/render/rendergraph/history_resources.ts"],"sourcesContent":["/**\n * Resource names for render graph history resources.\n * @public\n */\nexport const RGHistoryResources = {\n TAA_COLOR: 'taaColor',\n TAA_MOTION_VECTOR: 'taaMotionVector'\n} as const;\n"],"names":["RGHistoryResources","TAA_COLOR","TAA_MOTION_VECTOR"],"mappings":"AAAA;;;UAIaA,kBAAqB,GAAA;IAChCC,SAAW,EAAA,UAAA;IACXC,iBAAmB,EAAA;AACrB;;;;"}
1
+ {"version":3,"file":"history_resources.js","sources":["../../../src/render/rendergraph/history_resources.ts"],"sourcesContent":["/**\r\n * Resource names for render graph history resources.\r\n * @public\r\n */\r\nexport const RGHistoryResources = {\r\n TAA_COLOR: 'taaColor',\r\n TAA_MOTION_VECTOR: 'taaMotionVector'\r\n} as const;\r\n"],"names":["RGHistoryResources","TAA_COLOR","TAA_MOTION_VECTOR"],"mappings":"AAAA;;;UAIaA,kBAAqB,GAAA;IAChCC,SAAW,EAAA,UAAA;IACXC,iBAAmB,EAAA;AACrB;;;;"}
@@ -1,12 +1,12 @@
1
1
  // ─── Handles ────────────────────────────────────────────────────────────
2
- /**
3
- * Opaque handle referencing a resource within the render graph.
4
- *
5
- * Handles are obtained from {@link RGPassBuilder.createTexture}, {@link RGPassBuilder.createFramebuffer},
6
- * {@link RenderGraph.importTexture}, or {@link RGPassBuilder.write}. They are lightweight identifiers
7
- * used to declare dependencies between passes.
8
- *
9
- * @public
2
+ /**
3
+ * Opaque handle referencing a resource within the render graph.
4
+ *
5
+ * Handles are obtained from {@link RGPassBuilder.createTexture}, {@link RGPassBuilder.createFramebuffer},
6
+ * {@link RenderGraph.importTexture}, or {@link RGPassBuilder.write}. They are lightweight identifiers
7
+ * used to declare dependencies between passes.
8
+ *
9
+ * @public
10
10
  */ class RGHandle {
11
11
  /** @internal */ _id;
12
12
  /** @internal */ _name;
@@ -18,9 +18,9 @@
18
18
  return this._name;
19
19
  }
20
20
  }
21
- /**
22
- * Internal bookkeeping for a resource within the render graph.
23
- * @public
21
+ /**
22
+ * Internal bookkeeping for a resource within the render graph.
23
+ * @public
24
24
  */ class RGResource {
25
25
  id;
26
26
  name;
@@ -37,14 +37,14 @@
37
37
  this.physicalId = physicalId;
38
38
  }
39
39
  }
40
- /**
41
- * Ordered execution step inside a render graph pass.
42
- *
43
- * Subpasses share the parent pass's resource declarations, lifetime, culling,
44
- * and access validation. They are intended to make multi-step pass bodies
45
- * explicit without splitting graph-level resource dependencies.
46
- *
47
- * @public
40
+ /**
41
+ * Ordered execution step inside a render graph pass.
42
+ *
43
+ * Subpasses share the parent pass's resource declarations, lifetime, culling,
44
+ * and access validation. They are intended to make multi-step pass bodies
45
+ * explicit without splitting graph-level resource dependencies.
46
+ *
47
+ * @public
48
48
  */ class RGSubpass {
49
49
  name;
50
50
  executeFn;
@@ -53,9 +53,9 @@
53
53
  this.executeFn = executeFn;
54
54
  }
55
55
  }
56
- /**
57
- * Internal bookkeeping for a pass within the render graph.
58
- * @public
56
+ /**
57
+ * Internal bookkeeping for a pass within the render graph.
58
+ * @public
59
59
  */ class RGPass {
60
60
  index;
61
61
  name;