From ad7340921e242faeeefa1727b3e94a202a0a2b70 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 16 Oct 2026 16:52:59 -0400 Subject: [PATCH] [Fix] (MG_Impl/GLImpl, MG_State/GLState, MG_Test/Texture, scripts/data): keep GENERATE_MIPMAP on the texture, not keyed by GL name - A process-wide map keyed by GL name gave a deleted texture's flag to the next texture created under the recycled name. - The flag is now texture object state, so it dies with its texture. --- .../MG_Impl/GLImpl/Texture/GL_Texture.cpp | 11 +++----- .../GLState/TextureState/TextureObject.h | 6 +++++ .../MG_Test/Texture/TextureByNameTest.cpp | 26 +++++++++++++++++++ scripts/data/structure_baseline.json | 2 +- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index af914160..aa3114f0 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -59,7 +59,6 @@ namespace MobileGL::MG_Impl::GLImpl { static SharedPtr nullTextureObject; - static UnorderedMap g_autoGenerateMipmapByTextureId; namespace { void SetTextureBorderColorFromFloats(const SharedPtr& textureObject, @@ -1321,7 +1320,7 @@ namespace MobileGL::MG_Impl::GLImpl { textureObject->GetSamplerObject()->SetMaxAnisotropy(static_cast(param)); break; case GL_GENERATE_MIPMAP: - g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != GL_FALSE); + textureObject->SetAutoGenerateMipmap(param != GL_FALSE); break; case GL_DEPTH_STENCIL_TEXTURE_MODE: if (param != GL_DEPTH_COMPONENT && param != GL_STENCIL_INDEX) { @@ -1435,7 +1434,7 @@ namespace MobileGL::MG_Impl::GLImpl { textureObject->GetSamplerObject()->SetMaxAnisotropy(param); break; case GL_GENERATE_MIPMAP: - g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != 0.0f); + textureObject->SetAutoGenerateMipmap(param != 0.0f); break; case GL_DEPTH_STENCIL_TEXTURE_MODE: if (param != GL_DEPTH_COMPONENT && param != GL_STENCIL_INDEX) { @@ -1599,11 +1598,7 @@ namespace MobileGL::MG_Impl::GLImpl { void MaybeAutoGenerateMipmap(const SharedPtr& textureObject, Bool isProxy, GLint level) { - if (isProxy || level != 0 || !textureObject) { - return; - } - const auto it = g_autoGenerateMipmapByTextureId.find(textureObject->GetExternalIndex()); - if (it == g_autoGenerateMipmapByTextureId.end() || !it->second) { + if (isProxy || level != 0 || !textureObject || !textureObject->GetAutoGenerateMipmap()) { return; } GenerateMipmap_Backend(textureObject); diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.h b/MobileGL/MG_State/GLState/TextureState/TextureObject.h index 47ab98ea..496034dd 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.h @@ -99,6 +99,9 @@ namespace MobileGL::MG_State::GLState { // DEPTH_COMPONENT until set, and meaningless for every other format. virtual GLenum GetDepthStencilTextureMode() const = 0; virtual void SetDepthStencilTextureMode(GLenum mode) = 0; + // GENERATE_MIPMAP: level 0 uploads regenerate the chain. Frontend-only, so no version moves. + virtual Bool GetAutoGenerateMipmap() const = 0; + virtual void SetAutoGenerateMipmap(Bool enabled) = 0; // ---- Texture views (ARB_texture_view / GL 4.6 core 8.18) ---- // The texture object whose immutable storage this one's texels actually live in, or @@ -206,6 +209,8 @@ namespace MobileGL::MG_State::GLState { // set_texture_params is addressed by resource and is independent of every binding. PipePublishParams(); } + Bool GetAutoGenerateMipmap() const override { return m_autoGenerateMipmap; } + void SetAutoGenerateMipmap(Bool enabled) override { m_autoGenerateMipmap = enabled; } protected: static Uint64 AllocateLifetimeId(); @@ -290,6 +295,7 @@ namespace MobileGL::MG_State::GLState { Uint m_viewNumLayers = 0; Int m_samples = 0; Bool m_fixedSampleLocations = true; + Bool m_autoGenerateMipmap = false; }; class TextureObjectMipmap : public TextureObjectBase { diff --git a/MobileGL/MG_Test/Texture/TextureByNameTest.cpp b/MobileGL/MG_Test/Texture/TextureByNameTest.cpp index f93397cd..80639f31 100644 --- a/MobileGL/MG_Test/Texture/TextureByNameTest.cpp +++ b/MobileGL/MG_Test/Texture/TextureByNameTest.cpp @@ -392,3 +392,29 @@ TEST_F(TextureByNameTest, MipmapGenerationChecksTheTargetOfBothForms) { MG_Impl::GLImpl::GenerateMipmap(GL_TEXTURE_RECTANGLE); ExpectSingleGlError(GL_INVALID_ENUM); } + +// GENERATE_MIPMAP belongs to the texture it was set on. GL names are recycled, so the next texture +// created under a deleted texture's name must start without the flag. +TEST_F(TextureByNameTest, AutoMipmapFlagDoesNotOutliveItsTexture) { + const ScopedBackendStubs stubs; + static Int generated; + generated = 0; + MG_Backend::gBackendFunctionsTable.GL.GenerateTextureMipmap = + [](const SharedPtr&, GLenum) { ++generated; }; + const Uint8 pixels[4 * 4 * 4] = {}; + + const GLuint deleted = CreateTexture(GL_TEXTURE_2D); + MG_Impl::GLImpl::TextureParameteri(deleted, GL_GENERATE_MIPMAP, GL_TRUE); + MG_Impl::GLImpl::TextureStorage2D(deleted, 3, GL_RGBA8, 4, 4); + MG_Impl::GLImpl::TextureSubImage2D(deleted, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); + ASSERT_EQ(generated, 1) << "the flag did not generate mipmaps on its own texture"; + MG_Impl::GLImpl::DeleteTextures(1, &deleted); + + const GLuint recycled = CreateTexture(GL_TEXTURE_2D); + ASSERT_EQ(recycled, deleted) << "the name was not recycled, so nothing here is tested"; + MG_Impl::GLImpl::TextureStorage2D(recycled, 3, GL_RGBA8, 4, 4); + MG_Impl::GLImpl::TextureSubImage2D(recycled, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); + EXPECT_EQ(generated, 1) << "the new texture inherited the deleted texture's GENERATE_MIPMAP"; +} diff --git a/scripts/data/structure_baseline.json b/scripts/data/structure_baseline.json index c7020f5e..4b5f8fe2 100644 --- a/scripts/data/structure_baseline.json +++ b/scripts/data/structure_baseline.json @@ -1,5 +1,5 @@ { - "file_excess_lines": 21859, + "file_excess_lines": 21854, "function_excess_lines": 15516, "layering_violations": 63 }