From 765aaec6dcb768b1f40eb226826c01233a74390c Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Wed, 5 Aug 2026 02:47:27 -0400 Subject: [PATCH] [Fix] (MG_Impl, MG_Backend): stop the new layer attachment from reaching backends that cannot back it Implementing NamedFramebufferTextureLayer made layered attachments reachable for the first time, and direct_state_access.framebuffers_texture_layer_attachment went from Fail to Crash on DirectVulkan. Two separate gaps sat behind it, both of them asserted on rather than reported: - The renderer resolves an attachment's GL layer straight onto a Vulkan array layer. A 3D texture's z-slice therefore lands outside its image, which has one array layer by construction, and the array texture objects are still the one-image stubs in TextureObjectStubs.h, so their image has a single layer whatever GL believes. MaterializePendingClearForTexture tripped over a clear whose layer span was outside the image it was given. - A cube map array has no image shape in VkTextureManager at all, so SyncTextureAndGetDescriptor returns null for it. NamedFramebufferTextureLayer now answers the full error set for every target and layer - which is what took the two error cases green - and then declines to attach anything but layer zero of a non-cube-array texture, through the same RecordUnsupportedFramebufferTextureAttachmentError the by-target entry point already uses. Layer zero of the other targets is the plain first-slice attachment glFramebufferTextureLayer already backs, so it still goes through. SyncTextureResource's assertion on an unsupported texture shape is also gone: it is a gap in this backend's coverage, not a broken invariant, and the code below it already handles the failure by declining the sync. It logs a warning instead. framebuffers_texture_layer_attachment goes back to Fail on DirectVulkan rather than Crash; no case changes in either direction beyond that. --- .../DirectVulkan/Renderer/VkTextureManager.cpp | 18 ++++++++++-------- .../GLImpl/Framebuffer/GL_Framebuffer.cpp | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index 18a967e7..9306a6d1 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -1497,15 +1497,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { : (mipLevels > 1 ? std::max(mipLevels, ComputeFullMipLevelCount(texelSize)) : 1u); TextureShapeInfo shapeInfo{}; const Bool supportedShape = TryResolveTextureShapeInfo(texture, uploadTarget, texelSize, shapeInfo); - MOBILEGL_ASSERT(supportedShape, - "SyncTextureResource: unsupported uploadTarget=%s textureTarget=%s textureId=%d size=(%d,%d,%d) " - "mipLevels=%u vkViewType=%d", - MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), - MG_Util::ConvertTextureTargetToString(texture.GetTarget()).c_str(), - texture.GetExternalIndex(), texelSize.x(), texelSize.y(), texelSize.z(), mipLevels, - static_cast(MG_Util::ConvertTextureUploadTargetToVkEnum(uploadTarget))); if (!supportedShape) { - MGLOG_D("%s: not Texture2D, unsupported", __func__); + // A gap in this backend's coverage, not a broken invariant: the GL front end accepts + // targets this manager has no Vulkan image shape for yet (cube map arrays above all). + // Declining the sync leaves the texture unbacked - wrong, but recoverable - where an + // assertion would take the whole process down instead. + MGLOG_W("SyncTextureResource: unsupported uploadTarget=%s textureTarget=%s textureId=%d size=(%d,%d,%d) " + "mipLevels=%u vkViewType=%d", + MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), + MG_Util::ConvertTextureTargetToString(texture.GetTarget()).c_str(), texture.GetExternalIndex(), + texelSize.x(), texelSize.y(), texelSize.z(), mipLevels, + static_cast(MG_Util::ConvertTextureUploadTargetToVkEnum(uploadTarget))); return false; } VkSampleCountFlagBits resolvedSampleCount = VK_SAMPLE_COUNT_1_BIT; diff --git a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp index e44bfd88..938ca435 100644 --- a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp @@ -1398,6 +1398,24 @@ namespace MobileGL::MG_Impl::GLImpl { return; } + // Everything above is the spec's error set and is answered for every target and every + // layer. Actually attaching a layer other than the first is a different matter: no backend + // resolves a GL layer onto its image yet. The Vulkan renderer treats the layer as an array + // slice - so a 3D texture's z-slice lands outside its single-array-layer image - and the + // array texture objects are still the one-image stubs in TextureObjectStubs.h, whose image + // has one layer whatever GL thinks. Letting the attachment through only moves the failure + // downstream into a clear whose layer span is outside the image; declining keeps it a + // reported error. Layer zero is the plain first-slice attachment the by-target + // glFramebufferTextureLayer already backs, so it goes through. + // A cube map array has no Vulkan image shape at all (TryResolveTextureShapeInfo), so it + // cannot be an attachment on that backend whatever the layer is. + if (layer != 0 || textureObject->GetTarget() == TextureTarget::TextureCubeMapArray) { + RecordUnsupportedFramebufferTextureAttachmentError( + __func__, "Attaching a layer other than the first, or any layer of a cube map array, is not " + "represented by the current framebuffer attachment model."); + return; + } + framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level, layer, /*layered=*/false); }