mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
fix(perf): free a turned-off layer's entities that Cesium keeps (#1367)
Release stale Cesium command references after disabling a layer while preserving current-frame commands. Contribution by @quanticsoul4772.
This commit is contained in:
1 parent
405c7f0d20
commit
69fba2ebbe
6 files changed
+237
-1
No files matched your search
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Let a turned-off layer's memory go.
|
||||
*
|
||||
* Cesium (engine 22.3, `Scene/View.js`) reuses each view's per-pass command
|
||||
* arrays: every frame resets `frustumCommands.indices[pass]` to 0 and
|
||||
* overwrites `commands[pass][i]` from the start. `Scene.js` truncates the
|
||||
* voxel, Gaussian-splat and translucent passes to their counts; the opaque
|
||||
* and other passes keep the slots past the new count. When a layer is turned
|
||||
* off the next frame has fewer commands, so that tail keeps the destroyed
|
||||
* primitives' DrawCommands, and through `_owner` → primitive → entity →
|
||||
* EntityCollection the whole data source stays reachable. The offscreen view
|
||||
* `scene.sampleHeight` / `pickFromRay` render into keeps its last list the
|
||||
* same way, until the next height sample.
|
||||
*
|
||||
* Measured (production build, heap after GC, Data Centers on → off): 116 MiB
|
||||
* kept on main, 13 MiB with this module; heap snapshots traced the entities
|
||||
* through `View.frustumCommandsList` and `Picking._pickOffscreenView`.
|
||||
*
|
||||
* After a layer finishes turning off, this renders one frame, trims the main
|
||||
* view's arrays to that frame's counts, and empties the offscreen pick view's
|
||||
* lists (it rebuilds them in full on every pick). It reads private Cesium
|
||||
* fields: `src/sceneCommandRelease.test.mjs` fails if any of them is renamed
|
||||
* or if Cesium changes which passes it truncates, and once Cesium clears the
|
||||
* tail itself this module can go.
|
||||
*/
|
||||
|
||||
/** Drop command references a view no longer draws. */
|
||||
function trimView(view, { keepCurrent }) {
|
||||
for (const frustum of view?.frustumCommandsList || []) {
|
||||
const { commands, indices } = frustum;
|
||||
for (let pass = 0; pass < commands.length; pass += 1) {
|
||||
const keep = keepCurrent ? indices[pass] : 0;
|
||||
if (commands[pass].length > keep) commands[pass].length = keep;
|
||||
if (!keepCurrent) indices[pass] = 0;
|
||||
}
|
||||
}
|
||||
if (!keepCurrent)
|
||||
for (const extent of view?._commandExtents || [])
|
||||
extent.command = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release stale command references in the scene's main view (keeping what
|
||||
* the last frame drew) and in its offscreen pick view (all of it).
|
||||
* @param {object} scene Cesium Scene, right after a render.
|
||||
*/
|
||||
export function trimStaleSceneCommands(scene) {
|
||||
trimView(scene._defaultView, { keepCurrent: true });
|
||||
trimView(scene._picking?._pickOffscreenView, { keepCurrent: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* After every layer disable, render one frame and trim once it is drawn.
|
||||
* @param {{scene: object, dataManager: object, requestRender: (reason: string) => void}} deps
|
||||
* @returns {() => void} uninstall
|
||||
*/
|
||||
export function installLayerReleaseTrim({ scene, dataManager, requestRender }) {
|
||||
let removeOneShot = null;
|
||||
const unsubscribe = dataManager.subscribe((change) => {
|
||||
if (change?.type !== 'visibility' || change.enabled !== false) return;
|
||||
if (removeOneShot) return; // a trim is already waiting for its frame
|
||||
removeOneShot = scene.postRender.addEventListener(() => {
|
||||
removeOneShot();
|
||||
removeOneShot = null;
|
||||
trimStaleSceneCommands(scene);
|
||||
});
|
||||
requestRender('layer-release-trim');
|
||||
});
|
||||
return () => {
|
||||
unsubscribe();
|
||||
removeOneShot?.();
|
||||
removeOneShot = null;
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user