fix(M00): release GUI capture render resources
Work-Package: M00-QAR-GUI-RID-SHUTDOWN-001 Agent: sindo-main-codex Tests: render baseline dry-run; runtime cache shutdown; comparator self-test; coordination and documentation gates Fidelity: shutdown-only ownership fix; no visual or Blizzlike335 behavior change
This commit is contained in:
@@ -374,6 +374,39 @@ func _exit_tree() -> void:
|
||||
_shutting_down = true
|
||||
_wait_for_tile_tasks()
|
||||
_clear_streamed_world()
|
||||
_release_runtime_caches_for_shutdown()
|
||||
|
||||
|
||||
## Frees detached prototype nodes and releases render resources owned by this
|
||||
## loader after all asynchronous work has completed. Map refreshes retain these
|
||||
## caches; only scene shutdown destroys them.
|
||||
func _release_runtime_caches_for_shutdown() -> void:
|
||||
_free_detached_node_cache(_m2_scene_cache)
|
||||
_free_detached_node_cache(_m2_animated_scene_cache)
|
||||
_free_detached_node_cache(_wmo_prototype_cache)
|
||||
_m2_mesh_cache.clear()
|
||||
_m2_static_animation_cache.clear()
|
||||
_m2_missing_cache.clear()
|
||||
_wmo_render_cache.clear()
|
||||
_wmo_scene_resource_cache.clear()
|
||||
_wmo_render_missing_cache.clear()
|
||||
_wmo_scene_cache_missing.clear()
|
||||
_wmo_missing_cache.clear()
|
||||
_shared_tex_cache.clear()
|
||||
|
||||
|
||||
func _free_detached_node_cache(node_cache: Dictionary) -> void:
|
||||
for cached_value in node_cache.values():
|
||||
if not (cached_value is Node):
|
||||
continue
|
||||
var cached_node := cached_value as Node
|
||||
if not is_instance_valid(cached_node):
|
||||
continue
|
||||
if cached_node.is_inside_tree():
|
||||
cached_node.queue_free()
|
||||
else:
|
||||
cached_node.free()
|
||||
node_cache.clear()
|
||||
|
||||
|
||||
func _apply_quality_preset() -> void:
|
||||
@@ -2781,15 +2814,27 @@ func _clear_streamed_world() -> void:
|
||||
_free_render_instance(chunk_rid)
|
||||
var tile_root: Node = state.get("root", null)
|
||||
if tile_root:
|
||||
tile_root.queue_free()
|
||||
_queue_free_streamed_node(tile_root)
|
||||
|
||||
_tile_states.clear()
|
||||
_clear_tile_mesh_cache()
|
||||
_clear_quality_terrain_mesh_cache()
|
||||
_clear_wmo_registry()
|
||||
_ensure_world_wmo_root()
|
||||
if enable_wmo:
|
||||
_place_global_wmo()
|
||||
if not _shutting_down:
|
||||
_ensure_world_wmo_root()
|
||||
if enable_wmo:
|
||||
_place_global_wmo()
|
||||
|
||||
|
||||
## During world shutdown, parented nodes are recursively owned by the world
|
||||
## root. Queueing them separately from `_exit_tree()` can detach them from that
|
||||
## deletion and leave empty Node objects alive at engine teardown.
|
||||
func _queue_free_streamed_node(node: Node) -> void:
|
||||
if node == null or not is_instance_valid(node):
|
||||
return
|
||||
if _shutting_down and node.is_inside_tree():
|
||||
return
|
||||
node.queue_free()
|
||||
|
||||
|
||||
func _reset_terrain_root_children() -> void:
|
||||
@@ -3889,10 +3934,10 @@ func _clear_wmo_registry() -> void:
|
||||
var entry: Dictionary = entry_variant
|
||||
var node: Node = entry.get("node", null)
|
||||
if node and is_instance_valid(node):
|
||||
node.queue_free()
|
||||
_queue_free_streamed_node(node)
|
||||
_wmo_registry.clear()
|
||||
if _world_wmo_root and is_instance_valid(_world_wmo_root):
|
||||
_world_wmo_root.queue_free()
|
||||
_queue_free_streamed_node(_world_wmo_root)
|
||||
_world_wmo_root = null
|
||||
|
||||
|
||||
@@ -4458,7 +4503,7 @@ func _cancel_m2_build_job(key: String) -> void:
|
||||
var job: Dictionary = _m2_build_jobs[key]
|
||||
var root: Node = job.get("root", null)
|
||||
if root != null and is_instance_valid(root):
|
||||
root.queue_free()
|
||||
_queue_free_streamed_node(root)
|
||||
_m2_build_jobs.erase(key)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user