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.h : Defines functions for querying the thread-local GL and EGL state.
8
9 #ifndef LIBGLESV2_GLOBALSTATE_H_
10 #define LIBGLESV2_GLOBALSTATE_H_
11
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Debug.h"
14 #include "libANGLE/Thread.h"
15 #include "libANGLE/features.h"
16
17 #if defined(ANGLE_PLATFORM_APPLE) || (ANGLE_PLATFORM_ANDROID)
18 # include "common/tls.h"
19 #endif
20
21 #include <mutex>
22
23 namespace angle
24 {
25 using GlobalMutex = std::recursive_mutex;
26
27 // - TLS_SLOT_OPENGL and TLS_SLOT_OPENGL_API: These two aren't used by bionic
28 // itself, but allow the graphics code to access TLS directly rather than
29 // using the pthread API.
30 //
31 // Choose the TLS_SLOT_OPENGL TLS slot with the value that matches value in the header file in
32 // bionic(tls_defines.h)
33 constexpr size_t kAndroidOpenGLTlsSlot = 3;
34
35 #if defined(ANGLE_PLATFORM_ANDROID)
36
37 // The following ASM variant provides a much more performant store/retrieve interface
38 // compared to those provided by the pthread library. These have been derived from code
39 // in the bionic module of Android ->
40 // https://cs.android.com/android/platform/superproject/+/master:bionic/libc/platform/bionic/tls.h;l=30
41
42 # if defined(__aarch64__)
43 # define ANGLE_ANDROID_GET_GL_TLS() \
44 ({ \
45 void **__val; \
46 __asm__("mrs %0, tpidr_el0" : "=r"(__val)); \
47 __val; \
48 })
49 # elif defined(__arm__)
50 # define ANGLE_ANDROID_GET_GL_TLS() \
51 ({ \
52 void **__val; \
53 __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); \
54 __val; \
55 })
56 # elif defined(__mips__)
57 // On mips32r1, this goes via a kernel illegal instruction trap that's
58 // optimized for v1
59 # define ANGLE_ANDROID_GET_GL_TLS() \
60 ({ \
61 register void **__val asm("v1"); \
62 __asm__( \
63 ".set push\n" \
64 ".set mips32r2\n" \
65 "rdhwr %0,$29\n" \
66 ".set pop\n" \
67 : "=r"(__val)); \
68 __val; \
69 })
70 # elif defined(__i386__)
71 # define ANGLE_ANDROID_GET_GL_TLS() \
72 ({ \
73 void **__val; \
74 __asm__("movl %%gs:0, %0" : "=r"(__val)); \
75 __val; \
76 })
77 # elif defined(__x86_64__)
78 # define ANGLE_ANDROID_GET_GL_TLS() \
79 ({ \
80 void **__val; \
81 __asm__("mov %%fs:0, %0" : "=r"(__val)); \
82 __val; \
83 })
84 # else
85 # error unsupported architecture
86 # endif
87
88 #endif // ANGLE_PLATFORM_ANDROID
89 } // namespace angle
90
91 namespace egl
92 {
93 class Debug;
94 class Thread;
95
96 #if defined(ANGLE_PLATFORM_APPLE)
97 extern Thread *GetCurrentThreadTLS();
98 extern void SetCurrentThreadTLS(Thread *thread);
99 #else
100 extern thread_local Thread *gCurrentThread;
101 #endif
102
103 angle::GlobalMutex &GetGlobalMutex();
104 angle::GlobalMutex &GetGlobalSurfaceMutex();
105 gl::Context *GetGlobalLastContext();
106 void SetGlobalLastContext(gl::Context *context);
107 Thread *GetCurrentThread();
108 Debug *GetDebug();
109
110 // Sync the current context from Thread to global state.
111 class ANGLE_NO_DISCARD ScopedSyncCurrentContextFromThread
112 {
113 public:
114 ScopedSyncCurrentContextFromThread(egl::Thread *thread);
115 ~ScopedSyncCurrentContextFromThread();
116
117 private:
118 egl::Thread *const mThread;
119 };
120
121 } // namespace egl
122
123 #define ANGLE_GLOBAL_SURFACE_LOCK_VAR_NAME globalSurfaceMutexLock
124 #define ANGLE_SCOPED_GLOBAL_SURFACE_LOCK() \
125 std::lock_guard<angle::GlobalMutex> ANGLE_GLOBAL_SURFACE_LOCK_VAR_NAME( \
126 egl::GetGlobalSurfaceMutex())
127
128 #define ANGLE_GLOBAL_LOCK_VAR_NAME globalMutexLock
129 #define ANGLE_SCOPED_GLOBAL_LOCK() \
130 std::lock_guard<angle::GlobalMutex> ANGLE_GLOBAL_LOCK_VAR_NAME(egl::GetGlobalMutex())
131
132 namespace gl
133 {
GetGlobalContext()134 ANGLE_INLINE Context *GetGlobalContext()
135 {
136 #if defined(ANGLE_PLATFORM_ANDROID)
137 // TODO: Replace this branch with a compile time flag (http://anglebug.com/4764)
138 if (angle::gUseAndroidOpenGLTlsSlot)
139 {
140 return static_cast<gl::Context *>(ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot]);
141 }
142 #endif
143
144 #if defined(ANGLE_PLATFORM_APPLE)
145 egl::Thread *currentThread = egl::GetCurrentThreadTLS();
146 #else
147 egl::Thread *currentThread = egl::gCurrentThread;
148 #endif
149 ASSERT(currentThread);
150 return currentThread->getContext();
151 }
152
GetValidGlobalContext()153 ANGLE_INLINE Context *GetValidGlobalContext()
154 {
155 #if defined(ANGLE_PLATFORM_ANDROID)
156 // TODO: Replace this branch with a compile time flag (http://anglebug.com/4764)
157 if (angle::gUseAndroidOpenGLTlsSlot)
158 {
159 Context *context =
160 static_cast<gl::Context *>(ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot]);
161 if (context && !context->isContextLost())
162 {
163 return context;
164 }
165 }
166 #endif
167
168 #if defined(ANGLE_PLATFORM_APPLE)
169 return GetCurrentValidContextTLS();
170 #else
171 return gCurrentValidContext;
172 #endif
173 }
174
175 // Generate a context lost error on the context if it is non-null and lost.
176 void GenerateContextLostErrorOnContext(Context *context);
177 void GenerateContextLostErrorOnCurrentGlobalContext();
178
179 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
180 // TODO(b/177574181): This should be handled in a backend-specific way.
181 // if previous context different from current context, dirty all state
DirtyContextIfNeeded(Context * context)182 static ANGLE_INLINE void DirtyContextIfNeeded(Context *context)
183 {
184 if (context && context != egl::GetGlobalLastContext())
185 {
186 context->dirtyAllState();
187 SetGlobalLastContext(context);
188 }
189 }
190
191 #endif
192
GetContextLock(Context * context)193 ANGLE_INLINE std::unique_lock<angle::GlobalMutex> GetContextLock(Context *context)
194 {
195 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
196 auto lock = std::unique_lock<angle::GlobalMutex>(egl::GetGlobalMutex());
197
198 DirtyContextIfNeeded(context);
199 return lock;
200 #else
201 return context->isShared() ? std::unique_lock<angle::GlobalMutex>(egl::GetGlobalMutex())
202 : std::unique_lock<angle::GlobalMutex>();
203 #endif
204 }
205
206 } // namespace gl
207
208 #endif // LIBGLESV2_GLOBALSTATE_H_
209