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