Never use X11 EGL on Nvidia proprietary drivers

Fixes #1751
This commit is contained in:
Cameron Gutman 2025-12-05 23:10:31 -06:00
commit 1c24aada0a
4 changed files with 55 additions and 13 deletions

View file

@ -476,12 +476,18 @@ int main(int argc, char *argv[])
#endif
}
// Some ARM and RISC-V embedded devices don't have working GLX which can cause
// SDL to fail to find a working OpenGL implementation at all. Let's force EGL
// on all platforms for both SDL and Qt. This also avoids GLX-EGL interop issues
// when trying to use EGL on the main thread after Qt uses GLX.
SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1");
qputenv("QT_XCB_GL_INTEGRATION", "xcb_egl");
// Nvidia's proprietary driver has broken EGL support on X11, so don't use it.
// This will break the EGLRenderer, but that's fine on Nvidia because they
// support both VDPAU and Vulkan renderers instead.
// https://github.com/moonlight-stream/moonlight-qt/issues/1751
if (!WMUtils::isRunningX11NvidiaProprietaryDriver()) {
// Some ARM and RISC-V embedded devices don't have working GLX which can cause
// SDL to fail to find a working OpenGL implementation at all. Let's force EGL
// on all platforms for both SDL and Qt. This also avoids GLX-EGL interop issues
// when trying to use EGL on the main thread after Qt uses GLX.
SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1");
qputenv("QT_XCB_GL_INTEGRATION", "xcb_egl");
}
#ifdef Q_OS_MACOS
// This avoids using the default keychain for SSL, which may cause

View file

@ -434,6 +434,14 @@ bool EGLRenderer::initialize(PDECODER_PARAMETERS params)
return false;
}
// If we're using X11 GLX (both in SDL and Qt), don't use this renderer.
// Switching between EGL and GLX can cause interoperability issues.
if (strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0 &&
!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE)) {
EGL_LOG(Warn, "Disabled due to use of GLX");
return false;
}
// This hint will ensure we use EGL to retrieve our GL context,
// even on X11 where that is not the default. EGL is required
// to avoid a crash in Mesa.
@ -657,13 +665,6 @@ bool EGLRenderer::initialize(PDECODER_PARAMETERS params)
// Detach the context from this thread, so the render thread can attach it
SDL_GL_MakeCurrent(m_Window, nullptr);
if (err == GL_NO_ERROR) {
// If we got a working GL implementation via EGL, avoid using GLX from now on.
// GLX will cause problems if we later want to use EGL again on this window.
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "EGL passed preflight checks. Using EGL for GL context creation.");
SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1");
}
return err == GL_NO_ERROR;
}

View file

@ -7,6 +7,7 @@
namespace WMUtils {
bool isRunningX11();
bool isRunningX11NvidiaProprietaryDriver();
bool isRunningWayland();
bool isRunningWindowManager();
bool isRunningDesktopEnvironment();

View file

@ -47,6 +47,40 @@ bool WMUtils::isRunningX11()
return false;
}
bool WMUtils::isRunningX11NvidiaProprietaryDriver()
{
#ifdef HAS_X11
static SDL_atomic_t isRunningOnX11NvidiaDriver;
// If the value is not set yet, populate it now.
int val = SDL_AtomicGet(&isRunningOnX11NvidiaDriver);
if (!(val & VALUE_SET)) {
Display* display = XOpenDisplay(nullptr);
bool nvidiaDriver = false;
if (display != nullptr) {
int opcode, event, error;
// We use the presence of the NV-CONTROL extension to indicate
// that the Nvidia proprietary driver is in use on native X11
nvidiaDriver = XQueryExtension(display, "NV-CONTROL", &opcode, &event, &error);
XCloseDisplay(display);
}
// Populate the value to return and have for next time.
// This can race with another thread populating the same data,
// but that's no big deal.
val = VALUE_SET | (nvidiaDriver ? VALUE_TRUE : 0);
SDL_AtomicSet(&isRunningOnX11NvidiaDriver, val);
}
return !!(val & VALUE_TRUE);
#endif
return false;
}
bool WMUtils::isRunningWayland()
{
#ifdef HAS_WAYLAND