Files
NX2navi/runtime
chrg6 e70cbb6a39 Destroy finalized pools in vk_mem_collect outside every lock, not in the completion callback or under the upload lock.
pool_retire destroyed the record at once (destroy_rec: vmaDestroyBuffer of the mirror, vkDestroyBuffer and
vkFreeMemory of the imported memory, which the driver unpins). It ran in two places, and both were costly. In the
completion thread's callbacks it ran before done is published, so every fence waiter waited for those frees: 717.7 ms
in 7,250 calls in the 0.10.0 session, up to 76.8 ms within one 240-submission window at an area change. From
pool_wait_collect it ran under cmd_lock, in the upload flush of whichever thread collected first, such as the replay's
per-submission vk_upload_flush or the game's presenting thread. Every upload and deferral waited on cmd_lock
meanwhile, and a slow frame showed the time as unattributed.

Now pool_retire only moves the record from the retiring list to a new pool_dead list (retire_lock). vk_mem_collect
alone drains that list, after its cmd_lock section and holding no lock. The completion thread calls vk_mem_collect
right after it publishes done and wakes the waiters, and pool_fini calls it for its own frees. collect_locked
(vk_upload_flush, shutdown) never drains the list. vk_mem_shutdown destroys what is left on it, after its
vkDeviceWaitIdle. The trace=perf "mem: sizes" GPU line counts the records destroyed this way.

Not reproduced before the change: the cost was summed from the completion thread's per-callback lines of the 0.10.0
log, not measured on a frame. Checks that passed: pass_cc_check on vk_memory.c, no new -Wall -Wextra warnings,
gpa_check, mem_budget_check, tex_release_check, sync_hw_check, wb_lazy_check, mem_growth_check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 18:41:40 -05:00
..
2026-11-07 05:04:38 -05:00
2026-11-07 05:04:38 -05:00
2026-11-07 05:04:38 -05:00
2026-11-07 05:04:38 -05:00