egl: add null platform
[mesa.git] / src / egl / main / egldisplay.c
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
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
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
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 #ifdef HAVE_WAYLAND_PLATFORM
161 /* wl_display is a wl_proxy, which is a wl_object.
162 * wl_object's first element points to the interfacetype. */
163 if (first_pointer == &wl_display_interface)
164 return _EGL_PLATFORM_WAYLAND;
165 #endif
166
167 #ifdef HAVE_DRM_PLATFORM
168 /* gbm has a pointer to its constructor as first element. */
169 if (first_pointer == gbm_create_device)
170 return _EGL_PLATFORM_DRM;
171 #endif
172
173 #ifdef HAVE_X11_PLATFORM
174 /* If not matched to any other platform, fallback to x11. */
175 return _EGL_PLATFORM_X11;
176 #endif
177 }
178
179 return _EGL_INVALID_PLATFORM;
180 }
181
182
183 /**
184 * Return the native platform. It is the platform of the EGL native types.
185 */
186 _EGLPlatformType
187 _eglGetNativePlatform(EGLNativeDisplayType nativeDisplay)
188 {
189 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
190 char *detection_method = NULL;
191
192 if (native_platform == _EGL_INVALID_PLATFORM) {
193 native_platform = _eglGetNativePlatformFromEnv();
194 detection_method = "environment overwrite";
195 if (native_platform == _EGL_INVALID_PLATFORM) {
196 native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
197 detection_method = "autodetected";
198 if (native_platform == _EGL_INVALID_PLATFORM) {
199 native_platform = _EGL_NATIVE_PLATFORM;
200 detection_method = "build-time configuration";
201 }
202 }
203 }
204
205 if (detection_method != NULL)
206 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
207 egl_platforms[native_platform].name, detection_method);
208
209 return native_platform;
210 }
211
212
213 /**
214 * Finish display management.
215 */
216 void
217 _eglFiniDisplay(void)
218 {
219 _EGLDisplay *dpyList, *dpy;
220
221 /* atexit function is called with global mutex locked */
222 dpyList = _eglGlobal.DisplayList;
223 while (dpyList) {
224 EGLint i;
225
226 /* pop list head */
227 dpy = dpyList;
228 dpyList = dpyList->Next;
229
230 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
231 if (dpy->ResourceLists[i]) {
232 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
233 break;
234 }
235 }
236
237 free(dpy);
238 }
239 _eglGlobal.DisplayList = NULL;
240 }
241
242
243 /**
244 * Find the display corresponding to the specified native display, or create a
245 * new one.
246 */
247 _EGLDisplay *
248 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
249 {
250 _EGLDisplay *dpy;
251
252 if (plat == _EGL_INVALID_PLATFORM)
253 return NULL;
254
255 _eglLockMutex(_eglGlobal.Mutex);
256
257 /* search the display list first */
258 dpy = _eglGlobal.DisplayList;
259 while (dpy) {
260 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
261 break;
262 dpy = dpy->Next;
263 }
264
265 /* create a new display */
266 if (!dpy) {
267 dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
268 if (dpy) {
269 _eglInitMutex(&dpy->Mutex);
270 dpy->Platform = plat;
271 dpy->PlatformDisplay = plat_dpy;
272
273 /* add to the display list */
274 dpy->Next = _eglGlobal.DisplayList;
275 _eglGlobal.DisplayList = dpy;
276 }
277 }
278
279 _eglUnlockMutex(_eglGlobal.Mutex);
280
281 return dpy;
282 }
283
284
285 /**
286 * Destroy the contexts and surfaces that are linked to the display.
287 */
288 void
289 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
290 {
291 _EGLResource *list;
292
293 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
294 while (list) {
295 _EGLContext *ctx = (_EGLContext *) list;
296 list = list->Next;
297
298 _eglUnlinkContext(ctx);
299 drv->API.DestroyContext(drv, display, ctx);
300 }
301 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
302
303 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
304 while (list) {
305 _EGLSurface *surf = (_EGLSurface *) list;
306 list = list->Next;
307
308 _eglUnlinkSurface(surf);
309 drv->API.DestroySurface(drv, display, surf);
310 }
311 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
312 }
313
314
315 /**
316 * Free all the data hanging of an _EGLDisplay object, but not
317 * the object itself.
318 */
319 void
320 _eglCleanupDisplay(_EGLDisplay *disp)
321 {
322 if (disp->Configs) {
323 _eglDestroyArray(disp->Configs, free);
324 disp->Configs = NULL;
325 }
326
327 /* XXX incomplete */
328 }
329
330
331 /**
332 * Return EGL_TRUE if the given handle is a valid handle to a display.
333 */
334 EGLBoolean
335 _eglCheckDisplayHandle(EGLDisplay dpy)
336 {
337 _EGLDisplay *cur;
338
339 _eglLockMutex(_eglGlobal.Mutex);
340 cur = _eglGlobal.DisplayList;
341 while (cur) {
342 if (cur == (_EGLDisplay *) dpy)
343 break;
344 cur = cur->Next;
345 }
346 _eglUnlockMutex(_eglGlobal.Mutex);
347 return (cur != NULL);
348 }
349
350
351 /**
352 * Return EGL_TRUE if the given resource is valid. That is, the display does
353 * own the resource.
354 */
355 EGLBoolean
356 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
357 {
358 _EGLResource *list = dpy->ResourceLists[type];
359
360 if (!res)
361 return EGL_FALSE;
362
363 while (list) {
364 if (res == (void *) list) {
365 assert(list->Display == dpy);
366 break;
367 }
368 list = list->Next;
369 }
370
371 return (list != NULL);
372 }
373
374
375 /**
376 * Initialize a display resource.
377 */
378 void
379 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
380 {
381 memset(res, 0, size);
382 res->Display = dpy;
383 res->RefCount = 1;
384 }
385
386
387 /**
388 * Increment reference count for the resource.
389 */
390 void
391 _eglGetResource(_EGLResource *res)
392 {
393 assert(res && res->RefCount > 0);
394 /* hopefully a resource is always manipulated with its display locked */
395 res->RefCount++;
396 }
397
398
399 /**
400 * Decrement reference count for the resource.
401 */
402 EGLBoolean
403 _eglPutResource(_EGLResource *res)
404 {
405 assert(res && res->RefCount > 0);
406 res->RefCount--;
407 return (!res->RefCount);
408 }
409
410
411 /**
412 * Link a resource to its display.
413 */
414 void
415 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
416 {
417 assert(res->Display);
418
419 res->IsLinked = EGL_TRUE;
420 res->Next = res->Display->ResourceLists[type];
421 res->Display->ResourceLists[type] = res;
422 _eglGetResource(res);
423 }
424
425
426 /**
427 * Unlink a linked resource from its display.
428 */
429 void
430 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
431 {
432 _EGLResource *prev;
433
434 prev = res->Display->ResourceLists[type];
435 if (prev != res) {
436 while (prev) {
437 if (prev->Next == res)
438 break;
439 prev = prev->Next;
440 }
441 assert(prev);
442 prev->Next = res->Next;
443 }
444 else {
445 res->Display->ResourceLists[type] = res->Next;
446 }
447
448 res->Next = NULL;
449 res->IsLinked = EGL_FALSE;
450 _eglPutResource(res);
451
452 /* We always unlink before destroy. The driver still owns a reference */
453 assert(res->RefCount);
454 }