Download scripts/core/mesh_pool.gd from geter62/monkeystudio: direct link, hf CLI and curl.
- Browser
- Download file 1.75 kB
-
https://huggingface.co/geter62/monkeystudio/resolve/main/scripts/core/mesh_pool.gd
- Command line
-
hf download hf://geter62/monkeystudio/scripts/core/mesh_pool.gd
-
curl -L -o mesh_pool.gd https://huggingface.co/geter62/monkeystudio/resolve/main/scripts/core/mesh_pool.gd
1.75 kB
| extends Node | |
| ## | |
| ## MeshPool - recycles ArrayMesh instances to avoid allocation churn. | |
| ## | |
| ## On low-RAM Android, creating and freeing ArrayMesh objects every frame causes | |
| ## GC spikes and fragmentation. This pool keeps a bounded number of meshes alive | |
| ## and reuses them. Meshes handed back to the pool have their surfaces cleared, | |
| ## freeing their GPU buffers while keeping the object (and its native handle). | |
| ## | |
| signal pool_grew(size: int) | |
| signal pool_trimmed(freed: int) | |
| ## Hard cap so the pool itself cannot become the memory leak. | |
| @export var max_pooled: int = 32 | |
| var _free: Array[ArrayMesh] = [] | |
| var _live_count: int = 0 | |
| var _peak_live: int = 0 | |
| ## Get a cleared mesh. Reuses a pooled one if available. | |
| func acquire_mesh() -> ArrayMesh: | |
| var mesh: ArrayMesh | |
| if _free.size() > 0: | |
| mesh = _free.pop_back() | |
| else: | |
| mesh = ArrayMesh.new() | |
| _live_count += 1 | |
| _peak_live = maxi(_peak_live, _live_count) | |
| return mesh | |
| ## Return a mesh for reuse. Clears surfaces so its VRAM is released immediately. | |
| func release_mesh(mesh: ArrayMesh) -> void: | |
| if mesh == null: | |
| return | |
| _live_count = maxi(0, _live_count - 1) | |
| # Drop all surfaces: this frees the vertex buffers on the GPU side. | |
| for i in range(mesh.get_surface_count()): | |
| pass | |
| mesh.clear_surfaces() | |
| if _free.size() < max_pooled: | |
| _free.append(mesh) | |
| else: | |
| # Pool is full: let Godot free this one (mesh has no surfaces = cheap). | |
| pass | |
| ## Remove pooled-but-unused meshes down to `keep`. Call on scene transitions. | |
| func trim(keep: int = 8) -> void: | |
| var freed := 0 | |
| while _free.size() > keep: | |
| _free.pop_back() | |
| freed += 1 | |
| if freed > 0: | |
| pool_trimmed.emit(freed) | |
| func stats() -> Dictionary: | |
| return { | |
| "pooled": _free.size(), | |
| "live": _live_count, | |
| "peak_live": _peak_live, | |
| } | |