xref: /aosp_15_r20/external/angle/src/libGLESv2/global_state.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/egl_stubs_autogen.h"
17 #include "libGLESv2/resource.h"
18 
19 #include <atomic>
20 #if defined(ANGLE_PLATFORM_APPLE)
21 #    include <dispatch/dispatch.h>
22 #endif
23 namespace egl
24 {
25 namespace
26 {
27 ANGLE_REQUIRE_CONSTANT_INIT gl::Context *g_LastContext(nullptr);
28 static_assert(std::is_trivially_destructible<decltype(g_LastContext)>::value,
29               "global last context is not trivially destructible");
30 
31 bool g_EGLValidationEnabled = true;
32 
33 // Called only on Android platform
ThreadCleanupCallback(void * ptr)34 [[maybe_unused]] void ThreadCleanupCallback(void *ptr)
35 {
36     egl::Thread *thread = static_cast<egl::Thread *>(ptr);
37     ASSERT(thread);
38     ANGLE_SCOPED_GLOBAL_EGL_AND_EGL_SYNC_LOCK();
39     // ReleaseThread() and makeCurrent() inside will perform:
40     // - destroy Context if it was already marked for destruction;
41     // - invalidate Context if Display was already terminated by app;
42     // - perform Display termination when no active threads (and current Contexts);
43     // - release any invalid objects in case if Display was not terminated.
44     (void)ReleaseThread(thread);
45 }
46 
AllocateCurrentThread()47 Thread *AllocateCurrentThread()
48 {
49     Thread *thread;
50     {
51         // Global thread intentionally leaked.
52         // Display TLS data is also intentionally leaked.
53         ANGLE_SCOPED_DISABLE_LSAN();
54         thread = new Thread();
55 #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
56         SetCurrentThreadTLS(thread);
57 #else
58         gCurrentThread = thread;
59 #endif
60 
61         Display::InitTLS();
62     }
63 
64     // Initialize current-context TLS slot
65     gl::SetCurrentValidContext(nullptr);
66 
67 #if defined(ANGLE_PLATFORM_ANDROID)
68     static pthread_once_t keyOnce                 = PTHREAD_ONCE_INIT;
69     static angle::TLSIndex gThreadCleanupTLSIndex = TLS_INVALID_INDEX;
70 
71     // Create thread cleanup TLS slot
72     auto CreateThreadCleanupTLSIndex = []() {
73         gThreadCleanupTLSIndex = angle::CreateTLSIndex(ThreadCleanupCallback);
74     };
75     pthread_once(&keyOnce, CreateThreadCleanupTLSIndex);
76     ASSERT(gThreadCleanupTLSIndex != TLS_INVALID_INDEX);
77 
78     // Initialize thread cleanup TLS slot
79     angle::SetTLSValue(gThreadCleanupTLSIndex, thread);
80 #endif  // ANGLE_PLATFORM_ANDROID
81 
82     ASSERT(thread);
83     return thread;
84 }
85 
86 }  // anonymous namespace
87 
88 #if defined(ANGLE_PLATFORM_APPLE)
89 // TODO(angleproject:6479): Due to a bug in Apple's dyld loader, `thread_local` will cause
90 // excessive memory use. Temporarily avoid it by using pthread's thread
91 // local storage instead.
92 // https://bugs.webkit.org/show_bug.cgi?id=228240
93 
GetCurrentThreadTLSIndex()94 static angle::TLSIndex GetCurrentThreadTLSIndex()
95 {
96     static angle::TLSIndex CurrentThreadIndex = TLS_INVALID_INDEX;
97     static dispatch_once_t once;
98     dispatch_once(&once, ^{
99       ASSERT(CurrentThreadIndex == TLS_INVALID_INDEX);
100       CurrentThreadIndex = angle::CreateTLSIndex(nullptr);
101     });
102     return CurrentThreadIndex;
103 }
GetCurrentThreadTLS()104 Thread *GetCurrentThreadTLS()
105 {
106     angle::TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
107     ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
108     return static_cast<Thread *>(angle::GetTLSValue(CurrentThreadIndex));
109 }
SetCurrentThreadTLS(Thread * thread)110 void SetCurrentThreadTLS(Thread *thread)
111 {
112     angle::TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
113     ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
114     angle::SetTLSValue(CurrentThreadIndex, thread);
115 }
116 #elif defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
117 static thread_local Thread *gCurrentThread = nullptr;
GetCurrentThreadTLS()118 Thread *GetCurrentThreadTLS()
119 {
120     return gCurrentThread;
121 }
SetCurrentThreadTLS(Thread * thread)122 void SetCurrentThreadTLS(Thread *thread)
123 {
124     gCurrentThread = thread;
125 }
126 #else
127 thread_local Thread *gCurrentThread = nullptr;
128 #endif
129 
GetGlobalLastContext()130 gl::Context *GetGlobalLastContext()
131 {
132     return g_LastContext;
133 }
134 
SetGlobalLastContext(gl::Context * context)135 void SetGlobalLastContext(gl::Context *context)
136 {
137     g_LastContext = context;
138 }
139 
140 // This function causes an MSAN false positive, which is muted. See https://crbug.com/1211047
141 // It also causes a flaky false positive in TSAN. http://crbug.com/1223970
GetCurrentThread()142 ANGLE_NO_SANITIZE_MEMORY ANGLE_NO_SANITIZE_THREAD Thread *GetCurrentThread()
143 {
144 #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
145     Thread *current = GetCurrentThreadTLS();
146 #else
147     Thread *current = gCurrentThread;
148 #endif
149     return (current ? current : AllocateCurrentThread());
150 }
151 
SetContextCurrent(Thread * thread,gl::Context * context)152 void SetContextCurrent(Thread *thread, gl::Context *context)
153 {
154 #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
155     Thread *currentThread = GetCurrentThreadTLS();
156 #else
157     Thread *currentThread = gCurrentThread;
158 #endif
159     ASSERT(currentThread);
160     currentThread->setCurrent(context);
161 
162     gl::SetCurrentValidContext(context);
163 
164 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
165     DirtyContextIfNeeded(context);
166 #endif
167 }
168 
ScopedSyncCurrentContextFromThread(egl::Thread * thread)169 ScopedSyncCurrentContextFromThread::ScopedSyncCurrentContextFromThread(egl::Thread *thread)
170     : mThread(thread)
171 {
172     ASSERT(mThread);
173 }
174 
~ScopedSyncCurrentContextFromThread()175 ScopedSyncCurrentContextFromThread::~ScopedSyncCurrentContextFromThread()
176 {
177     SetContextCurrent(mThread, mThread->getContext());
178 }
179 
SetEGLValidationEnabled(bool enabled)180 void SetEGLValidationEnabled(bool enabled)
181 {
182     g_EGLValidationEnabled = enabled;
183 }
184 
IsEGLValidationEnabled()185 bool IsEGLValidationEnabled()
186 {
187     return g_EGLValidationEnabled;
188 }
189 
190 }  // namespace egl
191 
192 namespace gl
193 {
GenerateContextLostErrorOnContext(Context * context)194 void GenerateContextLostErrorOnContext(Context *context)
195 {
196     if (context && context->isContextLost())
197     {
198         context->getMutableErrorSetForValidation()->validationError(
199             angle::EntryPoint::Invalid, GL_CONTEXT_LOST, err::kContextLost);
200     }
201 }
202 
GenerateContextLostErrorOnCurrentGlobalContext()203 void GenerateContextLostErrorOnCurrentGlobalContext()
204 {
205     // If the client starts issuing GL calls before ANGLE has had a chance to initialize,
206     // GenerateContextLostErrorOnCurrentGlobalContext can be called before AllocateCurrentThread has
207     // had a chance to run. Calling GetCurrentThread() ensures that TLS thread state is set up.
208     egl::GetCurrentThread();
209 
210     GenerateContextLostErrorOnContext(GetGlobalContext());
211 }
212 }  // namespace gl
213 
214 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
215 namespace egl
216 {
217 
218 namespace
219 {
220 
DeallocateCurrentThread()221 void DeallocateCurrentThread()
222 {
223     SafeDelete(gCurrentThread);
224 }
225 
InitializeProcess()226 bool InitializeProcess()
227 {
228     EnsureDebugAllocated();
229     AllocateGlobalMutex();
230     return AllocateCurrentThread() != nullptr;
231 }
232 
TerminateProcess()233 void TerminateProcess()
234 {
235     DeallocateDebug();
236     DeallocateGlobalMutex();
237     DeallocateCurrentThread();
238 }
239 
240 }  // anonymous namespace
241 
242 }  // namespace egl
243 
244 namespace
245 {
246 // The following WaitForDebugger code is based on SwiftShader. See:
247 // https://cs.chromium.org/chromium/src/third_party/swiftshader/src/Vulkan/main.cpp
248 #    if defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
DebuggerWaitDialogProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)249 INT_PTR CALLBACK DebuggerWaitDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
250 {
251     RECT rect;
252 
253     switch (uMsg)
254     {
255         case WM_INITDIALOG:
256             ::GetWindowRect(GetDesktopWindow(), &rect);
257             ::SetWindowPos(hwnd, HWND_TOP, rect.right / 2, rect.bottom / 2, 0, 0, SWP_NOSIZE);
258             ::SetTimer(hwnd, 1, 100, NULL);
259             return TRUE;
260         case WM_COMMAND:
261             if (LOWORD(wParam) == IDCANCEL)
262             {
263                 ::EndDialog(hwnd, 0);
264             }
265             break;
266         case WM_TIMER:
267             if (angle::IsDebuggerAttached())
268             {
269                 ::EndDialog(hwnd, 0);
270             }
271     }
272 
273     return FALSE;
274 }
275 
WaitForDebugger(HINSTANCE instance)276 void WaitForDebugger(HINSTANCE instance)
277 {
278     if (angle::IsDebuggerAttached())
279         return;
280 
281     HRSRC dialog = ::FindResourceA(instance, MAKEINTRESOURCEA(IDD_DIALOG1), MAKEINTRESOURCEA(5));
282     if (!dialog)
283     {
284         printf("Error finding wait for debugger dialog. Error %lu.\n", ::GetLastError());
285         return;
286     }
287 
288     DLGTEMPLATE *dialogTemplate = reinterpret_cast<DLGTEMPLATE *>(::LoadResource(instance, dialog));
289     ::DialogBoxIndirectA(instance, dialogTemplate, NULL, DebuggerWaitDialogProc);
290 }
291 #    else
292 void WaitForDebugger(HINSTANCE instance) {}
293 #    endif  // defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
294 }  // namespace
295 
DllMain(HINSTANCE instance,DWORD reason,LPVOID)296 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
297 {
298     switch (reason)
299     {
300         case DLL_PROCESS_ATTACH:
301             if (angle::GetBoolEnvironmentVar("ANGLE_WAIT_FOR_DEBUGGER"))
302             {
303                 WaitForDebugger(instance);
304             }
305             return static_cast<BOOL>(egl::InitializeProcess());
306 
307         case DLL_THREAD_ATTACH:
308             return static_cast<BOOL>(egl::AllocateCurrentThread() != nullptr);
309 
310         case DLL_THREAD_DETACH:
311             egl::DeallocateCurrentThread();
312             break;
313 
314         case DLL_PROCESS_DETACH:
315             egl::TerminateProcess();
316             break;
317     }
318 
319     return TRUE;
320 }
321 #endif  // defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
322