Scope render demand to each scene attachment

Give each scene its own render governor, owner holds and recent idle requests.
Make the Cesium render backend own its request mode directly, so the governor
drives engine.render on both engines without a dependency back from Cesium.
Route layer requests through their attached engine and capture the attachment's
governor for camera motions, orbit, annotations and shell controls. Release
retained-layer holds before clearing the outgoing engine, and destroy the
governor after scene consumers have detached.

Preserve Cesium's owner-keyed holds, pre-install buffering, last-release settling
frame and one-shot requests during continuous rendering. Navara keeps the same
render policy. There is no intended visible change on either engine. Simultaneous
scenes no longer share holds, and an old captured service cannot release a
replacement attachment's hold. Cover both rules on fake and headless Cesium
engines, including an old orbit ending after reattachment.

Viewer-reference lines fall from 910 to 891, Navara-kind checks from 2 to 1,
and engine-name lines from 33 to 32. All other coupling counts stay unchanged.

Checked in the browser, keyless: qa-perf passes on both engines with the
same idle, active and release counts as before (24 checks on Cesium, 22 on
Navara).
This commit is contained in:
German Khokhlov committed 2026-11-07 16:56:34 +04:00
1 parent 4252ed0798
commit 0459ee6d58
87 files changed
+720 -935

No files matched your search

+6 -23
View File
@@ -1,15 +1,5 @@
// GlobeRender on the app's render governor, which owns Cesium's
// requestRenderMode and maximumRenderTimeChange; the engine only takes a
// hold under its own owner id. The full-frame effects (visual styles,
// bloom, sharpening) are the scene's post stages (postStages.js), the
// contact sonar the scene's native draw commands (sonar.js).
// Cesium owns its render mode and scene effects. Scene services drive this API.
import {
governorRequestRender,
holdContinuousRender,
isRenderGovernorInstalled,
releaseContinuousRender,
} from '../../renderGovernor.js';
import { CONTACT_SONAR_INITIAL, mergeContactSonar } from '../contract.js';
import { createCesiumPostStages } from './postStages.js';
import { createCesiumSonar } from './sonar.js';
@@ -21,8 +11,7 @@ export const RENDER_OWNER = 'globe-engine';
* @param {{ requestRender?: (reason: string) => void,
* createStage?: (options: object) => object,
* createSonar?: typeof createCesiumSonar }} [options] `requestRender`
* defaults to the render governor when it governs this viewer, else the
* scene itself (before the governor is installed, or on another viewer);
* defaults to the scene itself;
* `createStage` (postStages.js) and `createSonar` are test seams.
* @returns {{ render: import('../contract.js').GlobeRender,
* sonarDiagnostics: () => object, destroy: () => void }}
@@ -30,15 +19,12 @@ export const RENDER_OWNER = 'globe-engine';
export function createCesiumRender(
viewer,
{
requestRender = (reason) => {
if (isRenderGovernorInstalled(viewer)) governorRequestRender(reason);
else viewer.scene.requestRender?.();
},
requestRender = () => viewer.scene.requestRender?.(),
createStage,
createSonar = createCesiumSonar,
} = {},
) {
let held = false;
viewer.scene.maximumRenderTimeChange = Infinity;
const effects = createCesiumPostStages(viewer, {
requestRender,
...(createStage ? { createStage } : {}),
@@ -69,11 +55,8 @@ export function createCesiumRender(
requestRender(reason);
},
setContinuous(enabled) {
held = Boolean(enabled);
if (held) holdContinuousRender(RENDER_OWNER);
else releaseContinuousRender(RENDER_OWNER);
viewer.scene.requestRenderMode = !enabled;
},
// The scene's real mode: another owner's hold keeps it continuous.
isContinuous: () => viewer.scene.requestRenderMode === false,
...effects.render,
setContactSonar(options) {
@@ -93,7 +76,7 @@ export function createCesiumRender(
render,
sonarDiagnostics: () => sonar.diagnostics(),
destroy() {
if (held) render.setContinuous(false);
render.setContinuous(false);
removeFrameWatch?.();
sonar.destroy();
effects.destroy();