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