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