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