From 027310f993f1fd6b4eb20afbeff0b89edbadd9ce Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sun, 2 Aug 2026 04:54:48 -0400 Subject: [PATCH] [Fix] (MG_Impl): ask whether a colour format is renderable per target The framebuffer-completeness check scanned every row of the backend's format-capability cache and called the format renderable if any target said so. That was already loose, and it broke outright once DirectGLES started widening three-channel formats so they stay renderable as multisample storage: the caveat capability recorded for the multisample target made GL_RGB8_SNORM look renderable everywhere, so an ordinary 2D GL_RGB8_SNORM texture attachment reported GL_FRAMEBUFFER_COMPLETE while the driver's own framebuffer was INCOMPLETE_ATTACHMENT. KHR-GL3x.packed_pixels stopped skipping those formats and read a framebuffer that could not be read, so all 18 of its rgb8_snorm cases got back an untouched buffer. Pass the row the attachment actually lives in - the texture's target, or the renderbuffer row - and consult only that one; a format is still asked about in general when the caller has no target. --- .../GLImpl/Framebuffer/GL_Framebuffer.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp index 40eb3166..da6dc6c9 100644 --- a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp @@ -101,7 +101,14 @@ namespace MobileGL::MG_Impl::GLImpl { // shared-exponent, SNORM, three-channel norm16/float32/sRGB and three-channel integer formats. // Desktop GL treats those as texture-only too (not in the GL 3.3 required-renderable list), so // reporting GL_FRAMEBUFFER_UNSUPPORTED for them is legal. - Bool IsColorInternalFormatRenderable(TextureInternalFormat format) { + // + // `capabilityTargetIndex` is the row of the cache the attachment actually lives in; + // kFormatCapabilityTargetCount asks about the format in general. Asking per target matters + // because a capability recorded for one of them says nothing about the others: DirectGLES + // widens three-channel formats to four channels to keep them renderable as *multisample* + // storage, and a format that survives only through that substitution is still texture-only + // on every ordinary target. + Bool IsColorInternalFormatRenderable(TextureInternalFormat format, SizeT capabilityTargetIndex) { const SizeT formatIndex = static_cast(format); if (MG_Backend::pActiveBackendObject && formatIndex < MG_Backend::kFormatCapabilityFormatCount) { const auto& cache = MG_Backend::pActiveBackendObject->GetFormatCapabilities(); @@ -113,8 +120,11 @@ namespace MobileGL::MG_Impl::GLImpl { MG_Backend::FormatCapability::Creatable); } if (cachePopulated) { - for (SizeT targetIndex = 0; targetIndex < MG_Backend::kFormatCapabilityTargetCount; - ++targetIndex) { + const Bool singleTarget = capabilityTargetIndex < MG_Backend::kFormatCapabilityTargetCount; + const SizeT firstTarget = singleTarget ? capabilityTargetIndex : 0; + const SizeT lastTarget = + singleTarget ? capabilityTargetIndex + 1 : MG_Backend::kFormatCapabilityTargetCount; + for (SizeT targetIndex = firstTarget; targetIndex < lastTarget; ++targetIndex) { if (MG_Backend::HasFormatCapability(cache.FullCaps[targetIndex][formatIndex], MG_Backend::FormatCapability::FramebufferRenderable) || MG_Backend::HasFormatCapability(cache.CaveatCaps[targetIndex][formatIndex], @@ -163,12 +173,17 @@ namespace MobileGL::MG_Impl::GLImpl { const auto& attachment = attachments[i]; if (!attachment.IsValid()) continue; TextureInternalFormat format = TextureInternalFormat::Unknown; + SizeT capabilityTargetIndex = MG_Backend::kFormatCapabilityTargetCount; if (attachment.IsTexture() && attachment.GetTexture()) { format = attachment.GetTexture()->GetFormat(); + capabilityTargetIndex = + MG_Backend::GetFormatCapabilityTargetIndex(attachment.GetTexture()->GetTarget()); } else if (attachment.IsRenderbuffer() && attachment.GetRenderbuffer()) { format = attachment.GetRenderbuffer()->GetInternalFormat(); + capabilityTargetIndex = MG_Backend::GetRenderbufferFormatCapabilityTargetIndex(); } - if (format != TextureInternalFormat::Unknown && !IsColorInternalFormatRenderable(format)) { + if (format != TextureInternalFormat::Unknown && + !IsColorInternalFormatRenderable(format, capabilityTargetIndex)) { return true; } }