@woosh/meep-engine 3.26.0 → 3.27.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 (236) hide show
  1. package/package.json +1 -1
  2. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
  3. package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
  4. package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
  5. package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
  6. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
  7. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
  8. package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
  9. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
  10. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
  11. package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
  12. package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
  13. package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
  14. package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
  15. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +14 -7
  16. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  17. package/src/core/geom/3d/shape/HeightMapShape3D.js +87 -78
  18. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  19. package/src/shade/playground/vgeo_runtime/README.md +167 -22
  20. package/src/shade/playground/vgeo_runtime/index.html +112 -62
  21. package/src/shade/playground/vgeo_runtime/main.js +660 -83
  22. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
  23. package/src/shade/playground/vgeo_viewer/sample_asset.js +19 -2
  24. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
  25. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  26. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
  27. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  28. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
  29. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +73 -5
  30. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +26 -15
  31. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +5 -3
  32. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +18 -0
  33. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  34. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +20 -0
  35. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  36. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +56 -9
  37. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  38. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -0
  39. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
  40. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  41. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
  42. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
  43. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  44. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
  45. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
  46. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  47. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
  48. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
  49. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  50. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
  51. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
  52. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
  53. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
  54. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
  55. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
  56. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
  57. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
  58. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
  59. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
  60. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
  61. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
  62. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
  63. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
  64. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
  65. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
  66. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  67. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
  68. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
  69. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  70. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
  71. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
  72. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  73. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
  74. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
  75. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  76. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
  77. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
  78. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
  79. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
  80. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
  81. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  82. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
  83. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
  84. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
  85. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
  86. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
  87. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  88. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
  89. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
  90. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
  91. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
  92. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
  93. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
  94. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
  95. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  96. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +55 -0
  97. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  98. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +202 -13
  99. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  100. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +147 -10
  101. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +637 -0
  102. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
  103. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
  104. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
  105. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +58 -28
  106. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  107. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +77 -105
  108. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
  109. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +105 -22
  110. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
  111. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
  112. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  113. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +47 -489
  114. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
  115. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
  116. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
  117. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
  118. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
  119. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1363 -0
  120. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
  121. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
  122. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
  123. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
  124. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  125. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
  126. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
  127. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
  128. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
  129. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
  130. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
  131. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
  132. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
  133. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
  134. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
  135. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
  136. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
  137. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  138. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +15 -0
  139. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
  140. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
  141. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
  142. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
  143. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
  144. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
  145. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
  146. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
  147. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
  148. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +186 -0
  149. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
  150. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +20 -8
  151. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  152. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +580 -188
  153. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
  154. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
  156. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  157. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
  158. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  159. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
  160. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  161. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
  162. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
  163. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
  164. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
  165. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
  166. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
  167. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
  168. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
  169. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
  171. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
  172. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
  173. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
  183. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
  184. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
  185. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
  191. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
  192. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
  193. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
  194. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  195. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
  196. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  197. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
  198. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  199. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  200. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
  201. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  202. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
  203. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  204. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  205. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
  206. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
  207. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  208. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  209. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  210. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
  211. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  212. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
  213. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  214. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
  215. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  216. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
  217. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  218. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
  219. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  220. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +7 -1
  221. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  222. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +7 -1
  223. package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
  224. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  225. package/src/shade/renderer/scene/GPUSceneContext.js +59 -4
  226. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  227. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
  228. package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
  229. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  230. package/src/shade/renderer/view/GPUViewContext.js +21 -0
  231. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  232. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
  233. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
  234. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
  235. package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
  236. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
@@ -17,6 +17,8 @@ import { VGEO_NODE_RECORD_SIZE } from "../page/VGEO_NODE_RECORD_SIZE.js";
17
17
  import { VGEO_PAGE_HEADER_SIZE } from "../page/VGEO_PAGE_HEADER_SIZE.js";
18
18
  import { VGEO_PAGE_MAGIC } from "../frame/VGEO_PAGE_MAGIC.js";
19
19
  import { VGEO_PAGE_OFFSET } from "../page/VGEO_PAGE_OFFSET.js";
20
+ import { VGEO_PARENT_ENTRY_SIZE } from "../page/VGEO_PARENT_ENTRY_SIZE.js";
21
+ import { VGEO_PARENT_PAGE_ENTRY_SIZE } from "../page/VGEO_PARENT_PAGE_ENTRY_SIZE.js";
20
22
  import { vgeo_read_frame_extent } from "../frame/vgeo_read_frame_extent.js";
21
23
  import { VGeoPage } from "./VGeoPage.js";
22
24
 
@@ -127,6 +129,7 @@ export function vgeo_read_page(frame_bytes, page_index) {
127
129
  read_group_table(result);
128
130
  read_node_table(result);
129
131
  read_cluster_table(result);
132
+ read_parent_tables(result);
130
133
 
131
134
  return result;
132
135
  }
@@ -290,6 +293,7 @@ function read_group_table(page) {
290
293
  page.group_cluster_first = new Uint16Array(count);
291
294
  page.group_cluster_count = new Uint16Array(count);
292
295
  page.group_parent_count = new Uint16Array(count);
296
+ page.group_parent_first = new Uint32Array(count);
293
297
 
294
298
  for (let i = 0; i < count; i++) {
295
299
  const record = VGEO_PAGE_HEADER_SIZE + i * VGEO_GROUP_RECORD_SIZE;
@@ -297,6 +301,57 @@ function read_group_table(page) {
297
301
  page.group_cluster_first[i] = data.getUint16(record, LE);
298
302
  page.group_cluster_count[i] = data.getUint16(record + 2, LE);
299
303
  page.group_parent_count[i] = data.getUint16(record + 4, LE);
304
+ page.group_parent_first[i] = data.getUint16(record + 6, LE);
305
+ }
306
+ }
307
+
308
+ /**
309
+ * The parent-page table and the group-parent table, in that order, from `parent_table_offset`.
310
+ *
311
+ * **A zero offset is a container without an upward edge**, not a malformed one: those bytes were
312
+ * reserved before `format_version` 4 and written as zero, so every container built earlier says
313
+ * so about itself, and this leaves the arrays empty rather than reading the payload as a table.
314
+ * Nothing downstream has to ask what version it is holding.
315
+ *
316
+ * @param {VGeoPage} page
317
+ * @throws {Error} when the tables run past the decoded page
318
+ */
319
+ function read_parent_tables(page) {
320
+ const data = page.data;
321
+
322
+ const table = data.getUint32(VGEO_PAGE_OFFSET.PARENT_TABLE_OFFSET, LE);
323
+
324
+ if (table === 0) {
325
+ return;
326
+ }
327
+
328
+ const page_count = data.getUint16(VGEO_PAGE_OFFSET.PARENT_PAGE_COUNT, LE);
329
+ const entry_count = data.getUint16(VGEO_PAGE_OFFSET.PARENT_ENTRY_COUNT, LE);
330
+
331
+ const entries = table + page_count * VGEO_PARENT_PAGE_ENTRY_SIZE;
332
+ const end = entries + entry_count * VGEO_PARENT_ENTRY_SIZE;
333
+
334
+ if (end > page.bytes.byteLength) {
335
+ throw new Error(
336
+ `virtual geometry: page ${page.index} parent tables end at ${end}, past the`
337
+ + ` ${page.bytes.byteLength} bytes it decoded to`
338
+ );
339
+ }
340
+
341
+ page.parent_page_index = new Uint32Array(page_count);
342
+
343
+ for (let i = 0; i < page_count; i++) {
344
+ page.parent_page_index[i] = data.getUint32(table + i * VGEO_PARENT_PAGE_ENTRY_SIZE, LE);
345
+ }
346
+
347
+ page.parent_ref = new Uint16Array(entry_count);
348
+ page.parent_cluster = new Uint16Array(entry_count);
349
+
350
+ for (let i = 0; i < entry_count; i++) {
351
+ const record = entries + i * VGEO_PARENT_ENTRY_SIZE;
352
+
353
+ page.parent_ref[i] = data.getUint16(record, LE);
354
+ page.parent_cluster[i] = data.getUint16(record + 2, LE);
300
355
  }
301
356
  }
302
357
 
@@ -1 +1 @@
1
- {"version":3,"file":"vgeo_validate_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js"],"names":[],"mappings":"AAshDA;;;;;GAKG;AACH,gDAHW,YAAY,GACV,UAAU,EAAE,CAkFxB;6BA5mD4B,4CAA4C;2BA+C9C,iBAAiB"}
1
+ {"version":3,"file":"vgeo_validate_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js"],"names":[],"mappings":"AAgtDA;;;;;GAKG;AACH,gDAHW,YAAY,GACV,UAAU,EAAE,CAqFxB;6BAzyD4B,4CAA4C;2BAkD9C,iBAAiB"}
@@ -30,7 +30,10 @@ import { VGEO_MAX_CHILD_REF } from "./cluster/VGEO_MAX_CHILD_REF.js";
30
30
  import { VGEO_MAX_CLUSTER_TRIANGLE_COUNT } from "./cluster/VGEO_MAX_CLUSTER_TRIANGLE_COUNT.js";
31
31
  import { VGEO_MAX_CLUSTER_VERTEX_COUNT } from "./cluster/VGEO_MAX_CLUSTER_VERTEX_COUNT.js";
32
32
  import { VGEO_MAX_GROUP_CLUSTER_COUNT } from "./page/VGEO_MAX_GROUP_CLUSTER_COUNT.js";
33
+ import { VGEO_MAX_PARENT_REF } from "./page/VGEO_MAX_PARENT_REF.js";
33
34
  import { VGEO_MIN_READER_VERSION } from "./header/VGEO_MIN_READER_VERSION.js";
35
+ import { VGEO_PARENT_ENTRY_SIZE } from "./page/VGEO_PARENT_ENTRY_SIZE.js";
36
+ import { VGEO_PARENT_PAGE_ENTRY_SIZE } from "./page/VGEO_PARENT_PAGE_ENTRY_SIZE.js";
34
37
  import { VGEO_NO_CHILD } from "./cluster/VGEO_NO_CHILD.js";
35
38
  import { VGEO_NO_GROUP } from "./cluster/VGEO_NO_GROUP.js";
36
39
  import { VGEO_NODE_FANOUT } from "./page/VGEO_NODE_FANOUT.js";
@@ -114,12 +117,42 @@ class DecodedPage {
114
117
  payload_offset = 0;
115
118
  payload_size = 0;
116
119
 
120
+ /**
121
+ * Start of the parent section — the parent-page table, then the group-parent table. Zero on a
122
+ * page written before `format_version` 4, which carries neither.
123
+ * @type {number}
124
+ */
125
+ parent_table_offset = 0;
126
+
127
+ /**
128
+ * @type {number}
129
+ */
130
+ parent_entry_count = 0;
131
+
132
+ /**
133
+ * @type {number}
134
+ */
135
+ parent_page_count = 0;
136
+
117
137
  /**
118
138
  * `[page_index, ...]` in child-table order.
119
139
  * @type {number[]}
120
140
  */
121
141
  child_pages = [];
122
142
 
143
+ /**
144
+ * `[page_index, ...]` in parent-page-table order.
145
+ * @type {number[]}
146
+ */
147
+ parent_pages = [];
148
+
149
+ /**
150
+ * The group-parent table, flat: `[parent_ref, parent_cluster, ...]` in table order, which the
151
+ * groups' `parent_first` slices.
152
+ * @type {number[]}
153
+ */
154
+ parent_entries = [];
155
+
123
156
  /**
124
157
  * Position `buffer` at a page-relative offset.
125
158
  * @param {number} offset
@@ -617,13 +650,9 @@ function decode_page(buffer, frame, level_count, out) {
617
650
  page.payload_size = decoded.readUint32();
618
651
  page.node_table_offset = decoded.readUint32();
619
652
 
620
- for (let offset = 24; offset < VGEO_PAGE_OFFSET.METRIC; offset++) {
621
- if (decoded.raw_bytes[page.base + offset] !== 0) {
622
- out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${frame.page_index}: reserved byte at ${offset} in the page header is not zero`));
623
-
624
- break;
625
- }
626
- }
653
+ page.parent_table_offset = decoded.readUint32();
654
+ page.parent_entry_count = decoded.readUint16();
655
+ page.parent_page_count = decoded.readUint16();
627
656
 
628
657
  page.seek(VGEO_PAGE_OFFSET.METRIC);
629
658
 
@@ -674,7 +703,22 @@ function decode_page(buffer, frame, level_count, out) {
674
703
  return undefined;
675
704
  }
676
705
 
677
- const expected_payload_offset = page.cluster_table_offset + page.cluster_count * VGEO_CLUSTER_RECORD_SIZE;
706
+ const expected_parent_table_offset = page.cluster_table_offset
707
+ + page.cluster_count * VGEO_CLUSTER_RECORD_SIZE;
708
+
709
+ if (page.parent_table_offset !== expected_parent_table_offset) {
710
+ out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${frame.page_index}: parent_table_offset is ${page.parent_table_offset}, expected ${expected_parent_table_offset}`));
711
+
712
+ return undefined;
713
+ }
714
+
715
+ if (page.parent_page_count > page.parent_entry_count) {
716
+ out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${frame.page_index}: parent_page_count is ${page.parent_page_count}, above the ${page.parent_entry_count} entries that could name a page`));
717
+ }
718
+
719
+ const expected_payload_offset = page.parent_table_offset
720
+ + page.parent_page_count * VGEO_PARENT_PAGE_ENTRY_SIZE
721
+ + page.parent_entry_count * VGEO_PARENT_ENTRY_SIZE;
678
722
 
679
723
  if (page.payload_offset !== expected_payload_offset) {
680
724
  out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${frame.page_index}: payload_offset is ${page.payload_offset}, expected ${expected_payload_offset}`));
@@ -1016,7 +1060,7 @@ function check_child_tables(buffer, frames, pages, out) {
1016
1060
  /**
1017
1061
  * @param {DecodedPage} page
1018
1062
  * @param {VGeoDefect[]} out
1019
- * @returns {{cluster_first:number, cluster_count:number, parent_cluster_count:number}[]}
1063
+ * @returns {{cluster_first:number, cluster_count:number, parent_cluster_count:number, parent_first:number}[]}
1020
1064
  */
1021
1065
  function read_groups(page, out) {
1022
1066
  const result = [];
@@ -1024,6 +1068,7 @@ function read_groups(page, out) {
1024
1068
  const buffer = page.buffer;
1025
1069
 
1026
1070
  let expected_first = 0;
1071
+ let expected_parent_first = 0;
1027
1072
 
1028
1073
  for (let g = 0; g < page.group_count; g++) {
1029
1074
  page.seek(VGEO_PAGE_HEADER_SIZE + g * VGEO_GROUP_RECORD_SIZE);
@@ -1032,12 +1077,9 @@ function read_groups(page, out) {
1032
1077
  cluster_first: buffer.readUint16(),
1033
1078
  cluster_count: buffer.readUint16(),
1034
1079
  parent_cluster_count: buffer.readUint16(),
1080
+ parent_first: buffer.readUint16(),
1035
1081
  };
1036
1082
 
1037
- if (buffer.readUint16() !== 0) {
1038
- out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${g}: reserved is not zero`));
1039
- }
1040
-
1041
1083
  if (group.cluster_count < 1 || group.cluster_count > VGEO_MAX_GROUP_CLUSTER_COUNT) {
1042
1084
  out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${g}: cluster_count ${group.cluster_count} is outside [1, ${VGEO_MAX_GROUP_CLUSTER_COUNT}]`));
1043
1085
  }
@@ -1048,6 +1090,12 @@ function read_groups(page, out) {
1048
1090
 
1049
1091
  expected_first = group.cluster_first + group.cluster_count;
1050
1092
 
1093
+ if (group.parent_first !== expected_parent_first) {
1094
+ out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${g}: parent_first ${group.parent_first}, expected ${expected_parent_first}; a page's groups must tile its group-parent table in order`));
1095
+ }
1096
+
1097
+ expected_parent_first = group.parent_first + group.parent_cluster_count;
1098
+
1051
1099
  result.push(group);
1052
1100
  }
1053
1101
 
@@ -1055,9 +1103,147 @@ function read_groups(page, out) {
1055
1103
  out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index}: groups cover ${expected_first} clusters, the page holds ${page.cluster_count}`));
1056
1104
  }
1057
1105
 
1106
+ if (expected_parent_first !== page.parent_entry_count) {
1107
+ out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index}: groups cover ${expected_parent_first} parent entries, the page's table holds ${page.parent_entry_count}`));
1108
+ }
1109
+
1058
1110
  return result;
1059
1111
  }
1060
1112
 
1113
+ /**
1114
+ * Read the two parent tables onto the page, and check the shape of what they hold before anything
1115
+ * tries to resolve it.
1116
+ *
1117
+ * @param {DecodedPage} page
1118
+ * @param {VGeoDefect[]} out
1119
+ */
1120
+ function read_parent_tables(page, out) {
1121
+ const buffer = page.buffer;
1122
+
1123
+ page.seek(page.parent_table_offset);
1124
+
1125
+ for (let i = 0; i < page.parent_page_count; i++) {
1126
+ page.parent_pages.push(buffer.readUint32());
1127
+ }
1128
+
1129
+ // Ascending and distinct, so that a parent page resolves to one reference and the refine-side
1130
+ // election in a runtime reading this table is deterministic.
1131
+ for (let i = 1; i < page.parent_pages.length; i++) {
1132
+ if (page.parent_pages[i] <= page.parent_pages[i - 1]) {
1133
+ out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${page.page_index} parent page entry ${i}: page index ${page.parent_pages[i]} does not follow ${page.parent_pages[i - 1]}; the table is ascending and deduplicated`));
1134
+
1135
+ break;
1136
+ }
1137
+ }
1138
+
1139
+ for (const parent_page of page.parent_pages) {
1140
+ if (parent_page === page.page_index) {
1141
+ out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${page.page_index}: its own index is in its parent-page table, where SAME_PAGE belongs`));
1142
+
1143
+ break;
1144
+ }
1145
+ }
1146
+
1147
+ page.seek(page.parent_table_offset + page.parent_page_count * VGEO_PARENT_PAGE_ENTRY_SIZE);
1148
+
1149
+ for (let i = 0; i < page.parent_entry_count; i++) {
1150
+ const parent_ref = buffer.readUint16();
1151
+ const parent_cluster = buffer.readUint16();
1152
+
1153
+ if (parent_ref !== VGEO_SAME_PAGE
1154
+ && (parent_ref > VGEO_MAX_PARENT_REF || parent_ref >= page.parent_page_count)) {
1155
+ out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} parent entry ${i}: parent_ref ${parent_ref} is outside the ${page.parent_page_count}-entry parent-page table`));
1156
+ }
1157
+
1158
+ page.parent_entries.push(parent_ref, parent_cluster);
1159
+ }
1160
+ }
1161
+
1162
+ /**
1163
+ * The upward edge, checked against the downward one it mirrors — format §11.16.
1164
+ *
1165
+ * Every parent reference must resolve to a cluster that really does name this group as its child,
1166
+ * and each group's list must be sorted and free of repeats. The first is what makes a coarsen legal
1167
+ * at all; the second is what lets a runtime elect one appender out of a group's parents by taking
1168
+ * the first entry of the list, rather than carrying a bitmask sized by instances times groups.
1169
+ *
1170
+ * It is checked by rebuilding the lists from the cluster records and comparing, rather than by
1171
+ * resolving each reference on its own: the downward edge is already validated by {@link check_dag},
1172
+ * so rebuilding from it catches a *missing* parent as well as a wrong one.
1173
+ *
1174
+ * @param {DecodedPage[]} pages
1175
+ * @param {object[][]} page_groups
1176
+ * @param {object[][]} page_clusters
1177
+ * @param {VGeoDefect[]} out
1178
+ */
1179
+ function check_parent_tables(pages, page_groups, page_clusters, out) {
1180
+ /**
1181
+ * `page:group` to the parents the cluster records say it has, in the order §11.16 requires.
1182
+ * @type {Map<string, {page: number, cluster: number}[]>}
1183
+ */
1184
+ const expected = new Map();
1185
+
1186
+ for (const page of pages) {
1187
+ for (const cluster of page_clusters[page.page_index]) {
1188
+ if (cluster.child_ref === VGEO_NO_CHILD) {
1189
+ continue;
1190
+ }
1191
+
1192
+ const child_page = cluster.child_ref === VGEO_SAME_PAGE
1193
+ ? page.page_index
1194
+ : page.child_pages[cluster.child_ref];
1195
+
1196
+ if (child_page === undefined) {
1197
+ // a broken child reference, which check_dag reports; nothing to mirror
1198
+ continue;
1199
+ }
1200
+
1201
+ const id = `${child_page}:${cluster.child_group}`;
1202
+
1203
+ let list = expected.get(id);
1204
+
1205
+ if (list === undefined) {
1206
+ expected.set(id, list = []);
1207
+ }
1208
+
1209
+ list.push({ page: page.page_index, cluster: cluster.index });
1210
+ }
1211
+ }
1212
+
1213
+ for (const list of expected.values()) {
1214
+ list.sort((a, b) => a.page - b.page || a.cluster - b.cluster);
1215
+ }
1216
+
1217
+ for (const page of pages) {
1218
+ page_groups[page.page_index].forEach((group, group_index) => {
1219
+ const want = expected.get(`${page.page_index}:${group_index}`) ?? [];
1220
+
1221
+ if (group.parent_first + group.parent_cluster_count > page.parent_entry_count) {
1222
+ out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${group_index}: parents ${group.parent_first}..${group.parent_first + group.parent_cluster_count} run past the ${page.parent_entry_count}-entry table`));
1223
+
1224
+ return;
1225
+ }
1226
+
1227
+ for (let i = 0; i < group.parent_cluster_count && i < want.length; i++) {
1228
+ const base = (group.parent_first + i) * 2;
1229
+
1230
+ const parent_ref = page.parent_entries[base];
1231
+ const parent_cluster = page.parent_entries[base + 1];
1232
+
1233
+ const named_page = parent_ref === VGEO_SAME_PAGE
1234
+ ? page.page_index
1235
+ : page.parent_pages[parent_ref];
1236
+
1237
+ if (named_page !== want[i].page || parent_cluster !== want[i].cluster) {
1238
+ out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${group_index} parent ${i}: names page ${named_page} cluster ${parent_cluster}, but the ${i}th cluster refining into this group is page ${want[i].page} cluster ${want[i].cluster}`));
1239
+
1240
+ break;
1241
+ }
1242
+ }
1243
+ });
1244
+ }
1245
+ }
1246
+
1061
1247
  /**
1062
1248
  * Decode a cluster's local positions from its payload — the only way to check that the culling
1063
1249
  * bounds actually bound anything.
@@ -1617,6 +1803,8 @@ export function vgeo_validate_container(buffer) {
1617
1803
  const groups = read_groups(page, out);
1618
1804
  const clusters = read_clusters(page, out);
1619
1805
 
1806
+ read_parent_tables(page, out);
1807
+
1620
1808
  page_groups.push(groups);
1621
1809
  page_clusters.push(clusters);
1622
1810
 
@@ -1637,6 +1825,7 @@ export function vgeo_validate_container(buffer) {
1637
1825
  }
1638
1826
 
1639
1827
  check_page_nodes(pages, page_groups, page_clusters, out);
1828
+ check_parent_tables(pages, page_groups, page_clusters, out);
1640
1829
 
1641
1830
  check_dag(pages, page_groups, page_clusters, level_count, out);
1642
1831
  check_directory(buffer, frames, pages, out);
@@ -1 +1 @@
1
- {"version":3,"file":"vgeo_write_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_write_container.js"],"names":[],"mappings":"AAmTA;;;;;;;;GAQG;AACH,4CANW,qBAAqB,8BAGnB,YAAY,CAmNxB;6BA3gB4B,4CAA4C"}
1
+ {"version":3,"file":"vgeo_write_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_write_container.js"],"names":[],"mappings":"AA4bA;;;;;;;;GAQG;AACH,4CANW,qBAAqB,8BAGnB,YAAY,CAmNxB;6BAppB4B,4CAA4C"}
@@ -24,6 +24,8 @@ import { VGEO_HEADER_SIZE } from "./header/VGEO_HEADER_SIZE.js";
24
24
  import { VGEO_LEVEL_RECORD_SIZE } from "./header/VGEO_LEVEL_RECORD_SIZE.js";
25
25
  import { VGEO_MAGIC } from "./header/VGEO_MAGIC.js";
26
26
  import { VGEO_MAX_CHILD_REF } from "./cluster/VGEO_MAX_CHILD_REF.js";
27
+ import { VGEO_MAX_PARENT_ENTRY_COUNT } from "./page/VGEO_MAX_PARENT_ENTRY_COUNT.js";
28
+ import { VGEO_MAX_PARENT_REF } from "./page/VGEO_MAX_PARENT_REF.js";
27
29
  import { VGEO_MIN_READER_VERSION } from "./header/VGEO_MIN_READER_VERSION.js";
28
30
  import { VGEO_NO_CHILD } from "./cluster/VGEO_NO_CHILD.js";
29
31
  import { VGEO_NO_GROUP } from "./cluster/VGEO_NO_GROUP.js";
@@ -32,7 +34,10 @@ import { VGEO_NODE_RECORD_SIZE } from "./page/VGEO_NODE_RECORD_SIZE.js";
32
34
  import { VGEO_PAGE_HEADER_SIZE } from "./page/VGEO_PAGE_HEADER_SIZE.js";
33
35
  import { VGEO_PAGE_MAGIC } from "./frame/VGEO_PAGE_MAGIC.js";
34
36
  import { VGEO_PAGE_OFFSET } from "./page/VGEO_PAGE_OFFSET.js";
37
+ import { VGEO_PARENT_ENTRY_SIZE } from "./page/VGEO_PARENT_ENTRY_SIZE.js";
38
+ import { VGEO_PARENT_PAGE_ENTRY_SIZE } from "./page/VGEO_PARENT_PAGE_ENTRY_SIZE.js";
35
39
  import { VGEO_PAYLOAD_ENCODING_SHADE_MESHLET_V1 } from "./header/VGEO_PAYLOAD_ENCODING_SHADE_MESHLET_V1.js";
40
+ import { VGEO_SAME_PAGE } from "./cluster/VGEO_SAME_PAGE.js";
36
41
  import { vgeo_scan_frames } from "./frame/vgeo_scan_frames.js";
37
42
 
38
43
  /**
@@ -98,28 +103,84 @@ class PageBlob {
98
103
  }
99
104
 
100
105
  /**
101
- * Count how many clusters name each group, and index the groups within their pages. Both are
102
- * derived, so recomputing them here keeps a caller from having to maintain them.
106
+ * Count how many clusters name each group, index the groups and clusters within their pages, and
107
+ * build the upward edge. All of it is derived, so recomputing it here keeps a caller from having to
108
+ * maintain any of it.
109
+ *
110
+ * The upward edge is the one piece that cannot be resolved while a single page is written: a
111
+ * group's parents live in whichever pages happen to refine into it, so the map is built across the
112
+ * whole page set once and then read per page.
103
113
  *
104
114
  * @param {VirtualGeometryPage[]} pages
115
+ * @returns {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} each group's parents,
116
+ * sorted by (page index, cluster index) — the order format §11.16 requires, and the order the
117
+ * runtime's refine-side election depends on being deterministic
105
118
  */
106
119
  function resolve_group_references(pages) {
107
120
  for (const page of pages) {
121
+ let cluster_index = 0;
122
+
108
123
  page.groups.forEach((group, index) => {
109
124
  group.index_in_page = index;
110
125
  group.parent_cluster_count = 0;
126
+
127
+ for (const cluster of group.clusters) {
128
+ cluster.index_in_page = cluster_index;
129
+ cluster_index++;
130
+ }
111
131
  });
112
132
  }
113
133
 
134
+ /** @type {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} */
135
+ const parents = new Map();
136
+
114
137
  for (const page of pages) {
115
138
  for (const group of page.groups) {
116
139
  for (const cluster of group.clusters) {
117
- if (cluster.child_group !== undefined) {
118
- cluster.child_group.parent_cluster_count++;
140
+ const child = cluster.child_group;
141
+
142
+ if (child === undefined) {
143
+ continue;
119
144
  }
145
+
146
+ child.parent_cluster_count++;
147
+
148
+ let list = parents.get(child);
149
+
150
+ if (list === undefined) {
151
+ parents.set(child, list = []);
152
+ }
153
+
154
+ list.push({ page: page.index, cluster: cluster.index_in_page });
155
+ }
156
+ }
157
+ }
158
+
159
+ for (const list of parents.values()) {
160
+ list.sort((a, b) => a.page - b.page || a.cluster - b.cluster);
161
+ }
162
+
163
+ return parents;
164
+ }
165
+
166
+ /**
167
+ * @param {VirtualGeometryPage} page
168
+ * @param {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} parents
169
+ * @returns {number[]} distinct indices of *other* pages holding a parent of one of this page's
170
+ * groups, ascending; a parent in this page is named by `VGEO_SAME_PAGE` and is not here
171
+ */
172
+ function collect_parent_pages(page, parents) {
173
+ const seen = new Set();
174
+
175
+ for (const group of page.groups) {
176
+ for (const parent of parents.get(group) ?? []) {
177
+ if (parent.page !== page.index) {
178
+ seen.add(parent.page);
120
179
  }
121
180
  }
122
181
  }
182
+
183
+ return Array.from(seen).sort((a, b) => a - b);
123
184
  }
124
185
 
125
186
  /**
@@ -149,9 +210,10 @@ function collect_child_pages(page) {
149
210
  /**
150
211
  * @param {VirtualGeometryPage} page
151
212
  * @param {number[]} child_pages
213
+ * @param {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} parents
152
214
  * @returns {Uint8Array} the decoded page
153
215
  */
154
- function build_page_blob(page, child_pages) {
216
+ function build_page_blob(page, child_pages, parents) {
155
217
  const clusters = [];
156
218
 
157
219
  for (const group of page.groups) {
@@ -160,9 +222,41 @@ function build_page_blob(page, child_pages) {
160
222
  }
161
223
  }
162
224
 
225
+ const parent_pages = collect_parent_pages(page, parents);
226
+
227
+ let parent_entry_count = 0;
228
+
229
+ for (const group of page.groups) {
230
+ parent_entry_count += (parents.get(group) ?? []).length;
231
+ }
232
+
233
+ assert.lessThanOrEqual(
234
+ parent_entry_count, VGEO_MAX_PARENT_ENTRY_COUNT,
235
+ 'page group-parent table must stay within what parent_first can index (format §11.15)'
236
+ );
237
+
238
+ assert.lessThanOrEqual(
239
+ parent_pages.length, VGEO_MAX_PARENT_REF + 1,
240
+ 'page parent-page table must stay within what parent_ref can index'
241
+ );
242
+
163
243
  const node_table_offset = VGEO_PAGE_HEADER_SIZE + page.groups.length * VGEO_GROUP_RECORD_SIZE;
164
244
  const cluster_table_offset = node_table_offset + page.nodes.length * VGEO_NODE_RECORD_SIZE;
165
- const payload_offset = cluster_table_offset + clusters.length * VGEO_CLUSTER_RECORD_SIZE;
245
+
246
+ /*
247
+ The parent section sits between the cluster records and the payload rather than beside the
248
+ group table, which keeps `node_table_offset`'s "= 56 + 8·group_count" true and leaves every
249
+ offset a reader before format 4 computed exactly where it was. Both tables hold 4-byte entries
250
+ and the sections above them are all multiples of four, so the payload stays word-aligned —
251
+ format §11.8's promise, which the meshlet batch divides by four without rounding.
252
+ */
253
+ const parent_table_offset = cluster_table_offset + clusters.length * VGEO_CLUSTER_RECORD_SIZE;
254
+
255
+ const group_parent_table_offset = parent_table_offset
256
+ + parent_pages.length * VGEO_PARENT_PAGE_ENTRY_SIZE;
257
+
258
+ const payload_offset = group_parent_table_offset
259
+ + parent_entry_count * VGEO_PARENT_ENTRY_SIZE;
166
260
 
167
261
  let payload_size = 0;
168
262
 
@@ -185,6 +279,9 @@ function build_page_blob(page, child_pages) {
185
279
  buffer.writeUint32(payload_offset);
186
280
  buffer.writeUint32(payload_size);
187
281
  buffer.writeUint32(node_table_offset);
282
+ buffer.writeUint32(parent_table_offset);
283
+ buffer.writeUint16(parent_entry_count);
284
+ buffer.writeUint16(parent_pages.length);
188
285
 
189
286
  // The page's own metric, so an installed page can be re-tested from itself rather than from
190
287
  // whichever of its parents happened to reference it.
@@ -216,16 +313,56 @@ function build_page_blob(page, child_pages) {
216
313
  child_ref_of_page.set(page_index, index);
217
314
  });
218
315
 
316
+ /**
317
+ * `page_index -> parent-page-table index`. The same shape as above and resolved the same way;
318
+ * a parent inside this page is `VGEO_SAME_PAGE` and is not in the table at all.
319
+ * @type {Map<number, number>}
320
+ */
321
+ const parent_ref_of_page = new Map();
322
+
323
+ parent_pages.forEach((page_index, index) => {
324
+ assert.lessThanOrEqual(index, VGEO_MAX_PARENT_REF, 'parent table index must stay below the sentinel range');
325
+
326
+ parent_ref_of_page.set(page_index, index);
327
+ });
328
+
329
+ parent_pages.forEach((page_index, index) => {
330
+ buffer.position = parent_table_offset + index * VGEO_PARENT_PAGE_ENTRY_SIZE;
331
+
332
+ buffer.writeUint32(page_index);
333
+ });
334
+
219
335
  let cluster_index = 0;
220
336
  let cursor = 0;
221
337
 
338
+ let parent_first = 0;
339
+
222
340
  page.groups.forEach((group, group_index) => {
341
+ const group_parents = parents.get(group) ?? [];
342
+
343
+ assert.equal(
344
+ group_parents.length, group.parent_cluster_count,
345
+ 'a group\'s parent list and its parent_cluster_count are the same fact twice'
346
+ );
347
+
348
+ group_parents.forEach((parent, index) => {
349
+ buffer.position = group_parent_table_offset
350
+ + (parent_first + index) * VGEO_PARENT_ENTRY_SIZE;
351
+
352
+ buffer.writeUint16(
353
+ parent.page === page.index ? VGEO_SAME_PAGE : parent_ref_of_page.get(parent.page)
354
+ );
355
+ buffer.writeUint16(parent.cluster);
356
+ });
357
+
223
358
  buffer.position = VGEO_PAGE_HEADER_SIZE + group_index * VGEO_GROUP_RECORD_SIZE;
224
359
 
225
360
  buffer.writeUint16(cluster_index);
226
361
  buffer.writeUint16(group.clusters.length);
227
362
  buffer.writeUint16(group.parent_cluster_count);
228
- buffer.writeUint16(0);
363
+ buffer.writeUint16(parent_first);
364
+
365
+ parent_first += group_parents.length;
229
366
 
230
367
  for (const cluster of group.clusters) {
231
368
  const offset = cluster_table_offset + cluster_index * VGEO_CLUSTER_RECORD_SIZE;
@@ -322,19 +459,19 @@ export function vgeo_write_container(pages, options) {
322
459
  assert.equal(page.index, index, `page ${index} carries index ${page.index}`);
323
460
  });
324
461
 
325
- resolve_group_references(pages);
462
+ const parents = resolve_group_references(pages);
326
463
 
327
464
  const blobs = pages.map((page) => {
328
465
  const blob = new PageBlob();
329
466
 
330
467
  blob.child_pages = collect_child_pages(page);
331
468
 
332
- const decoded = build_page_blob(page, blob.child_pages);
469
+ const decoded = build_page_blob(page, blob.child_pages, parents);
333
470
 
334
471
  // Compression happens here, before a single offset is known, and that is what keeps the
335
472
  // layout non-circular: a frame's extent follows from its *stored* size and its child count,
336
473
  // and neither depends on any offset value, because the child table is plaintext.
337
- const encoded = vgeo_encode_frame_blob(decoded, options.codec);
474
+ const encoded = vgeo_encode_frame_blob(decoded, options.codec, options.codec_level);
338
475
 
339
476
  blob.codec = encoded.codec;
340
477
  blob.stored = encoded.bytes;