egl/main: Enable Linux platform extensions
[mesa.git] / src / egl / main / egldisplay.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
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 "eglcurrent.h"
40 #include "eglsurface.h"
41 #include "egldisplay.h"
42 #include "egldriver.h"
43 #include "eglglobals.h"
44 #include "eglmutex.h"
45 #include "egllog.h"
46
47 /* Includes for _eglNativePlatformDetectNativeDisplay */
48 #ifdef HAVE_MINCORE
49 #include <unistd.h>
50 #include <sys/mman.h>
51 #endif
52 #ifdef HAVE_WAYLAND_PLATFORM
53 #include <wayland-client.h>
54 #endif
55 #ifdef HAVE_DRM_PLATFORM
56 #include <gbm.h>
57 #endif
58 #ifdef HAVE_FBDEV_PLATFORM
59 #include <stdint.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #endif
63
64
65 /**
66 * Map --with-egl-platforms names to platform types.
67 */
68 static const struct {
69 _EGLPlatformType platform;
70 const char *name;
71 } egl_platforms[_EGL_NUM_PLATFORMS] = {
72 { _EGL_PLATFORM_WINDOWS, "gdi" },
73 { _EGL_PLATFORM_X11, "x11" },
74 { _EGL_PLATFORM_WAYLAND, "wayland" },
75 { _EGL_PLATFORM_DRM, "drm" },
76 { _EGL_PLATFORM_FBDEV, "fbdev" },
77 { _EGL_PLATFORM_NULL, "null" },
78 { _EGL_PLATFORM_ANDROID, "android" }
79 };
80
81
82 /**
83 * Return the native platform by parsing EGL_PLATFORM.
84 */
85 static _EGLPlatformType
86 _eglGetNativePlatformFromEnv(void)
87 {
88 _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
89 const char *plat_name;
90 EGLint i;
91
92 plat_name = getenv("EGL_PLATFORM");
93 /* try deprecated env variable */
94 if (!plat_name || !plat_name[0])
95 plat_name = getenv("EGL_DISPLAY");
96 if (!plat_name || !plat_name[0])
97 return _EGL_INVALID_PLATFORM;
98
99 for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
100 if (strcmp(egl_platforms[i].name, plat_name) == 0) {
101 plat = egl_platforms[i].platform;
102 break;
103 }
104 }
105
106 return plat;
107 }
108
109
110 /**
111 * Perform validity checks on a generic pointer.
112 */
113 static EGLBoolean
114 _eglPointerIsDereferencable(void *p)
115 {
116 #ifdef HAVE_MINCORE
117 uintptr_t addr = (uintptr_t) p;
118 unsigned char valid = 0;
119 const long page_size = getpagesize();
120
121 if (p == NULL)
122 return EGL_FALSE;
123
124 /* align addr to page_size */
125 addr &= ~(page_size - 1);
126
127 if (mincore((void *) addr, page_size, &valid) < 0) {
128 _eglLog(_EGL_DEBUG, "mincore failed: %m");
129 return EGL_FALSE;
130 }
131
132 return (valid & 0x01) == 0x01;
133 #else
134 return p != NULL;
135 #endif
136 }
137
138
139 /**
140 * Try detecting native platform with the help of native display characteristcs.
141 */
142 static _EGLPlatformType
143 _eglNativePlatformDetectNativeDisplay(void *nativeDisplay)
144 {
145 #ifdef HAVE_FBDEV_PLATFORM
146 struct stat buf;
147 #endif
148
149 if (nativeDisplay == EGL_DEFAULT_DISPLAY)
150 return _EGL_INVALID_PLATFORM;
151
152 #ifdef HAVE_FBDEV_PLATFORM
153 /* fbdev is the only platform that can be a file descriptor. */
154 if (fstat((intptr_t) nativeDisplay, &buf) == 0 && S_ISCHR(buf.st_mode))
155 return _EGL_PLATFORM_FBDEV;
156 #endif
157
158 if (_eglPointerIsDereferencable(nativeDisplay)) {
159 void *first_pointer = *(void **) nativeDisplay;
160
161 (void) first_pointer; /* silence unused var warning */
162
163 #ifdef HAVE_WAYLAND_PLATFORM
164 /* wl_display is a wl_proxy, which is a wl_object.
165 * wl_object's first element points to the interfacetype. */
166 if (first_pointer == &wl_display_interface)
167 return _EGL_PLATFORM_WAYLAND;
168 #endif
169
170 #ifdef HAVE_DRM_PLATFORM
171 /* gbm has a pointer to its constructor as first element. */
172 if (first_pointer == gbm_create_device)
173 return _EGL_PLATFORM_DRM;
174 #endif
175
176 #ifdef HAVE_X11_PLATFORM
177 /* If not matched to any other platform, fallback to x11. */
178 return _EGL_PLATFORM_X11;
179 #endif
180 }
181
182 return _EGL_INVALID_PLATFORM;
183 }
184
185
186 /**
187 * Return the native platform. It is the platform of the EGL native types.
188 */
189 _EGLPlatformType
190 _eglGetNativePlatform(void *nativeDisplay)
191 {
192 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
193 char *detection_method = NULL;
194
195 if (native_platform == _EGL_INVALID_PLATFORM) {
196 native_platform = _eglGetNativePlatformFromEnv();
197 detection_method = "environment overwrite";
198 if (native_platform == _EGL_INVALID_PLATFORM) {
199 native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
200 detection_method = "autodetected";
201 if (native_platform == _EGL_INVALID_PLATFORM) {
202 native_platform = _EGL_NATIVE_PLATFORM;
203 detection_method = "build-time configuration";
204 }
205 }
206 }
207
208 if (detection_method != NULL)
209 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
210 egl_platforms[native_platform].name, detection_method);
211
212 return native_platform;
213 }
214
215
216 /**
217 * Finish display management.
218 */
219 void
220 _eglFiniDisplay(void)
221 {
222 _EGLDisplay *dpyList, *dpy;
223
224 /* atexit function is called with global mutex locked */
225 dpyList = _eglGlobal.DisplayList;
226 while (dpyList) {
227 EGLint i;
228
229 /* pop list head */
230 dpy = dpyList;
231 dpyList = dpyList->Next;
232
233 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
234 if (dpy->ResourceLists[i]) {
235 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
236 break;
237 }
238 }
239
240 free(dpy);
241 }
242 _eglGlobal.DisplayList = NULL;
243 }
244
245
246 /**
247 * Find the display corresponding to the specified native display, or create a
248 * new one.
249 */
250 _EGLDisplay *
251 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
252 {
253 _EGLDisplay *dpy;
254
255 if (plat == _EGL_INVALID_PLATFORM)
256 return NULL;
257
258 _eglLockMutex(_eglGlobal.Mutex);
259
260 /* search the display list first */
261 dpy = _eglGlobal.DisplayList;
262 while (dpy) {
263 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
264 break;
265 dpy = dpy->Next;
266 }
267
268 /* create a new display */
269 if (!dpy) {
270 dpy = calloc(1, sizeof(_EGLDisplay));
271 if (dpy) {
272 _eglInitMutex(&dpy->Mutex);
273 dpy->Platform = plat;
274 dpy->PlatformDisplay = plat_dpy;
275
276 /* add to the display list */
277 dpy->Next = _eglGlobal.DisplayList;
278 _eglGlobal.DisplayList = dpy;
279 }
280 }
281
282 _eglUnlockMutex(_eglGlobal.Mutex);
283
284 return dpy;
285 }
286
287
288 /**
289 * Destroy the contexts and surfaces that are linked to the display.
290 */
291 void
292 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
293 {
294 _EGLResource *list;
295
296 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
297 while (list) {
298 _EGLContext *ctx = (_EGLContext *) list;
299 list = list->Next;
300
301 _eglUnlinkContext(ctx);
302 drv->API.DestroyContext(drv, display, ctx);
303 }
304 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
305
306 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
307 while (list) {
308 _EGLSurface *surf = (_EGLSurface *) list;
309 list = list->Next;
310
311 _eglUnlinkSurface(surf);
312 drv->API.DestroySurface(drv, display, surf);
313 }
314 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
315 }
316
317
318 /**
319 * Free all the data hanging of an _EGLDisplay object, but not
320 * the object itself.
321 */
322 void
323 _eglCleanupDisplay(_EGLDisplay *disp)
324 {
325 if (disp->Configs) {
326 _eglDestroyArray(disp->Configs, free);
327 disp->Configs = NULL;
328 }
329
330 /* XXX incomplete */
331 }
332
333
334 /**
335 * Return EGL_TRUE if the given handle is a valid handle to a display.
336 */
337 EGLBoolean
338 _eglCheckDisplayHandle(EGLDisplay dpy)
339 {
340 _EGLDisplay *cur;
341
342 _eglLockMutex(_eglGlobal.Mutex);
343 cur = _eglGlobal.DisplayList;
344 while (cur) {
345 if (cur == (_EGLDisplay *) dpy)
346 break;
347 cur = cur->Next;
348 }
349 _eglUnlockMutex(_eglGlobal.Mutex);
350 return (cur != NULL);
351 }
352
353
354 /**
355 * Return EGL_TRUE if the given resource is valid. That is, the display does
356 * own the resource.
357 */
358 EGLBoolean
359 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
360 {
361 _EGLResource *list = dpy->ResourceLists[type];
362
363 if (!res)
364 return EGL_FALSE;
365
366 while (list) {
367 if (res == (void *) list) {
368 assert(list->Display == dpy);
369 break;
370 }
371 list = list->Next;
372 }
373
374 return (list != NULL);
375 }
376
377
378 /**
379 * Initialize a display resource. The size of the subclass object is
380 * specified.
381 *
382 * This is supposed to be called from the initializers of subclasses, such as
383 * _eglInitContext or _eglInitSurface.
384 */
385 void
386 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
387 {
388 memset(res, 0, size);
389 res->Display = dpy;
390 res->RefCount = 1;
391 }
392
393
394 /**
395 * Increment reference count for the resource.
396 */
397 void
398 _eglGetResource(_EGLResource *res)
399 {
400 assert(res && res->RefCount > 0);
401 /* hopefully a resource is always manipulated with its display locked */
402 res->RefCount++;
403 }
404
405
406 /**
407 * Decrement reference count for the resource.
408 */
409 EGLBoolean
410 _eglPutResource(_EGLResource *res)
411 {
412 assert(res && res->RefCount > 0);
413 res->RefCount--;
414 return (!res->RefCount);
415 }
416
417
418 /**
419 * Link a resource to its display.
420 */
421 void
422 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
423 {
424 assert(res->Display);
425
426 res->IsLinked = EGL_TRUE;
427 res->Next = res->Display->ResourceLists[type];
428 res->Display->ResourceLists[type] = res;
429 _eglGetResource(res);
430 }
431
432
433 /**
434 * Unlink a linked resource from its display.
435 */
436 void
437 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
438 {
439 _EGLResource *prev;
440
441 prev = res->Display->ResourceLists[type];
442 if (prev != res) {
443 while (prev) {
444 if (prev->Next == res)
445 break;
446 prev = prev->Next;
447 }
448 assert(prev);
449 prev->Next = res->Next;
450 }
451 else {
452 res->Display->ResourceLists[type] = res->Next;
453 }
454
455 res->Next = NULL;
456 res->IsLinked = EGL_FALSE;
457 _eglPutResource(res);
458
459 /* We always unlink before destroy. The driver still owns a reference */
460 assert(res->RefCount);
461 }
462
463 #ifdef HAVE_X11_PLATFORM
464 static EGLBoolean
465 _eglParseX11DisplayAttribList(const EGLint *attrib_list)
466 {
467 int i;
468
469 if (attrib_list == NULL) {
470 return EGL_TRUE;
471 }
472
473 for (i = 0; attrib_list[i] != EGL_NONE; i += 2) {
474 EGLint attrib = attrib_list[i];
475 EGLint value = attrib_list[i + 1];
476
477 /* EGL_EXT_platform_x11 recognizes exactly one attribute,
478 * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
479 *
480 * Mesa supports connecting to only the default screen, so we reject
481 * screen != 0.
482 */
483 if (attrib != EGL_PLATFORM_X11_SCREEN_EXT || value != 0) {
484 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
485 return EGL_FALSE;
486 }
487 }
488
489 return EGL_TRUE;
490 }
491
492 _EGLDisplay*
493 _eglGetX11Display(Display *native_display,
494 const EGLint *attrib_list)
495 {
496 if (!_eglParseX11DisplayAttribList(attrib_list)) {
497 return NULL;
498 }
499
500 return _eglFindDisplay(_EGL_PLATFORM_X11, native_display);
501 }
502 #endif /* HAVE_X11_PLATFORM */
503
504 #ifdef HAVE_DRM_PLATFORM
505 _EGLDisplay*
506 _eglGetGbmDisplay(struct gbm_device *native_display,
507 const EGLint *attrib_list)
508 {
509 /* EGL_MESA_platform_gbm recognizes no attributes. */
510 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
511 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
512 return NULL;
513 }
514
515 return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display);
516 }
517 #endif /* HAVE_DRM_PLATFORM */
518
519 #ifdef HAVE_WAYLAND_PLATFORM
520 _EGLDisplay*
521 _eglGetWaylandDisplay(struct wl_display *native_display,
522 const EGLint *attrib_list)
523 {
524 /* EGL_EXT_platform_wayland recognizes no attributes. */
525 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
526 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
527 return NULL;
528 }
529
530 return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display);
531 }
532 #endif /* HAVE_WAYLAND_PLATFORM */