[Fix] (MG_Backend/DirectGLES, MG_State, Docs): CopyImageSubData held a registry reference across a re-entrant sync; retarget container rationales at the new erase contract

This commit is contained in:
2026-08-12 00:11:54 -04:00
parent 21ec744ef2
commit 8f3ce5f5b7
10 changed files with 61 additions and 34 deletions
@@ -67,9 +67,13 @@ namespace MobileGL::MG_State::GLState {
}
}
}
// Key-based erase skips FastSTL's successor-iterator scan, which is
// pure overhead here and dominates delete-heavy frames.
m_bufferObjects.erase(index);
// Erase through the iterator already in hand: erase(key) would repeat the
// find() from line 55, and the successor scan that once made key-based
// erase the cheaper of the two no longer happens here - erase(iterator)
// hands back an unconverted proxy, and the scan is what converting it
// would cost. The unbind loops above touch only the binding arrays, so
// `it` is still live.
m_bufferObjects.erase(it);
}
m_indexGenerator.Delete(index);
}
@@ -70,9 +70,10 @@ namespace MobileGL::MG_State::GLState {
void ShaderCompileAdoptionMap::SweepIfCrowded() {
if (m_entries.size() < m_sweepThreshold) return;
// Collect first, erase after: FastSTL::unordered_map is open-addressed, so erasing
// through an iterator that the same loop is still advancing is not worth reasoning
// about on a path this cold.
// Collect first, erase after: the map is open-addressed and erases by shifting the
// rest of the probe cluster into the hole, so an erase moves entries other than the
// erased one. Copying the keys out sidesteps that entirely, and this path is cold
// enough that the extra vector is not worth reasoning about the alternative.
Vector<ShaderSourceKey> dead;
for (const auto& entry : m_entries) {
const SharedPtr<ShaderCompileTask> node = entry.second.lock();