@forgeax/engine-runtime 0.1.2
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/LICENSE +202 -0
- package/README.md +183 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/active-camera.unit.test.d.ts +2 -0
- package/dist/__tests__/active-camera.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-add.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-add.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-asset-union.test-d.d.ts +2 -0
- package/dist/__tests__/animation-graph-asset-union.test-d.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-blend.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-blend.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-build.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-build.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-clip-missing.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-clip-missing.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-clip.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-clip.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-default-path.integration.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-default-path.integration.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-describe.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-describe.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-errors.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-errors.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-nesting.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-nesting.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-orthogonal-weight.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-orthogonal-weight.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-slot-fill.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-slot-fill.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-nslot.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-nslot.unit.test.d.ts.map +1 -0
- package/dist/__tests__/animation-slot-length-guard.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-slot-length-guard.unit.test.d.ts.map +1 -0
- package/dist/__tests__/append-injection.test.d.ts +2 -0
- package/dist/__tests__/append-injection.test.d.ts.map +1 -0
- package/dist/__tests__/asi-world-baseline-export.unit.test.d.ts +2 -0
- package/dist/__tests__/asi-world-baseline-export.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asi-world-ci-config.unit.test.d.ts +2 -0
- package/dist/__tests__/asi-world-ci-config.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asi-world-smoke.unit.test.d.ts +2 -0
- package/dist/__tests__/asi-world-smoke.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-scene.test-d.d.ts +2 -0
- package/dist/__tests__/asset-registry-scene.test-d.d.ts.map +1 -0
- package/dist/__tests__/bind-group-cache-binding.test.d.ts +2 -0
- package/dist/__tests__/bind-group-cache-binding.test.d.ts.map +1 -0
- package/dist/__tests__/bind-group-cache-frame.test.d.ts +2 -0
- package/dist/__tests__/bind-group-cache-frame.test.d.ts.map +1 -0
- package/dist/__tests__/bind-group-cache-keying.test.d.ts +2 -0
- package/dist/__tests__/bind-group-cache-keying.test.d.ts.map +1 -0
- package/dist/__tests__/block-upload-math.unit.test.d.ts +2 -0
- package/dist/__tests__/block-upload-math.unit.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-shader-register-e2e.test.d.ts +2 -0
- package/dist/__tests__/builtin-shader-register-e2e.test.d.ts.map +1 -0
- package/dist/__tests__/cache-false-eviction.test.d.ts +2 -0
- package/dist/__tests__/cache-false-eviction.test.d.ts.map +1 -0
- package/dist/__tests__/cache-isolation-matrix.test.d.ts +2 -0
- package/dist/__tests__/cache-isolation-matrix.test.d.ts.map +1 -0
- package/dist/__tests__/camera-clear-snapshot-equivalence.unit.test.d.ts +2 -0
- package/dist/__tests__/camera-clear-snapshot-equivalence.unit.test.d.ts.map +1 -0
- package/dist/__tests__/clamp-to-last.e2e.browser.test.d.ts +2 -0
- package/dist/__tests__/clamp-to-last.e2e.browser.test.d.ts.map +1 -0
- package/dist/__tests__/clamp-to-last.e2e.dawn.test.d.ts +2 -0
- package/dist/__tests__/clamp-to-last.e2e.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/collect-scene-asset.test.d.ts +3 -0
- package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -0
- package/dist/__tests__/collect-subtree.unit.test.d.ts +2 -0
- package/dist/__tests__/collect-subtree.unit.test.d.ts.map +1 -0
- package/dist/__tests__/collect-transient-children-absent.test.d.ts +2 -0
- package/dist/__tests__/collect-transient-children-absent.test.d.ts.map +1 -0
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/collect-transient-skip.test.d.ts +3 -0
- package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -0
- package/dist/__tests__/components.test-d.d.ts +2 -0
- package/dist/__tests__/components.test-d.d.ts.map +1 -0
- package/dist/__tests__/components.unit.test.d.ts +2 -0
- package/dist/__tests__/components.unit.test.d.ts.map +1 -0
- package/dist/__tests__/composite-skybox-cross-world.browser.test.d.ts +2 -0
- package/dist/__tests__/composite-skybox-cross-world.browser.test.d.ts.map +1 -0
- package/dist/__tests__/create-renderer-assembly.integration.test.d.ts +2 -0
- package/dist/__tests__/create-renderer-assembly.integration.test.d.ts.map +1 -0
- package/dist/__tests__/createRenderer-dispose.test.d.ts +2 -0
- package/dist/__tests__/createRenderer-dispose.test.d.ts.map +1 -0
- package/dist/__tests__/createRenderer-requiredFeatures.unit.test.d.ts +2 -0
- package/dist/__tests__/createRenderer-requiredFeatures.unit.test.d.ts.map +1 -0
- package/dist/__tests__/createRenderer.browser-no-webgpu.test.d.ts +2 -0
- package/dist/__tests__/createRenderer.browser-no-webgpu.test.d.ts.map +1 -0
- package/dist/__tests__/createRenderer.unit.test.d.ts +2 -0
- package/dist/__tests__/createRenderer.unit.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/ibl-compose.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/ibl-compose.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/ibl-modules-compose.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/ibl-modules-compose.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/ibl-precompute-readback.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/ibl-precompute-readback.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/instances-per-instance-pbr.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/instances-per-instance-pbr.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/instances-shadow.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/instances-shadow.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/instances-uniform-fallback.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/instances-uniform-fallback.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/material-alpha.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/material-alpha.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/material-cooked-fixture.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/material-cooked-fixture.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/mipmap-srgb-linear.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/mipmap-srgb-linear.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/tonemap.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/tonemap.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/user-handle-mesh-render.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/user-handle-mesh-render.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/user-mesh-upload.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/user-mesh-upload.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/zero-manifest-ready.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/zero-manifest-ready.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/demo-sortscope-migration.unit.test.d.ts +2 -0
- package/dist/__tests__/demo-sortscope-migration.unit.test.d.ts.map +1 -0
- package/dist/__tests__/derive-bgl-integration.test.d.ts +2 -0
- package/dist/__tests__/derive-bgl-integration.test.d.ts.map +1 -0
- package/dist/__tests__/derive-render-data-skin.unit.test.d.ts +2 -0
- package/dist/__tests__/derive-render-data-skin.unit.test.d.ts.map +1 -0
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts +2 -0
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts +2 -0
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts +2 -0
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts +2 -0
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts.map +1 -0
- package/dist/__tests__/draw-published.d.ts +5 -0
- package/dist/__tests__/draw-published.d.ts.map +1 -0
- package/dist/__tests__/environment-error-exhaustive.test-d.d.ts +8 -0
- package/dist/__tests__/environment-error-exhaustive.test-d.d.ts.map +1 -0
- package/dist/__tests__/equirect-bc6h.integration.test.d.ts +2 -0
- package/dist/__tests__/equirect-bc6h.integration.test.d.ts.map +1 -0
- package/dist/__tests__/error-exhaustive.test.d.ts +2 -0
- package/dist/__tests__/error-exhaustive.test.d.ts.map +1 -0
- package/dist/__tests__/extract-frames-graceful-degradation.test.d.ts +2 -0
- package/dist/__tests__/extract-frames-graceful-degradation.test.d.ts.map +1 -0
- package/dist/__tests__/extract-frames-merge.test.d.ts +2 -0
- package/dist/__tests__/extract-frames-merge.test.d.ts.map +1 -0
- package/dist/__tests__/extract-frames-reset.test.d.ts +2 -0
- package/dist/__tests__/extract-frames-reset.test.d.ts.map +1 -0
- package/dist/__tests__/extract-record-no-hardcoded-texture-fields.test.d.ts +2 -0
- package/dist/__tests__/extract-record-no-hardcoded-texture-fields.test.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-manifest.d.ts +131 -0
- package/dist/__tests__/fog-producer-manifest.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-pixel-probe.d.ts +42 -0
- package/dist/__tests__/fog-producer-pixel-probe.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts +2 -0
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts +2 -0
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-real-fixture.d.ts +5 -0
- package/dist/__tests__/fog-producer-real-fixture.d.ts.map +1 -0
- package/dist/__tests__/fog-producer-vfx-effect.d.ts +3 -0
- package/dist/__tests__/fog-producer-vfx-effect.d.ts.map +1 -0
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts +2 -0
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts.map +1 -0
- package/dist/__tests__/frame-targets-shadow-regression.unit.test.d.ts +2 -0
- package/dist/__tests__/frame-targets-shadow-regression.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fullscreen-post-bgl-depth.test.d.ts +2 -0
- package/dist/__tests__/fullscreen-post-bgl-depth.test.d.ts.map +1 -0
- package/dist/__tests__/fullscreen-post-depth-params-arity.test.d.ts +2 -0
- package/dist/__tests__/fullscreen-post-depth-params-arity.test.d.ts.map +1 -0
- package/dist/__tests__/fullscreen-post-process-pass.dawn.test.d.ts +2 -0
- package/dist/__tests__/fullscreen-post-process-pass.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/fullscreen-post-process-pass.unit.test.d.ts +2 -0
- package/dist/__tests__/fullscreen-post-process-pass.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fxaa-pixel-diff.dawn.test.d.ts +2 -0
- package/dist/__tests__/fxaa-pixel-diff.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/fxaa-validation-and-resize.dawn.test.d.ts +2 -0
- package/dist/__tests__/fxaa-validation-and-resize.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/fxaa-zero-overhead.dawn.test.d.ts +2 -0
- package/dist/__tests__/fxaa-zero-overhead.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/geometry.unit.test.d.ts +2 -0
- package/dist/__tests__/geometry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/glyph-tilemap-worldid.test.d.ts +2 -0
- package/dist/__tests__/glyph-tilemap-worldid.test.d.ts.map +1 -0
- package/dist/__tests__/gpu-resource-cow-survivor.test.d.ts +2 -0
- package/dist/__tests__/gpu-resource-cow-survivor.test.d.ts.map +1 -0
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts +2 -0
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts.map +1 -0
- package/dist/__tests__/gpu-resource.test.d.ts +2 -0
- package/dist/__tests__/gpu-resource.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts +2 -0
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts +2 -0
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts +2 -0
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts +2 -0
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts +2 -0
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts.map +1 -0
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts +2 -0
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts.map +1 -0
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts +2 -0
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts.map +1 -0
- package/dist/__tests__/hello-tilemap-smoke-upgrade.unit.test.d.ts +2 -0
- package/dist/__tests__/hello-tilemap-smoke-upgrade.unit.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/mock-shader-registry.d.ts +11 -0
- package/dist/__tests__/helpers/mock-shader-registry.d.ts.map +1 -0
- package/dist/__tests__/helpers/primitive-world.d.ts +8 -0
- package/dist/__tests__/helpers/primitive-world.d.ts.map +1 -0
- package/dist/__tests__/helpers/register-runtime-components.d.ts +4 -0
- package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -0
- package/dist/__tests__/helpers/register-scene-components.d.ts +4 -0
- package/dist/__tests__/helpers/register-scene-components.d.ts.map +1 -0
- package/dist/__tests__/helpers/render-asset-port.d.ts +15 -0
- package/dist/__tests__/helpers/render-asset-port.d.ts.map +1 -0
- package/dist/__tests__/helpers/scene-asset-port.d.ts +9 -0
- package/dist/__tests__/helpers/scene-asset-port.d.ts.map +1 -0
- package/dist/__tests__/helpers/tilemap-assets.d.ts +6 -0
- package/dist/__tests__/helpers/tilemap-assets.d.ts.map +1 -0
- package/dist/__tests__/instances.test-d.d.ts +2 -0
- package/dist/__tests__/instances.test-d.d.ts.map +1 -0
- package/dist/__tests__/light-attenuation-formula.test.d.ts +2 -0
- package/dist/__tests__/light-attenuation-formula.test.d.ts.map +1 -0
- package/dist/__tests__/light-casters-9-light.browser.test.d.ts +2 -0
- package/dist/__tests__/light-casters-9-light.browser.test.d.ts.map +1 -0
- package/dist/__tests__/light-gpu-byte-neutral.unit.test.d.ts +2 -0
- package/dist/__tests__/light-gpu-byte-neutral.unit.test.d.ts.map +1 -0
- package/dist/__tests__/light-snapshot.test-d.d.ts +2 -0
- package/dist/__tests__/light-snapshot.test-d.d.ts.map +1 -0
- package/dist/__tests__/lights-vec-negative.unit.test.d.ts +2 -0
- package/dist/__tests__/lights-vec-negative.unit.test.d.ts.map +1 -0
- package/dist/__tests__/lights.unit.test.d.ts +2 -0
- package/dist/__tests__/lights.unit.test.d.ts.map +1 -0
- package/dist/__tests__/m3-vec-negative.unit.test.d.ts +2 -0
- package/dist/__tests__/m3-vec-negative.unit.test.d.ts.map +1 -0
- package/dist/__tests__/m5-browser-dawn-sweep.integration.test.d.ts +2 -0
- package/dist/__tests__/m5-browser-dawn-sweep.integration.test.d.ts.map +1 -0
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts +2 -0
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts.map +1 -0
- package/dist/__tests__/material-texture-uv-scale.unit.test.d.ts +2 -0
- package/dist/__tests__/material-texture-uv-scale.unit.test.d.ts.map +1 -0
- package/dist/__tests__/materials.unit.test.d.ts +2 -0
- package/dist/__tests__/materials.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-ssbo-grow.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-ssbo-grow.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mip-gate.unit.test.d.ts +2 -0
- package/dist/__tests__/mip-gate.unit.test.d.ts.map +1 -0
- package/dist/__tests__/msaa-sprite-pixel-diff.dawn.test.d.ts +2 -0
- package/dist/__tests__/msaa-sprite-pixel-diff.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/multi-uv-8set.e2e.dawn.test.d.ts +2 -0
- package/dist/__tests__/multi-uv-8set.e2e.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/name.unit.test.d.ts +2 -0
- package/dist/__tests__/name.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pass-selector.unit.test.d.ts +2 -0
- package/dist/__tests__/pass-selector.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pbr-pipeline.unit.test.d.ts +2 -0
- package/dist/__tests__/pbr-pipeline.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline-builder-msaa.unit.test.d.ts +2 -0
- package/dist/__tests__/pipeline-builder-msaa.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline-cache-keying.unit.test.d.ts +2 -0
- package/dist/__tests__/pipeline-cache-keying.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline-layout-selection.test.d.ts +2 -0
- package/dist/__tests__/pipeline-layout-selection.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline-spec.test.d.ts +2 -0
- package/dist/__tests__/pipeline-spec.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline.unit.test.d.ts +2 -0
- package/dist/__tests__/pipeline.unit.test.d.ts.map +1 -0
- package/dist/__tests__/point-light-shadow.browser.test.d.ts +2 -0
- package/dist/__tests__/point-light-shadow.browser.test.d.ts.map +1 -0
- package/dist/__tests__/point-light-shadow.dawn.test.d.ts +2 -0
- package/dist/__tests__/point-light-shadow.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/point-light-shadow.unit.test.d.ts +2 -0
- package/dist/__tests__/point-light-shadow.unit.test.d.ts.map +1 -0
- package/dist/__tests__/post-process-error-codes.unit.test.d.ts +2 -0
- package/dist/__tests__/post-process-error-codes.unit.test.d.ts.map +1 -0
- package/dist/__tests__/post-process-params-component.unit.test.d.ts +2 -0
- package/dist/__tests__/post-process-params-component.unit.test.d.ts.map +1 -0
- package/dist/__tests__/post-process-params-extract.unit.test.d.ts +2 -0
- package/dist/__tests__/post-process-params-extract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts +2 -0
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts.map +1 -0
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts +2 -0
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/postprocess-camera-consistency.test.d.ts +2 -0
- package/dist/__tests__/postprocess-camera-consistency.test.d.ts.map +1 -0
- package/dist/__tests__/profiler-assembly.integration.test.d.ts +2 -0
- package/dist/__tests__/profiler-assembly.integration.test.d.ts.map +1 -0
- package/dist/__tests__/propagate-transforms.dawn.test.d.ts +2 -0
- package/dist/__tests__/propagate-transforms.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/record-worldid-isolation.test.d.ts +2 -0
- package/dist/__tests__/record-worldid-isolation.test.d.ts.map +1 -0
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +11 -0
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -0
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts +11 -0
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -0
- package/dist/__tests__/render-feature-assembly.test-d.d.ts +2 -0
- package/dist/__tests__/render-feature-assembly.test-d.d.ts.map +1 -0
- package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts +2 -0
- package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-feature-prepared-graphics.browser.test.d.ts +2 -0
- package/dist/__tests__/render-feature-prepared-graphics.browser.test.d.ts.map +1 -0
- package/dist/__tests__/render-feature-prepared-graphics.dawn.test.d.ts +2 -0
- package/dist/__tests__/render-feature-prepared-graphics.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/render-feature-prepared-graphics.integration.test.d.ts +2 -0
- package/dist/__tests__/render-feature-prepared-graphics.integration.test.d.ts.map +1 -0
- package/dist/__tests__/render-feature-prepared-graphics.regression.integration.test.d.ts +2 -0
- package/dist/__tests__/render-feature-prepared-graphics.regression.integration.test.d.ts.map +1 -0
- package/dist/__tests__/render-feature-recover.integration.test.d.ts +2 -0
- package/dist/__tests__/render-feature-recover.integration.test.d.ts.map +1 -0
- package/dist/__tests__/render-feature-runtime-surface.test-d.d.ts +2 -0
- package/dist/__tests__/render-feature-runtime-surface.test-d.d.ts.map +1 -0
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts +2 -0
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts.map +1 -0
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts +2 -0
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/render-schema-consumer.integration.test.d.ts +2 -0
- package/dist/__tests__/render-schema-consumer.integration.test.d.ts.map +1 -0
- package/dist/__tests__/render-schema-owner-boundary.unit.test.d.ts +2 -0
- package/dist/__tests__/render-schema-owner-boundary.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-cross-world-overlay-queue.test.d.ts +2 -0
- package/dist/__tests__/render-system-cross-world-overlay-queue.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-extract-dispatch-ordering.test.d.ts +2 -0
- package/dist/__tests__/render-system-extract-dispatch-ordering.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-extract.test.d.ts +2 -0
- package/dist/__tests__/render-system-extract.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-fold-bucket.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-fold-bucket.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-fold-fallback.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-fold-fallback.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-fold-material.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-fold-material.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-fold-metrics.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-fold-metrics.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-fold-modegate.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-fold-modegate.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-fold-scene-instances.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-fold-scene-instances.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-fold.dawn.test.d.ts +2 -0
- package/dist/__tests__/render-system-fold.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-mega.test.d.ts +2 -0
- package/dist/__tests__/render-system-mega.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-owner-split-contract.test.d.ts +2 -0
- package/dist/__tests__/render-system-owner-split-contract.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-record-multi-material-textureview.test.d.ts +2 -0
- package/dist/__tests__/render-system-record-multi-material-textureview.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-record-per-submesh-transparency.test.d.ts +2 -0
- package/dist/__tests__/render-system-record-per-submesh-transparency.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-record.test.d.ts +2 -0
- package/dist/__tests__/render-system-record.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-record.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-record.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-system-skin-bg.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-skin-bg.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-consumer.test-d.d.ts +2 -0
- package/dist/__tests__/renderer-consumer.test-d.d.ts.map +1 -0
- package/dist/__tests__/renderer-health.unit.test.d.ts +2 -0
- package/dist/__tests__/renderer-health.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-lifecycle.integration.test.d.ts +2 -0
- package/dist/__tests__/renderer-lifecycle.integration.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-recover.unit.test.d.ts +2 -0
- package/dist/__tests__/renderer-recover.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-result.test-d.d.ts +2 -0
- package/dist/__tests__/renderer-result.test-d.d.ts.map +1 -0
- package/dist/__tests__/renderer-surface.unit.test.d.ts +2 -0
- package/dist/__tests__/renderer-surface.unit.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-depth-only-view.test.d.ts +2 -0
- package/dist/__tests__/resolve-depth-only-view.test.d.ts.map +1 -0
- package/dist/__tests__/rhi-null-command-flow.unit.test.d.ts +2 -0
- package/dist/__tests__/rhi-null-command-flow.unit.test.d.ts.map +1 -0
- package/dist/__tests__/rhi-null-noop-behavior.unit.test.d.ts +2 -0
- package/dist/__tests__/rhi-null-noop-behavior.unit.test.d.ts.map +1 -0
- package/dist/__tests__/rhi-null-renderer-lifecycle.unit.test.d.ts +2 -0
- package/dist/__tests__/rhi-null-renderer-lifecycle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/roots-to-scene-asset.test.d.ts +2 -0
- package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -0
- package/dist/__tests__/runtime-authority-scan.unit.test.d.ts +2 -0
- package/dist/__tests__/runtime-authority-scan.unit.test.d.ts.map +1 -0
- package/dist/__tests__/runtime-domain-residue.unit.test.d.ts +2 -0
- package/dist/__tests__/runtime-domain-residue.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-equirect-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/scene-equirect-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/scene-instance-bridge.integration.test.d.ts +2 -0
- package/dist/__tests__/scene-instance-bridge.integration.test.d.ts.map +1 -0
- package/dist/__tests__/scene-instance-component.test.d.ts +2 -0
- package/dist/__tests__/scene-instance-component.test.d.ts.map +1 -0
- package/dist/__tests__/scene-instantiate-cycle-runtime.test.d.ts +2 -0
- package/dist/__tests__/scene-instantiate-cycle-runtime.test.d.ts.map +1 -0
- package/dist/__tests__/serialize-scene-asset.test.d.ts +2 -0
- package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-caster-empty-schema.test.d.ts +2 -0
- package/dist/__tests__/shadow-caster-empty-schema.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-atlas.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-atlas.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-blend.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-blend.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-cascade-loadop.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-cascade-loadop.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-component.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-component.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-extract.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-extract.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-orthoz.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-orthoz.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-pssm.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-pssm.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-runtime-vary.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-runtime-vary.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-shader.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-shader.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-tile-consistency.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-tile-consistency.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-ubo.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-ubo.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-ubo.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-ubo.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-viewport.browser.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-viewport.browser.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-csm-viewport.test.d.ts +2 -0
- package/dist/__tests__/shadow-csm-viewport.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-fields-observable.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-fields-observable.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-m1.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-m1.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-m2.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-m2.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-m3-calibrate.d.ts +83 -0
- package/dist/__tests__/shadow-m3-calibrate.d.ts.map +1 -0
- package/dist/__tests__/shadow-m3.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-m3.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-mesh-ssbo-order.test.d.ts +2 -0
- package/dist/__tests__/shadow-mesh-ssbo-order.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts +2 -0
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/skin-error-exhaustive.test-d.d.ts +11 -0
- package/dist/__tests__/skin-error-exhaustive.test-d.d.ts.map +1 -0
- package/dist/__tests__/skin-errors.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-errors.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-extract-getarrayview-count.unit.test.d.ts +2 -0
- package/dist/__tests__/skin-extract-getarrayview-count.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skin-parented-double-transform.test.d.ts +14 -0
- package/dist/__tests__/skin-parented-double-transform.test.d.ts.map +1 -0
- package/dist/__tests__/skylight-lazy-projection.test.d.ts +2 -0
- package/dist/__tests__/skylight-lazy-projection.test.d.ts.map +1 -0
- package/dist/__tests__/sparse-tag-scene-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/sparse-tag-scene-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-cullmode-flip.dawn.test.d.ts +2 -0
- package/dist/__tests__/sprite-cullmode-flip.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-lit-bgl-byte-identical.test.d.ts +2 -0
- package/dist/__tests__/sprite-lit-bgl-byte-identical.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-lit-extract-branch.test.d.ts +2 -0
- package/dist/__tests__/sprite-lit-extract-branch.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-lit-pipeline-cache-key.test.d.ts +2 -0
- package/dist/__tests__/sprite-lit-pipeline-cache-key.test.d.ts.map +1 -0
- package/dist/__tests__/sprite-param-values.test-d.d.ts +2 -0
- package/dist/__tests__/sprite-param-values.test-d.d.ts.map +1 -0
- package/dist/__tests__/ssao-bgl.test.d.ts +2 -0
- package/dist/__tests__/ssao-bgl.test.d.ts.map +1 -0
- package/dist/__tests__/ssao-buffers.test.d.ts +2 -0
- package/dist/__tests__/ssao-buffers.test.d.ts.map +1 -0
- package/dist/__tests__/ssao-data.test.d.ts +2 -0
- package/dist/__tests__/ssao-data.test.d.ts.map +1 -0
- package/dist/__tests__/ssao-errors.test.d.ts +2 -0
- package/dist/__tests__/ssao-errors.test.d.ts.map +1 -0
- package/dist/__tests__/ssao-manifest.test.d.ts +2 -0
- package/dist/__tests__/ssao-manifest.test.d.ts.map +1 -0
- package/dist/__tests__/ssao-passes.test.d.ts +2 -0
- package/dist/__tests__/ssao-passes.test.d.ts.map +1 -0
- package/dist/__tests__/ssao-pipelines.test.d.ts +2 -0
- package/dist/__tests__/ssao-pipelines.test.d.ts.map +1 -0
- package/dist/__tests__/ssao-uniform-layout.test.d.ts +2 -0
- package/dist/__tests__/ssao-uniform-layout.test.d.ts.map +1 -0
- package/dist/__tests__/static-rig.integration.test.d.ts +2 -0
- package/dist/__tests__/static-rig.integration.test.d.ts.map +1 -0
- package/dist/__tests__/stencil-outline-pixel.dawn.test.d.ts +2 -0
- package/dist/__tests__/stencil-outline-pixel.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/swap-chain-format.unit.test.d.ts +2 -0
- package/dist/__tests__/swap-chain-format.unit.test.d.ts.map +1 -0
- package/dist/__tests__/systems.unit.test.d.ts +2 -0
- package/dist/__tests__/systems.unit.test.d.ts.map +1 -0
- package/dist/__tests__/temporal-off-path.unit.test.d.ts +2 -0
- package/dist/__tests__/temporal-off-path.unit.test.d.ts.map +1 -0
- package/dist/__tests__/text.unit.test.d.ts +2 -0
- package/dist/__tests__/text.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-childed-despawn.test.d.ts +2 -0
- package/dist/__tests__/tilemap-childed-despawn.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-chunk-extract.overhang-bounds.test.d.ts +2 -0
- package/dist/__tests__/tilemap-chunk-extract.overhang-bounds.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-chunk-extract.propagate-order.test.d.ts +2 -0
- package/dist/__tests__/tilemap-chunk-extract.propagate-order.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.d.ts +2 -0
- package/dist/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-chunk-extract.test.d.ts +2 -0
- package/dist/__tests__/tilemap-chunk-extract.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-chunk-extract.unit.test.d.ts +2 -0
- package/dist/__tests__/tilemap-chunk-extract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-chunk-y-sort-bench.unit.test.d.ts +2 -0
- package/dist/__tests__/tilemap-chunk-y-sort-bench.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-dirty-rebuild.test.d.ts +2 -0
- package/dist/__tests__/tilemap-dirty-rebuild.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-material-cache.test.d.ts +2 -0
- package/dist/__tests__/tilemap-material-cache.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-multi-atlas.test.d.ts +2 -0
- package/dist/__tests__/tilemap-multi-atlas.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-owner-boundary.unit.test.d.ts +2 -0
- package/dist/__tests__/tilemap-owner-boundary.unit.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-region-pack.test.d.ts +2 -0
- package/dist/__tests__/tilemap-region-pack.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-spawn-flip-pivot.test.d.ts +2 -0
- package/dist/__tests__/tilemap-spawn-flip-pivot.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-uv-inset.test.d.ts +2 -0
- package/dist/__tests__/tilemap-uv-inset.test.d.ts.map +1 -0
- package/dist/__tests__/tilemap-validate.test.d.ts +2 -0
- package/dist/__tests__/tilemap-validate.test.d.ts.map +1 -0
- package/dist/__tests__/transform-hierarchy-pixel-diff.dawn.test.d.ts +2 -0
- package/dist/__tests__/transform-hierarchy-pixel-diff.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/transient-fields-collect.test.d.ts +2 -0
- package/dist/__tests__/transient-fields-collect.test.d.ts.map +1 -0
- package/dist/__tests__/transitional-authoring.integration.test.d.ts +2 -0
- package/dist/__tests__/transitional-authoring.integration.test.d.ts.map +1 -0
- package/dist/__tests__/transparent-sort-tilemap-sprite-interleave.test.d.ts +2 -0
- package/dist/__tests__/transparent-sort-tilemap-sprite-interleave.test.d.ts.map +1 -0
- package/dist/__tests__/variant-selection.unit.test.d.ts +2 -0
- package/dist/__tests__/variant-selection.unit.test.d.ts.map +1 -0
- package/dist/__tests__/vertex-attribute-layout.test.d.ts +2 -0
- package/dist/__tests__/vertex-attribute-layout.test.d.ts.map +1 -0
- package/dist/__tests__/video-cache-regression.unit.test.d.ts +2 -0
- package/dist/__tests__/video-cache-regression.unit.test.d.ts.map +1 -0
- package/dist/__tests__/video-extract-bindgroup.dawn.test.d.ts +2 -0
- package/dist/__tests__/video-extract-bindgroup.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/view-ubo-layout.browser.test.d.ts +2 -0
- package/dist/__tests__/view-ubo-layout.browser.test.d.ts.map +1 -0
- package/dist/__tests__/world-entity-key.test.d.ts +2 -0
- package/dist/__tests__/world-entity-key.test.d.ts.map +1 -0
- package/dist/__tests__/world-scene-despawn.test.d.ts +2 -0
- package/dist/__tests__/world-scene-despawn.test.d.ts.map +1 -0
- package/dist/__tests__/world-scene-instantiate.test.d.ts +2 -0
- package/dist/__tests__/world-scene-instantiate.test.d.ts.map +1 -0
- package/dist/__tests__/world-scene-nested.test.d.ts +2 -0
- package/dist/__tests__/world-scene-nested.test.d.ts.map +1 -0
- package/dist/__tests__/world-scene-override.test.d.ts +2 -0
- package/dist/__tests__/world-scene-override.test.d.ts.map +1 -0
- package/dist/__tests__/zero-compression-zero-load.integration.test.d.ts +2 -0
- package/dist/__tests__/zero-compression-zero-load.integration.test.d.ts.map +1 -0
- package/dist/asset-contributions.d.ts +3 -0
- package/dist/asset-contributions.d.ts.map +1 -0
- package/dist/asset-kind.d.ts +4 -0
- package/dist/asset-kind.d.ts.map +1 -0
- package/dist/collect-scene-asset.d.ts +16 -0
- package/dist/collect-scene-asset.d.ts.map +1 -0
- package/dist/components/__tests__/camera.test-d.d.ts +2 -0
- package/dist/components/__tests__/camera.test-d.d.ts.map +1 -0
- package/dist/components/__tests__/camera.test.d.ts +2 -0
- package/dist/components/__tests__/camera.test.d.ts.map +1 -0
- package/dist/components/__tests__/child-of.test.d.ts +2 -0
- package/dist/components/__tests__/child-of.test.d.ts.map +1 -0
- package/dist/components/__tests__/sprite-animation.test-d.d.ts +2 -0
- package/dist/components/__tests__/sprite-animation.test-d.d.ts.map +1 -0
- package/dist/components/__tests__/sprite-instances.unit.test.d.ts +2 -0
- package/dist/components/__tests__/sprite-instances.unit.test.d.ts.map +1 -0
- package/dist/components/__tests__/sprite-region-override.test-d.d.ts +2 -0
- package/dist/components/__tests__/sprite-region-override.test-d.d.ts.map +1 -0
- package/dist/components/__tests__/tile-layer.test-d.d.ts +2 -0
- package/dist/components/__tests__/tile-layer.test-d.d.ts.map +1 -0
- package/dist/components/__tests__/tile-layer.unit.test.d.ts +2 -0
- package/dist/components/__tests__/tile-layer.unit.test.d.ts.map +1 -0
- package/dist/components/__tests__/tilemap.test-d.d.ts +2 -0
- package/dist/components/__tests__/tilemap.test-d.d.ts.map +1 -0
- package/dist/components/__tests__/transform-vec-schema.test.d.ts +2 -0
- package/dist/components/__tests__/transform-vec-schema.test.d.ts.map +1 -0
- package/dist/create-renderer-env-classify.d.ts +21 -0
- package/dist/create-renderer-env-classify.d.ts.map +1 -0
- package/dist/createRenderer.d.ts +3 -0
- package/dist/createRenderer.d.ts.map +1 -0
- package/dist/dev-import-transport.d.ts +24 -0
- package/dist/dev-import-transport.d.ts.map +1 -0
- package/dist/errors/environment.d.ts +2 -0
- package/dist/errors/environment.d.ts.map +1 -0
- package/dist/errors/sprite-animation.d.ts +3 -0
- package/dist/errors/sprite-animation.d.ts.map +1 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +814 -0
- package/dist/index.mjs.map +1 -0
- package/dist/scene-asset-port.d.ts +17 -0
- package/dist/scene-asset-port.d.ts.map +1 -0
- package/dist/scene-collect-errors.d.ts +22 -0
- package/dist/scene-collect-errors.d.ts.map +1 -0
- package/dist/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.d.ts +2 -0
- package/dist/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.d.ts.map +1 -0
- package/dist/scene-utils/mount-override-fold.d.ts +16 -0
- package/dist/scene-utils/mount-override-fold.d.ts.map +1 -0
- package/dist/shadow-m3-calibrate.d.ts +40 -0
- package/dist/shadow-m3-calibrate.d.ts.map +1 -0
- package/dist/sprite-param-values.d.ts +62 -0
- package/dist/sprite-param-values.d.ts.map +1 -0
- package/dist/systems/__tests__/_xorshift.d.ts +28 -0
- package/dist/systems/__tests__/_xorshift.d.ts.map +1 -0
- package/dist/systems/__tests__/argsort-in-place.test.d.ts +2 -0
- package/dist/systems/__tests__/argsort-in-place.test.d.ts.map +1 -0
- package/dist/systems/__tests__/transparent-sort.bench.d.ts +2 -0
- package/dist/systems/__tests__/transparent-sort.bench.d.ts.map +1 -0
- package/dist/systems/sprite-animation-tick.d.ts +50 -0
- package/dist/systems/sprite-animation-tick.d.ts.map +1 -0
- package/dist/systems/tonemap.d.ts +27 -0
- package/dist/systems/tonemap.d.ts.map +1 -0
- package/dist/systems/transparent-sort.d.ts +51 -0
- package/dist/systems/transparent-sort.d.ts.map +1 -0
- package/dist/tilemap-register-validate.d.ts +21 -0
- package/dist/tilemap-register-validate.d.ts.map +1 -0
- package/package.json +100 -0
- package/src/__tests__/active-camera.unit.test.ts +193 -0
- package/src/__tests__/animation-graph-add.unit.test.ts +67 -0
- package/src/__tests__/animation-graph-asset-union.test-d.ts +83 -0
- package/src/__tests__/animation-graph-blend.unit.test.ts +66 -0
- package/src/__tests__/animation-graph-build.unit.test.ts +100 -0
- package/src/__tests__/animation-graph-clip-missing.unit.test.ts +62 -0
- package/src/__tests__/animation-graph-clip.unit.test.ts +77 -0
- package/src/__tests__/animation-graph-default-path.integration.test.ts +65 -0
- package/src/__tests__/animation-graph-describe.unit.test.ts +68 -0
- package/src/__tests__/animation-graph-errors.unit.test.ts +75 -0
- package/src/__tests__/animation-graph-nesting.unit.test.ts +84 -0
- package/src/__tests__/animation-graph-orthogonal-weight.unit.test.ts +98 -0
- package/src/__tests__/animation-graph-slot-fill.unit.test.ts +95 -0
- package/src/__tests__/animation-nslot.unit.test.ts +63 -0
- package/src/__tests__/animation-slot-length-guard.unit.test.ts +81 -0
- package/src/__tests__/append-injection.test.ts +105 -0
- package/src/__tests__/asi-world-baseline-export.unit.test.ts +173 -0
- package/src/__tests__/asi-world-ci-config.unit.test.ts +186 -0
- package/src/__tests__/asi-world-smoke.unit.test.ts +192 -0
- package/src/__tests__/asset-registry-scene.test-d.ts +49 -0
- package/src/__tests__/bind-group-cache-binding.test.ts +2513 -0
- package/src/__tests__/bind-group-cache-frame.test.ts +1511 -0
- package/src/__tests__/bind-group-cache-keying.test.ts +295 -0
- package/src/__tests__/block-upload-math.unit.test.ts +192 -0
- package/src/__tests__/builtin-shader-register-e2e.test.ts +151 -0
- package/src/__tests__/cache-false-eviction.test.ts +126 -0
- package/src/__tests__/cache-isolation-matrix.test.ts +182 -0
- package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +76 -0
- package/src/__tests__/clamp-to-last.e2e.browser.test.ts +183 -0
- package/src/__tests__/clamp-to-last.e2e.dawn.test.ts +325 -0
- package/src/__tests__/collect-scene-asset.test.ts +876 -0
- package/src/__tests__/collect-subtree.unit.test.ts +76 -0
- package/src/__tests__/collect-transient-children-absent.test.ts +154 -0
- package/src/__tests__/collect-transient-roundtrip.test.ts +245 -0
- package/src/__tests__/collect-transient-skip.test.ts +165 -0
- package/src/__tests__/components.test-d.ts +236 -0
- package/src/__tests__/components.unit.test.ts +2665 -0
- package/src/__tests__/composite-skybox-cross-world.browser.test.ts +378 -0
- package/src/__tests__/create-renderer-assembly.integration.test.ts +42 -0
- package/src/__tests__/createRenderer-dispose.test.ts +416 -0
- package/src/__tests__/createRenderer-requiredFeatures.unit.test.ts +134 -0
- package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +59 -0
- package/src/__tests__/createRenderer.unit.test.ts +231 -0
- package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +393 -0
- package/src/__tests__/dawn/ibl-compose.dawn.test.ts +151 -0
- package/src/__tests__/dawn/ibl-modules-compose.dawn.test.ts +223 -0
- package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +241 -0
- package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +611 -0
- package/src/__tests__/dawn/instances-shadow.dawn.test.ts +443 -0
- package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +313 -0
- package/src/__tests__/dawn/material-alpha.dawn.test.ts +304 -0
- package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +64 -0
- package/src/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.ts +106 -0
- package/src/__tests__/dawn/mesh-update.dawn.test.ts +342 -0
- package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +117 -0
- package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +567 -0
- package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +251 -0
- package/src/__tests__/dawn/tonemap.dawn.test.ts +107 -0
- package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +291 -0
- package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +204 -0
- package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +122 -0
- package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +99 -0
- package/src/__tests__/demo-sortscope-migration.unit.test.ts +115 -0
- package/src/__tests__/derive-bgl-integration.test.ts +398 -0
- package/src/__tests__/derive-render-data-skin.unit.test.ts +90 -0
- package/src/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.ts +204 -0
- package/src/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.ts +297 -0
- package/src/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.ts +271 -0
- package/src/__tests__/dispatch-fullscreen-pass-params.unit.test.ts +321 -0
- package/src/__tests__/draw-published.ts +10 -0
- package/src/__tests__/environment-error-exhaustive.test-d.ts +28 -0
- package/src/__tests__/equirect-bc6h.integration.test.ts +35 -0
- package/src/__tests__/error-exhaustive.test.ts +220 -0
- package/src/__tests__/extract-frames-graceful-degradation.test.ts +298 -0
- package/src/__tests__/extract-frames-merge.test.ts +643 -0
- package/src/__tests__/extract-frames-reset.test.ts +158 -0
- package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +92 -0
- package/src/__tests__/fog-producer-manifest.ts +162 -0
- package/src/__tests__/fog-producer-pixel-probe.ts +263 -0
- package/src/__tests__/fog-producer-pixel.browser.test.ts +26 -0
- package/src/__tests__/fog-producer-pixel.dawn.test.ts +55 -0
- package/src/__tests__/fog-producer-real-fixture.ts +805 -0
- package/src/__tests__/fog-producer-vfx-effect.ts +272 -0
- package/src/__tests__/fog-scene-asset.integration.test.ts +123 -0
- package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +28 -0
- package/src/__tests__/fullscreen-post-bgl-depth.test.ts +131 -0
- package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +84 -0
- package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +320 -0
- package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +107 -0
- package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +292 -0
- package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +358 -0
- package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +254 -0
- package/src/__tests__/geometry.unit.test.ts +2265 -0
- package/src/__tests__/glyph-tilemap-worldid.test.ts +146 -0
- package/src/__tests__/gpu-resource-cow-survivor.test.ts +388 -0
- package/src/__tests__/gpu-resource-store-cubemap-status.test.ts +207 -0
- package/src/__tests__/gpu-resource.test.ts +1206 -0
- package/src/__tests__/hdrp-bgl-slots.browser.test.ts +50 -0
- package/src/__tests__/hdrp-buffers.unit.test.ts +70 -0
- package/src/__tests__/hdrp-execute-filter.unit.test.ts +200 -0
- package/src/__tests__/hdrp-gbuffer-attachments.browser.test.ts +64 -0
- package/src/__tests__/hdrp-pipeline-asset-type.test-d.ts +139 -0
- package/src/__tests__/hdrp-ssao-boundary.test.ts +237 -0
- package/src/__tests__/hdrp-ssao-falsification.test.ts +289 -0
- package/src/__tests__/hello-tilemap-smoke-upgrade.unit.test.ts +147 -0
- package/src/__tests__/helpers/mock-shader-registry.ts +139 -0
- package/src/__tests__/helpers/primitive-world.ts +91 -0
- package/src/__tests__/helpers/register-runtime-components.ts +69 -0
- package/src/__tests__/helpers/register-scene-components.ts +10 -0
- package/src/__tests__/helpers/render-asset-port.ts +65 -0
- package/src/__tests__/helpers/scene-asset-port.ts +23 -0
- package/src/__tests__/helpers/tilemap-assets.ts +29 -0
- package/src/__tests__/instances.test-d.ts +61 -0
- package/src/__tests__/light-attenuation-formula.test.ts +171 -0
- package/src/__tests__/light-casters-9-light.browser.test.ts +880 -0
- package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +163 -0
- package/src/__tests__/light-snapshot.test-d.ts +84 -0
- package/src/__tests__/lights-vec-negative.unit.test.ts +52 -0
- package/src/__tests__/lights.unit.test.ts +2936 -0
- package/src/__tests__/m3-vec-negative.unit.test.ts +45 -0
- package/src/__tests__/m5-browser-dawn-sweep.integration.test.ts +8 -0
- package/src/__tests__/material-derived-coordinates.integration.test.ts +100 -0
- package/src/__tests__/material-texture-uv-scale.unit.test.ts +49 -0
- package/src/__tests__/materials.unit.test.ts +271 -0
- package/src/__tests__/mesh-ssbo-grow.unit.test.ts +244 -0
- package/src/__tests__/mip-gate.unit.test.ts +79 -0
- package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +406 -0
- package/src/__tests__/multi-uv-8set.e2e.dawn.test.ts +296 -0
- package/src/__tests__/name.unit.test.ts +123 -0
- package/src/__tests__/node-shims.d.ts +33 -0
- package/src/__tests__/pass-selector.unit.test.ts +102 -0
- package/src/__tests__/pbr-pipeline.unit.test.ts +204 -0
- package/src/__tests__/pipeline-builder-msaa.unit.test.ts +224 -0
- package/src/__tests__/pipeline-cache-keying.unit.test.ts +316 -0
- package/src/__tests__/pipeline-layout-selection.test.ts +298 -0
- package/src/__tests__/pipeline-spec.test.ts +1061 -0
- package/src/__tests__/pipeline.unit.test.ts +6974 -0
- package/src/__tests__/point-light-shadow.browser.test.ts +278 -0
- package/src/__tests__/point-light-shadow.dawn.test.ts +822 -0
- package/src/__tests__/point-light-shadow.unit.test.ts +716 -0
- package/src/__tests__/post-process-error-codes.unit.test.ts +158 -0
- package/src/__tests__/post-process-params-component.unit.test.ts +153 -0
- package/src/__tests__/post-process-params-extract.unit.test.ts +100 -0
- package/src/__tests__/post-process-reads-narrowing.test-d.ts +52 -0
- package/src/__tests__/post-process-register-roundtrip.dawn.test.ts +230 -0
- package/src/__tests__/postprocess-camera-consistency.test.ts +378 -0
- package/src/__tests__/profiler-assembly.integration.test.ts +74 -0
- package/src/__tests__/propagate-transforms.dawn.test.ts +253 -0
- package/src/__tests__/record-worldid-isolation.test.ts +247 -0
- package/src/__tests__/recover-error-exhaustive.test-d.ts +35 -0
- package/src/__tests__/render-error-exhaustive.test-d.ts +245 -0
- package/src/__tests__/render-feature-assembly.test-d.ts +28 -0
- package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +124 -0
- package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +582 -0
- package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +602 -0
- package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +264 -0
- package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +361 -0
- package/src/__tests__/render-feature-recover.integration.test.ts +142 -0
- package/src/__tests__/render-feature-runtime-surface.test-d.ts +45 -0
- package/src/__tests__/render-feature-zero-feature.browser.test.ts +152 -0
- package/src/__tests__/render-pipeline-trivial.dawn.test.ts +525 -0
- package/src/__tests__/render-schema-consumer.integration.test.ts +25 -0
- package/src/__tests__/render-schema-owner-boundary.unit.test.ts +26 -0
- package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +172 -0
- package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +322 -0
- package/src/__tests__/render-system-extract.test.ts +1399 -0
- package/src/__tests__/render-system-fold-bucket.unit.test.ts +288 -0
- package/src/__tests__/render-system-fold-fallback.unit.test.ts +148 -0
- package/src/__tests__/render-system-fold-material.unit.test.ts +145 -0
- package/src/__tests__/render-system-fold-metrics.unit.test.ts +170 -0
- package/src/__tests__/render-system-fold-modegate.unit.test.ts +166 -0
- package/src/__tests__/render-system-fold-scene-instances.unit.test.ts +51 -0
- package/src/__tests__/render-system-fold.dawn.test.ts +306 -0
- package/src/__tests__/render-system-mega.test.ts +1578 -0
- package/src/__tests__/render-system-owner-split-contract.test.ts +200 -0
- package/src/__tests__/render-system-record-multi-material-textureview.test.ts +684 -0
- package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +464 -0
- package/src/__tests__/render-system-record.test.ts +1505 -0
- package/src/__tests__/render-system-record.unit.test.ts +270 -0
- package/src/__tests__/render-system-skin-bg.unit.test.ts +147 -0
- package/src/__tests__/renderer-consumer.test-d.ts +5 -0
- package/src/__tests__/renderer-health.unit.test.ts +935 -0
- package/src/__tests__/renderer-lifecycle.integration.test.ts +29 -0
- package/src/__tests__/renderer-recover.unit.test.ts +1075 -0
- package/src/__tests__/renderer-result.test-d.ts +26 -0
- package/src/__tests__/renderer-surface.unit.test.ts +416 -0
- package/src/__tests__/resolve-depth-only-view.test.ts +173 -0
- package/src/__tests__/rhi-null-command-flow.unit.test.ts +273 -0
- package/src/__tests__/rhi-null-noop-behavior.unit.test.ts +196 -0
- package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +182 -0
- package/src/__tests__/roots-to-scene-asset.test.ts +605 -0
- package/src/__tests__/runtime-authority-scan.unit.test.ts +19 -0
- package/src/__tests__/runtime-domain-residue.unit.test.ts +13 -0
- package/src/__tests__/scene-equirect-roundtrip.test.ts +33 -0
- package/src/__tests__/scene-instance-bridge.integration.test.ts +8 -0
- package/src/__tests__/scene-instance-component.test.ts +45 -0
- package/src/__tests__/scene-instantiate-cycle-runtime.test.ts +66 -0
- package/src/__tests__/serialize-scene-asset.test.ts +336 -0
- package/src/__tests__/shadow-caster-empty-schema.test.ts +83 -0
- package/src/__tests__/shadow-csm-atlas.test.ts +178 -0
- package/src/__tests__/shadow-csm-blend.dawn.test.ts +230 -0
- package/src/__tests__/shadow-csm-cascade-loadop.test.ts +334 -0
- package/src/__tests__/shadow-csm-caster-membership.test.ts +232 -0
- package/src/__tests__/shadow-csm-component.test.ts +286 -0
- package/src/__tests__/shadow-csm-extract.test.ts +334 -0
- package/src/__tests__/shadow-csm-orthoz.test.ts +151 -0
- package/src/__tests__/shadow-csm-pssm.test.ts +142 -0
- package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +198 -0
- package/src/__tests__/shadow-csm-shader.dawn.test.ts +358 -0
- package/src/__tests__/shadow-csm-temporal.browser.test.ts +145 -0
- package/src/__tests__/shadow-csm-tile-consistency.test.ts +419 -0
- package/src/__tests__/shadow-csm-ubo.dawn.test.ts +293 -0
- package/src/__tests__/shadow-csm-ubo.test.ts +300 -0
- package/src/__tests__/shadow-csm-viewport.browser.test.ts +85 -0
- package/src/__tests__/shadow-csm-viewport.test.ts +74 -0
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +615 -0
- package/src/__tests__/shadow-m1.dawn.test.ts +105 -0
- package/src/__tests__/shadow-m2.dawn.test.ts +394 -0
- package/src/__tests__/shadow-m3-calibrate-run.dawn.test.ts +248 -0
- package/src/__tests__/shadow-m3-calibrate.ts +203 -0
- package/src/__tests__/shadow-m3.dawn.test.ts +288 -0
- package/src/__tests__/shadow-mesh-ssbo-order.test.ts +64 -0
- package/src/__tests__/shadow-probe-control-flow.dawn.test.ts +264 -0
- package/src/__tests__/shadow-quality-metrics.dawn.test.ts +324 -0
- package/src/__tests__/skin-error-exhaustive.test-d.ts +74 -0
- package/src/__tests__/skin-errors.unit.test.ts +10 -0
- package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +23 -0
- package/src/__tests__/skin-parented-double-transform.test.ts +268 -0
- package/src/__tests__/skylight-lazy-projection.test.ts +359 -0
- package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +43 -0
- package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +470 -0
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +141 -0
- package/src/__tests__/sprite-lit-extract-branch.test.ts +117 -0
- package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +123 -0
- package/src/__tests__/sprite-param-values.test-d.ts +104 -0
- package/src/__tests__/ssao-bgl.test.ts +347 -0
- package/src/__tests__/ssao-buffers.test.ts +211 -0
- package/src/__tests__/ssao-data.test.ts +121 -0
- package/src/__tests__/ssao-errors.test.ts +162 -0
- package/src/__tests__/ssao-manifest.test.ts +109 -0
- package/src/__tests__/ssao-passes.test.ts +1229 -0
- package/src/__tests__/ssao-pipelines.test.ts +275 -0
- package/src/__tests__/ssao-uniform-layout.test.ts +178 -0
- package/src/__tests__/static-rig.integration.test.ts +9 -0
- package/src/__tests__/stencil-outline-pixel.dawn.test.ts +295 -0
- package/src/__tests__/swap-chain-format.unit.test.ts +117 -0
- package/src/__tests__/systems.unit.test.ts +9957 -0
- package/src/__tests__/temporal-off-path.unit.test.ts +69 -0
- package/src/__tests__/text.unit.test.ts +466 -0
- package/src/__tests__/tilemap-childed-despawn.test.ts +468 -0
- package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +314 -0
- package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +80 -0
- package/src/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.ts +424 -0
- package/src/__tests__/tilemap-chunk-extract.test.ts +236 -0
- package/src/__tests__/tilemap-chunk-extract.unit.test.ts +383 -0
- package/src/__tests__/tilemap-chunk-y-sort-bench.unit.test.ts +109 -0
- package/src/__tests__/tilemap-dirty-rebuild.test.ts +300 -0
- package/src/__tests__/tilemap-material-cache.test.ts +137 -0
- package/src/__tests__/tilemap-multi-atlas.test.ts +237 -0
- package/src/__tests__/tilemap-owner-boundary.unit.test.ts +63 -0
- package/src/__tests__/tilemap-region-pack.test.ts +153 -0
- package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +274 -0
- package/src/__tests__/tilemap-uv-inset.test.ts +204 -0
- package/src/__tests__/tilemap-validate.test.ts +201 -0
- package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +274 -0
- package/src/__tests__/transient-fields-collect.test.ts +203 -0
- package/src/__tests__/transitional-authoring.integration.test.ts +7 -0
- package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +227 -0
- package/src/__tests__/variant-selection.unit.test.ts +21 -0
- package/src/__tests__/vertex-attribute-layout.test.ts +324 -0
- package/src/__tests__/video-cache-regression.unit.test.ts +186 -0
- package/src/__tests__/video-extract-bindgroup.dawn.test.ts +450 -0
- package/src/__tests__/view-ubo-layout.browser.test.ts +183 -0
- package/src/__tests__/world-entity-key.test.ts +92 -0
- package/src/__tests__/world-scene-despawn.test.ts +132 -0
- package/src/__tests__/world-scene-instantiate.test.ts +228 -0
- package/src/__tests__/world-scene-nested.test.ts +230 -0
- package/src/__tests__/world-scene-override.test.ts +199 -0
- package/src/__tests__/zero-compression-zero-load.integration.test.ts +107 -0
- package/src/asset-contributions.ts +48 -0
- package/src/asset-kind.ts +7 -0
- package/src/collect-scene-asset.ts +689 -0
- package/src/components/__tests__/camera.test-d.ts +57 -0
- package/src/components/__tests__/camera.test.ts +95 -0
- package/src/components/__tests__/child-of.test.ts +35 -0
- package/src/components/__tests__/sprite-animation.test-d.ts +160 -0
- package/src/components/__tests__/sprite-instances.unit.test.ts +108 -0
- package/src/components/__tests__/sprite-region-override.test-d.ts +101 -0
- package/src/components/__tests__/tile-layer.test-d.ts +33 -0
- package/src/components/__tests__/tile-layer.unit.test.ts +125 -0
- package/src/components/__tests__/tilemap.test-d.ts +35 -0
- package/src/components/__tests__/transform-vec-schema.test.ts +121 -0
- package/src/create-renderer-env-classify.ts +110 -0
- package/src/createRenderer.ts +61 -0
- package/src/dev-import-transport.ts +97 -0
- package/src/errors/environment.ts +6 -0
- package/src/errors/sprite-animation.ts +5 -0
- package/src/index.ts +442 -0
- package/src/scene-asset-port.ts +32 -0
- package/src/scene-collect-errors.ts +30 -0
- package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +183 -0
- package/src/scene-utils/mount-override-fold.ts +217 -0
- package/src/shadow-m3-calibrate.ts +171 -0
- package/src/sprite-param-values.ts +61 -0
- package/src/systems/__tests__/_xorshift.ts +83 -0
- package/src/systems/__tests__/argsort-in-place.test.ts +155 -0
- package/src/systems/__tests__/transparent-sort.bench.ts +218 -0
- package/src/systems/sprite-animation-tick.ts +302 -0
- package/src/systems/tonemap.ts +68 -0
- package/src/systems/transparent-sort.ts +434 -0
- package/src/tilemap-register-validate.ts +100 -0
|
@@ -0,0 +1,1206 @@
|
|
|
1
|
+
// feat-20260612-rhi-destroy-renderer-dispose-gpu-lifecycle / M2 / w6 —
|
|
2
|
+
// GpuBuffer / GpuTexture .destroy() unit tests.
|
|
3
|
+
//
|
|
4
|
+
// Coverage matrix (requirements AC-04 + plan-strategy §5.3):
|
|
5
|
+
// 1. GpuBuffer.destroy: first call returns ok; isDestroyed flips to true.
|
|
6
|
+
// 2. GpuBuffer.destroy: second call routes the underlying RhiDevice
|
|
7
|
+
// 'destroy-after-destroy' err verbatim (D-7 SSOT — RHI shim is the
|
|
8
|
+
// lifecycle SSOT; the runtime wrapper forwards instead of duplicating
|
|
9
|
+
// the bookkeeping; charter §F1).
|
|
10
|
+
// 3. GpuTexture.destroy: same first / ok + isDestroyed=true.
|
|
11
|
+
// 4. GpuTexture.destroy: same second / 'destroy-after-destroy' forward.
|
|
12
|
+
//
|
|
13
|
+
// Mock shape: a minimal RhiDevice stub with destroyBuffer / destroyTexture
|
|
14
|
+
// implementing per-handle `destroyed: Set` bookkeeping that mirrors the
|
|
15
|
+
// real shim's contract (rhi-webgpu device.ts lines 1404–1473). Plain
|
|
16
|
+
// branded handles are fabricated via `as unknown as Buffer / Texture` —
|
|
17
|
+
// the runtime wrapper never reads the brand; only the device methods
|
|
18
|
+
// touch the handle (charter §F4 explicit failure: any future shape
|
|
19
|
+
// change to handle bookkeeping flips the second-destroy branch).
|
|
20
|
+
|
|
21
|
+
import { World } from '@forgeax/engine-ecs';
|
|
22
|
+
import { deriveVertexLayoutProjection } from '@forgeax/engine-geometry';
|
|
23
|
+
import { GpuBuffer, GpuResourceStore, GpuTexture } from '@forgeax/engine-render/internal';
|
|
24
|
+
import type { Buffer, Result, RhiCaps, RhiDevice, Texture } from '@forgeax/engine-rhi';
|
|
25
|
+
import { err, ok, RhiError } from '@forgeax/engine-rhi';
|
|
26
|
+
import {
|
|
27
|
+
type EquirectAsset,
|
|
28
|
+
type Handle,
|
|
29
|
+
type MeshAsset,
|
|
30
|
+
type TextureAsset,
|
|
31
|
+
toShared,
|
|
32
|
+
unwrapHandle,
|
|
33
|
+
} from '@forgeax/engine-types';
|
|
34
|
+
import { describe, expect, it } from 'vitest';
|
|
35
|
+
|
|
36
|
+
const TEST_LAYOUT_PROJECTION = deriveVertexLayoutProjection({
|
|
37
|
+
position: new Float32Array(0),
|
|
38
|
+
normal: new Float32Array(0),
|
|
39
|
+
uv: new Float32Array(0),
|
|
40
|
+
tangent: new Float32Array(0),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// ── Minimal RhiDevice stub (only destroyBuffer / destroyTexture wired) ──
|
|
44
|
+
|
|
45
|
+
type MinimalDevice = Pick<RhiDevice, 'destroyBuffer' | 'destroyTexture'>;
|
|
46
|
+
|
|
47
|
+
function makeMockDevice(): MinimalDevice {
|
|
48
|
+
const destroyedBufs = new WeakSet<Buffer>();
|
|
49
|
+
const destroyedTexs = new WeakSet<Texture>();
|
|
50
|
+
return {
|
|
51
|
+
destroyBuffer(buf: Buffer): Result<void, RhiError> {
|
|
52
|
+
if (destroyedBufs.has(buf)) {
|
|
53
|
+
return err(
|
|
54
|
+
new RhiError({
|
|
55
|
+
code: 'destroy-after-destroy',
|
|
56
|
+
expected: 'GPU buffer handle has not been destroyed yet',
|
|
57
|
+
hint: 'object already destroyed; track lifecycle in caller or check isDestroyed before re-destroy',
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
destroyedBufs.add(buf);
|
|
62
|
+
return ok(undefined);
|
|
63
|
+
},
|
|
64
|
+
destroyTexture(tex: Texture): Result<void, RhiError> {
|
|
65
|
+
if (destroyedTexs.has(tex)) {
|
|
66
|
+
return err(
|
|
67
|
+
new RhiError({
|
|
68
|
+
code: 'destroy-after-destroy',
|
|
69
|
+
expected: 'GPU texture handle has not been destroyed yet',
|
|
70
|
+
hint: 'object already destroyed; track lifecycle in caller or check isDestroyed before re-destroy',
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
destroyedTexs.add(tex);
|
|
75
|
+
return ok(undefined);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Branded opaque handles; the runtime wrapper never inspects the brand,
|
|
81
|
+
// only the mock device methods key off identity.
|
|
82
|
+
function makeBufHandle(): Buffer {
|
|
83
|
+
return {} as unknown as Buffer;
|
|
84
|
+
}
|
|
85
|
+
function makeTexHandle(): Texture {
|
|
86
|
+
return {} as unknown as Texture;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
describe('GpuBuffer (feat-20260612 M2 / w6)', () => {
|
|
90
|
+
it('destroy: first call returns ok; isDestroyed flips to true', () => {
|
|
91
|
+
const device = makeMockDevice();
|
|
92
|
+
const handle = makeBufHandle();
|
|
93
|
+
const gpuBuf = new GpuBuffer(device as unknown as RhiDevice, handle);
|
|
94
|
+
|
|
95
|
+
expect(gpuBuf.isDestroyed).toBe(false);
|
|
96
|
+
|
|
97
|
+
const r = gpuBuf.destroy();
|
|
98
|
+
expect(r.ok).toBe(true);
|
|
99
|
+
expect(gpuBuf.isDestroyed).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("destroy: second call returns err 'destroy-after-destroy' (forwarded from RHI shim)", () => {
|
|
103
|
+
const device = makeMockDevice();
|
|
104
|
+
const handle = makeBufHandle();
|
|
105
|
+
const gpuBuf = new GpuBuffer(device as unknown as RhiDevice, handle);
|
|
106
|
+
|
|
107
|
+
const first = gpuBuf.destroy();
|
|
108
|
+
expect(first.ok).toBe(true);
|
|
109
|
+
|
|
110
|
+
const second = gpuBuf.destroy();
|
|
111
|
+
expect(second.ok).toBe(false);
|
|
112
|
+
if (!second.ok) {
|
|
113
|
+
expect(second.error.code).toBe('destroy-after-destroy');
|
|
114
|
+
}
|
|
115
|
+
// isDestroyed stays true — the second call did not un-destroy it.
|
|
116
|
+
expect(gpuBuf.isDestroyed).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('GpuTexture (feat-20260612 M2 / w6)', () => {
|
|
121
|
+
it('destroy: first call returns ok; isDestroyed flips to true', () => {
|
|
122
|
+
const device = makeMockDevice();
|
|
123
|
+
const handle = makeTexHandle();
|
|
124
|
+
const gpuTex = new GpuTexture(device as unknown as RhiDevice, handle);
|
|
125
|
+
|
|
126
|
+
expect(gpuTex.isDestroyed).toBe(false);
|
|
127
|
+
|
|
128
|
+
const r = gpuTex.destroy();
|
|
129
|
+
expect(r.ok).toBe(true);
|
|
130
|
+
expect(gpuTex.isDestroyed).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("destroy: second call returns err 'destroy-after-destroy' (forwarded from RHI shim)", () => {
|
|
134
|
+
const device = makeMockDevice();
|
|
135
|
+
const handle = makeTexHandle();
|
|
136
|
+
const gpuTex = new GpuTexture(device as unknown as RhiDevice, handle);
|
|
137
|
+
|
|
138
|
+
const first = gpuTex.destroy();
|
|
139
|
+
expect(first.ok).toBe(true);
|
|
140
|
+
|
|
141
|
+
const second = gpuTex.destroy();
|
|
142
|
+
expect(second.ok).toBe(false);
|
|
143
|
+
if (!second.ok) {
|
|
144
|
+
expect(second.error.code).toBe('destroy-after-destroy');
|
|
145
|
+
}
|
|
146
|
+
expect(gpuTex.isDestroyed).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// ── M-3 / w9 + w10: gpuStore narrowing + destroyAll unit tests ──
|
|
151
|
+
//
|
|
152
|
+
// Coverage matrix (requirements AC-05 + AC-06 / plan-strategy §7 M-3 / D-2 / D-9):
|
|
153
|
+
// w9: type-level narrowing — getMeshGpuHandles(...).vertexBuffer / indexBuffer
|
|
154
|
+
// is GpuBuffer (not raw RHI Buffer); getCubemapGpuTexture(...) is GpuTexture
|
|
155
|
+
// (not raw Texture). Validated by `const _: GpuBuffer = entry.vertexBuffer`
|
|
156
|
+
// in the test body — `pnpm typecheck` is the gate.
|
|
157
|
+
// w10: gpuStore.destroyAll() walks the three handle maps + every GpuResource
|
|
158
|
+
// isDestroyed flips to true; second call is idempotent (no error).
|
|
159
|
+
//
|
|
160
|
+
// The mock device extends the pipeline.unit.test.ts shape with destroyBuffer /
|
|
161
|
+
// destroyTexture (M-1) so the GpuBuffer / GpuTexture wrappers can forward.
|
|
162
|
+
|
|
163
|
+
interface DeviceProbe {
|
|
164
|
+
buffers: number;
|
|
165
|
+
textures: number;
|
|
166
|
+
views: number;
|
|
167
|
+
destroyedBuffers: number;
|
|
168
|
+
destroyedTextures: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function freshProbe(): DeviceProbe {
|
|
172
|
+
return { buffers: 0, textures: 0, views: 0, destroyedBuffers: 0, destroyedTextures: 0 };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const okShim = <T>(v: T) => ({ ok: true as const, value: v });
|
|
176
|
+
|
|
177
|
+
// biome-ignore lint/suspicious/noExplicitAny: opaque mock GPU device surface
|
|
178
|
+
function makeStoreMockDevice(probe: DeviceProbe, maxTextureDimension2D = 16_384): any {
|
|
179
|
+
const destroyedBufs = new WeakSet<object>();
|
|
180
|
+
const destroyedTexs = new WeakSet<object>();
|
|
181
|
+
return {
|
|
182
|
+
createShaderModule: () => okShim({ __mock: 'shader' }),
|
|
183
|
+
createSampler: () => okShim({ __mock: 'sampler' }),
|
|
184
|
+
createBindGroupLayout: () => okShim({ __mock: 'bgl' }),
|
|
185
|
+
createPipelineLayout: () => okShim({ __mock: 'layout' }),
|
|
186
|
+
createRenderPipeline: () => okShim({ __mock: 'pipeline' }),
|
|
187
|
+
createBindGroup: () => okShim({ __mock: 'bindGroup' }),
|
|
188
|
+
createBuffer: (desc: { size?: number }) => {
|
|
189
|
+
probe.buffers += 1;
|
|
190
|
+
return okShim({ __mock: `buffer-${probe.buffers}`, size: desc.size ?? 0 });
|
|
191
|
+
},
|
|
192
|
+
createTexture: () => {
|
|
193
|
+
probe.textures += 1;
|
|
194
|
+
return okShim({ __mock: `texture-${probe.textures}` });
|
|
195
|
+
},
|
|
196
|
+
createTextureView: () => {
|
|
197
|
+
probe.views += 1;
|
|
198
|
+
return okShim({ __mock: `view-${probe.views}` });
|
|
199
|
+
},
|
|
200
|
+
limits: { maxTextureDimension2D },
|
|
201
|
+
destroyBuffer(buf: object): Result<void, RhiError> {
|
|
202
|
+
if (destroyedBufs.has(buf)) {
|
|
203
|
+
return err(
|
|
204
|
+
new RhiError({
|
|
205
|
+
code: 'destroy-after-destroy',
|
|
206
|
+
expected: 'GPU buffer handle has not been destroyed yet',
|
|
207
|
+
hint: 'object already destroyed; track lifecycle in caller',
|
|
208
|
+
}),
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
destroyedBufs.add(buf);
|
|
212
|
+
probe.destroyedBuffers += 1;
|
|
213
|
+
return ok(undefined);
|
|
214
|
+
},
|
|
215
|
+
destroyTexture(tex: object): Result<void, RhiError> {
|
|
216
|
+
if (destroyedTexs.has(tex)) {
|
|
217
|
+
return err(
|
|
218
|
+
new RhiError({
|
|
219
|
+
code: 'destroy-after-destroy',
|
|
220
|
+
expected: 'GPU texture handle has not been destroyed yet',
|
|
221
|
+
hint: 'object already destroyed; track lifecycle in caller',
|
|
222
|
+
}),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
destroyedTexs.add(tex);
|
|
226
|
+
probe.destroyedTextures += 1;
|
|
227
|
+
return ok(undefined);
|
|
228
|
+
},
|
|
229
|
+
queue: {
|
|
230
|
+
writeBuffer: () => okShim(undefined),
|
|
231
|
+
writeTexture: () => okShim(undefined),
|
|
232
|
+
submit: () => okShim(undefined),
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const mockCaps: RhiCaps = {
|
|
238
|
+
backendKind: 'webgpu',
|
|
239
|
+
compute: true,
|
|
240
|
+
timestampQuery: false,
|
|
241
|
+
timestampPeriodNanoseconds: null,
|
|
242
|
+
indirectDrawing: false,
|
|
243
|
+
textureCompressionBc: false,
|
|
244
|
+
textureCompressionEtc2: false,
|
|
245
|
+
textureCompressionAstc: false,
|
|
246
|
+
multiDrawIndirect: false,
|
|
247
|
+
pushConstants: false,
|
|
248
|
+
textureBindingArray: false,
|
|
249
|
+
samplerAliasing: false,
|
|
250
|
+
firstInstanceIndirect: false,
|
|
251
|
+
storageBuffer: true,
|
|
252
|
+
storageTexture: false,
|
|
253
|
+
rgba16floatRenderable: true,
|
|
254
|
+
rg11b10ufloatRenderable: false,
|
|
255
|
+
float32Filterable: false,
|
|
256
|
+
maxColorAttachments: 8,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
function makeRegisterCube(): (
|
|
260
|
+
pod: EquirectAsset,
|
|
261
|
+
) => Result<Handle<'EquirectAsset', 'shared'>, never> {
|
|
262
|
+
let next = 1000;
|
|
263
|
+
return () => ok(toShared<'EquirectAsset'>(next++));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// biome-ignore lint/suspicious/noExplicitAny: shader-module factory shim
|
|
267
|
+
const shaderFactory = async (_d: any, desc: { code: string; label?: string }) =>
|
|
268
|
+
ok({ __mock: 'shader', label: desc.label ?? '' }) as never;
|
|
269
|
+
|
|
270
|
+
function configuredStore(probe: DeviceProbe, maxTextureDimension2D = 16_384): GpuResourceStore {
|
|
271
|
+
const store = new GpuResourceStore();
|
|
272
|
+
store.configureGpuDevice(
|
|
273
|
+
makeStoreMockDevice(probe, maxTextureDimension2D),
|
|
274
|
+
shaderFactory,
|
|
275
|
+
makeRegisterCube() as never,
|
|
276
|
+
mockCaps,
|
|
277
|
+
);
|
|
278
|
+
return store;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function meshPodFixture(): MeshAsset {
|
|
282
|
+
const attributes: MeshAsset['attributes'] = {
|
|
283
|
+
position: new Float32Array(4 * 3),
|
|
284
|
+
normal: new Float32Array(4 * 3),
|
|
285
|
+
uv: new Float32Array(4 * 2),
|
|
286
|
+
tangent: new Float32Array(4 * 4),
|
|
287
|
+
};
|
|
288
|
+
return {
|
|
289
|
+
kind: 'mesh',
|
|
290
|
+
vertices: new Float32Array(4 * 12),
|
|
291
|
+
indices: new Uint16Array([0, 1, 2, 0, 2, 3]),
|
|
292
|
+
attributes,
|
|
293
|
+
aabb: new Float32Array(6),
|
|
294
|
+
submeshes: [
|
|
295
|
+
{
|
|
296
|
+
indexOffset: 0,
|
|
297
|
+
indexCount: 6,
|
|
298
|
+
vertexCount: 0,
|
|
299
|
+
topology: 'triangle-list',
|
|
300
|
+
materialSlot: 0,
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
|
|
304
|
+
materialSlots: [{ slotName: 'Default' }],
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function texturePodFixture(): TextureAsset {
|
|
309
|
+
return {
|
|
310
|
+
kind: 'texture',
|
|
311
|
+
width: 2,
|
|
312
|
+
height: 2,
|
|
313
|
+
format: 'rgba8unorm-srgb',
|
|
314
|
+
data: new Uint8Array(2 * 2 * 4).fill(188),
|
|
315
|
+
colorSpace: 'srgb',
|
|
316
|
+
mipmap: false,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
describe('GpuResourceStore handle map narrowing (feat-20260612 M3 / w9, AC-05)', () => {
|
|
321
|
+
it('getMeshGpuHandles returns entry whose vertexBuffer / indexBuffer are GpuBuffer (no `as` cast)', () => {
|
|
322
|
+
const probe = freshProbe();
|
|
323
|
+
const store = configuredStore(probe);
|
|
324
|
+
const handle = toShared<'MeshAsset'>(1024);
|
|
325
|
+
|
|
326
|
+
const res = store.ensureResident(handle, meshPodFixture());
|
|
327
|
+
expect(res.ok).toBe(true);
|
|
328
|
+
|
|
329
|
+
const entry = store.getMeshGpuHandles(handle);
|
|
330
|
+
expect(entry).toBeDefined();
|
|
331
|
+
if (entry === undefined) return;
|
|
332
|
+
|
|
333
|
+
// Type-level narrowing assertion (AC-05): TS must accept the assignment
|
|
334
|
+
// without an `as` cast. If the field type were still raw `any` this would
|
|
335
|
+
// also compile (any flows everywhere) -- the structural guarantee is the
|
|
336
|
+
// runtime instanceof below; together they catch the migration regression.
|
|
337
|
+
const _vbo: GpuBuffer = entry.vertexBuffer;
|
|
338
|
+
expect(_vbo).toBeInstanceOf(GpuBuffer);
|
|
339
|
+
|
|
340
|
+
// Mesh has indices in the fixture, so indexBuffer is non-null GpuBuffer.
|
|
341
|
+
expect(entry.indexBuffer).not.toBeNull();
|
|
342
|
+
if (entry.indexBuffer !== null) {
|
|
343
|
+
const _ibo: GpuBuffer = entry.indexBuffer;
|
|
344
|
+
expect(_ibo).toBeInstanceOf(GpuBuffer);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('getTextureGpuView returns the underlying view; texture entry holds a GpuTexture (M-3 wrapper)', () => {
|
|
349
|
+
const probe = freshProbe();
|
|
350
|
+
const store = configuredStore(probe);
|
|
351
|
+
const handle = toShared<'TextureAsset'>(2048);
|
|
352
|
+
|
|
353
|
+
const res = store.ensureResident(handle, texturePodFixture());
|
|
354
|
+
expect(res.ok).toBe(true);
|
|
355
|
+
|
|
356
|
+
// The view accessor stays decoupled (TextureView != GpuResource); the
|
|
357
|
+
// narrowing applies to the texture-side entry, exercised via the public
|
|
358
|
+
// destroyAll path in w10 (the texture field is private to the entry).
|
|
359
|
+
expect(store.getTextureGpuView(handle)).toBeDefined();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('rejects a texture over maxTextureDimension2D before creating a GPU handle', () => {
|
|
363
|
+
const probe = freshProbe();
|
|
364
|
+
const store = configuredStore(probe, 2048);
|
|
365
|
+
const handle = toShared<'TextureAsset'>(2049);
|
|
366
|
+
|
|
367
|
+
const res = store.ensureResident(handle, {
|
|
368
|
+
...texturePodFixture(),
|
|
369
|
+
width: 2049,
|
|
370
|
+
height: 1,
|
|
371
|
+
data: new Uint8Array(2049 * 4),
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
expect(res.ok).toBe(false);
|
|
375
|
+
if (res.ok) return;
|
|
376
|
+
expect(res.error.code).toBe('image-dimension-out-of-bounds');
|
|
377
|
+
const detail = res.error.detail;
|
|
378
|
+
if (detail === undefined || !('requested' in detail) || !('limit' in detail)) return;
|
|
379
|
+
expect(detail.requested).toEqual({ width: 2049, height: 1 });
|
|
380
|
+
expect(detail.limit).toBe(2048);
|
|
381
|
+
expect(probe.textures).toBe(0);
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
describe('GpuResourceStore.destroyAll (feat-20260612 M3 / w10, AC-06 prereq)', () => {
|
|
386
|
+
it('walks all 3 handle maps + every entry is destroyed after destroyAll()', async () => {
|
|
387
|
+
const probe = freshProbe();
|
|
388
|
+
const store = configuredStore(probe);
|
|
389
|
+
const meshHandle = toShared<'MeshAsset'>(1024);
|
|
390
|
+
const texHandle = toShared<'TextureAsset'>(2048);
|
|
391
|
+
|
|
392
|
+
// Populate mesh + texture maps via ensureResident.
|
|
393
|
+
expect(store.ensureResident(meshHandle, meshPodFixture()).ok).toBe(true);
|
|
394
|
+
expect(store.ensureResident(texHandle, texturePodFixture()).ok).toBe(true);
|
|
395
|
+
|
|
396
|
+
const meshEntry = store.getMeshGpuHandles(meshHandle);
|
|
397
|
+
expect(meshEntry).toBeDefined();
|
|
398
|
+
if (meshEntry === undefined) return;
|
|
399
|
+
expect(meshEntry.vertexBuffer.isDestroyed).toBe(false);
|
|
400
|
+
if (meshEntry.indexBuffer !== null) {
|
|
401
|
+
expect(meshEntry.indexBuffer.isDestroyed).toBe(false);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// destroyedBuffers / destroyedTextures probe baseline.
|
|
405
|
+
const baselineDestroyedBufs = probe.destroyedBuffers;
|
|
406
|
+
const baselineDestroyedTexs = probe.destroyedTextures;
|
|
407
|
+
|
|
408
|
+
store.destroyAll();
|
|
409
|
+
|
|
410
|
+
// Mesh entry's GpuBuffer wrappers flipped to destroyed.
|
|
411
|
+
expect(meshEntry.vertexBuffer.isDestroyed).toBe(true);
|
|
412
|
+
if (meshEntry.indexBuffer !== null) {
|
|
413
|
+
expect(meshEntry.indexBuffer.isDestroyed).toBe(true);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// RHI device.destroyBuffer fired for vbo + ibo (2); destroyTexture for the
|
|
417
|
+
// texture (1). The cubemap map is empty in this fixture (no equirect
|
|
418
|
+
// upload); a non-empty cubemap path is exercised below.
|
|
419
|
+
expect(probe.destroyedBuffers - baselineDestroyedBufs).toBe(2);
|
|
420
|
+
expect(probe.destroyedTextures - baselineDestroyedTexs).toBe(1);
|
|
421
|
+
|
|
422
|
+
// After destroyAll() the maps are cleared so subsequent accessors miss.
|
|
423
|
+
expect(store.getMeshGpuHandles(meshHandle)).toBeUndefined();
|
|
424
|
+
expect(store.getTextureGpuView(texHandle)).toBeUndefined();
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('idempotent: second destroyAll() does nothing and does not throw', () => {
|
|
428
|
+
const probe = freshProbe();
|
|
429
|
+
const store = configuredStore(probe);
|
|
430
|
+
const meshHandle = toShared<'MeshAsset'>(1024);
|
|
431
|
+
|
|
432
|
+
expect(store.ensureResident(meshHandle, meshPodFixture()).ok).toBe(true);
|
|
433
|
+
|
|
434
|
+
store.destroyAll();
|
|
435
|
+
const afterFirst = probe.destroyedBuffers;
|
|
436
|
+
|
|
437
|
+
// Second call: maps are already empty; no further RHI destroy fires.
|
|
438
|
+
expect(() => store.destroyAll()).not.toThrow();
|
|
439
|
+
expect(probe.destroyedBuffers).toBe(afterFirst);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it('destroyAll on an empty store is a no-op', () => {
|
|
443
|
+
const probe = freshProbe();
|
|
444
|
+
const store = configuredStore(probe);
|
|
445
|
+
|
|
446
|
+
expect(() => store.destroyAll()).not.toThrow();
|
|
447
|
+
expect(probe.destroyedBuffers).toBe(0);
|
|
448
|
+
expect(probe.destroyedTextures).toBe(0);
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// ── M-4 / w14: instanceBuffers dispose-path cleanup unit test ──
|
|
453
|
+
//
|
|
454
|
+
// Coverage matrix (requirements §scope item 7 + plan-strategy §7 M-4 + D-7):
|
|
455
|
+
// 1. disposeInstanceBuffers walks the Map, calls .destroy() on every
|
|
456
|
+
// entry.buffer (a GpuBuffer wrapper), and clears the Map.
|
|
457
|
+
// 2. Every wrapped GpuBuffer flips isDestroyed=true after the helper runs.
|
|
458
|
+
// 3. The helper is idempotent: a second call on the cleared Map is a no-op.
|
|
459
|
+
// 4. The helper on an empty Map is a safe no-op.
|
|
460
|
+
//
|
|
461
|
+
// Dispose path is independent of the per-frame Map.delete cleanup — the
|
|
462
|
+
// per-frame path keeps its existing 'just delete the key' semantics
|
|
463
|
+
// (plan-strategy D-7 / OOS-11).
|
|
464
|
+
|
|
465
|
+
import { disposeInstanceBuffers, GpuBuffer as GpuBufferCls } from '@forgeax/engine-render/internal';
|
|
466
|
+
|
|
467
|
+
describe('disposeInstanceBuffers (feat-20260612 M4 / w14)', () => {
|
|
468
|
+
it('walks the Map and destroys every entry; clears the Map', () => {
|
|
469
|
+
const device = makeMockDevice();
|
|
470
|
+
const map = new Map<
|
|
471
|
+
number,
|
|
472
|
+
{ buffer: GpuBufferCls; uploadedByteLength: number; uploadedArchVersion: number }
|
|
473
|
+
>();
|
|
474
|
+
const buf1 = new GpuBufferCls(device as unknown as RhiDevice, makeBufHandle());
|
|
475
|
+
const buf2 = new GpuBufferCls(device as unknown as RhiDevice, makeBufHandle());
|
|
476
|
+
map.set(1, { buffer: buf1, uploadedByteLength: 256, uploadedArchVersion: 1 });
|
|
477
|
+
map.set(2, { buffer: buf2, uploadedByteLength: 512, uploadedArchVersion: 1 });
|
|
478
|
+
|
|
479
|
+
expect(buf1.isDestroyed).toBe(false);
|
|
480
|
+
expect(buf2.isDestroyed).toBe(false);
|
|
481
|
+
expect(map.size).toBe(2);
|
|
482
|
+
|
|
483
|
+
disposeInstanceBuffers(map);
|
|
484
|
+
|
|
485
|
+
expect(buf1.isDestroyed).toBe(true);
|
|
486
|
+
expect(buf2.isDestroyed).toBe(true);
|
|
487
|
+
expect(map.size).toBe(0);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
it('idempotent: a second dispose on the cleared Map is a no-op', () => {
|
|
491
|
+
const device = makeMockDevice();
|
|
492
|
+
const map = new Map<
|
|
493
|
+
number,
|
|
494
|
+
{ buffer: GpuBufferCls; uploadedByteLength: number; uploadedArchVersion: number }
|
|
495
|
+
>();
|
|
496
|
+
const buf = new GpuBufferCls(device as unknown as RhiDevice, makeBufHandle());
|
|
497
|
+
map.set(1, { buffer: buf, uploadedByteLength: 256, uploadedArchVersion: 1 });
|
|
498
|
+
|
|
499
|
+
disposeInstanceBuffers(map);
|
|
500
|
+
expect(map.size).toBe(0);
|
|
501
|
+
|
|
502
|
+
expect(() => disposeInstanceBuffers(map)).not.toThrow();
|
|
503
|
+
expect(map.size).toBe(0);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it('on an empty Map is a safe no-op', () => {
|
|
507
|
+
const map = new Map<
|
|
508
|
+
number,
|
|
509
|
+
{ buffer: GpuBufferCls; uploadedByteLength: number; uploadedArchVersion: number }
|
|
510
|
+
>();
|
|
511
|
+
expect(() => disposeInstanceBuffers(map)).not.toThrow();
|
|
512
|
+
expect(map.size).toBe(0);
|
|
513
|
+
});
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// ── M1 feat-20260619-gpu-resource-ownership-symmetric-release-primitive ──
|
|
517
|
+
//
|
|
518
|
+
// w1: AC-01 evict primitives basic unit tests (red phase)
|
|
519
|
+
// w2: AC-01 cubemap wrapper shared-dedup unit tests (red phase)
|
|
520
|
+
// w3: AC-03 releaseUnreferenced idempotent unit tests (red phase)
|
|
521
|
+
// w4: AC-04 aggregate failure unit tests (red phase)
|
|
522
|
+
|
|
523
|
+
// ── Helpers for A-family evict tests ──
|
|
524
|
+
|
|
525
|
+
function evictableTextureStore(): {
|
|
526
|
+
store: GpuResourceStore;
|
|
527
|
+
probe: DeviceProbe;
|
|
528
|
+
handle: ReturnType<typeof toShared<'TextureAsset'>>;
|
|
529
|
+
tex: GpuTexture;
|
|
530
|
+
} {
|
|
531
|
+
const probe = freshProbe();
|
|
532
|
+
const store = configuredStore(probe);
|
|
533
|
+
const handle = toShared<'TextureAsset'>(3001);
|
|
534
|
+
|
|
535
|
+
const res = store.ensureResident(handle, texturePodFixture());
|
|
536
|
+
expect(res.ok).toBe(true);
|
|
537
|
+
|
|
538
|
+
const tex = store._getTextureGpuTexture(handle);
|
|
539
|
+
expect(tex).toBeDefined();
|
|
540
|
+
if (tex === undefined) throw new Error('unreachable');
|
|
541
|
+
expect(tex.isDestroyed).toBe(false);
|
|
542
|
+
|
|
543
|
+
return { store, probe, handle, tex };
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function evictableMeshStore(): {
|
|
547
|
+
store: GpuResourceStore;
|
|
548
|
+
probe: DeviceProbe;
|
|
549
|
+
handle: ReturnType<typeof toShared<'MeshAsset'>>;
|
|
550
|
+
vbo: GpuBuffer;
|
|
551
|
+
ibo: GpuBuffer;
|
|
552
|
+
} {
|
|
553
|
+
const probe = freshProbe();
|
|
554
|
+
const store = configuredStore(probe);
|
|
555
|
+
const handle = toShared<'MeshAsset'>(3002);
|
|
556
|
+
|
|
557
|
+
const res = store.ensureResident(handle, meshPodFixture());
|
|
558
|
+
expect(res.ok).toBe(true);
|
|
559
|
+
|
|
560
|
+
const entry = store.getMeshGpuHandles(handle);
|
|
561
|
+
expect(entry).toBeDefined();
|
|
562
|
+
if (entry === undefined) throw new Error('unreachable');
|
|
563
|
+
expect(entry.vertexBuffer.isDestroyed).toBe(false);
|
|
564
|
+
expect(entry.indexBuffer).not.toBeNull();
|
|
565
|
+
if (entry.indexBuffer === null) throw new Error('unreachable');
|
|
566
|
+
|
|
567
|
+
return {
|
|
568
|
+
store,
|
|
569
|
+
probe,
|
|
570
|
+
handle,
|
|
571
|
+
vbo: entry.vertexBuffer,
|
|
572
|
+
ibo: entry.indexBuffer,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
describe('evictTexture / evictMesh / evictCubemap (feat-20260619 M1 / w1)', () => {
|
|
577
|
+
it('evictTexture: removes entry from Map + isDestroyed === true', () => {
|
|
578
|
+
const { store, probe, handle, tex } = evictableTextureStore();
|
|
579
|
+
const baselineDestroyed = probe.destroyedTextures;
|
|
580
|
+
|
|
581
|
+
const r = store.evictTexture(handle);
|
|
582
|
+
expect(r.freed).toBe(1);
|
|
583
|
+
expect(r.errors).toEqual([]);
|
|
584
|
+
|
|
585
|
+
expect(tex.isDestroyed).toBe(true);
|
|
586
|
+
expect(store._getTextureGpuTexture(handle)).toBeUndefined();
|
|
587
|
+
expect(store.getTextureGpuView(handle)).toBeUndefined();
|
|
588
|
+
expect(probe.destroyedTextures - baselineDestroyed).toBe(1);
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
it('evictTexture: double evict is no-op (freed=0, no error)', () => {
|
|
592
|
+
const { store, handle } = evictableTextureStore();
|
|
593
|
+
|
|
594
|
+
const r1 = store.evictTexture(handle);
|
|
595
|
+
expect(r1.freed).toBe(1);
|
|
596
|
+
|
|
597
|
+
const r2 = store.evictTexture(handle);
|
|
598
|
+
expect(r2.freed).toBe(0);
|
|
599
|
+
expect(r2.errors).toEqual([]);
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
it('evictTexture: non-existent key is no-op', () => {
|
|
603
|
+
const probe = freshProbe();
|
|
604
|
+
const store = configuredStore(probe);
|
|
605
|
+
const handle = toShared<'TextureAsset'>(9999);
|
|
606
|
+
|
|
607
|
+
const r = store.evictTexture(handle);
|
|
608
|
+
expect(r.freed).toBe(0);
|
|
609
|
+
expect(r.errors).toEqual([]);
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
it('evictMesh: removes entry + both vbo and ibo destroyed', () => {
|
|
613
|
+
const { store, probe, handle, vbo, ibo } = evictableMeshStore();
|
|
614
|
+
const baselineDestroyed = probe.destroyedBuffers;
|
|
615
|
+
|
|
616
|
+
const r = store.evictMesh(handle);
|
|
617
|
+
expect(r.freed).toBe(1);
|
|
618
|
+
expect(r.errors).toEqual([]);
|
|
619
|
+
|
|
620
|
+
expect(vbo.isDestroyed).toBe(true);
|
|
621
|
+
expect(ibo.isDestroyed).toBe(true);
|
|
622
|
+
expect(store.getMeshGpuHandles(handle)).toBeUndefined();
|
|
623
|
+
// vbo + ibo = 2 buffer destroys
|
|
624
|
+
expect(probe.destroyedBuffers - baselineDestroyed).toBe(2);
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it('evictMesh: double evict is no-op', () => {
|
|
628
|
+
const { store, handle } = evictableMeshStore();
|
|
629
|
+
|
|
630
|
+
const r1 = store.evictMesh(handle);
|
|
631
|
+
expect(r1.freed).toBe(1);
|
|
632
|
+
|
|
633
|
+
const r2 = store.evictMesh(handle);
|
|
634
|
+
expect(r2.freed).toBe(0);
|
|
635
|
+
expect(r2.errors).toEqual([]);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it('evictMesh: non-existent key is no-op', () => {
|
|
639
|
+
const probe = freshProbe();
|
|
640
|
+
const store = configuredStore(probe);
|
|
641
|
+
const handle = toShared<'MeshAsset'>(9999);
|
|
642
|
+
|
|
643
|
+
const r = store.evictMesh(handle);
|
|
644
|
+
expect(r.freed).toBe(0);
|
|
645
|
+
expect(r.errors).toEqual([]);
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
it('evictCubemap: non-existent key is no-op', () => {
|
|
649
|
+
const probe = freshProbe();
|
|
650
|
+
const store = configuredStore(probe);
|
|
651
|
+
|
|
652
|
+
const r = store.evictCubemap(9999);
|
|
653
|
+
expect(r.freed).toBe(0);
|
|
654
|
+
expect(r.errors).toEqual([]);
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
describe('evictCubemap wrapper shared-dedup (feat-20260619 M1 / w2)', () => {
|
|
659
|
+
it('evictCubemap on sourceId destroys wrapper; cubeId entry remains but is destroyed', () => {
|
|
660
|
+
const probe = freshProbe();
|
|
661
|
+
const store = configuredStore(probe);
|
|
662
|
+
|
|
663
|
+
// Construct a cubemap with two entries sharing one GpuTexture wrapper
|
|
664
|
+
// (mirrors uploadCubemapFromEquirect's dual set at sourceId + cubeId).
|
|
665
|
+
const srcHandle = toShared<'EquirectAsset'>(4001);
|
|
666
|
+
const cubeHandle = toShared<'EquirectAsset'>(4002);
|
|
667
|
+
const sourceId = unwrapHandle(srcHandle);
|
|
668
|
+
const cubeId = unwrapHandle(cubeHandle);
|
|
669
|
+
|
|
670
|
+
// Create a GpuTexture wrapper directly
|
|
671
|
+
const device = makeMockDevice() as unknown as RhiDevice;
|
|
672
|
+
const gpuTex = new GpuTexture(device, {} as unknown as Texture);
|
|
673
|
+
|
|
674
|
+
// biome-ignore lint/suspicious/noExplicitAny: access private store maps for test setup
|
|
675
|
+
const storeAny = store as any;
|
|
676
|
+
const sharedView = { __mock: 'cubemap-view' };
|
|
677
|
+
const sharedFaceViews = [
|
|
678
|
+
{ __mock: 'face-0' },
|
|
679
|
+
{ __mock: 'face-1' },
|
|
680
|
+
{ __mock: 'face-2' },
|
|
681
|
+
{ __mock: 'face-3' },
|
|
682
|
+
{ __mock: 'face-4' },
|
|
683
|
+
{ __mock: 'face-5' },
|
|
684
|
+
];
|
|
685
|
+
storeAny.cubemapGpuHandles.set(sourceId, {
|
|
686
|
+
status: 'ready',
|
|
687
|
+
texture: gpuTex,
|
|
688
|
+
view: sharedView,
|
|
689
|
+
faceViews: sharedFaceViews,
|
|
690
|
+
});
|
|
691
|
+
storeAny.cubemapGpuHandles.set(cubeId, {
|
|
692
|
+
status: 'ready',
|
|
693
|
+
texture: gpuTex,
|
|
694
|
+
view: sharedView,
|
|
695
|
+
faceViews: sharedFaceViews,
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
expect(gpuTex.isDestroyed).toBe(false);
|
|
699
|
+
expect(storeAny.cubemapGpuHandles.has(sourceId)).toBe(true);
|
|
700
|
+
expect(storeAny.cubemapGpuHandles.has(cubeId)).toBe(true);
|
|
701
|
+
|
|
702
|
+
// Evict sourceId
|
|
703
|
+
const r1 = store.evictCubemap(srcHandle);
|
|
704
|
+
expect(r1.freed).toBe(1);
|
|
705
|
+
expect(r1.errors).toEqual([]);
|
|
706
|
+
|
|
707
|
+
expect(gpuTex.isDestroyed).toBe(true);
|
|
708
|
+
expect(storeAny.cubemapGpuHandles.has(sourceId)).toBe(false);
|
|
709
|
+
// cubeId entry still exists but wrapper is destroyed
|
|
710
|
+
expect(storeAny.cubemapGpuHandles.has(cubeId)).toBe(true);
|
|
711
|
+
|
|
712
|
+
// Evict cubeId: isDestroyed gate makes this no-op
|
|
713
|
+
const r2 = store.evictCubemap(cubeHandle);
|
|
714
|
+
expect(r2.freed).toBe(0);
|
|
715
|
+
expect(r2.errors).toEqual([]);
|
|
716
|
+
expect(storeAny.cubemapGpuHandles.has(cubeId)).toBe(false);
|
|
717
|
+
});
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
describe('releaseUnreferenced (feat-20260619 M1 / w3)', () => {
|
|
721
|
+
it('releases entries not in liveSet; keeps entries in liveSet', () => {
|
|
722
|
+
const probe = freshProbe();
|
|
723
|
+
const store = configuredStore(probe);
|
|
724
|
+
const keepHandle = toShared<'TextureAsset'>(5001);
|
|
725
|
+
const evictHandle = toShared<'TextureAsset'>(5002);
|
|
726
|
+
|
|
727
|
+
store.ensureResident(keepHandle, texturePodFixture());
|
|
728
|
+
store.ensureResident(evictHandle, texturePodFixture());
|
|
729
|
+
|
|
730
|
+
const keepId = unwrapHandle(keepHandle);
|
|
731
|
+
const liveSet = new Set<number>([keepId]);
|
|
732
|
+
|
|
733
|
+
const r = store.releaseUnreferenced(liveSet);
|
|
734
|
+
expect(r.freed).toBe(1);
|
|
735
|
+
expect(r.errors).toEqual([]);
|
|
736
|
+
|
|
737
|
+
// kept entry is intact
|
|
738
|
+
expect(store._getTextureGpuTexture(keepHandle)).toBeDefined();
|
|
739
|
+
expect(store._getTextureGpuTexture(keepHandle)?.isDestroyed).toBe(false);
|
|
740
|
+
|
|
741
|
+
// evicted entry is gone
|
|
742
|
+
expect(store._getTextureGpuTexture(evictHandle)).toBeUndefined();
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
it('ignores ids in liveSet that do not exist in store', () => {
|
|
746
|
+
const probe = freshProbe();
|
|
747
|
+
const store = configuredStore(probe);
|
|
748
|
+
const handle = toShared<'TextureAsset'>(5003);
|
|
749
|
+
store.ensureResident(handle, texturePodFixture());
|
|
750
|
+
|
|
751
|
+
const liveSet = new Set<number>([unwrapHandle(handle), 99999]);
|
|
752
|
+
|
|
753
|
+
const r = store.releaseUnreferenced(liveSet);
|
|
754
|
+
// Only the resident texture should be kept; external id is ignored.
|
|
755
|
+
expect(r.freed).toBe(0);
|
|
756
|
+
expect(store._getTextureGpuTexture(handle)).toBeDefined();
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
it('empty liveSet releases everything; second call is no-op', () => {
|
|
760
|
+
const probe = freshProbe();
|
|
761
|
+
const store = configuredStore(probe);
|
|
762
|
+
const h1 = toShared<'TextureAsset'>(5101);
|
|
763
|
+
const h2 = toShared<'TextureAsset'>(5102);
|
|
764
|
+
const h3 = toShared<'MeshAsset'>(5103);
|
|
765
|
+
|
|
766
|
+
store.ensureResident(h1, texturePodFixture());
|
|
767
|
+
store.ensureResident(h2, texturePodFixture());
|
|
768
|
+
store.ensureResident(h3, meshPodFixture());
|
|
769
|
+
|
|
770
|
+
const r1 = store.releaseUnreferenced(new Set());
|
|
771
|
+
// 2 textures (1 each) + 1 mesh (vbo + ibo = 2 buffer frees) = 4
|
|
772
|
+
expect(r1.freed).toBe(4);
|
|
773
|
+
|
|
774
|
+
// Everything gone
|
|
775
|
+
expect(store._getTextureGpuTexture(h1)).toBeUndefined();
|
|
776
|
+
expect(store._getTextureGpuTexture(h2)).toBeUndefined();
|
|
777
|
+
expect(store.getMeshGpuHandles(h3)).toBeUndefined();
|
|
778
|
+
|
|
779
|
+
// Second call: no-op (Map already empty)
|
|
780
|
+
const r2 = store.releaseUnreferenced(new Set());
|
|
781
|
+
expect(r2.freed).toBe(0);
|
|
782
|
+
expect(r2.errors).toEqual([]);
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
it('is idempotent: calling twice with same liveSet gives same result', () => {
|
|
786
|
+
const probe = freshProbe();
|
|
787
|
+
const store = configuredStore(probe);
|
|
788
|
+
const keepHandle = toShared<'TextureAsset'>(5201);
|
|
789
|
+
const evictHandle = toShared<'TextureAsset'>(5202);
|
|
790
|
+
|
|
791
|
+
store.ensureResident(keepHandle, texturePodFixture());
|
|
792
|
+
store.ensureResident(evictHandle, texturePodFixture());
|
|
793
|
+
|
|
794
|
+
const liveSet = new Set<number>([unwrapHandle(keepHandle)]);
|
|
795
|
+
|
|
796
|
+
const r1 = store.releaseUnreferenced(liveSet);
|
|
797
|
+
expect(r1.freed).toBe(1);
|
|
798
|
+
|
|
799
|
+
const r2 = store.releaseUnreferenced(liveSet);
|
|
800
|
+
expect(r2.freed).toBe(0);
|
|
801
|
+
expect(r2.errors).toEqual([]);
|
|
802
|
+
});
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
describe('evict aggregate failure (feat-20260619 M1 / w4)', () => {
|
|
806
|
+
function makeFailingMockDevice(): {
|
|
807
|
+
device: MinimalDevice;
|
|
808
|
+
failTex: Texture;
|
|
809
|
+
failBuf: Buffer;
|
|
810
|
+
} {
|
|
811
|
+
const destroyedBufs = new WeakSet<Buffer>();
|
|
812
|
+
const destroyedTexs = new WeakSet<Texture>();
|
|
813
|
+
const failTex = {} as unknown as Texture;
|
|
814
|
+
const failBuf = {} as unknown as Buffer;
|
|
815
|
+
|
|
816
|
+
const device: MinimalDevice = {
|
|
817
|
+
destroyBuffer(buf: Buffer): Result<void, RhiError> {
|
|
818
|
+
if (buf === failBuf) {
|
|
819
|
+
return err(
|
|
820
|
+
new RhiError({
|
|
821
|
+
code: 'destroy-after-destroy',
|
|
822
|
+
expected: 'buffer not yet destroyed',
|
|
823
|
+
hint: 'injected test failure',
|
|
824
|
+
}),
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
if (destroyedBufs.has(buf)) {
|
|
828
|
+
return err(
|
|
829
|
+
new RhiError({
|
|
830
|
+
code: 'destroy-after-destroy',
|
|
831
|
+
expected: 'GPU buffer handle has not been destroyed yet',
|
|
832
|
+
hint: 'object already destroyed; track lifecycle in caller',
|
|
833
|
+
}),
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
destroyedBufs.add(buf);
|
|
837
|
+
return ok(undefined);
|
|
838
|
+
},
|
|
839
|
+
destroyTexture(tex: Texture): Result<void, RhiError> {
|
|
840
|
+
if (tex === failTex) {
|
|
841
|
+
return err(
|
|
842
|
+
new RhiError({
|
|
843
|
+
code: 'destroy-after-destroy',
|
|
844
|
+
expected: 'texture not yet destroyed',
|
|
845
|
+
hint: 'injected test failure',
|
|
846
|
+
}),
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
if (destroyedTexs.has(tex)) {
|
|
850
|
+
return err(
|
|
851
|
+
new RhiError({
|
|
852
|
+
code: 'destroy-after-destroy',
|
|
853
|
+
expected: 'GPU texture handle has not been destroyed yet',
|
|
854
|
+
hint: 'object already destroyed; track lifecycle in caller',
|
|
855
|
+
}),
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
destroyedTexs.add(tex);
|
|
859
|
+
return ok(undefined);
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
return { device, failTex, failBuf };
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
it('single evictTexture failure: errors collected, freed counts remaining', () => {
|
|
867
|
+
const { device, failTex } = makeFailingMockDevice();
|
|
868
|
+
|
|
869
|
+
// Build two GpuTexture wrappers: one that will fail, one normal.
|
|
870
|
+
const goodTex = new GpuTexture(device as unknown as RhiDevice, {} as unknown as Texture);
|
|
871
|
+
const badTex = new GpuTexture(device as unknown as RhiDevice, failTex);
|
|
872
|
+
|
|
873
|
+
const probe = freshProbe();
|
|
874
|
+
const store = configuredStore(probe);
|
|
875
|
+
|
|
876
|
+
const goodHandle = toShared<'TextureAsset'>(6001);
|
|
877
|
+
const badHandle = toShared<'TextureAsset'>(6002);
|
|
878
|
+
const goodId = unwrapHandle(goodHandle);
|
|
879
|
+
const badId = unwrapHandle(badHandle);
|
|
880
|
+
|
|
881
|
+
// biome-ignore lint/suspicious/noExplicitAny: access private store maps for test setup
|
|
882
|
+
const storeAny = store as any;
|
|
883
|
+
storeAny.textureGpuHandles.set(goodId, {
|
|
884
|
+
texture: goodTex,
|
|
885
|
+
view: { __mock: 'view-good' },
|
|
886
|
+
});
|
|
887
|
+
storeAny.textureGpuHandles.set(badId, {
|
|
888
|
+
texture: badTex,
|
|
889
|
+
view: { __mock: 'view-bad' },
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
// Evict the good handle first
|
|
893
|
+
const rGood = store.evictTexture(goodHandle);
|
|
894
|
+
expect(rGood.freed).toBe(1);
|
|
895
|
+
expect(rGood.errors).toEqual([]);
|
|
896
|
+
expect(goodTex.isDestroyed).toBe(true);
|
|
897
|
+
|
|
898
|
+
// Evict the bad handle
|
|
899
|
+
const rBad = store.evictTexture(badHandle);
|
|
900
|
+
expect(rBad.freed).toBe(0);
|
|
901
|
+
expect(rBad.errors.length).toBe(1);
|
|
902
|
+
expect(rBad.errors[0]?.code).toBe('destroy-after-destroy');
|
|
903
|
+
// Sweep continued — bad handle entry removed
|
|
904
|
+
expect(storeAny.textureGpuHandles.has(badId)).toBe(false);
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
it('single evictMesh failure: errors collected, freed counts remaining buffers', () => {
|
|
908
|
+
const { device, failBuf } = makeFailingMockDevice();
|
|
909
|
+
const probe = freshProbe();
|
|
910
|
+
const store = configuredStore(probe);
|
|
911
|
+
|
|
912
|
+
const handle = toShared<'MeshAsset'>(6003);
|
|
913
|
+
const id = unwrapHandle(handle);
|
|
914
|
+
|
|
915
|
+
const goodVbo = new GpuBuffer(device as unknown as RhiDevice, {} as unknown as Buffer);
|
|
916
|
+
const badIbo = new GpuBuffer(device as unknown as RhiDevice, failBuf);
|
|
917
|
+
|
|
918
|
+
// biome-ignore lint/suspicious/noExplicitAny: access private store maps for test setup
|
|
919
|
+
const storeAny = store as any;
|
|
920
|
+
storeAny.meshGpuHandles.set(id, {
|
|
921
|
+
vertexBuffer: goodVbo,
|
|
922
|
+
indexBuffer: badIbo,
|
|
923
|
+
vboBytes: 256,
|
|
924
|
+
iboBytes: 256,
|
|
925
|
+
indexCount: 6,
|
|
926
|
+
indexFormat: 'uint16',
|
|
927
|
+
layoutProjection: TEST_LAYOUT_PROJECTION,
|
|
928
|
+
vertexCount: 4,
|
|
929
|
+
indexed: true,
|
|
930
|
+
topology: 'triangle-list',
|
|
931
|
+
materialSlot: 0,
|
|
932
|
+
submeshes: [
|
|
933
|
+
{
|
|
934
|
+
indexOffset: 0,
|
|
935
|
+
indexCount: 6,
|
|
936
|
+
vertexCount: 0,
|
|
937
|
+
topology: 'triangle-list',
|
|
938
|
+
materialSlot: 0,
|
|
939
|
+
},
|
|
940
|
+
],
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
const r = store.evictMesh(handle);
|
|
944
|
+
// vbo destroyed ok but ibo failed — freed counts 0 (only vbo, but treat mesh as atomic evict)
|
|
945
|
+
// The plan says evict counts freed per-resource, mesh has two buffers.
|
|
946
|
+
// Per w5 design: evictMesh frees 1 (the mesh entry), errors collects both buffer failures.
|
|
947
|
+
// Actually, let's check: D-1 says "read Result (ok→freed++; err→fire+errors.push)"
|
|
948
|
+
// For mesh: two buffers → two destroy calls. freed counts successful destroys.
|
|
949
|
+
expect(r.freed).toBe(1); // vbo ok
|
|
950
|
+
expect(r.errors.length).toBe(1); // ibo failed
|
|
951
|
+
expect(r.errors[0]?.code).toBe('destroy-after-destroy');
|
|
952
|
+
expect(goodVbo.isDestroyed).toBe(true);
|
|
953
|
+
expect(storeAny.meshGpuHandles.has(id)).toBe(false);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
it('releaseUnreferenced with mixed failures: errors collected, sweep continues', () => {
|
|
957
|
+
const { device, failTex } = makeFailingMockDevice();
|
|
958
|
+
const probe = freshProbe();
|
|
959
|
+
const store = configuredStore(probe);
|
|
960
|
+
|
|
961
|
+
const badHandle = toShared<'TextureAsset'>(6010);
|
|
962
|
+
const goodHandle = toShared<'MeshAsset'>(6011);
|
|
963
|
+
const badId = unwrapHandle(badHandle);
|
|
964
|
+
const goodId = unwrapHandle(goodHandle);
|
|
965
|
+
|
|
966
|
+
const badTex = new GpuTexture(device as unknown as RhiDevice, failTex);
|
|
967
|
+
const goodVbo = new GpuBuffer(device as unknown as RhiDevice, {} as unknown as Buffer);
|
|
968
|
+
const goodIbo = new GpuBuffer(device as unknown as RhiDevice, {} as unknown as Buffer);
|
|
969
|
+
|
|
970
|
+
// biome-ignore lint/suspicious/noExplicitAny: access private store maps for test setup
|
|
971
|
+
const storeAny = store as any;
|
|
972
|
+
storeAny.textureGpuHandles.set(badId, {
|
|
973
|
+
texture: badTex,
|
|
974
|
+
view: { __mock: 'view-bad' },
|
|
975
|
+
});
|
|
976
|
+
storeAny.meshGpuHandles.set(goodId, {
|
|
977
|
+
vertexBuffer: goodVbo,
|
|
978
|
+
indexBuffer: goodIbo,
|
|
979
|
+
vboBytes: 256,
|
|
980
|
+
iboBytes: 256,
|
|
981
|
+
indexCount: 6,
|
|
982
|
+
indexFormat: 'uint16',
|
|
983
|
+
layoutProjection: TEST_LAYOUT_PROJECTION,
|
|
984
|
+
vertexCount: 4,
|
|
985
|
+
indexed: true,
|
|
986
|
+
topology: 'triangle-list',
|
|
987
|
+
materialSlot: 0,
|
|
988
|
+
submeshes: [
|
|
989
|
+
{
|
|
990
|
+
indexOffset: 0,
|
|
991
|
+
indexCount: 6,
|
|
992
|
+
vertexCount: 0,
|
|
993
|
+
topology: 'triangle-list',
|
|
994
|
+
materialSlot: 0,
|
|
995
|
+
},
|
|
996
|
+
],
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
const r = store.releaseUnreferenced(new Set());
|
|
1000
|
+
// badTex fails (1 error), goodVbo+goodIbo both succeed — freed counts each
|
|
1001
|
+
// per-resource destroy, so 2 buffer destroys = freed 2. bad tex = 0 frees, 1 error.
|
|
1002
|
+
expect(r.freed).toBe(2); // 2 buffer frees (vbo + ibo), 0 texture frees
|
|
1003
|
+
expect(r.errors.length).toBe(1);
|
|
1004
|
+
expect(r.errors[0]?.code).toBe('destroy-after-destroy');
|
|
1005
|
+
expect(goodVbo.isDestroyed).toBe(true);
|
|
1006
|
+
expect(goodIbo.isDestroyed).toBe(true);
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
// ── M2 w7: AC-02 event-driven recycle closed-loop integration test ──
|
|
1011
|
+
//
|
|
1012
|
+
// Validates the owner chain: SharedRefStore.release publishes evidence, then
|
|
1013
|
+
// the GPU owner consumes that evidence and calls gpuStore.evictX.
|
|
1014
|
+
//
|
|
1015
|
+
// Scope per task description:
|
|
1016
|
+
// (1) Three resource types (TextureAsset / MeshAsset / EquirectAsset cubemap)
|
|
1017
|
+
// each construct one alloc -> retain -> release-to-rc=0 ->
|
|
1018
|
+
// owner evidence triggers evict -> assert wrapper.isDestroyed===true.
|
|
1019
|
+
// (2) Covers "no manual evict needed" — entity despawn path auto-recycles.
|
|
1020
|
+
// (3) Negative assertion: ECS release alone does not evict the resource
|
|
1021
|
+
// (stays resident in store).
|
|
1022
|
+
//
|
|
1023
|
+
describe('event-driven recycle closed-loop (feat-20260619 M2 / w7, AC-02)', () => {
|
|
1024
|
+
// Helper: create a GpuResourceStore with configured device and probe,
|
|
1025
|
+
// using the same mock infrastructure from earlier describe blocks.
|
|
1026
|
+
function evictCapturingStore(): {
|
|
1027
|
+
store: GpuResourceStore;
|
|
1028
|
+
probe: DeviceProbe;
|
|
1029
|
+
sharedRefs: World['sharedRefs'];
|
|
1030
|
+
} {
|
|
1031
|
+
const probe = freshProbe();
|
|
1032
|
+
const store = new GpuResourceStore();
|
|
1033
|
+
store.configureGpuDevice(
|
|
1034
|
+
makeStoreMockDevice(probe),
|
|
1035
|
+
shaderFactory,
|
|
1036
|
+
makeRegisterCube() as never,
|
|
1037
|
+
mockCaps,
|
|
1038
|
+
);
|
|
1039
|
+
return { store, probe, sharedRefs: new World().sharedRefs };
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
it('TextureAsset: release evidence -> owner evicts texture', () => {
|
|
1043
|
+
const { store, probe, sharedRefs } = evictCapturingStore();
|
|
1044
|
+
const baselineDestroyed = probe.destroyedTextures;
|
|
1045
|
+
|
|
1046
|
+
const payload: TextureAsset = texturePodFixture();
|
|
1047
|
+
const handle = sharedRefs.alloc('TextureAsset', payload);
|
|
1048
|
+
|
|
1049
|
+
// Step 2: ensureResident so GPU resources are materialised in the store
|
|
1050
|
+
const residentRes = store.ensureResident(handle, payload);
|
|
1051
|
+
expect(residentRes.ok).toBe(true);
|
|
1052
|
+
|
|
1053
|
+
const tex = store._getTextureGpuTexture(handle);
|
|
1054
|
+
expect(tex).toBeDefined();
|
|
1055
|
+
if (tex === undefined) return;
|
|
1056
|
+
expect(tex.isDestroyed).toBe(false);
|
|
1057
|
+
|
|
1058
|
+
const releaseRes = sharedRefs.release(handle);
|
|
1059
|
+
expect(releaseRes.ok).toBe(true);
|
|
1060
|
+
expect(releaseRes.unwrap()).toMatchObject({ payload, refcount: 0, evidence: 'released' });
|
|
1061
|
+
store.evictTexture(handle);
|
|
1062
|
+
|
|
1063
|
+
expect(tex.isDestroyed).toBe(true);
|
|
1064
|
+
expect(store._getTextureGpuTexture(handle)).toBeUndefined();
|
|
1065
|
+
expect(store.getTextureGpuView(handle)).toBeUndefined();
|
|
1066
|
+
expect(probe.destroyedTextures - baselineDestroyed).toBe(1);
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
it('MeshAsset: release evidence -> owner evicts mesh', () => {
|
|
1070
|
+
const { store, probe, sharedRefs } = evictCapturingStore();
|
|
1071
|
+
const baselineDestroyed = probe.destroyedBuffers;
|
|
1072
|
+
|
|
1073
|
+
const payload: MeshAsset = meshPodFixture();
|
|
1074
|
+
const handle = sharedRefs.alloc('MeshAsset', payload);
|
|
1075
|
+
|
|
1076
|
+
const residentRes = store.ensureResident(handle, payload);
|
|
1077
|
+
expect(residentRes.ok).toBe(true);
|
|
1078
|
+
|
|
1079
|
+
const entry = store.getMeshGpuHandles(handle);
|
|
1080
|
+
expect(entry).toBeDefined();
|
|
1081
|
+
if (entry === undefined) return;
|
|
1082
|
+
expect(entry.vertexBuffer.isDestroyed).toBe(false);
|
|
1083
|
+
expect(entry.indexBuffer).not.toBeNull();
|
|
1084
|
+
if (entry.indexBuffer === null) return;
|
|
1085
|
+
|
|
1086
|
+
const releaseRes = sharedRefs.release(handle);
|
|
1087
|
+
expect(releaseRes.ok).toBe(true);
|
|
1088
|
+
expect(releaseRes.unwrap()).toMatchObject({ payload, refcount: 0, evidence: 'released' });
|
|
1089
|
+
store.evictMesh(handle);
|
|
1090
|
+
|
|
1091
|
+
expect(entry.vertexBuffer.isDestroyed).toBe(true);
|
|
1092
|
+
expect(entry.indexBuffer.isDestroyed).toBe(true);
|
|
1093
|
+
expect(store.getMeshGpuHandles(handle)).toBeUndefined();
|
|
1094
|
+
expect(probe.destroyedBuffers - baselineDestroyed).toBe(2);
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
it('EquirectAsset cubemap: release evidence -> owner evicts cubemap', () => {
|
|
1098
|
+
const { store, sharedRefs } = evictCapturingStore();
|
|
1099
|
+
|
|
1100
|
+
let cubeIdNum = 0;
|
|
1101
|
+
const cubePayload: EquirectAsset = {
|
|
1102
|
+
kind: 'equirect',
|
|
1103
|
+
width: 64,
|
|
1104
|
+
height: 64,
|
|
1105
|
+
format: 'rgba16float',
|
|
1106
|
+
data: new Uint8Array(64 * 64 * 8),
|
|
1107
|
+
colorSpace: 'linear',
|
|
1108
|
+
};
|
|
1109
|
+
const cubeHandle = sharedRefs.alloc('EquirectAsset', cubePayload);
|
|
1110
|
+
cubeIdNum = unwrapHandle(cubeHandle);
|
|
1111
|
+
|
|
1112
|
+
// Directly seed a cubemap entry into the store (simulating uploadCubemapFromEquirect
|
|
1113
|
+
// with the matching sourceId). We don't test the full equirect upload path;
|
|
1114
|
+
// we only verify the evict callback chain.
|
|
1115
|
+
const device = makeMockDevice() as unknown as RhiDevice;
|
|
1116
|
+
const gpuTex = new GpuTexture(device, {} as unknown as Texture);
|
|
1117
|
+
|
|
1118
|
+
// biome-ignore lint/suspicious/noExplicitAny: access private store maps for test setup
|
|
1119
|
+
const storeAny = store as any;
|
|
1120
|
+
storeAny.cubemapGpuHandles.set(cubeIdNum, {
|
|
1121
|
+
status: 'ready',
|
|
1122
|
+
texture: gpuTex,
|
|
1123
|
+
view: { __mock: 'cubemap-view' },
|
|
1124
|
+
faceViews: [
|
|
1125
|
+
{ __mock: 'face-0' },
|
|
1126
|
+
{ __mock: 'face-1' },
|
|
1127
|
+
{ __mock: 'face-2' },
|
|
1128
|
+
{ __mock: 'face-3' },
|
|
1129
|
+
{ __mock: 'face-4' },
|
|
1130
|
+
{ __mock: 'face-5' },
|
|
1131
|
+
],
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
expect(gpuTex.isDestroyed).toBe(false);
|
|
1135
|
+
expect(storeAny.cubemapGpuHandles.has(cubeIdNum)).toBe(true);
|
|
1136
|
+
|
|
1137
|
+
const releaseRes = sharedRefs.release(cubeHandle);
|
|
1138
|
+
expect(releaseRes.ok).toBe(true);
|
|
1139
|
+
expect(releaseRes.unwrap()).toMatchObject({
|
|
1140
|
+
payload: cubePayload,
|
|
1141
|
+
refcount: 0,
|
|
1142
|
+
evidence: 'released',
|
|
1143
|
+
});
|
|
1144
|
+
store.evictCubemap(cubeIdNum);
|
|
1145
|
+
|
|
1146
|
+
expect(gpuTex.isDestroyed).toBe(true);
|
|
1147
|
+
expect(storeAny.cubemapGpuHandles.has(cubeIdNum)).toBe(false);
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
it('negative: release alone does not evict a GPU resource', () => {
|
|
1151
|
+
const { store, sharedRefs } = evictCapturingStore();
|
|
1152
|
+
|
|
1153
|
+
const payload: TextureAsset = texturePodFixture();
|
|
1154
|
+
const handle = sharedRefs.alloc('TextureAsset', payload);
|
|
1155
|
+
|
|
1156
|
+
const residentRes = store.ensureResident(handle, payload);
|
|
1157
|
+
expect(residentRes.ok).toBe(true);
|
|
1158
|
+
|
|
1159
|
+
const tex = store._getTextureGpuTexture(handle);
|
|
1160
|
+
expect(tex).toBeDefined();
|
|
1161
|
+
if (tex === undefined) return;
|
|
1162
|
+
expect(tex.isDestroyed).toBe(false);
|
|
1163
|
+
|
|
1164
|
+
// Release to rc=0
|
|
1165
|
+
const releaseRes = sharedRefs.release(handle);
|
|
1166
|
+
expect(releaseRes.ok).toBe(true);
|
|
1167
|
+
|
|
1168
|
+
// Resource still resident — the GPU owner has not consumed evidence.
|
|
1169
|
+
expect(tex.isDestroyed).toBe(false);
|
|
1170
|
+
expect(store._getTextureGpuTexture(handle)).toBeDefined();
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
it('retain -> release retains rc>0: no premature evict at rc 2->1', () => {
|
|
1174
|
+
const { store, sharedRefs } = evictCapturingStore();
|
|
1175
|
+
|
|
1176
|
+
const payload: TextureAsset = texturePodFixture();
|
|
1177
|
+
const handle = sharedRefs.alloc('TextureAsset', payload);
|
|
1178
|
+
|
|
1179
|
+
store.ensureResident(handle, payload);
|
|
1180
|
+
const tex = store._getTextureGpuTexture(handle);
|
|
1181
|
+
expect(tex).toBeDefined();
|
|
1182
|
+
if (tex === undefined) return;
|
|
1183
|
+
|
|
1184
|
+
// retain (rc 1->2)
|
|
1185
|
+
const retainRes = sharedRefs.retain(handle);
|
|
1186
|
+
expect(retainRes.ok).toBe(true);
|
|
1187
|
+
expect(sharedRefs.refcount(handle)).toBe(2);
|
|
1188
|
+
|
|
1189
|
+
// release to rc=2->1 (no release evidence is published yet)
|
|
1190
|
+
const releaseRes = sharedRefs.release(handle);
|
|
1191
|
+
expect(releaseRes.ok).toBe(true);
|
|
1192
|
+
expect(sharedRefs.refcount(handle)).toBe(1);
|
|
1193
|
+
|
|
1194
|
+
// Resource still resident — no final-release evidence exists yet.
|
|
1195
|
+
expect(tex.isDestroyed).toBe(false);
|
|
1196
|
+
expect(store._getTextureGpuTexture(handle)).toBeDefined();
|
|
1197
|
+
|
|
1198
|
+
// Final release to rc=0 publishes evidence; the owner performs eviction.
|
|
1199
|
+
const finalRes = sharedRefs.release(handle);
|
|
1200
|
+
expect(finalRes.ok).toBe(true);
|
|
1201
|
+
expect(finalRes.unwrap()).toMatchObject({ payload, refcount: 0, evidence: 'released' });
|
|
1202
|
+
store.evictTexture(handle);
|
|
1203
|
+
expect(tex.isDestroyed).toBe(true);
|
|
1204
|
+
expect(store._getTextureGpuTexture(handle)).toBeUndefined();
|
|
1205
|
+
});
|
|
1206
|
+
});
|