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/Display.h"
15 #include "libANGLE/GlobalMutex.h"
16 #include "libANGLE/Thread.h"
17 #include "libANGLE/features.h"
18 #include "libANGLE/validationEGL.h"
19
20 #if defined(ANGLE_PLATFORM_APPLE) || (ANGLE_PLATFORM_ANDROID)
21 # include "common/tls.h"
22 #endif
23
24 #include <mutex>
25
26 namespace egl
27 {
28 class Debug;
29 class Thread;
30
31 #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
32 extern Thread *GetCurrentThreadTLS();
33 extern void SetCurrentThreadTLS(Thread *thread);
34 #else
35 extern thread_local Thread *gCurrentThread;
36 #endif
37
38 gl::Context *GetGlobalLastContext();
39 void SetGlobalLastContext(gl::Context *context);
40 Thread *GetCurrentThread();
41 Debug *GetDebug();
42
43 // Sync the current context from Thread to global state.
44 class [[nodiscard]] ScopedSyncCurrentContextFromThread
45 {
46 public:
47 ScopedSyncCurrentContextFromThread(egl::Thread *thread);
48 ~ScopedSyncCurrentContextFromThread();
49
50 private:
51 egl::Thread *const mThread;
52 };
53
54 // Tries to lock "ContextMutex" of the Context current to the "thread".
TryLockCurrentContext(Thread * thread)55 ANGLE_INLINE ScopedContextMutexLock TryLockCurrentContext(Thread *thread)
56 {
57 ASSERT(kIsSharedContextMutexEnabled);
58 gl::Context *context = thread->getContext();
59 return context != nullptr ? ScopedContextMutexLock(context->getContextMutex(), context)
60 : ScopedContextMutexLock();
61 }
62
63 // Tries to lock "ContextMutex" or "SharedContextMutex" of the Context with "contextID" if it is
64 // valid, in order to safely use the Context from the "thread".
65 // Note: this function may change mutex type to SharedContextMutex.
TryLockContextForThread(Thread * thread,Display * display,gl::ContextID contextID)66 ANGLE_INLINE ScopedContextMutexLock TryLockContextForThread(Thread *thread,
67 Display *display,
68 gl::ContextID contextID)
69 {
70 ASSERT(kIsSharedContextMutexEnabled);
71 gl::Context *context = GetContextIfValid(display, contextID);
72 return context != nullptr ? (context == thread->getContext()
73 ? ScopedContextMutexLock(context->getContextMutex(), context)
74 : context->lockAndActivateSharedContextMutex())
75 : ScopedContextMutexLock();
76 }
77
78 // Tries to lock "SharedContextMutex" of the Context with "contextID" if it is valid.
79 // Note: this function will change mutex type to SharedContextMutex.
TryLockAndActivateSharedContextMutex(Display * display,gl::ContextID contextID)80 ANGLE_INLINE ScopedContextMutexLock TryLockAndActivateSharedContextMutex(Display *display,
81 gl::ContextID contextID)
82 {
83 ASSERT(kIsSharedContextMutexEnabled);
84 gl::Context *context = GetContextIfValid(display, contextID);
85 return context != nullptr ? context->lockAndActivateSharedContextMutex()
86 : ScopedContextMutexLock();
87 }
88
89 // Locks "SharedContextMutex" of the "context" and then tries to merge it with the
90 // "SharedContextMutex" of the Image with "imageID" if it is valid.
91 // Note: this function may change mutex type to SharedContextMutex.
LockAndTryMergeSharedContextMutexes(gl::Context * context,ImageID imageID)92 ANGLE_INLINE ScopedContextMutexLock LockAndTryMergeSharedContextMutexes(gl::Context *context,
93 ImageID imageID)
94 {
95 ASSERT(kIsSharedContextMutexEnabled);
96 ASSERT(context->getDisplay() != nullptr);
97 const Image *image = context->getDisplay()->getImage(imageID);
98 if (image != nullptr)
99 {
100 ContextMutex *imageMutex = image->getSharedContextMutex();
101 if (imageMutex != nullptr)
102 {
103 ScopedContextMutexLock lock = context->lockAndActivateSharedContextMutex();
104 context->mergeSharedContextMutexes(imageMutex);
105 return lock;
106 }
107 }
108 // Do not activate "SharedContextMutex" if Image is not valid or does not have the mutex.
109 return ScopedContextMutexLock(context->getContextMutex(), context);
110 }
111
112 #if !defined(ANGLE_ENABLE_SHARED_CONTEXT_MUTEX)
113 # define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...)
114 #else
115 # define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...) \
116 egl::ScopedContextMutexLock shareContextLock = GetContextLock_##EP(THREAD, ##__VA_ARGS__)
117 #endif
118
119 } // namespace egl
120
121 #define ANGLE_SCOPED_GLOBAL_LOCK() egl::ScopedGlobalMutexLock globalMutexLock
122
123 namespace gl
124 {
GetGlobalContext()125 ANGLE_INLINE Context *GetGlobalContext()
126 {
127 #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
128 egl::Thread *currentThread = egl::GetCurrentThreadTLS();
129 #else
130 egl::Thread *currentThread = egl::gCurrentThread;
131 #endif
132 ASSERT(currentThread);
133 return currentThread->getContext();
134 }
135
GetValidGlobalContext()136 ANGLE_INLINE Context *GetValidGlobalContext()
137 {
138 #if defined(ANGLE_USE_ANDROID_TLS_SLOT)
139 // TODO: Replace this branch with a compile time flag (http://anglebug.com/4764)
140 if (angle::gUseAndroidOpenGLTlsSlot)
141 {
142 return static_cast<gl::Context *>(ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot]);
143 }
144 #endif
145
146 #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
147 return GetCurrentValidContextTLS();
148 #else
149 return gCurrentValidContext;
150 #endif
151 }
152
153 // Generate a context lost error on the context if it is non-null and lost.
154 void GenerateContextLostErrorOnContext(Context *context);
155 void GenerateContextLostErrorOnCurrentGlobalContext();
156
157 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
158 // TODO(b/177574181): This should be handled in a backend-specific way.
159 // if previous context different from current context, dirty all state
DirtyContextIfNeeded(Context * context)160 static ANGLE_INLINE void DirtyContextIfNeeded(Context *context)
161 {
162 if (context && context != egl::GetGlobalLastContext())
163 {
164 context->dirtyAllState();
165 SetGlobalLastContext(context);
166 }
167 }
168
169 #endif
170
171 #if !defined(ANGLE_ENABLE_SHARE_CONTEXT_LOCK)
172 # define SCOPED_SHARE_CONTEXT_LOCK(context)
173 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
174 #else
175 # if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
176 # define SCOPED_SHARE_CONTEXT_LOCK(context) \
177 egl::ScopedGlobalMutexLock shareContextLock; \
178 DirtyContextIfNeeded(context)
179 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
180 SCOPED_SHARE_CONTEXT_LOCK(context)
181 # elif !defined(ANGLE_ENABLE_SHARED_CONTEXT_MUTEX)
182 # define SCOPED_SHARE_CONTEXT_LOCK(context) \
183 egl::ScopedOptionalGlobalMutexLock shareContextLock(context->isShared())
184 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
185 # else
186 # define SCOPED_SHARE_CONTEXT_LOCK(context) \
187 egl::ScopedContextMutexLock shareContextLock(context->getContextMutex(), context)
188 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
189 ANGLE_SCOPED_GLOBAL_LOCK(); \
190 egl::ScopedContextMutexLock shareContextLock = \
191 egl::LockAndTryMergeSharedContextMutexes(context, imageID)
192 # endif
193 #endif
194
195 } // namespace gl
196
197 #endif // LIBGLESV2_GLOBALSTATE_H_
198