diff --git a/MobileGL/MG_Backend/BackendObject.h b/MobileGL/MG_Backend/BackendObject.h index dcab60f3..8eac285f 100644 --- a/MobileGL/MG_Backend/BackendObject.h +++ b/MobileGL/MG_Backend/BackendObject.h @@ -353,6 +353,12 @@ namespace MobileGL { // real ES drivers behind DirectGLES both do. Defaults to true so a backend // that never sets it keeps the permissive behaviour. Bool SupportsDistinctDepthStencilAttachments = true; + // Whether attaching a single layer of a 3D or array texture to a framebuffer actually + // renders to that layer. DirectGLES hands the layer straight to + // glFramebufferTextureLayer, so it does; DirectVulkan maps a GL layer onto a Vulkan + // array layer with no notion of a 3D depth slice, so it does not yet. Defaults to false + // so a backend that never sets it gets the conservative answer. + Bool SupportsPerLayerFramebufferAttachment = false; SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024; Uint32 SubgroupSize = 0; Uint32 SubgroupSupportedStages = 0; diff --git a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp index 451a8809..34a2ecf6 100644 --- a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp @@ -1109,6 +1109,11 @@ namespace MobileGL::MG_Backend::DirectGLES { clampStageImageUniforms(m_GLESCapabilities.MaxComputeImageUniforms); m_dynamicParameters.SupportsDistinctDepthStencilAttachments = ProbeDistinctDepthStencilAttachments(DirectGLES::g_GLESFuncs); + // SyncAttachmentObject routes a layered upload target to glFramebufferTextureLayer with the + // attachment's layer passed through, so this backend really does render to the layer it was + // given - provided the driver resolved the entry point at all. + m_dynamicParameters.SupportsPerLayerFramebufferAttachment = + DirectGLES::g_GLESFuncs.glFramebufferTextureLayer != nullptr; m_dynamicParameters.MaxDrawBuffers = m_GLESCapabilities.MaxDrawBuffers; m_dynamicParameters.MaxColorAttachments = m_GLESCapabilities.MaxColorAttachments; m_dynamicParameters.MaxClipDistances = m_GLESCapabilities.MaxClipDistances; diff --git a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp index 938ca435..bed9a41f 100644 --- a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp @@ -1398,21 +1398,20 @@ 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) { + // Everything above is the spec's error set and is answered for every target and every layer + // on every backend. Whether the attachment can actually be honoured is a backend question: + // DirectGLES hands the layer to glFramebufferTextureLayer and renders to it, while + // DirectVulkan maps a GL layer onto a Vulkan array layer with no notion of a 3D depth slice, + // so a slice lands outside the image and the renderer asserts on the clear. Letting it + // through there would only move the failure downstream, so it is declined instead - layer + // zero always works, being the plain first-slice attachment. + const Bool backsLayeredAttachment = limits.SupportsPerLayerFramebufferAttachment; + // A cube map array additionally has no image shape at all in VkTextureManager, so on that + // backend it cannot be an attachment whatever the layer is. + const Bool isCubeMapArray = textureObject->GetTarget() == TextureTarget::TextureCubeMapArray; + if ((layer != 0 && !backsLayeredAttachment) || (isCubeMapArray && !backsLayeredAttachment)) { 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."); + __func__, "This backend does not resolve a framebuffer attachment's layer onto its image."); return; }