From 4f679d669d2ce629051797e342caa951595dfbc2 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 2 Oct 2026 20:03:45 -0400 Subject: [PATCH] [Fix] (EGL): answer client queries and proc lookups without bringing a session up --- MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp | 31 ++++++++++++++++++++++- MobileGL/MG_Test/Wire/ServerProbeTest.cpp | 8 ++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp index 81fb993c..e9496b42 100644 --- a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp +++ b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp @@ -51,7 +51,14 @@ namespace MobileGL::MG_Impl::EGLImpl { // re-initialize after the last eglTerminate tore everything down. // Teardown-ish entry points keep using GetState() and fail benignly // when MobileGL is not initialized. + // + // Bringing MobileGL up dials its server, and with none reachable that waits out the + // bring-up's whole budget. So it is not attempted then: the entry point fails at once, as + // it would on any implementation without a display to offer. EGLStateContext* GetStateEnsureInitialized() { + if (!MG_State::pEGLContext && !MobileGL::ImplementationAvailable()) { + return nullptr; + } MobileGL::EnsureInitialized(); return GetState(); } @@ -852,6 +859,24 @@ namespace MobileGL::MG_Impl::EGLImpl { } char const* QueryString(EGLDisplay display, EGLint name) { + // THE CLIENT QUERIES BRING NOTHING UP. A dispatcher with several vendors asks every one of + // them for its client extensions before it picks one, so answering this must not cost a + // session - nor wait for a server that is not there. + if (display == EGL_NO_DISPLAY) { + switch (name) { + case EGL_VENDOR: + return "MobileGL"; + case EGL_VERSION: + return "1.5 MobileGL"; + case EGL_CLIENT_APIS: + return "OpenGL OpenGL_ES"; + case EGL_EXTENSIONS: + return kClientExtensionString; + default: + if (auto* state = MG_State::pEGLContext.get()) state->SetError(EGL_BAD_PARAMETER); + return nullptr; + } + } auto* state = GetStateEnsureInitialized(); if (!state) { return nullptr; @@ -1348,7 +1373,11 @@ namespace MobileGL::MG_Impl::EGLImpl { if (!name) { return nullptr; } - MobileGL::EnsureInitialized(); + // The answer is a static table; the bring-up is only the lazy-initialization contract, and + // it is skipped when there is no server to bring up against (see GetStateEnsureInitialized). + if (MobileGL::ImplementationAvailable()) { + MobileGL::EnsureInitialized(); + } MGLOG_D("eglGetProcAddress(%s)", name); void* proc = MG_Impl::GetProcAddress(name); diff --git a/MobileGL/MG_Test/Wire/ServerProbeTest.cpp b/MobileGL/MG_Test/Wire/ServerProbeTest.cpp index 41f7bf5f..30d6656b 100644 --- a/MobileGL/MG_Test/Wire/ServerProbeTest.cpp +++ b/MobileGL/MG_Test/Wire/ServerProbeTest.cpp @@ -191,6 +191,7 @@ namespace { Int32 vendorDisplay = -1; // 1: the glvnd vendor's getPlatformDisplay did Int32 vendorDevices = -1; // the vendor's eglQueryDevicesEXT count Int32 glxLoaded = -1; // __glx_Main's answer + Int32 clientQueries = -1; // 1: client extensions and a proc address answered (no display needed) Int64 elapsedMs = -1; // all of the above, end to end }; @@ -214,6 +215,11 @@ namespace { __EGLapiExports exports{}; __EGLapiImports imports{}; const bool vendor = __egl_Main(EGL_VENDOR_ABI_VERSION, &exports, nullptr, &imports) == EGL_TRUE; + // What a dispatcher asks every vendor before choosing one: never a session bring-up. + r.clientQueries = vendor && imports.getProcAddress("eglQueryString") != nullptr && + EGL::QueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS) != nullptr && + imports.getDispatchAddress("glClear") != nullptr && + EGL::GetProcAddress("eglQueryDmaBufModifiersEXT") != nullptr; r.vendorDisplay = vendor && imports.getPlatformDisplay(EGL_NONE, EGL_DEFAULT_DISPLAY, nullptr) != EGL_NO_DISPLAY; r.getDisplay = EGL::GetDisplay(EGL_DEFAULT_DISPLAY) != EGL_NO_DISPLAY; if (vendor) { @@ -253,6 +259,7 @@ namespace { EXPECT_EQ(r.getDisplay, 0); EXPECT_EQ(r.vendorDevices, 0) << "no device either, and no error (glvnd fails its merge on one)"; EXPECT_EQ(r.glxLoaded, 0) << "the GLX vendor must refuse to load so libGLX falls back"; + EXPECT_EQ(r.clientQueries, 1) << "client queries are answered without a server"; EXPECT_GE(r.elapsedMs, 0); EXPECT_LT(r.elapsedMs, 1000) << "declining must not cost the bring-up's 20 s connect budget"; std::error_code ec; @@ -313,6 +320,7 @@ namespace { EXPECT_EQ(r.getDisplay, 1); EXPECT_EQ(r.vendorDevices, 1); EXPECT_EQ(r.glxLoaded, 1); + EXPECT_EQ(r.clientQueries, 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);