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