From ef3178a98f854b94abbece48b1345d3d4475a360 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 12 Oct 2026 03:55:04 -0400 Subject: [PATCH] [Fix] (GL): keep ES-only image_external and ARB_robustness names off the wrong context kinds --- MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp | 121 +++++++++++-------- MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h | 9 ++ 2 files changed, 78 insertions(+), 52 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp index 45bd7e00..c4808aa6 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp @@ -593,64 +593,16 @@ namespace MobileGL::MG_Impl::GLImpl { } namespace { - // Extensions this library implements itself, appended after the backend's own list (the - // server's, under split), which cannot know about them: - // * GL_OES_EGL_image binds the EGL side's dma-buf images, which only a backend with - // shared images has (EGLImpl::SharedImagesAvailable); - // * the robustness family - reset notification (glGetGraphicsResetStatus, the contexts' - // EGL reset strategy, GL_CONTEXT_LOST) and the bounded queries (glReadnPixels, - // glGetnUniform*) are this frontend's, whatever the backend. KHR for GL and ES, ARB for - // GL applications that ask for that name, EXT for ES applications that ask for that one. - // Robust buffer ACCESS is a separate promise (GL_CONTEXT_ROBUST_ACCESS) and is not - // implied by any of them. - // One list for glGetString and glGetStringi, so the two forms always agree. Bool EsIdentityActive(); + // One list for glGetString and glGetStringi, so the two forms always agree. const Vector& ClientSideExtensions() { - // GL_OES_EGL_image_external(_essl3) only where the server samples YUV images: an - // external texture is a 2D texture holding the image converted to RGBA, which needs - // the server to hold the YUV image in the first place (EGLImpl::SharedImageYuvAvailable). - static const auto build = [](Bool images, Bool external, Bool es, Bool esApi) { - Vector list; - if (images) list.push_back("GL_OES_EGL_image"); - if (images && external) { - list.push_back("GL_OES_EGL_image_external"); - list.push_back("GL_OES_EGL_image_external_essl3"); - } - for (const char* name : {"GL_KHR_robustness", "GL_ARB_robustness", "GL_EXT_robustness"}) - list.push_back(name); - // Under the ES identity (EsIdentityActive) the ES names of what desktop GL has in core: - // BGRA textures, render targets and read-backs. GL_BGRA_EXT / GL_BGRA8_EXT as internal - // formats are taken as RGBA storage (TextureEnumConverter), the byte order being the - // pixel transfer format's, as on desktop GL. - if (es) { - list.push_back("GL_EXT_texture_format_BGRA8888"); - list.push_back("GL_EXT_read_format_bgra"); - } - // Any context created for the OpenGL ES API, whatever it calls itself: the ES 2.0 - // names of what desktop GL has in core - RGB8/RGBA8 and DEPTH_COMPONENT24 - // renderbuffers, and glMapBuffer (exported under its OES names as well). - if (esApi) { - list.push_back("GL_OES_rgb8_rgba8"); - list.push_back("GL_OES_depth24"); - list.push_back("GL_OES_mapbuffer"); - } - return list; - }; - static const Vector lists[16] = { - build(false, false, false, false), build(false, false, false, true), - build(false, false, true, false), build(false, false, true, true), - build(false, true, false, false), build(false, true, false, true), - build(false, true, true, false), build(false, true, true, true), - build(true, false, false, false), build(true, false, false, true), - build(true, false, true, false), build(true, false, true, true), - build(true, true, false, false), build(true, true, false, true), - build(true, true, true, false), build(true, true, true, true)}; const Bool images = MG_Impl::EGLImpl::SharedImagesAvailable(); - const Bool external = images && MG_Impl::EGLImpl::SharedImageYuvAvailable(); const Bool esApi = MG_State::pEGLContext && MG_State::pEGLContext->GetCurrentContextClientAPI() == EGL_OPENGL_ES_API; - return lists[(images ? 8 : 0) + (external ? 4 : 0) + (EsIdentityActive() ? 2 : 0) + (esApi ? 1 : 0)]; + const Bool external = + images && ClientSideExternalImageExtensionsAllowed() && MG_Impl::EGLImpl::SharedImageYuvAvailable(); + return ClientSideExtensionList(images, external, EsIdentityActive(), esApi); } // Robust buffer access as GL 4.5 / KHR_robust_buffer_access_behavior define it: the backend @@ -706,6 +658,71 @@ namespace MobileGL::MG_Impl::GLImpl { #endif } // namespace + // Extensions this library implements itself, appended after the backend's own list (the + // server's, under split), which cannot know about them: + // * GL_OES_EGL_image binds the EGL side's dma-buf images, which only a backend with + // shared images has (EGLImpl::SharedImagesAvailable); + // * the robustness family - reset notification (glGetGraphicsResetStatus, the contexts' + // EGL reset strategy, GL_CONTEXT_LOST) and the bounded queries (glReadnPixels, + // glGetnUniform*) are this frontend's, whatever the backend. KHR for GL and ES, ARB for + // desktop GL applications that ask for that name, EXT for ES applications that ask for + // that one. Robust buffer ACCESS is a separate promise (GL_CONTEXT_ROBUST_ACCESS) and is + // not implied by any of them. + const Vector& ClientSideExtensionList(Bool images, Bool external, Bool es, Bool esApi) { + // GL_OES_EGL_image_external(_essl3) only where the server samples YUV images: an + // external texture is a 2D texture holding the image converted to RGBA, which needs + // the server to hold the YUV image in the first place (EGLImpl::SharedImageYuvAvailable). + static const auto build = [](Bool images, Bool external, Bool es, Bool esApi) { + Vector list; + if (images) list.push_back("GL_OES_EGL_image"); + if (images && external) { + list.push_back("GL_OES_EGL_image_external"); + list.push_back("GL_OES_EGL_image_external_essl3"); + } + // An ES context lists no ARB names (KHR-GLES*.exposed_extensions). + list.push_back("GL_KHR_robustness"); + if (!esApi) list.push_back("GL_ARB_robustness"); + list.push_back("GL_EXT_robustness"); + // Under the ES identity (EsIdentityActive) the ES names of what desktop GL has in core: + // BGRA textures, render targets and read-backs. GL_BGRA_EXT / GL_BGRA8_EXT as internal + // formats are taken as RGBA storage (TextureEnumConverter), the byte order being the + // pixel transfer format's, as on desktop GL. + if (es) { + list.push_back("GL_EXT_texture_format_BGRA8888"); + list.push_back("GL_EXT_read_format_bgra"); + } + // Any context created for the OpenGL ES API, whatever it calls itself: the ES 2.0 + // names of what desktop GL has in core - RGB8/RGBA8 and DEPTH_COMPONENT24 + // renderbuffers, and glMapBuffer (exported under its OES names as well). + if (esApi) { + list.push_back("GL_OES_rgb8_rgba8"); + list.push_back("GL_OES_depth24"); + list.push_back("GL_OES_mapbuffer"); + } + return list; + }; + static const Vector lists[16] = { + build(false, false, false, false), build(false, false, false, true), + build(false, false, true, false), build(false, false, true, true), + build(false, true, false, false), build(false, true, false, true), + build(false, true, true, false), build(false, true, true, true), + build(true, false, false, false), build(true, false, false, true), + build(true, false, true, false), build(true, false, true, true), + build(true, true, false, false), build(true, true, false, true), + build(true, true, true, false), build(true, true, true, true)}; + return lists[(images ? 8 : 0) + (external ? 4 : 0) + (es ? 2 : 0) + (esApi ? 1 : 0)]; + } + + // The external-image names are ES extensions (GL_OES_EGL_image_external_essl3 extends ESSL + // only), and a desktop context lists no OES name but GL_OES_EGL_image + // (KHR-GL40.exposed_extensions). An explicit core-profile context therefore does not list + // them; samplerExternalOES itself stays accepted on every context, only the names are gated. + Bool ClientSideExternalImageExtensionsAllowed() { + const Bool esApi = + MG_State::pEGLContext && MG_State::pEGLContext->GetCurrentContextClientAPI() == EGL_OPENGL_ES_API; + return esApi || MG_State::IsRelaxedSemanticsActive(); + } + /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ const GLubyte* GetString(GLenum name) { static String vendorString; diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h index d99e37bd..608f8f64 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h @@ -45,4 +45,13 @@ namespace MobileGL::MG_Impl::GLImpl { // gl_NumSamples stand-in - a shader comparing gl_NumSamples against glGetIntegerv(GL_SAMPLES) // is exactly what the sample_variables CTS does. GLint ResolveDrawFramebufferSampleCount(); + // The extensions the frontend appends to the backend's list - one list behind + // glGetString(GL_EXTENSIONS), glGetStringi and GL_NUM_EXTENSIONS - for the given conditions: + // shared images, YUV images that may be advertised (ClientSideExternalImageExtensionsAllowed), + // the ES identity, and a context created for the OpenGL ES API. + const Vector& ClientSideExtensionList(Bool images, Bool external, Bool es, Bool esApi); + // Whether the current context may list GL_OES_EGL_image_external(_essl3): a context created + // for the OpenGL ES API, or any context outside the strict core-profile rules + // (MG_State::IsRelaxedSemanticsActive). + Bool ClientSideExternalImageExtensionsAllowed(); } // namespace MobileGL::MG_Impl::GLImpl