From bc3451a593cb25477392d901abd9fc5c08f68f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 10 Oct 2019 13:48:59 +0200 Subject: [PATCH] Platform: how did Linus say it, fuck NVidia? Thanks a lot, there goes my morning. --- .../Platform/WindowlessEglApplication.cpp | 37 ++++++++++++++++++- .../Platform/WindowlessEglApplication.h | 32 ++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/Magnum/Platform/WindowlessEglApplication.cpp b/src/Magnum/Platform/WindowlessEglApplication.cpp index 8fd847a97..5a003aece 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.cpp +++ b/src/Magnum/Platform/WindowlessEglApplication.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "Magnum/GL/Version.h" #include "Magnum/Platform/GLContext.h" @@ -47,6 +49,18 @@ typedef void *EGLDeviceEXT; #define EGL_PLATFORM_DEVICE_EXT 0x313F #endif +#ifndef EGL_VERSION_1_5 +typedef intptr_t EGLAttrib; +#endif + +#ifndef EGL_KHR_debug +#define EGL_DEBUG_MSG_WARN_KHR 0x33BB +#define EGL_DEBUG_MSG_INFO_KHR 0x33BC +typedef void* EGLObjectKHR; +typedef void* EGLLabelKHR; +typedef void (APIENTRY *EGLDEBUGPROCKHR)(EGLenum error, const char* command, EGLint messageType, EGLLabelKHR threadLabel, EGLLabelKHR objectLabel, const char* message); +#endif + namespace Magnum { namespace Platform { namespace { @@ -83,6 +97,24 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G thousand extensions?!). This is supported only since Mesa 19.2. */ extensionSupported(extensions, "EGL_EXT_platform_device") ) { + /* When libEGL_nvidia.so is present on a system w/o a NV GPU, + eglQueryDevicesEXT() fails there with EGL_BAD_ALLOC, but that is + never propagated to the glvnd wrapper. Enable debug output if + --magnum-gpu-validation is enabled because otherwise it's fucking + hard to discover what's to blame (lost > 3 hours already). See class + docs for more info and a workaround. */ + if(extensionSupported(extensions, "EGL_KHR_debug") && magnumContext && (magnumContext->internalFlags() & GL::Context::InternalFlag::GpuValidation)) { + auto eglDebugMessageControl = reinterpret_cast(eglGetProcAddress("eglDebugMessageControlKHR")); + const EGLAttrib debugAttribs[] = { + EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, + EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, + EGL_NONE + }; + CORRADE_INTERNAL_ASSERT_OUTPUT(eglDebugMessageControl([](EGLenum, const char* const command, EGLint, EGLLabelKHR, EGLLabelKHR, const char* message) { + Debug{} << command << Debug::nospace << "():" << Utility::String::rtrim(message); + }, debugAttribs) == EGL_SUCCESS); + } + EGLint count; auto eglQueryDevices = reinterpret_cast(eglGetProcAddress("eglQueryDevicesEXT")); if(!eglQueryDevices(0, nullptr, &count)) { @@ -91,7 +123,10 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G } if(!count) { - Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): no EGL devices found"; + Error e; + e << "Platform::WindowlessEglApplication::tryCreateContext(): no EGL devices found, likely a driver issue"; + if(!magnumContext || !(magnumContext->internalFlags() & GL::Context::InternalFlag::GpuValidation)) + e << Debug::nospace << "; enable --magnum-gpu-validation to see additional info"; return; } diff --git a/src/Magnum/Platform/WindowlessEglApplication.h b/src/Magnum/Platform/WindowlessEglApplication.h index 0816fc17a..cfce477a8 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.h +++ b/src/Magnum/Platform/WindowlessEglApplication.h @@ -358,6 +358,38 @@ The application prefers to use the @m_class{m-doc-external} @m_class{m-doc-external} [EGL_EXT_platform_device](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_device.txt) where available instead of `EGL_DEFAULT_DISPLAY` to work better on headless setups. The application always chooses the first found device. + +@m_class{m-block m-danger} + +@par No EGL devices found +@parblock +Systems running Mesa 19.2 (which has the above extensions) that also have +`libEGL_nvidia.so` installed (for example as a CUDA dependency) may fail +to create the context with the following error (with additional output +produced when the `--magnum-gpu-validation` +@ref GL-Context-command-line "command-line option" is enabled): + +@m_class{m-console-wrap} + +@code{.shell-session} +eglQueryDevicesEXT(): EGL_BAD_ALLOC error: In internal function: Additional INFO may be available +eglQueryDevicesEXT(): EGL_BAD_ALLOC error: In function eglQueryDevicesEXT(), backend failed to query devices +Platform::WindowlessEglApplication::tryCreateContext(): no EGL devices found +@endcode + +This is due to the NVidia's EGL implementation failing to enumerate devices +(because there aren't any), which then causes the GLVND wrapper to stop +instead of enumerating the Mesa devices as well. The solution is +whitelisting all EGL implementations except the NVidia one +as described in the libglvnd documentation +using the `__EGL_VENDOR_LIBRARY_FILENAMES` environment variable, for example: + +@m_class{m-console-wrap} + +@code{.sh} +__EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json ./my-application +@endcode +@endparblock */ class WindowlessEglApplication { public: