1 #include "libeglcurrent.h"
2 
3 #include "glvnd_pthread.h"
4 #include "lkdhash.h"
5 
6 static void OnDispatchThreadDestroyed(__GLdispatchThreadState *state);
7 static void OnThreadDestroyed(void *data);
8 
9 static __EGLThreadAPIState *CreateThreadState(void);
10 static void DestroyThreadState(__EGLThreadAPIState *threadState);
11 
12 /**
13  * A list of current __EGLdispatchThreadState structures. This is used so that we can
14  * clean up at process termination or after a fork.
15  */
16 static struct glvnd_list currentAPIStateList;
17 static struct glvnd_list currentThreadStateList;
18 static glvnd_mutex_t currentStateListMutex = PTHREAD_MUTEX_INITIALIZER;
19 static glvnd_key_t threadStateKey;
20 
__eglQueryAPI(void)21 EGLenum __eglQueryAPI(void)
22 {
23     __EGLThreadAPIState *state = __eglGetCurrentThreadAPIState(EGL_FALSE);
24     if (state != NULL) {
25         return state->currentClientApi;
26     } else {
27         // FIXME: If none of the vendor libraries support GLES, then this
28         // should be EGL_NONE.
29         return EGL_OPENGL_ES_API;
30     }
31 }
32 
__eglGetCurrentVendor(void)33 __EGLvendorInfo *__eglGetCurrentVendor(void)
34 {
35     __EGLdispatchThreadState *state = __eglGetCurrentAPIState();
36     if (state != NULL) {
37         return state->currentVendor;
38     } else {
39         return NULL;
40     }
41 }
42 
__eglGetCurrentContext(void)43 EGLContext __eglGetCurrentContext(void)
44 {
45     __EGLdispatchThreadState *state = __eglGetCurrentAPIState();
46     if (state != NULL) {
47         return state->currentContext;
48     } else {
49         return EGL_NO_CONTEXT;
50     }
51 }
52 
__eglGetCurrentDisplay(void)53 EGLDisplay __eglGetCurrentDisplay(void)
54 {
55     __EGLdispatchThreadState *state = __eglGetCurrentAPIState();
56     if (state != NULL && state->currentDisplay != NULL) {
57         return state->currentDisplay->dpy;
58     } else {
59         return EGL_NO_DISPLAY;
60     }
61 }
62 
__eglGetCurrentSurface(EGLint readDraw)63 EGLSurface __eglGetCurrentSurface(EGLint readDraw)
64 {
65     __EGLdispatchThreadState *state = __eglGetCurrentAPIState();
66     if (state != NULL) {
67         if (readDraw == EGL_DRAW) {
68             return state->currentDraw;
69         } else if (readDraw == EGL_READ) {
70             return state->currentRead;
71         } else {
72             return EGL_NO_SURFACE;
73         }
74     } else {
75         return EGL_NO_SURFACE;
76     }
77 }
78 
__eglCurrentInit(void)79 void __eglCurrentInit(void)
80 {
81     glvnd_list_init(&currentAPIStateList);
82     glvnd_list_init(&currentThreadStateList);
83     __glvndPthreadFuncs.key_create(&threadStateKey, OnThreadDestroyed);
84 }
85 
__eglCurrentTeardown(EGLBoolean doReset)86 void __eglCurrentTeardown(EGLBoolean doReset)
87 {
88     while (!glvnd_list_is_empty(&currentAPIStateList)) {
89         __EGLdispatchThreadState *apiState = glvnd_list_first_entry(
90                 &currentAPIStateList, __EGLdispatchThreadState, entry);
91         __eglDestroyAPIState(apiState);
92     }
93 
94     while (!glvnd_list_is_empty(&currentThreadStateList)) {
95         __EGLThreadAPIState *threadState = glvnd_list_first_entry(
96                 &currentThreadStateList, __EGLThreadAPIState, entry);
97         DestroyThreadState(threadState);
98     }
99 
100     if (doReset) {
101         __glvndPthreadFuncs.mutex_init(&currentStateListMutex, NULL);
102     }
103 }
104 
CreateThreadState(void)105 __EGLThreadAPIState *CreateThreadState(void)
106 {
107     __EGLThreadAPIState *threadState = calloc(1, sizeof(__EGLThreadAPIState));
108     if (threadState == NULL) {
109         return NULL;
110     }
111 
112     threadState->lastError = EGL_SUCCESS;
113     threadState->lastVendor = NULL;
114 
115     // TODO: If no vendor library supports GLES, then we should initialize this
116     // to EGL_NONE.
117     threadState->currentClientApi = EGL_OPENGL_ES_API;
118 
119     __glvndPthreadFuncs.mutex_lock(&currentStateListMutex);
120     glvnd_list_add(&threadState->entry, &currentThreadStateList);
121     __glvndPthreadFuncs.mutex_unlock(&currentStateListMutex);
122 
123     __glvndPthreadFuncs.setspecific(threadStateKey, threadState);
124     return threadState;
125 }
126 
__eglGetCurrentThreadAPIState(EGLBoolean create)127 __EGLThreadAPIState *__eglGetCurrentThreadAPIState(EGLBoolean create)
128 {
129     __EGLThreadAPIState *threadState = (__EGLThreadAPIState *) __glvndPthreadFuncs.getspecific(threadStateKey);
130     if (threadState == NULL && create) {
131         threadState = CreateThreadState();
132     }
133     return threadState;
134 }
135 
DestroyThreadState(__EGLThreadAPIState * threadState)136 void DestroyThreadState(__EGLThreadAPIState *threadState)
137 {
138     if (threadState != NULL) {
139         __glvndPthreadFuncs.mutex_lock(&currentStateListMutex);
140         glvnd_list_del(&threadState->entry);
141         __glvndPthreadFuncs.mutex_unlock(&currentStateListMutex);
142 
143         free(threadState);
144     }
145 }
146 
__eglDestroyCurrentThreadAPIState(void)147 void __eglDestroyCurrentThreadAPIState(void)
148 {
149     __EGLThreadAPIState *threadState = __glvndPthreadFuncs.getspecific(threadStateKey);
150     if (threadState != NULL) {
151         __glvndPthreadFuncs.setspecific(threadStateKey, NULL);
152         DestroyThreadState(threadState);
153     }
154 }
155 
OnThreadDestroyed(void * data)156 void OnThreadDestroyed(void *data)
157 {
158     __EGLThreadAPIState *threadState = (__EGLThreadAPIState *) data;
159     DestroyThreadState(threadState);
160 }
161 
__eglCreateAPIState(void)162 __EGLdispatchThreadState *__eglCreateAPIState(void)
163 {
164     __EGLdispatchThreadState *apiState = calloc(1, sizeof(__EGLdispatchThreadState));
165     if (apiState == NULL) {
166         return NULL;
167     }
168 
169     apiState->glas.tag = GLDISPATCH_API_EGL;
170     apiState->glas.threadDestroyedCallback = OnDispatchThreadDestroyed;
171 
172     apiState->currentDisplay = NULL;
173     apiState->currentDraw = EGL_NO_SURFACE;
174     apiState->currentRead = EGL_NO_SURFACE;
175     apiState->currentContext = EGL_NO_CONTEXT;
176     apiState->currentVendor = NULL;
177 
178     __glvndPthreadFuncs.mutex_lock(&currentStateListMutex);
179     glvnd_list_add(&apiState->entry, &currentAPIStateList);
180     __glvndPthreadFuncs.mutex_unlock(&currentStateListMutex);
181 
182     return apiState;
183 }
184 
__eglDestroyAPIState(__EGLdispatchThreadState * apiState)185 void __eglDestroyAPIState(__EGLdispatchThreadState *apiState)
186 {
187     if (apiState != NULL) {
188         __glvndPthreadFuncs.mutex_lock(&currentStateListMutex);
189         glvnd_list_del(&apiState->entry);
190         __glvndPthreadFuncs.mutex_unlock(&currentStateListMutex);
191 
192         free(apiState);
193     }
194 }
195 
OnDispatchThreadDestroyed(__GLdispatchThreadState * state)196 void OnDispatchThreadDestroyed(__GLdispatchThreadState *state)
197 {
198     __EGLdispatchThreadState *eglState = (__EGLdispatchThreadState *) state;
199     __eglDestroyAPIState(eglState);
200 }
201 
202