1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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 "eglcontext.h"
39 #include "eglsurface.h"
40 #include "egldisplay.h"
41 #include "egldriver.h"
42 #include "eglglobals.h"
43 #include "eglmutex.h"
44 #include "egllog.h"
45
46 /* Includes for _eglNativePlatformDetectNativeDisplay */
47 #ifdef HAVE_MINCORE
48 #include <unistd.h>
49 #include <sys/mman.h>
50 #endif
51 #ifdef HAVE_WAYLAND_PLATFORM
52 #include <wayland-client.h>
53 #endif
54 #ifdef HAVE_DRM_PLATFORM
55 #include <gbm.h>
56 #endif
57 #ifdef HAVE_FBDEV_PLATFORM
58 #include <stdint.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #endif
62
63
64 /**
65 * Map --with-egl-platforms names to platform types.
66 */
67 static const struct {
68 _EGLPlatformType platform;
69 const char *name;
70 } egl_platforms[_EGL_NUM_PLATFORMS] = {
71 { _EGL_PLATFORM_WINDOWS, "gdi" },
72 { _EGL_PLATFORM_X11, "x11" },
73 { _EGL_PLATFORM_WAYLAND, "wayland" },
74 { _EGL_PLATFORM_DRM, "drm" },
75 { _EGL_PLATFORM_FBDEV, "fbdev" },
76 { _EGL_PLATFORM_NULL, "null" },
77 { _EGL_PLATFORM_ANDROID, "android" }
78 };
79
80
81 /**
82 * Return the native platform by parsing EGL_PLATFORM.
83 */
84 static _EGLPlatformType
_eglGetNativePlatformFromEnv(void)85 _eglGetNativePlatformFromEnv(void)
86 {
87 _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
88 const char *plat_name;
89 EGLint i;
90
91 plat_name = getenv("EGL_PLATFORM");
92 /* try deprecated env variable */
93 if (!plat_name || !plat_name[0])
94 plat_name = getenv("EGL_DISPLAY");
95 if (!plat_name || !plat_name[0])
96 return _EGL_INVALID_PLATFORM;
97
98 for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
99 if (strcmp(egl_platforms[i].name, plat_name) == 0) {
100 plat = egl_platforms[i].platform;
101 break;
102 }
103 }
104
105 return plat;
106 }
107
108
109 /**
110 * Perform validity checks on a generic pointer.
111 */
112 static EGLBoolean
_eglPointerIsDereferencable(void * p)113 _eglPointerIsDereferencable(void *p)
114 {
115 #ifdef HAVE_MINCORE
116 uintptr_t addr = (uintptr_t) p;
117 unsigned char valid = 0;
118 const long page_size = getpagesize();
119
120 if (p == NULL)
121 return EGL_FALSE;
122
123 /* align addr to page_size */
124 addr &= ~(page_size - 1);
125
126 if (mincore((void *) addr, page_size, &valid) < 0) {
127 _eglLog(_EGL_DEBUG, "mincore failed: %m");
128 return EGL_FALSE;
129 }
130
131 return (valid & 0x01) == 0x01;
132 #else
133 return p != NULL;
134 #endif
135 }
136
137
138 /**
139 * Try detecting native platform with the help of native display characteristcs.
140 */
141 static _EGLPlatformType
_eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay)142 _eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay)
143 {
144 #ifdef HAVE_FBDEV_PLATFORM
145 struct stat buf;
146 #endif
147
148 if (nativeDisplay == EGL_DEFAULT_DISPLAY)
149 return _EGL_INVALID_PLATFORM;
150
151 #ifdef HAVE_FBDEV_PLATFORM
152 /* fbdev is the only platform that can be a file descriptor. */
153 if (fstat((intptr_t) nativeDisplay, &buf) == 0 && S_ISCHR(buf.st_mode))
154 return _EGL_PLATFORM_FBDEV;
155 #endif
156
157 if (_eglPointerIsDereferencable(nativeDisplay)) {
158 void *first_pointer = *(void **) nativeDisplay;
159
160 (void) first_pointer; /* silence unused var warning */
161
162 #ifdef HAVE_WAYLAND_PLATFORM
163 /* wl_display is a wl_proxy, which is a wl_object.
164 * wl_object's first element points to the interfacetype. */
165 if (first_pointer == &wl_display_interface)
166 return _EGL_PLATFORM_WAYLAND;
167 #endif
168
169 #ifdef HAVE_DRM_PLATFORM
170 /* gbm has a pointer to its constructor as first element. */
171 if (first_pointer == gbm_create_device)
172 return _EGL_PLATFORM_DRM;
173 #endif
174
175 #ifdef HAVE_X11_PLATFORM
176 /* If not matched to any other platform, fallback to x11. */
177 return _EGL_PLATFORM_X11;
178 #endif
179 }
180
181 return _EGL_INVALID_PLATFORM;
182 }
183
184
185 /**
186 * Return the native platform. It is the platform of the EGL native types.
187 */
188 _EGLPlatformType
_eglGetNativePlatform(EGLNativeDisplayType nativeDisplay)189 _eglGetNativePlatform(EGLNativeDisplayType nativeDisplay)
190 {
191 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
192 char *detection_method = NULL;
193
194 if (native_platform == _EGL_INVALID_PLATFORM) {
195 native_platform = _eglGetNativePlatformFromEnv();
196 detection_method = "environment overwrite";
197 if (native_platform == _EGL_INVALID_PLATFORM) {
198 native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
199 detection_method = "autodetected";
200 if (native_platform == _EGL_INVALID_PLATFORM) {
201 native_platform = _EGL_NATIVE_PLATFORM;
202 detection_method = "build-time configuration";
203 }
204 }
205 }
206
207 if (detection_method != NULL)
208 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
209 egl_platforms[native_platform].name, detection_method);
210
211 return native_platform;
212 }
213
214
215 /**
216 * Finish display management.
217 */
218 void
_eglFiniDisplay(void)219 _eglFiniDisplay(void)
220 {
221 _EGLDisplay *dpyList, *dpy;
222
223 /* atexit function is called with global mutex locked */
224 dpyList = _eglGlobal.DisplayList;
225 while (dpyList) {
226 EGLint i;
227
228 /* pop list head */
229 dpy = dpyList;
230 dpyList = dpyList->Next;
231
232 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
233 if (dpy->ResourceLists[i]) {
234 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
235 break;
236 }
237 }
238
239 free(dpy);
240 }
241 _eglGlobal.DisplayList = NULL;
242 }
243
244
245 /**
246 * Find the display corresponding to the specified native display, or create a
247 * new one.
248 */
249 _EGLDisplay *
_eglFindDisplay(_EGLPlatformType plat,void * plat_dpy)250 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
251 {
252 _EGLDisplay *dpy;
253
254 if (plat == _EGL_INVALID_PLATFORM)
255 return NULL;
256
257 _eglLockMutex(_eglGlobal.Mutex);
258
259 /* search the display list first */
260 dpy = _eglGlobal.DisplayList;
261 while (dpy) {
262 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
263 break;
264 dpy = dpy->Next;
265 }
266
267 /* create a new display */
268 if (!dpy) {
269 dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
270 if (dpy) {
271 _eglInitMutex(&dpy->Mutex);
272 dpy->Platform = plat;
273 dpy->PlatformDisplay = plat_dpy;
274
275 /* add to the display list */
276 dpy->Next = _eglGlobal.DisplayList;
277 _eglGlobal.DisplayList = dpy;
278 }
279 }
280
281 _eglUnlockMutex(_eglGlobal.Mutex);
282
283 return dpy;
284 }
285
286
287 /**
288 * Destroy the contexts and surfaces that are linked to the display.
289 */
290 void
_eglReleaseDisplayResources(_EGLDriver * drv,_EGLDisplay * display)291 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
292 {
293 _EGLResource *list;
294
295 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
296 while (list) {
297 _EGLContext *ctx = (_EGLContext *) list;
298 list = list->Next;
299
300 _eglUnlinkContext(ctx);
301 drv->API.DestroyContext(drv, display, ctx);
302 }
303 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
304
305 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
306 while (list) {
307 _EGLSurface *surf = (_EGLSurface *) list;
308 list = list->Next;
309
310 _eglUnlinkSurface(surf);
311 drv->API.DestroySurface(drv, display, surf);
312 }
313 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
314 }
315
316
317 /**
318 * Free all the data hanging of an _EGLDisplay object, but not
319 * the object itself.
320 */
321 void
_eglCleanupDisplay(_EGLDisplay * disp)322 _eglCleanupDisplay(_EGLDisplay *disp)
323 {
324 if (disp->Configs) {
325 _eglDestroyArray(disp->Configs, free);
326 disp->Configs = NULL;
327 }
328
329 /* XXX incomplete */
330 }
331
332
333 /**
334 * Return EGL_TRUE if the given handle is a valid handle to a display.
335 */
336 EGLBoolean
_eglCheckDisplayHandle(EGLDisplay dpy)337 _eglCheckDisplayHandle(EGLDisplay dpy)
338 {
339 _EGLDisplay *cur;
340
341 _eglLockMutex(_eglGlobal.Mutex);
342 cur = _eglGlobal.DisplayList;
343 while (cur) {
344 if (cur == (_EGLDisplay *) dpy)
345 break;
346 cur = cur->Next;
347 }
348 _eglUnlockMutex(_eglGlobal.Mutex);
349 return (cur != NULL);
350 }
351
352
353 /**
354 * Return EGL_TRUE if the given resource is valid. That is, the display does
355 * own the resource.
356 */
357 EGLBoolean
_eglCheckResource(void * res,_EGLResourceType type,_EGLDisplay * dpy)358 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
359 {
360 _EGLResource *list = dpy->ResourceLists[type];
361
362 if (!res)
363 return EGL_FALSE;
364
365 while (list) {
366 if (res == (void *) list) {
367 assert(list->Display == dpy);
368 break;
369 }
370 list = list->Next;
371 }
372
373 return (list != NULL);
374 }
375
376
377 /**
378 * Initialize a display resource.
379 */
380 void
_eglInitResource(_EGLResource * res,EGLint size,_EGLDisplay * dpy)381 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
382 {
383 memset(res, 0, size);
384 res->Display = dpy;
385 res->RefCount = 1;
386 }
387
388
389 /**
390 * Increment reference count for the resource.
391 */
392 void
_eglGetResource(_EGLResource * res)393 _eglGetResource(_EGLResource *res)
394 {
395 assert(res && res->RefCount > 0);
396 /* hopefully a resource is always manipulated with its display locked */
397 res->RefCount++;
398 }
399
400
401 /**
402 * Decrement reference count for the resource.
403 */
404 EGLBoolean
_eglPutResource(_EGLResource * res)405 _eglPutResource(_EGLResource *res)
406 {
407 assert(res && res->RefCount > 0);
408 res->RefCount--;
409 return (!res->RefCount);
410 }
411
412
413 /**
414 * Link a resource to its display.
415 */
416 void
_eglLinkResource(_EGLResource * res,_EGLResourceType type)417 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
418 {
419 assert(res->Display);
420
421 res->IsLinked = EGL_TRUE;
422 res->Next = res->Display->ResourceLists[type];
423 res->Display->ResourceLists[type] = res;
424 _eglGetResource(res);
425 }
426
427
428 /**
429 * Unlink a linked resource from its display.
430 */
431 void
_eglUnlinkResource(_EGLResource * res,_EGLResourceType type)432 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
433 {
434 _EGLResource *prev;
435
436 prev = res->Display->ResourceLists[type];
437 if (prev != res) {
438 while (prev) {
439 if (prev->Next == res)
440 break;
441 prev = prev->Next;
442 }
443 assert(prev);
444 prev->Next = res->Next;
445 }
446 else {
447 res->Display->ResourceLists[type] = res->Next;
448 }
449
450 res->Next = NULL;
451 res->IsLinked = EGL_FALSE;
452 _eglPutResource(res);
453
454 /* We always unlink before destroy. The driver still owns a reference */
455 assert(res->RefCount);
456 }
457