MeshResourceManager
MeshResourceManager is the shared GPU mesh cache for immediate and
cache-backed .untold loads. It caches all renderable mesh arrays produced from
one .untold file, tracks which entities retain each named mesh, and evicts
unused cached geometry under memory pressure.
It is not the OCC CPU registry. Tile-owned OCC stubs use
ProgressiveAssetLoader and CPURuntimeEntry.
Core Data Model
resources: URL -> MeshResource (one cache entry per .untold file)
entityToMesh: EntityID -> (URL, name) (which cached mesh an entity retains)
A MeshResource stores all renderable mesh groups from a .untold file:
struct MeshResource {
var meshesByName: [String: [Mesh]]
var refCountByName: [String: Int]
var totalMemorySize: Int
var sourceURL: URL
var lastAccessFrame: Int
}
The cache key is the source URL. The per-mesh key is the runtime asset name.
Loading
When a caller requests a mesh:
The manager:
- Checks
resources[url]for a cached mesh group. - Uses a single-flight gate so concurrent requests for the same URL share one load.
- Loads the
.untoldfile throughNativeFormatLoader. - Converts every renderable
RuntimeAssetNodeto[Mesh]. - Stores the result in
meshesByName.
Only .untold files are supported by this runtime cache.
Reference Counting
When an entity begins using a cached mesh:
This records the entity-to-mesh mapping and increments the mesh name's reference count. When the entity unloads or is destroyed:
The mapping is removed and the reference count is decremented. Cache entries with live references are not eligible for eviction.
Cache Prewarming
Immediate registration paths can call:
This seeds the cache with meshes that were already loaded during registration, so later cache-backed requests do not reparse the file.
Eviction
Three cleanup paths are available:
| Method | Purpose |
|---|---|
evict(url:) |
Force-remove one URL if it has no live refs |
evictUnused() |
Sweep all zero-ref cache entries |
evictToFreeMemory(targetBytes:) |
LRU eviction of zero-ref entries until the target is reached |
Eviction calls mesh.cleanUp() on cached meshes to release Metal resources.
Relationship to Streaming
GeometryStreamingSystem uses two residency layers:
| Path | CPU/GPU source |
|---|---|
Immediate/full-load .untold geometry |
MeshResourceManager cache and entity-local mesh copies |
| Tile-owned OCC stubs | ProgressiveAssetLoader.CPURuntimeEntry uploaded on demand |
Full-load tile geometry is not tracked in loadedStreamingEntities, so ordinary
OCC LRU eviction does not free it. The streaming system now follows OCC eviction
with evictTileGeometry(...) when geometry pressure remains high; normal tile
unload and GeometryStreamingSystem.forceUnloadAllParsedTiles() are the other
paths that tear down full-load tile geometry.