From ac811859688bf9015b1daddcfd2290e716bd6628 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sat, 1 Aug 2026 11:14:33 -0400 Subject: [PATCH] [Fix] (DirectGLES): implement GL_DEPTH_STENCIL readback for ReadPixels/GetTexImage Neither ReadPixels nor GetTexImage recognized format=GL_DEPTH_STENCIL (type GL_UNSIGNED_INT_24_8 / GL_FLOAT_32_UNSIGNED_INT_24_8_REV): it matched none of the native-passthrough gates nor the color-channel conversion mapping, so both silently no-op'd (logging a compiled-out MGLOG_E) and left the caller's buffer untouched. Real GLES/GL drivers already implement this readback natively, so widen the native-pair gates to include it. GetTexImage additionally always attached the source texture to its scratch FBO as GL_COLOR_ATTACHMENT0, which a depth-stencil texture cannot be (framebuffer-incomplete) - route it through the existing EnsureDepthAttachment2D(..., withStencil=true) path instead and skip the color-only glReadBuffer call for that format. Fixes KHR-GL3{2,3}.packed_depth_stencil.verify_read_pixels, verify_get_tex_image, and verify_copy_tex_image (which depends on GetTexImage internally) for both depth24_stencil8 and depth32f_stencil8. --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index b4567eb2..c27911ae 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -3632,12 +3632,16 @@ namespace MobileGL::MG_Backend::DirectGLES { static Bool IsLegacyNativeReadPixelsFormat(GLenum format) { return format == GL_RGBA || format == GL_RGBA_INTEGER || format == GL_RED || format == GL_RED_INTEGER || - format == GL_DEPTH_COMPONENT || format == GL_STENCIL_INDEX; + format == GL_DEPTH_COMPONENT || format == GL_STENCIL_INDEX || format == GL_DEPTH_STENCIL; } static Bool IsLegacyNativeReadPixelsType(GLenum type) { + // GL_UNSIGNED_INT_24_8 / GL_FLOAT_32_UNSIGNED_INT_24_8_REV are only ever valid + // paired with GL_DEPTH_STENCIL (packed_depth_stencil.verify_read_pixels); the real + // driver already implements this readback natively. return type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT || type == GL_UNSIGNED_INT_2_10_10_10_REV || - type == GL_INT || type == GL_FLOAT; + type == GL_INT || type == GL_FLOAT || type == GL_UNSIGNED_INT_24_8 || + type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV; } void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { @@ -3782,6 +3786,9 @@ namespace MobileGL::MG_Backend::DirectGLES { if (format == GL_RGBA_INTEGER) { return type == GL_INT || type == GL_UNSIGNED_INT || type == GL_UNSIGNED_INT_2_10_10_10_REV; } + if (format == GL_DEPTH_STENCIL) { + return type == GL_UNSIGNED_INT_24_8 || type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + } return false; } @@ -3850,7 +3857,14 @@ namespace MobileGL::MG_Backend::DirectGLES { MGLOG_D("GetTexImage: attaching level %d to the scratch FBO", level); const GLenum backendAttachTarget = TextureImpl::ConvertTextureUploadTargetToBackendGLEnum( MG_Util::ConvertGLEnumToTextureUploadTarget(target)); - if (backendAttachTarget == GL_TEXTURE_3D || backendAttachTarget == GL_TEXTURE_2D_ARRAY) { + // GL_DEPTH_STENCIL can't be attached as a color attachment (glCheckFramebufferStatus + // would report it incomplete); it has its own combined depth+stencil attachment point. + // glReadBuffer only selects among color attachments, so it does not apply here. + if (format == GL_DEPTH_STENCIL) { + ScratchFBOImpl::EnsureDepthAttachment2D( + tempFB, GL_READ_FRAMEBUFFER, backendTexId, + backendAttachTarget == GL_UNKNOWN_MGL ? target : backendAttachTarget, level, /*withStencil=*/true); + } else if (backendAttachTarget == GL_TEXTURE_3D || backendAttachTarget == GL_TEXTURE_2D_ARRAY) { // ES cannot attach 3D/array textures through glFramebufferTexture2D; read layer 0. Reads // of deeper slices are served from the CPU shadow instead (see the shadow-first branch). ScratchFBOImpl::EnsureColorAttachmentLayer(tempFB, GL_READ_FRAMEBUFFER, backendTexId, level, 0); @@ -3859,8 +3873,10 @@ namespace MobileGL::MG_Backend::DirectGLES { tempFB, GL_READ_FRAMEBUFFER, backendTexId, backendAttachTarget == GL_UNKNOWN_MGL ? target : backendAttachTarget, level); } - MGLOG_D("GetTexImage: glReadBuffer(GL_COLOR_ATTACHMENT0)"); - ScratchFBOImpl::EnsureReadBuffer(tempFB, GL_COLOR_ATTACHMENT0); + if (format != GL_DEPTH_STENCIL) { + MGLOG_D("GetTexImage: glReadBuffer(GL_COLOR_ATTACHMENT0)"); + ScratchFBOImpl::EnsureReadBuffer(tempFB, GL_COLOR_ATTACHMENT0); + } GLenum fbStatus = g_GLESFuncs.glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); MGLOG_D("GetTexImage: GL_READ_FRAMEBUFFER status = %s", MG_Util::ConvertGLEnumToString(fbStatus).c_str());