global_state.cpp (10006B)
1 // 2 // Copyright 2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // global_state.cpp : Implements functions for querying the thread-local GL and EGL state. 8 9 #include "libGLESv2/global_state.h" 10 11 #include "common/debug.h" 12 #include "common/platform.h" 13 #include "common/system_utils.h" 14 #include "libANGLE/ErrorStrings.h" 15 #include "libANGLE/Thread.h" 16 #include "libGLESv2/resource.h" 17 18 #include <atomic> 19 #if defined(ANGLE_PLATFORM_APPLE) 20 # include <dispatch/dispatch.h> 21 #endif 22 namespace egl 23 { 24 namespace 25 { 26 ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_Mutex{}; 27 static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value, 28 "global mutex is not trivially destructible"); 29 ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_SurfaceMutex{}; 30 static_assert(std::is_trivially_destructible<decltype(g_SurfaceMutex)>::value, 31 "global mutex is not trivially destructible"); 32 33 ANGLE_REQUIRE_CONSTANT_INIT gl::Context *g_LastContext(nullptr); 34 static_assert(std::is_trivially_destructible<decltype(g_LastContext)>::value, 35 "global last context is not trivially destructible"); 36 37 void SetContextToAndroidOpenGLTLSSlot(gl::Context *value) 38 { 39 #if defined(ANGLE_USE_ANDROID_TLS_SLOT) 40 if (angle::gUseAndroidOpenGLTlsSlot) 41 { 42 ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot] = static_cast<void *>(value); 43 } 44 #endif 45 } 46 47 // Called only on Android platform 48 [[maybe_unused]] void ThreadCleanupCallback(void *ptr) 49 { 50 ANGLE_SCOPED_GLOBAL_LOCK(); 51 angle::PthreadKeyDestructorCallback(ptr); 52 } 53 54 Thread *AllocateCurrentThread() 55 { 56 Thread *thread; 57 { 58 // Global thread intentionally leaked 59 ANGLE_SCOPED_DISABLE_LSAN(); 60 thread = new Thread(); 61 #if defined(ANGLE_PLATFORM_APPLE) 62 SetCurrentThreadTLS(thread); 63 #else 64 gCurrentThread = thread; 65 #endif 66 } 67 68 // Initialize fast TLS slot 69 SetContextToAndroidOpenGLTLSSlot(nullptr); 70 71 #if defined(ANGLE_PLATFORM_APPLE) 72 gl::SetCurrentValidContextTLS(nullptr); 73 #else 74 gl::gCurrentValidContext = nullptr; 75 #endif 76 77 #if defined(ANGLE_PLATFORM_ANDROID) 78 static pthread_once_t keyOnce = PTHREAD_ONCE_INIT; 79 static TLSIndex gThreadCleanupTLSIndex = TLS_INVALID_INDEX; 80 81 // Create thread cleanup TLS slot 82 auto CreateThreadCleanupTLSIndex = []() { 83 gThreadCleanupTLSIndex = CreateTLSIndex(ThreadCleanupCallback); 84 }; 85 pthread_once(&keyOnce, CreateThreadCleanupTLSIndex); 86 ASSERT(gThreadCleanupTLSIndex != TLS_INVALID_INDEX); 87 88 // Initialize thread cleanup TLS slot 89 SetTLSValue(gThreadCleanupTLSIndex, thread); 90 #endif // ANGLE_PLATFORM_ANDROID 91 92 ASSERT(thread); 93 return thread; 94 } 95 96 void AllocateGlobalMutex(std::atomic<angle::GlobalMutex *> &mutex) 97 { 98 if (mutex == nullptr) 99 { 100 std::unique_ptr<angle::GlobalMutex> newMutex(new angle::GlobalMutex()); 101 angle::GlobalMutex *expected = nullptr; 102 if (mutex.compare_exchange_strong(expected, newMutex.get())) 103 { 104 newMutex.release(); 105 } 106 } 107 } 108 109 void AllocateMutex() 110 { 111 AllocateGlobalMutex(g_Mutex); 112 } 113 114 void AllocateSurfaceMutex() 115 { 116 AllocateGlobalMutex(g_SurfaceMutex); 117 } 118 119 } // anonymous namespace 120 121 #if defined(ANGLE_PLATFORM_APPLE) 122 // TODO(angleproject:6479): Due to a bug in Apple's dyld loader, `thread_local` will cause 123 // excessive memory use. Temporarily avoid it by using pthread's thread 124 // local storage instead. 125 // https://bugs.webkit.org/show_bug.cgi?id=228240 126 127 static TLSIndex GetCurrentThreadTLSIndex() 128 { 129 static TLSIndex CurrentThreadIndex = TLS_INVALID_INDEX; 130 static dispatch_once_t once; 131 dispatch_once(&once, ^{ 132 ASSERT(CurrentThreadIndex == TLS_INVALID_INDEX); 133 CurrentThreadIndex = CreateTLSIndex(nullptr); 134 }); 135 return CurrentThreadIndex; 136 } 137 Thread *GetCurrentThreadTLS() 138 { 139 TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex(); 140 ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX); 141 return static_cast<Thread *>(GetTLSValue(CurrentThreadIndex)); 142 } 143 void SetCurrentThreadTLS(Thread *thread) 144 { 145 TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex(); 146 ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX); 147 SetTLSValue(CurrentThreadIndex, thread); 148 } 149 #else 150 thread_local Thread *gCurrentThread = nullptr; 151 #endif 152 153 angle::GlobalMutex &GetGlobalMutex() 154 { 155 AllocateMutex(); 156 return *g_Mutex; 157 } 158 159 angle::GlobalMutex &GetGlobalSurfaceMutex() 160 { 161 AllocateSurfaceMutex(); 162 return *g_SurfaceMutex; 163 } 164 165 gl::Context *GetGlobalLastContext() 166 { 167 return g_LastContext; 168 } 169 170 void SetGlobalLastContext(gl::Context *context) 171 { 172 g_LastContext = context; 173 } 174 175 // This function causes an MSAN false positive, which is muted. See https://crbug.com/1211047 176 // It also causes a flaky false positive in TSAN. http://crbug.com/1223970 177 ANGLE_NO_SANITIZE_MEMORY ANGLE_NO_SANITIZE_THREAD Thread *GetCurrentThread() 178 { 179 #if defined(ANGLE_PLATFORM_APPLE) 180 Thread *current = GetCurrentThreadTLS(); 181 #else 182 Thread *current = gCurrentThread; 183 #endif 184 return (current ? current : AllocateCurrentThread()); 185 } 186 187 void SetContextCurrent(Thread *thread, gl::Context *context) 188 { 189 #if defined(ANGLE_PLATFORM_APPLE) 190 Thread *currentThread = GetCurrentThreadTLS(); 191 #else 192 Thread *currentThread = gCurrentThread; 193 #endif 194 ASSERT(currentThread); 195 currentThread->setCurrent(context); 196 SetContextToAndroidOpenGLTLSSlot(context); 197 198 #if defined(ANGLE_PLATFORM_APPLE) 199 gl::SetCurrentValidContextTLS(context); 200 #else 201 gl::gCurrentValidContext = context; 202 #endif 203 204 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL) 205 DirtyContextIfNeeded(context); 206 #endif 207 } 208 209 ScopedSyncCurrentContextFromThread::ScopedSyncCurrentContextFromThread(egl::Thread *thread) 210 : mThread(thread) 211 { 212 ASSERT(mThread); 213 } 214 215 ScopedSyncCurrentContextFromThread::~ScopedSyncCurrentContextFromThread() 216 { 217 SetContextCurrent(mThread, mThread->getContext()); 218 } 219 220 } // namespace egl 221 222 namespace gl 223 { 224 void GenerateContextLostErrorOnContext(Context *context) 225 { 226 if (context && context->isContextLost()) 227 { 228 context->validationError(angle::EntryPoint::GLInvalid, GL_CONTEXT_LOST, err::kContextLost); 229 } 230 } 231 232 void GenerateContextLostErrorOnCurrentGlobalContext() 233 { 234 // If the client starts issuing GL calls before ANGLE has had a chance to initialize, 235 // GenerateContextLostErrorOnCurrentGlobalContext can be called before AllocateCurrentThread has 236 // had a chance to run. Calling GetCurrentThread() ensures that TLS thread state is set up. 237 egl::GetCurrentThread(); 238 239 GenerateContextLostErrorOnContext(GetGlobalContext()); 240 } 241 } // namespace gl 242 243 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC) 244 namespace egl 245 { 246 247 namespace 248 { 249 250 void DeallocateGlobalMutex(std::atomic<angle::GlobalMutex *> &mutex) 251 { 252 angle::GlobalMutex *toDelete = mutex.exchange(nullptr); 253 if (!mutex) 254 return; 255 { 256 // Wait for toDelete to become released by other threads before deleting. 257 std::lock_guard<angle::GlobalMutex> lock(*toDelete); 258 } 259 SafeDelete(toDelete); 260 } 261 262 void DeallocateCurrentThread() 263 { 264 SafeDelete(gCurrentThread); 265 } 266 267 void DeallocateMutex() 268 { 269 DeallocateGlobalMutex(g_Mutex); 270 } 271 272 void DeallocateSurfaceMutex() 273 { 274 DeallocateGlobalMutex(g_SurfaceMutex); 275 } 276 277 bool InitializeProcess() 278 { 279 EnsureDebugAllocated(); 280 AllocateMutex(); 281 return AllocateCurrentThread() != nullptr; 282 } 283 284 void TerminateProcess() 285 { 286 DeallocateDebug(); 287 DeallocateSurfaceMutex(); 288 DeallocateMutex(); 289 DeallocateCurrentThread(); 290 } 291 292 } // anonymous namespace 293 294 } // namespace egl 295 296 namespace 297 { 298 // The following WaitForDebugger code is based on SwiftShader. See: 299 // https://cs.chromium.org/chromium/src/third_party/swiftshader/src/Vulkan/main.cpp 300 # if defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP) 301 INT_PTR CALLBACK DebuggerWaitDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 302 { 303 RECT rect; 304 305 switch (uMsg) 306 { 307 case WM_INITDIALOG: 308 ::GetWindowRect(GetDesktopWindow(), &rect); 309 ::SetWindowPos(hwnd, HWND_TOP, rect.right / 2, rect.bottom / 2, 0, 0, SWP_NOSIZE); 310 ::SetTimer(hwnd, 1, 100, NULL); 311 return TRUE; 312 case WM_COMMAND: 313 if (LOWORD(wParam) == IDCANCEL) 314 { 315 ::EndDialog(hwnd, 0); 316 } 317 break; 318 case WM_TIMER: 319 if (angle::IsDebuggerAttached()) 320 { 321 ::EndDialog(hwnd, 0); 322 } 323 } 324 325 return FALSE; 326 } 327 328 void WaitForDebugger(HINSTANCE instance) 329 { 330 if (angle::IsDebuggerAttached()) 331 return; 332 333 HRSRC dialog = ::FindResourceA(instance, MAKEINTRESOURCEA(IDD_DIALOG1), MAKEINTRESOURCEA(5)); 334 if (!dialog) 335 { 336 printf("Error finding wait for debugger dialog. Error %lu.\n", ::GetLastError()); 337 return; 338 } 339 340 DLGTEMPLATE *dialogTemplate = reinterpret_cast<DLGTEMPLATE *>(::LoadResource(instance, dialog)); 341 ::DialogBoxIndirectA(instance, dialogTemplate, NULL, DebuggerWaitDialogProc); 342 } 343 # else 344 void WaitForDebugger(HINSTANCE instance) {} 345 # endif // defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP) 346 } // namespace 347 348 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) 349 { 350 switch (reason) 351 { 352 case DLL_PROCESS_ATTACH: 353 if (angle::GetEnvironmentVar("ANGLE_WAIT_FOR_DEBUGGER") == "1") 354 { 355 WaitForDebugger(instance); 356 } 357 return static_cast<BOOL>(egl::InitializeProcess()); 358 359 case DLL_THREAD_ATTACH: 360 return static_cast<BOOL>(egl::AllocateCurrentThread() != nullptr); 361 362 case DLL_THREAD_DETACH: 363 egl::DeallocateCurrentThread(); 364 break; 365 366 case DLL_PROCESS_DETACH: 367 egl::TerminateProcess(); 368 break; 369 } 370 371 return TRUE; 372 } 373 #endif // defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)