From f38dbf018d8d3b117187f26a71d5a07d30e8ab85 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Tue, 4 Aug 2026 10:37:46 -0400 Subject: [PATCH] [Fix] (MG_State): give a rectangle texture its own initial sampler state Every texture object started from the shared defaults, which are the 2D ones: TEXTURE_MIN_FILTER of NEAREST_MIPMAP_LINEAR and TEXTURE_WRAP_S/T of REPEAT. A rectangle texture has no mip chain at all, so GL gives it a different initial state - LINEAR and CLAMP_TO_EDGE (GL 4.6 core table 23.15) - and a mipmapped minification filter is not even a legal value to set on one. With the 2D default in place a rectangle texture was mipmap-incomplete the moment it was created, and an application that (correctly) never touches the filters read (0, 0, 0, 1) out of every lookup. That is what the eleven KHR-GL40.texture_gather.*-2drect cases saw: they set only the wrap modes, because the filters are already what a rectangle texture needs. --- .../MG_State/GLState/TextureState/TextureObject.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp index fb3e6f74..6eee7f76 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp @@ -24,6 +24,19 @@ namespace MobileGL { TextureObjectBase::TextureObjectBase(TextureTarget target, Uint externalIndex) : m_externalIndex(externalIndex), m_lifetimeId(AllocateLifetimeId()), m_target(target) { m_sampler = MakeShared(0); + if (target == TextureTarget::TextureRectangle) { + // A rectangle texture has no mip chain, so its initial sampler state is not + // the shared one: TEXTURE_MIN_FILTER is LINEAR and TEXTURE_WRAP_S/T are + // CLAMP_TO_EDGE (GL 4.6 core table 23.15). Leaving the 2D default of + // NEAREST_MIPMAP_LINEAR in place makes the texture mipmap-incomplete from + // birth, and every lookup that the application never re-filtered reads + // (0, 0, 0, 1) instead of its contents. + m_sampler->SetMinFilter(SamplerFilterMode::Linear); + m_sampler->SetMipmapMode(SamplerMipmapMode::None); + m_sampler->SetWrapS(SamplerWrapMode::ClampToEdge); + m_sampler->SetWrapT(SamplerWrapMode::ClampToEdge); + m_sampler->SetWrapR(SamplerWrapMode::ClampToEdge); + } } TextureInternalFormat TextureObjectBase::GetFormat() const {