@woosh/meep-engine 3.11.3 → 3.13.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.
- package/README.md +14 -18
- package/editor/SelectionVisualizer.js +127 -127
- package/editor/entity_world_bounds.js +27 -27
- package/editor/particles/rebuildParticleEmitter.js +31 -31
- package/editor/process/SymbolicDisplayProcess.js +1 -1
- package/editor/process/symbolic/CameraSymbolicDisplay.js +146 -146
- package/editor/process/symbolic/LightSymbolicDisplay.js +172 -172
- package/editor/prototypeEditorShell.js +156 -156
- package/editor/selection/editor_pick.js +130 -130
- package/editor/selection/screen_rect_frustum.js +119 -119
- package/editor/tools/v2/TransformControls.js +971 -971
- package/package.json +1 -1
- package/src/engine/Engine.d.ts +3 -3
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +726 -726
- package/src/engine/EngineHarness.d.ts +1 -1
- package/src/engine/EngineHarness.js +590 -590
- package/src/engine/ecs/HIERARCHY_REVIEW.md +717 -717
- package/src/engine/ecs/terrain/ecs/BuildLightTexture.d.ts +1 -1
- package/src/engine/ecs/terrain/ecs/BuildLightTexture.js +27 -27
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts +1 -5
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/Terrain.js +790 -790
- package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +129 -129
- package/src/engine/graphics/ecs/camera/camera_find_active.d.ts +1 -1
- package/src/engine/graphics/ecs/camera/camera_find_active.js +28 -28
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +1 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +428 -428
- package/src/engine/graphics/ecs/water/Water.d.ts +1 -1
- package/src/engine/graphics/ecs/water/Water.js +104 -104
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1 -1
- package/src/engine/graphics3/AnimationGraphSystem.d.ts +65 -0
- package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -0
- package/src/engine/graphics3/AnimationGraphSystem.js +329 -0
- package/src/engine/graphics3/AnimationGraphSystem3.d.ts +6 -61
- package/src/engine/graphics3/AnimationGraphSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationGraphSystem3.js +6 -325
- package/src/engine/graphics3/AnimationSystem.d.ts +76 -0
- package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -0
- package/src/engine/graphics3/AnimationSystem.js +352 -0
- package/src/engine/graphics3/AnimationSystem3.d.ts +6 -72
- package/src/engine/graphics3/AnimationSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationSystem3.js +6 -348
- package/src/engine/graphics3/CameraSystem.d.ts +49 -0
- package/src/engine/graphics3/CameraSystem.d.ts.map +1 -0
- package/src/engine/graphics3/CameraSystem.js +170 -0
- package/src/engine/graphics3/CameraSystem3.d.ts +6 -45
- package/src/engine/graphics3/CameraSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/CameraSystem3.js +6 -166
- package/src/engine/graphics3/DebugDrawSystem.d.ts +72 -0
- package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -0
- package/src/engine/graphics3/DebugDrawSystem.js +205 -0
- package/src/engine/graphics3/DebugDrawSystem3.d.ts +6 -68
- package/src/engine/graphics3/DebugDrawSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/DebugDrawSystem3.js +6 -201
- package/src/engine/graphics3/DecalSystem.d.ts +81 -0
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -0
- package/src/engine/graphics3/DecalSystem.js +441 -0
- package/src/engine/graphics3/DecalSystem3.d.ts +6 -77
- package/src/engine/graphics3/DecalSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem3.js +6 -437
- package/src/engine/graphics3/FogOfWarSystem.d.ts +74 -0
- package/src/engine/graphics3/FogOfWarSystem.d.ts.map +1 -0
- package/src/engine/graphics3/FogOfWarSystem.js +265 -0
- package/src/engine/graphics3/FogOfWarSystem3.d.ts +6 -70
- package/src/engine/graphics3/FogOfWarSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/FogOfWarSystem3.js +6 -261
- package/src/engine/graphics3/GraphicsEngine.d.ts +340 -0
- package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -0
- package/src/engine/graphics3/GraphicsEngine.js +790 -0
- package/src/engine/graphics3/GraphicsEngine3.d.ts +6 -336
- package/src/engine/graphics3/GraphicsEngine3.d.ts.map +1 -1
- package/src/engine/graphics3/GraphicsEngine3.js +6 -786
- package/src/engine/graphics3/HighlightSystem.d.ts +82 -0
- package/src/engine/graphics3/HighlightSystem.d.ts.map +1 -0
- package/src/engine/graphics3/HighlightSystem.js +241 -0
- package/src/engine/graphics3/HighlightSystem3.d.ts +6 -78
- package/src/engine/graphics3/HighlightSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/HighlightSystem3.js +6 -237
- package/src/engine/graphics3/LightSystem.d.ts +40 -0
- package/src/engine/graphics3/LightSystem.d.ts.map +1 -0
- package/src/engine/graphics3/LightSystem.js +211 -0
- package/src/engine/graphics3/LightSystem3.d.ts +6 -36
- package/src/engine/graphics3/LightSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/LightSystem3.js +6 -207
- package/src/engine/graphics3/MeshSystem.d.ts +106 -0
- package/src/engine/graphics3/MeshSystem.d.ts.map +1 -0
- package/src/engine/graphics3/MeshSystem.js +647 -0
- package/src/engine/graphics3/MeshSystem3.d.ts +6 -102
- package/src/engine/graphics3/MeshSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/MeshSystem3.js +6 -642
- package/src/engine/graphics3/ParticipatingMedia.d.ts +2 -2
- package/src/engine/graphics3/ParticipatingMedia.js +203 -203
- package/src/engine/graphics3/ParticipatingMediaSystem.d.ts +87 -0
- package/src/engine/graphics3/ParticipatingMediaSystem.d.ts.map +1 -0
- package/src/engine/graphics3/ParticipatingMediaSystem.js +184 -0
- package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts +6 -83
- package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/ParticipatingMediaSystem3.js +6 -180
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts +76 -0
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -0
- package/src/engine/graphics3/ParticleEmitterSystem.js +289 -0
- package/src/engine/graphics3/ParticleEmitterSystem3.d.ts +6 -72
- package/src/engine/graphics3/ParticleEmitterSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/ParticleEmitterSystem3.js +6 -285
- package/src/engine/graphics3/PathDisplaySystem.d.ts +70 -0
- package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -0
- package/src/engine/graphics3/PathDisplaySystem.js +309 -0
- package/src/engine/graphics3/PathDisplaySystem3.d.ts +6 -66
- package/src/engine/graphics3/PathDisplaySystem3.d.ts.map +1 -1
- package/src/engine/graphics3/PathDisplaySystem3.js +6 -305
- package/src/engine/graphics3/Pickable.d.ts +1 -1
- package/src/engine/graphics3/Pickable.js +65 -65
- package/src/engine/graphics3/PickingQuery.d.ts +1 -1
- package/src/engine/graphics3/PickingQuery.js +48 -48
- package/src/engine/graphics3/PickingSystem.d.ts +67 -0
- package/src/engine/graphics3/PickingSystem.d.ts.map +1 -0
- package/src/engine/graphics3/PickingSystem.js +273 -0
- package/src/engine/graphics3/PickingSystem3.d.ts +6 -63
- package/src/engine/graphics3/PickingSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/PickingSystem3.js +6 -269
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts +47 -0
- package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -0
- package/src/engine/graphics3/ShadedGeometrySystem.js +169 -0
- package/src/engine/graphics3/ShadedGeometrySystem3.d.ts +6 -43
- package/src/engine/graphics3/ShadedGeometrySystem3.d.ts.map +1 -1
- package/src/engine/graphics3/ShadedGeometrySystem3.js +6 -165
- package/src/engine/graphics3/TerrainSystem.d.ts +80 -0
- package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -0
- package/src/engine/graphics3/TerrainSystem.js +566 -0
- package/src/engine/graphics3/TerrainSystem3.d.ts +6 -76
- package/src/engine/graphics3/TerrainSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/TerrainSystem3.js +6 -562
- package/src/engine/graphics3/TooltipComponentSystem.d.ts +65 -0
- package/src/engine/graphics3/TooltipComponentSystem.d.ts.map +1 -0
- package/src/engine/graphics3/TooltipComponentSystem.js +328 -0
- package/src/engine/graphics3/TooltipComponentSystem3.d.ts +6 -61
- package/src/engine/graphics3/TooltipComponentSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/TooltipComponentSystem3.js +6 -324
- package/src/engine/graphics3/Trail3DSystem.d.ts +73 -0
- package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -0
- package/src/engine/graphics3/Trail3DSystem.js +221 -0
- package/src/engine/graphics3/Trail3DSystem3.d.ts +6 -69
- package/src/engine/graphics3/Trail3DSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/Trail3DSystem3.js +6 -217
- package/src/engine/graphics3/VolumetricLightMap.d.ts +2 -2
- package/src/engine/graphics3/VolumetricLightMap.js +2 -2
- package/src/engine/graphics3/VolumetricLightMapSystem.d.ts +98 -0
- package/src/engine/graphics3/VolumetricLightMapSystem.d.ts.map +1 -0
- package/src/engine/graphics3/VolumetricLightMapSystem.js +261 -0
- package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts +6 -94
- package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/VolumetricLightMapSystem3.js +10 -261
- package/src/engine/graphics3/WaterSystem.d.ts +59 -0
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -0
- package/src/engine/graphics3/WaterSystem.js +293 -0
- package/src/engine/graphics3/WaterSystem3.d.ts +6 -55
- package/src/engine/graphics3/WaterSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem3.js +6 -289
- package/src/engine/graphics3/animation/AnimationGraphController.d.ts +1 -1
- package/src/engine/graphics3/animation/AnimationGraphController.js +518 -518
- package/src/engine/graphics3/animation/ClipListPlayer.d.ts +1 -1
- package/src/engine/graphics3/animation/ClipListPlayer.js +263 -263
- package/src/engine/graphics3/animation/ClipPlayback.d.ts +2 -2
- package/src/engine/graphics3/animation/ClipPlayback.js +84 -84
- package/src/engine/graphics3/decal/GPUDecalRenderer.js +3 -3
- package/src/engine/graphics3/decal/graph_build_decal_clusters.d.ts.map +1 -1
- package/src/engine/graphics3/decal/graph_build_decal_clusters.js +6 -8
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.d.ts +0 -7
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +1 -1
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.d.ts +0 -4
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +1 -1
- 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/pack_highlight_table.d.ts +2 -2
- package/src/engine/graphics3/highlight/pack_highlight_table.d.ts.map +1 -1
- package/src/engine/graphics3/highlight/pack_highlight_table.js +74 -74
- package/src/engine/graphics3/highlight/shader_highlight_outline.js +150 -150
- package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +1 -1
- package/src/engine/graphics3/pose/query_entity_node_world_pose.js +101 -101
- package/src/engine/graphics3/preview/make_model_thumbnail.d.ts +3 -3
- package/src/engine/graphics3/preview/make_model_thumbnail.d.ts.map +1 -1
- package/src/engine/graphics3/preview/make_model_thumbnail.js +48 -48
- package/src/engine/graphics3/shade_camera_projection_ray.d.ts +1 -1
- package/src/engine/graphics3/shade_camera_projection_ray.js +77 -77
- package/src/engine/graphics3/shade_node_to_entity_composition.d.ts +1 -1
- package/src/engine/graphics3/shade_node_to_entity_composition.js +84 -84
- 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 +750 -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 -2
- 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 -2
- 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 +135 -134
- package/src/shade/playground/skinned_blas_refit/verify_leaf_triangles.js +202 -202
- package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.js +249 -249
- 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/STATIC_GRAPHICS_ENGINE_ASSETS.js +1 -1
- 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/pose/PosePlayback.d.ts +2 -1
- package/src/shade/renderer/animation/pose/PosePlayback.d.ts.map +1 -1
- package/src/shade/renderer/animation/pose/PosePlayback.js +2 -1
- package/src/shade/renderer/animation/shader_animation_apply.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_apply.js +128 -129
- package/src/shade/renderer/animation/shader_animation_pose_resolve.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_pose_resolve.js +176 -177
- package/src/shade/renderer/animation/shader_animation_tick.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_tick.js +4 -2
- 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 +3 -2
- 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 +4 -2
- 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 +24 -10
- 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 +3 -2
- 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 +5 -2
- package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.js +104 -105
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +0 -1
- package/src/shade/renderer/atmosphere/shader_transmittance_lut.js +3 -3
- package/src/shade/renderer/buffer/graph_inspect_gpu_buffer.js +136 -136
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.js +16 -22
- 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 +11 -5
- 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 +43 -42
- package/src/shade/renderer/buffer/util/shader_buffer_intra_copy_regions.d.ts.map +1 -1
- package/src/shade/renderer/buffer/util/shader_buffer_intra_copy_regions.js +83 -84
- 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/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +177 -170
- package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +918 -918
- 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 +5 -2
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +3 -11
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +1 -1
- 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 +6 -4
- 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/lpv/placement/graph_generate_probe_locations.js +367 -367
- 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 +9 -6
- 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 +1115 -1115
- package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +3 -3
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.js +10 -10
- 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 +4 -2
- 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 -83
- 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 +4 -2
- 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 -85
- 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 -192
- 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/cluster/cull/graph_cull_lights.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/cull/graph_cull_lights.js +191 -198
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.d.ts +0 -6
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.js +120 -120
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_hzb.d.ts +0 -4
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_hzb.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/cull/shader_cull_lights_hzb.js +112 -112
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.js +4 -7
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.d.ts +0 -6
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.js +1 -1
- 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 +222 -222
- 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/lightmap/bake/tile/shader_lightmap_tile_composit.js +81 -81
- package/src/shade/renderer/material/GPUMaterialContext.js +380 -380
- package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
- package/src/shade/renderer/object_property/shader_object_property_process.d.ts.map +1 -1
- package/src/shade/renderer/object_property/shader_object_property_process.js +83 -84
- package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.d.ts.map +1 -1
- package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.js +57 -58
- 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 +5 -7
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +27 -13
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_finalize.js +4 -4
- package/src/shade/renderer/particles/shaders/shader_particle_render.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_render.js +190 -183
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +18 -7
- package/src/shade/renderer/particles/sort/shader_particle_sort.d.ts.map +1 -1
- package/src/shade/renderer/particles/sort/shader_particle_sort.js +47 -21
- 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/path_tracer/graph_path_trace_scene.js +184 -184
- 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 +19 -17
- 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 +5 -8
- 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 +4 -2
- 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 +4 -2
- 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 +3 -2
- package/src/shade/renderer/postprocess/nss/shader_nss_conv_layer.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_conv_layer.js +225 -226
- package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.js +49 -50
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +291 -292
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +230 -231
- 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/reproject/shader_ffx_denoiser_reflections_reproject.d.ts +16 -2
- package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/shader_ffx_denoiser_reflections_reproject.js +12 -12
- 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/bucket/shader_count_meshlets_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.js +68 -69
- package/src/shade/renderer/rasterize/bucket/shader_make_meshlet_indirect_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_make_meshlet_indirect_draw_commands_by_material.js +59 -60
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +0 -1
- package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.js +64 -65
- package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.js +168 -169
- package/src/shade/renderer/rasterize/compute/graph_mesh_sphere_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/compute/graph_mesh_sphere_cull.js +160 -161
- 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 +6 -2
- 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 +4 -2
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_classify_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_classify_bucket.js +139 -140
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_count_by_rasterization_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_count_by_rasterization_bucket.js +91 -92
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.js +88 -89
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +90 -91
- 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 +5 -2
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +89 -90
- package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.js +169 -170
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +89 -90
- package/src/shade/renderer/rasterize/expand/mesh/shader_meshes_to_meshlet_counts.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_meshes_to_meshlet_counts.js +61 -62
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +153 -154
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +144 -144
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.js +88 -88
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +722 -722
- package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.js +217 -217
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +179 -179
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +178 -178
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +194 -194
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_opaque_pass_descriptor.js +76 -76
- 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 +5 -3
- 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 +4 -3
- 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 +4 -3
- package/src/shade/renderer/restir/di/shader_restir_di_spatial.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_spatial.js +116 -117
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +3 -7
- package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy_naive.js +123 -123
- package/src/shade/renderer/scene/hierarchy/shader_nodes_record_input_positions.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/shader_nodes_record_input_positions.js +64 -65
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy.js +372 -373
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy_naive.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/shader_nodes_update_transform_hierarchy_naive.js +111 -112
- 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 -145
- package/src/shade/renderer/shader/ComputeShader.d.ts +26 -5
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +347 -296
- package/src/shade/renderer/shader/ImageShader.js +217 -217
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts +5 -0
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/ShaderDescriptor.js +20 -0
- 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/shader/util/compute_infer_workgroup_size_from_source.d.ts +47 -0
- package/src/shade/renderer/shader/util/compute_infer_workgroup_size_from_source.d.ts.map +1 -0
- package/src/shade/renderer/shader/util/compute_infer_workgroup_size_from_source.js +448 -0
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +14 -18
- package/src/shade/renderer/shadow/map/csm/graph_csm_setup_cascades.js +3 -3
- 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 +6 -4
- 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 +11 -12
- 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 +3 -2
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +14 -19
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts +3 -2
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +3 -2
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts +0 -2
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +17 -6
- package/src/shade/renderer/water/shader_water.js +246 -246
- package/src/shade/vitest.setup.mjs +1 -1
- package/src/shade/wgsl/emulator/ComputeShaderEmulator.js +291 -291
- package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
- package/src/shade/wgsl/validate_wgsl_source.js +8 -3
- package/src/view/minimap/Minimap.d.ts +2 -2
- package/src/view/minimap/Minimap.d.ts.map +1 -1
- package/src/view/minimap/Minimap.js +225 -225
- package/src/view/minimap/dom/MinimapCameraView.d.ts +3 -3
- package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
- package/src/view/minimap/dom/MinimapCameraView.js +206 -206
- 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
- package/src/shade/renderer/shadow/map/csm/shader/shader_setup_cascades.d.ts +0 -3
- package/src/shade/renderer/shadow/map/csm/shader/shader_setup_cascades.d.ts.map +0 -1
- package/src/shade/renderer/shadow/map/csm/shader/shader_setup_cascades.js +0 -20
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
# Pass encoder decorators, and the end of the debug-timer path
|
|
2
|
+
|
|
3
|
+
**Status:** implemented — revision 3
|
|
4
|
+
**Date:** 2026-08-31
|
|
5
|
+
**Scope:** `src/shade/device/ShadeGPUCommandContext.js`, `src/shade/device/timing/`, `src/shade/descriptor/pipeline/compute/`, `src/shade/renderer/Renderer.js`
|
|
6
|
+
**Supersedes:** [GPU_PROFILER_PROPOSAL_2026_08_28.md](timing/GPU_PROFILER_PROPOSAL_2026_08_28.md) §6.1 (last paragraph) and §6.2 hook 3
|
|
7
|
+
|
|
8
|
+
> **Revision 2** carried the workgroup size rather than re-parsing it (§3.5), dropped the pretence
|
|
9
|
+
> of WebGPU overload compatibility (§3.2), removed the scratch-object side channel revision 1
|
|
10
|
+
> introduced (§3.4), and added an adversarial pass (§8) that changed four decisions.
|
|
11
|
+
>
|
|
12
|
+
> **Revision 3** records what shipped. The §9 decisions were taken (§9), the error-carrying
|
|
13
|
+
> `workgroup_size_error` of revision 2 was rejected in favour of throwing at construction (§3.5),
|
|
14
|
+
> and the code landed in three commits (§10).
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. What is there now
|
|
19
|
+
|
|
20
|
+
Profiling reaches a GPU pass through four private members of `ShadeGPUCommandContext` and one `Proxy`.
|
|
21
|
+
|
|
22
|
+
| Piece | Where | What it does |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `#with_timestamp_writes(descriptor, kind)` | [ShadeGPUCommandContext.js:461](ShadeGPUCommandContext.js:461) | Branches on the string `'compute'`/`'render'`, asks `GPUTimerArray` for a slot, shallow-copies the descriptor to add `timestampWrites`, and **as a side effect** writes `#pending_work`. |
|
|
25
|
+
| `#pending_work` | [:128](ShadeGPUCommandContext.js:128) | A one-slot channel between `#with_timestamp_writes` and `#instrument_pass`. |
|
|
26
|
+
| `#instrument_pass(encoder)` | [:136](ShadeGPUCommandContext.js:136) | Reads `#pending_work`, clears it, writes `#last_work`, and returns either the raw encoder or a `Proxy`. |
|
|
27
|
+
| `#last_work` | [:577](ShadeGPUCommandContext.js:577) | A second one-slot channel, this time between `begin*Pass` and `#note_pipeline`. |
|
|
28
|
+
| `make_profiling_pass_encoder` | [timing/profile/make_profiling_pass_encoder.js](timing/profile/make_profiling_pass_encoder.js) | A `Proxy` whose `get` trap switches on the method **name as a string**, wraps six of them, memoises bound closures in a `Map`, and forwards the rest by `Reflect`. |
|
|
29
|
+
| `parse_workgroup_size` | [timing/profile/parse_workgroup_size.js](timing/profile/parse_workgroup_size.js) | Re-parses WGSL per pass to recover `@workgroup_size`. Already marked `@deprecated`: it duplicates `compute_infer_workgroup_size_from_source`, badly. |
|
|
30
|
+
|
|
31
|
+
So `beginComputePass` reads:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
const _descriptor = this.#with_timestamp_writes(descriptor, 'compute');
|
|
35
|
+
|
|
36
|
+
return this.#instrument_pass(encoder.beginComputePass(_descriptor))
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Two calls, neither of which names what it produced, coupled through two private fields that neither
|
|
40
|
+
signature mentions.
|
|
41
|
+
|
|
42
|
+
Alongside it, a second entry point into the same machinery:
|
|
43
|
+
|
|
44
|
+
| Piece | Where | What it does |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `enable_debug_timers(cb)` | [:93](ShadeGPUCommandContext.js:93) | Allocates the `GPUTimerArray`, and at `finish()` hands `results_to_console_table()` to a callback. |
|
|
47
|
+
| `Renderer.add_debug_frame(n)` / `Renderer.onFrameDebug` | [Renderer.js:671](../renderer/Renderer.js:671), [:431](../renderer/Renderer.js:431) | Arms N frames, fires the table. |
|
|
48
|
+
|
|
49
|
+
## 2. What is wrong with it
|
|
50
|
+
|
|
51
|
+
**The two hidden channels.** `#pending_work` and `#last_work` are the whole objection. Neither
|
|
52
|
+
appears in a signature. `#with_timestamp_writes` is a *getter-shaped* method that mutates; the only
|
|
53
|
+
thing keeping it correct is that the very next statement consumes what it left behind. Insert a line
|
|
54
|
+
between them, reach `beginComputePass` from inside its call tree, or throw part way, and the next
|
|
55
|
+
pass silently inherits the previous pass's work record. Nothing would catch it.
|
|
56
|
+
|
|
57
|
+
**`kind` as a string.** `#with_timestamp_writes(descriptor, 'compute')` re-derives, by string
|
|
58
|
+
comparison, a fact the call site already knew statically — it is *literally inside*
|
|
59
|
+
`beginComputePass`.
|
|
60
|
+
|
|
61
|
+
**Reflection where a method call belongs.** `make_profiling_pass_encoder` switches on
|
|
62
|
+
`'dispatchWorkgroups'`, `'draw'`, `'drawIndexed'` as strings, in a `Proxy` `get` trap, on the hot
|
|
63
|
+
encoding path. `work.dispatch_count++` is three characters of real logic wrapped in a dispatch
|
|
64
|
+
mechanism.
|
|
65
|
+
|
|
66
|
+
**The Proxy's own justification does not survive contact with the fix.** The file argues a
|
|
67
|
+
hand-written forwarder is dangerous because a missed method "does not fail loudly, it silently drops
|
|
68
|
+
a call … and only while profiling". That is true *only because the wrapper is conditional*. Make the
|
|
69
|
+
decorator the one and only pass type Shade hands out, and the failure mode inverts: a missing method
|
|
70
|
+
is `pass.setScissorRect is not a function`, on the first frame, in every build, profiling or not. The
|
|
71
|
+
argument for the Proxy is an argument against *conditional* wrapping, not against hand-writing the
|
|
72
|
+
forwarder.
|
|
73
|
+
|
|
74
|
+
**Three silent returns.** `#with_timestamp_writes` returns the descriptor unchanged for three
|
|
75
|
+
different reasons (timers off, device lacks `timestamp-query`, array full) and the caller cannot tell
|
|
76
|
+
which — nor that the pass ended up untimed.
|
|
77
|
+
|
|
78
|
+
**A second, worse WGSL parser, run per pass.** `parse_workgroup_size` reads a bare decimal literal
|
|
79
|
+
and returns `[0,0,0]` for anything else — while `compute_infer_workgroup_size_from_source`, twenty
|
|
80
|
+
metres away, resolves `const` references, strips comments, handles hex and `i`/`u` suffixes, and
|
|
81
|
+
throws with a specific message when it genuinely cannot tell. `ComputeShader` already calls the good
|
|
82
|
+
one **once, at construction**, and keeps the answer. The profiler re-derives a worse answer at encode
|
|
83
|
+
time, for a value that has not changed since the pipeline was created.
|
|
84
|
+
|
|
85
|
+
**`enable_debug_timers` is a redundant second face.** It shares the `GPUTimerArray` with
|
|
86
|
+
`enable_profiling`, either may allocate it, and `finish()` runs both drains. It produces a
|
|
87
|
+
slot-shaped console table with no graph-pass attribution, no workload, no pipeline identity — a
|
|
88
|
+
strictly worse view than the profiler's, reached through a separate API. Its consumers:
|
|
89
|
+
|
|
90
|
+
- `Renderer.add_debug_frame` / `Renderer.onFrameDebug` — **zero subscribers anywhere in the tree**
|
|
91
|
+
(grep across all packages; the 2026-08-28 proposal noted the same and left them in).
|
|
92
|
+
- [verify_gpu_bvh_build.js:316](../renderer/gpu_primitive/bvh/verify_gpu_bvh_build.js:316) — one
|
|
93
|
+
developer verification tool that wants a console table.
|
|
94
|
+
|
|
95
|
+
That is the entire public surface. It is the cheapest moment this will ever be to remove it.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 3. Proposed design
|
|
100
|
+
|
|
101
|
+
### 3.1 `ShadeGPUComputePassEncoder` / `ShadeGPURenderPassEncoder`
|
|
102
|
+
|
|
103
|
+
Two concrete decorator classes, in `src/shade/device/pass/`. **Every** pass Shade opens is one of
|
|
104
|
+
these; there is no unwrapped path and no conditional wrapping. They hold a nullable
|
|
105
|
+
`GPUProfileWork` and tally into it.
|
|
106
|
+
|
|
107
|
+
They import **nothing** from `timing/profile/`. `work` is a bag of counters, `null` is the ordinary
|
|
108
|
+
case, and the classes do not know what a capture is — which preserves (in fact improves) the
|
|
109
|
+
tree-shaking property `GPUProfileSession`'s header promises.
|
|
110
|
+
|
|
111
|
+
### 3.2 Forward exactly the arity you received
|
|
112
|
+
|
|
113
|
+
These are not a compatibility shim. Following WebGPU's method names removes friction for anyone who
|
|
114
|
+
already knows the API; it is not a promise of substitutability.
|
|
115
|
+
|
|
116
|
+
**The rule, learnt the hard way (§8.9): a forwarder passes exactly the arity it was given, and never
|
|
117
|
+
reasons about what a binding layer will do with a trailing `undefined`.** Three shapes satisfy it,
|
|
118
|
+
and every method in both classes uses one of them:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
// 1. Only forwards, and has trailing optionals → rest arguments. Arity is preserved by
|
|
122
|
+
// construction, which is the property that matters and the one a reader should not have to
|
|
123
|
+
// verify branch by branch. `size` here means "the rest of the buffer" and has no default to
|
|
124
|
+
// stand in for at all, so an absent argument and an `undefined` one are different requests.
|
|
125
|
+
setVertexBuffer(...args) {
|
|
126
|
+
this.#pass.setVertexBuffer(...args);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 2. One trailing optional → branch on it. Cheap, and it also means this form can never select
|
|
130
|
+
// the five-argument overload by accident, which is what makes `setBindGroupRange` an honest
|
|
131
|
+
// name rather than only a convention.
|
|
132
|
+
setBindGroup(index, bind_group, dynamic_offsets) {
|
|
133
|
+
if (dynamic_offsets === undefined) {
|
|
134
|
+
this.#pass.setBindGroup(index, bind_group);
|
|
135
|
+
} else {
|
|
136
|
+
this.#pass.setBindGroup(index, bind_group, dynamic_offsets);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 3. Has to read its arguments in order to count them → named parameters, with WebGPU's own
|
|
141
|
+
// defaults spelled out. Those defaults are 1 and 0, so materialising them passes four defined
|
|
142
|
+
// values rather than a trailing `undefined`, and is equivalent to omitting them.
|
|
143
|
+
draw(vertex_count, instance_count = 1, first_vertex = 0, first_instance = 0) { /* ... */ }
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Where WebGPU resolves an overload by arity, Shade gives each form its own name: `setBindGroup` for
|
|
147
|
+
the `sequence` form and `setBindGroupRange` for the `Uint32Array`-slice form. Nothing in the
|
|
148
|
+
renderer uses the slice form today; it exists because `SoftwareGPUComputePassEncoder` models it.
|
|
149
|
+
|
|
150
|
+
> Revision 2 got this exactly half right. It identified `setBindGroup` as the one forward that could
|
|
151
|
+
> be *wrong* rather than merely incomplete, then guarded the wrong end of it — see §8.9.
|
|
152
|
+
|
|
153
|
+
### 3.3 The compute decorator in full
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
export class ShadeGPUComputePassEncoder {
|
|
157
|
+
|
|
158
|
+
/** @type {GPUComputePassEncoder} */
|
|
159
|
+
#pass;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Where this pass's encoded work is tallied, or null when nothing is profiling.
|
|
163
|
+
* @type {GPUProfileWork|null}
|
|
164
|
+
*/
|
|
165
|
+
#work;
|
|
166
|
+
|
|
167
|
+
#ended = false;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @param {GPUComputePassEncoder} pass
|
|
171
|
+
* @param {GPUProfileWork|null} work
|
|
172
|
+
*/
|
|
173
|
+
constructor(pass, work) {
|
|
174
|
+
assert.defined(pass, 'pass');
|
|
175
|
+
|
|
176
|
+
this.#pass = pass;
|
|
177
|
+
this.#work = work;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** @returns {string} */
|
|
181
|
+
get label() { return this.#pass.label; }
|
|
182
|
+
|
|
183
|
+
/** @param {string} value */
|
|
184
|
+
set label(value) { this.#pass.label = value; }
|
|
185
|
+
|
|
186
|
+
// --- GPUComputePassEncoder ------------------------------------------------
|
|
187
|
+
|
|
188
|
+
setPipeline(pipeline) {
|
|
189
|
+
this.#pass.setPipeline(pipeline);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
dispatchWorkgroups(x, y = 1, z = 1) {
|
|
193
|
+
const work = this.#work;
|
|
194
|
+
|
|
195
|
+
if (work !== null) {
|
|
196
|
+
work.dispatch_count++;
|
|
197
|
+
work.workgroups[0] += x;
|
|
198
|
+
work.workgroups[1] += y;
|
|
199
|
+
work.workgroups[2] += z;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this.#pass.dispatchWorkgroups(x, y, z);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
dispatchWorkgroupsIndirect(indirect_buffer, indirect_offset) {
|
|
206
|
+
const work = this.#work;
|
|
207
|
+
|
|
208
|
+
if (work !== null) {
|
|
209
|
+
// Size lives in a GPU buffer, so there is nothing to add to `workgroups`. Counted
|
|
210
|
+
// apart so the totals are not read as covering this.
|
|
211
|
+
work.indirect_dispatch_count++;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.#pass.dispatchWorkgroupsIndirect(indirect_buffer, indirect_offset);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
end() {
|
|
218
|
+
assert.notOk(this.#ended, 'pass already ended');
|
|
219
|
+
|
|
220
|
+
this.#ended = true;
|
|
221
|
+
|
|
222
|
+
this.#pass.end();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// --- GPUBindingCommandsMixin ----------------------------------------------
|
|
226
|
+
|
|
227
|
+
setBindGroup(index, bind_group, dynamic_offsets) { /* §3.2 */ }
|
|
228
|
+
|
|
229
|
+
setBindGroupRange(index, bind_group, data, data_start, data_length) { /* §3.2 */ }
|
|
230
|
+
|
|
231
|
+
setImmediates(range_offset, data, data_offset, data_size) {
|
|
232
|
+
this.#pass.setImmediates(range_offset, data, data_offset, data_size);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// --- GPUDebugCommandsMixin ------------------------------------------------
|
|
236
|
+
|
|
237
|
+
pushDebugGroup(label) { this.#pass.pushDebugGroup(label); }
|
|
238
|
+
|
|
239
|
+
popDebugGroup() { this.#pass.popDebugGroup(); }
|
|
240
|
+
|
|
241
|
+
insertDebugMarker(label) { this.#pass.insertDebugMarker(label); }
|
|
242
|
+
|
|
243
|
+
// --- Shade ----------------------------------------------------------------
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Record which pipeline descriptor this pass ran.
|
|
247
|
+
*
|
|
248
|
+
* Separate from `setPipeline` because `setPipeline` receives the compiled
|
|
249
|
+
* {@link GPUComputePipeline}, and neither the label the descriptor was given nor its workgroup
|
|
250
|
+
* size is on it. Only `constructComputePass` holds the descriptor, so a pass begun the long way
|
|
251
|
+
* records its counts but not what ran them — which the model represents as an unknown rather
|
|
252
|
+
* than a zero.
|
|
253
|
+
*
|
|
254
|
+
* @param {ComputePipelineDescriptor} descriptor
|
|
255
|
+
* @returns {void}
|
|
256
|
+
*/
|
|
257
|
+
record_pipeline(descriptor) {
|
|
258
|
+
const work = this.#work;
|
|
259
|
+
|
|
260
|
+
if (work === null) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
work.pipeline = descriptor.label ?? "";
|
|
265
|
+
work.workgroup_size = descriptor.workgroup_size;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`ShadeGPURenderPassEncoder` is the mirror image over the render surface: `setViewport`,
|
|
271
|
+
`setScissorRect`, `setBlendConstant`, `setStencilReference`, `setIndexBuffer`, `setVertexBuffer`,
|
|
272
|
+
`beginOcclusionQuery`, `endOcclusionQuery`, `executeBundles`, `draw`, `drawIndexed`, `drawIndirect`,
|
|
273
|
+
`drawIndexedIndirect`, plus the same two mixins, `end` and `record_pipeline`. Only the four `draw*`
|
|
274
|
+
methods carry a tally; the rest forward.
|
|
275
|
+
|
|
276
|
+
**Only six methods branch** — four `draw*` and two `dispatch*`. Everything else is a one-line
|
|
277
|
+
forward. Both classes come to roughly 130 lines and read top to bottom as a complete statement of the
|
|
278
|
+
interface they decorate, which is the entire point.
|
|
279
|
+
|
|
280
|
+
> **Known blind spot, inherited:** draws inside a `GPURenderBundle` passed to `executeBundles` are
|
|
281
|
+
> not counted — the bundle was encoded elsewhere. The Proxy had the same gap and nothing in Shade
|
|
282
|
+
> uses bundles today. It belongs in `GPUProfileWork`'s documentation rather than being left implicit.
|
|
283
|
+
|
|
284
|
+
### 3.4 The context's profiling state, in one object
|
|
285
|
+
|
|
286
|
+
`ShadeGPUCommandContext` currently carries six fields for a feature that is off by default:
|
|
287
|
+
`#debug_timers`, `#debug_timers_callback`, `#profile_recorder`, `#profile_query_set_id`,
|
|
288
|
+
`#pending_work`, `#last_work`, plus `#profiling_absorbed` and its resolver. Collapse them into one
|
|
289
|
+
nullable `#profiler`.
|
|
290
|
+
|
|
291
|
+
The profiler **opens the pass itself**. Two values are needed at two different instants —
|
|
292
|
+
`timestampWrites` before the encoder exists, the `GPUProfileWork` after — and any design that returns
|
|
293
|
+
them to the caller has to carry them across that gap somehow. Handing the profiler the encoder
|
|
294
|
+
collapses the gap: both values are produced and consumed inside one method, and there is nothing to
|
|
295
|
+
carry. (Revision 1 returned a reused `{writes, work}` struct, which was `#pending_work` again in
|
|
296
|
+
better clothes. See §8.3.)
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
/**
|
|
300
|
+
* Everything one command context needs in order to be profiled: its timer array, the recorder the
|
|
301
|
+
* timings go to, and which query set it is within the frame.
|
|
302
|
+
*/
|
|
303
|
+
export class ShadeGPUContextProfiler {
|
|
304
|
+
|
|
305
|
+
#timers;
|
|
306
|
+
#recorder;
|
|
307
|
+
#query_set_id;
|
|
308
|
+
|
|
309
|
+
#absorbed;
|
|
310
|
+
#absorbed_resolve;
|
|
311
|
+
|
|
312
|
+
constructor(device, recorder, query_set_id) {
|
|
313
|
+
this.#timers = new GPUTimerArray(device);
|
|
314
|
+
this.#recorder = recorder;
|
|
315
|
+
this.#query_set_id = query_set_id;
|
|
316
|
+
|
|
317
|
+
this.#absorbed = new Promise(resolve => { this.#absorbed_resolve = resolve; });
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
get absorbed() { return this.#absorbed; }
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @param {GPUCommandEncoder} encoder
|
|
324
|
+
* @param {GPUComputePassDescriptor} [descriptor]
|
|
325
|
+
* @returns {ShadeGPUComputePassEncoder}
|
|
326
|
+
*/
|
|
327
|
+
begin_compute_pass(encoder, descriptor) {
|
|
328
|
+
const writes = this.#timers.getComputeWrites(descriptor?.label);
|
|
329
|
+
|
|
330
|
+
if (writes === undefined) {
|
|
331
|
+
/*
|
|
332
|
+
No slot left, or the device withheld `timestamp-query`. An untimed pass is the correct
|
|
333
|
+
degradation in both; a pass carrying query indices the set does not have is a
|
|
334
|
+
validation error blamed on a pass that did nothing wrong.
|
|
335
|
+
*/
|
|
336
|
+
return new ShadeGPUComputePassEncoder(encoder.beginComputePass(descriptor), null);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/*
|
|
340
|
+
Copied, never written through. Several call sites reuse one descriptor across passes, and
|
|
341
|
+
stamping `timestampWrites` onto it left the next pass carrying the previous pass's query
|
|
342
|
+
indices. `{...undefined}` is `{}`, which is also how the no-descriptor form stays legal.
|
|
343
|
+
*/
|
|
344
|
+
const gpu_pass = encoder.beginComputePass({ ...descriptor, timestampWrites: writes });
|
|
345
|
+
|
|
346
|
+
return new ShadeGPUComputePassEncoder(gpu_pass, this.#note_slot(writes));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** The render mirror of {@link begin_compute_pass}. */
|
|
350
|
+
begin_render_pass(encoder, descriptor) { /* getRenderWrites, ShadeGPURenderPassEncoder */ }
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* @param {GPUComputePassTimestampWrites|GPURenderPassTimestampWrites} writes
|
|
354
|
+
* @returns {GPUProfileWork|null}
|
|
355
|
+
*/
|
|
356
|
+
#note_slot(writes) {
|
|
357
|
+
/*
|
|
358
|
+
The one moment the join can be made. The recorder knows which frame graph pass is
|
|
359
|
+
executing right now; the slot is what the timings will come back keyed by. Neither fact is
|
|
360
|
+
recoverable later — see GPUFrameRecorder.
|
|
361
|
+
*/
|
|
362
|
+
return this.#recorder.note_pass_slot(
|
|
363
|
+
this.#query_set_id,
|
|
364
|
+
writes.beginningOfPassWriteIndex / 2
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** @param {GPUCommandEncoder} encoder */
|
|
369
|
+
resolve(encoder) { this.#timers.resolve(encoder); }
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Read the timings back and hand them to the recorder. Resolves {@link absorbed} either way.
|
|
373
|
+
* @returns {void}
|
|
374
|
+
*/
|
|
375
|
+
absorb() {
|
|
376
|
+
const timers = this.#timers;
|
|
377
|
+
|
|
378
|
+
timers.download_results()
|
|
379
|
+
.then(() => { this.#recorder.absorb(timers, this.#query_set_id); })
|
|
380
|
+
.finally(() => {
|
|
381
|
+
timers.destroy();
|
|
382
|
+
|
|
383
|
+
// In `finally` so a failed readback still releases whoever is waiting on the frame.
|
|
384
|
+
// A profile session that hangs because one download rejected is worse than one
|
|
385
|
+
// missing a frame.
|
|
386
|
+
this.#absorbed_resolve();
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
`beginComputePass` on the context becomes five lines with two named outcomes:
|
|
393
|
+
|
|
394
|
+
```js
|
|
395
|
+
/**
|
|
396
|
+
* @param {GPUComputePassDescriptor} [descriptor]
|
|
397
|
+
* @returns {ShadeGPUComputePassEncoder}
|
|
398
|
+
*/
|
|
399
|
+
beginComputePass(descriptor) {
|
|
400
|
+
const profiler = this.#profiler;
|
|
401
|
+
|
|
402
|
+
if (profiler === null) {
|
|
403
|
+
return new ShadeGPUComputePassEncoder(this.#gpu_encoder.beginComputePass(descriptor), null);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return profiler.begin_compute_pass(this.#gpu_encoder, descriptor);
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
No `kind` string. No hidden field. `beginRenderPass` is the same five lines.
|
|
411
|
+
|
|
412
|
+
`constructComputePass` loses `#note_pipeline` and `#last_work` entirely:
|
|
413
|
+
|
|
414
|
+
```js
|
|
415
|
+
const pass = this.beginComputePass(pass_descriptor);
|
|
416
|
+
|
|
417
|
+
pass.setPipeline(gpu_pipeline);
|
|
418
|
+
pass.record_pipeline(pipeline);
|
|
419
|
+
|
|
420
|
+
graphics.setPipelineBindings(pass, pipeline, bindings, immediate);
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### 3.5 The workgroup size is carried, not re-parsed
|
|
424
|
+
|
|
425
|
+
`ComputePipelineDescriptor` reads `@workgroup_size` out of its code **as the code is set**, in
|
|
426
|
+
`from`, `simplified` and `fromJSON`, and becomes the single owner of the answer:
|
|
427
|
+
|
|
428
|
+
```js
|
|
429
|
+
/**
|
|
430
|
+
* `[x, y, z]` of this pipeline's `@workgroup_size`.
|
|
431
|
+
*
|
|
432
|
+
* Read once, when the code is set, and kept — the source cannot change under a descriptor without
|
|
433
|
+
* going back through one of the factories, each of which reads it again.
|
|
434
|
+
*
|
|
435
|
+
* Frozen, because it is handed out by reference to per-pass profile records and a descriptor that
|
|
436
|
+
* outlives a whole capture must not be mutable through one of them.
|
|
437
|
+
*
|
|
438
|
+
* Takes no part in `equals`/`hash`: it is derived from `compute.module`, which both already cover,
|
|
439
|
+
* and a cache key computed two ways is a cache that can disagree with itself.
|
|
440
|
+
*
|
|
441
|
+
* @returns {readonly number[]}
|
|
442
|
+
*/
|
|
443
|
+
get workgroup_size()
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Backed by `compute_infer_workgroup_size_from_source`. **Source it cannot read throws, at
|
|
447
|
+
construction.** Revision 2 proposed a `workgroup_size_error` companion so the descriptor could
|
|
448
|
+
report rather than throw, on the grounds that a capture must not take a frame down. That was
|
|
449
|
+
rejected, and rightly:
|
|
450
|
+
|
|
451
|
+
> The user can't construct a ComputeShader because their source is messed up — that's preferred to
|
|
452
|
+
> them constructing an invalid shader that we then have to recognize and deal with.
|
|
453
|
+
|
|
454
|
+
Every consumer of this number divides a thread count by it. A descriptor that cannot state its own
|
|
455
|
+
workgroup size is one nobody downstream can use correctly, so `[0, 0, 0]` would only defer the
|
|
456
|
+
failure to somewhere with less context to explain it. The only `[0, 0, 0]` left is a bare
|
|
457
|
+
`new ComputePipelineDescriptor()` that has no code yet — not a fallback, a state `new` alone
|
|
458
|
+
produces.
|
|
459
|
+
|
|
460
|
+
`ComputeShader` reads the descriptor instead of parsing separately. Its message keeps the shader's
|
|
461
|
+
label because the pipeline is given the same one, so nothing is wrapped and nothing is lost.
|
|
462
|
+
|
|
463
|
+
This is strictly better than what either side did before:
|
|
464
|
+
|
|
465
|
+
- **One parse**, at pipeline-descriptor construction, by the parser that actually handles WGSL.
|
|
466
|
+
- The nine `ComputePipelineDescriptor` sites that do **not** go through `ComputeShader` — VSM
|
|
467
|
+
residence, tile allocation, coarse bounds, probe dering, indirect command build ×2, irradiance
|
|
468
|
+
lookup, debug reprojection, virtual shadow residence — get correct workgroup sizes in profiles
|
|
469
|
+
for the first time. `parse_workgroup_size` returned `[0,0,0]` for any of them stating the size
|
|
470
|
+
through a `const`.
|
|
471
|
+
- `parse_workgroup_size.js` is deleted, resolving the `@deprecated` note already on it.
|
|
472
|
+
- `timing/profile/` loses its last unconditionally-linked module, so the whole profiler directory
|
|
473
|
+
is now unreachable from any engine entry point — which is what `GPUProfileSession`'s header
|
|
474
|
+
claims and, before this, was not quite true.
|
|
475
|
+
|
|
476
|
+
**`fromJSON` re-reads it.** `ComputePipelineDescriptor.fromJSON` replaces `compute` in place, so a
|
|
477
|
+
size read for whatever was there before would be the wrong shader's — and wrong here means a wrong
|
|
478
|
+
*divisor*. Covered by a spec.
|
|
479
|
+
|
|
480
|
+
Verified before landing that eager reading breaks nothing: every compute pipeline reachable in the
|
|
481
|
+
tree parses. Two modules would not, and both are unreferenced — `GPUVirtualShadowTextureResidence`
|
|
482
|
+
(which already throws on import today, for an unrelated missing default export) and
|
|
483
|
+
`graph_pass_debug_reprojection`.
|
|
484
|
+
|
|
485
|
+
### 3.6 A check the device already does, dropped
|
|
486
|
+
|
|
487
|
+
`#with_timestamp_writes` guards on `this.#graphics.device.features.has('timestamp-query')`. This is
|
|
488
|
+
redundant: `GPUTimerArray`'s constructor returns early without the feature, leaving `#query_set`
|
|
489
|
+
undefined, and `#get_writes` already returns `undefined` in that case
|
|
490
|
+
([GPUTimerArray.js:97](timing/GPUTimerArray.js:97)). One fewer place that has to know the feature
|
|
491
|
+
exists.
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## 4. Removing the debug-timer path
|
|
496
|
+
|
|
497
|
+
| File | Change |
|
|
498
|
+
|---|---|
|
|
499
|
+
| `ShadeGPUCommandContext.js` | Delete `enable_debug_timers` (:93), `#debug_timers_callback` (:87), and the `results_to_console_table` branch in `finish()` (:975). The `noop` import becomes unused — its only two uses are `#debug_timers_callback` and `#profiling_absorbed_resolve`, and both leave. |
|
|
500
|
+
| `renderer/Renderer.js` | Delete `onFrameDebug` (:431), `#debug_frame_count` (:606), `add_debug_frame` (:671), and the arming block (:1736–1744). **Zero subscribers repo-wide.** |
|
|
501
|
+
| `renderer/gpu_primitive/bvh/verify_gpu_bvh_build.js` | Move onto the profiler (below). |
|
|
502
|
+
| `RENDERER_CONTRACT.md:544` | Drop `add_debug_frame(n)` from the surface table. |
|
|
503
|
+
| `timing/GPU_PROFILER_PROPOSAL_2026_08_28.md` | §6.1 last ¶, §6.2 hook 3, and table rows 57/59/60 describe things that no longer exist. |
|
|
504
|
+
| `gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md:235`, `PHASE1_HANDOVER.md:148` | Same. |
|
|
505
|
+
|
|
506
|
+
The replacement for the one real consumer is *better* than what it replaces — it gains dispatch and
|
|
507
|
+
invocation counts, which is what a BVH build verification actually wants:
|
|
508
|
+
|
|
509
|
+
```js
|
|
510
|
+
let recorder = null;
|
|
511
|
+
|
|
512
|
+
if (test_case.count >= 100000) {
|
|
513
|
+
recorder = new GPUFrameRecorder(0, performance.now());
|
|
514
|
+
recorder.enable_work_capture();
|
|
515
|
+
|
|
516
|
+
cmd.enable_profiling(recorder, 0);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// ... build the graph ...
|
|
520
|
+
|
|
521
|
+
if (recorder !== null) {
|
|
522
|
+
recorder.attach_graph(graph);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
cmd.encodeGraph(graph);
|
|
526
|
+
cmd.finish();
|
|
527
|
+
|
|
528
|
+
if (recorder !== null) {
|
|
529
|
+
const captured = recorder;
|
|
530
|
+
|
|
531
|
+
cmd.profiling_absorbed.then(() => {
|
|
532
|
+
const frame = captured.close(performance.now());
|
|
533
|
+
|
|
534
|
+
console.log(`[BVH] GPU timings — ${test_case.name}`);
|
|
535
|
+
console.table(frame.spans.map(span => ({
|
|
536
|
+
label: span.label,
|
|
537
|
+
duration_ms: span.duration_ns * 1e-6,
|
|
538
|
+
dispatches: span.work?.dispatch_count ?? 0,
|
|
539
|
+
invocations: span.work?.invocation_count ?? 0
|
|
540
|
+
})));
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
"Profile the next N frames" — what `add_debug_frame` was for — is already
|
|
546
|
+
`new GPUProfileSession({ frame_limit: N })`.
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## 5. One migration hazard, worth stating plainly
|
|
551
|
+
|
|
552
|
+
**Do not null `#profiler` inside `finish()`.** The renderer reads `profiling_absorbed` *after*
|
|
553
|
+
`finish()` ([Renderer.js:2520, then :2531](../renderer/Renderer.js:2531)). If `profiling_absorbed`
|
|
554
|
+
becomes a getter that returns `Promise.resolve()` when `#profiler === null`, nulling the field in
|
|
555
|
+
`finish()` hands the renderer an already-resolved promise and it commits an empty frame — every
|
|
556
|
+
frame, silently, with no error anywhere. The current code survives this only because
|
|
557
|
+
`#profiling_absorbed` is a separate cached field.
|
|
558
|
+
|
|
559
|
+
The profiler holds no GPU resources after `absorb()` — it destroys the timer array itself — so
|
|
560
|
+
leaving the reference in place is correct and costs nothing.
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## 6. Testing
|
|
565
|
+
|
|
566
|
+
| Tier | What |
|
|
567
|
+
|---|---|
|
|
568
|
+
| **Unit, node** | Port `sgpt_workload.spec.js` off `make_profiling_pass_encoder` onto the two classes: counting *and* forwarding, which it already tests. Its "a method the proxy has never heard of still works" test is deleted — that behaviour is gone deliberately. |
|
|
569
|
+
| **Unit, node** | `ComputePipelineDescriptor.workgroup_size`: the size for a literal, for a `const`, `[0,0,0]` plus a populated `workgroup_size_error` for an override expression, the memo invalidated by `fromJSON`/`copy`, and the returned array frozen. |
|
|
570
|
+
| **Unit, node** | `ComputeShader` still throws the same message for an unreadable size — a spec that pins the wrapping, since §3.5 rewrites how it gets there. |
|
|
571
|
+
| **Unit, node** | Drift guard: every method name on `SoftwareGPUComputePassEncoder.prototype` / `SoftwareGPURenderPassEncoder.prototype` has a counterpart on the decorator, modulo the §3.2 rename. This catches the decorator falling behind **the mock**, which is what breaks node-tier specs. It is *not* a completeness check against WebGPU — see §8.2. |
|
|
572
|
+
| **`SoftwareGPUDevice`** | `ShadeGPUCommandContextFrame.spec.js` already drives `setViewport`/`draw`/`dispatchWorkgroups`/`end` through the context and asserts on the underlying mock encoder — it passes unchanged if the forwarding is right, which makes it the integration check for free. `GPUFrameRecorder.spec.js` and `GPUProfileSession.spec.js` cover the join end to end. |
|
|
573
|
+
| **Browser playground** | The **only** real completeness check: diff each decorator against the live `GPUComputePassEncoder.prototype` / `GPURenderPassEncoder.prototype` and **throw**, not warn. A console warning in a playground page is a warning nobody reads. |
|
|
574
|
+
| **Measurement** | `shade/playground/volumetrics_froxel/measure.js`, before and after, profiling **off**. |
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## 7. Cost, honestly
|
|
579
|
+
|
|
580
|
+
**Not profiling** — per pass: one object allocation, one `assert.defined`, one `assert.notOk`; per
|
|
581
|
+
encoder method: one call frame. Asserts in this codebase are **not** stripped in production
|
|
582
|
+
([core/assert.js](../../core/assert.js) has no build-time gate), so those two are real work on every
|
|
583
|
+
pass, not a debug-build cost.
|
|
584
|
+
|
|
585
|
+
How many passes per frame is **not known** — the 2026-08-28 proposal lists it as an open question
|
|
586
|
+
(§734 there) and `GPUTimerArray`'s 1024-slot default is a ceiling, not a measurement. So the total is
|
|
587
|
+
unquantified by construction and §6's measurement is the answer, not this paragraph.
|
|
588
|
+
|
|
589
|
+
**Profiling** — strictly faster. A `Proxy` `get` trap plus a `Map` lookup on every property access
|
|
590
|
+
becomes a direct method call. Plus one WGSL parse removed per profiled compute pass (§3.5).
|
|
591
|
+
|
|
592
|
+
**Correctness** — the two hidden fields go, and with them any defect that could only manifest while
|
|
593
|
+
profiling.
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## 8. Adversarial pass
|
|
598
|
+
|
|
599
|
+
Attacking the above. Four findings changed the design; the rest are recorded because they are the
|
|
600
|
+
things most likely to be wrong.
|
|
601
|
+
|
|
602
|
+
### 8.1 `label` was write-only-broken *(fixed above)*
|
|
603
|
+
|
|
604
|
+
Revision 1 gave the decorators a `label` getter and no setter. `GPUObjectBase.label` is a read-write
|
|
605
|
+
attribute, ES modules are always strict mode, and assigning to an accessor with no setter throws
|
|
606
|
+
`TypeError`. Nothing writes `pass.label` today (checked), so this would have sat dormant until
|
|
607
|
+
someone tried — and the §6 drift guard compares *method* names and would never have caught a missing
|
|
608
|
+
accessor. Fixed: `get`/`set` pair. The general lesson is that the drift guard's scope is narrower
|
|
609
|
+
than it looks, which is §8.2.
|
|
610
|
+
|
|
611
|
+
### 8.2 The node conformance test was oversold *(claim corrected above)*
|
|
612
|
+
|
|
613
|
+
Revision 1 called the node-tier test "the completeness guarantee … which the Proxy could not do".
|
|
614
|
+
That is wrong twice over. It compares meep's decorator against meep's own hand-written mock, so it
|
|
615
|
+
cannot possibly catch a method Chrome adds — both sides would be missing it. And `toHaveProperty`
|
|
616
|
+
walks the prototype chain, so `Object.prototype` members pass vacuously. It is a **drift guard**
|
|
617
|
+
between two files in this repo, which is worth having and is not the same claim. Only the browser
|
|
618
|
+
check tests completeness, and it has to *throw*. §6 now says so.
|
|
619
|
+
|
|
620
|
+
This weakens — but does not overturn — the §2 argument. The Proxy's real advantage was forwarding
|
|
621
|
+
methods **nobody had heard of yet**; that advantage is real and this proposal gives it up on purpose,
|
|
622
|
+
in exchange for a failure that is loud and immediate instead of silent and capture-only. Worth being
|
|
623
|
+
explicit that it is a trade, not a free win.
|
|
624
|
+
|
|
625
|
+
### 8.3 Revision 1 reintroduced the bug it was removing *(design changed above)*
|
|
626
|
+
|
|
627
|
+
Revision 1 replaced `#pending_work` with a reused `ShadeGPUPassProfile` scratch object returned from
|
|
628
|
+
`open_compute_pass`, "valid until the next call". That is the same coupling — a mutable value whose
|
|
629
|
+
correctness depends on the caller consuming it before anything else runs — moved one class down and
|
|
630
|
+
given a name. Having just written two pages about why that pattern is bad, shipping it would have
|
|
631
|
+
been indefensible. §3.4 now has the profiler open the pass, so both values are produced and consumed
|
|
632
|
+
inside one method and there is nothing to carry.
|
|
633
|
+
|
|
634
|
+
### 8.4 The commit sequence was not actually independently green *(fixed above, see §9)*
|
|
635
|
+
|
|
636
|
+
Revision 1 ordered "decorators first, profiler-state consolidation second". But the decorators need
|
|
637
|
+
the work record to come from *somewhere*, so step 1 would have had to build `begin*Pass` against the
|
|
638
|
+
old `#pending_work` channel and then immediately rewrite it. Reordered.
|
|
639
|
+
|
|
640
|
+
### 8.5 Sharing the workgroup-size array is a real aliasing hazard *(mitigated above)*
|
|
641
|
+
|
|
642
|
+
`work.workgroup_size = descriptor.workgroup_size` hands a per-pass profile record a reference to an
|
|
643
|
+
array owned by a descriptor that outlives the whole capture. Nothing mutates it today —
|
|
644
|
+
`GPUProfileWork` assigns it and never writes through it, unlike `workgroups`, which is mutated in
|
|
645
|
+
place three lines away in the same class. That is close enough to be worth removing as a possibility
|
|
646
|
+
rather than as a bug: §3.5 freezes it.
|
|
647
|
+
|
|
648
|
+
### 8.6 The memo has two invalidation paths and I nearly missed both *(covered above)*
|
|
649
|
+
|
|
650
|
+
`ComputePipelineDescriptor.fromJSON` mutates `this.compute` in place and `PipelineDescriptorBase` has
|
|
651
|
+
a `copy`. A memoised `workgroup_size` read before either would be silently stale afterwards — and
|
|
652
|
+
stale in the worst way, since the number is used as a *divisor* for thread counts. §3.5 and §6 both
|
|
653
|
+
call it out. This is the single most likely place for this change to introduce a real bug.
|
|
654
|
+
|
|
655
|
+
### 8.7 Claims I softened rather than defended
|
|
656
|
+
|
|
657
|
+
- **"Perfectly predicted branch."** The `#work !== null` check is uniform within a frame but flips
|
|
658
|
+
when a capture starts or stops. Predictable, not free, and not worth a sentence of advocacy.
|
|
659
|
+
- **"~200 passes/frame, ~1200 calls/frame."** Invented. The number is unknown and is listed as an
|
|
660
|
+
open question in the profiler proposal itself. §7 now says so instead of quoting a fabricated
|
|
661
|
+
figure at two decimal places of confidence.
|
|
662
|
+
- **"Both classes ~120 lines."** Now ~130 with the `label` setter and the split `setBindGroup`.
|
|
663
|
+
Immaterial, but the earlier number was a guess presented as a measurement.
|
|
664
|
+
|
|
665
|
+
### 8.9 It shipped broken anyway — the arity bug *(found in a browser, after landing)*
|
|
666
|
+
|
|
667
|
+
`setBindGroup(0, bind_group)` forwarded `setBindGroup(0, bind_group, undefined)`, and the renderer
|
|
668
|
+
died on its first bind group with "the provided value cannot be converted to a sequence".
|
|
669
|
+
|
|
670
|
+
The failure is worth recording in full, because every safeguard in this document was pointed at it
|
|
671
|
+
and it got through anyway.
|
|
672
|
+
|
|
673
|
+
**§3.2 named the right method and guarded the wrong end of it.** It identified `setBindGroup` as the
|
|
674
|
+
one forward that could be actively wrong, correctly diagnosed *why* — an overload resolved by
|
|
675
|
+
counting arguments — and then wrote a three-argument forwarder whose whole purpose was to avoid the
|
|
676
|
+
five-argument one. The hazard was never the arity it might reach; it was the `undefined` it would
|
|
677
|
+
hand over on the way. The proposal even asserted the opposite in as many words: "Every other method
|
|
678
|
+
has all-optional trailing parameters with WebIDL defaults, for which forwarding `undefined` is
|
|
679
|
+
correct." That sentence was reasoning about a specification, presented as a fact about a browser,
|
|
680
|
+
and it was load-bearing for seven methods.
|
|
681
|
+
|
|
682
|
+
**Six more had the same defect waiting.** `setImmediates`, `setIndexBuffer`, `setVertexBuffer` and
|
|
683
|
+
the render-side `setBindGroup`. `setVertexBuffer(0, buffer)` — from `prototypeParticleSystem` — was
|
|
684
|
+
next in line, and worse: `size` there has no default to stand in for, it means "the rest of the
|
|
685
|
+
buffer", so an absent argument and an `undefined` one are genuinely different requests.
|
|
686
|
+
|
|
687
|
+
**The node tier could not have caught it.** The mock encoders are plain JS functions and take a
|
|
688
|
+
trailing `undefined` happily, so the mock and the browser disagree in exactly the place the design
|
|
689
|
+
depended on. §6's drift guard compared method *names*, which was never going to help — §8.2 already
|
|
690
|
+
observed the node tier was weaker than it looked, and still put a name-comparison in the plan.
|
|
691
|
+
|
|
692
|
+
**What replaced it:** specs that assert arity preservation against a recording fake, which is
|
|
693
|
+
mock-independent and would have failed on the first run; and the fix verified against real WebGPU
|
|
694
|
+
in a browser rather than against the mock.
|
|
695
|
+
|
|
696
|
+
**Not fully explained.** The in-app browser (Chrome 148) *accepts* the explicit `undefined`; the
|
|
697
|
+
build that crashed does not. So the fix is verified correct on both, but the exact behavioural
|
|
698
|
+
difference was not reproduced, and the code comment says "some builds accept it, others do not"
|
|
699
|
+
rather than claiming a mechanism it cannot demonstrate.
|
|
700
|
+
|
|
701
|
+
**The standing lesson.** The browser-tier check §9 leaves open is not a nice-to-have. Two of the
|
|
702
|
+
three tiers in §6 are blind to the mock/browser boundary by construction, and this change has now
|
|
703
|
+
been wrong at that boundary twice.
|
|
704
|
+
|
|
705
|
+
### 8.8 Residual risks, accepted
|
|
706
|
+
|
|
707
|
+
- **A WebGPU method Chrome ships that Shade has not modelled** is now a hard failure rather than a
|
|
708
|
+
silent forward. That is the intended trade (§8.2), but it means the browser check is load-bearing
|
|
709
|
+
and needs to actually run in CI or a pre-release checklist, not just exist.
|
|
710
|
+
- **`executeBundles` work is uncounted** (§3.3). Pre-existing, documented, nothing uses bundles.
|
|
711
|
+
- **99 call sites change type.** No reflection over pass objects exists anywhere in the tree
|
|
712
|
+
(`typeof pass.x`, `Object.keys(pass)`, spread, `instanceof` — all checked, all absent), so the
|
|
713
|
+
surface is method calls only. If one is missed it throws at that call; it cannot silently misbehave.
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## 9. Decisions taken
|
|
718
|
+
|
|
719
|
+
| # | Question | Decision |
|
|
720
|
+
|---|---|---|
|
|
721
|
+
| 1 | Location | **`device/pass/`**, with `ShadeGPUContextProfiler` in `device/timing/` beside the timer array it owns. |
|
|
722
|
+
| 2 | `GPUTimerArray.results_to_console_table` | **Deleted** — "a crude tool, no longer required". Its two specs moved onto `traverse_results`. |
|
|
723
|
+
| 3 | `setBindGroupRange` | **Kept.** The mock models the slice form, and naming it is the whole point of §3.2. |
|
|
724
|
+
| 4 | A `gpu_pass` escape hatch | **Omitted.** Nothing needs one and it invites bypass. |
|
|
725
|
+
| 5 | `end()` double-end assert | **In.** Tracking open passes on the context stays a separate change. |
|
|
726
|
+
| 6 | `workgroup_size_error` | **Rejected — throw instead.** See §3.5. |
|
|
727
|
+
|
|
728
|
+
Still open, and deliberately not done here:
|
|
729
|
+
|
|
730
|
+
- **The browser-tier completeness check** against the live `GPUComputePassEncoder.prototype` /
|
|
731
|
+
`GPURenderPassEncoder.prototype`. It is the only real completeness check (§8.2) and it is now
|
|
732
|
+
load-bearing, since a method Chrome ships that Shade has not modelled throws rather than being
|
|
733
|
+
forwarded blind.
|
|
734
|
+
- **The measurement.** `shade/playground/volumetrics_froxel/measure.js`, profiling off, before and
|
|
735
|
+
after. §7 says why the numbers are not guessed at here.
|
|
736
|
+
- **Two unreferenced modules** found on the way: `GPUVirtualShadowTextureResidence.js` imports a
|
|
737
|
+
default export that does not exist and throws on import; `graph_pass_debug_reprojection.js` is
|
|
738
|
+
dead. Both predate this change and neither was touched.
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
## 10. Commits
|
|
743
|
+
|
|
744
|
+
1. `refactor(shade): pipeline descriptors carry their workgroup size` — §3.5.
|
|
745
|
+
2. `refactor(shade): pass encoders become explicit decorator classes` — §§3.1–3.4 and 3.6, plus the
|
|
746
|
+
BVH verification tool moved onto a `GPUFrameRecorder`.
|
|
747
|
+
3. `refactor(shade): remove the debug-timer path, the profiler is the only one` — §4.
|
|
748
|
+
|
|
749
|
+
Revision 2 ordered these decorators-first; that was wrong (§8.4) and the workgroup size went first
|
|
750
|
+
instead. Full suite green after each: 15,012 tests.
|