egldisplay.c revision 01e04c3f
11.1Sjmcneill/**************************************************************************
21.1Sjmcneill *
31.1Sjmcneill * Copyright 2008 VMware, Inc.
41.1Sjmcneill * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
51.1Sjmcneill * Copyright 2010-2011 LunarG, Inc.
61.1Sjmcneill * All Rights Reserved.
71.1Sjmcneill *
81.1Sjmcneill * Permission is hereby granted, free of charge, to any person obtaining a
91.1Sjmcneill * copy of this software and associated documentation files (the
101.1Sjmcneill * "Software"), to deal in the Software without restriction, including
111.1Sjmcneill * without limitation the rights to use, copy, modify, merge, publish,
121.1Sjmcneill * distribute, sub license, and/or sell copies of the Software, and to
131.1Sjmcneill * permit persons to whom the Software is furnished to do so, subject to
141.1Sjmcneill * the following conditions:
151.1Sjmcneill *
161.1Sjmcneill * The above copyright notice and this permission notice (including the
171.1Sjmcneill * next paragraph) shall be included in all copies or substantial portions
181.1Sjmcneill * of the Software.
191.1Sjmcneill *
201.1Sjmcneill * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
211.1Sjmcneill * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
221.1Sjmcneill * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
231.1Sjmcneill * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
241.1Sjmcneill * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
251.1Sjmcneill * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
261.1Sjmcneill * DEALINGS IN THE SOFTWARE.
271.1Sjmcneill *
281.1Sjmcneill **************************************************************************/
291.1Sjmcneill
301.1Sjmcneill
311.1Sjmcneill/**
321.1Sjmcneill * Functions related to EGLDisplay.
331.1Sjmcneill */
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 */
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 *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 *
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 */
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 *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 */
370void
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 */
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