@driftengine/core 3.63.0 → 4.0.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/CHANGELOG.json +111 -0
- package/NOTICE +20 -0
- package/README.md +1 -1
- package/dist/core/loop.js +18 -2
- package/dist/core/storage.js +5 -0
- package/dist/geometry/meshBuilder.d.ts +1 -1
- package/dist/geometry/meshBuilder.js +6 -2
- package/dist/index.d.ts +69 -4
- package/dist/index.js +112 -2
- package/dist/input/input.js +6 -1
- package/dist/math/exact.d.ts +13 -3
- package/dist/math/exact.js +68 -3
- package/dist/math/frustum.d.ts +17 -2
- package/dist/math/frustum.js +24 -0
- package/dist/render/backend/api.d.ts +34 -1
- package/dist/render/backend/api.js +22 -1
- package/dist/render/backend/budget.d.ts +7 -6
- package/dist/render/backend/budget.js +7 -6
- package/dist/render/backend/createRenderer.d.ts +57 -0
- package/dist/render/backend/createRenderer.js +51 -2
- package/dist/render/backend/materialChanges.d.ts +41 -0
- package/dist/render/backend/materialChanges.js +38 -0
- package/dist/render/backend/select.js +8 -0
- package/dist/render/backend/webgl2/renderer.d.ts +80 -1
- package/dist/render/backend/webgl2/renderer.js +208 -10
- package/dist/render/backend/webgpu/buffers.d.ts +20 -1
- package/dist/render/backend/webgpu/buffers.js +116 -58
- package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
- package/dist/render/backend/webgpu/fieldCompose.js +396 -0
- package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
- package/dist/render/backend/webgpu/giFieldPass.js +137 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
- package/dist/render/backend/webgpu/linePass.d.ts +4 -14
- package/dist/render/backend/webgpu/linePass.js +4 -33
- package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
- package/dist/render/backend/webgpu/probeBake.js +493 -0
- package/dist/render/backend/webgpu/renderer.d.ts +379 -24
- package/dist/render/backend/webgpu/renderer.js +1369 -76
- package/dist/render/backend/webgpu/scatterPass.js +15 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +19 -9
- package/dist/render/backend/webgpu/surfaceTexturePass.js +58 -32
- package/dist/render/causticsRenderer.d.ts +3 -1
- package/dist/render/causticsRenderer.js +4 -1
- package/dist/render/depthConvention.d.ts +12 -0
- package/dist/render/depthConvention.js +14 -0
- package/dist/render/deviceFeatures.d.ts +32 -0
- package/dist/render/deviceFeatures.js +41 -0
- package/dist/render/fog.d.ts +79 -0
- package/dist/render/fog.js +138 -0
- package/dist/render/frame/alias.d.ts +30 -0
- package/dist/render/frame/alias.js +61 -0
- package/dist/render/frame/deps.d.ts +37 -0
- package/dist/render/frame/deps.js +122 -0
- package/dist/render/frame/flushGraph.d.ts +43 -0
- package/dist/render/frame/flushGraph.js +84 -0
- package/dist/render/frame/graphSchedule.d.ts +49 -0
- package/dist/render/frame/graphSchedule.js +120 -0
- package/dist/render/frame/index.d.ts +15 -0
- package/dist/render/frame/index.js +8 -0
- package/dist/render/frame/lifetime.d.ts +24 -0
- package/dist/render/frame/lifetime.js +36 -0
- package/dist/render/frame/passTimings.d.ts +42 -0
- package/dist/render/frame/passTimings.js +38 -0
- package/dist/render/frame/validate.d.ts +15 -0
- package/dist/render/frame/validate.js +22 -0
- package/dist/render/frame/virtual.d.ts +44 -0
- package/dist/render/frame/virtual.js +61 -0
- package/dist/render/gi/chain.d.ts +82 -0
- package/dist/render/gi/chain.js +135 -0
- package/dist/render/gi/denoise.d.ts +114 -0
- package/dist/render/gi/denoise.js +169 -0
- package/dist/render/gi/fieldScene.d.ts +125 -0
- package/dist/render/gi/fieldScene.js +219 -0
- package/dist/render/gi/globalField.d.ts +157 -0
- package/dist/render/gi/globalField.js +373 -0
- package/dist/render/gi/probeGridFit.d.ts +24 -0
- package/dist/render/gi/probeGridFit.js +71 -0
- package/dist/render/gi/probeTrace.d.ts +82 -0
- package/dist/render/gi/probeTrace.js +128 -0
- package/dist/render/gi/probeVolume.d.ts +136 -0
- package/dist/render/gi/probeVolume.js +191 -0
- package/dist/render/gi/reflection.d.ts +73 -0
- package/dist/render/gi/reflection.js +109 -0
- package/dist/render/gi/traceField.d.ts +91 -0
- package/dist/render/gi/traceField.js +129 -0
- package/dist/render/gi/traceScreen.d.ts +68 -0
- package/dist/render/gi/traceScreen.js +82 -0
- package/dist/render/gpuScene.d.ts +38 -0
- package/dist/render/gpuScene.js +41 -0
- package/dist/render/gpudriven/alphaTest.d.ts +28 -0
- package/dist/render/gpudriven/alphaTest.js +32 -0
- package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
- package/dist/render/gpudriven/clusterUpload.js +75 -0
- package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
- package/dist/render/gpudriven/clusterWorld.js +155 -0
- package/dist/render/gpudriven/compact.d.ts +51 -0
- package/dist/render/gpudriven/compact.js +68 -0
- package/dist/render/gpudriven/cullClusters.d.ts +129 -0
- package/dist/render/gpudriven/cullClusters.js +237 -0
- package/dist/render/gpudriven/decodeTables.d.ts +64 -0
- package/dist/render/gpudriven/decodeTables.js +219 -0
- package/dist/render/gpudriven/frustum.d.ts +25 -0
- package/dist/render/gpudriven/frustum.js +59 -0
- package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
- package/dist/render/gpudriven/geometryHarness.js +31 -0
- package/dist/render/gpudriven/hzb.d.ts +60 -0
- package/dist/render/gpudriven/hzb.js +97 -0
- package/dist/render/gpudriven/ibl.d.ts +85 -0
- package/dist/render/gpudriven/ibl.js +129 -0
- package/dist/render/gpudriven/indirect.d.ts +67 -0
- package/dist/render/gpudriven/indirect.js +77 -0
- package/dist/render/gpudriven/instances.d.ts +43 -0
- package/dist/render/gpudriven/instances.js +172 -0
- package/dist/render/gpudriven/lit.d.ts +165 -0
- package/dist/render/gpudriven/lit.js +165 -0
- package/dist/render/gpudriven/lodCut.d.ts +28 -0
- package/dist/render/gpudriven/lodCut.js +38 -0
- package/dist/render/gpudriven/materialBin.d.ts +60 -0
- package/dist/render/gpudriven/materialBin.js +108 -0
- package/dist/render/gpudriven/materialTable.d.ts +88 -0
- package/dist/render/gpudriven/materialTable.js +115 -0
- package/dist/render/gpudriven/pipeline.d.ts +135 -0
- package/dist/render/gpudriven/pipeline.js +237 -0
- package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
- package/dist/render/gpudriven/rangeAlloc.js +112 -0
- package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
- package/dist/render/gpudriven/sceneUpload.js +115 -0
- package/dist/render/gpudriven/shadeBins.d.ts +92 -0
- package/dist/render/gpudriven/shadeBins.js +182 -0
- package/dist/render/gpudriven/shadow.d.ts +136 -0
- package/dist/render/gpudriven/shadow.js +224 -0
- package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
- package/dist/render/gpudriven/shadowCamera.js +345 -0
- package/dist/render/gpudriven/streamScene.d.ts +194 -0
- package/dist/render/gpudriven/streamScene.js +459 -0
- package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
- package/dist/render/gpudriven/surfaceFrame.js +51 -0
- package/dist/render/gpudriven/twoPhase.d.ts +122 -0
- package/dist/render/gpudriven/twoPhase.js +160 -0
- package/dist/render/gpudriven/visbuffer.d.ts +25 -0
- package/dist/render/gpudriven/visbuffer.js +37 -0
- package/dist/render/halfFloat.d.ts +10 -0
- package/dist/render/halfFloat.js +23 -4
- package/dist/render/inference/attentionTiled.d.ts +27 -0
- package/dist/render/inference/attentionTiled.js +117 -0
- package/dist/render/inference/denseKernels.d.ts +29 -0
- package/dist/render/inference/denseKernels.js +312 -0
- package/dist/render/inference/device.d.ts +21 -0
- package/dist/render/inference/device.js +32 -0
- package/dist/render/inference/deviceGraph.d.ts +34 -0
- package/dist/render/inference/deviceGraph.js +17 -0
- package/dist/render/inference/fuse.d.ts +15 -0
- package/dist/render/inference/fuse.js +37 -0
- package/dist/render/inference/kernelKit.d.ts +52 -0
- package/dist/render/inference/kernelKit.js +70 -0
- package/dist/render/inference/kernels.d.ts +3 -0
- package/dist/render/inference/kernels.js +11 -0
- package/dist/render/inference/plan.d.ts +13 -0
- package/dist/render/inference/plan.js +18 -0
- package/dist/render/inference/reuse.d.ts +39 -0
- package/dist/render/inference/reuse.js +65 -0
- package/dist/render/inference/runner.d.ts +31 -0
- package/dist/render/inference/runner.js +175 -0
- package/dist/render/inference/schedule.d.ts +39 -0
- package/dist/render/inference/schedule.js +59 -0
- package/dist/render/inference/shapeKernels.d.ts +10 -0
- package/dist/render/inference/shapeKernels.js +80 -0
- package/dist/render/inference/spatialKernels.d.ts +21 -0
- package/dist/render/inference/spatialKernels.js +179 -0
- package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
- package/dist/render/inference/splatRaster.wgsl.js +337 -0
- package/dist/render/inference/splatTiles.d.ts +79 -0
- package/dist/render/inference/splatTiles.js +161 -0
- package/dist/render/lineBatch.d.ts +2 -5
- package/dist/render/lineBatch.js +4 -24
- package/dist/render/mesh.d.ts +4 -0
- package/dist/render/mesh.js +45 -1
- package/dist/render/pass.d.ts +145 -8
- package/dist/render/prefilterEnvMap.d.ts +22 -0
- package/dist/render/prefilterEnvMap.js +31 -0
- package/dist/render/readback.d.ts +30 -0
- package/dist/render/readback.js +47 -0
- package/dist/render/recon/clamp.d.ts +36 -0
- package/dist/render/recon/clamp.js +92 -0
- package/dist/render/recon/disocclusion.d.ts +60 -0
- package/dist/render/recon/disocclusion.js +109 -0
- package/dist/render/recon/frameGen.d.ts +81 -0
- package/dist/render/recon/frameGen.js +150 -0
- package/dist/render/recon/frameSizes.d.ts +34 -0
- package/dist/render/recon/frameSizes.js +58 -0
- package/dist/render/recon/jitter.d.ts +60 -0
- package/dist/render/recon/jitter.js +118 -0
- package/dist/render/recon/motionVectors.d.ts +55 -0
- package/dist/render/recon/motionVectors.js +107 -0
- package/dist/render/recon/reproject.d.ts +41 -0
- package/dist/render/recon/reproject.js +131 -0
- package/dist/render/recon/resolve.d.ts +90 -0
- package/dist/render/recon/resolve.js +313 -0
- package/dist/render/recon/tier.d.ts +24 -0
- package/dist/render/recon/tier.js +8 -0
- package/dist/render/reflectionProbe.d.ts +26 -0
- package/dist/render/reflectionProbe.js +33 -0
- package/dist/render/renderQuality.d.ts +69 -0
- package/dist/render/renderQuality.js +22 -0
- package/dist/render/screenSpaceReflection.d.ts +23 -0
- package/dist/render/screenSpaceReflection.js +22 -3
- package/dist/render/sdfFont.js +2 -0
- package/dist/render/segmentQuads.d.ts +13 -0
- package/dist/render/segmentQuads.js +32 -0
- package/dist/render/shaders/flat/lobes.d.ts +27 -0
- package/dist/render/shaders/flat/lobes.js +33 -3
- package/dist/render/shaders/flat/preamble.d.ts +7 -0
- package/dist/render/shaders/flat/preamble.js +24 -1
- package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
- package/dist/render/shaders/flat/probeGrid.js +71 -2
- package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
- package/dist/render/shaders/generated/flat.wgsl.js +64 -24
- package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
- package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
- package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
- package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
- package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
- package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
- package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
- package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
- package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
- package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
- package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
- package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
- package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
- package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
- package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
- package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
- package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
- package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
- package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
- package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
- package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
- package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
- package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
- package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
- package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
- package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
- package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
- package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
- package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
- package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
- package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
- package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
- package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
- package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
- package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
- package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
- package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
- package/dist/render/shaders/network.wgsl.d.ts +101 -0
- package/dist/render/shaders/network.wgsl.js +206 -0
- package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
- package/dist/render/shaders/recon/motion.wgsl.js +96 -0
- package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
- package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
- package/dist/render/temporalAa.js +8 -33
- package/dist/render/textLayout.js +12 -6
- package/dist/render/textRenderer.d.ts +3 -1
- package/dist/render/textRenderer.js +4 -1
- package/dist/render/translucentQueue.d.ts +6 -0
- package/dist/render/translucentQueue.js +11 -0
- package/dist/render/windStreakRenderer.d.ts +2 -1
- package/dist/render/windStreakRenderer.js +3 -1
- package/dist/world/cell.d.ts +63 -0
- package/dist/world/cell.js +181 -0
- package/dist/world/cellStream.d.ts +103 -0
- package/dist/world/cellStream.js +198 -0
- package/dist/world/freeze.d.ts +81 -0
- package/dist/world/freeze.js +114 -0
- package/dist/world/rebase.d.ts +29 -0
- package/dist/world/rebase.js +41 -0
- package/package.json +8 -3
- package/scripts/frames.mjs +92 -0
- package/scripts/gpuCompute.mjs +323 -0
- package/scripts/png.d.mts +16 -0
- package/scripts/png.mjs +25 -0
- package/src/core/loop.ts +19 -2
- package/src/core/storage.ts +5 -0
- package/src/geometry/meshBuilder.ts +5 -1
- package/src/index.ts +246 -4
- package/src/input/input.ts +6 -1
- package/src/math/exact.ts +69 -3
- package/src/math/frustum.ts +52 -3
- package/src/render/backend/api.ts +42 -1
- package/src/render/backend/budget.ts +7 -6
- package/src/render/backend/createRenderer.ts +92 -3
- package/src/render/backend/materialChanges.ts +54 -0
- package/src/render/backend/select.ts +8 -0
- package/src/render/backend/webgl2/renderer.ts +211 -9
- package/src/render/backend/webgpu/buffers.ts +182 -69
- package/src/render/backend/webgpu/fieldCompose.ts +482 -0
- package/src/render/backend/webgpu/giFieldPass.ts +200 -0
- package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
- package/src/render/backend/webgpu/linePass.ts +4 -39
- package/src/render/backend/webgpu/probeBake.ts +588 -0
- package/src/render/backend/webgpu/renderer.ts +1481 -76
- package/src/render/backend/webgpu/scatterPass.ts +15 -1
- package/src/render/backend/webgpu/surfaceTexturePass.ts +63 -36
- package/src/render/causticsRenderer.ts +5 -2
- package/src/render/depthConvention.ts +15 -0
- package/src/render/deviceFeatures.ts +77 -0
- package/src/render/fog.ts +185 -0
- package/src/render/frame/alias.ts +97 -0
- package/src/render/frame/deps.ts +155 -0
- package/src/render/frame/flushGraph.ts +135 -0
- package/src/render/frame/graphSchedule.ts +170 -0
- package/src/render/frame/index.ts +52 -0
- package/src/render/frame/lifetime.ts +61 -0
- package/src/render/frame/passTimings.ts +69 -0
- package/src/render/frame/validate.ts +40 -0
- package/src/render/frame/virtual.ts +91 -0
- package/src/render/gi/chain.ts +225 -0
- package/src/render/gi/denoise.ts +276 -0
- package/src/render/gi/fieldScene.ts +264 -0
- package/src/render/gi/globalField.ts +543 -0
- package/src/render/gi/probeGridFit.ts +89 -0
- package/src/render/gi/probeTrace.ts +143 -0
- package/src/render/gi/probeVolume.ts +288 -0
- package/src/render/gi/reflection.ts +163 -0
- package/src/render/gi/traceField.ts +223 -0
- package/src/render/gi/traceScreen.ts +106 -0
- package/src/render/gpuScene.ts +80 -0
- package/src/render/gpudriven/alphaTest.ts +33 -0
- package/src/render/gpudriven/clusterUpload.ts +123 -0
- package/src/render/gpudriven/clusterWorld.ts +239 -0
- package/src/render/gpudriven/compact.ts +80 -0
- package/src/render/gpudriven/cullClusters.ts +333 -0
- package/src/render/gpudriven/decodeTables.ts +332 -0
- package/src/render/gpudriven/frustum.ts +70 -0
- package/src/render/gpudriven/geometryHarness.ts +51 -0
- package/src/render/gpudriven/hzb.ts +113 -0
- package/src/render/gpudriven/ibl.ts +147 -0
- package/src/render/gpudriven/indirect.ts +89 -0
- package/src/render/gpudriven/instances.ts +234 -0
- package/src/render/gpudriven/lit.ts +329 -0
- package/src/render/gpudriven/lodCut.ts +62 -0
- package/src/render/gpudriven/materialBin.ts +131 -0
- package/src/render/gpudriven/materialTable.ts +164 -0
- package/src/render/gpudriven/pipeline.ts +336 -0
- package/src/render/gpudriven/rangeAlloc.ts +122 -0
- package/src/render/gpudriven/sceneUpload.ts +173 -0
- package/src/render/gpudriven/shadeBins.ts +222 -0
- package/src/render/gpudriven/shadow.ts +285 -0
- package/src/render/gpudriven/shadowCamera.ts +406 -0
- package/src/render/gpudriven/streamScene.ts +575 -0
- package/src/render/gpudriven/surfaceFrame.ts +68 -0
- package/src/render/gpudriven/twoPhase.ts +214 -0
- package/src/render/gpudriven/visbuffer.ts +41 -0
- package/src/render/halfFloat.ts +22 -4
- package/src/render/inference/attentionTiled.ts +132 -0
- package/src/render/inference/denseKernels.ts +369 -0
- package/src/render/inference/device.ts +44 -0
- package/src/render/inference/deviceGraph.ts +39 -0
- package/src/render/inference/fuse.ts +47 -0
- package/src/render/inference/kernelKit.ts +120 -0
- package/src/render/inference/kernels.ts +18 -0
- package/src/render/inference/plan.ts +26 -0
- package/src/render/inference/reuse.ts +79 -0
- package/src/render/inference/runner.ts +204 -0
- package/src/render/inference/schedule.ts +80 -0
- package/src/render/inference/shapeKernels.ts +112 -0
- package/src/render/inference/spatialKernels.ts +220 -0
- package/src/render/inference/splatRaster.wgsl.ts +348 -0
- package/src/render/inference/splatTiles.ts +186 -0
- package/src/render/lineBatch.ts +4 -24
- package/src/render/mesh.ts +46 -1
- package/src/render/pass.ts +155 -10
- package/src/render/prefilterEnvMap.ts +33 -0
- package/src/render/readback.ts +73 -0
- package/src/render/recon/clamp.ts +113 -0
- package/src/render/recon/disocclusion.ts +143 -0
- package/src/render/recon/frameGen.ts +191 -0
- package/src/render/recon/frameSizes.ts +64 -0
- package/src/render/recon/jitter.ts +126 -0
- package/src/render/recon/motionVectors.ts +138 -0
- package/src/render/recon/reproject.ts +179 -0
- package/src/render/recon/resolve.ts +444 -0
- package/src/render/recon/tier.ts +31 -0
- package/src/render/reflectionProbe.ts +34 -0
- package/src/render/renderQuality.ts +87 -0
- package/src/render/screenSpaceReflection.ts +37 -3
- package/src/render/sdfFont.ts +2 -0
- package/src/render/segmentQuads.ts +39 -0
- package/src/render/shaders/flat/lobes.ts +35 -3
- package/src/render/shaders/flat/preamble.ts +25 -1
- package/src/render/shaders/flat/probeGrid.ts +77 -2
- package/src/render/shaders/generated/flat.wgsl.ts +64 -24
- package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
- package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
- package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
- package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
- package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
- package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
- package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
- package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
- package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
- package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
- package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
- package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
- package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
- package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
- package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
- package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
- package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
- package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
- package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
- package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
- package/src/render/shaders/network.wgsl.ts +238 -0
- package/src/render/shaders/recon/motion.wgsl.ts +101 -0
- package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
- package/src/render/temporalAa.ts +9 -33
- package/src/render/textLayout.ts +12 -6
- package/src/render/textRenderer.ts +5 -2
- package/src/render/translucentQueue.ts +11 -0
- package/src/render/windStreakRenderer.ts +4 -2
- package/src/world/cell.ts +231 -0
- package/src/world/cellStream.ts +278 -0
- package/src/world/freeze.ts +157 -0
- package/src/world/rebase.ts +56 -0
package/dist/input/input.js
CHANGED
|
@@ -317,7 +317,12 @@ export class InputSource {
|
|
|
317
317
|
constructor(target, preventDefaultCodes = [], options = {}) {
|
|
318
318
|
this.target = target;
|
|
319
319
|
this.preventDefaultCodes = new Set(preventDefaultCodes);
|
|
320
|
-
|
|
320
|
+
/* Guarded, and `ui/fullscreen.ts` guards the identical query with the identical test. This
|
|
321
|
+
line is in a constructor, so unguarded it did not degrade a hint — it threw, and an embedder
|
|
322
|
+
without `matchMedia` could not construct input at all. False is what a runtime with no
|
|
323
|
+
pointer media query honestly is. */
|
|
324
|
+
this.isCoarse =
|
|
325
|
+
typeof window.matchMedia === 'function' && window.matchMedia('(pointer: coarse)').matches;
|
|
321
326
|
this.deadzone = options.deadzone ?? DEFAULT_DEADZONE;
|
|
322
327
|
this.autoPoll = options.autoPoll ?? true;
|
|
323
328
|
for (const name of ['keyboard', 'mouse', 'touch', 'gamepad']) {
|
package/dist/math/exact.d.ts
CHANGED
|
@@ -18,9 +18,10 @@
|
|
|
18
18
|
*
|
|
19
19
|
* ## What is here, and what is deliberately not
|
|
20
20
|
*
|
|
21
|
-
* `exactSin`, `exactCos`, `exactExp`, `exactAcos`.
|
|
22
|
-
* first consumer actually reach for: the terrain binding's slope angle needs `acos`,
|
|
23
|
-
* fixture rotating anything needs `sin` and `cos`,
|
|
21
|
+
* `exactSin`, `exactCos`, `exactExp`, `exactAcos` and `exactLog`. Five, because five is what the
|
|
22
|
+
* engine and its first consumer actually reach for: the terrain binding's slope angle needs `acos`,
|
|
23
|
+
* a lockstep fixture rotating anything needs `sin` and `cos`, exponential decay needs `exp`, and a
|
|
24
|
+
* detector's box prior is a logit of the patch grid, which needs `log`.
|
|
24
25
|
*
|
|
25
26
|
* **`atan2` is absent.** It is the obvious fifth and nothing here needs one: `shape.ts` sorts by a
|
|
26
27
|
* comparison key computed from two in-plane axes rather than by an angle, and `joints.ts` compares
|
|
@@ -55,6 +56,15 @@ export declare function exactCos(x: number): number;
|
|
|
55
56
|
* representation and there is nothing a fitted polynomial would buy.
|
|
56
57
|
*/
|
|
57
58
|
export declare function exactExp(x: number): number;
|
|
59
|
+
/**
|
|
60
|
+
* `Math.log`, reproducibly: fdlibm's algorithm, which is also V8's.
|
|
61
|
+
*
|
|
62
|
+
* Take the power of two out as `k` and leave a significand in [√2/2, √2), so that `f = m - 1` is
|
|
63
|
+
* small either side of zero; then log(1 + f) = f - f²/2 + s·(f²/2 + R(s²)) with s = f/(2 + f), and
|
|
64
|
+
* `k·ln 2` added back in two parts so the large part loses nothing. The exponent is read and the
|
|
65
|
+
* significand rescaled through the double's own words — integer operations, not transcendentals.
|
|
66
|
+
*/
|
|
67
|
+
export declare function exactLog(x: number): number;
|
|
58
68
|
/**
|
|
59
69
|
* `Math.acos`, reproducibly. Outside [-1, 1] this answers NaN, as `Math.acos` does.
|
|
60
70
|
*
|
package/dist/math/exact.js
CHANGED
|
@@ -18,9 +18,10 @@
|
|
|
18
18
|
*
|
|
19
19
|
* ## What is here, and what is deliberately not
|
|
20
20
|
*
|
|
21
|
-
* `exactSin`, `exactCos`, `exactExp`, `exactAcos`.
|
|
22
|
-
* first consumer actually reach for: the terrain binding's slope angle needs `acos`,
|
|
23
|
-
* fixture rotating anything needs `sin` and `cos`,
|
|
21
|
+
* `exactSin`, `exactCos`, `exactExp`, `exactAcos` and `exactLog`. Five, because five is what the
|
|
22
|
+
* engine and its first consumer actually reach for: the terrain binding's slope angle needs `acos`,
|
|
23
|
+
* a lockstep fixture rotating anything needs `sin` and `cos`, exponential decay needs `exp`, and a
|
|
24
|
+
* detector's box prior is a logit of the patch grid, which needs `log`.
|
|
24
25
|
*
|
|
25
26
|
* **`atan2` is absent.** It is the obvious fifth and nothing here needs one: `shape.ts` sorts by a
|
|
26
27
|
* comparison key computed from two in-plane axes rather than by an angle, and `joints.ts` compares
|
|
@@ -226,6 +227,70 @@ export function exactExp(x) {
|
|
|
226
227
|
sum = 1 + r * sum;
|
|
227
228
|
return sum * pow2(k);
|
|
228
229
|
}
|
|
230
|
+
/* fdlibm's `log` polynomial in s², for log(1 + f) around f = 0 by way of s = f / (2 + f). */
|
|
231
|
+
const LG1 = 6.66666666666673513e-1;
|
|
232
|
+
const LG2 = 3.999999999940941908e-1;
|
|
233
|
+
const LG3 = 2.857142874366239149e-1;
|
|
234
|
+
const LG4 = 2.222219843214978396e-1;
|
|
235
|
+
const LG5 = 1.818357216161805012e-1;
|
|
236
|
+
const LG6 = 1.531383769920937332e-1;
|
|
237
|
+
const LG7 = 1.479819860511658591e-1;
|
|
238
|
+
const TWO54 = 1.8014398509481984e16;
|
|
239
|
+
const SMALLEST_NORMAL = 2.2250738585072014e-308;
|
|
240
|
+
/* A double's two words, for reading and setting an exponent; one view, reused. */
|
|
241
|
+
const words = new DataView(new ArrayBuffer(8));
|
|
242
|
+
/**
|
|
243
|
+
* `Math.log`, reproducibly: fdlibm's algorithm, which is also V8's.
|
|
244
|
+
*
|
|
245
|
+
* Take the power of two out as `k` and leave a significand in [√2/2, √2), so that `f = m - 1` is
|
|
246
|
+
* small either side of zero; then log(1 + f) = f - f²/2 + s·(f²/2 + R(s²)) with s = f/(2 + f), and
|
|
247
|
+
* `k·ln 2` added back in two parts so the large part loses nothing. The exponent is read and the
|
|
248
|
+
* significand rescaled through the double's own words — integer operations, not transcendentals.
|
|
249
|
+
*/
|
|
250
|
+
export function exactLog(x) {
|
|
251
|
+
if (Number.isNaN(x) || x < 0)
|
|
252
|
+
return Number.NaN;
|
|
253
|
+
if (x === 0)
|
|
254
|
+
return Number.NEGATIVE_INFINITY;
|
|
255
|
+
if (x === Number.POSITIVE_INFINITY)
|
|
256
|
+
return x;
|
|
257
|
+
let k = 0;
|
|
258
|
+
let value = x;
|
|
259
|
+
if (value < SMALLEST_NORMAL) {
|
|
260
|
+
k = -54;
|
|
261
|
+
value *= TWO54;
|
|
262
|
+
}
|
|
263
|
+
words.setFloat64(0, value);
|
|
264
|
+
let hx = words.getUint32(0);
|
|
265
|
+
k += (hx >>> 20) - 1023;
|
|
266
|
+
hx &= 0x000fffff;
|
|
267
|
+
/* Keep the significand at or above √2/2: past √2, halve it and count one more power of two. */
|
|
268
|
+
const i = (hx + 0x95f64) & 0x100000;
|
|
269
|
+
words.setUint32(0, hx | (i ^ 0x3ff00000));
|
|
270
|
+
k += i >>> 20;
|
|
271
|
+
const f = words.getFloat64(0) - 1;
|
|
272
|
+
if ((0x000fffff & (2 + hx)) < 3) {
|
|
273
|
+
/* |f| < 2^-20: two terms of the series are the whole answer. */
|
|
274
|
+
if (f === 0)
|
|
275
|
+
return k === 0 ? 0 : k * LN2_HI + k * LN2_LO;
|
|
276
|
+
const r = f * f * (0.5 - 0.33333333333333333 * f);
|
|
277
|
+
return k === 0 ? f - r : k * LN2_HI - (r - k * LN2_LO - f);
|
|
278
|
+
}
|
|
279
|
+
const s = f / (2 + f);
|
|
280
|
+
const z = s * s;
|
|
281
|
+
const w = z * z;
|
|
282
|
+
const t1 = w * (LG2 + w * (LG4 + w * LG6));
|
|
283
|
+
const t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
|
|
284
|
+
const r = t2 + t1;
|
|
285
|
+
/* Far enough from one that f²/2 is worth carrying apart from f. */
|
|
286
|
+
if (((hx - 0x6147a) | (0x6b851 - hx)) > 0) {
|
|
287
|
+
const half = 0.5 * f * f;
|
|
288
|
+
return k === 0
|
|
289
|
+
? f - (half - s * (half + r))
|
|
290
|
+
: k * LN2_HI - (half - (s * (half + r) + k * LN2_LO) - f);
|
|
291
|
+
}
|
|
292
|
+
return k === 0 ? f - s * (f - r) : k * LN2_HI - (s * (f - r) - k * LN2_LO - f);
|
|
293
|
+
}
|
|
229
294
|
/** fdlibm's `asin` rational on `z = x²`, valid where `z` is small. */
|
|
230
295
|
function asinRational(z) {
|
|
231
296
|
const numerator = z * (P0 + z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))));
|
package/dist/math/frustum.d.ts
CHANGED
|
@@ -10,6 +10,11 @@ import type { ReadonlyMat4 } from 'gl-matrix';
|
|
|
10
10
|
* the frustum when `n · p + d >= 0` for all six.
|
|
11
11
|
*/
|
|
12
12
|
export type Frustum = Float32Array;
|
|
13
|
+
/**
|
|
14
|
+
* Planes in either precision. **Double precision is for a world past 2^24 units**, where a plane's
|
|
15
|
+
* offset is a number a single float cannot hold to the metre; `cellsInFrustum` asks for it.
|
|
16
|
+
*/
|
|
17
|
+
export type FrustumPlanes = Float32Array | Float64Array;
|
|
13
18
|
export declare function createFrustum(): Frustum;
|
|
14
19
|
/**
|
|
15
20
|
* Pull the six planes out of a view-projection matrix.
|
|
@@ -28,7 +33,7 @@ export declare function createFrustum(): Frustum;
|
|
|
28
33
|
*
|
|
29
34
|
* gl-matrix stores column-major, so `m[column * 4 + row]`.
|
|
30
35
|
*/
|
|
31
|
-
export declare function frustumFromViewProjection(m: ReadonlyMat4, out:
|
|
36
|
+
export declare function frustumFromViewProjection<T extends FrustumPlanes>(m: ReadonlyMat4 | Float64Array, out: T): T;
|
|
32
37
|
/**
|
|
33
38
|
* Whether a world-space sphere is anywhere inside the frustum.
|
|
34
39
|
*
|
|
@@ -41,4 +46,14 @@ export declare function frustumFromViewProjection(m: ReadonlyMat4, out: Frustum)
|
|
|
41
46
|
* all six planes, near an edge. That costs a draw that turns out to be invisible and never costs
|
|
42
47
|
* a draw that was visible, which is the only asymmetry a cull may have.
|
|
43
48
|
*/
|
|
44
|
-
export declare function sphereInFrustum(frustum:
|
|
49
|
+
export declare function sphereInFrustum(frustum: FrustumPlanes, x: number, y: number, z: number, radius: number): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Whether an axis-aligned box is anywhere inside the frustum, by the same question the sphere test
|
|
52
|
+
* asks: outside only when wholly beyond one plane.
|
|
53
|
+
*
|
|
54
|
+
* **The corner that decides it is chosen per plane** — the one furthest along that plane's normal.
|
|
55
|
+
* A fixed corner answers correctly for the planes whose normals happen to point its way and culls a
|
|
56
|
+
* box straddling any of the others. Conservative at the edges, as the sphere test is: a box near a
|
|
57
|
+
* corner of the frustum can be outside it and still kept.
|
|
58
|
+
*/
|
|
59
|
+
export declare function boxInFrustum(frustum: FrustumPlanes, minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): boolean;
|
package/dist/math/frustum.js
CHANGED
|
@@ -88,3 +88,27 @@ export function sphereInFrustum(frustum, x, y, z, radius) {
|
|
|
88
88
|
}
|
|
89
89
|
return true;
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Whether an axis-aligned box is anywhere inside the frustum, by the same question the sphere test
|
|
93
|
+
* asks: outside only when wholly beyond one plane.
|
|
94
|
+
*
|
|
95
|
+
* **The corner that decides it is chosen per plane** — the one furthest along that plane's normal.
|
|
96
|
+
* A fixed corner answers correctly for the planes whose normals happen to point its way and culls a
|
|
97
|
+
* box straddling any of the others. Conservative at the edges, as the sphere test is: a box near a
|
|
98
|
+
* corner of the frustum can be outside it and still kept.
|
|
99
|
+
*/
|
|
100
|
+
export function boxInFrustum(frustum, minX, minY, minZ, maxX, maxY, maxZ) {
|
|
101
|
+
for (let plane = 0; plane < PLANE_COUNT; plane += 1) {
|
|
102
|
+
const at = plane * 4;
|
|
103
|
+
const nx = frustum[at] ?? 0;
|
|
104
|
+
const ny = frustum[at + 1] ?? 0;
|
|
105
|
+
const nz = frustum[at + 2] ?? 0;
|
|
106
|
+
const reach = nx * (nx >= 0 ? maxX : minX) +
|
|
107
|
+
ny * (ny >= 0 ? maxY : minY) +
|
|
108
|
+
nz * (nz >= 0 ? maxZ : minZ) +
|
|
109
|
+
(frustum[at + 3] ?? 0);
|
|
110
|
+
if (reach < 0)
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
@@ -464,7 +464,20 @@ export type RendererApi = Omit<{
|
|
|
464
464
|
*/
|
|
465
465
|
updateMesh(mesh: MeshHandle, positions: Float32Array, normals?: Float32Array): void;
|
|
466
466
|
/** Draw a handle this renderer made. Passing one from the other backend is a caller error. */
|
|
467
|
-
drawMesh(mesh: MeshHandle, model: ReadonlyMat4, depthLayer?: number, tint?: Vec3 | null
|
|
467
|
+
drawMesh(mesh: MeshHandle, model: ReadonlyMat4, depthLayer?: number, tint?: Vec3 | null,
|
|
468
|
+
/**
|
|
469
|
+
* Where this mesh's surface was last frame, for a reconstruction's motion target.
|
|
470
|
+
*
|
|
471
|
+
* **Only a reconstruction reads it**, and only on WebGPU: it is what turns a moving object's
|
|
472
|
+
* stale history from a smear into a reprojection. A draw that says nothing gets the camera's
|
|
473
|
+
* motion, derived from the depth, which is exactly right for anything that did not move and
|
|
474
|
+
* wrong in proportion to how far a mover moved. Null and omitted mean the same thing.
|
|
475
|
+
*
|
|
476
|
+
* It is the *model* matrix this mesh was drawn with last frame, not a velocity: the pass
|
|
477
|
+
* transforms each vertex twice and lets the perspective divide do the rest, so a rotation and a
|
|
478
|
+
* scale are as correct as a translation.
|
|
479
|
+
*/
|
|
480
|
+
previousModel?: ReadonlyMat4 | null): void;
|
|
468
481
|
/** Release the geometry behind a handle. */
|
|
469
482
|
disposeMesh(mesh: MeshHandle): void;
|
|
470
483
|
/**
|
|
@@ -494,3 +507,23 @@ export type RendererApi = Omit<{
|
|
|
494
507
|
};
|
|
495
508
|
/** Which backend is actually drawing. Reported, never inferred. */
|
|
496
509
|
export type RenderBackend = 'webgl2' | 'webgpu';
|
|
510
|
+
/**
|
|
511
|
+
* Whether this backend can be driven from buffers the GPU itself wrote.
|
|
512
|
+
*
|
|
513
|
+
* **A fact about the backend, not a method on this surface, and that is the finding rather than
|
|
514
|
+
* the shortcut.** Indirect execution needs a render or compute pass encoder, and both are already
|
|
515
|
+
* in the hands of the code that would use them: `PassContext` hands a contributed pass the
|
|
516
|
+
* `GPURenderPassEncoder`, and `ComputeDefinition.dispatch` hands a definition the
|
|
517
|
+
* `GPUComputePassEncoder` while saying in as many words that the workgroup count is the
|
|
518
|
+
* definition's and does not cross this surface. A `drawIndexedIndirect` here would be a second
|
|
519
|
+
* way to reach an encoder a caller already holds.
|
|
520
|
+
*
|
|
521
|
+
* So what is missing is not a verb. It is an answer to *may I*, which a GPU-driven pipeline has
|
|
522
|
+
* to ask before it builds an argument buffer nothing can consume.
|
|
523
|
+
*
|
|
524
|
+
* **WebGL2 is a refusal rather than an omission.** It has no compute stage to write an argument
|
|
525
|
+
* buffer and no indirect draw to read one. Emulating it means reading the buffer back to the
|
|
526
|
+
* processor and issuing the draws from there, which is slower than the ordinary path it would be
|
|
527
|
+
* pretending to replace — so this reports false and the GPU-driven pipeline is WebGPU-only.
|
|
528
|
+
*/
|
|
529
|
+
export declare function indirectSupport(backend: 'webgl2' | 'webgpu'): boolean;
|
|
@@ -1 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Whether this backend can be driven from buffers the GPU itself wrote.
|
|
3
|
+
*
|
|
4
|
+
* **A fact about the backend, not a method on this surface, and that is the finding rather than
|
|
5
|
+
* the shortcut.** Indirect execution needs a render or compute pass encoder, and both are already
|
|
6
|
+
* in the hands of the code that would use them: `PassContext` hands a contributed pass the
|
|
7
|
+
* `GPURenderPassEncoder`, and `ComputeDefinition.dispatch` hands a definition the
|
|
8
|
+
* `GPUComputePassEncoder` while saying in as many words that the workgroup count is the
|
|
9
|
+
* definition's and does not cross this surface. A `drawIndexedIndirect` here would be a second
|
|
10
|
+
* way to reach an encoder a caller already holds.
|
|
11
|
+
*
|
|
12
|
+
* So what is missing is not a verb. It is an answer to *may I*, which a GPU-driven pipeline has
|
|
13
|
+
* to ask before it builds an argument buffer nothing can consume.
|
|
14
|
+
*
|
|
15
|
+
* **WebGL2 is a refusal rather than an omission.** It has no compute stage to write an argument
|
|
16
|
+
* buffer and no indirect draw to read one. Emulating it means reading the buffer back to the
|
|
17
|
+
* processor and issuing the draws from there, which is slower than the ordinary path it would be
|
|
18
|
+
* pretending to replace — so this reports false and the GPU-driven pipeline is WebGPU-only.
|
|
19
|
+
*/
|
|
20
|
+
export function indirectSupport(backend) {
|
|
21
|
+
return backend === 'webgpu';
|
|
22
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What a frame asked of a backend, against what that backend allows.
|
|
3
3
|
*
|
|
4
|
-
* **This exists because a ceiling firing was unobservable.** The WebGPU backend holds
|
|
5
|
-
* ceilings — draws, material changes,
|
|
6
|
-
* effect batch and
|
|
7
|
-
* `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and
|
|
8
|
-
* So a scene over a ceiling renders differently on the two backends, silently,
|
|
9
|
-
* developing against WebGL2
|
|
4
|
+
* **This exists because a ceiling firing was unobservable.** The WebGPU backend holds fourteen
|
|
5
|
+
* per-frame ceilings — draws, material changes, two kinds of shadow draw, water bodies, light
|
|
6
|
+
* volumes, four kinds of effect batch and four kinds of overlay — and past any of them it skips the
|
|
7
|
+
* work and writes one `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and
|
|
8
|
+
* draws everything. So a scene over a ceiling renders differently on the two backends, silently,
|
|
9
|
+
* and a consumer developing against WebGL2 had no way to see it coming — which is why WebGL2 counts
|
|
10
|
+
* the same fifteen lines by the same rules, and reports the number the other backend rations.
|
|
10
11
|
*
|
|
11
12
|
* **The cost of that was measured from outside.** A consumer spent weeks on ground that
|
|
12
13
|
* vanished and reappeared as the camera moved; its own report still lists, as the decisive
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What a frame asked of a backend, against what that backend allows.
|
|
3
3
|
*
|
|
4
|
-
* **This exists because a ceiling firing was unobservable.** The WebGPU backend holds
|
|
5
|
-
* ceilings — draws, material changes,
|
|
6
|
-
* effect batch and
|
|
7
|
-
* `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and
|
|
8
|
-
* So a scene over a ceiling renders differently on the two backends, silently,
|
|
9
|
-
* developing against WebGL2
|
|
4
|
+
* **This exists because a ceiling firing was unobservable.** The WebGPU backend holds fourteen
|
|
5
|
+
* per-frame ceilings — draws, material changes, two kinds of shadow draw, water bodies, light
|
|
6
|
+
* volumes, four kinds of effect batch and four kinds of overlay — and past any of them it skips the
|
|
7
|
+
* work and writes one `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and
|
|
8
|
+
* draws everything. So a scene over a ceiling renders differently on the two backends, silently,
|
|
9
|
+
* and a consumer developing against WebGL2 had no way to see it coming — which is why WebGL2 counts
|
|
10
|
+
* the same fifteen lines by the same rules, and reports the number the other backend rations.
|
|
10
11
|
*
|
|
11
12
|
* **The cost of that was measured from outside.** A consumer spent weeks on ground that
|
|
12
13
|
* vanished and reappeared as the camera moved; its own report still lists, as the decisive
|
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
import { type RenderQualityOptions } from '../renderQuality.ts';
|
|
2
2
|
import type { RenderBackend, RendererApi } from './api.ts';
|
|
3
3
|
import { type SplashOptions } from '../../ui/splash.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Which of the two pipelines is drawing.
|
|
6
|
+
*
|
|
7
|
+
* A union rather than a boolean because a third is foreseeable and a boolean named for one of them
|
|
8
|
+
* is what makes the third awkward — `ROADMAP.md`'s own note about `hdrScene` starting life as
|
|
9
|
+
* `bool hdr`.
|
|
10
|
+
*/
|
|
11
|
+
export type RenderPipeline = 'forward' | 'gpu-driven';
|
|
12
|
+
/**
|
|
13
|
+
* What a caller who says nothing gets.
|
|
14
|
+
*
|
|
15
|
+
* **A named constant rather than a literal in the `??`**, because the literal is unreachable from
|
|
16
|
+
* a test here: nothing in this environment resolves a renderer, so flipping it changed no answer
|
|
17
|
+
* and no test noticed. The constant is where the decision lives and it is asserted directly.
|
|
18
|
+
*
|
|
19
|
+
* Forward, and it stays forward until the second pipeline has drawn the six published scenes.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_PIPELINE: RenderPipeline;
|
|
22
|
+
/**
|
|
23
|
+
* Why a requested pipeline cannot run on the backend that is about to draw, or null where it can.
|
|
24
|
+
*
|
|
25
|
+
* **Its own function because it is the only part of the decision a test in this environment can
|
|
26
|
+
* reach.** Nothing here can resolve a renderer — there is no GL context and no adapter — so every
|
|
27
|
+
* test of `createRenderer` ends in a rejection, and a check that lives only inside the factory is
|
|
28
|
+
* a check nothing exercises. `built` is this function's one caller and every return from the
|
|
29
|
+
* factory passes through it.
|
|
30
|
+
*
|
|
31
|
+
* **The backend is the one that will draw, not the one that was asked for.** Three paths into
|
|
32
|
+
* `built` arrive having fallen back from WebGPU, and a check written against the request passes on
|
|
33
|
+
* all three.
|
|
34
|
+
*/
|
|
35
|
+
export declare function pipelineRefusal(pipeline: RenderPipeline, backend: RenderBackend, reason: string): string | null;
|
|
4
36
|
/** Everything about selection a caller may want to decide instead of inherit. */
|
|
5
37
|
export interface CreateRendererOptions {
|
|
6
38
|
/**
|
|
@@ -19,6 +51,23 @@ export interface CreateRendererOptions {
|
|
|
19
51
|
* shows that, and the fallback is silent when it happens.
|
|
20
52
|
*/
|
|
21
53
|
readonly preferWebGpu?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Which pipeline to draw with. **Defaults to `'forward'`.**
|
|
56
|
+
*
|
|
57
|
+
* `'gpu-driven'` selects the cluster pipeline: instances and clusters culled on the device
|
|
58
|
+
* against a depth pyramid built this frame, a visibility buffer, and one shading dispatch per
|
|
59
|
+
* material. It needs indirect draws and dispatches, which WebGL2 does not have.
|
|
60
|
+
*
|
|
61
|
+
* **Asking for it where it cannot run throws.** Not a warning and not a fallback: a silent
|
|
62
|
+
* fallback means a consumer ships believing they have a pipeline they do not, and the difference
|
|
63
|
+
* only shows as a frame time on somebody else's machine. The throw carries the reason in words,
|
|
64
|
+
* from `gpuDrivenRefusal`.
|
|
65
|
+
*
|
|
66
|
+
* **This includes a WebGPU request that fell back**, which is the case a check written against
|
|
67
|
+
* the *asked-for* backend would miss: every fallback path here is a path where the pipeline
|
|
68
|
+
* became unavailable after the choice was made.
|
|
69
|
+
*/
|
|
70
|
+
readonly pipeline?: RenderPipeline;
|
|
22
71
|
/**
|
|
23
72
|
* The query string to read `?backend=` from. Defaults to the document's own.
|
|
24
73
|
*
|
|
@@ -116,6 +165,14 @@ export interface CreatedRenderer {
|
|
|
116
165
|
* renderer knows.
|
|
117
166
|
*/
|
|
118
167
|
readonly reversedDepth: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Which pipeline is drawing: the forward path, or the one driven from buffers the GPU wrote.
|
|
170
|
+
*
|
|
171
|
+
* Reported for the same reason `backend` is — a consumer who asked for one and got the other
|
|
172
|
+
* has to be able to find out. They cannot, here: asking for `gpu-driven` on a backend that
|
|
173
|
+
* cannot run it throws rather than answering `forward`. See `CreateRendererOptions.pipeline`.
|
|
174
|
+
*/
|
|
175
|
+
readonly pipeline: RenderPipeline;
|
|
119
176
|
}
|
|
120
177
|
/**
|
|
121
178
|
* Build a renderer on the best backend this browser will actually give us.
|
|
@@ -3,6 +3,35 @@ import { resolveRenderQuality } from '../renderQuality.js';
|
|
|
3
3
|
import { BACKEND_TIMEOUT_MS, forcedBackend, selectBackend } from './select.js';
|
|
4
4
|
import { TIMED_OUT, withDeadline } from './deadline.js';
|
|
5
5
|
import { mountSplash } from '../../ui/splash.js';
|
|
6
|
+
import { gpuDrivenRefusal, gpuDrivenSupported } from '../gpudriven/pipeline.js';
|
|
7
|
+
/**
|
|
8
|
+
* What a caller who says nothing gets.
|
|
9
|
+
*
|
|
10
|
+
* **A named constant rather than a literal in the `??`**, because the literal is unreachable from
|
|
11
|
+
* a test here: nothing in this environment resolves a renderer, so flipping it changed no answer
|
|
12
|
+
* and no test noticed. The constant is where the decision lives and it is asserted directly.
|
|
13
|
+
*
|
|
14
|
+
* Forward, and it stays forward until the second pipeline has drawn the six published scenes.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_PIPELINE = 'forward';
|
|
17
|
+
/**
|
|
18
|
+
* Why a requested pipeline cannot run on the backend that is about to draw, or null where it can.
|
|
19
|
+
*
|
|
20
|
+
* **Its own function because it is the only part of the decision a test in this environment can
|
|
21
|
+
* reach.** Nothing here can resolve a renderer — there is no GL context and no adapter — so every
|
|
22
|
+
* test of `createRenderer` ends in a rejection, and a check that lives only inside the factory is
|
|
23
|
+
* a check nothing exercises. `built` is this function's one caller and every return from the
|
|
24
|
+
* factory passes through it.
|
|
25
|
+
*
|
|
26
|
+
* **The backend is the one that will draw, not the one that was asked for.** Three paths into
|
|
27
|
+
* `built` arrive having fallen back from WebGPU, and a check written against the request passes on
|
|
28
|
+
* all three.
|
|
29
|
+
*/
|
|
30
|
+
export function pipelineRefusal(pipeline, backend, reason) {
|
|
31
|
+
if (pipeline !== 'gpu-driven' || gpuDrivenSupported(backend))
|
|
32
|
+
return null;
|
|
33
|
+
return `[driftengine] ${gpuDrivenRefusal(backend)} (${reason})`;
|
|
34
|
+
}
|
|
6
35
|
/**
|
|
7
36
|
* Hand the badge the one fact it is waiting for: a frame reached the screen.
|
|
8
37
|
*
|
|
@@ -60,7 +89,22 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
60
89
|
* the two failure paths — a fallback still paints, and a badge that outlived a fallback would
|
|
61
90
|
* sit on the screen until the cap for a game that was running perfectly well underneath it.
|
|
62
91
|
*/
|
|
92
|
+
const pipeline = options.pipeline ?? DEFAULT_PIPELINE;
|
|
63
93
|
const built = (result) => {
|
|
94
|
+
/*
|
|
95
|
+
* **Checked here rather than at the top, because every return passes through here.** The
|
|
96
|
+
* question is not which backend was *asked for* — it is which one is about to draw, and three
|
|
97
|
+
* of the paths into this function arrive having fallen back. A check against the request would
|
|
98
|
+
* pass on all three and hand back a forward renderer with `pipeline: 'gpu-driven'` on it.
|
|
99
|
+
*
|
|
100
|
+
* The splash goes down first. A page that throws out of `createRenderer` with a badge mounted
|
|
101
|
+
* leaves it on screen over nothing, for as long as the tab is open.
|
|
102
|
+
*/
|
|
103
|
+
const refused = pipelineRefusal(pipeline, result.backend, result.reason);
|
|
104
|
+
if (refused !== null) {
|
|
105
|
+
splash?.present();
|
|
106
|
+
throw new Error(refused);
|
|
107
|
+
}
|
|
64
108
|
if (splash !== null)
|
|
65
109
|
presentOnFirstFrame(result.renderer, splash);
|
|
66
110
|
/*
|
|
@@ -80,6 +124,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
80
124
|
...result,
|
|
81
125
|
rendererName: result.renderer.rendererName,
|
|
82
126
|
reversedDepth: result.renderer.reversedDepth,
|
|
127
|
+
pipeline,
|
|
83
128
|
};
|
|
84
129
|
};
|
|
85
130
|
/*
|
|
@@ -93,7 +138,11 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
93
138
|
* the promise the deadline was racing.
|
|
94
139
|
*/
|
|
95
140
|
const budgetMs = options.backendTimeoutMs ?? BACKEND_TIMEOUT_MS;
|
|
96
|
-
|
|
141
|
+
/* Monotonic, and it has to be: `budgetMs - spent` below subtracts two readings. The wall clock
|
|
142
|
+
steps — daylight saving, an NTP correction, a laptop resuming with a stale clock — and a
|
|
143
|
+
forward step makes `spent` exceed the budget, so the engine falls back to WebGL2 reporting
|
|
144
|
+
"WebGPU stalled" about a device that was fine. */
|
|
145
|
+
const startedAt = performance.now();
|
|
97
146
|
const choice = await selectBackend(search, options.preferWebGpu ?? true, quality.gpuTiming ?? false, options.probeShaders ?? [], budgetMs);
|
|
98
147
|
if (choice.backend === 'webgpu' && choice.device !== null) {
|
|
99
148
|
/*
|
|
@@ -131,7 +180,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
|
|
|
131
180
|
stage = 'constructing the renderer';
|
|
132
181
|
return { surface, WebGPURenderer };
|
|
133
182
|
})();
|
|
134
|
-
const spent =
|
|
183
|
+
const spent = performance.now() - startedAt;
|
|
135
184
|
const settled = await withDeadline(construction, budgetMs - spent);
|
|
136
185
|
if (settled === TIMED_OUT) {
|
|
137
186
|
device.destroy();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What counts as a material change: the rule both backends count their `materials` line by.
|
|
3
|
+
*
|
|
4
|
+
* **A material is the shading state a draw reads that is not its own placement**, and the WebGPU
|
|
5
|
+
* backend keeps it in a ring of per-frame slots: a draw copies the open material into a new slot
|
|
6
|
+
* when something has changed it since the last draw, and otherwise shares the slot before it. So
|
|
7
|
+
* the slots a frame takes are its material changes, and that is what the backend's ceiling
|
|
8
|
+
* rations. WebGL2 sets the same state as loose uniforms and has nothing to run out of — but a
|
|
9
|
+
* consumer developing there is building the frame the other backend will ration, so it counts the
|
|
10
|
+
* same changes by the same rule, and draws them all.
|
|
11
|
+
*
|
|
12
|
+
* **What changes it**: a material setter; the start of a frame or of a mesh pass, which reopens
|
|
13
|
+
* the pass's own material; a probe bake, which sets its own and puts the pass's back; and a draw
|
|
14
|
+
* carrying options of its own (`ownsMaterial`), whose state is written for it and restored after
|
|
15
|
+
* it, so that it and the draw after it each open one.
|
|
16
|
+
*
|
|
17
|
+
* What it gives up: a setter called with the value already set still counts, because it takes a
|
|
18
|
+
* slot on the backend that keeps slots, and comparing every field would cost more than the slot.
|
|
19
|
+
*/
|
|
20
|
+
/** What of a draw's own options its material carries. */
|
|
21
|
+
export interface DrawMaterialOptions {
|
|
22
|
+
readonly opacity: number;
|
|
23
|
+
readonly lit: boolean;
|
|
24
|
+
readonly fog: boolean;
|
|
25
|
+
readonly toneMapped: boolean;
|
|
26
|
+
/** Whether the draw refracts this time, which a backend decides by whether it has a snapshot. */
|
|
27
|
+
readonly refracting: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** Whether a draw's options differ from the pass's, so it takes a material and leaves one to restore. */
|
|
30
|
+
export declare function ownsMaterial(options: DrawMaterialOptions): boolean;
|
|
31
|
+
/** Whether the next draw shares the open material or opens a new one. */
|
|
32
|
+
export declare class MaterialChanges {
|
|
33
|
+
/**
|
|
34
|
+
* The slot the open material occupies on a backend that keeps slots, or -1 when the next draw
|
|
35
|
+
* opens one. A backend without slots writes 0 when it opens one.
|
|
36
|
+
*/
|
|
37
|
+
slot: number;
|
|
38
|
+
get open(): boolean;
|
|
39
|
+
/** Something the material holds changed, or a pass reopened it: the next draw opens a new one. */
|
|
40
|
+
dirty(): void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What counts as a material change: the rule both backends count their `materials` line by.
|
|
3
|
+
*
|
|
4
|
+
* **A material is the shading state a draw reads that is not its own placement**, and the WebGPU
|
|
5
|
+
* backend keeps it in a ring of per-frame slots: a draw copies the open material into a new slot
|
|
6
|
+
* when something has changed it since the last draw, and otherwise shares the slot before it. So
|
|
7
|
+
* the slots a frame takes are its material changes, and that is what the backend's ceiling
|
|
8
|
+
* rations. WebGL2 sets the same state as loose uniforms and has nothing to run out of — but a
|
|
9
|
+
* consumer developing there is building the frame the other backend will ration, so it counts the
|
|
10
|
+
* same changes by the same rule, and draws them all.
|
|
11
|
+
*
|
|
12
|
+
* **What changes it**: a material setter; the start of a frame or of a mesh pass, which reopens
|
|
13
|
+
* the pass's own material; a probe bake, which sets its own and puts the pass's back; and a draw
|
|
14
|
+
* carrying options of its own (`ownsMaterial`), whose state is written for it and restored after
|
|
15
|
+
* it, so that it and the draw after it each open one.
|
|
16
|
+
*
|
|
17
|
+
* What it gives up: a setter called with the value already set still counts, because it takes a
|
|
18
|
+
* slot on the backend that keeps slots, and comparing every field would cost more than the slot.
|
|
19
|
+
*/
|
|
20
|
+
/** Whether a draw's options differ from the pass's, so it takes a material and leaves one to restore. */
|
|
21
|
+
export function ownsMaterial(options) {
|
|
22
|
+
return (options.opacity < 1 || !options.lit || !options.fog || !options.toneMapped || options.refracting);
|
|
23
|
+
}
|
|
24
|
+
/** Whether the next draw shares the open material or opens a new one. */
|
|
25
|
+
export class MaterialChanges {
|
|
26
|
+
/**
|
|
27
|
+
* The slot the open material occupies on a backend that keeps slots, or -1 when the next draw
|
|
28
|
+
* opens one. A backend without slots writes 0 when it opens one.
|
|
29
|
+
*/
|
|
30
|
+
slot = -1;
|
|
31
|
+
get open() {
|
|
32
|
+
return this.slot >= 0;
|
|
33
|
+
}
|
|
34
|
+
/** Something the material holds changed, or a pass reopened it: the next draw opens a new one. */
|
|
35
|
+
dirty() {
|
|
36
|
+
this.slot = -1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -160,11 +160,19 @@ async function acquireWebGpu(gpu, wantsGpuTiming, shaders, stage) {
|
|
|
160
160
|
* the default still refuses the model, and `WebGPURenderer.createMesh` says so in one line
|
|
161
161
|
* rather than letting the driver say it a hundred times.
|
|
162
162
|
*/
|
|
163
|
+
/*
|
|
164
|
+
* **And the storage binding ceiling, for the same reason one level down.** A buffer that can be
|
|
165
|
+
* created is not a buffer that can be bound: `maxStorageBufferBindingSize` defaults to 128 MiB
|
|
166
|
+
* against this machine's 4 GiB, and the GPU-driven pipeline binds its whole vertex buffer as
|
|
167
|
+
* one storage binding. The voxel sandbox's port at a radius of ten asked for 262,807,200 bytes
|
|
168
|
+
* and came back as a hundred device warnings and a world with no terrain.
|
|
169
|
+
*/
|
|
163
170
|
const required = {};
|
|
164
171
|
for (const limit of [
|
|
165
172
|
'maxSampledTexturesPerShaderStage',
|
|
166
173
|
'maxSamplersPerShaderStage',
|
|
167
174
|
'maxBufferSize',
|
|
175
|
+
'maxStorageBufferBindingSize',
|
|
168
176
|
]) {
|
|
169
177
|
const ceiling = adapter.limits[limit];
|
|
170
178
|
if (typeof ceiling === 'number' && ceiling > 0)
|