From 25a76c1b2008364405373101ab142b73b4486960 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 3 Oct 2026 02:25:57 -0400 Subject: [PATCH] [Fix] (Pipe): drain a texture's pending texels only under a context of the share group that wrote them. --- MobileGL/MG_Impl/Pipe/TextureEmit.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/MobileGL/MG_Impl/Pipe/TextureEmit.h b/MobileGL/MG_Impl/Pipe/TextureEmit.h index 764d3a4d..5ec15bb5 100644 --- a/MobileGL/MG_Impl/Pipe/TextureEmit.h +++ b/MobileGL/MG_Impl/Pipe/TextureEmit.h @@ -1166,7 +1166,10 @@ namespace MobileGL::MG_Pipe { if (present == key) return; } entry.DrainKeys.push_back(key); - m_drain.push_back(DrainEntry{handle, key}); + // The share group the texels are owed to: the one the stream is bound to while the + // GL call that wrote them runs (GLStreamScope binds it to the writing thread's + // context, whose group the texture is in). See DrainTextureSubData. + m_drain.push_back(DrainEntry{handle, key, MGPipeCurrentShareGroupToken()}); } // The DRAIN, at the validate point: one resource_subdata per dirty (storage owner, @@ -1189,7 +1192,19 @@ namespace MobileGL::MG_Pipe { m_draining = true; Uint64 bytes = 0; Vector retry; + // ONLY THE BOUND SHARE GROUP'S TEXELS. The list is the process's, and the validate + // point that drains it belongs to whichever thread draws next - in a client whose + // threads draw with contexts of different share groups, often not the group that + // wrote the texels. Its records would land in the drawing context's group, where the + // texture has no record, and the level's dirty flag would be cleared all the same: + // the texture's own context then sampled a texture that never got its texels. A + // level owed to another group waits for a verb of that group. + const Uint64 group = MGPipeCurrentShareGroupToken(); for (const DrainEntry& pending : m_drain) { + if (pending.Group != group) { + retry.push_back(pending); + continue; + } if (EmitOneLevel(pending, bytes)) continue; retry.push_back(pending); } @@ -1319,6 +1334,7 @@ namespace MobileGL::MG_Pipe { struct DrainEntry { MGPipeHandle Handle; Uint32 Key; + Uint64 Group; // MGPipeCurrentShareGroupToken() when the level went dirty }; static constexpr Uint32 PackLevelKey(MobileGL::TextureUploadTarget uploadTarget, Uint level) {