@woosh/meep-engine 3.12.0 → 3.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/ConvexHullShape3D.js +41 -25
- package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/PosedShape3D.js +7 -2
- package/src/engine/graphics3/decal/GPUDecalRenderer.js +3 -3
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_decal_composite.js +4 -2
- package/src/engine/graphics3/highlight/GPUHighlightRenderer.d.ts.map +1 -1
- package/src/engine/graphics3/highlight/GPUHighlightRenderer.js +2 -3
- package/src/engine/graphics3/highlight/shader_highlight_outline.js +150 -150
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/RENDERER_CONTRACT.md +2 -1
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts +18 -0
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +73 -0
- package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +755 -0
- package/src/shade/device/ShadeGPUCommandContext.d.ts +10 -16
- package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
- package/src/shade/device/ShadeGPUCommandContext.js +801 -994
- package/src/shade/device/pass/ShadeGPUComputePassEncoder.d.ts +107 -0
- package/src/shade/device/pass/ShadeGPUComputePassEncoder.d.ts.map +1 -0
- package/src/shade/device/pass/ShadeGPUComputePassEncoder.js +222 -0
- package/src/shade/device/pass/ShadeGPURenderPassEncoder.d.ts +168 -0
- package/src/shade/device/pass/ShadeGPURenderPassEncoder.d.ts.map +1 -0
- package/src/shade/device/pass/ShadeGPURenderPassEncoder.js +317 -0
- package/src/shade/device/timing/GPUTimerArray.d.ts +4 -9
- package/src/shade/device/timing/GPUTimerArray.d.ts.map +1 -1
- package/src/shade/device/timing/GPUTimerArray.js +261 -289
- package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +20 -2
- package/src/shade/device/timing/ShadeGPUContextProfiler.d.ts +59 -0
- package/src/shade/device/timing/ShadeGPUContextProfiler.d.ts.map +1 -0
- package/src/shade/device/timing/ShadeGPUContextProfiler.js +182 -0
- package/src/shade/device/timing/profile/GPUProfileSession.d.ts +4 -4
- package/src/shade/device/timing/profile/GPUProfileSession.js +4 -4
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_leaf_triangles.js +3 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_points.js +3 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/shader_blas_audit_visibility.js +3 -1
- package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.js +2 -2
- package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.js +2 -2
- package/src/shade/renderer/Renderer.d.ts +0 -6
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +0 -29
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +1 -3
- package/src/shade/renderer/animation/shader_animation_tick.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_tick.js +128 -125
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +8 -18
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_geometry_sphere_derive.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_geometry_sphere_derive.js +100 -98
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.js +215 -212
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_scatter.d.ts +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_scatter.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_scatter.js +135 -120
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_skinned_mesh_bounds_refresh.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_skinned_mesh_bounds_refresh.js +77 -75
- package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.js +375 -371
- package/src/shade/renderer/atmosphere/shader_transmittance_lut.js +3 -3
- package/src/shade/renderer/buffer/graph_inspect_gpu_buffer.js +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.js +14 -19
- package/src/shade/renderer/buffer/table/gpu_table_element_upload_shader.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/gpu_table_element_upload_shader.js +7 -2
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +325 -319
- package/src/shade/renderer/buffer/util/shader_buffer_copy_storage_to_storage.d.ts.map +1 -1
- package/src/shade/renderer/buffer/util/shader_buffer_copy_storage_to_storage.js +3 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR.d.ts.map +1 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR.js +4 -1
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts +2 -2
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +167 -167
- package/src/shade/renderer/fow/GPUFogOfWarRenderer.js +3 -3
- package/src/shade/renderer/fow/shader_fog_of_war.d.ts.map +1 -1
- package/src/shade/renderer/fow/shader_fog_of_war.js +3 -1
- package/src/shade/renderer/geometry/bvh/record_blas_refit.js +102 -102
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_leaf_bounds.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/shader_blas_refit_leaf_bounds.js +125 -121
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +766 -774
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +72 -69
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +5 -10
- package/src/shade/renderer/geometry/sdf/shader_build_sdf.js +129 -129
- package/src/shade/renderer/geometry/sdf/shader_sdf_visualize.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/shader_sdf_visualize.js +5 -3
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.js +4 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_resolve_probes.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_resolve_probes.js +3 -1
- package/src/shade/renderer/global_illumination/clipmap/shader_update_clipmap_cascade.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/clipmap/shader_update_clipmap_cascade.js +114 -112
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lpv_store_sh.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lpv_store_sh.js +4 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.js +187 -184
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_reduce_atlas_to_sh.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_reduce_atlas_to_sh.js +4 -1
- package/src/shade/renderer/global_illumination/sharc/SpatialHashRadianceCache.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/sharc/SpatialHashRadianceCache.js +6 -8
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +3 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_update.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_update.js +3 -1
- package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +3 -3
- package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +3 -3
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.js +217 -217
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.js +145 -142
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.js +87 -82
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_refit.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_refit.js +143 -140
- package/src/shade/renderer/gpu_primitive/bvh/verify_gpu_bvh_build.d.ts +2 -2
- package/src/shade/renderer/gpu_primitive/bvh/verify_gpu_bvh_build.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/verify_gpu_bvh_build.js +43 -8
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +4 -5
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.js +88 -84
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.js +194 -191
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.js +33 -69
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +6 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.js +23 -7
- package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/execute_filter_environment_map.js +1 -2
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map.js +6 -1
- package/src/shade/renderer/lightmap/bake/raster/graph_draw_lightmap_viz_buffer.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/raster/graph_draw_lightmap_viz_buffer.js +234 -219
- package/src/shade/renderer/lightmap/bake/raster/shader_lightmap_to_viz_buffer.js +2 -2
- package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.js +191 -191
- package/src/shade/renderer/lightmap/bake/tile/shader_lightmap_accummulate_tile.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/tile/shader_lightmap_accummulate_tile.js +85 -82
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +5 -3
- package/src/shade/renderer/particles/prototypeParticleSystem.js +3 -4
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +132 -117
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +79 -77
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +111 -99
- package/src/shade/renderer/particles/sort/shader_particle_sort.d.ts.map +1 -1
- package/src/shade/renderer/particles/sort/shader_particle_sort.js +187 -158
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +7 -10
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.js +4 -1
- package/src/shade/renderer/postprocess/bloom/shader_bloom_mix.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/bloom/shader_bloom_mix.js +3 -1
- package/src/shade/renderer/postprocess/cas/shader_ffx_rcas.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/cas/shader_ffx_rcas.js +4 -2
- package/src/shade/renderer/postprocess/denoise/fragment_shader_denoise_ao.js +147 -147
- package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +121 -119
- package/src/shade/renderer/postprocess/dof/gather/graph_postprocess_dof2.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/gather/graph_postprocess_dof2.js +1 -2
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_far.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_far.js +4 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_near.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_near.js +4 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.js +4 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_setup.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_setup.js +4 -1
- package/src/shade/renderer/postprocess/dof/raymarch/graph_postprocess_dof.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/graph_postprocess_dof.js +2 -4
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_composite.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_composite.js +4 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_prefilter.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_prefilter.js +4 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch.js +4 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch_compute.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch_compute.js +269 -266
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_slice_compute.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_slice_compute.js +273 -270
- package/src/shade/renderer/postprocess/dof/shader_dof_autofocus.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/shader_dof_autofocus.js +4 -1
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +8 -11
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.js +5 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +11 -8
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +7 -8
- package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.js +3 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_concat.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_concat.js +70 -68
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.js +70 -68
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_IBL.js +3 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader_LPV.js +4 -1
- package/src/shade/renderer/postprocess/ssr/shader_downsample_encoded_normal.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/shader_downsample_encoded_normal.js +103 -101
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
- package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.js +3 -1
- package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/shader_taa.js +4 -1
- package/src/shade/renderer/postprocess/upscale-dither/fragment_shader_upscale_dither.js +5 -5
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +339 -341
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +114 -109
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +118 -115
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +69 -65
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +722 -722
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +1 -9
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +1 -6
- package/src/shade/renderer/restir/di/graph_restir_di.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/graph_restir_di.js +2 -3
- package/src/shade/renderer/restir/di/graph_restir_di_denoise.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/graph_restir_di_denoise.js +1 -2
- package/src/shade/renderer/restir/di/shader_restir_di_denoise.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_denoise.js +139 -136
- package/src/shade/renderer/restir/di/shader_restir_di_resample.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_resample.js +131 -129
- package/src/shade/renderer/restir/di/shader_restir_di_resolve.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_resolve.js +101 -99
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +379 -383
- package/src/shade/renderer/scene/Mesh.d.ts.map +1 -1
- package/src/shade/renderer/scene/Mesh.js +4 -6
- package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts.map +1 -1
- package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.js +147 -144
- package/src/shade/renderer/shader/ComputeShader.d.ts +2 -2
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +14 -17
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts +2 -2
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.js +189 -189
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +3 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +16 -7
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +1342 -1326
- package/src/shade/renderer/shadow/map/Shadowmap.d.ts +13 -0
- package/src/shade/renderer/shadow/map/Shadowmap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/Shadowmap.js +14 -0
- package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts +79 -0
- package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.js +196 -0
- package/src/shade/renderer/shadow/map/ShadowmapRegistry.d.ts +91 -0
- package/src/shade/renderer/shadow/map/ShadowmapRegistry.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/ShadowmapRegistry.js +156 -0
- package/src/shade/renderer/shadow/map/shader/shader_shadowmap_remap_cube_to_octahedral.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/shader_shadowmap_remap_cube_to_octahedral.js +5 -1
- package/src/shade/renderer/shadow/ray/shader_shadow_upscale.d.ts.map +1 -1
- package/src/shade/renderer/shadow/ray/shader_shadow_upscale.js +3 -1
- package/src/shade/renderer/shadow/ray/staged/gen/graph_gen_rays.js +73 -73
- package/src/shade/renderer/shadow/ray/staged/gen/shader_generate_rays.d.ts.map +1 -1
- package/src/shade/renderer/shadow/ray/staged/gen/shader_generate_rays.js +151 -148
- package/src/shade/renderer/shadow/ray/staged/trace/graph_trace_rays.d.ts.map +1 -1
- package/src/shade/renderer/shadow/ray/staged/trace/graph_trace_rays.js +4 -2
- package/src/shade/renderer/shadow/ray/staged/trace/shader_trace_rays.d.ts.map +1 -1
- package/src/shade/renderer/shadow/ray/staged/trace/shader_trace_rays.js +18 -4
- package/src/shade/renderer/shadow/sdf/cascade/CascadedSceneSDF.d.ts.map +1 -1
- package/src/shade/renderer/shadow/sdf/cascade/CascadedSceneSDF.js +7 -8
- package/src/shade/renderer/shadow/sdf/cascade/shader_build_scene_sdf_f32.d.ts.map +1 -1
- package/src/shade/renderer/shadow/sdf/cascade/shader_build_scene_sdf_f32.js +6 -2
- package/src/shade/renderer/shadow/sdf/cascade/shader_scene_sdf_debug_viz.d.ts.map +1 -1
- package/src/shade/renderer/shadow/sdf/cascade/shader_scene_sdf_debug_viz.js +129 -127
- package/src/shade/renderer/shadow/sdf/graph_draw_sdf_shadows.d.ts.map +1 -1
- package/src/shade/renderer/shadow/sdf/graph_draw_sdf_shadows.js +5 -3
- package/src/shade/renderer/texture/virtual/VirtualTextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +2 -5
- package/src/shade/renderer/texture/virtual/build_shader_vt_feedback.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/build_shader_vt_feedback.js +233 -231
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +2 -4
- package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
- package/src/shade/wgsl/validate_wgsl_source.js +8 -3
- package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts +0 -21
- package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts.map +0 -1
- package/src/shade/device/timing/profile/make_profiling_pass_encoder.js +0 -114
- package/src/shade/device/timing/profile/parse_workgroup_size.d.ts +0 -20
- package/src/shade/device/timing/profile/parse_workgroup_size.d.ts.map +0 -1
- package/src/shade/device/timing/profile/parse_workgroup_size.js +0 -43
|
@@ -113,6 +113,19 @@ export class Shadowmap {
|
|
|
113
113
|
* @type {boolean}
|
|
114
114
|
*/
|
|
115
115
|
metadata_changed: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Which reconciliation pass last saw this map's light in the scene. Owned entirely by
|
|
118
|
+
* {@link ShadowmapRegistry} — nothing else should read or write it.
|
|
119
|
+
*
|
|
120
|
+
* Lives on the map rather than in a side table because the reclamation pass tests it once per
|
|
121
|
+
* map per frame, and a hash lookup there costs more than the whole rest of the pass. A
|
|
122
|
+
* `WeakMap` keyed by map measured at about twice the total reconciliation time at 32 lights.
|
|
123
|
+
*
|
|
124
|
+
* 0 means "never marked", which is what a map reads as before its first reconciliation. The
|
|
125
|
+
* registry marks from 1 upward, so an unmarked map is correctly treated as stale.
|
|
126
|
+
* @type {number}
|
|
127
|
+
*/
|
|
128
|
+
_reconcile_mark: number;
|
|
116
129
|
/**
|
|
117
130
|
*
|
|
118
131
|
* @param {Camera} main_camera
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Shadowmap.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/map/Shadowmap.js"],"names":[],"mappings":"AAAA;IACI,WAAO;IAEP;;OAEG;IACH,aAAK;IAEL;;;;OAIG;IACH,QAFU,OAAO,CAEL;IAEZ;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,gBAFU,OAAO,GAAG,IAAI,CAEF;IAEtB;;;OAGG;IACH,OAFU,MAAM,CAEL;IAEX;;;;;;;;;;;OAWG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;;;;OAMG;IACH,0BAFU,MAAM,CAEc;IAE9B;;;;;;;OAOG;IACH,yBAFU,MAAM,CAEa;IAE7B;;;;;;;;;;;;;;;;;OAiBG;IACH,YAFU,OAAO,CAEC;IAElB;;;;;;;;OAQG;IACH,aAFU,OAAO,CAEG;IAEpB;;;;;;;;;;;;;;OAcG;IACH,kBAFU,OAAO,CAEO;IAExB;;;;OAIG;IACH,8DAEC;IAED;;;;;;;OAOG;IACH,mBAEC;IAED,gBAEC;CACJ"}
|
|
1
|
+
{"version":3,"file":"Shadowmap.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/map/Shadowmap.js"],"names":[],"mappings":"AAAA;IACI,WAAO;IAEP;;OAEG;IACH,aAAK;IAEL;;;;OAIG;IACH,QAFU,OAAO,CAEL;IAEZ;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,gBAFU,OAAO,GAAG,IAAI,CAEF;IAEtB;;;OAGG;IACH,OAFU,MAAM,CAEL;IAEX;;;;;;;;;;;OAWG;IACH,mBAFU,MAAM,CAEM;IAEtB;;;;;;OAMG;IACH,0BAFU,MAAM,CAEc;IAE9B;;;;;;;OAOG;IACH,yBAFU,MAAM,CAEa;IAE7B;;;;;;;;;;;;;;;;;OAiBG;IACH,YAFU,OAAO,CAEC;IAElB;;;;;;;;OAQG;IACH,aAFU,OAAO,CAEG;IAEpB;;;;;;;;;;;;;;OAcG;IACH,kBAFU,OAAO,CAEO;IAExB;;;;;;;;;;;OAWG;IACH,iBAFU,MAAM,CAEI;IAEpB;;;;OAIG;IACH,8DAEC;IAED;;;;;;;OAOG;IACH,mBAEC;IAED,gBAEC;CACJ"}
|
|
@@ -124,6 +124,20 @@ export class Shadowmap {
|
|
|
124
124
|
*/
|
|
125
125
|
metadata_changed = true;
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Which reconciliation pass last saw this map's light in the scene. Owned entirely by
|
|
129
|
+
* {@link ShadowmapRegistry} — nothing else should read or write it.
|
|
130
|
+
*
|
|
131
|
+
* Lives on the map rather than in a side table because the reclamation pass tests it once per
|
|
132
|
+
* map per frame, and a hash lookup there costs more than the whole rest of the pass. A
|
|
133
|
+
* `WeakMap` keyed by map measured at about twice the total reconciliation time at 32 lights.
|
|
134
|
+
*
|
|
135
|
+
* 0 means "never marked", which is what a map reads as before its first reconciliation. The
|
|
136
|
+
* registry marks from 1 upward, so an unmarked map is correctly treated as stale.
|
|
137
|
+
* @type {number}
|
|
138
|
+
*/
|
|
139
|
+
_reconcile_mark = 0;
|
|
140
|
+
|
|
127
141
|
/**
|
|
128
142
|
*
|
|
129
143
|
* @param {Camera} main_camera
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picks which shadowmaps get rasterized this frame, given a view budget.
|
|
3
|
+
*
|
|
4
|
+
* This is the score-and-select half of {@link GPUSceneShadowmapContext.select_for_draw}, split out
|
|
5
|
+
* so it can be measured without a GPU device — the scoring is arithmetic over plain fields, and
|
|
6
|
+
* the only reason it used to need a renderer was that it lived on the class that owns the atlas.
|
|
7
|
+
*
|
|
8
|
+
* **Why a heap and not a sort.** The budget is a handful of views and a scene can hold hundreds of
|
|
9
|
+
* candidates, so a full ordering is thrown away almost entirely: it sorts N to consume ~K. Popping
|
|
10
|
+
* a max-heap K times is O(N + K log N) against the sort's O(N log N), and skips the N `{map,
|
|
11
|
+
* score}` objects the sorted version allocated every frame. Measured at 512 lights: 30us per frame
|
|
12
|
+
* for the sort, 2.6us for the heap. Removing just the allocation and keeping the sort gets 8.3us,
|
|
13
|
+
* so roughly a third of the win is the allocation and the rest is not ordering the tail. See
|
|
14
|
+
* benchmark/select.spec.js.
|
|
15
|
+
*
|
|
16
|
+
* **Ordering is load-bearing, so the heap is drained in score order rather than partitioned.**
|
|
17
|
+
* A map that has never been drawn must refresh whether or not the budget can cover it, but WHEN it
|
|
18
|
+
* charges its views against the pool decides whether a lower-priority map still fits. Settling all
|
|
19
|
+
* the must-draws up front would be cheaper and would change which maps draw, so they compete in
|
|
20
|
+
* the same ordered drain as everything else.
|
|
21
|
+
*
|
|
22
|
+
* **Ties resolve differently than a sort.** `Array.sort` is stable, so equal scores kept array
|
|
23
|
+
* order; a heap has no such guarantee, and it compares float32 where the sort compared float64.
|
|
24
|
+
* Maps with equal scores are interchangeable by construction — the scorer is the definition of
|
|
25
|
+
* which map deserves the slot, and it rated them the same — so what the benchmark asserts is that
|
|
26
|
+
* the selection is equally good (same view spend, same carry-over signal, same multiset of
|
|
27
|
+
* selected scores), not that it is the same maps. Ties are common rather than exotic here: every
|
|
28
|
+
* light the camera sits inside reports the full viewport as its projected area.
|
|
29
|
+
*/
|
|
30
|
+
export class ShadowmapDrawSelector {
|
|
31
|
+
/**
|
|
32
|
+
* Maps chosen by the most recent {@link select}, in the order they were selected. Reused
|
|
33
|
+
* across frames — read it before the next call, don't retain it.
|
|
34
|
+
* @type {Shadowmap[]}
|
|
35
|
+
*/
|
|
36
|
+
selected: Shadowmap[];
|
|
37
|
+
/**
|
|
38
|
+
* Views the most recent {@link select} committed, counting must-draws that bypassed the
|
|
39
|
+
* budget. Can exceed the budget it was given.
|
|
40
|
+
* @type {number}
|
|
41
|
+
*/
|
|
42
|
+
views_spent: number;
|
|
43
|
+
/**
|
|
44
|
+
* True when the most recent {@link select} left at least one in-view candidate unrefreshed
|
|
45
|
+
* because the pool could not cover its view cost. Drives the caller's carry-over: unused
|
|
46
|
+
* budget is only worth carrying forward when there was demand it could not meet.
|
|
47
|
+
* @type {boolean}
|
|
48
|
+
*/
|
|
49
|
+
had_unfit_candidates: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Score every shadowmap and mark the winners with `should_draw`.
|
|
52
|
+
*
|
|
53
|
+
* Categories, in the order the drain encounters them:
|
|
54
|
+
*
|
|
55
|
+
* - **Directional** — always refreshes. Scores Infinity, so it would head the ordering
|
|
56
|
+
* anyway; it is settled during the scoring pass instead of being pushed onto the heap
|
|
57
|
+
* because the outcome cannot depend on where it lands. Its view cost is still charged, so
|
|
58
|
+
* local lights see a reduced pool.
|
|
59
|
+
* - **Local, off-screen** (`projected_area_px <= 0`) — skipped entirely. Not demand, and not
|
|
60
|
+
* carry-over fuel: the map keeps its flags and springs back when it returns to view.
|
|
61
|
+
* - **Local, in-view, invalid** — must draw. `is_invalid` means the committed layout has
|
|
62
|
+
* never held valid depth, so sampling it would show garbage. Bypasses the budget but is
|
|
63
|
+
* visited in score order, because its charge against the pool is what decides whether the
|
|
64
|
+
* candidates below it still fit.
|
|
65
|
+
* - **Local, in-view, valid** — competes for what is left, highest score first.
|
|
66
|
+
*
|
|
67
|
+
* Results land on {@link selected}, {@link views_spent} and {@link had_unfit_candidates}.
|
|
68
|
+
* `map.update()` is deliberately NOT called here — that needs the camera and the scene, and
|
|
69
|
+
* keeping it out is what keeps this side GPU-free. The caller walks {@link selected}.
|
|
70
|
+
*
|
|
71
|
+
* @param {Shadowmap[]} shadowmaps every map in the scene; `projected_area_px` must already be
|
|
72
|
+
* current for this frame
|
|
73
|
+
* @param {number} frame_index monotonically increasing frame counter, used for staleness
|
|
74
|
+
* @param {number} budget_total views available this frame, including any carry-over
|
|
75
|
+
*/
|
|
76
|
+
select(shadowmaps: Shadowmap[], frame_index: number, budget_total: number): void;
|
|
77
|
+
#private;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=ShadowmapDrawSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShadowmapDrawSelector.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/map/ShadowmapDrawSelector.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;IACI;;;;OAIG;IACH,UAFU,WAAW,CAEP;IAEd;;;;OAIG;IACH,aAFU,MAAM,CAEA;IAEhB;;;;;OAKG;IACH,sBAFU,OAAO,CAEY;IAsC7B;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,mBALW,WAAW,eAEX,MAAM,gBACN,MAAM,QA+EhB;;CACJ"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { IndexedFloatMaxHeap } from "../../../../core/collection/heap/IndexedFloatMaxHeap.js";
|
|
2
|
+
import { compute_shadowmap_update_score } from "./shadowmap_update_score.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Picks which shadowmaps get rasterized this frame, given a view budget.
|
|
6
|
+
*
|
|
7
|
+
* This is the score-and-select half of {@link GPUSceneShadowmapContext.select_for_draw}, split out
|
|
8
|
+
* so it can be measured without a GPU device — the scoring is arithmetic over plain fields, and
|
|
9
|
+
* the only reason it used to need a renderer was that it lived on the class that owns the atlas.
|
|
10
|
+
*
|
|
11
|
+
* **Why a heap and not a sort.** The budget is a handful of views and a scene can hold hundreds of
|
|
12
|
+
* candidates, so a full ordering is thrown away almost entirely: it sorts N to consume ~K. Popping
|
|
13
|
+
* a max-heap K times is O(N + K log N) against the sort's O(N log N), and skips the N `{map,
|
|
14
|
+
* score}` objects the sorted version allocated every frame. Measured at 512 lights: 30us per frame
|
|
15
|
+
* for the sort, 2.6us for the heap. Removing just the allocation and keeping the sort gets 8.3us,
|
|
16
|
+
* so roughly a third of the win is the allocation and the rest is not ordering the tail. See
|
|
17
|
+
* benchmark/select.spec.js.
|
|
18
|
+
*
|
|
19
|
+
* **Ordering is load-bearing, so the heap is drained in score order rather than partitioned.**
|
|
20
|
+
* A map that has never been drawn must refresh whether or not the budget can cover it, but WHEN it
|
|
21
|
+
* charges its views against the pool decides whether a lower-priority map still fits. Settling all
|
|
22
|
+
* the must-draws up front would be cheaper and would change which maps draw, so they compete in
|
|
23
|
+
* the same ordered drain as everything else.
|
|
24
|
+
*
|
|
25
|
+
* **Ties resolve differently than a sort.** `Array.sort` is stable, so equal scores kept array
|
|
26
|
+
* order; a heap has no such guarantee, and it compares float32 where the sort compared float64.
|
|
27
|
+
* Maps with equal scores are interchangeable by construction — the scorer is the definition of
|
|
28
|
+
* which map deserves the slot, and it rated them the same — so what the benchmark asserts is that
|
|
29
|
+
* the selection is equally good (same view spend, same carry-over signal, same multiset of
|
|
30
|
+
* selected scores), not that it is the same maps. Ties are common rather than exotic here: every
|
|
31
|
+
* light the camera sits inside reports the full viewport as its projected area.
|
|
32
|
+
*/
|
|
33
|
+
export class ShadowmapDrawSelector {
|
|
34
|
+
/**
|
|
35
|
+
* Maps chosen by the most recent {@link select}, in the order they were selected. Reused
|
|
36
|
+
* across frames — read it before the next call, don't retain it.
|
|
37
|
+
* @type {Shadowmap[]}
|
|
38
|
+
*/
|
|
39
|
+
selected = [];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Views the most recent {@link select} committed, counting must-draws that bypassed the
|
|
43
|
+
* budget. Can exceed the budget it was given.
|
|
44
|
+
* @type {number}
|
|
45
|
+
*/
|
|
46
|
+
views_spent = 0;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* True when the most recent {@link select} left at least one in-view candidate unrefreshed
|
|
50
|
+
* because the pool could not cover its view cost. Drives the caller's carry-over: unused
|
|
51
|
+
* budget is only worth carrying forward when there was demand it could not meet.
|
|
52
|
+
* @type {boolean}
|
|
53
|
+
*/
|
|
54
|
+
had_unfit_candidates = false;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Heap of budget candidates, keyed by index into the shadowmap array the current
|
|
58
|
+
* {@link select} was handed. Held across frames so the id table and slot storage are
|
|
59
|
+
* allocated once rather than per frame.
|
|
60
|
+
* @type {IndexedFloatMaxHeap}
|
|
61
|
+
*/
|
|
62
|
+
#heap = new IndexedFloatMaxHeap(0);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Id capacity of {@link #heap}. Ids are shadowmap array indices, so this has to cover the
|
|
66
|
+
* largest map count seen so far.
|
|
67
|
+
* @type {number}
|
|
68
|
+
*/
|
|
69
|
+
#heap_capacity = 0;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Resize the heap to hold ids up to `count`. IndexedFloatMaxHeap sizes its id table at
|
|
73
|
+
* construction, so growing means a new heap — safe here because the heap is empty between
|
|
74
|
+
* frames and carries nothing worth migrating.
|
|
75
|
+
*
|
|
76
|
+
* Rounded up to a power of two so a scene that gains lights one at a time reallocates a
|
|
77
|
+
* handful of times rather than every frame.
|
|
78
|
+
*
|
|
79
|
+
* @param {number} count
|
|
80
|
+
*/
|
|
81
|
+
#ensure_capacity(count) {
|
|
82
|
+
if (count <= this.#heap_capacity) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const capacity = Math.max(64, 1 << (32 - Math.clz32(count - 1)));
|
|
87
|
+
|
|
88
|
+
this.#heap = new IndexedFloatMaxHeap(capacity);
|
|
89
|
+
this.#heap_capacity = capacity;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Score every shadowmap and mark the winners with `should_draw`.
|
|
94
|
+
*
|
|
95
|
+
* Categories, in the order the drain encounters them:
|
|
96
|
+
*
|
|
97
|
+
* - **Directional** — always refreshes. Scores Infinity, so it would head the ordering
|
|
98
|
+
* anyway; it is settled during the scoring pass instead of being pushed onto the heap
|
|
99
|
+
* because the outcome cannot depend on where it lands. Its view cost is still charged, so
|
|
100
|
+
* local lights see a reduced pool.
|
|
101
|
+
* - **Local, off-screen** (`projected_area_px <= 0`) — skipped entirely. Not demand, and not
|
|
102
|
+
* carry-over fuel: the map keeps its flags and springs back when it returns to view.
|
|
103
|
+
* - **Local, in-view, invalid** — must draw. `is_invalid` means the committed layout has
|
|
104
|
+
* never held valid depth, so sampling it would show garbage. Bypasses the budget but is
|
|
105
|
+
* visited in score order, because its charge against the pool is what decides whether the
|
|
106
|
+
* candidates below it still fit.
|
|
107
|
+
* - **Local, in-view, valid** — competes for what is left, highest score first.
|
|
108
|
+
*
|
|
109
|
+
* Results land on {@link selected}, {@link views_spent} and {@link had_unfit_candidates}.
|
|
110
|
+
* `map.update()` is deliberately NOT called here — that needs the camera and the scene, and
|
|
111
|
+
* keeping it out is what keeps this side GPU-free. The caller walks {@link selected}.
|
|
112
|
+
*
|
|
113
|
+
* @param {Shadowmap[]} shadowmaps every map in the scene; `projected_area_px` must already be
|
|
114
|
+
* current for this frame
|
|
115
|
+
* @param {number} frame_index monotonically increasing frame counter, used for staleness
|
|
116
|
+
* @param {number} budget_total views available this frame, including any carry-over
|
|
117
|
+
*/
|
|
118
|
+
select(shadowmaps, frame_index, budget_total) {
|
|
119
|
+
const n = shadowmaps.length;
|
|
120
|
+
|
|
121
|
+
const selected = this.selected;
|
|
122
|
+
selected.length = 0;
|
|
123
|
+
|
|
124
|
+
let views_spent = 0;
|
|
125
|
+
let had_unfit_candidates = false;
|
|
126
|
+
|
|
127
|
+
this.#ensure_capacity(n);
|
|
128
|
+
|
|
129
|
+
const heap = this.#heap;
|
|
130
|
+
heap.clear();
|
|
131
|
+
|
|
132
|
+
// Number of must-draw maps still in the heap. Tracked rather than looked for, because it
|
|
133
|
+
// is the only thing that can stop the drain from exiting early — see below.
|
|
134
|
+
let invalid_in_heap = 0;
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < n; i++) {
|
|
137
|
+
const map = shadowmaps[i];
|
|
138
|
+
|
|
139
|
+
map.should_draw = false;
|
|
140
|
+
|
|
141
|
+
if (map.light.isDirectionalLight) {
|
|
142
|
+
map.should_draw = true;
|
|
143
|
+
selected.push(map);
|
|
144
|
+
views_spent += map.views.length;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (map.projected_area_px <= 0) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (map.is_invalid) {
|
|
153
|
+
invalid_in_heap++;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
heap.insert(i, compute_shadowmap_update_score(map, frame_index));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
while (heap.size > 0) {
|
|
160
|
+
// Every map costs at least one view, so once the pool is gone nothing left can fit and
|
|
161
|
+
// the remainder are unfit by definition — provided none of them is a must-draw, which
|
|
162
|
+
// would have to be visited regardless. In steady state there are none (`is_invalid` is
|
|
163
|
+
// cleared by the first successful raster) and this fires after about `budget_total`
|
|
164
|
+
// pops, which is what bounds K. During a cold start it degrades to a full drain, i.e.
|
|
165
|
+
// to a heapsort, still ahead of the comparator sort it replaced.
|
|
166
|
+
if (views_spent >= budget_total && invalid_in_heap === 0) {
|
|
167
|
+
had_unfit_candidates = true;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const map = shadowmaps[heap.pop_max()];
|
|
172
|
+
const cost = map.views.length;
|
|
173
|
+
|
|
174
|
+
if (map.is_invalid) {
|
|
175
|
+
invalid_in_heap--;
|
|
176
|
+
map.should_draw = true;
|
|
177
|
+
selected.push(map);
|
|
178
|
+
views_spent += cost;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (views_spent + cost <= budget_total) {
|
|
183
|
+
map.should_draw = true;
|
|
184
|
+
selected.push(map);
|
|
185
|
+
views_spent += cost;
|
|
186
|
+
} else {
|
|
187
|
+
// Wanted to refresh but the pool could not cover its view cost. Keep going — a
|
|
188
|
+
// cheaper candidate further down may still fit.
|
|
189
|
+
had_unfit_candidates = true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.views_spent = views_spent;
|
|
194
|
+
this.had_unfit_candidates = had_unfit_candidates;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The set of shadowmaps a scene currently holds, indexed by the light each one belongs to.
|
|
3
|
+
*
|
|
4
|
+
* Exists to make {@link GPUSceneShadowmapContext.process_lights} cheap. That pass runs every
|
|
5
|
+
* frame for every scene, and its job is to answer two questions per element: "does this light
|
|
6
|
+
* already have a map" (once per light) and "is this map's light still in the scene" (once per
|
|
7
|
+
* map). Answering the first by scanning the map array made the pass O(lights x maps) — 148us per
|
|
8
|
+
* frame at 512 lights, 554us at 1024, against 24us and 57us with the index. See
|
|
9
|
+
* benchmark/reconcile.spec.js.
|
|
10
|
+
*
|
|
11
|
+
* The second question is answered by MARKING rather than by a per-frame `new Set(lights)`. A
|
|
12
|
+
* reconciliation stamps every light's map with the current pass's mark as it walks the light
|
|
13
|
+
* array; anything still carrying an older mark afterwards belongs to a light that has left. That
|
|
14
|
+
* folds the liveness check into the lookup that was happening anyway, so the pass builds no
|
|
15
|
+
* per-frame collection at all.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately GPU-free — it owns array and index bookkeeping and nothing else. Allocating an
|
|
18
|
+
* atlas rect, creating views and cameras, and releasing them again all stay in
|
|
19
|
+
* {@link GPUSceneShadowmapContext}, which is what lets this be measured without a device.
|
|
20
|
+
*
|
|
21
|
+
* Invariant: a light has at most one map. {@link add} asserts it.
|
|
22
|
+
*/
|
|
23
|
+
export class ShadowmapRegistry {
|
|
24
|
+
/**
|
|
25
|
+
* The live map array, in allocation order. Callers iterate this directly — the draw pass, the
|
|
26
|
+
* record writer and the resolution policy all walk it every frame and none of them should pay
|
|
27
|
+
* for a copy.
|
|
28
|
+
*
|
|
29
|
+
* Mutate it only through this class, or the light index silently stops matching it.
|
|
30
|
+
* @returns {Shadowmap[]}
|
|
31
|
+
*/
|
|
32
|
+
get maps(): Shadowmap[];
|
|
33
|
+
/**
|
|
34
|
+
* @returns {number}
|
|
35
|
+
*/
|
|
36
|
+
get size(): number;
|
|
37
|
+
/**
|
|
38
|
+
* @param {Light} light
|
|
39
|
+
* @returns {Shadowmap|undefined}
|
|
40
|
+
*/
|
|
41
|
+
get(light: Light): Shadowmap | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Open a reconciliation pass. Every map that should survive it must be handed to
|
|
44
|
+
* {@link mark_live} before {@link is_marked} is consulted.
|
|
45
|
+
*/
|
|
46
|
+
begin_reconcile(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Look up `light`'s map and, if it has one, mark it as belonging to a light that is still in
|
|
49
|
+
* the scene. The lookup and the liveness marking are the same operation on purpose — that is
|
|
50
|
+
* the whole point of the mark, and splitting them would put the hash probe back.
|
|
51
|
+
*
|
|
52
|
+
* @param {Light} light
|
|
53
|
+
* @returns {Shadowmap|undefined} undefined when the light has no map yet, i.e. it is new
|
|
54
|
+
*/
|
|
55
|
+
mark_live(light: Light): Shadowmap | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* @param {Shadowmap} map
|
|
58
|
+
* @returns {boolean} true when the map was marked during the current reconciliation pass
|
|
59
|
+
*/
|
|
60
|
+
is_marked(map: Shadowmap): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* @param {number} index
|
|
63
|
+
* @returns {Shadowmap}
|
|
64
|
+
*/
|
|
65
|
+
get_at(index: number): Shadowmap;
|
|
66
|
+
/**
|
|
67
|
+
* Take ownership of a newly created map. Marked live immediately — a map created during a
|
|
68
|
+
* reconciliation pass must survive that same pass's reclamation.
|
|
69
|
+
*
|
|
70
|
+
* @param {Shadowmap} map with `light` already assigned
|
|
71
|
+
*/
|
|
72
|
+
add(map: Shadowmap): void;
|
|
73
|
+
/**
|
|
74
|
+
* Drop the map at `index`. The caller is responsible for releasing its GPU-side resources
|
|
75
|
+
* first — this only unhooks it from the array and the index.
|
|
76
|
+
*
|
|
77
|
+
* Order of the remaining maps is preserved, because the per-type shadow ids assigned at the
|
|
78
|
+
* end of reconciliation are positional and the records they point at are re-published only
|
|
79
|
+
* when an id actually moves.
|
|
80
|
+
*
|
|
81
|
+
* @param {number} index
|
|
82
|
+
*/
|
|
83
|
+
remove_at(index: number): void;
|
|
84
|
+
/**
|
|
85
|
+
* Drop every map. Same caveat as {@link remove_at} — GPU-side resources are the caller's to
|
|
86
|
+
* release before calling this.
|
|
87
|
+
*/
|
|
88
|
+
clear(): void;
|
|
89
|
+
#private;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=ShadowmapRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShadowmapRegistry.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/map/ShadowmapRegistry.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAuBI;;;;;;;OAOG;IACH,wBAEC;IAED;;OAEG;IACH,mBAEC;IAED;;;OAGG;IACH,mBAFa,YAAU,SAAS,CAI/B;IAED;;;OAGG;IACH,wBAEC;IAED;;;;;;;OAOG;IACH,yBAFa,YAAU,SAAS,CAU/B;IAED;;;OAGG;IACH,2BAFa,OAAO,CAInB;IAED;;;OAGG;IACH,cAHW,MAAM,aAKhB;IAED;;;;;OAKG;IACH,0BAMC;IAED;;;;;;;;;OASG;IACH,iBAFW,MAAM,QAOhB;IAED;;;OAGG;IACH,cAGC;;CACJ"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The set of shadowmaps a scene currently holds, indexed by the light each one belongs to.
|
|
5
|
+
*
|
|
6
|
+
* Exists to make {@link GPUSceneShadowmapContext.process_lights} cheap. That pass runs every
|
|
7
|
+
* frame for every scene, and its job is to answer two questions per element: "does this light
|
|
8
|
+
* already have a map" (once per light) and "is this map's light still in the scene" (once per
|
|
9
|
+
* map). Answering the first by scanning the map array made the pass O(lights x maps) — 148us per
|
|
10
|
+
* frame at 512 lights, 554us at 1024, against 24us and 57us with the index. See
|
|
11
|
+
* benchmark/reconcile.spec.js.
|
|
12
|
+
*
|
|
13
|
+
* The second question is answered by MARKING rather than by a per-frame `new Set(lights)`. A
|
|
14
|
+
* reconciliation stamps every light's map with the current pass's mark as it walks the light
|
|
15
|
+
* array; anything still carrying an older mark afterwards belongs to a light that has left. That
|
|
16
|
+
* folds the liveness check into the lookup that was happening anyway, so the pass builds no
|
|
17
|
+
* per-frame collection at all.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately GPU-free — it owns array and index bookkeeping and nothing else. Allocating an
|
|
20
|
+
* atlas rect, creating views and cameras, and releasing them again all stay in
|
|
21
|
+
* {@link GPUSceneShadowmapContext}, which is what lets this be measured without a device.
|
|
22
|
+
*
|
|
23
|
+
* Invariant: a light has at most one map. {@link add} asserts it.
|
|
24
|
+
*/
|
|
25
|
+
export class ShadowmapRegistry {
|
|
26
|
+
/**
|
|
27
|
+
* @type {Shadowmap[]}
|
|
28
|
+
*/
|
|
29
|
+
#maps = [];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @type {Map<Light, Shadowmap>}
|
|
33
|
+
*/
|
|
34
|
+
#by_light = new Map();
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Monotonically increasing reconciliation counter. Compared against
|
|
38
|
+
* {@link Shadowmap._reconcile_mark} to tell a map whose light is still in the scene from one
|
|
39
|
+
* whose light has left. Starts at 0 and is pre-incremented by {@link begin_reconcile}, so the
|
|
40
|
+
* first pass marks with 1 and a never-marked map (whose field is 0) reads as stale.
|
|
41
|
+
*
|
|
42
|
+
* Increments once per frame. A double stays exact to 2^53, which at 1000 frames per second is
|
|
43
|
+
* longer than the hardware will last, so there is no wraparound to handle.
|
|
44
|
+
* @type {number}
|
|
45
|
+
*/
|
|
46
|
+
#mark = 0;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The live map array, in allocation order. Callers iterate this directly — the draw pass, the
|
|
50
|
+
* record writer and the resolution policy all walk it every frame and none of them should pay
|
|
51
|
+
* for a copy.
|
|
52
|
+
*
|
|
53
|
+
* Mutate it only through this class, or the light index silently stops matching it.
|
|
54
|
+
* @returns {Shadowmap[]}
|
|
55
|
+
*/
|
|
56
|
+
get maps() {
|
|
57
|
+
return this.#maps;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @returns {number}
|
|
62
|
+
*/
|
|
63
|
+
get size() {
|
|
64
|
+
return this.#maps.length;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Light} light
|
|
69
|
+
* @returns {Shadowmap|undefined}
|
|
70
|
+
*/
|
|
71
|
+
get(light) {
|
|
72
|
+
return this.#by_light.get(light);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Open a reconciliation pass. Every map that should survive it must be handed to
|
|
77
|
+
* {@link mark_live} before {@link is_marked} is consulted.
|
|
78
|
+
*/
|
|
79
|
+
begin_reconcile() {
|
|
80
|
+
this.#mark++;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Look up `light`'s map and, if it has one, mark it as belonging to a light that is still in
|
|
85
|
+
* the scene. The lookup and the liveness marking are the same operation on purpose — that is
|
|
86
|
+
* the whole point of the mark, and splitting them would put the hash probe back.
|
|
87
|
+
*
|
|
88
|
+
* @param {Light} light
|
|
89
|
+
* @returns {Shadowmap|undefined} undefined when the light has no map yet, i.e. it is new
|
|
90
|
+
*/
|
|
91
|
+
mark_live(light) {
|
|
92
|
+
const map = this.#by_light.get(light);
|
|
93
|
+
|
|
94
|
+
if (map !== undefined) {
|
|
95
|
+
map._reconcile_mark = this.#mark;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return map;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @param {Shadowmap} map
|
|
103
|
+
* @returns {boolean} true when the map was marked during the current reconciliation pass
|
|
104
|
+
*/
|
|
105
|
+
is_marked(map) {
|
|
106
|
+
return map._reconcile_mark === this.#mark;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {number} index
|
|
111
|
+
* @returns {Shadowmap}
|
|
112
|
+
*/
|
|
113
|
+
get_at(index) {
|
|
114
|
+
return this.#maps[index];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Take ownership of a newly created map. Marked live immediately — a map created during a
|
|
119
|
+
* reconciliation pass must survive that same pass's reclamation.
|
|
120
|
+
*
|
|
121
|
+
* @param {Shadowmap} map with `light` already assigned
|
|
122
|
+
*/
|
|
123
|
+
add(map) {
|
|
124
|
+
assert.equal(this.#by_light.has(map.light), false, 'light already has a shadowmap');
|
|
125
|
+
|
|
126
|
+
map._reconcile_mark = this.#mark;
|
|
127
|
+
this.#maps.push(map);
|
|
128
|
+
this.#by_light.set(map.light, map);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Drop the map at `index`. The caller is responsible for releasing its GPU-side resources
|
|
133
|
+
* first — this only unhooks it from the array and the index.
|
|
134
|
+
*
|
|
135
|
+
* Order of the remaining maps is preserved, because the per-type shadow ids assigned at the
|
|
136
|
+
* end of reconciliation are positional and the records they point at are re-published only
|
|
137
|
+
* when an id actually moves.
|
|
138
|
+
*
|
|
139
|
+
* @param {number} index
|
|
140
|
+
*/
|
|
141
|
+
remove_at(index) {
|
|
142
|
+
const map = this.#maps[index];
|
|
143
|
+
|
|
144
|
+
this.#by_light.delete(map.light);
|
|
145
|
+
this.#maps.splice(index, 1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Drop every map. Same caveat as {@link remove_at} — GPU-side resources are the caller's to
|
|
150
|
+
* release before calling this.
|
|
151
|
+
*/
|
|
152
|
+
clear() {
|
|
153
|
+
this.#maps.length = 0;
|
|
154
|
+
this.#by_light.clear();
|
|
155
|
+
}
|
|
156
|
+
}
|
package/src/shade/renderer/shadow/map/shader/shader_shadowmap_remap_cube_to_octahedral.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_shadowmap_remap_cube_to_octahedral.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/shadow/map/shader/shader_shadowmap_remap_cube_to_octahedral.js"],"names":[],"mappings":"AAeA;;;;;;;;;;;;GAYG;AACH,0CAFU,YAAY,CAKS;
|
|
1
|
+
{"version":3,"file":"shader_shadowmap_remap_cube_to_octahedral.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/shadow/map/shader/shader_shadowmap_remap_cube_to_octahedral.js"],"names":[],"mappings":"AAeA;;;;;;;;;;;;GAYG;AACH,0CAFU,YAAY,CAKS;AAmL/B,oEAcG;6BA9N0B,sCAAsC;4BAQvC,gCAAgC"}
|
|
@@ -33,8 +33,12 @@ export const POINT_SHADOW_REMAP_SETTINGS = WebGPUStruct.from({
|
|
|
33
33
|
|
|
34
34
|
const resources = new ShaderResourceSetDescriptor();
|
|
35
35
|
|
|
36
|
+
// per-dispatch, 32 bytes, read-only: immediate data rather than a uniform buffer. The tetrahedron
|
|
37
|
+
// variant of this shader cannot follow: its settings carry a face_view_proj array, and the immediate
|
|
38
|
+
// address space excludes arrays.
|
|
39
|
+
resources.setImmediate("settings", POINT_SHADOW_REMAP_SETTINGS);
|
|
40
|
+
|
|
36
41
|
resources.createGroup()
|
|
37
|
-
.addUniform('settings', POINT_SHADOW_REMAP_SETTINGS)
|
|
38
42
|
.addTexture('cube_faces', 'unfilterable-float');
|
|
39
43
|
|
|
40
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_shadow_upscale.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/ray/shader_shadow_upscale.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shader_shadow_upscale.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/ray/shader_shadow_upscale.js"],"names":[],"mappings":"AAqJA,gDASG;4BA5IyB,6BAA6B"}
|
|
@@ -25,8 +25,10 @@ const PUSH_CONSTANTS = WebGPUStruct.from({
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
const resources = new ShaderResourceSetDescriptor();
|
|
28
|
+
|
|
29
|
+
// per-pass, four bytes, read-only: immediate data rather than a uniform buffer
|
|
30
|
+
resources.setImmediate("settings", PUSH_CONSTANTS);
|
|
28
31
|
resources.createGroup()
|
|
29
|
-
.addUniform("settings", PUSH_CONSTANTS)
|
|
30
32
|
.addUniform("camera", CAMERA_UNIFORM_STRUCT)
|
|
31
33
|
.addTexture("tInput", "unfilterable-float")
|
|
32
34
|
.addTexture("tNormals", "uint")
|