From 6e6f5268fb3e9b1a9005823c38611c7cf9447ad8 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Wed, 5 Aug 2026 23:08:29 -0400 Subject: [PATCH] [Fix] (MG_Backend): let a default-visual X11 window match an alpha-free config ChooseConfigForSurface prefilters candidate configs with eglChooseConfig requiring EGL_ALPHA_SIZE 8, then tries to match the window's X visual. On NVIDIA's X11 EGL every alpha-8 config lives on the 32-bit ARGB visual, and the default depth-24 TrueColor visual only appears on alpha-0 configs - so for any window created with the default visual the match loop scanned a list that could not contain its visual, fell through to a 32-bit-visual config, and eglCreateWindowSurface failed with EGL_BAD_CONFIG. Keep the alpha-8 list as the first tier and add an alpha-relaxed second tier used only for the visual match; the sizeless fallbacks below still run on the alpha-8 list. Mesa is unaffected (its default-visual configs carry alpha), and a destination-alpha-free default framebuffer is exactly what native GLX hands out on these visuals anyway. Found by running Minecraft through the new GLXImpl on Espryt: NVIDIA EGL also needs EGL_PLATFORM=x11 under a Wayland session or eglGetDisplay itself returns no display, which is a launcher-environment concern, not a library one. --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index bbb5ed99..7a9b0896 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -5678,19 +5678,44 @@ namespace MobileGL::MG_Backend::DirectGLES { configs.resize(static_cast(numConfigs)); if (surfaceBit == EGL_WINDOW_BIT) { + // X11 drivers can reserve every alpha-8 config for 32-bit ARGB + // visuals (NVIDIA), so a default-visual (depth 24) window only + // matches an alpha-0 config; keep those as a second candidate tier + // for the visual match or eglCreateWindowSurface hits BAD_CONFIG. + Vector alphaFreeConfigs; + const EGLint alphaFreeAttribs[] = {EGL_SURFACE_TYPE, surfaceBit, EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES3_BIT, + EGL_RED_SIZE, 8, EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, 8, EGL_DEPTH_SIZE, + 24, + EGL_STENCIL_SIZE, 8, EGL_NONE}; + EGLint numAlphaFree = 0; + if (g_EGLFuncs.eglChooseConfig(g_Display, alphaFreeAttribs, nullptr, 0, &numAlphaFree) && + numAlphaFree > 0) { + alphaFreeConfigs.resize(static_cast(numAlphaFree)); + if (!g_EGLFuncs.eglChooseConfig(g_Display, alphaFreeAttribs, alphaFreeConfigs.data(), + numAlphaFree, &numAlphaFree)) { + numAlphaFree = 0; + } + alphaFreeConfigs.resize(static_cast(numAlphaFree)); + } + const EGLint windowVisualId = QueryX11WindowVisualId(window); const EGLint visualIds[] = {windowVisualId, QueryDefaultX11VisualId()}; for (const auto visualId : visualIds) { if (visualId == 0) { continue; } - for (const auto config : configs) { - EGLint nativeVisualId = 0; - if (ConfigSupports(config, surfaceBit) && - GetConfigAttrib(config, EGL_NATIVE_VISUAL_ID, nativeVisualId) && - nativeVisualId == visualId) { - outConfig = config; - return true; + for (const auto* candidates : {&configs, &alphaFreeConfigs}) { + for (const auto config : *candidates) { + EGLint nativeVisualId = 0; + if (ConfigSupports(config, surfaceBit) && + GetConfigAttrib(config, EGL_NATIVE_VISUAL_ID, nativeVisualId) && + nativeVisualId == visualId) { + outConfig = config; + return true; + } } } }