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) || defined(ANGLE_USE_ANDROID_TLS_SLOT)
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 void SetEGLValidationEnabled(bool enabled);
44 bool IsEGLValidationEnabled();
45
46 // Sync the current context from Thread to global state.
47 class [[nodiscard]] ScopedSyncCurrentContextFromThread
48 {
49 public:
50 ScopedSyncCurrentContextFromThread(egl::Thread *thread);
51 ~ScopedSyncCurrentContextFromThread();
52
53 private:
54 egl::Thread *const mThread;
55 };
56
57 // Tries to lock "ContextMutex" of the Context current to the "thread".
TryLockCurrentContext(Thread * thread)58 ANGLE_INLINE ScopedContextMutexLock TryLockCurrentContext(Thread *thread)
59 {
60 ASSERT(kIsContextMutexEnabled);
61 gl::Context *context = thread->getContext();
62 return context != nullptr ? ScopedContextMutexLock(context->getContextMutex())
63 : ScopedContextMutexLock();
64 }
65
66 // Tries to lock "ContextMutex" of the Context with "contextID" if it is valid.
TryLockContext(Display * display,gl::ContextID contextID)67 ANGLE_INLINE ScopedContextMutexLock TryLockContext(Display *display, gl::ContextID contextID)
68 {
69 ASSERT(kIsContextMutexEnabled);
70 gl::Context *context = GetContextIfValid(display, contextID);
71 return context != nullptr ? ScopedContextMutexLock(context->getContextMutex())
72 : ScopedContextMutexLock();
73 }
74
75 // Locks "ContextMutex" of the "context" and then tries to merge it with the "ContextMutex" of the
76 // Image with "imageID" if it is valid.
LockAndTryMergeContextMutexes(gl::Context * context,ImageID imageID)77 ANGLE_INLINE ScopedContextMutexLock LockAndTryMergeContextMutexes(gl::Context *context,
78 ImageID imageID)
79 {
80 ASSERT(kIsContextMutexEnabled);
81 ASSERT(context->getDisplay() != nullptr);
82 ScopedContextMutexLock lock(context->getContextMutex());
83 const Image *image = context->getDisplay()->getImage(imageID);
84 if (image != nullptr)
85 {
86 ContextMutex *imageMutex = image->getContextMutex();
87 if (imageMutex != nullptr)
88 {
89 ContextMutex::Merge(&context->getContextMutex(), imageMutex);
90 }
91 }
92 return lock;
93 }
94
95 #if !defined(ANGLE_ENABLE_CONTEXT_MUTEX)
96 # define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...)
97 #else
98 # define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...) \
99 egl::ScopedContextMutexLock shareContextLock = GetContextLock_##EP(THREAD, ##__VA_ARGS__)
100 #endif
101
102 } // namespace egl
103
104 #define ANGLE_SCOPED_GLOBAL_LOCK() egl::ScopedGlobalEGLMutexLock globalMutexLock
105 #if ANGLE_CAPTURE_ENABLED
106 # define ANGLE_SCOPED_GLOBAL_EGL_AND_EGL_SYNC_LOCK() \
107 egl::ScopedGlobalEGLMutexLock globalMutexLock
108 #else
109 # define ANGLE_SCOPED_GLOBAL_EGL_AND_EGL_SYNC_LOCK() \
110 egl::ScopedGlobalEGLMutexLock globalMutexLock; \
111 egl::ScopedGlobalEGLSyncObjectMutexLock globalEGLSyncObjectMutexLock
112 #endif
113
114 #if ANGLE_CAPTURE_ENABLED
115 # define ANGLE_SCOPED_GLOBAL_EGL_SYNC_LOCK() egl::ScopedGlobalEGLMutexLock globalMutexLock
116 #else
117 # define ANGLE_SCOPED_GLOBAL_EGL_SYNC_LOCK() \
118 egl::ScopedGlobalEGLSyncObjectMutexLock globalEGLSyncObjectMutexLock
119 #endif
120
121 namespace gl
122 {
GetGlobalContext()123 ANGLE_INLINE Context *GetGlobalContext()
124 {
125 #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
126 egl::Thread *currentThread = egl::GetCurrentThreadTLS();
127 #else
128 egl::Thread *currentThread = egl::gCurrentThread;
129 #endif
130 ASSERT(currentThread);
131 return currentThread->getContext();
132 }
133
GetValidGlobalContext()134 ANGLE_INLINE Context *GetValidGlobalContext()
135 {
136 #if defined(ANGLE_USE_ANDROID_TLS_SLOT)
137 // TODO: Replace this branch with a compile time flag (http://anglebug.com/42263361)
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) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
145 return GetCurrentValidContextTLS();
146 #else
147 return gCurrentValidContext;
148 #endif
149 }
150
151 // Generate a context lost error on the context if it is non-null and lost.
152 void GenerateContextLostErrorOnContext(Context *context);
153 void GenerateContextLostErrorOnCurrentGlobalContext();
154
155 #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
156 // TODO(b/177574181): This should be handled in a backend-specific way.
157 // if previous context different from current context, dirty all state
DirtyContextIfNeeded(Context * context)158 static ANGLE_INLINE void DirtyContextIfNeeded(Context *context)
159 {
160 if (context && context != egl::GetGlobalLastContext())
161 {
162 context->dirtyAllState();
163 SetGlobalLastContext(context);
164 }
165 }
166
167 #endif
168
169 #if !defined(ANGLE_ENABLE_SHARE_CONTEXT_LOCK)
170 # define SCOPED_SHARE_CONTEXT_LOCK(context)
171 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
172 #else
173 # if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
174 # define SCOPED_SHARE_CONTEXT_LOCK(context) \
175 egl::ScopedGlobalEGLMutexLock shareContextLock; \
176 DirtyContextIfNeeded(context)
177 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
178 SCOPED_SHARE_CONTEXT_LOCK(context)
179 # elif !defined(ANGLE_ENABLE_CONTEXT_MUTEX)
180 # define SCOPED_SHARE_CONTEXT_LOCK(context) \
181 egl::ScopedOptionalGlobalMutexLock shareContextLock(context->isShared())
182 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
183 # else
184 # define SCOPED_SHARE_CONTEXT_LOCK(context) \
185 egl::ScopedContextMutexLock shareContextLock(context->getContextMutex())
186 # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
187 ANGLE_SCOPED_GLOBAL_LOCK(); \
188 egl::ScopedContextMutexLock shareContextLock = \
189 egl::LockAndTryMergeContextMutexes(context, imageID)
190 # endif
191 #endif
192
193 } // namespace gl
194
195 #endif // LIBGLESV2_GLOBALSTATE_H_
196