[Fix] (MG_Backend/DirectVulkan): key the sampled-set walk-skip on a program lifetime id, not the recyclable GL name, so a deleted+recreated program can't false-hit the cache

This commit is contained in:
2026-07-13 04:58:05 -04:00
parent f098983c9f
commit 7fe5247626
4 changed files with 24 additions and 8 deletions
@@ -3406,11 +3406,11 @@ void main() {
// elides re-resolving *which* textures are sampled, never their layout handling.
auto& sampledTextures = m_sampledTexturesScratch;
{
const Uint programIndex = program.GetExternalIndex();
const Uint64 programLifetimeId = program.GetLifetimeId();
const Uint32 programVersion = program.GetBackendStateVersion();
const Uint64 bindGeneration = MG_State::pGLContext->GetTextureBindGeneration();
const Bool sampledSetUnchanged =
m_lastSampledSetValid && m_lastSampledSetProgramIndex == programIndex &&
m_lastSampledSetValid && m_lastSampledSetProgramLifetimeId == programLifetimeId &&
m_lastSampledSetProgramVersion == programVersion &&
m_lastSampledSetTransformFlags == transformFlags &&
m_lastSampledSetBindGeneration == bindGeneration;
@@ -3419,7 +3419,7 @@ void main() {
m_uniformManager->CollectSampledTextures(program, programObj, sampledTextures);
MOBILEGL_ASSERT(hasSampledTextures, "%s: CollectSampledTextures failed", __func__);
m_lastSampledSetValid = true;
m_lastSampledSetProgramIndex = programIndex;
m_lastSampledSetProgramLifetimeId = programLifetimeId;
m_lastSampledSetProgramVersion = programVersion;
m_lastSampledSetTransformFlags = transformFlags;
m_lastSampledSetBindGeneration = bindGeneration;
@@ -404,15 +404,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Vector<DeferredDepthMipmapCleanup> m_deferredDepthMipmapCleanup;
// Skip the per-draw CollectSampledTextures walk (~5% of the render thread) when the sampled
// texture SET is provably unchanged from the previous draw: same program (external index +
// texture SET is provably unchanged from the previous draw: same program (lifetime id +
// backend-state version, which covers sampler-uniform reassignment / relink) and transform
// flags, and no texture bind/unbind/delete since (GetTextureBindGeneration). On a hit,
// m_sampledTexturesScratch still holds the previous draw's list and steps 2-4 (feedback /
// layout probe / transition) re-run on it, so layout correctness is unaffected - only the GL
// walk is skipped. Reset per command-buffer recording so a reused program/FBO address can't
// outlive a frame.
// walk is skipped. The program lifetime id (never reused, unlike the GL name) and the
// monotonic bind generation make the key ABA-proof; the per-command-buffer reset is a cheap
// belt-and-suspenders.
Bool m_lastSampledSetValid = false;
Uint m_lastSampledSetProgramIndex = 0;
Uint64 m_lastSampledSetProgramLifetimeId = 0;
Uint32 m_lastSampledSetProgramVersion = 0;
ProgramFactory::CompileOptionFlags m_lastSampledSetTransformFlags = {};
Uint64 m_lastSampledSetBindGeneration = 0;