egldisplay.c revision 7e102996
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 build-system platform names to platform types.
62 */
63static 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 */
79static _EGLPlatformType
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 */
107static _EGLPlatformType
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
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 */
184void
185_eglFiniDisplay(void)
186{
187   _EGLDisplay *dispList, *disp;
188
189   /* atexit function is called with global mutex locked */
190   dispList = _eglGlobal.DisplayList;
191   while (dispList) {
192      EGLint i;
193
194      /* pop list head */
195      disp = dispList;
196      dispList = dispList->Next;
197
198      for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
199         if (disp->ResourceLists[i]) {
200            _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", disp);
201            break;
202         }
203      }
204
205      free(disp);
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 *
216_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
217{
218   _EGLDisplay *disp;
219
220   if (plat == _EGL_INVALID_PLATFORM)
221      return NULL;
222
223   mtx_lock(_eglGlobal.Mutex);
224
225   /* search the display list first */
226   disp = _eglGlobal.DisplayList;
227   while (disp) {
228      if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy)
229         break;
230      disp = disp->Next;
231   }
232
233   /* create a new display */
234   if (!disp) {
235      disp = calloc(1, sizeof(_EGLDisplay));
236      if (disp) {
237         mtx_init(&disp->Mutex, mtx_plain);
238         disp->Platform = plat;
239         disp->PlatformDisplay = plat_dpy;
240
241         /* add to the display list */
242         disp->Next = _eglGlobal.DisplayList;
243         _eglGlobal.DisplayList = disp;
244      }
245   }
246
247   mtx_unlock(_eglGlobal.Mutex);
248
249   return disp;
250}
251
252
253/**
254 * Destroy the contexts and surfaces that are linked to the display.
255 */
256void
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 */
307void
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 */
322EGLBoolean
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 */
343EGLBoolean
344_eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *disp)
345{
346   _EGLResource *list = disp->ResourceLists[type];
347
348   if (!res)
349      return EGL_FALSE;
350
351   while (list) {
352      if (res == (void *) list) {
353         assert(list->Display == disp);
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 */
370void
371_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *disp)
372{
373   memset(res, 0, size);
374   res->Display = disp;
375   res->RefCount = 1;
376}
377
378
379/**
380 * Increment reference count for the resource.
381 */
382void
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 */
394EGLBoolean
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 */
406void
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 */
421void
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
449static EGLBoolean
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*
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*
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*
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*
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