@woosh/meep-engine 3.39.0 → 3.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/engine/EngineHarness.d.ts.map +1 -1
  4. package/src/engine/EngineHarness.js +17 -4
  5. package/src/engine/asset/loaders/image/avif/threaded_image_encoder.js +1 -1
  6. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  7. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
  8. package/src/engine/graphics/ecs/water/Water.d.ts +14 -17
  9. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  10. package/src/engine/graphics/ecs/water/Water.js +100 -110
  11. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
  12. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +36 -38
  13. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.d.ts +6 -0
  14. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.d.ts.map +1 -0
  15. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.js +10 -0
  16. package/src/engine/graphics/ecs/water/WaterWaves.d.ts +3 -3
  17. package/src/engine/graphics/ecs/water/WaterWaves.js +46 -46
  18. package/src/engine/graphics/texture/sampler/sampler2d_to_avif.d.ts.map +1 -1
  19. package/src/engine/graphics/texture/sampler/sampler2d_to_avif.js +8 -5
  20. package/src/engine/graphics3/WaterSystem.d.ts +21 -74
  21. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  22. package/src/engine/graphics3/WaterSystem.js +174 -367
  23. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  24. package/src/format/image/avif/api/convert_to_rgba.d.ts +2 -2
  25. package/src/format/image/avif/api/convert_to_rgba.d.ts.map +1 -1
  26. package/src/format/image/avif/api/convert_to_rgba.js +10 -9
  27. package/src/format/image/avif/api/decode_avif.d.ts +2 -2
  28. package/src/format/image/avif/api/decode_avif.d.ts.map +1 -1
  29. package/src/format/image/avif/api/decode_avif.js +1 -1
  30. package/src/shade/playground/ssr_reprojection/README.md +111 -103
  31. package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.js +68 -68
  32. package/src/shade/playground/ssr_reprojection/index.html +80 -79
  33. package/src/shade/playground/ssr_reprojection/main.js +256 -247
  34. package/src/shade/playground/ssr_variance/capture.js +96 -96
  35. package/src/shade/playground/ssr_variance/reference.js +78 -78
  36. package/src/shade/playground/vsm/README.md +96 -0
  37. package/src/shade/playground/vsm/VSMDebugOverlay.d.ts +49 -0
  38. package/src/shade/playground/vsm/VSMDebugOverlay.d.ts.map +1 -0
  39. package/src/shade/playground/vsm/VSMDebugOverlay.js +351 -0
  40. package/src/shade/playground/vsm/clipmap_panel.d.ts +8 -0
  41. package/src/shade/playground/vsm/clipmap_panel.d.ts.map +1 -0
  42. package/src/shade/playground/vsm/clipmap_panel.js +138 -0
  43. package/src/shade/playground/vsm/index.html +170 -0
  44. package/src/shade/playground/vsm/main.d.ts +2 -0
  45. package/src/shade/playground/vsm/main.d.ts.map +1 -0
  46. package/src/shade/playground/vsm/main.js +389 -0
  47. package/src/shade/playground/vsm/scenes.d.ts +52 -0
  48. package/src/shade/playground/vsm/scenes.d.ts.map +1 -0
  49. package/src/shade/playground/vsm/scenes.js +320 -0
  50. package/src/shade/playground/vsm/verify_vsm.d.ts +38 -0
  51. package/src/shade/playground/vsm/verify_vsm.d.ts.map +1 -0
  52. package/src/shade/playground/vsm/verify_vsm.js +305 -0
  53. package/src/shade/playground/water_refraction/README.md +57 -9
  54. package/src/shade/playground/water_refraction/main.js +12 -3
  55. package/src/shade/playground/water_refraction/world.d.ts +1 -0
  56. package/src/shade/playground/water_refraction/world.d.ts.map +1 -1
  57. package/src/shade/playground/water_refraction/world.js +15 -5
  58. package/src/shade/renderer/Renderer.d.ts +19 -0
  59. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  60. package/src/shade/renderer/Renderer.js +72 -1
  61. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +8 -0
  62. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  63. package/src/shade/renderer/animation/GPUAnimationManager.js +18 -0
  64. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +7 -0
  65. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  66. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -0
  67. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts +3 -1
  68. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
  69. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +10 -1
  70. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_read_code.d.ts.map +1 -1
  71. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_read_code.js +28 -0
  72. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_write_code.d.ts.map +1 -1
  73. package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_write_code.js +31 -1
  74. package/src/shade/renderer/geometry/MeshletGeometry.d.ts +3 -0
  75. package/src/shade/renderer/geometry/MeshletGeometry.d.ts.map +1 -1
  76. package/src/shade/renderer/geometry/MeshletGeometry.js +1 -0
  77. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
  78. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +62 -4
  79. package/src/shade/renderer/light/environment/rgbe/parse_rgbe.d.ts +1 -1
  80. package/src/shade/renderer/light/environment/rgbe/parse_rgbe.js +2 -2
  81. package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.d.ts +2 -2
  82. package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.d.ts.map +1 -1
  83. package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.js +6 -14
  84. package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.d.ts.map +1 -1
  85. package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.js +5 -1
  86. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  87. package/src/shade/renderer/medium/ParticipatingMedium.d.ts +3 -0
  88. package/src/shade/renderer/medium/ParticipatingMedium.d.ts.map +1 -1
  89. package/src/shade/renderer/medium/ParticipatingMedium.js +7 -0
  90. package/src/shade/renderer/postprocess/eye/shader_autoexposure_build_histogram.d.ts.map +1 -1
  91. package/src/shade/renderer/postprocess/eye/shader_autoexposure_build_histogram.js +5 -35
  92. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  93. package/src/shade/renderer/postprocess/ssr/SSR.d.ts +12 -4
  94. package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
  95. package/src/shade/renderer/postprocess/ssr/SSR.js +36 -8
  96. package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.d.ts +3 -0
  97. package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.d.ts.map +1 -0
  98. package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.js +2 -0
  99. package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.d.ts +8 -0
  100. package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.d.ts.map +1 -0
  101. package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.js +40 -0
  102. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  103. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +150 -137
  104. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.d.ts +3 -0
  105. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.d.ts.map +1 -0
  106. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.js +44 -0
  107. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.d.ts +5 -0
  108. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.d.ts.map +1 -0
  109. package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.js +35 -0
  110. package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.d.ts +26 -0
  111. package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.d.ts.map +1 -0
  112. package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.js +42 -0
  113. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts +1 -0
  114. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
  115. package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +113 -105
  116. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts +2 -0
  117. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  118. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +177 -167
  119. package/src/shade/renderer/rasterize/DEPTH_STENCIL_STATE_SHADOW.d.ts.map +1 -1
  120. package/src/shade/renderer/rasterize/DEPTH_STENCIL_STATE_SHADOW.js +10 -0
  121. package/src/shade/renderer/rasterize/RasterizationJob.d.ts +1 -2
  122. package/src/shade/renderer/rasterize/RasterizationJob.d.ts.map +1 -1
  123. package/src/shade/renderer/rasterize/RasterizationJob.js +1 -2
  124. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts +5 -6
  125. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
  126. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +5 -6
  127. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +2 -2
  128. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  129. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +1 -1
  130. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
  131. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +11 -0
  132. package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/build_lut_fog_parameters_jendersie_deon.d.ts.map +1 -1
  133. package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/build_lut_fog_parameters_jendersie_deon.js +4 -5
  134. package/src/shade/renderer/shader/chunk/brdf/dfg/generate_dfg_texture.d.ts.map +1 -1
  135. package/src/shade/renderer/shader/chunk/brdf/dfg/generate_dfg_texture.js +1 -5
  136. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.d.ts +30 -0
  137. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.d.ts.map +1 -0
  138. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.js +54 -0
  139. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  140. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +3 -2
  141. package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.d.ts +19 -0
  142. package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.d.ts.map +1 -0
  143. package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.js +27 -0
  144. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts +1 -0
  145. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
  146. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +4 -0
  147. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +54 -0
  148. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  149. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +502 -10
  150. package/src/shade/renderer/shadow/map/Shadowmap.d.ts +3 -2
  151. package/src/shade/renderer/shadow/map/Shadowmap.d.ts.map +1 -1
  152. package/src/shade/renderer/shadow/map/Shadowmap.js +3 -2
  153. package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.d.ts +8 -0
  154. package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.d.ts.map +1 -1
  155. package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.js +34 -3
  156. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts +3 -2
  157. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts.map +1 -1
  158. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.js +17 -2
  159. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.d.ts.map +1 -1
  160. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.js +137 -133
  161. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.d.ts +15 -0
  162. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.d.ts.map +1 -0
  163. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.js +14 -0
  164. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.d.ts +16 -0
  165. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.d.ts.map +1 -0
  166. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.js +15 -0
  167. package/src/shade/renderer/shadow/vsm/PLAN.md +440 -0
  168. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +43 -0
  169. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts +42 -0
  170. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts.map +1 -0
  171. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.js +153 -0
  172. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts +327 -0
  173. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts.map +1 -0
  174. package/src/shade/renderer/shadow/vsm/VSMPageManager.js +1408 -0
  175. package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.d.ts +14 -0
  176. package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.d.ts.map +1 -0
  177. package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.js +13 -0
  178. package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.d.ts +63 -0
  179. package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.d.ts.map +1 -0
  180. package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.js +70 -0
  181. package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.d.ts +11 -0
  182. package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.d.ts.map +1 -0
  183. package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.js +10 -0
  184. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts +54 -0
  185. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts.map +1 -0
  186. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.js +75 -0
  187. package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.d.ts +23 -0
  188. package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.d.ts.map +1 -0
  189. package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.js +85 -0
  190. package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.d.ts +16 -0
  191. package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.d.ts.map +1 -0
  192. package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.js +29 -0
  193. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts +136 -25
  194. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
  195. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +282 -116
  196. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts +39 -0
  197. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts.map +1 -0
  198. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.js +289 -0
  199. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.d.ts +18 -0
  200. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.d.ts.map +1 -0
  201. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.js +65 -0
  202. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.d.ts +17 -0
  203. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.d.ts.map +1 -0
  204. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.js +75 -0
  205. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts +14 -0
  206. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts.map +1 -0
  207. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.js +45 -0
  208. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.d.ts +17 -0
  209. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.d.ts.map +1 -0
  210. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.js +100 -0
  211. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.d.ts +15 -0
  212. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.d.ts.map +1 -0
  213. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.js +47 -0
  214. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.d.ts +26 -0
  215. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.d.ts.map +1 -0
  216. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.js +156 -0
  217. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.d.ts +13 -0
  218. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.d.ts.map +1 -0
  219. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.js +65 -0
  220. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts +30 -0
  221. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts.map +1 -0
  222. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.js +184 -0
  223. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts +23 -0
  224. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts.map +1 -0
  225. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.js +109 -0
  226. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.d.ts +56 -0
  227. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.d.ts.map +1 -0
  228. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.js +211 -0
  229. package/src/shade/renderer/texture/format/decode_typed_gpu_data.d.ts +1 -1
  230. package/src/shade/renderer/texture/format/decode_typed_gpu_data.d.ts.map +1 -1
  231. package/src/shade/renderer/texture/format/decode_typed_gpu_data.js +3 -13
  232. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts.map +1 -1
  233. package/src/shade/renderer/texture/format/infer_format_from_parameters.js +2 -3
  234. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts.map +1 -1
  235. package/src/shade/renderer/texture/texture_write_to_gpu.js +16 -16
  236. package/src/shade/renderer/texture/virtual/VTPhysicalCache.d.ts +4 -90
  237. package/src/shade/renderer/texture/virtual/VTPhysicalCache.d.ts.map +1 -1
  238. package/src/shade/renderer/texture/virtual/VTPhysicalCache.js +6 -210
  239. package/src/shade/renderer/texture/virtual/VTPhysicalSlots.d.ts +119 -0
  240. package/src/shade/renderer/texture/virtual/VTPhysicalSlots.d.ts.map +1 -0
  241. package/src/shade/renderer/texture/virtual/VTPhysicalSlots.js +245 -0
  242. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.d.ts +1 -1
  243. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.d.ts.map +1 -1
  244. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.js +3 -19
  245. package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.d.ts +13 -0
  246. package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.d.ts.map +1 -0
  247. package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.js +34 -0
  248. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +7 -2
  249. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  250. package/src/shade/renderer/water/GPUWaterRenderer.js +49 -49
  251. package/src/shade/renderer/water/chunk_water_transport.js +3 -3
  252. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +11 -25
  253. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  254. package/src/shade/renderer/water/medium/GPUWaterBodies.js +64 -116
  255. package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts +1 -20
  256. package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts.map +1 -1
  257. package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.js +10 -42
  258. package/src/shade/renderer/water/medium/chunk_water_bodies.d.ts +3 -0
  259. package/src/shade/renderer/water/medium/chunk_water_bodies.d.ts.map +1 -0
  260. package/src/shade/renderer/water/medium/chunk_water_bodies.js +3 -0
  261. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts +1 -5
  262. package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts.map +1 -1
  263. package/src/shade/renderer/water/medium/shader_water_bodies_derive.js +32 -30
  264. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts +4 -0
  265. package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts.map +1 -0
  266. package/src/shade/renderer/water/medium/shader_water_meshlets.js +69 -0
  267. package/src/shade/renderer/water/optics/chunk_water_inscatter.d.ts.map +1 -1
  268. package/src/shade/renderer/water/optics/chunk_water_inscatter.js +124 -123
  269. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  270. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +75 -74
  271. package/src/shade/renderer/water/shader_water.d.ts +1 -1
  272. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  273. package/src/shade/renderer/water/shader_water.js +490 -406
  274. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts +12 -85
  275. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts.map +1 -1
  276. package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.js +128 -408
  277. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts +6 -0
  278. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts.map +1 -0
  279. package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.js +23 -0
  280. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts +9 -0
  281. package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts.map +1 -0
  282. package/src/shade/renderer/water/surface/chunk_water_tessellation.js +144 -0
  283. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts +3 -5
  284. package/src/shade/renderer/water/surface/chunk_water_wave.d.ts.map +1 -1
  285. package/src/shade/renderer/water/surface/chunk_water_wave.js +40 -48
  286. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +14 -0
  287. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -0
  288. package/src/shade/renderer/water/surface/graph_water_tessellation.js +34 -0
  289. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts +4 -0
  290. package/src/shade/renderer/water/surface/shader_water_tiles.d.ts.map +1 -0
  291. package/src/shade/renderer/water/surface/shader_water_tiles.js +123 -0
  292. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts +6 -0
  293. package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts.map +1 -0
  294. package/src/shade/renderer/water/surface/shader_water_wave_batch.js +85 -0
  295. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts +6 -0
  296. package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts.map +1 -0
  297. package/src/shade/renderer/water/surface/shader_water_wave_domain.js +83 -0
  298. package/src/shade/renderer/water/water_height_texture_from_sampler.d.ts.map +1 -1
  299. package/src/shade/renderer/water/water_height_texture_from_sampler.js +4 -3
  300. package/src/engine/graphics/ecs/water/WATER_SIZE.d.ts +0 -2
  301. package/src/engine/graphics/ecs/water/WATER_SIZE.d.ts.map +0 -1
  302. package/src/engine/graphics/ecs/water/WATER_SIZE.js +0 -1
  303. package/src/shade/renderer/light/GPUViewLightContext.d.ts +0 -22
  304. package/src/shade/renderer/light/GPUViewLightContext.d.ts.map +0 -1
  305. package/src/shade/renderer/light/GPUViewLightContext.js +0 -62
  306. package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts +0 -14
  307. package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts.map +0 -1
  308. package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.js +0 -20
  309. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts +0 -27
  310. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts.map +0 -1
  311. package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.js +0 -147
  312. package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.d.ts +0 -7
  313. package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.d.ts.map +0 -1
  314. package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.js +0 -10
  315. package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.d.ts +0 -2
  316. package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.d.ts.map +0 -1
  317. package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.js +0 -1
  318. package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.d.ts +0 -3
  319. package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.d.ts.map +0 -1
  320. package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.js +0 -8
  321. package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts +0 -27
  322. package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts.map +0 -1
  323. package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.js +0 -102
  324. package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.d.ts +0 -8
  325. package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.d.ts.map +0 -1
  326. package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.js +0 -34
  327. package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.d.ts +0 -10
  328. package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.d.ts.map +0 -1
  329. package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.js +0 -64
  330. package/src/shade/renderer/shadow/vsm/decode_tile_address.d.ts +0 -11
  331. package/src/shade/renderer/shadow/vsm/decode_tile_address.d.ts.map +0 -1
  332. package/src/shade/renderer/shadow/vsm/decode_tile_address.js +0 -26
  333. package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.d.ts +0 -2
  334. package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.d.ts.map +0 -1
  335. package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.js +0 -11
  336. package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.d.ts +0 -20
  337. package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.d.ts.map +0 -1
  338. package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.js +0 -184
  339. package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.d.ts +0 -25
  340. package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.d.ts.map +0 -1
  341. package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.js +0 -230
  342. package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.d.ts +0 -19
  343. package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.d.ts.map +0 -1
  344. package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.js +0 -127
  345. package/src/shade/renderer/texture/encode/ENCODE_NOTES_2026_09_02.md +0 -462
  346. package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts +0 -23
  347. package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts.map +0 -1
  348. package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts +0 -18
  349. package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts.map +0 -1
  350. package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts +0 -12
  351. package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts.map +0 -1
  352. package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.js +0 -27
  353. package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts +0 -14
  354. package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts.map +0 -1
  355. package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.js +0 -49
  356. package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts +0 -9
  357. package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts.map +0 -1
  358. package/src/shade/renderer/water/surface/chunk_water_wave_grid.js +0 -47
  359. package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts +0 -10
  360. package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts.map +0 -1
  361. package/src/shade/renderer/water/surface/shader_water_surface_write.js +0 -51
  362. package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts +0 -12
  363. package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts.map +0 -1
  364. package/src/shade/renderer/water/surface/shader_water_wave_step.js +0 -54
  365. package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts +0 -13
  366. package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts.map +0 -1
  367. package/src/shade/renderer/water/surface/water_surface_grid_indices.js +0 -39
@@ -0,0 +1,440 @@
1
+ # Virtual Shadow Map — build-out plan (2026-10-04)
2
+
3
+ Branch: `claude/virtual-shadow-map-build-64d4ad`. Nothing lands on master until Alex says so.
4
+
5
+ ## The brief
6
+
7
+ * Finish the partial VSM in this directory, and give it a playground with debug views and scenes.
8
+ * The number of page updates per frame is configurable.
9
+ * Moving casters mark the pages they overlap stale. The detection runs **on the GPU in a compute
10
+ shader**.
11
+ * Page requests come back to the CPU the way VT and VGeo feedback do. There they are prioritised,
12
+ allocated, and rendered under the budget.
13
+ * Reuse the engine's code; no parallel versions of it.
14
+ * An adversarial review at the end.
15
+
16
+ ## Forks, settled with Alex before implementing
17
+
18
+ * **F1 address space: clipmaps** (camera-centred, toroidal), not the prototype's single quadtree over
19
+ a fixed region.
20
+ * **F2 page rendering: a pooled view per page render**, reusing the raster/VG path as it is.
21
+ * **F3: superseded prototype code is deleted** (D14).
22
+
23
+ ## What exists today
24
+
25
+ * A mip quadtree over one orthographic light frustum: 16384² virtual, 256 tiles, a 4096²
26
+ `depth16unorm` pool.
27
+ * A demand pass counting pixels per tile from the main depth, and a coarse-bounds reduction.
28
+ * GPU allocation of pages **from zero every frame**. No caching, no invalidation, no page rendering
29
+ (`vms_render_tiles.js` is empty), no sampling.
30
+ * Nothing reaches it at runtime. `GPUViewLightContext` is never constructed, so `GPUViewShadowMaps`
31
+ and `VirtualShadowmapRenderer` are reached only by specs.
32
+
33
+ ## The clipmap
34
+
35
+ ### Light space
36
+
37
+ Light space is the view space of a rotation-only camera at the world origin, oriented as the light.
38
+ In `Camera.update_view_matrix` terms:
39
+
40
+ * `x = -dot(p, right)`
41
+ * `y = dot(p, up)`
42
+ * `d = dot(p, forward)`, the distance along the light
43
+
44
+ The page grids live on (x, y), anchored to the world, so a page's content does not depend on where
45
+ the camera is.
46
+
47
+ ### Levels
48
+
49
+ * There are `K` levels (default 12). Level `k` has texel `t_k = t_0 · 2^k`, with `t_0` defaulting
50
+ to 1 cm.
51
+ * Pages are 128 texels with a 4-texel border (`SHADOWMAP_ATLAS_BORDER`, which covers the PCF's
52
+ ±3.25-texel footprint), so a slot is 136 texels.
53
+ * Page `k` spans `p_k = 128 · t_k` world units. World page `(wx, wy)` at level `k` covers
54
+ `[wx·p_k, (wx+1)·p_k) × [wy·p_k, (wy+1)·p_k)`.
55
+ * Its parent at level `k+1` is `(wx >> 1, wy >> 1)` — floor division, exact for negatives on int32.
56
+
57
+ ### Windows
58
+
59
+ Each level keeps an `N×N` window of pages (default N = 64, which is 8192 texels a level).
60
+
61
+ * The window origin is `floor(camera_xy / p_k) - N/2`. The CPU computes it and writes it to the
62
+ record as integers, so the CPU and GPU agree exactly.
63
+ * Cells are toroidal: world page `(wx, wy)` sits in cell `(wx mod N, wy mod N)`.
64
+ * When a window scrolls, the CPU evicts only the cells it vacated. That costs O(scroll · N).
65
+ * With the defaults, level 0 is selected within about 19 m of the camera. Its window reaches ±41 m.
66
+ * The coarsest level's window is ±84 km.
67
+ * The origin puts the camera's page N/2 pages in from the window's low edge, so on its high side the
68
+ window reaches at least N/2 − 1 = 31 pages past the camera's page.
69
+ * The window covers the region where its level is selected whenever
70
+ `pixel_angle · (N/2 − 1) · 128 ≥ 2`, a pixel angle of at least 5.0e-4. That is a vertical field
71
+ of view of about 31° or more at 1080p, and 57° or more at 4K. (The first draft of this plan had
72
+ `N` for `N/2 − 1` and claimed 4x to spare; the review found it.)
73
+ * Where it does not hold — a narrow field, a zoom, 4K at 50°, a negative LOD bias — the outer ring
74
+ of each level on its high side is served by the next level up that contains the point. A
75
+ positive LOD bias widens the margin.
76
+
77
+ ### Depth range
78
+
79
+ There is one range for the whole clipmap: `[d_c - D, d_c + D]`, where `d_c` is the camera's `d`
80
+ snapped to `D/4`. D defaults to 1000 m.
81
+
82
+ ### Mip selection
83
+
84
+ `k0 = clamp(floor(log2(distance · pixel_angle / t_0) + bias), 0, K-1)`. The demand pass and every
85
+ sampler run **one shared chunk**: the first level at or above `k0` whose window holds the point.
86
+ So a pixel samples what it asked for, or a coarser resident page.
87
+
88
+ The selection is distance-based (the camera position and pixel angle travel in the record), so a
89
+ consumer with no neighbouring pixels — volumetrics, OIT, water — can still select a level.
90
+
91
+ ### Fallback
92
+
93
+ The sampler walks levels upward from the selected one until a resident page is found. The walk is
94
+ bounded by `K ≤ 16` and is usually one step.
95
+
96
+ VT's quadtree closure does not carry over to toroidal windows: a scroll would rewrite descendants
97
+ across levels. So the walk replaces it.
98
+
99
+ ## Where it lives: existing structures, no new bindings
100
+
101
+ ### Pool
102
+
103
+ The pool is a `bind()`-ed rect of the shadow atlas (`GPUSceneShadowmapContext.bind`,
104
+ `MaxRectanglesPacker`, depth32float). At 4080² it holds 900 slots shared by every level.
105
+
106
+ ### Light database
107
+
108
+ Every lighting consumer already binds the light database. It gains three tables:
109
+
110
+ * `shadow_virtual` — one record per map. It holds:
111
+ * the light view (mat4);
112
+ * the per-level window origins (`array<vec2i,16>`);
113
+ * near/far;
114
+ * `t_0`, K, N, page size, border, pool origin, slots per axis;
115
+ * the main camera position and pixel angle, and the LOD bias;
116
+ * the first rows and counts of its two runs (ranges, non-owning).
117
+ * `shadow_virtual_page` — `K·N²` u32 rows, level-major, toroidal cell order. Each is a VT entry,
118
+ `vt_entry_pack(phys_x, phys_y, level)`, or `VT_ENTRY_INVALID`.
119
+ * `shadow_virtual_slot` — one row per physical slot: the world page it holds (level, wx, wy, valid).
120
+ The stale test reads it.
121
+
122
+ `shadow_directional` gains a nullable `virtual_map` link. `CSM_SHADOWMAP_STRUCT` becomes
123
+ `DIRECTIONAL_SHADOWMAP_STRUCT`. `shadowmap_sample_directional` branches on the link, and the CSM path
124
+ is untouched.
125
+
126
+ ## Reused
127
+
128
+ | Need | From |
129
+ |---|---|
130
+ | Slots, LRU, protect window, finest-first tie-break | `VTPhysicalCache`'s bookkeeping, split out of its textures with no behaviour change; the VT specs keep pinning it |
131
+ | Page-table entry encode/decode | `vt_entry_pack`/`unpack`/`VT_ENTRY_INVALID`; the WGSL `vt_entry_unpack` lifted from `build_chunk_vt_lookup` into the static `chunk_vt_page_table_entry` that `VT_CONSTANTS` already names (a dangling link today) |
132
+ | Readback | `graph_read_buffer`, with the in-flight cap that skips the frame when full (VT 3, VGeo 2) |
133
+ | Choosing the frame's pages | `IndexedFloatMaxHeap` drained to the budget, as `ShadowmapDrawSelector` does |
134
+ | Rendering a page | `RasterizationJob` + `execute_rasterization_jobs`, the shadow pass descriptors, a viewport into the atlas, exactly `#draw_direct`; meshlets, alpha-tested and **VG cut-per-view** come with it |
135
+ | Sampling a page | `sample_shadowmap_atlas_for_light(page_view_projection, …, slot_rect)`: CSM's and spots' own bias and 5-tap PCF |
136
+ | Map lifecycle | `Shadowmap`, `ShadowmapRegistry`, `process_lights`' rebuild-on-settings-change (the tetrahedron and cascade-count precedent) |
137
+ | Mover inputs | `meshes.bounding_box`, `transforms.global`/`prev_global`, the `MESHES_TABLE` page iterator (the `shader_csm_caster_range` shape), the skinning bindings |
138
+ | Compute passes | `ComputeShader` + `ShaderResourceSetDescriptor`, immediates for small per-dispatch state |
139
+ | Debug | `RenderExtension` (`BeforePresent`/`Overlay`), `graph_image_pass`, the turbo depth map of `draw_texture_as_rgba` |
140
+
141
+ ## Decisions
142
+
143
+ **D5 Demand (GPU, per main-view pixel).**
144
+ - The pass reads depth and computes the world position, then the level, the world page and the
145
+ toroidal cell.
146
+ - It does an `atomicAdd` on the cell's counter. The add is subgroup-aggregated when all of a
147
+ subgroup's lanes hit one cell.
148
+ - The lane that sees the old value 0 appends `[level, wx, wy, count, d]`. `d` is that pixel's light
149
+ depth, used when a light changes. Dedupe and append happen in one step.
150
+ - A fixed-size gather writes the final counts into the list.
151
+ - No ancestors are requested by the GPU, per NOTES.md.
152
+
153
+ **D6 Movers (GPU, scene-level, once a frame).**
154
+ - The pass runs over every mesh-row slot, including slots in pages since freed. It uses the
155
+ page-iterator dispatch and covers a high-water mark of rows.
156
+ - It keeps a VSM-owned per-row buffer of the "bounds last seen".
157
+ - A row is a mover when **any** of these holds:
158
+ 1. `global != prev_global` — every rigid change, AABB-invariant rotations included;
159
+ 2. its world box, geometry or material differs from the one last seen — appear, remove, mesh or
160
+ material swap, deformation that changes bounds;
161
+ 3. it is skinned and a joint's skin matrix differs from last frame's, which the animation manager
162
+ keeps for motion vectors — a pose that changes inside the box. (The first build listed every
163
+ skinned mesh every frame, by category; the review found it.)
164
+ - The mover's `cur ∪ last` world box is appended to a list with capacity 4096.
165
+ - The test is observed, not declared (the `LastUpdateFrame` shape).
166
+
167
+ **D7 Stale (GPU, per map).**
168
+ - An indirect `(ceil(slots/64), movers, 1)` dispatch: one workgroup per mover, one lane per slot,
169
+ **no per-thread loop**.
170
+ - Each lane widens the slot's page rect by its border, and tests it against the mover box projected
171
+ through the light view.
172
+ - On a hit, `atomicExchange(&stale[slot], 1) == 0` appends the slot to the stale list.
173
+ - If the mover count exceeds capacity, every occupied slot is marked stale, and the overflow is
174
+ counted.
175
+
176
+ **D8 Readback.**
177
+ - One transient feedback buffer per map, cleared with the encoder (never queue-written: the
178
+ `framegraph-buffers-are-pooled` rule).
179
+ - It holds a header (counts and drops), the request list, and the stale list.
180
+ - Up to 3 readbacks are in flight. Each reading carries its frame.
181
+ - Readings older than the map's last invalidation are dropped.
182
+
183
+ **D9 CPU page manager** (`VSMPageManager`, pure CPU and specced on its own).
184
+ - **Each reading** replaces the want set, because each reading is a whole-frame snapshot.
185
+ - It touches the resident pages, and the serving fallback of every missing page.
186
+ - It sets the per-slot stale flags, unless the slot was rendered at or after the reading's frame.
187
+ - **Each frame**, candidates are drained from a max-heap to `page_budget`:
188
+ - **Uncovered** wanted pages are those with no resident page anywhere up their chain. Each is
189
+ covered by **one** page `COVER_STEP = 3` levels up, deduped per cell by frame stamp, before
190
+ anything finer. A cover page is drawn only because pixels are about to sample it, which keeps to
191
+ NOTES.md's "coarse tiles only when used".
192
+ - **Stale and wanted** pages come next, ordered by pixel count.
193
+ - **Missing but covered** pages come last, by pixel count, coarser first on ties.
194
+ - A missing page takes a free slot, or evicts the least recently touched page outside the protect
195
+ window. If nothing qualifies, it is refused and counted.
196
+ - Rows change only on delta: page-table rows on install, evict and scroll, slot rows on install and
197
+ evict. They are written before `draw()`'s existing `database.update`.
198
+
199
+ **D10 Light change.** A change of the light's rotation, or of the snapped depth centre, means:
200
+ - every page is evicted;
201
+ - readings recorded before the change are dropped;
202
+ - the last want set is **re-projected** into the new light space, through each want's page centre
203
+ and representative `d`, so wants exist the same frame;
204
+ - everything is now uncovered, so a few cover pages render first, the same frame.
205
+
206
+ Shadows go coarse and refine at the budget rate. They are never sampled through a projection they
207
+ were not rendered with.
208
+
209
+ **D11 Rendering.**
210
+ - One pooled `View` + `OrthographicCamera` per budget unit, from the shadow context's own
211
+ `ViewManager` (VG `tau_scale` 2, like the cascades).
212
+ - A page sets the light rotation and its border-widened ortho planes, and runs
213
+ `RasterizationPipelineType.Fast`: the point-light path, without an HZB. A pooled view's previous
214
+ HZB belongs to another page, and occlusion buys nothing on a 136² viewport.
215
+ - All of a frame's page jobs go into one graph, as `#draw_direct` does with cascades.
216
+ - Sampling widens the projection by the same border, so the page edges match what was rendered.
217
+
218
+ **D12 Selection and knobs.**
219
+ - `Renderer.feature_virtual_shadow_maps` (off by default) switches every directional light to VSM.
220
+ - A flip rebuilds the maps in `process_lights`, like `feature_tetrahedron_point_shadows`.
221
+ - `shadow_virtual_page_budget` (default 8) is the brief's page updates per frame.
222
+ - `shadow_virtual_lod_bias` (0).
223
+ - `shadow_virtual_first_texel_size` (0.01 m). Changing it rebuilds the maps.
224
+
225
+ **D14 Deleted**, along with its specs:
226
+ - `vsm_tile_allocation_pipeline`;
227
+ - `vms_pipeline_compute_coarse_bounds` and `debug_inspect_coarse_bounds_buffer`;
228
+ - `VirtualShadowmapRenderer`, `GPUViewShadowMaps`, `GPUViewLightContext`;
229
+ - `GPUVirtualShadowTextureResidence`;
230
+ - `render/vms_render_tiles.js`;
231
+ - `VSM_UNIFORMS_STRUCT`;
232
+ - `decode_tile_address` and `debug_inspect_residence_buffer` (quadtree-only).
233
+
234
+ The demand pass is the prototype's residence pass reworked, and `VirtualShadowMap` evolves in place.
235
+
236
+ ## Frame timeline
237
+
238
+ ```
239
+ frame N head: readings delivered since N-1 → want set, touches, stale flags
240
+ select_for_draw: map.update — light view, windows (scroll → evict), invalidation, record
241
+ → candidates → heap → page_budget jobs; allocate/evict → row deltas
242
+ draw: page jobs (Fast, pooled views) into slots; records; database.update
243
+ Shading graph, after the G-buffer:
244
+ movers (scene, once) → per map: demand, gather, stale args, stale test → readback
245
+ lighting: shadowmap_sample_directional → virtual_map? → level walk → VT entry →
246
+ sample_shadowmap_atlas_for_light(page VP, slot rect)
247
+ frame N+2..3 reading N lands, applied at the next head
248
+ ```
249
+
250
+ A mover's shadow lags by the readback latency (2–3 frames) plus its place in the queue. That lag
251
+ comes with CPU scheduling, which the brief asks for. On the mover itself it reads as acne; see Known
252
+ limits.
253
+
254
+ ## Playground: `src/shade/playground/vsm/`
255
+
256
+ **Scenes.**
257
+ * **Courtyard:** ground, pillars, walls, an overhang, thin poles at distance, a long avenue reaching
258
+ out through the clipmap levels, and movers (orbiting boxes, a pendulum, a bobbing sphere).
259
+ * **Crowd:** N wandering boxes, adjustable past the 4096 mover capacity.
260
+ * A **sun sweep** toggle in either scene.
261
+
262
+ **Controls.**
263
+ * VSM/CSM A/B.
264
+ * Page budget, LOD bias, first texel size.
265
+ * Movers and sun sweep on/off.
266
+ * Camera fly-through presets.
267
+ * Freeze residency (stop applying readings).
268
+
269
+ **Debug views.**
270
+ 1. A screen overlay, through an extension, showing one of: the serving level as a ramp; the deficit
271
+ (desired − serving), red; page id hash, to show page edges; the plain shadow factor.
272
+ 2. The physical pool, in the Overlay phase: turbo depth with the slot grid tinted by state (free,
273
+ resident, stale, rendered this frame).
274
+ 3. The clipmap, from CPU state on a 2D canvas: one panel per level for the N×N window, with
275
+ resident, wanted, stale and uncovered cells, and the camera.
276
+ 4. Stats:
277
+ - wants, uncovered and stale per reading;
278
+ - renders this frame, and the backlog;
279
+ - movers and overflow;
280
+ - pool use, evictions, refusals;
281
+ - scroll evictions;
282
+ - invalidations;
283
+ - readbacks in flight and dropped.
284
+
285
+ **Console.**
286
+ - `vsm_lab` exposes `renderer`, `scene`, `map()`, `stats()` and `step(n)`.
287
+ - `verify()` holds the animation still across its readbacks. It checks that the page-table rows equal
288
+ the CPU's residency, that the slot rows agree, that no world page has two slots, and that a still
289
+ scene converges to "nothing uncovered, nothing missing" within the expected number of frames.
290
+
291
+ ## Work, as commits (each green)
292
+
293
+ 1. VT extraction: the `VTPhysicalCache` slot base and `chunk_vt_page_table_entry`.
294
+ 2. Light database: the `DIRECTIONAL_SHADOWMAP_STRUCT` rename + `virtual_map`, and the three VSM
295
+ tables with links and ranges. CSM writes NULL.
296
+ 3. Shared chunks: light-space, level selection, world page and toroidal cell, the page VP mirroring
297
+ `ortho_reverse_z`, and the lookup with its level walk.
298
+ 4. `VSMPageManager`: readings, want set, cover, priority, heap, allocation and eviction, windows and
299
+ scroll, invalidation and re-projection, row deltas, debug accessors.
300
+ 5. Shadow-context integration: the `process_lights` branch, settings pushes, page jobs in `draw`,
301
+ records, evict and teardown.
302
+ 6. GPU feedback: demand, gather, movers, stale test, readback, and the Renderer hook beside VT's.
303
+ 7. Sampling: the `shadowmap_sample_directional` branch.
304
+ 8. Deleting the superseded files (D14).
305
+ 9. The playground, its scenes and debug views.
306
+ 10. Adversarial review, and its ledger worked red-then-green.
307
+
308
+ ## Tests, by tier (no mocks, hooks or `.each`; helpers inside the specs)
309
+
310
+ * **Tier 1:** every new WGSL module validated.
311
+ * **Tier 2 (emulator):**
312
+ - level selection against a distance oracle, with the window fallback;
313
+ - world page and cell for negative coordinates;
314
+ - **the page VP built in WGSL equals the CPU page camera's VP** (render/sample agreement);
315
+ - the lookup's level walk;
316
+ - the demand kernel on synthetic depth, giving the list plus counts;
317
+ - movers on real `gpu_database_words`: a still row, a moved row, appear, remove, mesh swap,
318
+ and a row in a freed page;
319
+ - the stale test: hit, miss, dedupe, overflow.
320
+ * **Tier 3 (SoftwareGPUDevice):**
321
+ - `process_lights` builds, rebuilds and evicts VSM maps, handing back the pool rect and rows;
322
+ - `draw` encodes at most `budget` page passes, with viewports exactly on slots;
323
+ - the host-written page and slot rows;
324
+ - readback scheduling and its cap;
325
+ - a teardown leak spec.
326
+ * **CPU:**
327
+ - priority, budget, and covers ahead of everything else;
328
+ - LRU and the protect window;
329
+ - the stale guard by frame;
330
+ - scroll eviction;
331
+ - invalidation and re-projection;
332
+ - a random fuzz holding "page rows == residency".
333
+ * **Tier 4:** a one-off headless-Chrome drive of the playground, reported and not committed:
334
+ pictures, `verify()`, stats, and paired frame times at budgets 1/8/32, a few hundred frames.
335
+
336
+ ## Known limits (stated, not fixed here)
337
+
338
+ * A page drawn under a clamped VG cut stays coarse until it is invalidated. The pooled view does not
339
+ keep per-page attribution for `caster_detail_pending`. This is a fact about the code; its cost has
340
+ not been measured.
341
+ * Demand and level selection follow the main view.
342
+ * Continuous light rotation invalidates every frame. Caching then buys nothing, and the budget bounds
343
+ what is drawn (UE's VSM has the same property).
344
+ * Casters further than D along the light from the camera's snapped depth are clipped. A receiver
345
+ past the far end is shadowed only by casters drawn inside the range: the atlas sampler holds its
346
+ reference depth just above the cleared value, where it would otherwise read shadowed everywhere.
347
+ * A change to a material's parameters — the same material, a new dissolve cutoff — is not a mover.
348
+ * ~~A shadow starts 1–1.5 texels of its page short of where a caster meets the ground.~~ Closed
349
+ 2026-10-04: every shadow caster is now drawn by its front faces, as the main view draws it. Back-face
350
+ casting stacked on the shared rasterizer slope bias (`DEPTH_STENCIL_STATE_SHADOW`) had pushed a
351
+ caster's steep far face past the ground near its base, in every shadow type. Point lights needed
352
+ their sampler's depth bias made texel-scaled to stay clean on front faces.
353
+ * **A mover self-shadows against its own stale image.** A stale slot reaches the CPU by readback, so a
354
+ page holding a mover is 0–5 frames old when it is sampled, about 1.6 on average (courtyard, budget
355
+ 64). Front-face casting puts that image on the mover's own lit faces, which read as hatched.
356
+ - Measured on an RTX 4090 in headless Chrome, the same pose through stale pages against freshly
357
+ drawn ones: pages 1, 2 and 3 frames stale, at the orbiters' motion at 140 fps, darken 27%, 47% and
358
+ 52% of an orbiter's pixels by more than 10%. Cascades, which redraw every frame: 0%. Back faces
359
+ cast in the same arms: 0–0.7%.
360
+ - Fresh pages are clean, so the bias is sufficient. Bias cannot absorb staleness: a motion Δ over
361
+ the latency needs |Δ·n| / cos θ of clearance, up to about 18 cm (9–18 texels at levels 0–1) for
362
+ three frames at 3.6 m/s.
363
+ - Removing it means drawing a mover's pages in the frame it moves, as UE 5.4 does: it invalidates
364
+ the old footprint during the scene update and draws a moved instance into every allocated page.
365
+ At the playground's close framing about 24 wanted pages hold a mover each frame, against 7 pages
366
+ drawn per frame now.
367
+ * Below the window coverage condition (see Windows), each level's outer ring is served a level
368
+ coarser.
369
+
370
+ ## Status (2026-10-04, branch only)
371
+
372
+ Landed as planned, with these departures, each made when the code or a measurement asked for it:
373
+
374
+ * **Window corners are a table** (`shadow_virtual_level`), not an array in the record: a by-value
375
+ record array indexed by level spills to local memory (the CSM 217→80 µs lesson).
376
+ * **Stale flags persist** on the GPU until a readback lists them, so a frame whose readback the cap
377
+ skipped loses no movers.
378
+ * **Priority is aged.** Covers first; stale and missing pages compete by
379
+ `log2((1 + importance)(1 + frames waited))`, the weighting `compute_shadowmap_update_score` uses.
380
+ Strict "stale before missing" starved missing pages for as long as anything moved: the 5000-walker
381
+ crowd left 217 waiting.
382
+ * **Pixels are weighed by where they are on screen.** The demand pass adds each pixel's weight under
383
+ the automatic exposure's metering mask (`chunk_screen_importance`, moved out of the exposure's
384
+ histogram shader so both share it): 64 at full importance over most of the screen, falling over
385
+ 13% of its height in from each edge, never below 1. So a page wanted in the middle of the view
386
+ outranks one wanted by as many pixels at its edge, and the middle resolves first.
387
+ * **An uncovered page is offered itself** beside its cover, so a budget with room fills both the same
388
+ frame.
389
+ * **Agreement in the demand pass** is `subgroupMin == subgroupMax`. The emulator has no
390
+ `subgroupAll`, and this form is exact on a device.
391
+ * **The cell index uses `u32()` per component**: the emulator returns NaN components for a vector
392
+ `bitcast` between i32 and u32.
393
+ * **Engine fixes found on the way:**
394
+ - the GPU database's WGSL serde gains i32/vec2-4i;
395
+ - `read_wgsl_type_value` read signed vectors into a `Uint32Array` (negatives came back as their bit
396
+ patterns).
397
+
398
+ **Measured** on an RTX 4090, headless Chrome, 1600×900, courtyard, paired arms in one launch:
399
+ - GPU per frame is 734–758 µs at budget 0, 779–795 at budget 1, 1072–1076 at budget 8 (7.1–7.5 pages),
400
+ and 1273–1305 µs for 3 cascades.
401
+ - A page costs about 40–45 µs GPU and about 85 µs CPU.
402
+ - The feedback passes cost about 59 µs, the demand pass 46 of it.
403
+ - `verify()` passes: GPU page table, slots and windows equal the CPU's after settling.
404
+
405
+ So the pooled-view cost (F2) is measured: at budget 8 it is CSM's CPU cost and less than CSM's GPU
406
+ cost in this scene.
407
+
408
+ The sun sweep at 0.05 rad/s falls back to cover pages every frame, which is the light-change limit
409
+ above, observed.
410
+
411
+ ## Adversarial review (2026-10-04)
412
+
413
+ Four reviewers, one dimension each: GPU shaders and dispatch, the page manager and integration,
414
+ regressions and house rules, and the playground. The findings are in `REVIEW_LEDGER.md`, worked in
415
+ order of severity, each pinned by a test that failed first wherever a test can see it, and each in a
416
+ commit of its own. Among them:
417
+
418
+ * **A receiver past the far end of the depth range read black.** Fixed in the shared atlas sampler.
419
+ * **The bias was sized off the page's matrix**, which takes in the depth range as the sun climbs: 29 m
420
+ a texel straight overhead. The virtual sampler hands the atlas sampler the page's texel.
421
+ * **A light turning every frame lost every reading**, older than the cutoff each time. Readings are
422
+ now carried from the light space they were recorded under, 16 remembered.
423
+ * **A camera on a snap plane moved the depth range every frame.** The range re-centres only once the
424
+ camera is a whole snap from its centre.
425
+ * **Skinned meshes were movers by category**, and **mesh or material swaps were missed.**
426
+ * The rest are smaller: the budget remainder, the pool search after a refusal, the dispatch fold,
427
+ the readback stamps of a new view, the playground's `verify()`, inset, crowd and controls.
428
+
429
+ **Measured on the device after the fixes** (RTX 4090, headless Chrome):
430
+ * The demand pass's subgroup counting is exact. Every pixel on the ground gave requests whose pixel
431
+ counts summed to the 1,265,556 pixels of the view, with no page asked for twice.
432
+ * The movers' wave-aggregated append listed 400 of 400 moving walkers.
433
+ * `verify()` passes on both scenes, with the new record and page-to-slot-to-page checks.
434
+ * **The virtual path costs the cascades about 2.4 µs.** Every directional shader carries the virtual
435
+ branch, uniform but compiled in. With cascades, deferred shading took 48.1–49.2 µs with it and
436
+ 46.1–47.1 µs with the branch stripped, over three launches a side alternated at 1578×802, and
437
+ volumetric lighting about 1 µs more. Open: taking it out would mean a lighting shader per
438
+ technique.
439
+ * The cascades share the matrix-read bias scale the virtual pages had, but measure 1.0–1.4x their
440
+ true texel from 45° to 89° of elevation: their depth ranges are fitted, so it stays small.
@@ -0,0 +1,43 @@
1
+ # Virtual shadow map — adversarial review ledger (2026-10-04)
2
+
3
+ There were four reviewers, each covering one dimension:
4
+
5
+ - **G**: shaders and dispatch.
6
+ - **CPU**: page manager and integration.
7
+ - **R**: regressions, house rules and test quality.
8
+ - **P**: playground and debug views.
9
+
10
+ Each row is worked red-then-green where a test can see it. "Device" means checked once on the RTX 4090 outside the repo, and reported in the commit.
11
+
12
+ | # | Severity | Finding | Status | Pinned by |
13
+ |---|---|---|---|---|
14
+ | 1 | major | Turning VSM off left `shadow_directional.virtual_map` naming the freed row; the sun went unshadowed (R1) | fixed `0189945bd` | VirtualShadowMap.spec, the flip test |
15
+ | 2 | major | Light rotating every frame: every reading is older than the cutoff and dropped, and the wants freeze and drift (CPU1) | fixed: readings carried through the view they were recorded under (16 light spaces remembered) | VSMPageManager.spec, the two "carried" tests |
16
+ | 3 | major | Per-view `frame_index` restarts with a new camera; the map drops readings until it catches up (CPU2) | fixed: each map keeps its own count | graph_vsm_feedback.spec, the second-camera test |
17
+ | 4 | major | Skinned rows are movers by category, every frame, idle or not (R6) | fixed: a skinned mesh is a mover when a joint's skin matrix differs from last frame's; the binding carries its joint count | shader_vsm_movers.spec, the skinned test; GPUMeshSkinningContext.spec, the matrices test |
18
+ | 5 | major | `verify()` "settles" passes vacuously when every page is refused, and needs no reading taken after the freeze (P1) | fixed: needs a reading recorded after the stop that wants pages; refused pages count as waiting (row 11) | device: both scenes pass |
19
+ | 6 | major | The inset's red edge shows GPU flags the compact pass has already cleared, not the CPU's stale state (P2) | fixed: the overlay uploads the page manager's stale state; a stale slot is washed red | device: screenshot of the crowd |
20
+ | 7 | major | Each crowd resize leaks a whole scene's GPU state (P3) | fixed: the crowd resizes in place | device: 200 to 400, same scene |
21
+ | 8 | minor | Depth snap has no hysteresis: a camera on a snap plane invalidates almost every frame (CPU3) | fixed: the range re-centres only once the camera is a snap from its centre | VirtualShadowMap.spec, the snap-plane test |
22
+ | 9 | minor | A pool that does not fit allocates about 2.3 MB of manager arrays per retry, every frame (CPU4) | fixed: the pool is bound before the map is built | none: the allocation is not visible through the API |
23
+ | 10 | minor | The budget remainder always goes to the first suns: with budget < suns, later suns starve (CPU5) | fixed: the remainder goes round the maps a frame at a time | VirtualShadowMap.spec, the two-suns test |
24
+ | 11 | minor | After one refusal, `select` keeps draining the heap, scanning 900 slots per candidate (CPU6) | fixed: no slot search after the first refusal of a frame; the backlog counts the refused | VSMPageManager.spec, the full-pool test |
25
+ | 12 | minor | The mover tracker outlives the feature (R2) | fixed: destroyed on the first frame with no virtual map | none: the tracker is private |
26
+ | 13 | minor | Every directional-shadow shader carries the virtual path; cost not measured (R3) | measured, open: with cascades, deferred shading costs 48.1–49.2 µs with the path and 46.1–47.1 µs without (+2.4 µs, 5%), volumetric lighting +1 µs; RTX 4090, 1578×802, three launches a side alternated | device A/B, not committed |
27
+ | 14 | minor | `afterEach` hooks in new specs (R4); vacuous assertions (R5) | fixed: hooks gone; the cover test derives its level from the constant | |
28
+ | 15 | minor | The mover dispatch has no fold: 65,535 × 128 rows is a hard cap (R7) | fixed: folded into rows of 65,535 workgroups | shader_vsm_movers.spec, the folded test |
29
+ | 16 | minor | Subgroup aggregation in demand and append is never exercised; the emulator is one lane wide (R/T2) | checked on the device: the requests' pixel counts summed to all 1,265,556 pixels with no page twice; 400 of 400 moving walkers listed | device, not committed |
30
+ | 17 | minor | The rows spec reads the CPU copy, not what reaches the device (R/T3) | fixed: entries, slots and windows read from the database's flushed words | VirtualShadowMap.spec, the rows test |
31
+ | 18 | minor | No test of the budget split or of two suns (R/T4) | fixed with row 10 | VirtualShadowMap.spec, the two-suns test |
32
+ | 19 | minor | `verify()` readback runs while frames continue; record row not read back; no GPU cell↔slot check; TypeError on missing rows (P4, P5) | fixed: page updates held across the readback; record, rows present, and page to slot to page checked | device: both scenes pass |
33
+ | 20 | minor | The overlay's doc claims more than it checks (P6); it draws last frame's map on a scene switch (P7) | fixed: doc says what it runs; the map is assigned before the render | |
34
+ | 21 | minor | `configure({scene})` does not switch scenes; a reload restores the dropdown but not the scene (P8); status line stuck (P9) | fixed | device: configure switches both ways, status returns |
35
+ | 22 | minor | README overstates "pause"; per-frame allocations in the playground; bfcache `pagehide` (P10–P12) | fixed: wording; no per-frame state objects, aim_sun keeps scratch; reload on a persisted pageshow, as caldera does | |
36
+ | 23 | minor | CHANGELOG entry missing; PLAN.md untracked (R10) | fixed | |
37
+ | 24 | major | A receiver past the far end of the depth range reads shadowed against a slot nothing was drawn into: ground over ~1 km down-sun under a 30° sun, all of it from 1.1 km up under a high one (G1) | fixed: the atlas sampler holds the reference depth just above the cleared value | chunk_shadowmap_sample_virtual.spec, the "beyond the far end" test |
38
+ | 25 | major | The bias is sized by a texel read off the page's matrix, which takes in the depth range as the sun climbs: 1.4x the true texel at 45°, 5.8x at 80°, 29 m straight overhead (G2) | fixed: the virtual sampler hands the atlas sampler its page's texel | chunk_shadowmap_sample_virtual.spec, the "overhead sun" test |
39
+ | 26 | minor | A mesh or material swapped in place, box and transform unchanged, is not a mover (G3) | fixed: the pass remembers each row's geometry and material with its box (8 words a row) | shader_vsm_movers.spec, the "in place" test |
40
+ | 27 | minor | PLAN's window coverage condition is off by two: a level's window reaches 31 pages on its +x/+y side, so a view needs a pixel angle of at least 5.0e-4 (about 31° vertical field at 1080p, 57° at 4K), not 2.4e-4; below it the outer ring of each level is served one level coarser (G4) | PLAN corrected, and the coarser ring listed as a known limit; argued, not measured | |
41
+ | — | note | verify script ships (R8): precedent `skinned_blas_refit/verify_*.js`; the owner's call | no change | |
42
+ | — | note | Per-frame graph and job objects (R9): the `#draw_direct` pattern, scaling with the page budget only | no change | |
43
+ | — | note | The cascades share the matrix-read bias scale of row 25: measured at 1.0–1.4x their true texel from 45° to 89°, their depth ranges being fitted | no change | device, not committed |
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The scene's memory of where its casters were and what they were: {@link VSM_LAST_SEEN_WORDS} per
3
+ * row of the `meshes` table — the world box {@link shader_vsm_movers} saw each row with last frame,
4
+ * and its geometry and material — empty for a row that held nothing. Comparing against it is how the
5
+ * mover pass sees a row appear, leave, change shape or change mesh, which no per-row fact of the
6
+ * scene database says.
7
+ *
8
+ * Covers every row the table has ever had — a high-water mark, so a page of rows that was freed
9
+ * still gets compared once more and its casters' old shadows found. Grows by doubling; a grown
10
+ * buffer starts empty and takes the old one's rows by a copy recorded in the next mover pass, in
11
+ * order with the rest of the frame.
12
+ */
13
+ export class VSMMoverTracker {
14
+ /**
15
+ * @param {GPUDevice} device
16
+ */
17
+ constructor(device: GPUDevice);
18
+ /**
19
+ * @returns {GPUBuffer|null}
20
+ */
21
+ get buffer(): any;
22
+ /**
23
+ * @returns {number} rows the buffer covers
24
+ */
25
+ get row_count(): number;
26
+ /**
27
+ * Cover at least `rows` rows.
28
+ *
29
+ * @param {number} rows
30
+ */
31
+ ensure(rows: number): void;
32
+ /**
33
+ * Record the copy of the rows the buffer had before it grew, if it did since the last call, and
34
+ * let the old buffer go once the frame is done with it.
35
+ *
36
+ * @param {ShadeGPUCommandContext} encoder
37
+ */
38
+ encode_growth(encoder: ShadeGPUCommandContext): void;
39
+ destroy(): void;
40
+ #private;
41
+ }
42
+ //# sourceMappingURL=VSMMoverTracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VSMMoverTracker.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/vsm/VSMMoverTracker.js"],"names":[],"mappings":"AASA;;;;;;;;;;;GAWG;AACH;IAwBI;;OAEG;IACH,+BAIC;IAED;;OAEG;IACH,kBAEC;IAED;;OAEG;IACH,wBAEC;IAED;;;;OAIG;IACH,aAFW,MAAM,QA+ChB;IAED;;;;;OAKG;IACH,qDAWC;IAED,gBAYC;;CACJ"}