diff --git a/app/main.cpp b/app/main.cpp index 0bdb22d9..bcf1705c 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -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 diff --git a/app/streaming/video/ffmpeg-renderers/eglvid.cpp b/app/streaming/video/ffmpeg-renderers/eglvid.cpp index 1859a7d0..7c919c84 100644 --- a/app/streaming/video/ffmpeg-renderers/eglvid.cpp +++ b/app/streaming/video/ffmpeg-renderers/eglvid.cpp @@ -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; } diff --git a/app/utils.h b/app/utils.h index 1a61231a..f234dc76 100644 --- a/app/utils.h +++ b/app/utils.h @@ -7,6 +7,7 @@ namespace WMUtils { bool isRunningX11(); + bool isRunningX11NvidiaProprietaryDriver(); bool isRunningWayland(); bool isRunningWindowManager(); bool isRunningDesktopEnvironment(); diff --git a/app/wm.cpp b/app/wm.cpp index 68f26d0f..704b7152 100644 --- a/app/wm.cpp +++ b/app/wm.cpp @@ -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