diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index b6c0baa2..259378c8 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -7883,9 +7883,15 @@ void main() { void VulkanRenderer::GenerateMipmap(GLenum target) { const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); - MOBILEGL_ASSERT(textureTarget == TextureTarget::Texture2D || textureTarget == TextureTarget::Texture2DArray || - textureTarget == TextureTarget::Texture3D || textureTarget == TextureTarget::TextureCubeMap, - "GenerateMipmap currently only supports GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D, and GL_TEXTURE_CUBE_MAP."); + // The other mipmappable targets - 1D, 1D array, cube map array - are legal GL and the front + // end lets them through, so reaching one here is a coverage gap in this backend, not a + // broken invariant. Declining leaves the mip chain unwritten; asserting took the process + // down with it. + if (textureTarget != TextureTarget::Texture2D && textureTarget != TextureTarget::Texture2DArray && + textureTarget != TextureTarget::Texture3D && textureTarget != TextureTarget::TextureCubeMap) { + MGLOG_W("GenerateMipmap: unsupported target %s", MG_Util::ConvertTextureTargetToString(textureTarget).c_str()); + return; + } auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); auto texture = textureUnit.GetBindingSlot(textureTarget).GetBoundObject(); diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index 49982bf6..3993d3b7 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -4309,6 +4309,24 @@ namespace MobileGL::MG_Impl::GLImpl { bindImageTexture(unit, texture, level, layered, layer, access, format); } + // GL 4.6 core 8.14.4: a cube map that is not cube complete has no consistent set of faces to + // filter down, so generating its mipmaps is INVALID_OPERATION. Without this the incomplete + // texture reached the backend, where DirectVulkan asserts on it and takes the process down. + Bool ValidateGenerateMipmapTexture(const SharedPtr& textureObject, + const char* caller) { + if (!textureObject) return false; + const auto target = textureObject->GetTarget(); + if ((target == TextureTarget::TextureCubeMap || target == TextureTarget::TextureCubeMapArray) && + !textureObject->IsComplete()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", caller, + "Mipmap generation requires a cube complete cube map texture.")); + return false; + } + return true; + } + void GenerateMipmap(GLenum target) { const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); if (!TextureImpl::ValidateTextureTarget(textureTarget)) { @@ -4322,6 +4340,7 @@ namespace MobileGL::MG_Impl::GLImpl { MakeUnique("MG_Impl/GLImpl", __func__, "GenerateMipmap requires a bound texture.")); return; } + if (!ValidateGenerateMipmapTexture(textureObject, __func__)) return; auto* mipmapTexture = dynamic_cast(textureObject.get()); MOBILEGL_ASSERT(mipmapTexture != nullptr, "GenerateMipmap requires mipmap texture storage."); @@ -4331,15 +4350,11 @@ namespace MobileGL::MG_Impl::GLImpl { void GenerateTextureMipmap(GLuint texture) { auto textureObject = GetTextureObjectByName(texture, __func__); - if (textureObject) { - auto* mipmapTexture = dynamic_cast(textureObject.get()); - MOBILEGL_ASSERT(mipmapTexture != nullptr, "GenerateTextureMipmap requires mipmap texture storage."); - } + if (!ValidateGenerateMipmapTexture(textureObject, __func__)) return; + auto* mipmapTexture = dynamic_cast(textureObject.get()); + MOBILEGL_ASSERT(mipmapTexture != nullptr, "GenerateTextureMipmap requires mipmap texture storage."); WithTemporarilyBoundNamedTexture(textureObject, [&](GLenum target) { - if (textureObject) { - auto* mipmapTexture = dynamic_cast(textureObject.get()); - EnsureGeneratedMipmapStorageAllocated(*mipmapTexture); - } + EnsureGeneratedMipmapStorageAllocated(*mipmapTexture); GenerateMipmap_Backend(target); }); }