Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / egl / main / egldisplay.c
1 /**
2 * Functions related to EGLDisplay.
3 */
4
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include "eglcontext.h"
9 #include "eglsurface.h"
10 #include "egldisplay.h"
11 #include "egldriver.h"
12 #include "eglglobals.h"
13 #include "eglmutex.h"
14 #include "egllog.h"
15
16
17 /**
18 * Return the native platform by parsing EGL_PLATFORM.
19 */
20 static _EGLPlatformType
21 _eglGetNativePlatformFromEnv(void)
22 {
23 /* map --with-egl-platforms names to platform types */
24 static const struct {
25 _EGLPlatformType platform;
26 const char *name;
27 } egl_platforms[_EGL_NUM_PLATFORMS] = {
28 { _EGL_PLATFORM_WINDOWS, "gdi" },
29 { _EGL_PLATFORM_X11, "x11" },
30 { _EGL_PLATFORM_WAYLAND, "wayland" },
31 { _EGL_PLATFORM_DRM, "drm" },
32 { _EGL_PLATFORM_FBDEV, "fbdev" }
33 };
34 _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
35 const char *plat_name;
36 EGLint i;
37
38 plat_name = getenv("EGL_PLATFORM");
39 /* try deprecated env variable */
40 if (!plat_name || !plat_name[0])
41 plat_name = getenv("EGL_DISPLAY");
42 if (!plat_name || !plat_name[0])
43 return _EGL_INVALID_PLATFORM;
44
45 for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
46 if (strcmp(egl_platforms[i].name, plat_name) == 0) {
47 plat = egl_platforms[i].platform;
48 break;
49 }
50 }
51
52 return plat;
53 }
54
55
56 /**
57 * Return the native platform. It is the platform of the EGL native types.
58 */
59 _EGLPlatformType
60 _eglGetNativePlatform(void)
61 {
62 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
63
64 if (native_platform == _EGL_INVALID_PLATFORM) {
65 native_platform = _eglGetNativePlatformFromEnv();
66 if (native_platform == _EGL_INVALID_PLATFORM)
67 native_platform = _EGL_NATIVE_PLATFORM;
68 }
69
70 return native_platform;
71 }
72
73
74 /**
75 * Finish display management.
76 */
77 void
78 _eglFiniDisplay(void)
79 {
80 _EGLDisplay *dpyList, *dpy;
81
82 /* atexit function is called with global mutex locked */
83 dpyList = _eglGlobal.DisplayList;
84 while (dpyList) {
85 EGLint i;
86
87 /* pop list head */
88 dpy = dpyList;
89 dpyList = dpyList->Next;
90
91 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
92 if (dpy->ResourceLists[i]) {
93 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
94 break;
95 }
96 }
97
98 free(dpy);
99 }
100 _eglGlobal.DisplayList = NULL;
101 }
102
103
104 /**
105 * Find the display corresponding to the specified native display, or create a
106 * new one.
107 */
108 _EGLDisplay *
109 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
110 {
111 _EGLDisplay *dpy;
112
113 if (plat == _EGL_INVALID_PLATFORM)
114 return NULL;
115
116 _eglLockMutex(_eglGlobal.Mutex);
117
118 /* search the display list first */
119 dpy = _eglGlobal.DisplayList;
120 while (dpy) {
121 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
122 break;
123 dpy = dpy->Next;
124 }
125
126 /* create a new display */
127 if (!dpy) {
128 dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
129 if (dpy) {
130 _eglInitMutex(&dpy->Mutex);
131 dpy->Platform = plat;
132 dpy->PlatformDisplay = plat_dpy;
133
134 /* add to the display list */
135 dpy->Next = _eglGlobal.DisplayList;
136 _eglGlobal.DisplayList = dpy;
137 }
138 }
139
140 _eglUnlockMutex(_eglGlobal.Mutex);
141
142 return dpy;
143 }
144
145
146 /**
147 * Destroy the contexts and surfaces that are linked to the display.
148 */
149 void
150 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
151 {
152 _EGLResource *list;
153
154 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
155 while (list) {
156 _EGLContext *ctx = (_EGLContext *) list;
157 list = list->Next;
158
159 _eglUnlinkContext(ctx);
160 drv->API.DestroyContext(drv, display, ctx);
161 }
162 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
163
164 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
165 while (list) {
166 _EGLSurface *surf = (_EGLSurface *) list;
167 list = list->Next;
168
169 _eglUnlinkSurface(surf);
170 drv->API.DestroySurface(drv, display, surf);
171 }
172 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
173 }
174
175
176 /**
177 * Free all the data hanging of an _EGLDisplay object, but not
178 * the object itself.
179 */
180 void
181 _eglCleanupDisplay(_EGLDisplay *disp)
182 {
183 if (disp->Configs) {
184 _eglDestroyArray(disp->Configs, free);
185 disp->Configs = NULL;
186 }
187
188 /* XXX incomplete */
189 }
190
191
192 /**
193 * Return EGL_TRUE if the given handle is a valid handle to a display.
194 */
195 EGLBoolean
196 _eglCheckDisplayHandle(EGLDisplay dpy)
197 {
198 _EGLDisplay *cur;
199
200 _eglLockMutex(_eglGlobal.Mutex);
201 cur = _eglGlobal.DisplayList;
202 while (cur) {
203 if (cur == (_EGLDisplay *) dpy)
204 break;
205 cur = cur->Next;
206 }
207 _eglUnlockMutex(_eglGlobal.Mutex);
208 return (cur != NULL);
209 }
210
211
212 /**
213 * Return EGL_TRUE if the given resource is valid. That is, the display does
214 * own the resource.
215 */
216 EGLBoolean
217 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
218 {
219 _EGLResource *list = dpy->ResourceLists[type];
220
221 if (!res)
222 return EGL_FALSE;
223
224 while (list) {
225 if (res == (void *) list) {
226 assert(list->Display == dpy);
227 break;
228 }
229 list = list->Next;
230 }
231
232 return (list != NULL);
233 }
234
235
236 /**
237 * Initialize a display resource.
238 */
239 void
240 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
241 {
242 memset(res, 0, size);
243 res->Display = dpy;
244 res->RefCount = 1;
245 }
246
247
248 /**
249 * Increment reference count for the resource.
250 */
251 void
252 _eglGetResource(_EGLResource *res)
253 {
254 assert(res && res->RefCount > 0);
255 /* hopefully a resource is always manipulated with its display locked */
256 res->RefCount++;
257 }
258
259
260 /**
261 * Decrement reference count for the resource.
262 */
263 EGLBoolean
264 _eglPutResource(_EGLResource *res)
265 {
266 assert(res && res->RefCount > 0);
267 res->RefCount--;
268 return (!res->RefCount);
269 }
270
271
272 /**
273 * Link a resource to its display.
274 */
275 void
276 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
277 {
278 assert(res->Display);
279
280 res->IsLinked = EGL_TRUE;
281 res->Next = res->Display->ResourceLists[type];
282 res->Display->ResourceLists[type] = res;
283 _eglGetResource(res);
284 }
285
286
287 /**
288 * Unlink a linked resource from its display.
289 */
290 void
291 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
292 {
293 _EGLResource *prev;
294
295 prev = res->Display->ResourceLists[type];
296 if (prev != res) {
297 while (prev) {
298 if (prev->Next == res)
299 break;
300 prev = prev->Next;
301 }
302 assert(prev);
303 prev->Next = res->Next;
304 }
305 else {
306 res->Display->ResourceLists[type] = res->Next;
307 }
308
309 res->Next = NULL;
310 res->IsLinked = EGL_FALSE;
311 _eglPutResource(res);
312
313 /* We always unlink before destroy. The driver still owns a reference */
314 assert(res->RefCount);
315 }