diff --git a/MobileGL/Init.cpp b/MobileGL/Init.cpp index 43204961..c62cee96 100644 --- a/MobileGL/Init.cpp +++ b/MobileGL/Init.cpp @@ -238,6 +238,18 @@ namespace MobileGL { #endif return true; } +#if defined(__linux__) && !defined(__ANDROID__) + // LIBGL_ALWAYS_SOFTWARE is how a process (or whoever launched it) asks the system's GL for a + // software renderer. MobileGL is a GPU forwarder, so it steps aside and lets the system's + // other implementation give the process what it asked for. + { + String software; + if (MG_ConfigLoader::LookupSetting("LIBGL_ALWAYS_SOFTWARE", software) && !software.empty() && + software != "0" && software != "false") { + return false; + } + } +#endif #if MOBILEGL_BUILD_DISAGGREGATED // Not yet: the bring-up would dial the configured server and wait for it. Ask first. return MG_Remote::Client::ConfiguredServerAvailable(); diff --git a/MobileGL/Init.h b/MobileGL/Init.h index de11c23f..d5c380fc 100644 --- a/MobileGL/Init.h +++ b/MobileGL/Init.h @@ -32,8 +32,9 @@ namespace MobileGL { Bool LookupSetting(const char* key, String& outValue); } // namespace MG_ConfigLoader - // Whether this process can be served right now. False only when MobileGL is configured to - // reach a server that is not there (or a split session already failed to come up), so a + // Whether this process can be served right now. False when MobileGL is configured to reach a + // server that is not there (or a split session already failed to come up), or when the process + // asked for software rendering (LIBGL_ALWAYS_SOFTWARE, desktop Linux), so a // caller that can choose another implementation - the system's EGL/GLX/GBM loaders - should // decline rather than hand out something that cannot draw. Cheap: once true it stays true // until the library is torn down, and a probe is one non-blocking connect with a short bound. diff --git a/MobileGL/MG_Test/Wire/ServerProbeTest.cpp b/MobileGL/MG_Test/Wire/ServerProbeTest.cpp index 4ddc19a9..41f7bf5f 100644 --- a/MobileGL/MG_Test/Wire/ServerProbeTest.cpp +++ b/MobileGL/MG_Test/Wire/ServerProbeTest.cpp @@ -194,7 +194,7 @@ namespace { Int64 elapsedMs = -1; // all of the above, end to end }; - EntryReport RunEntryPoints(const std::string& control, const std::string& logBase) { + EntryReport RunEntryPoints(const std::string& control, const std::string& logBase, bool software = false) { EntryReport report{}; int fds[2] = {-1, -1}; if (::pipe(fds) != 0) return report; @@ -206,6 +206,8 @@ namespace { ::setenv("MOBILEGL_TRANSPORT", "spawn", 1); ::setenv("MOBILEGL_IPC_CONTROL", control.c_str(), 1); ::setenv("MOBILEGL_BACKEND_TYPE", "DirectGLES", 1); + if (software) ::setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); + else ::unsetenv("LIBGL_ALWAYS_SOFTWARE"); EntryReport r{}; const auto start = std::chrono::steady_clock::now(); @@ -311,6 +313,13 @@ namespace { EXPECT_EQ(r.getDisplay, 1); EXPECT_EQ(r.vendorDevices, 1); EXPECT_EQ(r.glxLoaded, 1); + + // A process that asked for software rendering is left to the system's other GL, server or not. + const EntryReport software = RunEntryPoints(server.endpoint, logBase, true); + EXPECT_EQ(software.vendorDisplay, 0); + EXPECT_EQ(software.getDisplay, 0); + EXPECT_EQ(software.vendorDevices, 0); + EXPECT_EQ(software.glxLoaded, 0); std::error_code ec; std::filesystem::remove(Debug::RoleLogPath(logBase.c_str(), Debug::LogRole::Client), ec); }