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