egl_dri2.c revision dbecb413008c19e1864de93d9a8a9123bfee46e7
1/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Kristian Høgsberg <krh@bitplanet.net>
26 */
27
28#include <stdlib.h>
29#include <string.h>
30#include <stdio.h>
31#include <limits.h>
32#include <dlfcn.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <unistd.h>
36#include <xf86drm.h>
37#include <GL/gl.h>
38#include <GL/internal/dri_interface.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41
42#include "egl_dri2.h"
43
44const __DRIuseInvalidateExtension use_invalidate = {
45   { __DRI_USE_INVALIDATE, 1 }
46};
47
48EGLint dri2_to_egl_attribute_map[] = {
49   0,
50   EGL_BUFFER_SIZE,		/* __DRI_ATTRIB_BUFFER_SIZE */
51   EGL_LEVEL,			/* __DRI_ATTRIB_LEVEL */
52   EGL_RED_SIZE,		/* __DRI_ATTRIB_RED_SIZE */
53   EGL_GREEN_SIZE,		/* __DRI_ATTRIB_GREEN_SIZE */
54   EGL_BLUE_SIZE,		/* __DRI_ATTRIB_BLUE_SIZE */
55   EGL_LUMINANCE_SIZE,		/* __DRI_ATTRIB_LUMINANCE_SIZE */
56   EGL_ALPHA_SIZE,		/* __DRI_ATTRIB_ALPHA_SIZE */
57   0,				/* __DRI_ATTRIB_ALPHA_MASK_SIZE */
58   EGL_DEPTH_SIZE,		/* __DRI_ATTRIB_DEPTH_SIZE */
59   EGL_STENCIL_SIZE,		/* __DRI_ATTRIB_STENCIL_SIZE */
60   0,				/* __DRI_ATTRIB_ACCUM_RED_SIZE */
61   0,				/* __DRI_ATTRIB_ACCUM_GREEN_SIZE */
62   0,				/* __DRI_ATTRIB_ACCUM_BLUE_SIZE */
63   0,				/* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */
64   EGL_SAMPLE_BUFFERS,		/* __DRI_ATTRIB_SAMPLE_BUFFERS */
65   EGL_SAMPLES,			/* __DRI_ATTRIB_SAMPLES */
66   0,				/* __DRI_ATTRIB_RENDER_TYPE, */
67   0,				/* __DRI_ATTRIB_CONFIG_CAVEAT */
68   0,				/* __DRI_ATTRIB_CONFORMANT */
69   0,				/* __DRI_ATTRIB_DOUBLE_BUFFER */
70   0,				/* __DRI_ATTRIB_STEREO */
71   0,				/* __DRI_ATTRIB_AUX_BUFFERS */
72   0,				/* __DRI_ATTRIB_TRANSPARENT_TYPE */
73   0,				/* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */
74   0,				/* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */
75   0,				/* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */
76   0,				/* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */
77   0,				/* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */
78   0,				/* __DRI_ATTRIB_FLOAT_MODE */
79   0,				/* __DRI_ATTRIB_RED_MASK */
80   0,				/* __DRI_ATTRIB_GREEN_MASK */
81   0,				/* __DRI_ATTRIB_BLUE_MASK */
82   0,				/* __DRI_ATTRIB_ALPHA_MASK */
83   EGL_MAX_PBUFFER_WIDTH,	/* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */
84   EGL_MAX_PBUFFER_HEIGHT,	/* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */
85   EGL_MAX_PBUFFER_PIXELS,	/* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */
86   0,				/* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */
87   0,				/* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */
88   0,				/* __DRI_ATTRIB_VISUAL_SELECT_GROUP */
89   0,				/* __DRI_ATTRIB_SWAP_METHOD */
90   EGL_MAX_SWAP_INTERVAL,	/* __DRI_ATTRIB_MAX_SWAP_INTERVAL */
91   EGL_MIN_SWAP_INTERVAL,	/* __DRI_ATTRIB_MIN_SWAP_INTERVAL */
92   0,				/* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */
93   0,				/* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */
94   0,				/* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */
95   0,				/* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */
96   EGL_Y_INVERTED_NOK,		/* __DRI_ATTRIB_YINVERTED */
97   0,				/* __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE */
98};
99
100static EGLBoolean
101dri2_match_config(const _EGLConfig *conf, const _EGLConfig *criteria)
102{
103   if (_eglCompareConfigs(conf, criteria, NULL, EGL_FALSE) != 0)
104      return EGL_FALSE;
105
106   if (!_eglMatchConfig(conf, criteria))
107      return EGL_FALSE;
108
109   return EGL_TRUE;
110}
111
112struct dri2_egl_config *
113dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
114		int depth, EGLint surface_type, const EGLint *attr_list,
115		const unsigned int *rgba_masks)
116{
117   struct dri2_egl_config *conf;
118   struct dri2_egl_display *dri2_dpy;
119   _EGLConfig base;
120   unsigned int attrib, value, double_buffer;
121   EGLint key, bind_to_texture_rgb, bind_to_texture_rgba;
122   unsigned int dri_masks[4] = { 0, 0, 0, 0 };
123   _EGLConfig *matching_config;
124   EGLint num_configs = 0;
125   EGLint config_id;
126   int i;
127
128   dri2_dpy = disp->DriverData;
129   _eglInitConfig(&base, disp, id);
130
131   i = 0;
132   double_buffer = 0;
133   bind_to_texture_rgb = 0;
134   bind_to_texture_rgba = 0;
135
136   while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) {
137      switch (attrib) {
138      case __DRI_ATTRIB_RENDER_TYPE:
139	 if (value & __DRI_ATTRIB_RGBA_BIT)
140	    value = EGL_RGB_BUFFER;
141	 else if (value & __DRI_ATTRIB_LUMINANCE_BIT)
142	    value = EGL_LUMINANCE_BUFFER;
143	 else
144	    /* not valid */;
145	 _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value);
146	 break;
147
148      case __DRI_ATTRIB_CONFIG_CAVEAT:
149         if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
150            value = EGL_NON_CONFORMANT_CONFIG;
151         else if (value & __DRI_ATTRIB_SLOW_BIT)
152            value = EGL_SLOW_CONFIG;
153	 else
154	    value = EGL_NONE;
155	 _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value);
156         break;
157
158      case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB:
159	 bind_to_texture_rgb = value;
160	 break;
161
162      case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA:
163	 bind_to_texture_rgba = value;
164	 break;
165
166      case __DRI_ATTRIB_DOUBLE_BUFFER:
167	 double_buffer = value;
168	 break;
169
170      case __DRI_ATTRIB_RED_MASK:
171         dri_masks[0] = value;
172         break;
173
174      case __DRI_ATTRIB_GREEN_MASK:
175         dri_masks[1] = value;
176         break;
177
178      case __DRI_ATTRIB_BLUE_MASK:
179         dri_masks[2] = value;
180         break;
181
182      case __DRI_ATTRIB_ALPHA_MASK:
183         dri_masks[3] = value;
184         break;
185
186      default:
187	 key = dri2_to_egl_attribute_map[attrib];
188	 if (key != 0)
189	    _eglSetConfigKey(&base, key, value);
190	 break;
191      }
192   }
193
194   if (attr_list)
195      for (i = 0; attr_list[i] != EGL_NONE; i += 2)
196         _eglSetConfigKey(&base, attr_list[i], attr_list[i+1]);
197
198   if (depth > 0 && depth != base.BufferSize)
199      return NULL;
200
201   if (rgba_masks && memcmp(rgba_masks, dri_masks, sizeof(dri_masks)))
202      return NULL;
203
204   base.NativeRenderable = EGL_TRUE;
205
206   base.SurfaceType = surface_type;
207   if (surface_type & (EGL_PBUFFER_BIT |
208       (disp->Extensions.NOK_texture_from_pixmap ? EGL_PIXMAP_BIT : 0))) {
209      base.BindToTextureRGB = bind_to_texture_rgb;
210      if (base.AlphaSize > 0)
211         base.BindToTextureRGBA = bind_to_texture_rgba;
212   }
213
214   base.RenderableType = disp->ClientAPIs;
215   base.Conformant = disp->ClientAPIs;
216
217   if (!_eglValidateConfig(&base, EGL_FALSE)) {
218      _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
219      return NULL;
220   }
221
222   config_id = base.ConfigID;
223   base.ConfigID    = EGL_DONT_CARE;
224   base.SurfaceType = EGL_DONT_CARE;
225   num_configs = _eglFilterArray(disp->Configs, (void **) &matching_config, 1,
226                                 (_EGLArrayForEach) dri2_match_config, &base);
227
228   if (num_configs == 1) {
229      conf = (struct dri2_egl_config *) matching_config;
230
231      if (double_buffer && !conf->dri_double_config)
232         conf->dri_double_config = dri_config;
233      else if (!double_buffer && !conf->dri_single_config)
234         conf->dri_single_config = dri_config;
235      else
236         /* a similar config type is already added (unlikely) => discard */
237         return NULL;
238   }
239   else if (num_configs == 0) {
240      conf = malloc(sizeof *conf);
241      if (conf == NULL)
242         return NULL;
243
244      memcpy(&conf->base, &base, sizeof base);
245      if (double_buffer) {
246         conf->dri_double_config = dri_config;
247         conf->dri_single_config = NULL;
248      } else {
249         conf->dri_single_config = dri_config;
250         conf->dri_double_config = NULL;
251      }
252      conf->base.SurfaceType = 0;
253      conf->base.ConfigID = config_id;
254
255      _eglLinkConfig(&conf->base);
256   }
257   else {
258      assert(0);
259      return NULL;
260   }
261
262   if (double_buffer) {
263      surface_type &= ~EGL_PIXMAP_BIT;
264
265      if (dri2_dpy->swap_available) {
266         conf->base.MinSwapInterval = 0;
267         conf->base.MaxSwapInterval = 1000; /* XXX arbitrary value */
268      }
269   }
270
271   conf->base.SurfaceType |= surface_type;
272
273   return conf;
274}
275
276__DRIimage *
277dri2_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
278{
279   _EGLDisplay *disp = data;
280   struct dri2_egl_image *dri2_img;
281   _EGLImage *img;
282
283   (void) screen;
284
285   img = _eglLookupImage(image, disp);
286   if (img == NULL) {
287      _eglError(EGL_BAD_PARAMETER, "dri2_lookup_egl_image");
288      return NULL;
289   }
290
291   dri2_img = dri2_egl_image(image);
292
293   return dri2_img->dri_image;
294}
295
296const __DRIimageLookupExtension image_lookup_extension = {
297   { __DRI_IMAGE_LOOKUP, 1 },
298   dri2_lookup_egl_image
299};
300
301static const char dri_driver_path[] = DEFAULT_DRIVER_DIR;
302
303struct dri2_extension_match {
304   const char *name;
305   int version;
306   int offset;
307};
308
309static struct dri2_extension_match dri2_driver_extensions[] = {
310   { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
311   { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },
312   { NULL, 0, 0 }
313};
314
315static struct dri2_extension_match dri2_core_extensions[] = {
316   { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
317   { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
318   { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
319   { NULL, 0, 0 }
320};
321
322static struct dri2_extension_match swrast_driver_extensions[] = {
323   { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
324   { __DRI_SWRAST, 2, offsetof(struct dri2_egl_display, swrast) },
325   { NULL, 0, 0 }
326};
327
328static struct dri2_extension_match swrast_core_extensions[] = {
329   { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
330   { NULL, 0, 0 }
331};
332
333static EGLBoolean
334dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
335		     struct dri2_extension_match *matches,
336		     const __DRIextension **extensions)
337{
338   int i, j, ret = EGL_TRUE;
339   void *field;
340
341   for (i = 0; extensions[i]; i++) {
342      _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name);
343      for (j = 0; matches[j].name; j++) {
344	 if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
345	     extensions[i]->version >= matches[j].version) {
346	    field = ((char *) dri2_dpy + matches[j].offset);
347	    *(const __DRIextension **) field = extensions[i];
348	    _eglLog(_EGL_INFO, "DRI2: found extension %s version %d",
349		    extensions[i]->name, extensions[i]->version);
350	 }
351      }
352   }
353
354   for (j = 0; matches[j].name; j++) {
355      field = ((char *) dri2_dpy + matches[j].offset);
356      if (*(const __DRIextension **) field == NULL) {
357	 _eglLog(_EGL_FATAL, "DRI2: did not find extension %s version %d",
358		 matches[j].name, matches[j].version);
359	 ret = EGL_FALSE;
360      }
361   }
362
363   return ret;
364}
365
366static const __DRIextension **
367dri2_open_driver(_EGLDisplay *disp)
368{
369   struct dri2_egl_display *dri2_dpy = disp->DriverData;
370   const __DRIextension **extensions;
371   char path[PATH_MAX], *search_paths, *p, *next, *end;
372
373   search_paths = NULL;
374   if (geteuid() == getuid()) {
375      /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
376      search_paths = getenv("LIBGL_DRIVERS_PATH");
377   }
378   if (search_paths == NULL)
379      search_paths = DEFAULT_DRIVER_DIR;
380
381   dri2_dpy->driver = NULL;
382   end = search_paths + strlen(search_paths);
383   for (p = search_paths; p < end && dri2_dpy->driver == NULL; p = next + 1) {
384      int len;
385      next = strchr(p, ':');
386      if (next == NULL)
387         next = end;
388
389      len = next - p;
390#if GLX_USE_TLS
391      snprintf(path, sizeof path,
392	       "%.*s/tls/%s_dri.so", len, p, dri2_dpy->driver_name);
393      dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
394#endif
395      if (dri2_dpy->driver == NULL) {
396	 snprintf(path, sizeof path,
397		  "%.*s/%s_dri.so", len, p, dri2_dpy->driver_name);
398	 dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
399	 if (dri2_dpy->driver == NULL)
400	    _eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror());
401      }
402   }
403
404   if (dri2_dpy->driver == NULL) {
405      _eglLog(_EGL_WARNING,
406	      "DRI2: failed to open %s (search paths %s)",
407	      dri2_dpy->driver_name, search_paths);
408      return NULL;
409   }
410
411   _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
412   extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS);
413   if (extensions == NULL) {
414      _eglLog(_EGL_WARNING,
415	      "DRI2: driver exports no extensions (%s)", dlerror());
416      dlclose(dri2_dpy->driver);
417   }
418
419   return extensions;
420}
421
422EGLBoolean
423dri2_load_driver(_EGLDisplay *disp)
424{
425   struct dri2_egl_display *dri2_dpy = disp->DriverData;
426   const __DRIextension **extensions;
427
428   extensions = dri2_open_driver(disp);
429   if (!extensions)
430      return EGL_FALSE;
431
432   if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) {
433      dlclose(dri2_dpy->driver);
434      return EGL_FALSE;
435   }
436
437   return EGL_TRUE;
438}
439
440EGLBoolean
441dri2_load_driver_swrast(_EGLDisplay *disp)
442{
443   struct dri2_egl_display *dri2_dpy = disp->DriverData;
444   const __DRIextension **extensions;
445
446   dri2_dpy->driver_name = "swrast";
447   extensions = dri2_open_driver(disp);
448
449   if (!extensions)
450      return EGL_FALSE;
451
452   if (!dri2_bind_extensions(dri2_dpy, swrast_driver_extensions, extensions)) {
453      dlclose(dri2_dpy->driver);
454      return EGL_FALSE;
455   }
456
457   return EGL_TRUE;
458}
459
460void
461dri2_setup_screen(_EGLDisplay *disp)
462{
463   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
464   unsigned int api_mask;
465
466   if (dri2_dpy->dri2) {
467      api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
468   } else {
469      assert(dri2_dpy->swrast);
470      api_mask = 1 << __DRI_API_OPENGL | 1 << __DRI_API_GLES | 1 << __DRI_API_GLES2;
471   }
472
473   disp->ClientAPIs = 0;
474   if (api_mask & (1 <<__DRI_API_OPENGL))
475      disp->ClientAPIs |= EGL_OPENGL_BIT;
476   if (api_mask & (1 <<__DRI_API_GLES))
477      disp->ClientAPIs |= EGL_OPENGL_ES_BIT;
478   if (api_mask & (1 << __DRI_API_GLES2))
479      disp->ClientAPIs |= EGL_OPENGL_ES2_BIT;
480
481   assert(dri2_dpy->dri2 || dri2_dpy->swrast);
482   disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
483
484   if (dri2_dpy->dri2->base.version >= 3) {
485      disp->Extensions.KHR_create_context = EGL_TRUE;
486
487      if (dri2_dpy->robustness)
488         disp->Extensions.EXT_create_context_robustness = EGL_TRUE;
489   }
490
491   if (dri2_dpy->image) {
492      disp->Extensions.MESA_drm_image = EGL_TRUE;
493      disp->Extensions.KHR_image_base = EGL_TRUE;
494      disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
495   }
496}
497
498EGLBoolean
499dri2_create_screen(_EGLDisplay *disp)
500{
501   const __DRIextension **extensions;
502   struct dri2_egl_display *dri2_dpy;
503
504   dri2_dpy = disp->DriverData;
505
506   if (dri2_dpy->dri2) {
507      dri2_dpy->dri_screen =
508         dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
509				         &dri2_dpy->driver_configs, disp);
510   } else {
511      assert(dri2_dpy->swrast);
512      dri2_dpy->dri_screen =
513         dri2_dpy->swrast->createNewScreen(0, dri2_dpy->extensions,
514                                           &dri2_dpy->driver_configs, disp);
515   }
516
517   if (dri2_dpy->dri_screen == NULL) {
518      _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
519      return EGL_FALSE;
520   }
521
522   dri2_dpy->own_dri_screen = 1;
523
524   extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
525
526   if (dri2_dpy->dri2) {
527      unsigned i;
528
529      if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
530         goto cleanup_dri_screen;
531
532      for (i = 0; extensions[i]; i++) {
533	 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) {
534            dri2_dpy->robustness = (__DRIrobustnessExtension *) extensions[i];
535	 }
536      }
537   } else {
538      assert(dri2_dpy->swrast);
539      if (!dri2_bind_extensions(dri2_dpy, swrast_core_extensions, extensions))
540         goto cleanup_dri_screen;
541   }
542
543   dri2_setup_screen(disp);
544
545   return EGL_TRUE;
546
547 cleanup_dri_screen:
548   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
549
550   return EGL_FALSE;
551}
552
553/**
554 * Called via eglInitialize(), GLX_drv->API.Initialize().
555 */
556static EGLBoolean
557dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp)
558{
559   /* not until swrast_dri is supported */
560   if (disp->Options.UseFallback)
561      return EGL_FALSE;
562
563   switch (disp->Platform) {
564#ifdef HAVE_X11_PLATFORM
565   case _EGL_PLATFORM_X11:
566      if (disp->Options.TestOnly)
567         return EGL_TRUE;
568      return dri2_initialize_x11(drv, disp);
569#endif
570
571#ifdef HAVE_LIBUDEV
572#ifdef HAVE_DRM_PLATFORM
573   case _EGL_PLATFORM_DRM:
574      if (disp->Options.TestOnly)
575         return EGL_TRUE;
576      return dri2_initialize_drm(drv, disp);
577#endif
578#ifdef HAVE_WAYLAND_PLATFORM
579   case _EGL_PLATFORM_WAYLAND:
580      if (disp->Options.TestOnly)
581         return EGL_TRUE;
582      return dri2_initialize_wayland(drv, disp);
583#endif
584#endif
585#ifdef HAVE_ANDROID_PLATFORM
586   case _EGL_PLATFORM_ANDROID:
587      if (disp->Options.TestOnly)
588         return EGL_TRUE;
589      return dri2_initialize_android(drv, disp);
590#endif
591
592   default:
593      return EGL_FALSE;
594   }
595}
596
597/**
598 * Called via eglTerminate(), drv->API.Terminate().
599 */
600static EGLBoolean
601dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
602{
603   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
604
605   _eglReleaseDisplayResources(drv, disp);
606   _eglCleanupDisplay(disp);
607
608   if (dri2_dpy->own_dri_screen)
609      dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
610   if (dri2_dpy->fd)
611      close(dri2_dpy->fd);
612   if (dri2_dpy->driver)
613      dlclose(dri2_dpy->driver);
614   if (dri2_dpy->device_name)
615      free(dri2_dpy->device_name);
616
617   if (disp->PlatformDisplay == NULL) {
618      switch (disp->Platform) {
619#ifdef HAVE_X11_PLATFORM
620      case _EGL_PLATFORM_X11:
621         xcb_disconnect(dri2_dpy->conn);
622         break;
623#endif
624#ifdef HAVE_DRM_PLATFORM
625      case _EGL_PLATFORM_DRM:
626         if (dri2_dpy->own_device) {
627            gbm_device_destroy(&dri2_dpy->gbm_dri->base.base);
628         }
629         break;
630#endif
631      default:
632         break;
633      }
634   }
635
636   free(dri2_dpy);
637   disp->DriverData = NULL;
638
639   return EGL_TRUE;
640}
641
642
643/**
644 * Called via eglCreateContext(), drv->API.CreateContext().
645 */
646static _EGLContext *
647dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
648		    _EGLContext *share_list, const EGLint *attrib_list)
649{
650   struct dri2_egl_context *dri2_ctx;
651   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
652   struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
653   __DRIcontext *shared =
654      dri2_ctx_shared ? dri2_ctx_shared->dri_context : NULL;
655   struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
656   const __DRIconfig *dri_config;
657   int api;
658
659   (void) drv;
660
661   dri2_ctx = malloc(sizeof *dri2_ctx);
662   if (!dri2_ctx) {
663      _eglError(EGL_BAD_ALLOC, "eglCreateContext");
664      return NULL;
665   }
666
667   if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
668      goto cleanup;
669
670   switch (dri2_ctx->base.ClientAPI) {
671   case EGL_OPENGL_ES_API:
672      switch (dri2_ctx->base.ClientMajorVersion) {
673      case 1:
674         api = __DRI_API_GLES;
675         break;
676      case 2:
677      case 3:
678         api = __DRI_API_GLES2;
679         break;
680      default:
681	 _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
682	 return NULL;
683      }
684      break;
685   case EGL_OPENGL_API:
686      if ((dri2_ctx->base.ClientMajorVersion >= 4
687           || (dri2_ctx->base.ClientMajorVersion == 3
688               && dri2_ctx->base.ClientMinorVersion >= 2))
689          && dri2_ctx->base.Profile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR)
690         api = __DRI_API_OPENGL_CORE;
691      else
692         api = __DRI_API_OPENGL;
693      break;
694   default:
695      _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
696      return NULL;
697   }
698
699   if (conf != NULL) {
700      /* The config chosen here isn't necessarily
701       * used for surfaces later.
702       * A pixmap surface will use the single config.
703       * This opportunity depends on disabling the
704       * doubleBufferMode check in
705       * src/mesa/main/context.c:check_compatible()
706       */
707      if (dri2_config->dri_double_config)
708         dri_config = dri2_config->dri_double_config;
709      else
710         dri_config = dri2_config->dri_single_config;
711
712      /* EGL_WINDOW_BIT is set only when there is a dri_double_config.  This
713       * makes sure the back buffer will always be used.
714       */
715      if (conf->SurfaceType & EGL_WINDOW_BIT)
716         dri2_ctx->base.WindowRenderBuffer = EGL_BACK_BUFFER;
717   }
718   else
719      dri_config = NULL;
720
721   if (dri2_dpy->dri2) {
722      if (dri2_dpy->dri2->base.version >= 3) {
723         unsigned error;
724         unsigned num_attribs = 0;
725         uint32_t ctx_attribs[8];
726
727         ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
728         ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMajorVersion;
729         ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
730         ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMinorVersion;
731
732         if (dri2_ctx->base.Flags != 0) {
733            /* If the implementation doesn't support the __DRI2_ROBUSTNESS
734             * extension, don't even try to send it the robust-access flag.
735             * It may explode.  Instead, generate the required EGL error here.
736             */
737            if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0
738                && !dri2_dpy->robustness) {
739               _eglError(EGL_BAD_MATCH, "eglCreateContext");
740               goto cleanup;
741            }
742
743            ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
744            ctx_attribs[num_attribs++] = dri2_ctx->base.Flags;
745         }
746
747         if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) {
748            /* If the implementation doesn't support the __DRI2_ROBUSTNESS
749             * extension, don't even try to send it a reset strategy.  It may
750             * explode.  Instead, generate the required EGL error here.
751             */
752            if (!dri2_dpy->robustness) {
753               _eglError(EGL_BAD_CONFIG, "eglCreateContext");
754               goto cleanup;
755            }
756
757            ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
758            ctx_attribs[num_attribs++] = __DRI_CTX_RESET_LOSE_CONTEXT;
759         }
760
761         assert(num_attribs <= ARRAY_SIZE(ctx_attribs));
762
763	 dri2_ctx->dri_context =
764	    dri2_dpy->dri2->createContextAttribs(dri2_dpy->dri_screen,
765                                                 api,
766                                                 dri_config,
767                                                 shared,
768                                                 num_attribs / 2,
769                                                 ctx_attribs,
770                                                 & error,
771                                                 dri2_ctx);
772      } else {
773	 dri2_ctx->dri_context =
774	    dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
775						   api,
776						   dri_config,
777                                                   shared,
778						   dri2_ctx);
779      }
780   } else {
781      assert(dri2_dpy->swrast);
782      dri2_ctx->dri_context =
783         dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen,
784                                                  api,
785                                                  dri_config,
786                                                  shared,
787                                                  dri2_ctx);
788   }
789
790   if (!dri2_ctx->dri_context)
791      goto cleanup;
792
793   return &dri2_ctx->base;
794
795 cleanup:
796   free(dri2_ctx);
797   return NULL;
798}
799
800/**
801 * Called via eglDestroyContext(), drv->API.DestroyContext().
802 */
803static EGLBoolean
804dri2_destroy_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
805{
806   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
807   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
808
809   if (_eglPutContext(ctx)) {
810      dri2_dpy->core->destroyContext(dri2_ctx->dri_context);
811      free(dri2_ctx);
812   }
813
814   return EGL_TRUE;
815}
816
817/**
818 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
819 */
820static EGLBoolean
821dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
822		  _EGLSurface *rsurf, _EGLContext *ctx)
823{
824   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
825   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
826   struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
827   struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
828   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
829   _EGLContext *old_ctx;
830   _EGLSurface *old_dsurf, *old_rsurf;
831   __DRIdrawable *ddraw, *rdraw;
832   __DRIcontext *cctx;
833
834   /* make new bindings */
835   if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
836      return EGL_FALSE;
837
838   /* flush before context switch */
839   if (old_ctx && dri2_drv->glFlush)
840      dri2_drv->glFlush();
841
842   ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
843   rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL;
844   cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
845
846   if (old_ctx) {
847      __DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
848      dri2_dpy->core->unbindContext(old_cctx);
849   }
850
851   if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
852       dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
853      if (old_dsurf)
854         drv->API.DestroySurface(drv, disp, old_dsurf);
855      if (old_rsurf)
856         drv->API.DestroySurface(drv, disp, old_rsurf);
857      if (old_ctx)
858         drv->API.DestroyContext(drv, disp, old_ctx);
859
860      return EGL_TRUE;
861   } else {
862      /* undo the previous _eglBindContext */
863      _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
864      assert(&dri2_ctx->base == ctx &&
865             &dri2_dsurf->base == dsurf &&
866             &dri2_rsurf->base == rsurf);
867
868      _eglPutSurface(dsurf);
869      _eglPutSurface(rsurf);
870      _eglPutContext(ctx);
871
872      _eglPutSurface(old_dsurf);
873      _eglPutSurface(old_rsurf);
874      _eglPutContext(old_ctx);
875
876      return EGL_FALSE;
877   }
878}
879
880/*
881 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
882 */
883static _EGLProc
884dri2_get_proc_address(_EGLDriver *drv, const char *procname)
885{
886   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
887
888   return dri2_drv->get_proc_address(procname);
889}
890
891static EGLBoolean
892dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
893{
894   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
895   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(ctx->DrawSurface);
896
897   (void) drv;
898
899   /* FIXME: If EGL allows frontbuffer rendering for window surfaces,
900    * we need to copy fake to real here.*/
901
902   (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
903
904   return EGL_TRUE;
905}
906
907static EGLBoolean
908dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine)
909{
910   (void) drv;
911   (void) disp;
912
913   if (engine != EGL_CORE_NATIVE_ENGINE)
914      return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
915   /* glXWaitX(); */
916
917   return EGL_TRUE;
918}
919
920static EGLBoolean
921dri2_bind_tex_image(_EGLDriver *drv,
922		    _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
923{
924   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
925   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
926   struct dri2_egl_context *dri2_ctx;
927   _EGLContext *ctx;
928   GLint format, target;
929
930   ctx = _eglGetCurrentContext();
931   dri2_ctx = dri2_egl_context(ctx);
932
933   if (!_eglBindTexImage(drv, disp, surf, buffer))
934      return EGL_FALSE;
935
936   switch (dri2_surf->base.TextureFormat) {
937   case EGL_TEXTURE_RGB:
938      format = __DRI_TEXTURE_FORMAT_RGB;
939      break;
940   case EGL_TEXTURE_RGBA:
941      format = __DRI_TEXTURE_FORMAT_RGBA;
942      break;
943   default:
944      assert(0);
945   }
946
947   switch (dri2_surf->base.TextureTarget) {
948   case EGL_TEXTURE_2D:
949      target = GL_TEXTURE_2D;
950      break;
951   default:
952      assert(0);
953   }
954
955   (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
956					  target, format,
957					  dri2_surf->dri_drawable);
958
959   return EGL_TRUE;
960}
961
962static EGLBoolean
963dri2_release_tex_image(_EGLDriver *drv,
964		       _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
965{
966#if __DRI_TEX_BUFFER_VERSION >= 3
967   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
968   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
969   struct dri2_egl_context *dri2_ctx;
970   _EGLContext *ctx;
971   GLint  target;
972
973   ctx = _eglGetCurrentContext();
974   dri2_ctx = dri2_egl_context(ctx);
975
976   if (!_eglReleaseTexImage(drv, disp, surf, buffer))
977      return EGL_FALSE;
978
979   switch (dri2_surf->base.TextureTarget) {
980   case EGL_TEXTURE_2D:
981      target = GL_TEXTURE_2D;
982      break;
983   default:
984      assert(0);
985   }
986   if (dri2_dpy->tex_buffer->releaseTexBuffer!=NULL)
987    (*dri2_dpy->tex_buffer->releaseTexBuffer)(dri2_ctx->dri_context,
988                                             target,
989                                             dri2_surf->dri_drawable);
990#endif
991
992   return EGL_TRUE;
993}
994
995static _EGLImage *
996dri2_create_image(_EGLDisplay *disp, __DRIimage *dri_image)
997{
998   struct dri2_egl_image *dri2_img;
999
1000   if (dri_image == NULL) {
1001      _eglError(EGL_BAD_ALLOC, "dri2_create_image");
1002      return NULL;
1003   }
1004
1005   dri2_img = malloc(sizeof *dri2_img);
1006   if (!dri2_img) {
1007      _eglError(EGL_BAD_ALLOC, "dri2_create_image");
1008      return NULL;
1009   }
1010
1011   if (!_eglInitImage(&dri2_img->base, disp)) {
1012      free(dri2_img);
1013      return NULL;
1014   }
1015
1016   dri2_img->dri_image = dri_image;
1017
1018   return &dri2_img->base;
1019}
1020
1021static _EGLImage *
1022dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
1023				   EGLClientBuffer buffer,
1024				   const EGLint *attr_list)
1025{
1026   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1027   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1028   GLuint renderbuffer = (GLuint) (uintptr_t) buffer;
1029   __DRIimage *dri_image;
1030
1031   if (renderbuffer == 0) {
1032      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
1033      return EGL_NO_IMAGE_KHR;
1034   }
1035
1036   dri_image =
1037      dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context,
1038                                                   renderbuffer, NULL);
1039
1040   return dri2_create_image(disp, dri_image);
1041}
1042
1043static _EGLImage *
1044dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
1045				  EGLClientBuffer buffer, const EGLint *attr_list)
1046{
1047   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1048   EGLint format, name, pitch, err;
1049   _EGLImageAttribs attrs;
1050   __DRIimage *dri_image;
1051
1052   name = (EGLint) (uintptr_t) buffer;
1053
1054   err = _eglParseImageAttribList(&attrs, disp, attr_list);
1055   if (err != EGL_SUCCESS)
1056      return NULL;
1057
1058   if (attrs.Width <= 0 || attrs.Height <= 0 ||
1059       attrs.DRMBufferStrideMESA <= 0) {
1060      _eglError(EGL_BAD_PARAMETER,
1061		"bad width, height or stride");
1062      return NULL;
1063   }
1064
1065   switch (attrs.DRMBufferFormatMESA) {
1066   case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
1067      format = __DRI_IMAGE_FORMAT_ARGB8888;
1068      pitch = attrs.DRMBufferStrideMESA;
1069      break;
1070   default:
1071      _eglError(EGL_BAD_PARAMETER,
1072		"dri2_create_image_khr: unsupported pixmap depth");
1073      return NULL;
1074   }
1075
1076   dri_image =
1077      dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1078					   attrs.Width,
1079					   attrs.Height,
1080					   format,
1081					   name,
1082					   pitch,
1083					   NULL);
1084
1085   return dri2_create_image(disp, dri_image);
1086}
1087
1088#ifdef HAVE_WAYLAND_PLATFORM
1089
1090/* This structure describes how a wl_buffer maps to one or more
1091 * __DRIimages.  A wl_drm_buffer stores the wl_drm format code and the
1092 * offsets and strides of the planes in the buffer.  This table maps a
1093 * wl_drm format code to a description of the planes in the buffer
1094 * that lets us create a __DRIimage for each of the planes. */
1095
1096static const struct wl_drm_format_descriptor {
1097   uint32_t wl_format;
1098   EGLint components;
1099   int nplanes;
1100   struct {
1101      int buffer_index;
1102      int width_shift;
1103      int height_shift;
1104      uint32_t dri_format;
1105      int cpp;
1106   } planes[3];
1107} wl_drm_formats[] = {
1108   { WL_DRM_FORMAT_ARGB8888, EGL_TEXTURE_RGBA, 1,
1109     { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 }, } },
1110
1111   { WL_DRM_FORMAT_XRGB8888, EGL_TEXTURE_RGB, 1,
1112     { { 0, 0, 0, __DRI_IMAGE_FORMAT_XRGB8888, 4 }, } },
1113
1114   { WL_DRM_FORMAT_YUV410, EGL_TEXTURE_Y_U_V_WL, 3,
1115     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1116       { 1, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 },
1117       { 2, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 } } },
1118
1119   { WL_DRM_FORMAT_YUV411, EGL_TEXTURE_Y_U_V_WL, 3,
1120     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1121       { 1, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1122       { 2, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
1123
1124   { WL_DRM_FORMAT_YUV420, EGL_TEXTURE_Y_U_V_WL, 3,
1125     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1126       { 1, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 },
1127       { 2, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 } } },
1128
1129   { WL_DRM_FORMAT_YUV422, EGL_TEXTURE_Y_U_V_WL, 3,
1130     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1131       { 1, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1132       { 2, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
1133
1134   { WL_DRM_FORMAT_YUV444, EGL_TEXTURE_Y_U_V_WL, 3,
1135     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1136       { 1, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1137       { 2, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
1138
1139   { WL_DRM_FORMAT_NV12, EGL_TEXTURE_Y_UV_WL, 2,
1140     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1141       { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88, 2 } } },
1142
1143   { WL_DRM_FORMAT_NV16, EGL_TEXTURE_Y_UV_WL, 2,
1144     { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
1145       { 1, 1, 0, __DRI_IMAGE_FORMAT_GR88, 2 } } },
1146
1147   /* For YUYV buffers, we set up two overlapping DRI images and treat
1148    * them as planar buffers in the compositors.  Plane 0 is GR88 and
1149    * samples YU or YV pairs and places Y into the R component, while
1150    * plane 1 is ARGB and samples YUYV clusters and places pairs and
1151    * places U into the G component and V into A.  This lets the
1152    * texture sampler interpolate the Y components correctly when
1153    * sampling from plane 0, and interpolate U and V correctly when
1154    * sampling from plane 1. */
1155   { WL_DRM_FORMAT_YUYV, EGL_TEXTURE_Y_XUXV_WL, 2,
1156     { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88, 2 },
1157       { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 } } }
1158};
1159
1160static _EGLImage *
1161dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx,
1162				    EGLClientBuffer _buffer,
1163				    const EGLint *attr_list)
1164{
1165   struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
1166   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1167   __DRIimage *dri_image;
1168   _EGLImageAttribs attrs;
1169   EGLint err;
1170   uint32_t format;
1171   int32_t offset, stride, plane, width, height;
1172   int cpp, index;
1173   const struct wl_drm_format_descriptor *f;
1174
1175   if (!wayland_buffer_is_drm(&buffer->buffer))
1176       return NULL;
1177
1178   err = _eglParseImageAttribList(&attrs, disp, attr_list);
1179   plane = attrs.PlaneWL;
1180   if (err != EGL_SUCCESS) {
1181      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
1182      return NULL;
1183   }
1184
1185   f = buffer->driver_format;
1186   if (plane < 0 || plane >= f->nplanes) {
1187      _eglError(EGL_BAD_PARAMETER,
1188                "dri2_create_image_wayland_wl_buffer (plane out of bounds)");
1189      return NULL;
1190   }
1191
1192   width = buffer->buffer.width >> f->planes[plane].width_shift;
1193   height = buffer->buffer.height >> f->planes[plane].height_shift;
1194   format = f->planes[plane].dri_format;
1195   cpp = f->planes[plane].cpp;
1196   index = f->planes[plane].buffer_index;
1197   offset = buffer->offset[index];
1198   stride = buffer->stride[index];
1199
1200   dri_image = dri2_dpy->image->createSubImage(buffer->driver_buffer,
1201                                               width, height, format,
1202                                               offset, stride / cpp, NULL);
1203
1204   return dri2_create_image(disp, dri_image);
1205}
1206#endif
1207
1208_EGLImage *
1209dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
1210		      _EGLContext *ctx, EGLenum target,
1211		      EGLClientBuffer buffer, const EGLint *attr_list)
1212{
1213   (void) drv;
1214
1215   switch (target) {
1216   case EGL_GL_RENDERBUFFER_KHR:
1217      return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list);
1218   case EGL_DRM_BUFFER_MESA:
1219      return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list);
1220#ifdef HAVE_WAYLAND_PLATFORM
1221   case EGL_WAYLAND_BUFFER_WL:
1222      return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list);
1223#endif
1224   default:
1225      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
1226      return EGL_NO_IMAGE_KHR;
1227   }
1228}
1229
1230static EGLBoolean
1231dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
1232{
1233   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1234   struct dri2_egl_image *dri2_img = dri2_egl_image(image);
1235
1236   (void) drv;
1237
1238   dri2_dpy->image->destroyImage(dri2_img->dri_image);
1239   free(dri2_img);
1240
1241   return EGL_TRUE;
1242}
1243
1244static _EGLImage *
1245dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
1246			   const EGLint *attr_list)
1247{
1248   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1249   struct dri2_egl_image *dri2_img;
1250   _EGLImageAttribs attrs;
1251   unsigned int dri_use, valid_mask;
1252   int format;
1253   EGLint err = EGL_SUCCESS;
1254
1255   (void) drv;
1256
1257   dri2_img = malloc(sizeof *dri2_img);
1258   if (!dri2_img) {
1259      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1260      return EGL_NO_IMAGE_KHR;
1261   }
1262
1263   if (!attr_list) {
1264      err = EGL_BAD_PARAMETER;
1265      goto cleanup_img;
1266   }
1267
1268   if (!_eglInitImage(&dri2_img->base, disp)) {
1269      err = EGL_BAD_PARAMETER;
1270      goto cleanup_img;
1271   }
1272
1273   err = _eglParseImageAttribList(&attrs, disp, attr_list);
1274   if (err != EGL_SUCCESS)
1275      goto cleanup_img;
1276
1277   if (attrs.Width <= 0 || attrs.Height <= 0) {
1278      _eglLog(_EGL_WARNING, "bad width or height (%dx%d)",
1279            attrs.Width, attrs.Height);
1280      goto cleanup_img;
1281   }
1282
1283   switch (attrs.DRMBufferFormatMESA) {
1284   case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
1285      format = __DRI_IMAGE_FORMAT_ARGB8888;
1286      break;
1287   default:
1288      _eglLog(_EGL_WARNING, "bad image format value 0x%04x",
1289            attrs.DRMBufferFormatMESA);
1290      goto cleanup_img;
1291   }
1292
1293   valid_mask =
1294      EGL_DRM_BUFFER_USE_SCANOUT_MESA |
1295      EGL_DRM_BUFFER_USE_SHARE_MESA |
1296      EGL_DRM_BUFFER_USE_CURSOR_MESA;
1297   if (attrs.DRMBufferUseMESA & ~valid_mask) {
1298      _eglLog(_EGL_WARNING, "bad image use bit 0x%04x",
1299            attrs.DRMBufferUseMESA & ~valid_mask);
1300      goto cleanup_img;
1301   }
1302
1303   dri_use = 0;
1304   if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA)
1305      dri_use |= __DRI_IMAGE_USE_SHARE;
1306   if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
1307      dri_use |= __DRI_IMAGE_USE_SCANOUT;
1308   if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_CURSOR_MESA)
1309      dri_use |= __DRI_IMAGE_USE_CURSOR;
1310
1311   dri2_img->dri_image =
1312      dri2_dpy->image->createImage(dri2_dpy->dri_screen,
1313				   attrs.Width, attrs.Height,
1314                                   format, dri_use, dri2_img);
1315   if (dri2_img->dri_image == NULL) {
1316      err = EGL_BAD_ALLOC;
1317      goto cleanup_img;
1318   }
1319
1320   return &dri2_img->base;
1321
1322 cleanup_img:
1323   free(dri2_img);
1324   _eglError(err, "dri2_create_drm_image_mesa");
1325
1326   return EGL_NO_IMAGE_KHR;
1327}
1328
1329static EGLBoolean
1330dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
1331			  EGLint *name, EGLint *handle, EGLint *stride)
1332{
1333   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1334   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
1335
1336   (void) drv;
1337
1338   if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image,
1339					    __DRI_IMAGE_ATTRIB_NAME, name)) {
1340      _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa");
1341      return EGL_FALSE;
1342   }
1343
1344   if (handle)
1345      dri2_dpy->image->queryImage(dri2_img->dri_image,
1346				  __DRI_IMAGE_ATTRIB_HANDLE, handle);
1347
1348   if (stride)
1349      dri2_dpy->image->queryImage(dri2_img->dri_image,
1350				  __DRI_IMAGE_ATTRIB_STRIDE, stride);
1351
1352   return EGL_TRUE;
1353}
1354
1355#ifdef HAVE_WAYLAND_PLATFORM
1356
1357static void
1358dri2_wl_reference_buffer(void *user_data, uint32_t name,
1359                         struct wl_drm_buffer *buffer)
1360{
1361   _EGLDisplay *disp = user_data;
1362   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1363   int i;
1364
1365   for (i = 0; i < ARRAY_SIZE(wl_drm_formats); i++)
1366      if (wl_drm_formats[i].wl_format == buffer->format) {
1367         buffer->driver_format = &wl_drm_formats[i];
1368         break;
1369      }
1370
1371   if (buffer->driver_format == NULL)
1372      return;
1373
1374   buffer->driver_buffer =
1375      dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1376                                           buffer->buffer.width,
1377                                           buffer->buffer.height,
1378                                           __DRI_IMAGE_FORMAT_NONE, name,
1379                                           buffer->stride[0] / 4,
1380                                           NULL);
1381}
1382
1383static void
1384dri2_wl_release_buffer(void *user_data, struct wl_drm_buffer *buffer)
1385{
1386   _EGLDisplay *disp = user_data;
1387   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1388
1389   dri2_dpy->image->destroyImage(buffer->driver_buffer);
1390}
1391
1392static struct wayland_drm_callbacks wl_drm_callbacks = {
1393	.authenticate = NULL,
1394	.reference_buffer = dri2_wl_reference_buffer,
1395	.release_buffer = dri2_wl_release_buffer
1396};
1397
1398static EGLBoolean
1399dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
1400			     struct wl_display *wl_dpy)
1401{
1402   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1403
1404   (void) drv;
1405
1406   if (dri2_dpy->wl_server_drm)
1407	   return EGL_FALSE;
1408
1409   wl_drm_callbacks.authenticate =
1410      (int(*)(void *, uint32_t)) dri2_dpy->authenticate;
1411
1412   dri2_dpy->wl_server_drm =
1413	   wayland_drm_init(wl_dpy, dri2_dpy->device_name,
1414                            &wl_drm_callbacks, disp);
1415
1416   if (!dri2_dpy->wl_server_drm)
1417	   return EGL_FALSE;
1418
1419   return EGL_TRUE;
1420}
1421
1422static EGLBoolean
1423dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
1424			       struct wl_display *wl_dpy)
1425{
1426   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1427
1428   (void) drv;
1429
1430   if (!dri2_dpy->wl_server_drm)
1431	   return EGL_FALSE;
1432
1433   wayland_drm_uninit(dri2_dpy->wl_server_drm);
1434   dri2_dpy->wl_server_drm = NULL;
1435
1436   return EGL_TRUE;
1437}
1438
1439static EGLBoolean
1440dri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp,
1441                             struct wl_buffer *_buffer,
1442                             EGLint attribute, EGLint *value)
1443{
1444   struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
1445   const struct wl_drm_format_descriptor *format;
1446
1447   if (!wayland_buffer_is_drm(&buffer->buffer))
1448      return EGL_FALSE;
1449
1450   format = buffer->driver_format;
1451   switch (attribute) {
1452   case EGL_TEXTURE_FORMAT:
1453      *value = format->components;
1454      return EGL_TRUE;
1455   case EGL_WIDTH:
1456      *value = buffer->buffer.width;
1457      break;
1458   case EGL_HEIGHT:
1459      *value = buffer->buffer.height;
1460      break;
1461   }
1462
1463   return EGL_FALSE;
1464}
1465#endif
1466
1467static void
1468dri2_unload(_EGLDriver *drv)
1469{
1470   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
1471
1472   if (dri2_drv->handle)
1473      dlclose(dri2_drv->handle);
1474   free(dri2_drv);
1475}
1476
1477static EGLBoolean
1478dri2_load(_EGLDriver *drv)
1479{
1480   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
1481#ifdef HAVE_SHARED_GLAPI
1482#ifdef HAVE_ANDROID_PLATFORM
1483   const char *libname = "libglapi.so";
1484#else
1485   const char *libname = "libglapi.so.0";
1486#endif
1487#else
1488   /*
1489    * Both libGL.so and libglapi.so are glapi providers.  There is no way to
1490    * tell which one to load.
1491    */
1492   const char *libname = NULL;
1493#endif
1494   void *handle;
1495
1496   /* RTLD_GLOBAL to make sure glapi symbols are visible to DRI drivers */
1497   handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
1498   if (handle) {
1499      dri2_drv->get_proc_address = (_EGLProc (*)(const char *))
1500         dlsym(handle, "_glapi_get_proc_address");
1501      if (!dri2_drv->get_proc_address || !libname) {
1502         /* no need to keep a reference */
1503         dlclose(handle);
1504         handle = NULL;
1505      }
1506   }
1507
1508   /* if glapi is not available, loading DRI drivers will fail */
1509   if (!dri2_drv->get_proc_address) {
1510      _eglLog(_EGL_WARNING, "DRI2: failed to find _glapi_get_proc_address");
1511      return EGL_FALSE;
1512   }
1513
1514   dri2_drv->glFlush = (void (*)(void))
1515      dri2_drv->get_proc_address("glFlush");
1516
1517   dri2_drv->handle = handle;
1518
1519   return EGL_TRUE;
1520}
1521
1522/**
1523 * This is the main entrypoint into the driver, called by libEGL.
1524 * Create a new _EGLDriver object and init its dispatch table.
1525 */
1526_EGLDriver *
1527_eglBuiltInDriverDRI2(const char *args)
1528{
1529   struct dri2_egl_driver *dri2_drv;
1530
1531   (void) args;
1532
1533   dri2_drv = malloc(sizeof *dri2_drv);
1534   if (!dri2_drv)
1535      return NULL;
1536
1537   memset(dri2_drv, 0, sizeof *dri2_drv);
1538
1539   if (!dri2_load(&dri2_drv->base)) {
1540      free(dri2_drv);
1541      return NULL;
1542   }
1543
1544   _eglInitDriverFallbacks(&dri2_drv->base);
1545   dri2_drv->base.API.Initialize = dri2_initialize;
1546   dri2_drv->base.API.Terminate = dri2_terminate;
1547   dri2_drv->base.API.CreateContext = dri2_create_context;
1548   dri2_drv->base.API.DestroyContext = dri2_destroy_context;
1549   dri2_drv->base.API.MakeCurrent = dri2_make_current;
1550   dri2_drv->base.API.GetProcAddress = dri2_get_proc_address;
1551   dri2_drv->base.API.WaitClient = dri2_wait_client;
1552   dri2_drv->base.API.WaitNative = dri2_wait_native;
1553   dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
1554   dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
1555   dri2_drv->base.API.CreateImageKHR = dri2_create_image_khr;
1556   dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr;
1557   dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa;
1558   dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa;
1559#ifdef HAVE_WAYLAND_PLATFORM
1560   dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;
1561   dri2_drv->base.API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl;
1562   dri2_drv->base.API.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl;
1563#endif
1564
1565   dri2_drv->base.Name = "DRI2";
1566   dri2_drv->base.Unload = dri2_unload;
1567
1568   return &dri2_drv->base;
1569}
1570