[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.
This commit is contained in:
BZLZHH
2026-08-05 02:47:27 -04:00
parent bcd669bd25
commit 765aaec6dc
2 changed files with 28 additions and 8 deletions
@@ -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<Int>(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<Int>(MG_Util::ConvertTextureUploadTargetToVkEnum(uploadTarget)));
return false;
}
VkSampleCountFlagBits resolvedSampleCount = VK_SAMPLE_COUNT_1_BIT;
@@ -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);
}