[Refactor] (Espryt): key every backend twin on {slot, gen} instead of the frontend object heap address

- ResolveVaoTwin, SyncCurrentProgram and BindCurrentFBO stop consulting the three
  TwinLookupMemos on the handle arm. The memo existed to replace the registry hash probe
  with an array index, and the slot table Find already IS that array index; its safety
  argument - owner-equality of a weak snapshot against a recycled heap address - is
  answered by the generation instead of re-derived per lookup. OwnerEquals, the memo
  template and its three instances are now compiled only under MOBILEGL_PIPE_LEGACY_MEMOS.
- UnitSamplerLookupMemo compares {slot, gen} instead of owner-equality, and keeps its "a
  miss is never cached" contract verbatim: the sampler twin is created later in the same
  draw by the program pass.
- UnitBindingsSnapshot holds lifetime ids rather than weak_ptrs under push. It cannot hold
  handles: a bound-but-never-synced texture has no twin and so no handle, and two of those
  would read as equal. A lifetime id exists before the twin does and is never handed out
  twice, which is the property the weak_ptr was there for.
- SyncTextureObjectToBackend keeps its by-value copy only to hold the twin alive across the
  nested glTextureView sync; the second Find-or-create and the put-the-twin-back repair are
  gone on the handle arm, because nothing there erases a live entry.
- The one direct-iteration site walks ForEachLive, which hands over a strong reference to
  the framebuffer instead of the map key - the raw frontend address it had to null- and
  expiry-check by hand before dereferencing.
- GetFramebufferBindingSlotFast becomes GetFramebufferBindingSlotChecked and, under push,
  reads MGB_CTX->GetFramebufferBindingSlot(target) every time. This closes the P1 accessor
  bypass: the cached raw pointer ran the checked accessor once per context change and then
  handed out the pointee forever, so the per-verb poison stamp and the verify read-hook
  were skipped at all five call sites.
- Every one of these is a push-build arm; the pull build compiles the pre-P2 text and its
  symbol report stays 0 added / 0 removed / 0 renamed with no new resize.
This commit is contained in:
Swung0x48
2026-09-07 23:18:09 -04:00
committed by swung0x48
parent f4dbea2300
commit bd2092f4eb
2 changed files with 270 additions and 18 deletions
@@ -407,6 +407,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
return MG_Pipe::kMGPipeNullHandle;
}
// The twin at a handle, or null when the slot is free or its Gen has moved on. This is
// the lookup a backend memo that already holds a handle wants: no lifetime-id probe.
BackendPtr* FindByHandle(MG_Pipe::MGPipeHandle handle) {
if (EsprytSlotTablesEnabled()) {
return m_slotTable.FindByHandle(handle);
}
return nullptr;
}
// fn(const StatePtr& state, const BackendPtr& twin) over every live entry. The legacy
// begin()/end() handed out the map key, i.e. the raw frontend address - exactly the
// identity the backend must stop reading - and handed it out for entries whose state