From 5f72c9b23b630dacf3e85163cf5de15b28b110a2 Mon Sep 17 00:00:00 2001 From: Basilisk-Dev Date: Mon, 4 May 2026 19:17:24 -0400 Subject: [PATCH] Issue #3079 - Use desktop OpenGL for X11 EGL --- gfx/gl/GLContextProviderEGL.cpp | 166 +++++++++++++++++++------------- toolkit/xre/glxtest.cpp | 43 +++++---- 2 files changed, 122 insertions(+), 87 deletions(-) diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index ad515e6040..068146ac54 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -13,13 +13,23 @@ #if defined(XP_UNIX) - #define GLES2_LIB "libGLESv2.so" - #define GLES2_LIB2 "libGLESv2.so.2" + #if defined(MOZ_X11) + #if defined(__OpenBSD__) || defined(__NetBSD__) + #define EGL_OPENGL_LIB "libGL.so" + #define EGL_OPENGL_LIB2 "libGL.so.1" + #else + #define EGL_OPENGL_LIB "libGL.so.1" + #define EGL_OPENGL_LIB2 "libGL.so" + #endif + #else + #define EGL_OPENGL_LIB "libGLESv2.so" + #define EGL_OPENGL_LIB2 "libGLESv2.so.2" + #endif #elif defined(XP_WIN) #include "nsIFile.h" - #define GLES2_LIB "libGLESv2.dll" + #define EGL_OPENGL_LIB "libGLESv2.dll" #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 @@ -102,6 +112,45 @@ using namespace mozilla::widget; static bool CreateConfig(EGLConfig* aConfig, nsIWidget* aWidget); +static bool +UseDesktopOpenGLForEGL() +{ +#ifdef MOZ_X11 + return true; +#else + return false; +#endif +} + +static EGLint +GetEGLRenderableType(CreateContextFlags flags) +{ + if (UseDesktopOpenGLForEGL()) { + return LOCAL_EGL_OPENGL_BIT; + } + + return bool(flags & CreateContextFlags::PREFER_ES3) + ? LOCAL_EGL_OPENGL_ES3_BIT_KHR + : LOCAL_EGL_OPENGL_ES2_BIT; +} + +static bool +BindContextAPI(nsACString* const out_failureId) +{ + const EGLenum api = UseDesktopOpenGLForEGL() + ? LOCAL_EGL_OPENGL_API + : LOCAL_EGL_OPENGL_ES_API; + if (sEGLLibrary.fBindAPI(api) == LOCAL_EGL_FALSE) { + *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_BIND_API"); + NS_WARNING(UseDesktopOpenGLForEGL() + ? "Failed to bind API to OpenGL!" + : "Failed to bind API to GLES!"); + return false; + } + + return true; +} + // append three zeros at the end of attribs list to work around // EGL implementation bugs that iterate until they find 0, instead of // EGL_NONE. See bug 948406. @@ -172,8 +221,12 @@ GLContextEGL::GLContextEGL(CreateContextFlags flags, const SurfaceCaps& caps, , mShareWithEGLImage(false) , mOwnsContext(true) { - // any EGL contexts will always be GLESv2 - SetProfileVersion(ContextProfile::OpenGLES, 200); + // X11 uses desktop OpenGL-over-EGL. Other EGL paths still use GLES/ANGLE. + if (UseDesktopOpenGLForEGL()) { + SetProfileVersion(ContextProfile::OpenGLCompatibility, 200); + } else { + SetProfileVersion(ContextProfile::OpenGLES, 200); + } #ifdef DEBUG printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY()); @@ -202,10 +255,10 @@ GLContextEGL::~GLContextEGL() bool GLContextEGL::Init() { - if (!OpenLibrary(GLES2_LIB)) { + if (!OpenLibrary(EGL_OPENGL_LIB)) { #if defined(XP_UNIX) - if (!OpenLibrary(GLES2_LIB2)) { - NS_WARNING("Couldn't load GLES2 LIB."); + if (!OpenLibrary(EGL_OPENGL_LIB2)) { + NS_WARNING("Couldn't load EGL GL library."); return false; } #endif @@ -451,9 +504,7 @@ GLContextEGL::CreateGLContext(CreateContextFlags flags, EGLSurface surface, nsACString* const out_failureId) { - if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) { - *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_ES"); - NS_WARNING("Failed to bind API to GLES!"); + if (!BindContextAPI(out_failureId)) { return nullptr; } @@ -462,11 +513,14 @@ GLContextEGL::CreateGLContext(CreateContextFlags flags, nsTArray contextAttribs; - contextAttribs.AppendElement(LOCAL_EGL_CONTEXT_CLIENT_VERSION); - if (flags & CreateContextFlags::PREFER_ES3) - contextAttribs.AppendElement(3); - else - contextAttribs.AppendElement(2); + if (!UseDesktopOpenGLForEGL()) { + contextAttribs.AppendElement(LOCAL_EGL_CONTEXT_CLIENT_VERSION); + if (flags & CreateContextFlags::PREFER_ES3) { + contextAttribs.AppendElement(3); + } else { + contextAttribs.AppendElement(2); + } + } if (sEGLLibrary.HasRobustness()) { // contextAttribs.AppendElement(LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT); @@ -550,70 +604,52 @@ TRY_AGAIN_POWER_OF_TWO: return surface; } -static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - // Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856) - LOCAL_EGL_RED_SIZE, 8, - LOCAL_EGL_GREEN_SIZE, 8, - LOCAL_EGL_BLUE_SIZE, 8, - LOCAL_EGL_ALPHA_SIZE, 0, - EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS -}; +static void +AppendWindowConfigAttribs(int32_t depth, nsTArray* out) +{ + out->AppendElement(LOCAL_EGL_SURFACE_TYPE); + out->AppendElement(LOCAL_EGL_WINDOW_BIT); -static const EGLint kEGLConfigAttribsRGB16[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_RED_SIZE, 5, - LOCAL_EGL_GREEN_SIZE, 6, - LOCAL_EGL_BLUE_SIZE, 5, - LOCAL_EGL_ALPHA_SIZE, 0, - EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS -}; + out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE); + out->AppendElement(GetEGLRenderableType(CreateContextFlags::NONE)); -static const EGLint kEGLConfigAttribsRGB24[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_RED_SIZE, 8, - LOCAL_EGL_GREEN_SIZE, 8, - LOCAL_EGL_BLUE_SIZE, 8, - LOCAL_EGL_ALPHA_SIZE, 0, - EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS -}; + out->AppendElement(LOCAL_EGL_RED_SIZE); + out->AppendElement(depth == 16 ? 5 : 8); -static const EGLint kEGLConfigAttribsRGBA32[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_RED_SIZE, 8, - LOCAL_EGL_GREEN_SIZE, 8, - LOCAL_EGL_BLUE_SIZE, 8, - LOCAL_EGL_ALPHA_SIZE, 8, - EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS -}; + out->AppendElement(LOCAL_EGL_GREEN_SIZE); + out->AppendElement(depth == 16 ? 6 : 8); + + out->AppendElement(LOCAL_EGL_BLUE_SIZE); + out->AppendElement(depth == 16 ? 5 : 8); + + out->AppendElement(LOCAL_EGL_ALPHA_SIZE); + out->AppendElement(depth == 32 ? 8 : 0); + + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(gTerminationAttribs); ++i) { + out->AppendElement(gTerminationAttribs[i]); + } +} static bool CreateConfig(EGLConfig* aConfig, int32_t depth, nsIWidget* aWidget) { EGLConfig configs[64]; - const EGLint* attribs; EGLint ncfg = ArrayLength(configs); + nsTArray attribs; switch (depth) { case 16: - attribs = kEGLConfigAttribsRGB16; - break; case 24: - attribs = kEGLConfigAttribsRGB24; - break; case 32: - attribs = kEGLConfigAttribsRGBA32; break; default: NS_ERROR("Unknown pixel depth"); return false; } - if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs, + AppendWindowConfigAttribs(depth, &attribs); + + if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs.Elements(), configs, ncfg, &ncfg) || ncfg < 1) { return false; @@ -727,17 +763,13 @@ GLContextProviderEGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated static void FillContextAttribs(bool alpha, bool depth, bool stencil, bool bpp16, - bool es3, nsTArray* out) + CreateContextFlags flags, nsTArray* out) { out->AppendElement(LOCAL_EGL_SURFACE_TYPE); out->AppendElement(LOCAL_EGL_PBUFFER_BIT); out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE); - if (es3) { - out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR); - } else { - out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT); - } + out->AppendElement(GetEGLRenderableType(flags)); out->AppendElement(LOCAL_EGL_RED_SIZE); if (bpp16) { @@ -797,7 +829,7 @@ ChooseConfig(GLLibraryEGL* egl, CreateContextFlags flags, const SurfaceCaps& min { nsTArray configAttribList; FillContextAttribs(minCaps.alpha, minCaps.depth, minCaps.stencil, minCaps.bpp16, - bool(flags & CreateContextFlags::PREFER_ES3), &configAttribList); + flags, &configAttribList); const EGLint* configAttribs = configAttribList.Elements(); diff --git a/toolkit/xre/glxtest.cpp b/toolkit/xre/glxtest.cpp index d0280fa158..6024bf03c8 100644 --- a/toolkit/xre/glxtest.cpp +++ b/toolkit/xre/glxtest.cpp @@ -43,6 +43,14 @@ #include "mozilla/Unused.h" +#if defined(__OpenBSD__) || defined(__NetBSD__) +# define LIBGL_FILENAME "libGL.so" +# define LIBGL_FILENAME_FALLBACK "libGL.so.1" +#else +# define LIBGL_FILENAME "libGL.so.1" +# define LIBGL_FILENAME_FALLBACK "libGL.so" +#endif + // stuff from glx.h typedef struct __GLXcontextRec *GLXContext; typedef XID GLXPixmap; @@ -189,7 +197,7 @@ try_egltest(std::string* aError) { static const EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, @@ -202,7 +210,6 @@ try_egltest(std::string* aError) EGL_NONE }; static const EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; @@ -211,8 +218,8 @@ try_egltest(std::string* aError) return false; } - void* libgles = nullptr; - if (!load_library("libGLESv2.so", "libGLESv2.so.2", &libgles, aError)) { + void* libgl = nullptr; + if (!load_library(LIBGL_FILENAME, LIBGL_FILENAME_FALLBACK, &libgl, aError)) { dlclose(libegl); return false; } @@ -242,7 +249,7 @@ try_egltest(std::string* aError) PFNEGLDESTROYSURFACE eglDestroySurface = cast(dlsym(libegl, "eglDestroySurface")); PFNEGLTERMINATE eglTerminate = cast(dlsym(libegl, "eglTerminate")); PFNEGLGETERROR eglGetError = cast(dlsym(libegl, "eglGetError")); - PFNGLGETSTRING glGetString = cast(dlsym(libgles, "glGetString")); + PFNGLGETSTRING glGetString = cast(dlsym(libgl, "glGetString")); if (!eglGetDisplay || !eglInitialize || @@ -257,8 +264,8 @@ try_egltest(std::string* aError) !eglGetError || !glGetString) { - *aError = "EGL probe couldn't find required EGL/GLES symbols"; - dlclose(libgles); + *aError = "EGL probe couldn't find required EGL/OpenGL symbols"; + dlclose(libgl); dlclose(libegl); return false; } @@ -266,7 +273,7 @@ try_egltest(std::string* aError) Display* dpy = XOpenDisplay(nullptr); if (!dpy) { *aError = "Unable to open a connection to the X server"; - dlclose(libgles); + dlclose(libgl); dlclose(libegl); return false; } @@ -296,8 +303,8 @@ try_egltest(std::string* aError) goto egltest_error; } - if (!eglBindAPI(EGL_OPENGL_ES_API)) { - *aError = "EGL probe could not bind the OpenGL ES API"; + if (!eglBindAPI(EGL_OPENGL_API)) { + *aError = "EGL probe could not bind the OpenGL API"; goto egltest_error; } @@ -364,7 +371,7 @@ try_egltest(std::string* aError) XSync(dpy, False); #endif - dlclose(libgles); + dlclose(libgl); dlclose(libegl); write_to_pipe(buf, length); @@ -384,7 +391,7 @@ egltest_error: #else XSync(dpy, False); #endif - dlclose(libgles); + dlclose(libgl); dlclose(libegl); return false; } @@ -454,14 +461,10 @@ void glxtest() } ///// Open libGL and load needed symbols ///// -#if defined(__OpenBSD__) || defined(__NetBSD__) - #define LIBGL_FILENAME "libGL.so" -#else - #define LIBGL_FILENAME "libGL.so.1" -#endif - void *libgl = dlopen(LIBGL_FILENAME, RTLD_LAZY); - if (!libgl) - fatal_error("Unable to load " LIBGL_FILENAME); + void* libgl = nullptr; + std::string libglError; + if (!load_library(LIBGL_FILENAME, LIBGL_FILENAME_FALLBACK, &libgl, &libglError)) + fatal_error(libglError.c_str()); typedef void* (* PFNGLXGETPROCADDRESS) (const char *); PFNGLXGETPROCADDRESS glXGetProcAddress = cast(dlsym(libgl, "glXGetProcAddress"));