blob: 5bc23a305c187328584650e6aa72ae2c19535f96 [file] [log] [blame]
David Ghandeharib1536522017-05-24 00:01:15 -07001//
Kaido Kert612c0202020-01-22 10:28:42 -08002// Copyright 2014 The ANGLE Project Authors. All rights reserved.
David Ghandeharib1536522017-05-24 00:01:15 -07003// 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 Top200ce4b2018-01-29 13:43:50 -080011#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 Ghandeharib1536522017-05-24 00:01:15 -070024#include "common/debug.h"
25#include "common/platform.h"
Kaido Kert612c0202020-01-22 10:28:42 -080026#include "common/system_utils.h"
David Ghandeharib1536522017-05-24 00:01:15 -070027#include "common/tls.h"
Kaido Kert612c0202020-01-22 10:28:42 -080028#include "libGLESv2/resource.h"
David Ghandeharib1536522017-05-24 00:01:15 -070029
30namespace gl
31{
Kaido Kert612c0202020-01-22 10:28:42 -080032// 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.
43Context *gSingleThreadedContext = nullptr;
44bool gIsMultiThreadedContext = false;
David Ghandeharib1536522017-05-24 00:01:15 -070045} // namespace gl
46
47namespace egl
48{
David Ghandeharib1536522017-05-24 00:01:15 -070049namespace
50{
David Ghandeharib1536522017-05-24 00:01:15 -070051static TLSIndex threadTLS = TLS_INVALID_INDEX;
Kaido Kert612c0202020-01-22 10:28:42 -080052Debug *g_Debug = nullptr;
53
54ANGLE_REQUIRE_CONSTANT_INIT std::atomic<std::mutex *> g_Mutex(nullptr);
55static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value,
56 "global mutex is not trivially destructible");
David Ghandeharib1536522017-05-24 00:01:15 -070057
58Thread *AllocateCurrentThread()
59{
60 ASSERT(threadTLS != TLS_INVALID_INDEX);
61 if (threadTLS == TLS_INVALID_INDEX)
62 {
63 return nullptr;
64 }
65
Andrew Top200ce4b2018-01-29 13:43:50 -080066#if HAS_LEAK_SANITIZER
67 __lsan_disable();
68#endif // HAS_LEAK_SANITIZER
David Ghandeharib1536522017-05-24 00:01:15 -070069 Thread *thread = new Thread();
Andrew Top200ce4b2018-01-29 13:43:50 -080070#if HAS_LEAK_SANITIZER
71 __lsan_enable();
72#endif // HAS_LEAK_SANITIZER
David Ghandeharib1536522017-05-24 00:01:15 -070073 if (!SetTLSValue(threadTLS, thread))
74 {
75 ERR() << "Could not set thread local storage.";
76 return nullptr;
77 }
78
79 return thread;
80}
81
Kaido Kert612c0202020-01-22 10:28:42 -080082void 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
91void 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 Ghandeharib1536522017-05-24 00:01:15 -0700104} // anonymous namespace
105
Kaido Kert612c0202020-01-22 10:28:42 -0800106std::mutex &GetGlobalMutex()
107{
108 AllocateMutex();
109 return *g_Mutex;
110}
111
David Ghandeharib1536522017-05-24 00:01:15 -0700112Thread *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 Kert612c0202020-01-22 10:28:42 -0800127Debug *GetDebug()
128{
129 AllocateDebug();
130 return g_Debug;
131}
132
133void 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 Ghandeharib1536522017-05-24 00:01:15 -0700154} // namespace egl
155
Andrew Topd84d4942017-08-22 17:31:32 -0700156#if defined(ANGLE_PLATFORM_WINDOWS) && defined(LIBGLESV2_DLL)
David Ghandeharib1536522017-05-24 00:01:15 -0700157namespace egl
158{
159
160namespace
161{
162
163bool DeallocateCurrentThread()
164{
165 Thread *thread = static_cast<Thread *>(GetTLSValue(threadTLS));
166 SafeDelete(thread);
167 return SetTLSValue(threadTLS, nullptr);
168}
169
Kaido Kert612c0202020-01-22 10:28:42 -0800170void DeallocateDebug()
171{
172 SafeDelete(g_Debug);
173}
174
175void 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 Ghandeharib1536522017-05-24 00:01:15 -0700185bool InitializeProcess()
186{
Kaido Kert612c0202020-01-22 10:28:42 -0800187 ASSERT(g_Debug == nullptr);
188 AllocateDebug();
189
190 AllocateMutex();
191
David Ghandeharib1536522017-05-24 00:01:15 -0700192 threadTLS = CreateTLSIndex();
193 if (threadTLS == TLS_INVALID_INDEX)
194 {
195 return false;
196 }
197
198 return AllocateCurrentThread() != nullptr;
199}
200
201bool TerminateProcess()
202{
Kaido Kert612c0202020-01-22 10:28:42 -0800203 DeallocateDebug();
204
205 DeallocateMutex();
206
David Ghandeharib1536522017-05-24 00:01:15 -0700207 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 Kert612c0202020-01-22 10:28:42 -0800230namespace
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)
235INT_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
262void 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
278void WaitForDebugger(HINSTANCE instance) {}
279# endif // defined(ANGLE_ENABLE_ASSERTS)
280} // namespace
281
282extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
David Ghandeharib1536522017-05-24 00:01:15 -0700283{
284 switch (reason)
285 {
286 case DLL_PROCESS_ATTACH:
Kaido Kert612c0202020-01-22 10:28:42 -0800287 if (angle::GetEnvironmentVar("ANGLE_WAIT_FOR_DEBUGGER") == "1")
288 {
289 WaitForDebugger(instance);
290 }
David Ghandeharib1536522017-05-24 00:01:15 -0700291 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 Topd84d4942017-08-22 17:31:32 -0700305#endif // defined(ANGLE_PLATFORM_WINDOWS) && defined(LIBGLESV2_DLL)