• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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