egl: fold _eglError() + return EGL_FALSE
[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 #include "util/u_atomic.h"
40
41 #include "eglcontext.h"
42 #include "eglcurrent.h"
43 #include "eglsurface.h"
44 #include "egldisplay.h"
45 #include "egldriver.h"
46 #include "eglglobals.h"
47 #include "egllog.h"
48 #include "eglimage.h"
49 #include "eglsync.h"
50
51 /* Includes for _eglNativePlatformDetectNativeDisplay */
52 #ifdef HAVE_MINCORE
53 #include <unistd.h>
54 #include <sys/mman.h>
55 #endif
56 #ifdef HAVE_WAYLAND_PLATFORM
57 #include <wayland-client.h>
58 #endif
59 #ifdef HAVE_DRM_PLATFORM
60 #include <gbm.h>
61 #endif
62
63
64 /**
65 * Map --with-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_X11, "x11" },
72 { _EGL_PLATFORM_WAYLAND, "wayland" },
73 { _EGL_PLATFORM_DRM, "drm" },
74 { _EGL_PLATFORM_ANDROID, "android" },
75 { _EGL_PLATFORM_HAIKU, "haiku" },
76 { _EGL_PLATFORM_SURFACELESS, "surfaceless" },
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(void *nativeDisplay)
142 {
143 if (nativeDisplay == EGL_DEFAULT_DISPLAY)
144 return _EGL_INVALID_PLATFORM;
145
146 if (_eglPointerIsDereferencable(nativeDisplay)) {
147 void *first_pointer = *(void **) nativeDisplay;
148
149 (void) first_pointer; /* silence unused var warning */
150
151 #ifdef HAVE_WAYLAND_PLATFORM
152 /* wl_display is a wl_proxy, which is a wl_object.
153 * wl_object's first element points to the interfacetype. */
154 if (first_pointer == &wl_display_interface)
155 return _EGL_PLATFORM_WAYLAND;
156 #endif
157
158 #ifdef HAVE_DRM_PLATFORM
159 /* gbm has a pointer to its constructor as first element. */
160 if (first_pointer == gbm_create_device)
161 return _EGL_PLATFORM_DRM;
162 #endif
163
164 #ifdef HAVE_X11_PLATFORM
165 /* If not matched to any other platform, fallback to x11. */
166 return _EGL_PLATFORM_X11;
167 #endif
168
169 #ifdef HAVE_HAIKU_PLATFORM
170 return _EGL_PLATFORM_HAIKU;
171 #endif
172 }
173
174 return _EGL_INVALID_PLATFORM;
175 }
176
177
178 /**
179 * Return the native platform. It is the platform of the EGL native types.
180 */
181 _EGLPlatformType
182 _eglGetNativePlatform(void *nativeDisplay)
183 {
184 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
185 _EGLPlatformType detected_platform = native_platform;
186
187 if (detected_platform == _EGL_INVALID_PLATFORM) {
188 const char *detection_method;
189
190 detected_platform = _eglGetNativePlatformFromEnv();
191 detection_method = "environment overwrite";
192
193 if (detected_platform == _EGL_INVALID_PLATFORM) {
194 detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
195 detection_method = "autodetected";
196 }
197
198 if (detected_platform == _EGL_INVALID_PLATFORM) {
199 detected_platform = _EGL_NATIVE_PLATFORM;
200 detection_method = "build-time configuration";
201 }
202
203 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
204 egl_platforms[detected_platform].name, detection_method);
205
206 p_atomic_cmpxchg(&native_platform, _EGL_INVALID_PLATFORM,
207 detected_platform);
208 }
209
210 return native_platform;
211 }
212
213
214 /**
215 * Finish display management.
216 */
217 void
218 _eglFiniDisplay(void)
219 {
220 _EGLDisplay *dpyList, *dpy;
221
222 /* atexit function is called with global mutex locked */
223 dpyList = _eglGlobal.DisplayList;
224 while (dpyList) {
225 EGLint i;
226
227 /* pop list head */
228 dpy = dpyList;
229 dpyList = dpyList->Next;
230
231 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
232 if (dpy->ResourceLists[i]) {
233 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
234 break;
235 }
236 }
237
238 free(dpy);
239 }
240 _eglGlobal.DisplayList = NULL;
241 }
242
243
244 /**
245 * Find the display corresponding to the specified native display, or create a
246 * new one.
247 */
248 _EGLDisplay *
249 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
250 {
251 _EGLDisplay *dpy;
252
253 if (plat == _EGL_INVALID_PLATFORM)
254 return NULL;
255
256 mtx_lock(_eglGlobal.Mutex);
257
258 /* search the display list first */
259 dpy = _eglGlobal.DisplayList;
260 while (dpy) {
261 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
262 break;
263 dpy = dpy->Next;
264 }
265
266 /* create a new display */
267 if (!dpy) {
268 dpy = calloc(1, sizeof(_EGLDisplay));
269 if (dpy) {
270 mtx_init(&dpy->Mutex, mtx_plain);
271 dpy->Platform = plat;
272 dpy->PlatformDisplay = plat_dpy;
273
274 /* add to the display list */
275 dpy->Next = _eglGlobal.DisplayList;
276 _eglGlobal.DisplayList = dpy;
277 }
278 }
279
280 mtx_unlock(_eglGlobal.Mutex);
281
282 return dpy;
283 }
284
285
286 /**
287 * Destroy the contexts and surfaces that are linked to the display.
288 */
289 void
290 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
291 {
292 _EGLResource *list;
293
294 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
295 while (list) {
296 _EGLContext *ctx = (_EGLContext *) list;
297 list = list->Next;
298
299 _eglUnlinkContext(ctx);
300 drv->API.DestroyContext(drv, display, ctx);
301 }
302 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
303
304 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
305 while (list) {
306 _EGLSurface *surf = (_EGLSurface *) list;
307 list = list->Next;
308
309 _eglUnlinkSurface(surf);
310 drv->API.DestroySurface(drv, display, surf);
311 }
312 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
313
314 list = display->ResourceLists[_EGL_RESOURCE_IMAGE];
315 while (list) {
316 _EGLImage *image = (_EGLImage *) list;
317 list = list->Next;
318
319 _eglUnlinkImage(image);
320 drv->API.DestroyImageKHR(drv, display, image);
321 }
322 assert(!display->ResourceLists[_EGL_RESOURCE_IMAGE]);
323
324 list = display->ResourceLists[_EGL_RESOURCE_SYNC];
325 while (list) {
326 _EGLSync *sync = (_EGLSync *) list;
327 list = list->Next;
328
329 _eglUnlinkSync(sync);
330 drv->API.DestroySyncKHR(drv, display, sync);
331 }
332 assert(!display->ResourceLists[_EGL_RESOURCE_SYNC]);
333 }
334
335
336 /**
337 * Free all the data hanging of an _EGLDisplay object, but not
338 * the object itself.
339 */
340 void
341 _eglCleanupDisplay(_EGLDisplay *disp)
342 {
343 if (disp->Configs) {
344 _eglDestroyArray(disp->Configs, free);
345 disp->Configs = NULL;
346 }
347
348 /* XXX incomplete */
349 }
350
351
352 /**
353 * Return EGL_TRUE if the given handle is a valid handle to a display.
354 */
355 EGLBoolean
356 _eglCheckDisplayHandle(EGLDisplay dpy)
357 {
358 _EGLDisplay *cur;
359
360 mtx_lock(_eglGlobal.Mutex);
361 cur = _eglGlobal.DisplayList;
362 while (cur) {
363 if (cur == (_EGLDisplay *) dpy)
364 break;
365 cur = cur->Next;
366 }
367 mtx_unlock(_eglGlobal.Mutex);
368 return (cur != NULL);
369 }
370
371
372 /**
373 * Return EGL_TRUE if the given resource is valid. That is, the display does
374 * own the resource.
375 */
376 EGLBoolean
377 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
378 {
379 _EGLResource *list = dpy->ResourceLists[type];
380
381 if (!res)
382 return EGL_FALSE;
383
384 while (list) {
385 if (res == (void *) list) {
386 assert(list->Display == dpy);
387 break;
388 }
389 list = list->Next;
390 }
391
392 return (list != NULL);
393 }
394
395
396 /**
397 * Initialize a display resource. The size of the subclass object is
398 * specified.
399 *
400 * This is supposed to be called from the initializers of subclasses, such as
401 * _eglInitContext or _eglInitSurface.
402 */
403 void
404 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
405 {
406 memset(res, 0, size);
407 res->Display = dpy;
408 res->RefCount = 1;
409 }
410
411
412 /**
413 * Increment reference count for the resource.
414 */
415 void
416 _eglGetResource(_EGLResource *res)
417 {
418 assert(res && res->RefCount > 0);
419 /* hopefully a resource is always manipulated with its display locked */
420 res->RefCount++;
421 }
422
423
424 /**
425 * Decrement reference count for the resource.
426 */
427 EGLBoolean
428 _eglPutResource(_EGLResource *res)
429 {
430 assert(res && res->RefCount > 0);
431 res->RefCount--;
432 return (!res->RefCount);
433 }
434
435
436 /**
437 * Link a resource to its display.
438 */
439 void
440 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
441 {
442 assert(res->Display);
443
444 res->IsLinked = EGL_TRUE;
445 res->Next = res->Display->ResourceLists[type];
446 res->Display->ResourceLists[type] = res;
447 _eglGetResource(res);
448 }
449
450
451 /**
452 * Unlink a linked resource from its display.
453 */
454 void
455 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
456 {
457 _EGLResource *prev;
458
459 prev = res->Display->ResourceLists[type];
460 if (prev != res) {
461 while (prev) {
462 if (prev->Next == res)
463 break;
464 prev = prev->Next;
465 }
466 assert(prev);
467 prev->Next = res->Next;
468 }
469 else {
470 res->Display->ResourceLists[type] = res->Next;
471 }
472
473 res->Next = NULL;
474 res->IsLinked = EGL_FALSE;
475 _eglPutResource(res);
476
477 /* We always unlink before destroy. The driver still owns a reference */
478 assert(res->RefCount);
479 }
480
481 #ifdef HAVE_X11_PLATFORM
482 static EGLBoolean
483 _eglParseX11DisplayAttribList(_EGLDisplay *display, const EGLint *attrib_list)
484 {
485 int i;
486
487 if (attrib_list == NULL) {
488 return EGL_TRUE;
489 }
490
491 for (i = 0; attrib_list[i] != EGL_NONE; i += 2) {
492 EGLint attrib = attrib_list[i];
493 EGLint value = attrib_list[i + 1];
494
495 /* EGL_EXT_platform_x11 recognizes exactly one attribute,
496 * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
497 */
498 if (attrib != EGL_PLATFORM_X11_SCREEN_EXT)
499 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
500
501 display->Options.Platform = (void *)(uintptr_t)value;
502 }
503
504 return EGL_TRUE;
505 }
506
507 _EGLDisplay*
508 _eglGetX11Display(Display *native_display,
509 const EGLint *attrib_list)
510 {
511 _EGLDisplay *display = _eglFindDisplay(_EGL_PLATFORM_X11,
512 native_display);
513
514 if (!display) {
515 _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
516 return NULL;
517 }
518
519 if (!_eglParseX11DisplayAttribList(display, attrib_list)) {
520 return NULL;
521 }
522
523 return display;
524 }
525 #endif /* HAVE_X11_PLATFORM */
526
527 #ifdef HAVE_DRM_PLATFORM
528 _EGLDisplay*
529 _eglGetGbmDisplay(struct gbm_device *native_display,
530 const EGLint *attrib_list)
531 {
532 /* EGL_MESA_platform_gbm recognizes no attributes. */
533 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
534 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
535 return NULL;
536 }
537
538 return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display);
539 }
540 #endif /* HAVE_DRM_PLATFORM */
541
542 #ifdef HAVE_WAYLAND_PLATFORM
543 _EGLDisplay*
544 _eglGetWaylandDisplay(struct wl_display *native_display,
545 const EGLint *attrib_list)
546 {
547 /* EGL_EXT_platform_wayland recognizes no attributes. */
548 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
549 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
550 return NULL;
551 }
552
553 return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display);
554 }
555 #endif /* HAVE_WAYLAND_PLATFORM */
556
557 #ifdef HAVE_SURFACELESS_PLATFORM
558 _EGLDisplay*
559 _eglGetSurfacelessDisplay(void *native_display,
560 const EGLint *attrib_list)
561 {
562 /* This platform has no native display. */
563 if (native_display != NULL) {
564 _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
565 return NULL;
566 }
567
568 /* This platform recognizes no display attributes. */
569 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
570 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
571 return NULL;
572 }
573
574 return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, native_display);
575 }
576 #endif /* HAVE_SURFACELESS_PLATFORM */