`Scene._enableEdgeVisibility` is never reset once enabled
- Dominant language
- JavaScript
- Stars
- 15.7k
- Forks
- 3.9k
- Avg merge
- 4d 6h
- Merged PRs (30d)
- 34
Description
### What happened?
Spun off from [this discussion](https://github.com/CesiumGS/cesium/pull/13178#discussion_r3666694127) on #13178, where the identical pattern was fixed for planar fill.
**Problem**
In `updateAndRenderPrimitives`, `_enableEdgeVisibility` is set true the first time any primitive requests edge visibility and stays true for the lifetime of the scene:
https://github.com/CesiumGS/cesium/blob/25741aacb23eac1df82fca39e00fcb4d35943092/packages/engine/Source/Scene/Scene.js#L3749-L3754
After the last edge-visibility model is removed, the scene permanently keeps:
- `view.edgeFramebuffer` allocated and updated every frame — MRT with color, id, and packed-depth attachments (~12+ bytes/pixel), resized on every viewport change
- the edge pass machinery enabled (`czm_edgeColorTexture` etc. rebound each frame)
Verified empirically: after `primitives.remove(model)`, `_enableEdgeVisibility` remains `true` and the MRT framebuffer remains allocated.
**Fix** (mirror the planar fill fix in #13178)
1. `edgeVisibilityRequested` is only set at draw-command build time, so add a per-frame renewal in `ModelSceneGraph.pushPrimitiveDrawCommands` while edge primitives are rendering.
2. In Scene, assign `scene._enableEdgeVisibility = frameState.edgeVisibilityRequested` each frame instead of setting it once and leaving it.
3. Release `edgeFramebuffer` GPU resources when disabled (recreate on demand via its existing `update()`); skip release on pick frames to avoid thrash.
4. Guard the edge passes against an unallocated framebuffer on the (re)enable frame — `updateAndClearFramebuffers` runs before primitives update, so the framebuffer isn't created until the frame after the flag flips.
**Repro**
1. Load a model with `EXT_mesh_primitive_edge_visibility` data and let it render:
```js
const model = await Cesium.Model.fromGltfAsync({
url: ".glb",
edgeDisplayMode: Cesium.EdgeDisplayMode.SURFACES_AND_EDGES,
});
viewer.scene.primitives.add(model);
```
2. Remove it:
```js
viewer.scene.primitives.remove(model);
```
3. Inspect scene state:
```js
console.log(viewer.scene._enableEdgeVisibility);
// true — never resets
console.log(Cesium.defined(viewer.scene._view.edgeFramebuffer._framebufferManager.framebuffer));
// true — MRT attachments still allocated
```
**Expected:** flag resets to false and the edge framebuffer is released once no
edge-visibility primitives are rendering.
**Actual:** flag stays true; the MRT framebuffer (color/id/depth attachments) is
updated every frame and resized on viewport changes for the scene's lifetime.
### Reproduction steps
1. Load a model with `EXT_mesh_primitive_edge_visibility` data and let it render:
```js
const model = await Cesium.Model.fromGltfAsync({
url: ".glb",
edgeDisplayMode: Cesium.EdgeDisplayMode.SURFACES_AND_EDGES,
});
viewer.scene.primitives.add(model);
```
2. Remove it:
```js
viewer.scene.primitives.remove(model);
```
3. Inspect scene state:
```js
console.log(viewer.scene._enableEdgeVisibility);
// true — never resets
console.log(viewer.scene._view.edgeFramebuffer._framebufferManager);
// MRT attachments still allocated
```
**Expected:** flag resets to false and the edge framebuffer is released once no
edge-visibility primitives are rendering.
**Actual:** flag stays true; the MRT framebuffer (color/id/depth attachments) is
updated every frame and resized on viewport changes for the scene's lifetime.
### Sandcastle example
_No response_
### Environment
Browser:
CesiumJS Version: Latest
Operating System: All
### AI acknowledgment
- [x] I used AI to generate this issue report.
- [x] (If the above is checked) I have reviewed the AI-generated content before submitting.
Contributor guide
Research direction
Start in Scene.js at the updateAndRenderPrimitives and edge-pass handling, then inspect ModelSceneGraph.pushPrimitiveDrawCommands and compare the planar-fill fix from #13178. Run the supplied model-removal reproduction; done means edge visibility resets after removal, the edge framebuffer is released when appropriate, and re-enabling does not fail on the first frame.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- computer-graphics, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100