David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 1 | // |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 2 | // Copyright 2014 The ANGLE Project Authors. All rights reserved. |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 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 | |
Andrew Top | 200ce4b | 2018-01-29 13:43:50 -0800 | [diff] [blame] | 11 | #if defined(ADDRESS_SANITIZER) |
| 12 | // By default, Leak Sanitizer and Address Sanitizer is expected to exist |
| 13 | // together. However, this is not true for all platforms. |
| 14 | // HAS_LEAK_SANTIZIER=0 explicitly removes the Leak Sanitizer from code. |
| 15 | #ifndef HAS_LEAK_SANITIZER |
| 16 | #define HAS_LEAK_SANITIZER 1 |
| 17 | #endif // HAS_LEAK_SANITIZER |
| 18 | #endif // defined(ADDRESS_SANITIZER) |
| 19 | |
| 20 | #if HAS_LEAK_SANITIZER |
| 21 | #include <sanitizer/lsan_interface.h> |
| 22 | #endif // HAS_LEAK_SANITIZER |
| 23 | |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 24 | #include "common/debug.h" |
| 25 | #include "common/platform.h" |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 26 | #include "common/system_utils.h" |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 27 | #include "common/tls.h" |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 28 | #include "libGLESv2/resource.h" |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 29 | |
| 30 | namespace gl |
| 31 | { |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 32 | // In single-threaded cases we can avoid a TLS lookup for the current Context. |
| 33 | // |
| 34 | // Let a global single-threaded context have 3 states: unset, set, and multi-threaded. |
| 35 | // Initially it is unset. Then, on MakeCurrent: |
| 36 | // |
| 37 | // * if the ST context is unset -> set the global context. |
| 38 | // * if the ST context is set and matches the TLS -> set the global context. |
| 39 | // * if the ST context is set and does not match TLS -> set multi-threaded mode. |
| 40 | // * if in multi-threaded mode, unset and subsequently ignore the global context. |
| 41 | // |
| 42 | // Implementation-wise we can use a pointer and a boolean to represent the three modes. |
| 43 | Context *gSingleThreadedContext = nullptr; |
| 44 | bool gIsMultiThreadedContext = false; |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 45 | } // namespace gl |
| 46 | |
| 47 | namespace egl |
| 48 | { |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 49 | namespace |
| 50 | { |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 51 | static TLSIndex threadTLS = TLS_INVALID_INDEX; |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 52 | Debug *g_Debug = nullptr; |
| 53 | |
| 54 | ANGLE_REQUIRE_CONSTANT_INIT std::atomic<std::mutex *> g_Mutex(nullptr); |
| 55 | static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value, |
| 56 | "global mutex is not trivially destructible"); |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 57 | |
| 58 | Thread *AllocateCurrentThread() |
| 59 | { |
| 60 | ASSERT(threadTLS != TLS_INVALID_INDEX); |
| 61 | if (threadTLS == TLS_INVALID_INDEX) |
| 62 | { |
| 63 | return nullptr; |
| 64 | } |
| 65 | |
Andrew Top | 200ce4b | 2018-01-29 13:43:50 -0800 | [diff] [blame] | 66 | #if HAS_LEAK_SANITIZER |
| 67 | __lsan_disable(); |
| 68 | #endif // HAS_LEAK_SANITIZER |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 69 | Thread *thread = new Thread(); |
Andrew Top | 200ce4b | 2018-01-29 13:43:50 -0800 | [diff] [blame] | 70 | #if HAS_LEAK_SANITIZER |
| 71 | __lsan_enable(); |
| 72 | #endif // HAS_LEAK_SANITIZER |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 73 | if (!SetTLSValue(threadTLS, thread)) |
| 74 | { |
| 75 | ERR() << "Could not set thread local storage."; |
| 76 | return nullptr; |
| 77 | } |
| 78 | |
| 79 | return thread; |
| 80 | } |
| 81 | |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 82 | void AllocateDebug() |
| 83 | { |
| 84 | // All EGL calls use a global lock, this is thread safe |
| 85 | if (g_Debug == nullptr) |
| 86 | { |
| 87 | g_Debug = new Debug(); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | void AllocateMutex() |
| 92 | { |
| 93 | if (g_Mutex == nullptr) |
| 94 | { |
| 95 | std::unique_ptr<std::mutex> newMutex(new std::mutex()); |
| 96 | std::mutex *expected = nullptr; |
| 97 | if (g_Mutex.compare_exchange_strong(expected, newMutex.get())) |
| 98 | { |
| 99 | newMutex.release(); |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 104 | } // anonymous namespace |
| 105 | |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 106 | std::mutex &GetGlobalMutex() |
| 107 | { |
| 108 | AllocateMutex(); |
| 109 | return *g_Mutex; |
| 110 | } |
| 111 | |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 112 | Thread *GetCurrentThread() |
| 113 | { |
| 114 | // Create a TLS index if one has not been created for this DLL |
| 115 | if (threadTLS == TLS_INVALID_INDEX) |
| 116 | { |
| 117 | threadTLS = CreateTLSIndex(); |
| 118 | } |
| 119 | |
| 120 | Thread *current = static_cast<Thread *>(GetTLSValue(threadTLS)); |
| 121 | |
| 122 | // ANGLE issue 488: when the dll is loaded after thread initialization, |
| 123 | // thread local storage (current) might not exist yet. |
| 124 | return (current ? current : AllocateCurrentThread()); |
| 125 | } |
| 126 | |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 127 | Debug *GetDebug() |
| 128 | { |
| 129 | AllocateDebug(); |
| 130 | return g_Debug; |
| 131 | } |
| 132 | |
| 133 | void SetContextCurrent(Thread *thread, gl::Context *context) |
| 134 | { |
| 135 | // See above comment on gGlobalContext. |
| 136 | // If the context is in multi-threaded mode, ignore the global context. |
| 137 | if (!gl::gIsMultiThreadedContext) |
| 138 | { |
| 139 | // If the global context is unset or matches the current TLS, set the global context. |
| 140 | if (gl::gSingleThreadedContext == nullptr || |
| 141 | gl::gSingleThreadedContext == thread->getContext()) |
| 142 | { |
| 143 | gl::gSingleThreadedContext = context; |
| 144 | } |
| 145 | else |
| 146 | { |
| 147 | // If the global context is set and does not match TLS, set multi-threaded mode. |
| 148 | gl::gSingleThreadedContext = nullptr; |
| 149 | gl::gIsMultiThreadedContext = true; |
| 150 | } |
| 151 | } |
| 152 | thread->setCurrent(context); |
| 153 | } |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 154 | } // namespace egl |
| 155 | |
Andrew Top | d84d494 | 2017-08-22 17:31:32 -0700 | [diff] [blame] | 156 | #if defined(ANGLE_PLATFORM_WINDOWS) && defined(LIBGLESV2_DLL) |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 157 | namespace egl |
| 158 | { |
| 159 | |
| 160 | namespace |
| 161 | { |
| 162 | |
| 163 | bool DeallocateCurrentThread() |
| 164 | { |
| 165 | Thread *thread = static_cast<Thread *>(GetTLSValue(threadTLS)); |
| 166 | SafeDelete(thread); |
| 167 | return SetTLSValue(threadTLS, nullptr); |
| 168 | } |
| 169 | |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 170 | void DeallocateDebug() |
| 171 | { |
| 172 | SafeDelete(g_Debug); |
| 173 | } |
| 174 | |
| 175 | void DeallocateMutex() |
| 176 | { |
| 177 | std::mutex *mutex = g_Mutex.exchange(nullptr); |
| 178 | { |
| 179 | // Wait for the mutex to become released by other threads before deleting. |
| 180 | std::lock_guard<std::mutex> lock(*mutex); |
| 181 | } |
| 182 | SafeDelete(mutex); |
| 183 | } |
| 184 | |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 185 | bool InitializeProcess() |
| 186 | { |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 187 | ASSERT(g_Debug == nullptr); |
| 188 | AllocateDebug(); |
| 189 | |
| 190 | AllocateMutex(); |
| 191 | |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 192 | threadTLS = CreateTLSIndex(); |
| 193 | if (threadTLS == TLS_INVALID_INDEX) |
| 194 | { |
| 195 | return false; |
| 196 | } |
| 197 | |
| 198 | return AllocateCurrentThread() != nullptr; |
| 199 | } |
| 200 | |
| 201 | bool TerminateProcess() |
| 202 | { |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 203 | DeallocateDebug(); |
| 204 | |
| 205 | DeallocateMutex(); |
| 206 | |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 207 | if (!DeallocateCurrentThread()) |
| 208 | { |
| 209 | return false; |
| 210 | } |
| 211 | |
| 212 | if (threadTLS != TLS_INVALID_INDEX) |
| 213 | { |
| 214 | TLSIndex tlsCopy = threadTLS; |
| 215 | threadTLS = TLS_INVALID_INDEX; |
| 216 | |
| 217 | if (!DestroyTLSIndex(tlsCopy)) |
| 218 | { |
| 219 | return false; |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | return true; |
| 224 | } |
| 225 | |
| 226 | } // anonymous namespace |
| 227 | |
| 228 | } // namespace egl |
| 229 | |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 230 | namespace |
| 231 | { |
| 232 | // The following WaitForDebugger code is based on SwiftShader. See: |
| 233 | // https://cs.chromium.org/chromium/src/third_party/swiftshader/src/Vulkan/main.cpp |
| 234 | # if defined(ANGLE_ENABLE_ASSERTS) |
| 235 | INT_PTR CALLBACK DebuggerWaitDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
| 236 | { |
| 237 | RECT rect; |
| 238 | |
| 239 | switch (uMsg) |
| 240 | { |
| 241 | case WM_INITDIALOG: |
| 242 | ::GetWindowRect(GetDesktopWindow(), &rect); |
| 243 | ::SetWindowPos(hwnd, HWND_TOP, rect.right / 2, rect.bottom / 2, 0, 0, SWP_NOSIZE); |
| 244 | ::SetTimer(hwnd, 1, 100, NULL); |
| 245 | return TRUE; |
| 246 | case WM_COMMAND: |
| 247 | if (LOWORD(wParam) == IDCANCEL) |
| 248 | { |
| 249 | ::EndDialog(hwnd, 0); |
| 250 | } |
| 251 | break; |
| 252 | case WM_TIMER: |
| 253 | if (angle::IsDebuggerAttached()) |
| 254 | { |
| 255 | ::EndDialog(hwnd, 0); |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | return FALSE; |
| 260 | } |
| 261 | |
| 262 | void WaitForDebugger(HINSTANCE instance) |
| 263 | { |
| 264 | if (angle::IsDebuggerAttached()) |
| 265 | return; |
| 266 | |
| 267 | HRSRC dialog = ::FindResourceA(instance, MAKEINTRESOURCEA(IDD_DIALOG1), MAKEINTRESOURCEA(5)); |
| 268 | if (!dialog) |
| 269 | { |
| 270 | printf("Error finding wait for debugger dialog. Error %lu.\n", ::GetLastError()); |
| 271 | return; |
| 272 | } |
| 273 | |
| 274 | DLGTEMPLATE *dialogTemplate = reinterpret_cast<DLGTEMPLATE *>(::LoadResource(instance, dialog)); |
| 275 | ::DialogBoxIndirectA(instance, dialogTemplate, NULL, DebuggerWaitDialogProc); |
| 276 | } |
| 277 | # else |
| 278 | void WaitForDebugger(HINSTANCE instance) {} |
| 279 | # endif // defined(ANGLE_ENABLE_ASSERTS) |
| 280 | } // namespace |
| 281 | |
| 282 | extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 283 | { |
| 284 | switch (reason) |
| 285 | { |
| 286 | case DLL_PROCESS_ATTACH: |
Kaido Kert | 612c020 | 2020-01-22 10:28:42 -0800 | [diff] [blame] | 287 | if (angle::GetEnvironmentVar("ANGLE_WAIT_FOR_DEBUGGER") == "1") |
| 288 | { |
| 289 | WaitForDebugger(instance); |
| 290 | } |
David Ghandehari | b153652 | 2017-05-24 00:01:15 -0700 | [diff] [blame] | 291 | return static_cast<BOOL>(egl::InitializeProcess()); |
| 292 | |
| 293 | case DLL_THREAD_ATTACH: |
| 294 | return static_cast<BOOL>(egl::AllocateCurrentThread() != nullptr); |
| 295 | |
| 296 | case DLL_THREAD_DETACH: |
| 297 | return static_cast<BOOL>(egl::DeallocateCurrentThread()); |
| 298 | |
| 299 | case DLL_PROCESS_DETACH: |
| 300 | return static_cast<BOOL>(egl::TerminateProcess()); |
| 301 | } |
| 302 | |
| 303 | return TRUE; |
| 304 | } |
Andrew Top | d84d494 | 2017-08-22 17:31:32 -0700 | [diff] [blame] | 305 | #endif // defined(ANGLE_PLATFORM_WINDOWS) && defined(LIBGLESV2_DLL) |