diff --git a/MobileGL/MG_Backend/BackendObject.cpp b/MobileGL/MG_Backend/BackendObject.cpp index f238dd3a..a7034b88 100644 --- a/MobileGL/MG_Backend/BackendObject.cpp +++ b/MobileGL/MG_Backend/BackendObject.cpp @@ -172,11 +172,15 @@ namespace MobileGL::MG_Backend { return false; } - if (m_eglDisplayInitialized && m_eglDisplay != dpy) { - MGLOG_E("InitializeEGLDisplay failed: backend already bound to a different EGLDisplay"); - return false; - } - + // A DISPLAY IS A CONNECTION, NOT A RESOURCE THIS BACKEND OWNS, and refusing the second one + // refused a caller for a reason that is not there: the surface and context tables are keyed + // by the display each was created on, every operation carries its own display handle, and + // this field has no reader anywhere - it was the whole of the rule. + // + // What the rule cost was a compositor. One asks for the display it will draw into AFTER + // probing another, so the second eglInitialize is the one that matters, and a refusal there + // is reported one layer up as "no usable DRM render device" - the probe having succeeded + // and the real display having failed, with nothing in between that says which was refused. m_eglDisplay = dpy; m_eglDisplayInitialized = true; if (major) { diff --git a/MobileGL/MG_Impl/EGLImpl/Exporting/GlvndVendor.cpp b/MobileGL/MG_Impl/EGLImpl/Exporting/GlvndVendor.cpp index 3865736a..9976b10e 100644 --- a/MobileGL/MG_Impl/EGLImpl/Exporting/GlvndVendor.cpp +++ b/MobileGL/MG_Impl/EGLImpl/Exporting/GlvndVendor.cpp @@ -245,7 +245,17 @@ namespace { {"eglLabelObjectKHR", reinterpret_cast(VendorLabelObjectKHR)}, }; - void* EGLAPIENTRY VendorGetProcAddress(const char* procName) { + // THE SAME ANSWER TO BOTH OF GLVND'S QUESTIONS, and that is not a shortcut - glvnd asks them + // from two places and a library that answers one of them has a hole the size of the other: + // + // getProcAddress is asked for every entry point glvnd builds its own static EGL table + // from, so a null here drops the vendor outright. + // getDispatchAddress is what glvnd falls back to for eglGetProcAddress on any name it does + // not know itself - which is every extension entry point that is not in + // its list, the device queries among them. A vendor that answers these + // from a GL-only table hands the application a null for a function the + // vendor implements, and the caller reports the extension as missing. + void* LookupEntryPoint(const char* procName) { if (procName == nullptr) { return nullptr; } @@ -259,6 +269,8 @@ namespace { return reinterpret_cast(MG_Impl::EGLImpl::GetProcAddress(procName)); } + void* EGLAPIENTRY VendorGetProcAddress(const char* procName) { return LookupEntryPoint(procName); } + // glvnd hands a vendor the index each EGL entry point occupies in its dispatch table, so that a // vendor whose entry points are thin wrappers around glvnd can call back into the right slot. // This library's entry points ARE the implementation - they never re-enter glvnd - so there is @@ -269,15 +281,7 @@ namespace { (void)index; } - // glvnd builds its GL/GLES dispatch out of these: one address per entry point, taken from the - // vendor that owns the current display. This library exports them all, so the answer is its - // own table. - void* EGLAPIENTRY VendorGetDispatchAddress(const char* procName) { - if (procName == nullptr) { - return nullptr; - } - return reinterpret_cast(MG_Impl::EGLImpl::GetProcAddress(procName)); - } + void* EGLAPIENTRY VendorGetDispatchAddress(const char* procName) { return LookupEntryPoint(procName); } } // namespace extern "C" MOBILEGL_EGL_API EGLBoolean __egl_Main(uint32_t version, const __EGLapiExports* exports,