1313#include < Logging.hpp>
1414
1515#include < array>
16+ #include < cstdint>
1617#include < cstdio>
1718
1819#ifdef _WIN32
@@ -30,12 +31,13 @@ namespace Platform {
3031
3132GLResolver::~GLResolver ()
3233{
33- SOIL_GL_Destroy ();
34-
35- // make sure handles are released
36- m_eglLib.Close ();
37- m_glLib.Close ();
38- m_glxLib.Close ();
34+ /*
35+ * Process-lifetime singleton: destructor runs during process teardown.
36+ * Do not call into GL or unload GL driver libraries here:
37+ * - GL context may already be destroyed on this thread.
38+ * - Other threads may still be running.
39+ * OS will reclaim mappings on exit.
40+ */
3941}
4042
4143auto GLResolver::Instance () -> GLResolver&
@@ -50,6 +52,8 @@ void GLResolver::SetBackendDefault()
5052 {
5153#ifdef __EMSCRIPTEN__
5254 m_backend = Backend::WebGl;
55+ #elif defined(__APPLE__)
56+ m_backend = Backend::Cgl;
5357#elif defined(USE_GLES)
5458 m_backend = Backend::Egl;
5559#elif defined(_WIN32)
@@ -63,7 +67,7 @@ void GLResolver::SetBackendDefault()
6367auto GLResolver::Initialize (UserResolver resolver, void * userData) -> bool
6468{
6569 // Avoids holding m_mutex while calling into GLAD (prevents deadlocks),
66- // Prevent concurrent Initialize()/Shutdown(),
70+ // Prevent concurrent Initialize()
6771 std::unique_lock<std::mutex> lock (m_mutex);
6872
6973 if (m_loaded)
@@ -101,17 +105,17 @@ auto GLResolver::Initialize(UserResolver resolver, void* userData) -> bool
101105
102106 lock.lock ();
103107
104- if (loaded)
108+ if (!loaded)
109+ {
110+ m_loaded = false ;
111+ }
112+ else
105113 {
106114 // set default in case detection failed, but loading succeeded
107115 SetBackendDefault ();
108116
109117 lock.unlock ();
110118
111- // init SOIL2 gl functions
112- SOIL_GL_SetResolver (&GLResolver::GladResolverThunk);
113- SOIL_GL_Init ();
114-
115119 GLContextCheck::Builder glCheck;
116120#ifdef USE_GLES
117121 glCheck
@@ -125,16 +129,29 @@ auto GLResolver::Initialize(UserResolver resolver, void* userData) -> bool
125129 .WithRequireCoreProfile (true );
126130#endif
127131
132+ const auto glDetails = glCheck.Check ();
133+
128134 lock.lock ();
129135
130- auto glDetails = glCheck.Check ();
131- LOG_INFO (std::string (" [GLResolver] GL Info: " ) + GLContextCheck::FormatCompactLine (glDetails.info ) + " backend=" + BackendToString (m_backend));
136+ LOG_INFO (std::string (" [GLResolver] GL Info: " ) +
137+ GLContextCheck::FormatCompactLine (glDetails.info ) +
138+ " backend=" + BackendToString (m_backend));
132139 if (!glDetails.success )
133140 {
134141 LOG_FATAL (std::string (" [GLResolver] GL Check failed: " ) + glDetails.reason );
135142 }
136143
137- m_loaded = glDetails.success ;
144+ lock.unlock ();
145+
146+ const bool ready = glDetails.success ;
147+ if (ready)
148+ {
149+ SOIL_GL_SetResolver (&GLResolver::GladResolverThunk);
150+ SOIL_GL_Init ();
151+ }
152+
153+ lock.lock ();
154+ m_loaded = ready;
138155 }
139156
140157 m_initializing = false ;
@@ -144,35 +161,6 @@ auto GLResolver::Initialize(UserResolver resolver, void* userData) -> bool
144161 return m_loaded;
145162}
146163
147- void GLResolver::Shutdown ()
148- {
149- std::unique_lock<std::mutex> lock (m_mutex);
150-
151- while (m_initializing)
152- {
153- m_initCv.wait (lock);
154- }
155-
156- SOIL_GL_Destroy ();
157-
158- m_loaded = false ;
159- m_backend = Backend::None;
160-
161- m_userResolver = nullptr ;
162- m_userData = nullptr ;
163-
164- m_eglGetProcAddress = nullptr ;
165- #ifndef _WIN32
166- m_glxGetProcAddress = nullptr ;
167- #else
168- m_wglGetProcAddress = nullptr ;
169- #endif
170-
171- m_eglLib.Close ();
172- m_glLib.Close ();
173- m_glxLib.Close ();
174- }
175-
176164auto GLResolver::IsLoaded () const -> bool
177165{
178166 const std::lock_guard<std::mutex> lock (m_mutex);
@@ -370,14 +358,17 @@ void GLResolver::ResolveProviderFunctions()
370358 }
371359#endif
372360
373- {
374- std::array<char , 256 > buf{};
375- std::snprintf (buf.data (), buf.size (), " [GLResolver] Library handles: egl=%p gl=%p glx=%p" ,
376- reinterpret_cast <void *>(m_eglLib.Handle ()),
377- reinterpret_cast <void *>(m_glLib.Handle ()),
378- reinterpret_cast <void *>(m_glxLib.Handle ()));
379- LOG_DEBUG (std::string (buf.data ()));
380- }
361+ LOG_DEBUG (std::string (" [GLResolver] EGL handle=" ) +
362+ std::to_string (reinterpret_cast <std::uintptr_t >(m_eglLib.Handle ())) +
363+ " lib=\" " + m_eglLib.LoadedName () + " \" " );
364+
365+ LOG_DEBUG (std::string (" [GLResolver] GL handle=" ) +
366+ std::to_string (reinterpret_cast <std::uintptr_t >(m_glLib.Handle ())) +
367+ " lib=\" " + m_glLib.LoadedName () + " \" " );
368+
369+ LOG_DEBUG (std::string (" [GLResolver] GLX handle=" ) +
370+ std::to_string (reinterpret_cast <std::uintptr_t >(m_glxLib.Handle ())) +
371+ " lib=\" " + m_glxLib.LoadedName () + " \" " );
381372
382373}
383374
@@ -514,10 +505,11 @@ auto GLResolver::ResolveUnlocked(const char* name,
514505 // 2) Platform provider getProcAddress (prefer for correctness, extensions, GLVND dispatch)
515506 if ((backend == Backend::Egl || backend == Backend::None) && eglGetProcAddressFn != nullptr )
516507 {
517- void * ptr = eglGetProcAddressFn (name);
518- if (ptr != nullptr )
508+ // eglGetProcAddress returns a function pointer type; convert only at the boundary.
509+ EglProc proc = eglGetProcAddressFn (name);
510+ if (proc != nullptr )
519511 {
520- return ptr ;
512+ return reinterpret_cast < void *>(proc) ;
521513 }
522514 }
523515
0 commit comments