decentraland / decentraland/unity-explorer
[TECH DEBT] Primitive Meshes | Confirm no leak under memory pressure & extend shared-mesh reuse to boxes/planes
- Dominant language
- C#
- Stars
- 23
- Forks
- 17
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 94
Description
### π **Priority Level:**
Medium
### π **Area/Component:**
Primitive mesh rendering β `Utility.Primitives` (`BoxFactory`, `PlaneFactory`, `SphereFactory`, `PrimitivesUtility`) and `ECS.Unity.PrimitiveRenderer` (`SpherePrimitive`, mesh component pools registered in `PrimitivesRenderingPlugin`).
### π **Description:**
Follow-up to #9614, which introduced a single shared immutable `Mesh` for spheres. Two open questions were deliberately left out of that PR's scope and should be validated/pursued separately:
1. **Confirm primitive meshes do not leak** and are reclaimed under memory pressure.
2. **Investigate whether the same shared-mesh reuse is applicable to boxes and planes** (and cylinders), not just spheres.
### π **Current State:**
- The sphere optimization relies on the fact that the primitive component pools register **no `actionOnDestroy`** (meshes are never `Destroy`ed) and the pool registry is a global singleton β so the shared sphere mesh intentionally lives for the app lifetime. This is safe for a single shared mesh, but it also means per-instance Box/Plane/Cylinder meshes are pooled/reused and never released under memory pressure. We have not verified their lifecycle against the memory-budgeting / cache-cleanup path.
- Boxes and planes still allocate one `Mesh` per entity because they *can* carry per-instance custom UVs (`PBMeshRenderer.Box.Uvs` / `.Plane.Uvs`). However, the **default** (no custom UVs) box/plane is geometrically identical across all instances β the same premise that made the sphere shareable. Those instances could share a single default mesh, with only custom-UV instances getting a private mesh.
### π‘ **Proposed Solution:**
1. **Leak/pressure audit:** Capture a Unity Memory Profiler snapshot (or reuse the benchmark scene deployed for #9614 β world `sdk7testscenes.dcl.eth` @ `40,40`) while spawning and destroying large primitive grids. Confirm Mesh assets are returned/reclaimed as scenes unload and under memory pressure, and that nothing (shared sphere mesh included) grows unbounded across teleports.
2. **Extend shared-mesh reuse:** Prototype a shared default mesh for boxes/planes (and cylinders) β share when no custom UVs are present, fall back to a per-instance mesh only when `Uvs` are supplied. Measure the Mesh-count reduction against the existing benchmark scene.
### βοΈ **Impact Assessment:**
#### Performance Impact:
Potential large reduction in Mesh asset count / native memory for scenes that spawn many default boxes/planes (mirrors the sphere win in #9614). Leak audit protects against unbounded growth across scene loads/teleports.
#### Maintainability Impact:
Consolidating on the shared-mesh pattern (already centralized via `PrimitivesUtility`) reduces per-factory divergence. Requires clear documentation of which primitives are shared vs per-instance and why.
#### Risk of Refactoring:
Medium. Sharing a mesh across box/plane instances requires guaranteeing the shared mesh is never mutated per instance (custom-UV path must branch to a private mesh). Getting the shared/immutable boundary wrong could cause cross-entity visual corruption. The leak audit itself is low risk (measurement only).
### π **Effort Estimate:**
M
### π **Dependencies:**
- Builds on #9614 (shared sphere mesh; `PrimitivesUtility.ApplyUVs`).
- Benchmark scene: decentraland/sdk7-test-scenes#84 (deployed to world `sdk7testscenes.dcl.eth` @ `40,40`).
### π₯οΈ **Additional Notes:**
Use the `unity-memory-snapshot` tooling to parse `.snap` captures headlessly for the leak audit. Verify behavior specifically across scene unload and teleport, since that is where pooled-but-never-released meshes would accumulate.
Contributor guide
Assessment
This issue has not been assessed yet.