egl/display: remove unnecessary code and make it easier to read
[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;
182 char *detection_method;
183
184 native_platform = _eglGetNativePlatformFromEnv();
185 detection_method = "environment overwrite";
186
187 if (native_platform == _EGL_INVALID_PLATFORM) {
188 native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
189 detection_method = "autodetected";
190 }
191
192 if (native_platform == _EGL_INVALID_PLATFORM) {
193 native_platform = _EGL_NATIVE_PLATFORM;
194 detection_method = "build-time configuration";
195 }
196
197 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
198 egl_platforms[native_platform].name, detection_method);
199
200 return native_platform;
201 }
202
203
204 /**
205 * Finish display management.
206 */
207 void
208 _eglFiniDisplay(void)
209 {
210 _EGLDisplay *dpyList, *dpy;
211
212 /* atexit function is called with global mutex locked */
213 dpyList = _eglGlobal.DisplayList;
214 while (dpyList) {
215 EGLint i;
216
217 /* pop list head */
218 dpy = dpyList;
219 dpyList = dpyList->Next;
220
221 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
222 if (dpy->ResourceLists[i]) {
223 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
224 break;
225 }
226 }
227
228 free(dpy);
229 }
230 _eglGlobal.DisplayList = NULL;
231 }
232
233
234 /**
235 * Find the display corresponding to the specified native display, or create a
236 * new one.
237 */
238 _EGLDisplay *
239 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
240 {
241 _EGLDisplay *dpy;
242
243 if (plat == _EGL_INVALID_PLATFORM)
244 return NULL;
245
246 mtx_lock(_eglGlobal.Mutex);
247
248 /* search the display list first */
249 dpy = _eglGlobal.DisplayList;
250 while (dpy) {
251 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
252 break;
253 dpy = dpy->Next;
254 }
255
256 /* create a new display */
257 if (!dpy) {
258 dpy = calloc(1, sizeof(_EGLDisplay));
259 if (dpy) {
260 mtx_init(&dpy->Mutex, mtx_plain);
261 dpy->Platform = plat;
262 dpy->PlatformDisplay = plat_dpy;
263
264 /* add to the display list */
265 dpy->Next = _eglGlobal.DisplayList;
266 _eglGlobal.DisplayList = dpy;
267 }
268 }
269
270 mtx_unlock(_eglGlobal.Mutex);
271
272 return dpy;
273 }
274
275
276 /**
277 * Destroy the contexts and surfaces that are linked to the display.
278 */
279 void
280 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
281 {
282 _EGLResource *list;
283
284 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
285 while (list) {
286 _EGLContext *ctx = (_EGLContext *) list;
287 list = list->Next;
288
289 _eglUnlinkContext(ctx);
290 drv->API.DestroyContext(drv, display, ctx);
291 }
292 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
293
294 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
295 while (list) {
296 _EGLSurface *surf = (_EGLSurface *) list;
297 list = list->Next;
298
299 _eglUnlinkSurface(surf);
300 drv->API.DestroySurface(drv, display, surf);
301 }
302 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
303 }
304
305
306 /**
307 * Free all the data hanging of an _EGLDisplay object, but not
308 * the object itself.
309 */
310 void
311 _eglCleanupDisplay(_EGLDisplay *disp)
312 {
313 if (disp->Configs) {
314 _eglDestroyArray(disp->Configs, free);
315 disp->Configs = NULL;
316 }
317
318 /* XXX incomplete */
319 }
320
321
322 /**
323 * Return EGL_TRUE if the given handle is a valid handle to a display.
324 */
325 EGLBoolean
326 _eglCheckDisplayHandle(EGLDisplay dpy)
327 {
328 _EGLDisplay *cur;
329
330 mtx_lock(_eglGlobal.Mutex);
331 cur = _eglGlobal.DisplayList;
332 while (cur) {
333 if (cur == (_EGLDisplay *) dpy)
334 break;
335 cur = cur->Next;
336 }
337 mtx_unlock(_eglGlobal.Mutex);
338 return (cur != NULL);
339 }
340
341
342 /**
343 * Return EGL_TRUE if the given resource is valid. That is, the display does
344 * own the resource.
345 */
346 EGLBoolean
347 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
348 {
349 _EGLResource *list = dpy->ResourceLists[type];
350
351 if (!res)
352 return EGL_FALSE;
353
354 while (list) {
355 if (res == (void *) list) {
356 assert(list->Display == dpy);
357 break;
358 }
359 list = list->Next;
360 }
361
362 return (list != NULL);
363 }
364
365
366 /**
367 * Initialize a display resource. The size of the subclass object is
368 * specified.
369 *
370 * This is supposed to be called from the initializers of subclasses, such as
371 * _eglInitContext or _eglInitSurface.
372 */
373 void
374 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
375 {
376 memset(res, 0, size);
377 res->Display = dpy;
378 res->RefCount = 1;
379 }
380
381
382 /**
383 * Increment reference count for the resource.
384 */
385 void
386 _eglGetResource(_EGLResource *res)
387 {
388 assert(res && res->RefCount > 0);
389 /* hopefully a resource is always manipulated with its display locked */
390 res->RefCount++;
391 }
392
393
394 /**
395 * Decrement reference count for the resource.
396 */
397 EGLBoolean
398 _eglPutResource(_EGLResource *res)
399 {
400 assert(res && res->RefCount > 0);
401 res->RefCount--;
402 return (!res->RefCount);
403 }
404
405
406 /**
407 * Link a resource to its display.
408 */
409 void
410 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
411 {
412 assert(res->Display);
413
414 res->IsLinked = EGL_TRUE;
415 res->Next = res->Display->ResourceLists[type];
416 res->Display->ResourceLists[type] = res;
417 _eglGetResource(res);
418 }
419
420
421 /**
422 * Unlink a linked resource from its display.
423 */
424 void
425 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
426 {
427 _EGLResource *prev;
428
429 prev = res->Display->ResourceLists[type];
430 if (prev != res) {
431 while (prev) {
432 if (prev->Next == res)
433 break;
434 prev = prev->Next;
435 }
436 assert(prev);
437 prev->Next = res->Next;
438 }
439 else {
440 res->Display->ResourceLists[type] = res->Next;
441 }
442
443 res->Next = NULL;
444 res->IsLinked = EGL_FALSE;
445 _eglPutResource(res);
446
447 /* We always unlink before destroy. The driver still owns a reference */
448 assert(res->RefCount);
449 }
450
451 #ifdef HAVE_X11_PLATFORM
452 static EGLBoolean
453 _eglParseX11DisplayAttribList(const EGLint *attrib_list)
454 {
455 int i;
456
457 if (attrib_list == NULL) {
458 return EGL_TRUE;
459 }
460
461 for (i = 0; attrib_list[i] != EGL_NONE; i += 2) {
462 EGLint attrib = attrib_list[i];
463 EGLint value = attrib_list[i + 1];
464
465 /* EGL_EXT_platform_x11 recognizes exactly one attribute,
466 * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
467 *
468 * Mesa supports connecting to only the default screen, so we reject
469 * screen != 0.
470 */
471 if (attrib != EGL_PLATFORM_X11_SCREEN_EXT || value != 0) {
472 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
473 return EGL_FALSE;
474 }
475 }
476
477 return EGL_TRUE;
478 }
479
480 _EGLDisplay*
481 _eglGetX11Display(Display *native_display,
482 const EGLint *attrib_list)
483 {
484 if (!_eglParseX11DisplayAttribList(attrib_list)) {
485 return NULL;
486 }
487
488 return _eglFindDisplay(_EGL_PLATFORM_X11, native_display);
489 }
490 #endif /* HAVE_X11_PLATFORM */
491
492 #ifdef HAVE_DRM_PLATFORM
493 _EGLDisplay*
494 _eglGetGbmDisplay(struct gbm_device *native_display,
495 const EGLint *attrib_list)
496 {
497 /* EGL_MESA_platform_gbm recognizes no attributes. */
498 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
499 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
500 return NULL;
501 }
502
503 return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display);
504 }
505 #endif /* HAVE_DRM_PLATFORM */
506
507 #ifdef HAVE_WAYLAND_PLATFORM
508 _EGLDisplay*
509 _eglGetWaylandDisplay(struct wl_display *native_display,
510 const EGLint *attrib_list)
511 {
512 /* EGL_EXT_platform_wayland recognizes no attributes. */
513 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
514 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
515 return NULL;
516 }
517
518 return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display);
519 }
520 #endif /* HAVE_WAYLAND_PLATFORM */