egl: add missing #include
[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 <unistd.h>
39 #include <fcntl.h>
40 #include "c11/threads.h"
41 #include "util/u_atomic.h"
42
43 #include "eglcontext.h"
44 #include "eglcurrent.h"
45 #include "eglsurface.h"
46 #include "egldevice.h"
47 #include "egldisplay.h"
48 #include "egldriver.h"
49 #include "eglglobals.h"
50 #include "egllog.h"
51 #include "eglimage.h"
52 #include "eglsync.h"
53
54 /* Includes for _eglNativePlatformDetectNativeDisplay */
55 #ifdef HAVE_WAYLAND_PLATFORM
56 #include <wayland-client.h>
57 #endif
58 #ifdef HAVE_DRM_PLATFORM
59 #include <gbm.h>
60 #endif
61
62
63 /**
64 * Map build-system platform names to platform types.
65 */
66 static const struct {
67 _EGLPlatformType platform;
68 const char *name;
69 } egl_platforms[_EGL_NUM_PLATFORMS] = {
70 { _EGL_PLATFORM_X11, "x11" },
71 { _EGL_PLATFORM_WAYLAND, "wayland" },
72 { _EGL_PLATFORM_DRM, "drm" },
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 * Try detecting native platform with the help of native display characteristcs.
109 */
110 static _EGLPlatformType
111 _eglNativePlatformDetectNativeDisplay(void *nativeDisplay)
112 {
113 if (nativeDisplay == EGL_DEFAULT_DISPLAY)
114 return _EGL_INVALID_PLATFORM;
115
116 if (_eglPointerIsDereferencable(nativeDisplay)) {
117 void *first_pointer = *(void **) nativeDisplay;
118
119 (void) first_pointer; /* silence unused var warning */
120
121 #ifdef HAVE_WAYLAND_PLATFORM
122 /* wl_display is a wl_proxy, which is a wl_object.
123 * wl_object's first element points to the interfacetype. */
124 if (first_pointer == &wl_display_interface)
125 return _EGL_PLATFORM_WAYLAND;
126 #endif
127
128 #ifdef HAVE_DRM_PLATFORM
129 /* gbm has a pointer to its constructor as first element. */
130 if (first_pointer == gbm_create_device)
131 return _EGL_PLATFORM_DRM;
132 #endif
133
134 #ifdef HAVE_X11_PLATFORM
135 /* If not matched to any other platform, fallback to x11. */
136 return _EGL_PLATFORM_X11;
137 #endif
138
139 #ifdef HAVE_HAIKU_PLATFORM
140 return _EGL_PLATFORM_HAIKU;
141 #endif
142 }
143
144 return _EGL_INVALID_PLATFORM;
145 }
146
147
148 /**
149 * Return the native platform. It is the platform of the EGL native types.
150 */
151 _EGLPlatformType
152 _eglGetNativePlatform(void *nativeDisplay)
153 {
154 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
155 _EGLPlatformType detected_platform = native_platform;
156
157 if (detected_platform == _EGL_INVALID_PLATFORM) {
158 const char *detection_method;
159
160 detected_platform = _eglGetNativePlatformFromEnv();
161 detection_method = "environment overwrite";
162
163 if (detected_platform == _EGL_INVALID_PLATFORM) {
164 detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
165 detection_method = "autodetected";
166 }
167
168 if (detected_platform == _EGL_INVALID_PLATFORM) {
169 detected_platform = _EGL_NATIVE_PLATFORM;
170 detection_method = "build-time configuration";
171 }
172
173 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
174 egl_platforms[detected_platform].name, detection_method);
175
176 p_atomic_cmpxchg(&native_platform, _EGL_INVALID_PLATFORM,
177 detected_platform);
178 }
179
180 return native_platform;
181 }
182
183
184 /**
185 * Finish display management.
186 */
187 void
188 _eglFiniDisplay(void)
189 {
190 _EGLDisplay *dispList, *disp;
191
192 /* atexit function is called with global mutex locked */
193 dispList = _eglGlobal.DisplayList;
194 while (dispList) {
195 EGLint i;
196
197 /* pop list head */
198 disp = dispList;
199 dispList = dispList->Next;
200
201 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
202 if (disp->ResourceLists[i]) {
203 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", disp);
204 break;
205 }
206 }
207
208
209 /* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
210 * and invalid one is 0.
211 */
212 if (disp->Options.fd)
213 close(disp->Options.fd);
214
215 free(disp->Options.Attribs);
216 free(disp);
217 }
218 _eglGlobal.DisplayList = NULL;
219 }
220
221 static EGLBoolean
222 _eglSameAttribs(const EGLAttrib *a, const EGLAttrib *b)
223 {
224 size_t na = _eglNumAttribs(a);
225 size_t nb = _eglNumAttribs(b);
226
227 /* different numbers of attributes must be different */
228 if (na != nb)
229 return EGL_FALSE;
230
231 /* both lists NULL are the same */
232 if (!a && !b)
233 return EGL_TRUE;
234
235 /* otherwise, compare the lists */
236 return memcmp(a, b, na * sizeof(a[0])) == 0 ? EGL_TRUE : EGL_FALSE;
237 }
238
239 /**
240 * Find the display corresponding to the specified native display, or create a
241 * new one. EGL 1.5 says:
242 *
243 * Multiple calls made to eglGetPlatformDisplay with the same parameters
244 * will return the same EGLDisplay handle.
245 *
246 * We read this extremely strictly, and treat a call with NULL attribs as
247 * different from a call with attribs only equal to { EGL_NONE }. Similarly
248 * we do not sort the attribute list, so even if all attribute _values_ are
249 * identical, different attribute orders will be considered different
250 * parameters.
251 */
252 _EGLDisplay *
253 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy,
254 const EGLAttrib *attrib_list)
255 {
256 _EGLDisplay *disp;
257 size_t num_attribs;
258
259 if (plat == _EGL_INVALID_PLATFORM)
260 return NULL;
261
262 mtx_lock(_eglGlobal.Mutex);
263
264 /* search the display list first */
265 disp = _eglGlobal.DisplayList;
266 while (disp) {
267 if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy &&
268 _eglSameAttribs(disp->Options.Attribs, attrib_list))
269 break;
270 disp = disp->Next;
271 }
272
273 /* create a new display */
274 if (!disp) {
275 disp = calloc(1, sizeof(_EGLDisplay));
276 if (disp) {
277 mtx_init(&disp->Mutex, mtx_plain);
278 disp->Platform = plat;
279 disp->PlatformDisplay = plat_dpy;
280 num_attribs = _eglNumAttribs(attrib_list);
281 if (num_attribs) {
282 disp->Options.Attribs = calloc(num_attribs, sizeof(EGLAttrib));
283 if (!disp->Options.Attribs) {
284 free(disp);
285 disp = NULL;
286 goto out;
287 }
288 memcpy(disp->Options.Attribs, attrib_list,
289 num_attribs * sizeof(EGLAttrib));
290 }
291 /* add to the display list */
292 disp->Next = _eglGlobal.DisplayList;
293 _eglGlobal.DisplayList = disp;
294 }
295 }
296
297 out:
298 mtx_unlock(_eglGlobal.Mutex);
299
300 return disp;
301 }
302
303
304 /**
305 * Destroy the contexts and surfaces that are linked to the display.
306 */
307 void
308 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
309 {
310 _EGLResource *list;
311
312 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
313 while (list) {
314 _EGLContext *ctx = (_EGLContext *) list;
315 list = list->Next;
316
317 _eglUnlinkContext(ctx);
318 drv->API.DestroyContext(drv, display, ctx);
319 }
320 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
321
322 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
323 while (list) {
324 _EGLSurface *surf = (_EGLSurface *) list;
325 list = list->Next;
326
327 _eglUnlinkSurface(surf);
328 drv->API.DestroySurface(drv, display, surf);
329 }
330 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
331
332 list = display->ResourceLists[_EGL_RESOURCE_IMAGE];
333 while (list) {
334 _EGLImage *image = (_EGLImage *) list;
335 list = list->Next;
336
337 _eglUnlinkImage(image);
338 drv->API.DestroyImageKHR(drv, display, image);
339 }
340 assert(!display->ResourceLists[_EGL_RESOURCE_IMAGE]);
341
342 list = display->ResourceLists[_EGL_RESOURCE_SYNC];
343 while (list) {
344 _EGLSync *sync = (_EGLSync *) list;
345 list = list->Next;
346
347 _eglUnlinkSync(sync);
348 drv->API.DestroySyncKHR(drv, display, sync);
349 }
350 assert(!display->ResourceLists[_EGL_RESOURCE_SYNC]);
351 }
352
353
354 /**
355 * Free all the data hanging of an _EGLDisplay object, but not
356 * the object itself.
357 */
358 void
359 _eglCleanupDisplay(_EGLDisplay *disp)
360 {
361 if (disp->Configs) {
362 _eglDestroyArray(disp->Configs, free);
363 disp->Configs = NULL;
364 }
365
366 /* XXX incomplete */
367 }
368
369
370 /**
371 * Return EGL_TRUE if the given handle is a valid handle to a display.
372 */
373 EGLBoolean
374 _eglCheckDisplayHandle(EGLDisplay dpy)
375 {
376 _EGLDisplay *cur;
377
378 mtx_lock(_eglGlobal.Mutex);
379 cur = _eglGlobal.DisplayList;
380 while (cur) {
381 if (cur == (_EGLDisplay *) dpy)
382 break;
383 cur = cur->Next;
384 }
385 mtx_unlock(_eglGlobal.Mutex);
386 return (cur != NULL);
387 }
388
389
390 /**
391 * Return EGL_TRUE if the given resource is valid. That is, the display does
392 * own the resource.
393 */
394 EGLBoolean
395 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *disp)
396 {
397 _EGLResource *list = disp->ResourceLists[type];
398
399 if (!res)
400 return EGL_FALSE;
401
402 while (list) {
403 if (res == (void *) list) {
404 assert(list->Display == disp);
405 break;
406 }
407 list = list->Next;
408 }
409
410 return (list != NULL);
411 }
412
413
414 /**
415 * Initialize a display resource. The size of the subclass object is
416 * specified.
417 *
418 * This is supposed to be called from the initializers of subclasses, such as
419 * _eglInitContext or _eglInitSurface.
420 */
421 void
422 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *disp)
423 {
424 memset(res, 0, size);
425 res->Display = disp;
426 res->RefCount = 1;
427 }
428
429
430 /**
431 * Increment reference count for the resource.
432 */
433 void
434 _eglGetResource(_EGLResource *res)
435 {
436 assert(res && res->RefCount > 0);
437 /* hopefully a resource is always manipulated with its display locked */
438 res->RefCount++;
439 }
440
441
442 /**
443 * Decrement reference count for the resource.
444 */
445 EGLBoolean
446 _eglPutResource(_EGLResource *res)
447 {
448 assert(res && res->RefCount > 0);
449 res->RefCount--;
450 return (!res->RefCount);
451 }
452
453
454 /**
455 * Link a resource to its display.
456 */
457 void
458 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
459 {
460 assert(res->Display);
461
462 res->IsLinked = EGL_TRUE;
463 res->Next = res->Display->ResourceLists[type];
464 res->Display->ResourceLists[type] = res;
465 _eglGetResource(res);
466 }
467
468
469 /**
470 * Unlink a linked resource from its display.
471 */
472 void
473 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
474 {
475 _EGLResource *prev;
476
477 prev = res->Display->ResourceLists[type];
478 if (prev != res) {
479 while (prev) {
480 if (prev->Next == res)
481 break;
482 prev = prev->Next;
483 }
484 assert(prev);
485 prev->Next = res->Next;
486 }
487 else {
488 res->Display->ResourceLists[type] = res->Next;
489 }
490
491 res->Next = NULL;
492 res->IsLinked = EGL_FALSE;
493 _eglPutResource(res);
494
495 /* We always unlink before destroy. The driver still owns a reference */
496 assert(res->RefCount);
497 }
498
499 #ifdef HAVE_X11_PLATFORM
500 _EGLDisplay*
501 _eglGetX11Display(Display *native_display,
502 const EGLAttrib *attrib_list)
503 {
504 /* EGL_EXT_platform_x11 recognizes exactly one attribute,
505 * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
506 */
507 if (attrib_list != NULL) {
508 for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
509 if (attrib_list[i] != EGL_PLATFORM_X11_SCREEN_EXT) {
510 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
511 return NULL;
512 }
513 }
514 }
515 return _eglFindDisplay(_EGL_PLATFORM_X11, native_display, attrib_list);
516 }
517 #endif /* HAVE_X11_PLATFORM */
518
519 #ifdef HAVE_DRM_PLATFORM
520 _EGLDisplay*
521 _eglGetGbmDisplay(struct gbm_device *native_display,
522 const EGLAttrib *attrib_list)
523 {
524 /* EGL_MESA_platform_gbm recognizes no attributes. */
525 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
526 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
527 return NULL;
528 }
529
530 return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display, attrib_list);
531 }
532 #endif /* HAVE_DRM_PLATFORM */
533
534 #ifdef HAVE_WAYLAND_PLATFORM
535 _EGLDisplay*
536 _eglGetWaylandDisplay(struct wl_display *native_display,
537 const EGLAttrib *attrib_list)
538 {
539 /* EGL_EXT_platform_wayland recognizes no attributes. */
540 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
541 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
542 return NULL;
543 }
544
545 return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display, attrib_list);
546 }
547 #endif /* HAVE_WAYLAND_PLATFORM */
548
549 #ifdef HAVE_SURFACELESS_PLATFORM
550 _EGLDisplay*
551 _eglGetSurfacelessDisplay(void *native_display,
552 const EGLAttrib *attrib_list)
553 {
554 /* This platform has no native display. */
555 if (native_display != NULL) {
556 _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
557 return NULL;
558 }
559
560 /* This platform recognizes no display attributes. */
561 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
562 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
563 return NULL;
564 }
565
566 return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, native_display,
567 attrib_list);
568 }
569 #endif /* HAVE_SURFACELESS_PLATFORM */
570
571
572 _EGLDisplay*
573 _eglGetDeviceDisplay(void *native_display,
574 const EGLAttrib *attrib_list)
575 {
576 _EGLDevice *dev;
577 _EGLDisplay *display;
578 int fd = -1;
579
580 dev = _eglLookupDevice(native_display);
581 if (!dev) {
582 _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
583 return NULL;
584 }
585
586 if (attrib_list) {
587 for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
588 EGLAttrib attrib = attrib_list[i];
589 EGLAttrib value = attrib_list[i + 1];
590
591 /* EGL_EXT_platform_device does not recognize any attributes,
592 * EGL_EXT_device_drm adds the optional EGL_DRM_MASTER_FD_EXT.
593 */
594
595 if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM) ||
596 attrib != EGL_DRM_MASTER_FD_EXT) {
597 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
598 return NULL;
599 }
600
601 fd = (int) value;
602 }
603 }
604
605 display = _eglFindDisplay(_EGL_PLATFORM_DEVICE, native_display, attrib_list);
606 if (!display) {
607 _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
608 return NULL;
609 }
610
611 /* If the fd is explicitly provided and we did not dup() it yet, do so.
612 * The spec mandates that we do so, since we'll need it past the
613 * eglGetPlatformDispay call.
614 *
615 * The new fd is guaranteed to be 3 or greater.
616 */
617 if (fd != -1 && display->Options.fd == 0) {
618 display->Options.fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
619 if (display->Options.fd == -1) {
620 /* Do not (really) need to teardown the display */
621 _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
622 return NULL;
623 }
624 }
625
626 return display;
627 }