Skip to content

alias_take_over notes the sRGB / linear twins' serials when it evicts their parent (fixes #2125) - #2323

Open
dean0396 wants to merge 1 commit into
seedds:mainfrom
dean0396:pr-2125
Open

dean0396 wants to merge 1 commit into
seedds:mainfrom
dean0396:pr-2125

Conversation

@dean0396

@dean0396 dean0396 commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Fixes #2125.

When a storage takeover (alias_take_over) evicts a shared texture that an sRGB / linear twin's view was made of (tex_mtl_'s srgb_twins path), the twin's texture IDs keep that view. Since #1489 the takeover records ser_note(0), and that note names none of the twin's IDs. So they stay on the fast path (tex_fast_rid), and the pool tables, patched or built whole, keep the view's resource ID. Meanwhile the parent leaves the sharing table and, once the takeover's submission completes, the residency set. The stale-view check in tex_mtl_ that the takeover's comment relies on only runs when something names the twin's texture object (a render target, a copy, a clear). Before #1489, the takeover's bare g_ser_gen++ sent every ID there.

The change, all in nvn_mtl.m, ported from my fork, where the code around it is different:

  • g_twin_par maps each shared texture a twin view was made of to the serials that took one (up to 8, under g_smu).
  • tex_mtl_'s twin path adds the serial only after checking, under that lock, that the parent is still the sharing table's entry for its key. Otherwise a takeover on another thread could have evicted it in between and found no list. In that case the view is dropped and the key looked up again (twice at most).
  • alias_take_over notes each listed serial of a texture it evicts, just before alias_del removes its entry. Only those IDs take the slow path, tex_mtl_ finds the view stale, and the tables are patched for just those IDs.
  • When a list fills, its finalized serials are dropped (a retired ID's view goes at the submission's end anyway). A list still full of live serials makes the takeover's bump a bare g_ser_gen++, which builds every table whole, as before A pool table takes again only the IDs a change reaches instead of being walked whole: registrations, memory pool changes, retired IDs at a new submission and storage takeovers each leave a note #1489.
  • alias_del, which 352e4a6 made the sharing table's one remover, drops the list of what it removes. So a pool's release (mtl_alias_drop_pool, whose bump already has no note) drops it too. The format-view upgrade replaces the texture in place and already bumps with no note: it drops the list and lists the asking serial again for the view it makes on the upgraded texture.

I haven't seen a visible symptom of this on main. It was found by reading the code and shown with the test below.

Checked

  • Tests (run on 352e4a6, and "unmodified main" below means that commit; the branch is now rebased onto 8b55ebb, which changes only the shader build tools and docs, and t_pool_notes 119/0, t_alias_takeover 45/0 and t_feedback 278/0 were re-run there):
    • t_pool_notes: the twin case (IDs 7 / 8 / 9) passed only because the note from ID 8's first resolution took ID 8 again in the takeover's walk. It now takes one more table() walk between the two, as in the issue. With that, unmodified main fails 2 of 83 checks (ID 8 keeps the view, and the patched table names it), three runs out of three. The case's checks move one walk later, because the takeover happens inside a walk and its notes reach the next one. It also keeps ID 8's first entry instead of reading b15 again: with the extra walks, that buffer is reused by the time of the check.
    • A new twin list case: a list that fills drops its finalized serials (only the live twin is noted), and a list full of live serials makes the bump bare. With the change, 119 checks and 0 failures, three runs out of three. Taking the twins' notes out of alias_take_over fails 3 checks, and taking the bare-bump fallback out fails 1.
    • t_alias_takeover passes (45 checks), and so does t_image_alias with and without the encoder thread (337 checks each).
    • make -k -C dm/gfx/tests GAME=0400486024DEC000 run: everything passes except, in some runs, t_feedback's check "with nothing running: a commit" (1 of 278), which fails just as often on unmodified main and has nothing to do with this change. t_refl and t_rt_range_ro skip the checks that need reflection samples, which this Mac doesn't have.
    • test_docs passes, and docs_symptoms.py --check reports the index current.
    • The Mac host (make -C dm/host GAME=0400486024DEC000) builds with the same 58 warnings as main.
  • Games run: none. No visible symptom is known, and I haven't built Ocarina of Time, the only game on this Mac, on main.
  • Devices and OS: MacBook Pro M3 Max (36 GB), macOS 26.7.2.
  • regress.py: no report, for the same reason. The change only reaches takeovers of a texture an sRGB / linear twin was made of: with no list, nothing changes.
  • Not checked: iOS, other games.

Overlapping PRs

Docs

  • New entry in docs/reference/nvn-objects.md (A storage takeover notes the serials of an sRGB / linear twin of what it evicts), linked from the takeover bullet of "Pool tables patched instead of built whole" and from the sRGB / linear pair entry in rendering.md. python3 dm/tools/docs_symptoms.py was run.
  • A chain tool changed (none)
  • No game files, keys or data extracted from a game in the change or the attachments

@github-actions github-actions Bot added nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests) docs Documentation labels Nov 11, 2026
…keover evicts the texture its view was made of: since PR seedds#1489 (0c7e88b) alias_take_over records the eviction as ser_note(0), which names none of the twin's IDs, so they kept the cached view on the fast path (tex_fast_rid) and the pool tables, patched or built whole, kept its resource ID, while the parent left the sharing table and, once the takeover's submission completed, the residency set (issue seedds#2125). The stale-view check in tex_mtl_ that the takeover's comment relied on ran only when something named the twin's texture object (a render target, a copy, a clear); before seedds#1489 the takeover's bare g_ser_gen++ sent every ID there. tex_mtl_'s twin path now lists the serial that took the view against its parent (g_twin_par, up to 8, under g_smu), only after checking under the same lock that the parent is still the sharing table's entry for its key; otherwise a takeover on another thread (tex_mtl_ also runs on the present thread and in mtl_read_texels) evicted it in between and found no list, so the view is dropped and the key looked up again. alias_take_over notes each listed serial of a texture it evicts, before alias_del removes its entry, so only those IDs take the slow path, where tex_mtl_ finds the view stale, and the tables are patched for them alone. A list that fills drops its finalized serials (a retired ID's view goes at the submission's end anyway), and one still full of live serials makes the takeover's bump a bare g_ser_gen++. alias_del, which 352e4a6 (PR seedds#2229) made the sharing table's one remover, drops the list of what it removes, so a pool's release (mtl_alias_drop_pool, whose bump already has no note) drops it too; the format-view upgrade, which replaces the texture in place and bumps with no note, drops it and lists the asking serial again for the view it makes on the upgraded texture. The reference entry (A storage takeover notes the serials of an sRGB / linear twin of what it evicts) says so. t_pool_notes's twin case (IDs 7 / 8 / 9) passed only because the note of ID 8's first resolution took ID 8 again in the takeover's walk: it now takes one walk between the two, as the issue proposes, which fails 2 of 83 checks on the old code, and its checks move one walk later, since the takeover's notes reach the walk after it; it keeps ID 8's first entry instead of reading that table's buffer again, which is used again once its submission completes. A new twin list case checks that a list that fills drops its finalized serials (only the live twin is noted) and that one full of live serials makes the bump bare. Checked on 352e4a6 and, after a rebase onto 8b55ebb (shader build tools and docs only), t_pool_notes, t_alias_takeover and t_feedback again there; M3 Max, macOS 26.7.2: t_pool_notes 119 checks, 0 failed, three runs (the twin case alone fails 2 of 83 on unmodified 352e4a6, three runs; taking the twins' notes out of alias_take_over fails 3, the bare-bump fallback 1); t_alias_takeover 45 checks and t_image_alias 337 with and without the encoder thread, 0 failed; make -k -C dm/gfx/tests GAME=0400486024DEC000 run: every test passes but, in some runs, t_feedback's check "with nothing running: a commit" (1 of 278), which fails as often on unmodified main and is unrelated (t_refl and t_rt_range_ro skip the reflection samples this Mac does not have); docs_symptoms.py --check; test_docs; the Mac host builds with main's 58 warnings. Not run: a game (no visible symptom is known, and Ocarina of Time, the only game on this Mac, was not built on main), regress.py (the reach is takeovers of a texture an sRGB / linear twin was made of), iOS
@dean0396

Copy link
Copy Markdown
Contributor Author

Rebased onto main (8b55ebb) now that #2229's cell index has landed (352e4a6). The conflict was in the eviction loops, which 352e4a6 replaced with alias_del.

What changed in the resolution:

  • The twin list is now dropped in alias_del, which 352e4a6 made the sharing table's one remover. A pool's release (mtl_alias_drop_pool) drops it from there now, instead of from its own loop.
  • alias_take_over notes each listed serial of a texture it evicts just before calling alias_del. A list full of live serials still makes its bump a bare g_ser_gen++.
  • The format-view upgrade and the twin path in tex_mtl_ are as before (352e4a6 doesn't touch either). The candidate search by pool cell doesn't change anything here: this change only affects what is noted once a texture is evicted.
  • The reference entry and the commit message now describe it in terms of alias_del. The test is unchanged.

Checked on 352e4a6, and again on 8b55ebb after the rebase (t_pool_notes 119/0, t_alias_takeover 45/0, t_feedback 278/0); MacBook Pro M3 Max, macOS 26.7.2:

  • t_pool_notes: 119 checks, 0 failed, three runs. The twin case alone fails 2 of 83 on unmodified 352e4a6, three runs. Taking the twins' notes out of alias_take_over fails 3, and taking the bare-bump fallback out fails 1.
  • t_alias_takeover: 45 checks, 0 failed. t_image_alias: 337 checks, 0 failed, with and without the encoder thread.
  • make -k -C dm/gfx/tests GAME=0400486024DEC000 run: everything passes except, in some runs, t_feedback's check "with nothing running: a commit" (1 of 278), which fails as often on unmodified main (t_refl and t_rt_range_ro skip the checks that need reflection samples, which this Mac doesn't have).
  • docs_symptoms.py --check and test_docs pass. The Mac host builds with main's 58 warnings.

No game run, as before. I've updated the description to match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sRGB / linear twin keeps its view of an evicted parent since #1489: alias_take_over's ser_note(0) never reaches the twin's texture IDs

1 participant