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