@zephyr3d/scene 0.9.21 → 0.9.23

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 (238) hide show
  1. package/dist/animation/joint_dynamics/collision.js +1 -7
  2. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  3. package/dist/animation/joint_dynamics/constraints.js +2 -17
  4. package/dist/animation/joint_dynamics/constraints.js.map +1 -1
  5. package/dist/animation/joint_dynamics/controller.js +2 -20
  6. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  7. package/dist/animation/joint_dynamics/joint_dynamics_system.js +1 -3
  8. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  9. package/dist/animation/joint_dynamics/solver.js +14 -60
  10. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  11. package/dist/animation/joint_dynamics/types.js +3 -3
  12. package/dist/animation/joint_dynamics/types.js.map +1 -1
  13. package/dist/app/app.js +23 -0
  14. package/dist/app/app.js.map +1 -1
  15. package/dist/app/scriptregistry.js +16 -53
  16. package/dist/app/scriptregistry.js.map +1 -1
  17. package/dist/asset/assetmanager.js +2 -0
  18. package/dist/asset/assetmanager.js.map +1 -1
  19. package/dist/asset/model.js +22 -0
  20. package/dist/asset/model.js.map +1 -1
  21. package/dist/blitter/bilateralblur.js +3 -1
  22. package/dist/blitter/bilateralblur.js.map +1 -1
  23. package/dist/blitter/blitter.js +3 -3
  24. package/dist/blitter/blitter.js.map +1 -1
  25. package/dist/camera/camera.js +398 -45
  26. package/dist/camera/camera.js.map +1 -1
  27. package/dist/camera/perspectivecamera.js +69 -2
  28. package/dist/camera/perspectivecamera.js.map +1 -1
  29. package/dist/index.d.ts +9100 -8712
  30. package/dist/index.js +9 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/material/blinn.js +1 -1
  33. package/dist/material/blinn.js.map +1 -1
  34. package/dist/material/lambert.js +3 -3
  35. package/dist/material/lambert.js.map +1 -1
  36. package/dist/material/material.js +8 -5
  37. package/dist/material/material.js.map +1 -1
  38. package/dist/material/meshmaterial.js +17 -10
  39. package/dist/material/meshmaterial.js.map +1 -1
  40. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  41. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  42. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  43. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  44. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +21 -6
  45. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  46. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +1 -1
  47. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  48. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +1 -1
  49. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  50. package/dist/material/mixins/lit.js +33 -11
  51. package/dist/material/mixins/lit.js.map +1 -1
  52. package/dist/material/mixins/pbr/brdf.js +44 -12
  53. package/dist/material/mixins/pbr/brdf.js.map +1 -1
  54. package/dist/material/mixins/pbr/common.js +149 -14
  55. package/dist/material/mixins/pbr/common.js.map +1 -1
  56. package/dist/material/mtoon.js +7 -4
  57. package/dist/material/mtoon.js.map +1 -1
  58. package/dist/material/pbrblueprint.js +5 -1
  59. package/dist/material/pbrblueprint.js.map +1 -1
  60. package/dist/material/pbrmr.js +1 -1
  61. package/dist/material/pbrmr.js.map +1 -1
  62. package/dist/material/pbrsg.js +1 -1
  63. package/dist/material/pbrsg.js.map +1 -1
  64. package/dist/material/shader/helper.js +186 -11
  65. package/dist/material/shader/helper.js.map +1 -1
  66. package/dist/material/skin.js +2 -2
  67. package/dist/material/skin.js.map +1 -1
  68. package/dist/material/terrain-cm.js +5 -5
  69. package/dist/material/terrain-cm.js.map +1 -1
  70. package/dist/material/water.js +6 -4
  71. package/dist/material/water.js.map +1 -1
  72. package/dist/posteffect/bloom.js +54 -4
  73. package/dist/posteffect/bloom.js.map +1 -1
  74. package/dist/posteffect/compositor.js +41 -0
  75. package/dist/posteffect/compositor.js.map +1 -1
  76. package/dist/posteffect/posteffect.js +51 -0
  77. package/dist/posteffect/posteffect.js.map +1 -1
  78. package/dist/posteffect/sao.js +7 -6
  79. package/dist/posteffect/sao.js.map +1 -1
  80. package/dist/posteffect/skinsss.js +3 -3
  81. package/dist/posteffect/skinsss.js.map +1 -1
  82. package/dist/posteffect/ssgi.js +1196 -0
  83. package/dist/posteffect/ssgi.js.map +1 -0
  84. package/dist/posteffect/ssr.js +83 -45
  85. package/dist/posteffect/ssr.js.map +1 -1
  86. package/dist/posteffect/sss.js +137 -49
  87. package/dist/posteffect/sss.js.map +1 -1
  88. package/dist/posteffect/taa.js +5 -4
  89. package/dist/posteffect/taa.js.map +1 -1
  90. package/dist/posteffect/tonemap.js +15 -3
  91. package/dist/posteffect/tonemap.js.map +1 -1
  92. package/dist/render/abuffer_oit.js +2 -2
  93. package/dist/render/abuffer_oit.js.map +1 -1
  94. package/dist/render/cluster_light.js +12 -6
  95. package/dist/render/cluster_light.js.map +1 -1
  96. package/dist/render/drawable_mixin.js +8 -5
  97. package/dist/render/drawable_mixin.js.map +1 -1
  98. package/dist/render/dualdepthpeeling_oit.js +10 -5
  99. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  100. package/dist/render/envlight.js +298 -5
  101. package/dist/render/envlight.js.map +1 -1
  102. package/dist/render/gpu_picking.js +7 -5
  103. package/dist/render/gpu_picking.js.map +1 -1
  104. package/dist/render/hzb.js +28 -19
  105. package/dist/render/hzb.js.map +1 -1
  106. package/dist/render/lightpass.js +18 -4
  107. package/dist/render/lightpass.js.map +1 -1
  108. package/dist/render/render_queue.js +37 -4
  109. package/dist/render/render_queue.js.map +1 -1
  110. package/dist/render/renderer.js +8 -3
  111. package/dist/render/renderer.js.map +1 -1
  112. package/dist/render/rendergraph/blackboard.js +20 -48
  113. package/dist/render/rendergraph/blackboard.js.map +1 -1
  114. package/dist/render/rendergraph/device_pool_allocator.js +18 -58
  115. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  116. package/dist/render/rendergraph/executor.js +89 -115
  117. package/dist/render/rendergraph/executor.js.map +1 -1
  118. package/dist/render/rendergraph/forward_plus_builder.js +1003 -715
  119. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  120. package/dist/render/rendergraph/frame_graph_context.js +41 -0
  121. package/dist/render/rendergraph/frame_graph_context.js.map +1 -0
  122. package/dist/render/rendergraph/frame_resource_requirements.js +14 -0
  123. package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -0
  124. package/dist/render/rendergraph/history_resource_manager.js +74 -140
  125. package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
  126. package/dist/render/rendergraph/history_resources.js +7 -5
  127. package/dist/render/rendergraph/history_resources.js.map +1 -1
  128. package/dist/render/rendergraph/render_context.js +19 -0
  129. package/dist/render/rendergraph/render_context.js.map +1 -0
  130. package/dist/render/rendergraph/render_pipeline.js +315 -0
  131. package/dist/render/rendergraph/render_pipeline.js.map +1 -0
  132. package/dist/render/rendergraph/rendergraph.js +158 -141
  133. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  134. package/dist/render/rendergraph/scene_render_context.js +267 -0
  135. package/dist/render/rendergraph/scene_render_context.js.map +1 -0
  136. package/dist/render/rendergraph/texture_affinity_cache.js +19 -0
  137. package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -0
  138. package/dist/render/rendergraph/types.js +19 -31
  139. package/dist/render/rendergraph/types.js.map +1 -1
  140. package/dist/render/renderpass.js +3 -3
  141. package/dist/render/renderpass.js.map +1 -1
  142. package/dist/render/shadow_mask_pass.js +10 -6
  143. package/dist/render/shadow_mask_pass.js.map +1 -1
  144. package/dist/render/sky.js +197 -35
  145. package/dist/render/sky.js.map +1 -1
  146. package/dist/render/weightedblended_oit.js +4 -3
  147. package/dist/render/weightedblended_oit.js.map +1 -1
  148. package/dist/scene/basesprite.js +2 -0
  149. package/dist/scene/basesprite.js.map +1 -1
  150. package/dist/scene/batchgroup.js +10 -0
  151. package/dist/scene/batchgroup.js.map +1 -1
  152. package/dist/scene/environment.js +61 -2
  153. package/dist/scene/environment.js.map +1 -1
  154. package/dist/scene/light.js +178 -10
  155. package/dist/scene/light.js.map +1 -1
  156. package/dist/scene/meshdrawable.js +89 -2
  157. package/dist/scene/meshdrawable.js.map +1 -1
  158. package/dist/scene/msdftext.js +2 -0
  159. package/dist/scene/msdftext.js.map +1 -1
  160. package/dist/scene/msdftextsprite.js +2 -0
  161. package/dist/scene/msdftextsprite.js.map +1 -1
  162. package/dist/scene/particlesys.js +2 -0
  163. package/dist/scene/particlesys.js.map +1 -1
  164. package/dist/scene/scene.js +34 -1
  165. package/dist/scene/scene.js.map +1 -1
  166. package/dist/scene/terrain-cm/grass.js +2 -1
  167. package/dist/scene/terrain-cm/grass.js.map +1 -1
  168. package/dist/scene/terrain-cm/terrain-cm.js +2 -0
  169. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  170. package/dist/scene/water.js +2 -0
  171. package/dist/scene/water.js.map +1 -1
  172. package/dist/shaders/atmosphere.js +5 -4
  173. package/dist/shaders/atmosphere.js.map +1 -1
  174. package/dist/shaders/fog.js +10 -3
  175. package/dist/shaders/fog.js.map +1 -1
  176. package/dist/shaders/shadow.js +96 -29
  177. package/dist/shaders/shadow.js.map +1 -1
  178. package/dist/shaders/ssgi.js +63 -0
  179. package/dist/shaders/ssgi.js.map +1 -0
  180. package/dist/shaders/ssgi_reprojection.js +118 -0
  181. package/dist/shaders/ssgi_reprojection.js.map +1 -0
  182. package/dist/shaders/ssr.js +322 -154
  183. package/dist/shaders/ssr.js.map +1 -1
  184. package/dist/shadow/esm.js +13 -8
  185. package/dist/shadow/esm.js.map +1 -1
  186. package/dist/shadow/pcf_opt.js +15 -12
  187. package/dist/shadow/pcf_opt.js.map +1 -1
  188. package/dist/shadow/pcf_pd.js +15 -12
  189. package/dist/shadow/pcf_pd.js.map +1 -1
  190. package/dist/shadow/pcss.js +17 -11
  191. package/dist/shadow/pcss.js.map +1 -1
  192. package/dist/shadow/shadow_impl.js +20 -2
  193. package/dist/shadow/shadow_impl.js.map +1 -1
  194. package/dist/shadow/shadowmapper.js +10 -3
  195. package/dist/shadow/shadowmapper.js.map +1 -1
  196. package/dist/shadow/ssm.js +16 -13
  197. package/dist/shadow/ssm.js.map +1 -1
  198. package/dist/shadow/vsm.js +10 -8
  199. package/dist/shadow/vsm.js.map +1 -1
  200. package/dist/utility/physical.js +74 -0
  201. package/dist/utility/physical.js.map +1 -0
  202. package/dist/utility/rendermipmap.js +2 -2
  203. package/dist/utility/rendermipmap.js.map +1 -1
  204. package/dist/utility/serialization/manager.js +3 -1
  205. package/dist/utility/serialization/manager.js.map +1 -1
  206. package/dist/utility/serialization/scene/animation.js +3 -1
  207. package/dist/utility/serialization/scene/animation.js.map +1 -1
  208. package/dist/utility/serialization/scene/batch.js +3 -1
  209. package/dist/utility/serialization/scene/batch.js.map +1 -1
  210. package/dist/utility/serialization/scene/camera.js +598 -2
  211. package/dist/utility/serialization/scene/camera.js.map +1 -1
  212. package/dist/utility/serialization/scene/light.js +180 -9
  213. package/dist/utility/serialization/scene/light.js.map +1 -1
  214. package/dist/utility/serialization/scene/material.js +43 -3
  215. package/dist/utility/serialization/scene/material.js.map +1 -1
  216. package/dist/utility/serialization/scene/mesh.js +3 -1
  217. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  218. package/dist/utility/serialization/scene/node.js +3 -1
  219. package/dist/utility/serialization/scene/node.js.map +1 -1
  220. package/dist/utility/serialization/scene/particle.js +3 -1
  221. package/dist/utility/serialization/scene/particle.js.map +1 -1
  222. package/dist/utility/serialization/scene/primitive.js +2 -0
  223. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  224. package/dist/utility/serialization/scene/scene.js +70 -0
  225. package/dist/utility/serialization/scene/scene.js.map +1 -1
  226. package/dist/utility/serialization/scene/sprite.js +3 -1
  227. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  228. package/dist/utility/serialization/scene/terrain.js +3 -1
  229. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  230. package/dist/utility/serialization/scene/text.js +3 -0
  231. package/dist/utility/serialization/scene/text.js.map +1 -1
  232. package/dist/utility/serialization/scene/water.js +3 -1
  233. package/dist/utility/serialization/scene/water.js.map +1 -1
  234. package/dist/values.js +2 -3
  235. package/dist/values.js.map +1 -1
  236. package/package.json +3 -3
  237. package/dist/animation/joint_dynamics/convex_collider.js +0 -320
  238. package/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
@@ -11,113 +11,74 @@ const DEFAULT_PROFILING_OPTIONS = {
11
11
  maxPendingFrames: 3,
12
12
  label: 'RenderGraph'
13
13
  };
14
- /**
15
- * Executes a compiled render graph with automatic resource lifecycle management.
16
- *
17
- * The executor allocates transient textures before their first use and releases
18
- * them after their last use, using the provided {@link RGTextureAllocator}.
19
- *
20
- * Usage:
21
- * ```ts
22
- * const executor = new RenderGraphExecutor(myAllocator, backbufferWidth, backbufferHeight);
23
- * executor.setImportedTexture(backbufferHandle, actualBackbufferTexture);
24
- * executor.execute(compiledGraph);
25
- * ```
26
- *
27
- * @typeParam TTexture - The concrete texture type (e.g. `Texture2D`).
28
- * @public
29
- */ class RenderGraphExecutor {
14
+ /** Executes compiled graphs with automatic resource lifetimes. @public */ class RenderGraphExecutor {
30
15
  static _defaultProfilingOptions = false;
31
16
  static _latestProfileResult = null;
32
17
  static _latestPendingProfileFrame = null;
33
18
  static _latestResolvedProfileSerial = 0;
34
19
  static _nextProfileSerial = 0;
35
- /** @internal */ _allocator;
36
- /** @internal */ _backbufferWidth;
37
- /** @internal */ _backbufferHeight;
38
- /** @internal */ _importedTextures = new Map();
39
- /** @internal */ _allocatedTextures = new Map();
40
- /** @internal */ _allocatedFramebuffers = new Map();
41
- /** @internal */ _importedTextureAliases = new Map();
42
- /** @internal */ _transientTextureAliases = new Map();
43
- /** @internal */ _resolvedImportedTextures = new Map();
44
- /** @internal */ _cleanupCallbacks = [];
45
- /** @internal */ _profilingOptions;
46
- /** @internal */ _pendingProfileFrames = [];
47
- /** @internal */ _latestProfileResult = null;
48
- /** @internal */ _latestResolvedProfileSerial = 0;
20
+ _allocator;
21
+ _backbufferWidth;
22
+ _backbufferHeight;
23
+ _importedTextures = new Map();
24
+ _allocatedTextures = new Map();
25
+ _allocatedFramebuffers = new Map();
26
+ _importedTextureAliases = new Map();
27
+ _transientTextureAliases = new Map();
28
+ _resolvedImportedTextures = new Map();
29
+ _cleanupCallbacks = [];
30
+ _profilingOptions;
31
+ _pendingProfileFrames = [];
32
+ _latestProfileResult = null;
33
+ _latestResolvedProfileSerial = 0;
34
+ _textureAffinityCache;
49
35
  constructor(allocator, backbufferWidth, backbufferHeight, options){
50
36
  this._allocator = allocator;
51
37
  this._backbufferWidth = backbufferWidth;
52
38
  this._backbufferHeight = backbufferHeight;
53
39
  this._profilingOptions = this._normalizeProfilingOptions(options?.profiling ?? RenderGraphExecutor._defaultProfilingOptions, options?.device);
40
+ this._textureAffinityCache = options?.textureAffinityCache ?? null;
54
41
  }
55
- /**
56
- * Set the default profiling options used by newly constructed render graph executors.
57
- */ static setDefaultProfilingOptions(options) {
42
+ /** Set profiling defaults for new executors. */ static setDefaultProfilingOptions(options) {
58
43
  RenderGraphExecutor._defaultProfilingOptions = options;
59
44
  }
60
- /**
61
- * Get the latest resolved profile result from any render graph executor.
62
- */ static getLatestProfileResult() {
45
+ /** Return the latest resolved result from any executor. */ static getLatestProfileResult() {
63
46
  return RenderGraphExecutor._latestProfileResult;
64
47
  }
65
- /**
66
- * Resolve the latest pending render graph profile result from any executor.
67
- */ static resolveProfileResult() {
48
+ /** Resolve the latest pending result from any executor. */ static resolveProfileResult() {
68
49
  return RenderGraphExecutor._latestPendingProfileFrame?.resolvePromise ?? Promise.resolve(RenderGraphExecutor._latestProfileResult);
69
50
  }
70
- /**
71
- * Enable, disable, or update timestamp profiling for this executor.
72
- */ setProfilingOptions(options) {
51
+ /** Update timestamp profiling for this executor. */ setProfilingOptions(options) {
73
52
  this._profilingOptions = this._normalizeProfilingOptions(options, this._profilingOptions.device);
74
53
  }
75
- /**
76
- * Get the latest resolved profile result produced by this executor.
77
- */ getLatestProfileResult() {
54
+ /** Return this executor's latest resolved profile. */ getLatestProfileResult() {
78
55
  return this._latestProfileResult;
79
56
  }
80
- /**
81
- * Resolve the latest pending profile result produced by this executor.
82
- */ resolveProfileResult() {
57
+ /** Resolve this executor's latest pending profile. */ resolveProfileResult() {
83
58
  return this._pendingProfileFrames[this._pendingProfileFrames.length - 1]?.resolvePromise ?? Promise.resolve(this._latestProfileResult);
84
59
  }
85
- /**
86
- * Update the backbuffer dimensions used for 'backbuffer-relative' sizing.
87
- */ setBackbufferSize(width, height) {
60
+ /** Update dimensions used for backbuffer-relative resources. */ setBackbufferSize(width, height) {
88
61
  this._backbufferWidth = width;
89
62
  this._backbufferHeight = height;
90
63
  }
91
- /**
92
- * Register an imported (external) texture so it can be resolved during execution.
93
- *
94
- * @param handle - The handle returned from {@link RenderGraph.importTexture}.
95
- * @param texture - The actual GPU texture object.
96
- */ setImportedTexture(handle, texture) {
64
+ /** Bind an imported texture for execution. */ setImportedTexture(handle, texture) {
97
65
  this._importedTextures.set(handle._id, texture);
98
66
  }
99
- /**
100
- * Execute the compiled graph with full resource lifecycle management.
101
- *
102
- * For each pass in topological order:
103
- * 1. Allocate any transient resources whose lifetime begins at this pass
104
- * 2. Invoke the pass's execute callback with a context that resolves handles
105
- * 3. Release any transient resources whose lifetime ends at this pass
106
- *
107
- * @param compiled - The compiled graph from {@link RenderGraph.compile}.
108
- */ execute(compiled) {
67
+ /** Execute a compiled graph and manage its transient resources. */ execute(compiled, bindings) {
68
+ if (bindings?.importedTextures) {
69
+ for (const [handle, texture] of bindings.importedTextures){
70
+ this.setImportedTexture(handle, texture);
71
+ }
72
+ }
109
73
  this._cleanupCallbacks.length = 0;
110
74
  this._resolveImportedTextureAliases(compiled);
111
75
  const profileFrame = this._beginProfileFrame();
112
- // Build per-pass allocation and release schedules
113
- const allocateAt = new Map(); // passIndex -> transient texture resourceIds to allocate
114
- const releaseAt = new Map(); // passIndex -> transient texture resourceIds to release
115
- const allocateFramebufferAt = new Map(); // passIndex -> framebuffer resourceIds to allocate
116
- const releaseFramebufferAt = new Map(); // passIndex -> framebuffer resourceIds to release
117
- // Transient write-versions (builder.write on a transient) alias the same
118
- // physical texture as the original resource: merge their lifetimes by
119
- // physicalId so one texture is allocated at the first use of any version
120
- // and released after the last use of any version.
76
+ const affinityEntries = new Map();
77
+ const allocateAt = new Map();
78
+ const releaseAt = new Map();
79
+ const allocateFramebufferAt = new Map();
80
+ const releaseFramebufferAt = new Map();
81
+ // Merge lifetimes of versions sharing one physical texture.
121
82
  this._transientTextureAliases.clear();
122
83
  const transientSchedules = new Map();
123
84
  for (const [resId, lifetime] of compiled.lifetimes){
@@ -132,7 +93,8 @@ const DEFAULT_PROFILING_OPTIONS = {
132
93
  transientSchedules.set(physicalId, {
133
94
  firstUse: lifetime.firstUse,
134
95
  lastUse: lifetime.lastUse,
135
- desc: lifetime.resource.desc
96
+ desc: lifetime.resource.desc,
97
+ allocationKey: lifetime.resource.allocationKey
136
98
  });
137
99
  }
138
100
  } else if (lifetime.resource.kind === 'framebuffer') {
@@ -161,17 +123,24 @@ const DEFAULT_PROFILING_OPTIONS = {
161
123
  try {
162
124
  for(let i = 0; i < compiled.orderedPasses.length; i++){
163
125
  const pass = compiled.orderedPasses[i];
164
- // Allocate resources that start at this pass
165
126
  const toAllocate = allocateAt.get(i);
166
127
  if (toAllocate) {
167
128
  for (const resId of toAllocate){
168
129
  const schedule = transientSchedules.get(resId);
169
130
  const size = this._resolveSize(schedule.desc);
170
- const texture = this._allocator.allocate(schedule.desc, size);
131
+ const descriptorSignature = this._getTextureDescriptorSignature(schedule.desc, size);
132
+ const preferred = schedule.allocationKey ? this._textureAffinityCache?.getPreferredTexture(schedule.allocationKey, descriptorSignature) : undefined;
133
+ const texture = this._allocator.allocate(schedule.desc, size, preferred);
171
134
  this._allocatedTextures.set(resId, texture);
135
+ if (schedule.allocationKey) {
136
+ affinityEntries.set(schedule.allocationKey, {
137
+ texture,
138
+ descriptorSignature
139
+ });
140
+ }
172
141
  }
173
142
  }
174
- // Allocate framebuffer views after their texture attachments are available.
143
+ // Allocate framebuffers after their attachments.
175
144
  const framebuffersToAllocate = allocateFramebufferAt.get(i);
176
145
  if (framebuffersToAllocate) {
177
146
  for (const resId of framebuffersToAllocate){
@@ -181,8 +150,7 @@ const DEFAULT_PROFILING_OPTIONS = {
181
150
  this._allocatedFramebuffers.set(resId, framebuffer);
182
151
  }
183
152
  }
184
- // Execute the pass with exception safety for resource cleanup.
185
- // Release errors must not hide the original pass execution error.
153
+ // Preserve pass errors ahead of release errors.
186
154
  let passError = null;
187
155
  const passProfile = this._beginPassProfileScope(profileFrame, pass);
188
156
  try {
@@ -224,7 +192,6 @@ const DEFAULT_PROFILING_OPTIONS = {
224
192
  }
225
193
  }
226
194
  }
227
- // Release resources that end at this pass (always runs even if pass throws)
228
195
  const toRelease = releaseAt.get(i);
229
196
  if (toRelease) {
230
197
  for (const resId of toRelease){
@@ -265,6 +232,9 @@ const DEFAULT_PROFILING_OPTIONS = {
265
232
  }
266
233
  }
267
234
  }
235
+ if (completed && !executionError && !cleanupError) {
236
+ this._textureAffinityCache?.replace(affinityEntries);
237
+ }
268
238
  if (executionError) {
269
239
  throw executionError;
270
240
  }
@@ -273,12 +243,9 @@ const DEFAULT_PROFILING_OPTIONS = {
273
243
  }
274
244
  }
275
245
  }
276
- /**
277
- * Clear imported texture registrations and any leftover allocated textures.
278
- * Call this after execution or when resetting for a new frame.
279
- */ reset() {
246
+ /** Release remaining resources and clear imported bindings. */ reset() {
280
247
  this._runCleanupCallbacks();
281
- // Release any textures that weren't released (shouldn't happen in normal flow)
248
+ // Handles aborted execution and allocator failures.
282
249
  for (const framebuffer of this._allocatedFramebuffers.values()){
283
250
  this._releaseFramebuffer(framebuffer);
284
251
  }
@@ -292,8 +259,7 @@ const DEFAULT_PROFILING_OPTIONS = {
292
259
  this._transientTextureAliases.clear();
293
260
  this._resolvedImportedTextures.clear();
294
261
  }
295
- // ─── Private ────────────────────────────────────────────────────────
296
- /** @internal */ _normalizeProfilingOptions(options, fallbackDevice) {
262
+ _normalizeProfilingOptions(options, fallbackDevice) {
297
263
  const source = typeof options === 'object' ? options : {};
298
264
  const enabled = typeof options === 'boolean' ? options : source.enabled ?? true;
299
265
  return {
@@ -308,7 +274,7 @@ const DEFAULT_PROFILING_OPTIONS = {
308
274
  device: source.device ?? fallbackDevice
309
275
  };
310
276
  }
311
- /** @internal */ _getProfilingDevice() {
277
+ _getProfilingDevice() {
312
278
  if (this._profilingOptions.device) {
313
279
  return this._profilingOptions.device;
314
280
  }
@@ -318,7 +284,7 @@ const DEFAULT_PROFILING_OPTIONS = {
318
284
  return null;
319
285
  }
320
286
  }
321
- /** @internal */ _beginProfileFrame() {
287
+ _beginProfileFrame() {
322
288
  if (!this._profilingOptions.enabled) {
323
289
  return null;
324
290
  }
@@ -358,20 +324,20 @@ const DEFAULT_PROFILING_OPTIONS = {
358
324
  }
359
325
  return frame;
360
326
  }
361
- /** @internal */ _beginPassProfileScope(frame, pass) {
327
+ _beginPassProfileScope(frame, pass) {
362
328
  if (!frame || !this._profilingOptions.pass && !this._profilingOptions.subpass) {
363
329
  return null;
364
330
  }
365
331
  return this._beginProfileScope(frame, frame.root, 'pass', pass.name, this._profilingOptions.pass);
366
332
  }
367
- /** @internal */ _beginSubpassProfileScope(frame, passScope, pass, subpassName) {
333
+ _beginSubpassProfileScope(frame, passScope, pass, subpassName) {
368
334
  if (!frame || !this._profilingOptions.subpass) {
369
335
  return null;
370
336
  }
371
337
  const parent = passScope ?? frame.root;
372
338
  return this._beginProfileScope(frame, parent, 'subpass', subpassName, true, `${pass.name}/${subpassName}`);
373
339
  }
374
- /** @internal */ _beginProfileScope(frame, parent, type, name, queryEnabled, queryLabel) {
340
+ _beginProfileScope(frame, parent, type, name, queryEnabled, queryLabel) {
375
341
  const status = frame.supported && !queryEnabled ? 'resolved' : frame.supported ? 'pending' : 'unsupported';
376
342
  const result = {
377
343
  name,
@@ -393,7 +359,7 @@ const DEFAULT_PROFILING_OPTIONS = {
393
359
  }
394
360
  return scope;
395
361
  }
396
- /** @internal */ _beginTimestampScope(frame, scope, label) {
362
+ _beginTimestampScope(frame, scope, label) {
397
363
  if (!frame.supported || !frame.device) {
398
364
  scope.result.status = 'unsupported';
399
365
  scope.result.message = 'GPU timestamp queries are not supported';
@@ -413,7 +379,7 @@ const DEFAULT_PROFILING_OPTIONS = {
413
379
  scope.result.message = 'GPU timestamp query was not started';
414
380
  }
415
381
  }
416
- /** @internal */ _endProfileScope(frame, scope) {
382
+ _endProfileScope(frame, scope) {
417
383
  if (!frame || !frame.device || !scope || scope.ended) {
418
384
  return;
419
385
  }
@@ -422,7 +388,7 @@ const DEFAULT_PROFILING_OPTIONS = {
422
388
  frame.device.endTimestampQuery(scope.queryId);
423
389
  }
424
390
  }
425
- /** @internal */ _finishProfileFrame(frame) {
391
+ _finishProfileFrame(frame) {
426
392
  if (!frame) {
427
393
  return;
428
394
  }
@@ -451,14 +417,14 @@ const DEFAULT_PROFILING_OPTIONS = {
451
417
  });
452
418
  this._trackPendingProfileFrame(frame);
453
419
  }
454
- /** @internal */ _trackPendingProfileFrame(frame) {
420
+ _trackPendingProfileFrame(frame) {
455
421
  this._pendingProfileFrames.push(frame);
456
422
  while(this._pendingProfileFrames.length > this._profilingOptions.maxPendingFrames){
457
423
  this._pendingProfileFrames.shift();
458
424
  }
459
425
  RenderGraphExecutor._latestPendingProfileFrame = frame;
460
426
  }
461
- /** @internal */ _publishProfileResult(frame) {
427
+ _publishProfileResult(frame) {
462
428
  this._pendingProfileFrames = this._pendingProfileFrames.filter((pending)=>pending !== frame);
463
429
  if (frame.serial >= this._latestResolvedProfileSerial) {
464
430
  this._latestResolvedProfileSerial = frame.serial;
@@ -472,13 +438,13 @@ const DEFAULT_PROFILING_OPTIONS = {
472
438
  RenderGraphExecutor._latestPendingProfileFrame = null;
473
439
  }
474
440
  }
475
- /** @internal */ _applyTimestampResult(scope, result) {
441
+ _applyTimestampResult(scope, result) {
476
442
  scope.result.queryId = result.id;
477
443
  scope.result.durationMs = result.durationMs;
478
444
  scope.result.status = result.status;
479
445
  scope.result.message = result.message;
480
446
  }
481
- /** @internal */ _aggregateProfileStatus(scope) {
447
+ _aggregateProfileStatus(scope) {
482
448
  const statuses = [];
483
449
  const collect = (node)=>{
484
450
  statuses.push(node.status);
@@ -503,7 +469,7 @@ const DEFAULT_PROFILING_OPTIONS = {
503
469
  }
504
470
  return 'resolved';
505
471
  }
506
- /** @internal */ _resolveSize(desc) {
472
+ _resolveSize(desc) {
507
473
  const mode = desc.sizeMode ?? 'backbuffer-relative';
508
474
  if (mode === 'absolute') {
509
475
  return {
@@ -511,7 +477,6 @@ const DEFAULT_PROFILING_OPTIONS = {
511
477
  height: desc.height ?? 1
512
478
  };
513
479
  }
514
- // backbuffer-relative: width/height are scale factors (default 1.0)
515
480
  const scaleX = desc.width ?? 1.0;
516
481
  const scaleY = desc.height ?? 1.0;
517
482
  return {
@@ -519,7 +484,16 @@ const DEFAULT_PROFILING_OPTIONS = {
519
484
  height: Math.max(1, Math.floor(this._backbufferHeight * scaleY))
520
485
  };
521
486
  }
522
- /** @internal */ _resolveImportedTextureAliases(compiled) {
487
+ _getTextureDescriptorSignature(desc, size) {
488
+ return JSON.stringify([
489
+ desc.format,
490
+ size.width,
491
+ size.height,
492
+ desc.mipLevels ?? 1,
493
+ desc.arrayLayers ?? null
494
+ ]);
495
+ }
496
+ _resolveImportedTextureAliases(compiled) {
523
497
  this._importedTextureAliases.clear();
524
498
  this._resolvedImportedTextures.clear();
525
499
  const physicalToTexture = new Map();
@@ -546,7 +520,7 @@ const DEFAULT_PROFILING_OPTIONS = {
546
520
  }
547
521
  }
548
522
  }
549
- /** @internal */ _runCleanupCallbacks() {
523
+ _runCleanupCallbacks() {
550
524
  let error = null;
551
525
  while(this._cleanupCallbacks.length > 0){
552
526
  const callback = this._cleanupCallbacks.pop();
@@ -560,7 +534,7 @@ const DEFAULT_PROFILING_OPTIONS = {
560
534
  throw error;
561
535
  }
562
536
  }
563
- /** @internal */ _createFramebuffer(desc, autoCleanup = true) {
537
+ _createFramebuffer(desc, autoCleanup = true) {
564
538
  if (!this._allocator.allocateFramebuffer || !this._allocator.releaseFramebuffer) {
565
539
  throw new Error('RenderGraphExecutor: framebuffer allocation is not supported by this allocator.');
566
540
  }
@@ -572,13 +546,13 @@ const DEFAULT_PROFILING_OPTIONS = {
572
546
  }
573
547
  return framebuffer;
574
548
  }
575
- /** @internal */ _releaseFramebuffer(framebuffer) {
549
+ _releaseFramebuffer(framebuffer) {
576
550
  if (!this._allocator.releaseFramebuffer) {
577
551
  throw new Error('RenderGraphExecutor: framebuffer release is not supported by this allocator.');
578
552
  }
579
553
  this._allocator.releaseFramebuffer(framebuffer);
580
554
  }
581
- /** @internal */ _resolveFramebufferDesc(desc, accessScope) {
555
+ _resolveFramebufferDesc(desc, accessScope) {
582
556
  const resolveAttachment = (attachment)=>{
583
557
  if (attachment instanceof RGHandle) {
584
558
  if (accessScope) {
@@ -595,7 +569,7 @@ const DEFAULT_PROFILING_OPTIONS = {
595
569
  depthAttachment: resolveAttachment(desc.depthAttachment)
596
570
  };
597
571
  }
598
- /** @internal */ _resolveResource(handle) {
572
+ _resolveResource(handle) {
599
573
  const imported = this._importedTextures.get(handle._id);
600
574
  if (imported !== undefined) {
601
575
  return imported;
@@ -615,7 +589,7 @@ const DEFAULT_PROFILING_OPTIONS = {
615
589
  if (allocated !== undefined) {
616
590
  return allocated;
617
591
  }
618
- // Transient write-versions resolve to the physical texture of the original.
592
+ // Written versions alias the original physical texture.
619
593
  const transientAlias = this._transientTextureAliases.get(handle._id);
620
594
  if (transientAlias !== undefined) {
621
595
  const aliased = this._allocatedTextures.get(transientAlias);
@@ -625,7 +599,7 @@ const DEFAULT_PROFILING_OPTIONS = {
625
599
  }
626
600
  throw new Error(`RenderGraphExecutor: cannot resolve resource "${handle.name}" (id=${handle._id}). ` + `It may not have been allocated yet or was already released.`);
627
601
  }
628
- /** @internal */ _createAccessScope(pass) {
602
+ _createAccessScope(pass) {
629
603
  const accessibleIds = new Set();
630
604
  const textureIds = new Set();
631
605
  const framebufferIds = new Set();
@@ -652,7 +626,7 @@ const DEFAULT_PROFILING_OPTIONS = {
652
626
  framebufferIds
653
627
  };
654
628
  }
655
- /** @internal */ _assertDeclaredAccess(accessScope, handle, access) {
629
+ _assertDeclaredAccess(accessScope, handle, access) {
656
630
  if (!accessScope.accessibleIds.has(handle._id)) {
657
631
  throw new Error(`RenderGraphExecutor: pass "${accessScope.passName}" tried to access ${access} "${handle.name}" ` + `without declaring a read/write dependency.`);
658
632
  }
@@ -663,13 +637,13 @@ const DEFAULT_PROFILING_OPTIONS = {
663
637
  throw new Error(`RenderGraphExecutor: pass "${accessScope.passName}" tried to access "${handle.name}" as a framebuffer, ` + `but it is not a framebuffer resource.`);
664
638
  }
665
639
  }
666
- /** @internal */ _wrapSubpassError(passName, subpassName, error) {
640
+ _wrapSubpassError(passName, subpassName, error) {
667
641
  const message = error instanceof Error ? error.message : String(error);
668
642
  const wrapped = new Error(`RenderGraphExecutor: pass "${passName}" subpass "${subpassName}" failed: ${message}`);
669
643
  wrapped.cause = error;
670
644
  return wrapped;
671
645
  }
672
- /** @internal */ _createContext(accessScope) {
646
+ _createContext(accessScope) {
673
647
  const self = this;
674
648
  return {
675
649
  getTexture (handle) {