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
20 namespace egl
21 {
22 namespace
23 {
24 ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_Mutex(nullptr);
25 static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value,
26 "global mutex is not trivially destructible");
27
28 ANGLE_REQUIRE_CONSTANT_INIT gl::Context *g_LastContext(nullptr);
29 static_assert(std::is_trivially_destructible<decltype(g_LastContext)>::value,
30 "global last context is not trivially destructible");
31
SetContextToAndroidOpenGLTLSSlot(gl::Context * value)32 void SetContextToAndroidOpenGLTLSSlot(gl::Context *value)
33 {
34 #if defined(ANGLE_PLATFORM_ANDROID)
35 if (angle::gUseAndroidOpenGLTlsSlot)
36 {
37 ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot] = static_cast<void *>(value);
38 }
39 #endif
40 }
41
AllocateCurrentThread()42 Thread *AllocateCurrentThread()
43 {
44 {
45 // Global thread intentionally leaked
46 ANGLE_SCOPED_DISABLE_LSAN();
47 gCurrentThread = new Thread();
48 }
49
50 // Initialize fast TLS slot
51 SetContextToAndroidOpenGLTLSSlot(nullptr);
52 gl::gCurrentValidContext = nullptr;
53
54 return gCurrentThread;
55 }
56
AllocateMutex()57 void AllocateMutex()
58 {
59 if (g_Mutex == nullptr)
60 {
61 std::unique_ptr<angle::GlobalMutex> newMutex(new angle::GlobalMutex());
62 angle::GlobalMutex *expected = nullptr;
63 if (g_Mutex.compare_exchange_strong(expected, newMutex.get()))
64 {
65 newMutex.release();
66 }
67 }
68 }
69
70 } // anonymous namespace
71
72 thread_local Thread *gCurrentThread = nullptr;
73
GetGlobalMutex()74 angle::GlobalMutex &GetGlobalMutex()
75 {
76 AllocateMutex();
77 return *g_Mutex;
78 }
79
GetGlobalLastContext()80 gl::Context *GetGlobalLastContext()
81 {
82 return g_LastContext;
83 }
84
SetGlobalLastContext(gl::Context * context)85 void SetGlobalLastContext(gl::Context *context)
86 {
87 g_LastContext = context;
88 }
89
90 // This function causes an MSAN false positive, which is muted. See https://crbug.com/1211047
91 // It also causes a flaky false positive in TSAN. http://crbug.com/1223970
GetCurrentThread()92 ANGLE_NO_SANITIZE_MEMORY ANGLE_NO_SANITIZE_THREAD Thread *GetCurrentThread()
93 {
94 Thread *current = gCurrentThread;
95 return (current ? current : AllocateCurrentThread());
96 }
97
SetContextCurrent(Thread * thread,gl::Context * context)98 void SetContextCurrent(Thread *thread, gl::Context *context)
99 {
100 ASSERT(gCurrentThread == thread);
101 SetContextToAndroidOpenGLTLSSlot(context);
102 gl::gCurrentValidContext = context;
103 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
104 DirtyContextIfNeeded(context);
105 #endif
106 }
107
ScopedSyncCurrentContextFromThread(egl::Thread * thread)108 ScopedSyncCurrentContextFromThread::ScopedSyncCurrentContextFromThread(egl::Thread *thread)
109 : mThread(thread)
110 {
111 ASSERT(mThread);
112 }
113
~ScopedSyncCurrentContextFromThread()114 ScopedSyncCurrentContextFromThread::~ScopedSyncCurrentContextFromThread()
115 {
116 SetContextCurrent(mThread, mThread->getContext());
117 }
118
119 } // namespace egl
120
121 namespace gl
122 {
GenerateContextLostErrorOnContext(Context * context)123 void GenerateContextLostErrorOnContext(Context *context)
124 {
125 if (context && context->isContextLost())
126 {
127 context->validationError(GL_CONTEXT_LOST, err::kContextLost);
128 }
129 }
130
GenerateContextLostErrorOnCurrentGlobalContext()131 void GenerateContextLostErrorOnCurrentGlobalContext()
132 {
133 GenerateContextLostErrorOnContext(GetGlobalContext());
134 }
135 } // namespace gl
136
137 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
138 namespace egl
139 {
140
141 namespace
142 {
DeallocateCurrentThread()143 void DeallocateCurrentThread()
144 {
145 SafeDelete(gCurrentThread);
146 }
147
DeallocateMutex()148 void DeallocateMutex()
149 {
150 angle::GlobalMutex *mutex = g_Mutex.exchange(nullptr);
151 {
152 // Wait for the mutex to become released by other threads before deleting.
153 std::lock_guard<angle::GlobalMutex> lock(*mutex);
154 }
155 SafeDelete(mutex);
156 }
157
InitializeProcess()158 bool InitializeProcess()
159 {
160 EnsureDebugAllocated();
161 AllocateMutex();
162 return AllocateCurrentThread() != nullptr;
163 }
164
TerminateProcess()165 void TerminateProcess()
166 {
167 DeallocateDebug();
168 DeallocateMutex();
169 DeallocateCurrentThread();
170 }
171
172 } // anonymous namespace
173
174 } // namespace egl
175
176 namespace
177 {
178 // The following WaitForDebugger code is based on SwiftShader. See:
179 // https://cs.chromium.org/chromium/src/third_party/swiftshader/src/Vulkan/main.cpp
180 # if defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
DebuggerWaitDialogProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)181 INT_PTR CALLBACK DebuggerWaitDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
182 {
183 RECT rect;
184
185 switch (uMsg)
186 {
187 case WM_INITDIALOG:
188 ::GetWindowRect(GetDesktopWindow(), &rect);
189 ::SetWindowPos(hwnd, HWND_TOP, rect.right / 2, rect.bottom / 2, 0, 0, SWP_NOSIZE);
190 ::SetTimer(hwnd, 1, 100, NULL);
191 return TRUE;
192 case WM_COMMAND:
193 if (LOWORD(wParam) == IDCANCEL)
194 {
195 ::EndDialog(hwnd, 0);
196 }
197 break;
198 case WM_TIMER:
199 if (angle::IsDebuggerAttached())
200 {
201 ::EndDialog(hwnd, 0);
202 }
203 }
204
205 return FALSE;
206 }
207
WaitForDebugger(HINSTANCE instance)208 void WaitForDebugger(HINSTANCE instance)
209 {
210 if (angle::IsDebuggerAttached())
211 return;
212
213 HRSRC dialog = ::FindResourceA(instance, MAKEINTRESOURCEA(IDD_DIALOG1), MAKEINTRESOURCEA(5));
214 if (!dialog)
215 {
216 printf("Error finding wait for debugger dialog. Error %lu.\n", ::GetLastError());
217 return;
218 }
219
220 DLGTEMPLATE *dialogTemplate = reinterpret_cast<DLGTEMPLATE *>(::LoadResource(instance, dialog));
221 ::DialogBoxIndirectA(instance, dialogTemplate, NULL, DebuggerWaitDialogProc);
222 }
223 # else
224 void WaitForDebugger(HINSTANCE instance) {}
225 # endif // defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
226 } // namespace
227
DllMain(HINSTANCE instance,DWORD reason,LPVOID)228 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
229 {
230 switch (reason)
231 {
232 case DLL_PROCESS_ATTACH:
233 if (angle::GetEnvironmentVar("ANGLE_WAIT_FOR_DEBUGGER") == "1")
234 {
235 WaitForDebugger(instance);
236 }
237 return static_cast<BOOL>(egl::InitializeProcess());
238
239 case DLL_THREAD_ATTACH:
240 return static_cast<BOOL>(egl::AllocateCurrentThread() != nullptr);
241
242 case DLL_THREAD_DETACH:
243 egl::DeallocateCurrentThread();
244 break;
245
246 case DLL_PROCESS_DETACH:
247 egl::TerminateProcess();
248 break;
249 }
250
251 return TRUE;
252 }
253 #endif // defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
254