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