Merge branch 'master' of git://anongit.freedesktop.org/mesa/mesa
[mesa.git] / src / egl / main / egldisplay.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31 /**
32 * Functions related to EGLDisplay.
33 */
34
35 #include <assert.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include "eglcontext.h"
39 #include "eglsurface.h"
40 #include "egldisplay.h"
41 #include "egldriver.h"
42 #include "eglglobals.h"
43 #include "eglmutex.h"
44 #include "egllog.h"
45
46 /* Includes for _eglNativePlatformDetectNativeDisplay */
47 #ifdef HAVE_MINCORE
48 #include <unistd.h>
49 #include <sys/mman.h>
50 #endif
51 #ifdef HAVE_WAYLAND_PLATFORM
52 #include <wayland-client.h>
53 #endif
54 #ifdef HAVE_DRM_PLATFORM
55 #include <gbm.h>
56 #endif
57 #ifdef HAVE_FBDEV_PLATFORM
58 #include <stdint.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #endif
62
63
64 /**
65 * Map --with-egl-platforms names to platform types.
66 */
67 static const struct {
68 _EGLPlatformType platform;
69 const char *name;
70 } egl_platforms[_EGL_NUM_PLATFORMS] = {
71 { _EGL_PLATFORM_WINDOWS, "gdi" },
72 { _EGL_PLATFORM_X11, "x11" },
73 { _EGL_PLATFORM_WAYLAND, "wayland" },
74 { _EGL_PLATFORM_DRM, "drm" },
75 { _EGL_PLATFORM_FBDEV, "fbdev" },
76 { _EGL_PLATFORM_ANDROID, "android" }
77 };
78
79
80 /**
81 * Return the native platform by parsing EGL_PLATFORM.
82 */
83 static _EGLPlatformType
84 _eglGetNativePlatformFromEnv(void)
85 {
86 _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
87 const char *plat_name;
88 EGLint i;
89
90 plat_name = getenv("EGL_PLATFORM");
91 /* try deprecated env variable */
92 if (!plat_name || !plat_name[0])
93 plat_name = getenv("EGL_DISPLAY");
94 if (!plat_name || !plat_name[0])
95 return _EGL_INVALID_PLATFORM;
96
97 for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
98 if (strcmp(egl_platforms[i].name, plat_name) == 0) {
99 plat = egl_platforms[i].platform;
100 break;
101 }
102 }
103
104 return plat;
105 }
106
107
108 /**
109 * Perform validity checks on a generic pointer.
110 */
111 static EGLBoolean
112 _eglPointerIsDereferencable(void *p)
113 {
114 #ifdef HAVE_MINCORE
115 uintptr_t addr = (uintptr_t) p;
116 unsigned char valid = 0;
117 const long page_size = getpagesize();
118
119 if (p == NULL)
120 return EGL_FALSE;
121
122 /* align addr to page_size */
123 addr &= ~(page_size - 1);
124
125 if (mincore((void *) addr, page_size, &valid) < 0) {
126 _eglLog(_EGL_DEBUG, "mincore failed: %m");
127 return EGL_FALSE;
128 }
129
130 return (valid & 0x01) == 0x01;
131 #else
132 return p != NULL;
133 #endif
134 }
135
136
137 /**
138 * Try detecting native platform with the help of native display characteristcs.
139 */
140 static _EGLPlatformType
141 _eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay)
142 {
143 #ifdef HAVE_FBDEV_PLATFORM
144 struct stat buf;
145 #endif
146
147 if (nativeDisplay == EGL_DEFAULT_DISPLAY)
148 return _EGL_INVALID_PLATFORM;
149
150 #ifdef HAVE_FBDEV_PLATFORM
151 /* fbdev is the only platform that can be a file descriptor. */
152 if (fstat((intptr_t) nativeDisplay, &buf) == 0 && S_ISCHR(buf.st_mode))
153 return _EGL_PLATFORM_FBDEV;
154 #endif
155
156 if (_eglPointerIsDereferencable(nativeDisplay)) {
157 void *first_pointer = *(void **) nativeDisplay;
158
159 #ifdef HAVE_WAYLAND_PLATFORM
160 /* wl_display is a wl_proxy, which is a wl_object.
161 * wl_object's first element points to the interfacetype. */
162 if (first_pointer == &wl_display_interface)
163 return _EGL_PLATFORM_WAYLAND;
164 #endif
165
166 #ifdef HAVE_DRM_PLATFORM
167 /* gbm has a pointer to its constructor as first element. */
168 if (first_pointer == gbm_create_device)
169 return _EGL_PLATFORM_DRM;
170 #endif
171
172 #ifdef HAVE_X11_PLATFORM
173 /* If not matched to any other platform, fallback to x11. */
174 return _EGL_PLATFORM_X11;
175 #endif
176 }
177
178 return _EGL_INVALID_PLATFORM;
179 }
180
181
182 /**
183 * Return the native platform. It is the platform of the EGL native types.
184 */
185 _EGLPlatformType
186 _eglGetNativePlatform(EGLNativeDisplayType nativeDisplay)
187 {
188 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
189 char *detection_method = NULL;
190
191 if (native_platform == _EGL_INVALID_PLATFORM) {
192 native_platform = _eglGetNativePlatformFromEnv();
193 detection_method = "environment overwrite";
194 if (native_platform == _EGL_INVALID_PLATFORM) {
195 native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
196 detection_method = "autodetected";
197 if (native_platform == _EGL_INVALID_PLATFORM) {
198 native_platform = _EGL_NATIVE_PLATFORM;
199 detection_method = "build-time configuration";
200 }
201 }
202 }
203
204 if (detection_method != NULL)
205 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
206 egl_platforms[native_platform].name, detection_method);
207
208 return native_platform;
209 }
210
211
212 /**
213 * Finish display management.
214 */
215 void
216 _eglFiniDisplay(void)
217 {
218 _EGLDisplay *dpyList, *dpy;
219
220 /* atexit function is called with global mutex locked */
221 dpyList = _eglGlobal.DisplayList;
222 while (dpyList) {
223 EGLint i;
224
225 /* pop list head */
226 dpy = dpyList;
227 dpyList = dpyList->Next;
228
229 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
230 if (dpy->ResourceLists[i]) {
231 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
232 break;
233 }
234 }
235
236 free(dpy);
237 }
238 _eglGlobal.DisplayList = NULL;
239 }
240
241
242 /**
243 * Find the display corresponding to the specified native display, or create a
244 * new one.
245 */
246 _EGLDisplay *
247 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
248 {
249 _EGLDisplay *dpy;
250
251 if (plat == _EGL_INVALID_PLATFORM)
252 return NULL;
253
254 _eglLockMutex(_eglGlobal.Mutex);
255
256 /* search the display list first */
257 dpy = _eglGlobal.DisplayList;
258 while (dpy) {
259 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
260 break;
261 dpy = dpy->Next;
262 }
263
264 /* create a new display */
265 if (!dpy) {
266 dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
267 if (dpy) {
268 _eglInitMutex(&dpy->Mutex);
269 dpy->Platform = plat;
270 dpy->PlatformDisplay = plat_dpy;
271
272 /* add to the display list */
273 dpy->Next = _eglGlobal.DisplayList;
274 _eglGlobal.DisplayList = dpy;
275 }
276 }
277
278 _eglUnlockMutex(_eglGlobal.Mutex);
279
280 return dpy;
281 }
282
283
284 /**
285 * Destroy the contexts and surfaces that are linked to the display.
286 */
287 void
288 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
289 {
290 _EGLResource *list;
291
292 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
293 while (list) {
294 _EGLContext *ctx = (_EGLContext *) list;
295 list = list->Next;
296
297 _eglUnlinkContext(ctx);
298 drv->API.DestroyContext(drv, display, ctx);
299 }
300 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
301
302 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
303 while (list) {
304 _EGLSurface *surf = (_EGLSurface *) list;
305 list = list->Next;
306
307 _eglUnlinkSurface(surf);
308 drv->API.DestroySurface(drv, display, surf);
309 }
310 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
311 }
312
313
314 /**
315 * Free all the data hanging of an _EGLDisplay object, but not
316 * the object itself.
317 */
318 void
319 _eglCleanupDisplay(_EGLDisplay *disp)
320 {
321 if (disp->Configs) {
322 _eglDestroyArray(disp->Configs, free);
323 disp->Configs = NULL;
324 }
325
326 /* XXX incomplete */
327 }
328
329
330 /**
331 * Return EGL_TRUE if the given handle is a valid handle to a display.
332 */
333 EGLBoolean
334 _eglCheckDisplayHandle(EGLDisplay dpy)
335 {
336 _EGLDisplay *cur;
337
338 _eglLockMutex(_eglGlobal.Mutex);
339 cur = _eglGlobal.DisplayList;
340 while (cur) {
341 if (cur == (_EGLDisplay *) dpy)
342 break;
343 cur = cur->Next;
344 }
345 _eglUnlockMutex(_eglGlobal.Mutex);
346 return (cur != NULL);
347 }
348
349
350 /**
351 * Return EGL_TRUE if the given resource is valid. That is, the display does
352 * own the resource.
353 */
354 EGLBoolean
355 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
356 {
357 _EGLResource *list = dpy->ResourceLists[type];
358
359 if (!res)
360 return EGL_FALSE;
361
362 while (list) {
363 if (res == (void *) list) {
364 assert(list->Display == dpy);
365 break;
366 }
367 list = list->Next;
368 }
369
370 return (list != NULL);
371 }
372
373
374 /**
375 * Initialize a display resource.
376 */
377 void
378 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
379 {
380 memset(res, 0, size);
381 res->Display = dpy;
382 res->RefCount = 1;
383 }
384
385
386 /**
387 * Increment reference count for the resource.
388 */
389 void
390 _eglGetResource(_EGLResource *res)
391 {
392 assert(res && res->RefCount > 0);
393 /* hopefully a resource is always manipulated with its display locked */
394 res->RefCount++;
395 }
396
397
398 /**
399 * Decrement reference count for the resource.
400 */
401 EGLBoolean
402 _eglPutResource(_EGLResource *res)
403 {
404 assert(res && res->RefCount > 0);
405 res->RefCount--;
406 return (!res->RefCount);
407 }
408
409
410 /**
411 * Link a resource to its display.
412 */
413 void
414 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
415 {
416 assert(res->Display);
417
418 res->IsLinked = EGL_TRUE;
419 res->Next = res->Display->ResourceLists[type];
420 res->Display->ResourceLists[type] = res;
421 _eglGetResource(res);
422 }
423
424
425 /**
426 * Unlink a linked resource from its display.
427 */
428 void
429 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
430 {
431 _EGLResource *prev;
432
433 prev = res->Display->ResourceLists[type];
434 if (prev != res) {
435 while (prev) {
436 if (prev->Next == res)
437 break;
438 prev = prev->Next;
439 }
440 assert(prev);
441 prev->Next = res->Next;
442 }
443 else {
444 res->Display->ResourceLists[type] = res->Next;
445 }
446
447 res->Next = NULL;
448 res->IsLinked = EGL_FALSE;
449 _eglPutResource(res);
450
451 /* We always unlink before destroy. The driver still owns a reference */
452 assert(res->RefCount);
453 }