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 gl::Context *GetGlobalLastContext();
105 void SetGlobalLastContext(gl::Context *context);
106 Thread *GetCurrentThread();
107 Debug *GetDebug();
108
109 // Sync the current context from Thread to global state.
110 class ScopedSyncCurrentContextFromThread
111 {
112 public:
113 ScopedSyncCurrentContextFromThread(egl::Thread *thread);
114 ~ScopedSyncCurrentContextFromThread();
115
116 private:
117 egl::Thread *const mThread;
118 };
119
120 } // namespace egl
121
122 #define ANGLE_SCOPED_GLOBAL_LOCK() \
123 std::lock_guard<angle::GlobalMutex> globalMutexLock(egl::GetGlobalMutex())
124
125 namespace gl
126 {
GetGlobalContext()127 ANGLE_INLINE Context *GetGlobalContext()
128 {
129 #if defined(ANGLE_PLATFORM_ANDROID)
130 // TODO: Replace this branch with a compile time flag (http://anglebug.com/4764)
131 if (angle::gUseAndroidOpenGLTlsSlot)
132 {
133 return static_cast<gl::Context *>(ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot]);
134 }
135 #endif
136
137 #if defined(ANGLE_PLATFORM_APPLE)
138 egl::Thread *currentThread = egl::GetCurrentThreadTLS();
139 #else
140 egl::Thread *currentThread = egl::gCurrentThread;
141 #endif
142 ASSERT(currentThread);
143 return currentThread->getContext();
144 }
145
GetValidGlobalContext()146 ANGLE_INLINE Context *GetValidGlobalContext()
147 {
148 #if defined(ANGLE_PLATFORM_ANDROID)
149 // TODO: Replace this branch with a compile time flag (http://anglebug.com/4764)
150 if (angle::gUseAndroidOpenGLTlsSlot)
151 {
152 Context *context =
153 static_cast<gl::Context *>(ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot]);
154 if (context && !context->isContextLost())
155 {
156 return context;
157 }
158 }
159 #endif
160
161 #if defined(ANGLE_PLATFORM_APPLE)
162 return GetCurrentValidContextTLS();
163 #else
164 return gCurrentValidContext;
165 #endif
166 }
167
168 // Generate a context lost error on the context if it is non-null and lost.
169 void GenerateContextLostErrorOnContext(Context *context);
170 void GenerateContextLostErrorOnCurrentGlobalContext();
171
172 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
173 // TODO(b/177574181): This should be handled in a backend-specific way.
174 // if previous context different from current context, dirty all state
DirtyContextIfNeeded(Context * context)175 static ANGLE_INLINE void DirtyContextIfNeeded(Context *context)
176 {
177 if (context && context != egl::GetGlobalLastContext())
178 {
179 context->dirtyAllState();
180 SetGlobalLastContext(context);
181 }
182 }
183
184 #endif
185
GetContextLock(Context * context)186 ANGLE_INLINE std::unique_lock<angle::GlobalMutex> GetContextLock(Context *context)
187 {
188 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
189 auto lock = std::unique_lock<angle::GlobalMutex>(egl::GetGlobalMutex());
190
191 DirtyContextIfNeeded(context);
192 return lock;
193 #else
194 return context->isShared() ? std::unique_lock<angle::GlobalMutex>(egl::GetGlobalMutex())
195 : std::unique_lock<angle::GlobalMutex>();
196 #endif
197 }
198
199 } // namespace gl
200
201 #endif // LIBGLESV2_GLOBALSTATE_H_
202