vk_memory.c hands out page write generations (gen_now, 32 bits) with no wrap handling. Past the wrap, textures and
pool mirrors the CPU writes can miss a write, and every check reads as a write. At about 181 generations a frame that
takes about 110 h at 60 fps or 27 h at 240. Only trace=perf's "mem: sizes" counted them, so nothing in a player's log
could tell a "textures went stale after a day" report from other causes.
The nine "++gen_now" sites now call gen_next, which hands out the next generation (gen_lock held exclusively, as at
every site). When the value reaches 0xC0000000, 0xD0000000, 0xE0000000 or 0xF0000000 it logs the count, the frame,
the rate per frame and about how many hours of play are left at that rate. At the wrap it logs that the generations
ran out. That is five lines at most a session and one predicted branch per generation. The log queue takes no lock
of vk_memory.c, so logging under gen_lock is safe. The wrap handling itself waits for approval.
The new tests/gen_wrap_check extracts the section from the "page write generations" banner to the "dirty census"
banner and runs it with stubs. It checks one line at each mark and at the wrap and none elsewhere, and the first
line's rate and hours. It also expects the four comparisons that are known to answer wrong across the wrap, and says
so: the change that handles the wrap turns them into failures there and flips them. On the code before this change
the check fails (no lines). Checks that passed: gen_wrap_check, pass_cc_check on vk_memory.c, no new -Wall -Wextra
warnings, gpa_check, mem_growth_check, mem_budget_check, wb_lazy_check, tex_release_check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>