• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 const __DRIuseInvalidateExtension use_invalidate = {
45    { __DRI_USE_INVALIDATE, 1 }
46 };
47 
48 EGLint 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 
100 static EGLBoolean
dri2_match_config(const _EGLConfig * conf,const _EGLConfig * criteria)101 dri2_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 
112 struct dri2_egl_config *
dri2_add_config(_EGLDisplay * disp,const __DRIconfig * dri_config,int id,int depth,EGLint surface_type,const EGLint * attr_list,const unsigned int * rgba_masks)113 dri2_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 *
dri2_lookup_egl_image(__DRIscreen * screen,void * image,void * data)277 dri2_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 
296 const __DRIimageLookupExtension image_lookup_extension = {
297    { __DRI_IMAGE_LOOKUP, 1 },
298    dri2_lookup_egl_image
299 };
300 
301 static const char dri_driver_path[] = DEFAULT_DRIVER_DIR;
302 
303 struct dri2_extension_match {
304    const char *name;
305    int version;
306    int offset;
307 };
308 
309 static 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 
315 static 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 
322 static 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 
328 static 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 
333 static EGLBoolean
dri2_bind_extensions(struct dri2_egl_display * dri2_dpy,struct dri2_extension_match * matches,const __DRIextension ** extensions)334 dri2_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 
366 static const __DRIextension **
dri2_open_driver(_EGLDisplay * disp)367 dri2_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 
422 EGLBoolean
dri2_load_driver(_EGLDisplay * disp)423 dri2_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 
440 EGLBoolean
dri2_load_driver_swrast(_EGLDisplay * disp)441 dri2_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 
460 void
dri2_setup_screen(_EGLDisplay * disp)461 dri2_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 && 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 
498 EGLBoolean
dri2_create_screen(_EGLDisplay * disp)499 dri2_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  */
556 static EGLBoolean
dri2_initialize(_EGLDriver * drv,_EGLDisplay * disp)557 dri2_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  */
600 static EGLBoolean
dri2_terminate(_EGLDriver * drv,_EGLDisplay * disp)601 dri2_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  * Set the error code after a call to
644  * dri2_egl_display::dri2::createContextAttribs.
645  */
646 static void
dri2_create_context_attribs_error(int dri_error)647 dri2_create_context_attribs_error(int dri_error)
648 {
649    EGLint egl_error;
650 
651    switch (dri_error) {
652    case __DRI_CTX_ERROR_SUCCESS:
653       return;
654 
655    case __DRI_CTX_ERROR_NO_MEMORY:
656       egl_error = EGL_BAD_ALLOC;
657       break;
658 
659   /* From the EGL_KHR_create_context spec, section "Errors":
660    *
661    *   * If <config> does not support a client API context compatible
662    *     with the requested API major and minor version, [...] context flags,
663    *     and context reset notification behavior (for client API types where
664    *     these attributes are supported), then an EGL_BAD_MATCH error is
665    *     generated.
666    *
667    *   * If an OpenGL ES context is requested and the values for
668    *     attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
669    *     EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
670    *     is not defined, than an EGL_BAD_MATCH error is generated.
671    *
672    *   * If an OpenGL context is requested, the requested version is
673    *     greater than 3.2, and the value for attribute
674    *     EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has any
675    *     bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR and
676    *     EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has more than
677    *     one of these bits set; or if the implementation does not support
678    *     the requested profile, then an EGL_BAD_MATCH error is generated.
679    */
680    case __DRI_CTX_ERROR_BAD_API:
681    case __DRI_CTX_ERROR_BAD_VERSION:
682    case __DRI_CTX_ERROR_BAD_FLAG:
683       egl_error = EGL_BAD_MATCH;
684       break;
685 
686   /* From the EGL_KHR_create_context spec, section "Errors":
687    *
688    *   * If an attribute name or attribute value in <attrib_list> is not
689    *     recognized (including unrecognized bits in bitmask attributes),
690    *     then an EGL_BAD_ATTRIBUTE error is generated."
691    */
692    case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE:
693    case __DRI_CTX_ERROR_UNKNOWN_FLAG:
694       egl_error = EGL_BAD_ATTRIBUTE;
695       break;
696 
697    default:
698       assert(0);
699       egl_error = EGL_BAD_MATCH;
700       break;
701    }
702 
703    _eglError(egl_error, "dri2_create_context");
704 }
705 
706 /**
707  * Called via eglCreateContext(), drv->API.CreateContext().
708  */
709 static _EGLContext *
dri2_create_context(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,_EGLContext * share_list,const EGLint * attrib_list)710 dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
711 		    _EGLContext *share_list, const EGLint *attrib_list)
712 {
713    struct dri2_egl_context *dri2_ctx;
714    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
715    struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
716    __DRIcontext *shared =
717       dri2_ctx_shared ? dri2_ctx_shared->dri_context : NULL;
718    struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
719    const __DRIconfig *dri_config;
720    int api;
721 
722    (void) drv;
723 
724    dri2_ctx = malloc(sizeof *dri2_ctx);
725    if (!dri2_ctx) {
726       _eglError(EGL_BAD_ALLOC, "eglCreateContext");
727       return NULL;
728    }
729 
730    if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
731       goto cleanup;
732 
733    switch (dri2_ctx->base.ClientAPI) {
734    case EGL_OPENGL_ES_API:
735       switch (dri2_ctx->base.ClientMajorVersion) {
736       case 1:
737          api = __DRI_API_GLES;
738          break;
739       case 2:
740       case 3:
741          api = __DRI_API_GLES2;
742          break;
743       default:
744 	 _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
745 	 return NULL;
746       }
747       break;
748    case EGL_OPENGL_API:
749       if ((dri2_ctx->base.ClientMajorVersion >= 4
750            || (dri2_ctx->base.ClientMajorVersion == 3
751                && dri2_ctx->base.ClientMinorVersion >= 2))
752           && dri2_ctx->base.Profile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR)
753          api = __DRI_API_OPENGL_CORE;
754       else
755          api = __DRI_API_OPENGL;
756       break;
757    default:
758       _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
759       return NULL;
760    }
761 
762    if (conf != NULL) {
763       /* The config chosen here isn't necessarily
764        * used for surfaces later.
765        * A pixmap surface will use the single config.
766        * This opportunity depends on disabling the
767        * doubleBufferMode check in
768        * src/mesa/main/context.c:check_compatible()
769        */
770       if (dri2_config->dri_double_config)
771          dri_config = dri2_config->dri_double_config;
772       else
773          dri_config = dri2_config->dri_single_config;
774 
775       /* EGL_WINDOW_BIT is set only when there is a dri_double_config.  This
776        * makes sure the back buffer will always be used.
777        */
778       if (conf->SurfaceType & EGL_WINDOW_BIT)
779          dri2_ctx->base.WindowRenderBuffer = EGL_BACK_BUFFER;
780    }
781    else
782       dri_config = NULL;
783 
784    if (dri2_dpy->dri2) {
785       if (dri2_dpy->dri2->base.version >= 3) {
786          unsigned error;
787          unsigned num_attribs = 0;
788          uint32_t ctx_attribs[8];
789 
790          ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
791          ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMajorVersion;
792          ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
793          ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMinorVersion;
794 
795          if (dri2_ctx->base.Flags != 0) {
796             /* If the implementation doesn't support the __DRI2_ROBUSTNESS
797              * extension, don't even try to send it the robust-access flag.
798              * It may explode.  Instead, generate the required EGL error here.
799              */
800             if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0
801                 && !dri2_dpy->robustness) {
802                _eglError(EGL_BAD_MATCH, "eglCreateContext");
803                goto cleanup;
804             }
805 
806             ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
807             ctx_attribs[num_attribs++] = dri2_ctx->base.Flags;
808          }
809 
810          if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) {
811             /* If the implementation doesn't support the __DRI2_ROBUSTNESS
812              * extension, don't even try to send it a reset strategy.  It may
813              * explode.  Instead, generate the required EGL error here.
814              */
815             if (!dri2_dpy->robustness) {
816                _eglError(EGL_BAD_CONFIG, "eglCreateContext");
817                goto cleanup;
818             }
819 
820             ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
821             ctx_attribs[num_attribs++] = __DRI_CTX_RESET_LOSE_CONTEXT;
822          }
823 
824          assert(num_attribs <= ARRAY_SIZE(ctx_attribs));
825 
826 	 dri2_ctx->dri_context =
827 	    dri2_dpy->dri2->createContextAttribs(dri2_dpy->dri_screen,
828                                                  api,
829                                                  dri_config,
830                                                  shared,
831                                                  num_attribs / 2,
832                                                  ctx_attribs,
833                                                  & error,
834                                                  dri2_ctx);
835 	 dri2_create_context_attribs_error(error);
836       } else {
837 	 dri2_ctx->dri_context =
838 	    dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
839 						   api,
840 						   dri_config,
841                                                    shared,
842 						   dri2_ctx);
843       }
844    } else {
845       assert(dri2_dpy->swrast);
846       dri2_ctx->dri_context =
847          dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen,
848                                                   api,
849                                                   dri_config,
850                                                   shared,
851                                                   dri2_ctx);
852    }
853 
854    if (!dri2_ctx->dri_context)
855       goto cleanup;
856 
857    return &dri2_ctx->base;
858 
859  cleanup:
860    free(dri2_ctx);
861    return NULL;
862 }
863 
864 /**
865  * Called via eglDestroyContext(), drv->API.DestroyContext().
866  */
867 static EGLBoolean
dri2_destroy_context(_EGLDriver * drv,_EGLDisplay * disp,_EGLContext * ctx)868 dri2_destroy_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
869 {
870    struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
871    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
872 
873    if (_eglPutContext(ctx)) {
874       dri2_dpy->core->destroyContext(dri2_ctx->dri_context);
875       free(dri2_ctx);
876    }
877 
878    return EGL_TRUE;
879 }
880 
881 /**
882  * Called via eglMakeCurrent(), drv->API.MakeCurrent().
883  */
884 static EGLBoolean
dri2_make_current(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * dsurf,_EGLSurface * rsurf,_EGLContext * ctx)885 dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
886 		  _EGLSurface *rsurf, _EGLContext *ctx)
887 {
888    struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
889    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
890    struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
891    struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
892    struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
893    _EGLContext *old_ctx;
894    _EGLSurface *old_dsurf, *old_rsurf;
895    __DRIdrawable *ddraw, *rdraw;
896    __DRIcontext *cctx;
897 
898    /* make new bindings */
899    if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
900       return EGL_FALSE;
901 
902    /* flush before context switch */
903    if (old_ctx && dri2_drv->glFlush)
904       dri2_drv->glFlush();
905 
906    ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
907    rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL;
908    cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
909 
910    if (old_ctx) {
911       __DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
912       dri2_dpy->core->unbindContext(old_cctx);
913    }
914 
915    if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
916        dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
917       if (old_dsurf)
918          drv->API.DestroySurface(drv, disp, old_dsurf);
919       if (old_rsurf)
920          drv->API.DestroySurface(drv, disp, old_rsurf);
921       if (old_ctx)
922          drv->API.DestroyContext(drv, disp, old_ctx);
923 
924       return EGL_TRUE;
925    } else {
926       /* undo the previous _eglBindContext */
927       _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
928       assert(&dri2_ctx->base == ctx &&
929              &dri2_dsurf->base == dsurf &&
930              &dri2_rsurf->base == rsurf);
931 
932       _eglPutSurface(dsurf);
933       _eglPutSurface(rsurf);
934       _eglPutContext(ctx);
935 
936       _eglPutSurface(old_dsurf);
937       _eglPutSurface(old_rsurf);
938       _eglPutContext(old_ctx);
939 
940       return EGL_FALSE;
941    }
942 }
943 
944 /*
945  * Called from eglGetProcAddress() via drv->API.GetProcAddress().
946  */
947 static _EGLProc
dri2_get_proc_address(_EGLDriver * drv,const char * procname)948 dri2_get_proc_address(_EGLDriver *drv, const char *procname)
949 {
950    struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
951 
952    return dri2_drv->get_proc_address(procname);
953 }
954 
955 static EGLBoolean
dri2_wait_client(_EGLDriver * drv,_EGLDisplay * disp,_EGLContext * ctx)956 dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
957 {
958    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
959    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(ctx->DrawSurface);
960 
961    (void) drv;
962 
963    /* FIXME: If EGL allows frontbuffer rendering for window surfaces,
964     * we need to copy fake to real here.*/
965 
966    (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
967 
968    return EGL_TRUE;
969 }
970 
971 static EGLBoolean
dri2_wait_native(_EGLDriver * drv,_EGLDisplay * disp,EGLint engine)972 dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine)
973 {
974    (void) drv;
975    (void) disp;
976 
977    if (engine != EGL_CORE_NATIVE_ENGINE)
978       return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
979    /* glXWaitX(); */
980 
981    return EGL_TRUE;
982 }
983 
984 static EGLBoolean
dri2_bind_tex_image(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf,EGLint buffer)985 dri2_bind_tex_image(_EGLDriver *drv,
986 		    _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
987 {
988    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
989    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
990    struct dri2_egl_context *dri2_ctx;
991    _EGLContext *ctx;
992    GLint format, target;
993 
994    ctx = _eglGetCurrentContext();
995    dri2_ctx = dri2_egl_context(ctx);
996 
997    if (!_eglBindTexImage(drv, disp, surf, buffer))
998       return EGL_FALSE;
999 
1000    switch (dri2_surf->base.TextureFormat) {
1001    case EGL_TEXTURE_RGB:
1002       format = __DRI_TEXTURE_FORMAT_RGB;
1003       break;
1004    case EGL_TEXTURE_RGBA:
1005       format = __DRI_TEXTURE_FORMAT_RGBA;
1006       break;
1007    default:
1008       assert(0);
1009    }
1010 
1011    switch (dri2_surf->base.TextureTarget) {
1012    case EGL_TEXTURE_2D:
1013       target = GL_TEXTURE_2D;
1014       break;
1015    default:
1016       assert(0);
1017    }
1018 
1019    (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
1020 					  target, format,
1021 					  dri2_surf->dri_drawable);
1022 
1023    return EGL_TRUE;
1024 }
1025 
1026 static EGLBoolean
dri2_release_tex_image(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf,EGLint buffer)1027 dri2_release_tex_image(_EGLDriver *drv,
1028 		       _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
1029 {
1030 #if __DRI_TEX_BUFFER_VERSION >= 3
1031    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1032    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1033    struct dri2_egl_context *dri2_ctx;
1034    _EGLContext *ctx;
1035    GLint  target;
1036 
1037    ctx = _eglGetCurrentContext();
1038    dri2_ctx = dri2_egl_context(ctx);
1039 
1040    if (!_eglReleaseTexImage(drv, disp, surf, buffer))
1041       return EGL_FALSE;
1042 
1043    switch (dri2_surf->base.TextureTarget) {
1044    case EGL_TEXTURE_2D:
1045       target = GL_TEXTURE_2D;
1046       break;
1047    default:
1048       assert(0);
1049    }
1050    if (dri2_dpy->tex_buffer->releaseTexBuffer!=NULL)
1051     (*dri2_dpy->tex_buffer->releaseTexBuffer)(dri2_ctx->dri_context,
1052                                              target,
1053                                              dri2_surf->dri_drawable);
1054 #endif
1055 
1056    return EGL_TRUE;
1057 }
1058 
1059 static _EGLImage *
dri2_create_image(_EGLDisplay * disp,__DRIimage * dri_image)1060 dri2_create_image(_EGLDisplay *disp, __DRIimage *dri_image)
1061 {
1062    struct dri2_egl_image *dri2_img;
1063 
1064    if (dri_image == NULL) {
1065       _eglError(EGL_BAD_ALLOC, "dri2_create_image");
1066       return NULL;
1067    }
1068 
1069    dri2_img = malloc(sizeof *dri2_img);
1070    if (!dri2_img) {
1071       _eglError(EGL_BAD_ALLOC, "dri2_create_image");
1072       return NULL;
1073    }
1074 
1075    if (!_eglInitImage(&dri2_img->base, disp)) {
1076       free(dri2_img);
1077       return NULL;
1078    }
1079 
1080    dri2_img->dri_image = dri_image;
1081 
1082    return &dri2_img->base;
1083 }
1084 
1085 static _EGLImage *
dri2_create_image_khr_renderbuffer(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)1086 dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
1087 				   EGLClientBuffer buffer,
1088 				   const EGLint *attr_list)
1089 {
1090    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1091    struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1092    GLuint renderbuffer = (GLuint) (uintptr_t) buffer;
1093    __DRIimage *dri_image;
1094 
1095    if (renderbuffer == 0) {
1096       _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
1097       return EGL_NO_IMAGE_KHR;
1098    }
1099 
1100    dri_image =
1101       dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context,
1102                                                    renderbuffer, NULL);
1103 
1104    return dri2_create_image(disp, dri_image);
1105 }
1106 
1107 static _EGLImage *
dri2_create_image_mesa_drm_buffer(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)1108 dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
1109 				  EGLClientBuffer buffer, const EGLint *attr_list)
1110 {
1111    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1112    EGLint format, name, pitch, err;
1113    _EGLImageAttribs attrs;
1114    __DRIimage *dri_image;
1115 
1116    name = (EGLint) (uintptr_t) buffer;
1117 
1118    err = _eglParseImageAttribList(&attrs, disp, attr_list);
1119    if (err != EGL_SUCCESS)
1120       return NULL;
1121 
1122    if (attrs.Width <= 0 || attrs.Height <= 0 ||
1123        attrs.DRMBufferStrideMESA <= 0) {
1124       _eglError(EGL_BAD_PARAMETER,
1125 		"bad width, height or stride");
1126       return NULL;
1127    }
1128 
1129    switch (attrs.DRMBufferFormatMESA) {
1130    case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
1131       format = __DRI_IMAGE_FORMAT_ARGB8888;
1132       pitch = attrs.DRMBufferStrideMESA;
1133       break;
1134    default:
1135       _eglError(EGL_BAD_PARAMETER,
1136 		"dri2_create_image_khr: unsupported pixmap depth");
1137       return NULL;
1138    }
1139 
1140    dri_image =
1141       dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1142 					   attrs.Width,
1143 					   attrs.Height,
1144 					   format,
1145 					   name,
1146 					   pitch,
1147 					   NULL);
1148 
1149    return dri2_create_image(disp, dri_image);
1150 }
1151 
1152 #ifdef HAVE_WAYLAND_PLATFORM
1153 
1154 /* This structure describes how a wl_buffer maps to one or more
1155  * __DRIimages.  A wl_drm_buffer stores the wl_drm format code and the
1156  * offsets and strides of the planes in the buffer.  This table maps a
1157  * wl_drm format code to a description of the planes in the buffer
1158  * that lets us create a __DRIimage for each of the planes. */
1159 
1160 static const struct wl_drm_components_descriptor {
1161    uint32_t dri_components;
1162    EGLint components;
1163    int nplanes;
1164 } wl_drm_components[] = {
1165    { __DRI_IMAGE_COMPONENTS_RGB, EGL_TEXTURE_RGB, 1 },
1166    { __DRI_IMAGE_COMPONENTS_RGBA, EGL_TEXTURE_RGBA, 1 },
1167    { __DRI_IMAGE_COMPONENTS_Y_U_V, EGL_TEXTURE_Y_U_V_WL, 3 },
1168    { __DRI_IMAGE_COMPONENTS_Y_UV, EGL_TEXTURE_Y_UV_WL, 2 },
1169    { __DRI_IMAGE_COMPONENTS_Y_XUXV, EGL_TEXTURE_Y_XUXV_WL, 2 },
1170 };
1171 
1172 static _EGLImage *
dri2_create_image_wayland_wl_buffer(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer _buffer,const EGLint * attr_list)1173 dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx,
1174 				    EGLClientBuffer _buffer,
1175 				    const EGLint *attr_list)
1176 {
1177    struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
1178    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1179    const struct wl_drm_components_descriptor *f;
1180    __DRIimage *dri_image;
1181    _EGLImageAttribs attrs;
1182    EGLint err;
1183    int32_t plane;
1184 
1185    if (!wayland_buffer_is_drm(&buffer->buffer))
1186        return NULL;
1187 
1188    err = _eglParseImageAttribList(&attrs, disp, attr_list);
1189    plane = attrs.PlaneWL;
1190    if (err != EGL_SUCCESS) {
1191       _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
1192       return NULL;
1193    }
1194 
1195    f = buffer->driver_format;
1196    if (plane < 0 || plane >= f->nplanes) {
1197       _eglError(EGL_BAD_PARAMETER,
1198                 "dri2_create_image_wayland_wl_buffer (plane out of bounds)");
1199       return NULL;
1200    }
1201 
1202    dri_image = dri2_dpy->image->fromPlanar(buffer->driver_buffer, plane, NULL);
1203 
1204    if (dri_image == NULL) {
1205       _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
1206       return NULL;
1207    }
1208 
1209    return dri2_create_image(disp, dri_image);
1210 }
1211 #endif
1212 
1213 _EGLImage *
dri2_create_image_khr(_EGLDriver * drv,_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)1214 dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
1215 		      _EGLContext *ctx, EGLenum target,
1216 		      EGLClientBuffer buffer, const EGLint *attr_list)
1217 {
1218    (void) drv;
1219 
1220    switch (target) {
1221    case EGL_GL_RENDERBUFFER_KHR:
1222       return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list);
1223    case EGL_DRM_BUFFER_MESA:
1224       return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list);
1225 #ifdef HAVE_WAYLAND_PLATFORM
1226    case EGL_WAYLAND_BUFFER_WL:
1227       return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list);
1228 #endif
1229    default:
1230       _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
1231       return EGL_NO_IMAGE_KHR;
1232    }
1233 }
1234 
1235 static EGLBoolean
dri2_destroy_image_khr(_EGLDriver * drv,_EGLDisplay * disp,_EGLImage * image)1236 dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
1237 {
1238    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1239    struct dri2_egl_image *dri2_img = dri2_egl_image(image);
1240 
1241    (void) drv;
1242 
1243    dri2_dpy->image->destroyImage(dri2_img->dri_image);
1244    free(dri2_img);
1245 
1246    return EGL_TRUE;
1247 }
1248 
1249 static _EGLImage *
dri2_create_drm_image_mesa(_EGLDriver * drv,_EGLDisplay * disp,const EGLint * attr_list)1250 dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
1251 			   const EGLint *attr_list)
1252 {
1253    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1254    struct dri2_egl_image *dri2_img;
1255    _EGLImageAttribs attrs;
1256    unsigned int dri_use, valid_mask;
1257    int format;
1258    EGLint err = EGL_SUCCESS;
1259 
1260    (void) drv;
1261 
1262    dri2_img = malloc(sizeof *dri2_img);
1263    if (!dri2_img) {
1264       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1265       return EGL_NO_IMAGE_KHR;
1266    }
1267 
1268    if (!attr_list) {
1269       err = EGL_BAD_PARAMETER;
1270       goto cleanup_img;
1271    }
1272 
1273    if (!_eglInitImage(&dri2_img->base, disp)) {
1274       err = EGL_BAD_PARAMETER;
1275       goto cleanup_img;
1276    }
1277 
1278    err = _eglParseImageAttribList(&attrs, disp, attr_list);
1279    if (err != EGL_SUCCESS)
1280       goto cleanup_img;
1281 
1282    if (attrs.Width <= 0 || attrs.Height <= 0) {
1283       _eglLog(_EGL_WARNING, "bad width or height (%dx%d)",
1284             attrs.Width, attrs.Height);
1285       goto cleanup_img;
1286    }
1287 
1288    switch (attrs.DRMBufferFormatMESA) {
1289    case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
1290       format = __DRI_IMAGE_FORMAT_ARGB8888;
1291       break;
1292    default:
1293       _eglLog(_EGL_WARNING, "bad image format value 0x%04x",
1294             attrs.DRMBufferFormatMESA);
1295       goto cleanup_img;
1296    }
1297 
1298    valid_mask =
1299       EGL_DRM_BUFFER_USE_SCANOUT_MESA |
1300       EGL_DRM_BUFFER_USE_SHARE_MESA |
1301       EGL_DRM_BUFFER_USE_CURSOR_MESA;
1302    if (attrs.DRMBufferUseMESA & ~valid_mask) {
1303       _eglLog(_EGL_WARNING, "bad image use bit 0x%04x",
1304             attrs.DRMBufferUseMESA & ~valid_mask);
1305       goto cleanup_img;
1306    }
1307 
1308    dri_use = 0;
1309    if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA)
1310       dri_use |= __DRI_IMAGE_USE_SHARE;
1311    if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
1312       dri_use |= __DRI_IMAGE_USE_SCANOUT;
1313    if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_CURSOR_MESA)
1314       dri_use |= __DRI_IMAGE_USE_CURSOR;
1315 
1316    dri2_img->dri_image =
1317       dri2_dpy->image->createImage(dri2_dpy->dri_screen,
1318 				   attrs.Width, attrs.Height,
1319                                    format, dri_use, dri2_img);
1320    if (dri2_img->dri_image == NULL) {
1321       err = EGL_BAD_ALLOC;
1322       goto cleanup_img;
1323    }
1324 
1325    return &dri2_img->base;
1326 
1327  cleanup_img:
1328    free(dri2_img);
1329    _eglError(err, "dri2_create_drm_image_mesa");
1330 
1331    return EGL_NO_IMAGE_KHR;
1332 }
1333 
1334 static EGLBoolean
dri2_export_drm_image_mesa(_EGLDriver * drv,_EGLDisplay * disp,_EGLImage * img,EGLint * name,EGLint * handle,EGLint * stride)1335 dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
1336 			  EGLint *name, EGLint *handle, EGLint *stride)
1337 {
1338    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1339    struct dri2_egl_image *dri2_img = dri2_egl_image(img);
1340 
1341    (void) drv;
1342 
1343    if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image,
1344 					    __DRI_IMAGE_ATTRIB_NAME, name)) {
1345       _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa");
1346       return EGL_FALSE;
1347    }
1348 
1349    if (handle)
1350       dri2_dpy->image->queryImage(dri2_img->dri_image,
1351 				  __DRI_IMAGE_ATTRIB_HANDLE, handle);
1352 
1353    if (stride)
1354       dri2_dpy->image->queryImage(dri2_img->dri_image,
1355 				  __DRI_IMAGE_ATTRIB_STRIDE, stride);
1356 
1357    return EGL_TRUE;
1358 }
1359 
1360 #ifdef HAVE_WAYLAND_PLATFORM
1361 
1362 static void
dri2_wl_reference_buffer(void * user_data,uint32_t name,struct wl_drm_buffer * buffer)1363 dri2_wl_reference_buffer(void *user_data, uint32_t name,
1364                          struct wl_drm_buffer *buffer)
1365 {
1366    _EGLDisplay *disp = user_data;
1367    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1368    __DRIimage *img;
1369    int i, dri_components = 0;
1370 
1371    img = dri2_dpy->image->createImageFromNames(dri2_dpy->dri_screen,
1372                                                buffer->buffer.width,
1373                                                buffer->buffer.height,
1374                                                buffer->format, (int*)&name, 1,
1375                                                buffer->stride,
1376                                                buffer->offset,
1377                                                NULL);
1378 
1379    if (img == NULL)
1380       return;
1381 
1382    dri2_dpy->image->queryImage(img, __DRI_IMAGE_ATTRIB_COMPONENTS, &dri_components);
1383 
1384    buffer->driver_format = NULL;
1385    for (i = 0; i < ARRAY_SIZE(wl_drm_components); i++)
1386       if (wl_drm_components[i].dri_components == dri_components)
1387          buffer->driver_format = &wl_drm_components[i];
1388 
1389    if (buffer->driver_format == NULL)
1390       dri2_dpy->image->destroyImage(img);
1391    else
1392       buffer->driver_buffer = img;
1393 }
1394 
1395 static void
dri2_wl_release_buffer(void * user_data,struct wl_drm_buffer * buffer)1396 dri2_wl_release_buffer(void *user_data, struct wl_drm_buffer *buffer)
1397 {
1398    _EGLDisplay *disp = user_data;
1399    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1400 
1401    dri2_dpy->image->destroyImage(buffer->driver_buffer);
1402 }
1403 
1404 static struct wayland_drm_callbacks wl_drm_callbacks = {
1405 	.authenticate = NULL,
1406 	.reference_buffer = dri2_wl_reference_buffer,
1407 	.release_buffer = dri2_wl_release_buffer
1408 };
1409 
1410 static EGLBoolean
dri2_bind_wayland_display_wl(_EGLDriver * drv,_EGLDisplay * disp,struct wl_display * wl_dpy)1411 dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
1412 			     struct wl_display *wl_dpy)
1413 {
1414    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1415 
1416    (void) drv;
1417 
1418    if (dri2_dpy->wl_server_drm)
1419 	   return EGL_FALSE;
1420 
1421    wl_drm_callbacks.authenticate =
1422       (int(*)(void *, uint32_t)) dri2_dpy->authenticate;
1423 
1424    dri2_dpy->wl_server_drm =
1425 	   wayland_drm_init(wl_dpy, dri2_dpy->device_name,
1426                             &wl_drm_callbacks, disp);
1427 
1428    if (!dri2_dpy->wl_server_drm)
1429 	   return EGL_FALSE;
1430 
1431    return EGL_TRUE;
1432 }
1433 
1434 static EGLBoolean
dri2_unbind_wayland_display_wl(_EGLDriver * drv,_EGLDisplay * disp,struct wl_display * wl_dpy)1435 dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
1436 			       struct wl_display *wl_dpy)
1437 {
1438    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1439 
1440    (void) drv;
1441 
1442    if (!dri2_dpy->wl_server_drm)
1443 	   return EGL_FALSE;
1444 
1445    wayland_drm_uninit(dri2_dpy->wl_server_drm);
1446    dri2_dpy->wl_server_drm = NULL;
1447 
1448    return EGL_TRUE;
1449 }
1450 
1451 static EGLBoolean
dri2_query_wayland_buffer_wl(_EGLDriver * drv,_EGLDisplay * disp,struct wl_buffer * _buffer,EGLint attribute,EGLint * value)1452 dri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp,
1453                              struct wl_buffer *_buffer,
1454                              EGLint attribute, EGLint *value)
1455 {
1456    struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
1457    const struct wl_drm_components_descriptor *format;
1458 
1459    if (!wayland_buffer_is_drm(&buffer->buffer))
1460       return EGL_FALSE;
1461 
1462    format = buffer->driver_format;
1463    switch (attribute) {
1464    case EGL_TEXTURE_FORMAT:
1465       *value = format->components;
1466       return EGL_TRUE;
1467    case EGL_WIDTH:
1468       *value = buffer->buffer.width;
1469       break;
1470    case EGL_HEIGHT:
1471       *value = buffer->buffer.height;
1472       break;
1473    }
1474 
1475    return EGL_FALSE;
1476 }
1477 #endif
1478 
1479 static void
dri2_unload(_EGLDriver * drv)1480 dri2_unload(_EGLDriver *drv)
1481 {
1482    struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
1483 
1484    if (dri2_drv->handle)
1485       dlclose(dri2_drv->handle);
1486    free(dri2_drv);
1487 }
1488 
1489 static EGLBoolean
dri2_load(_EGLDriver * drv)1490 dri2_load(_EGLDriver *drv)
1491 {
1492    struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
1493 #ifdef HAVE_SHARED_GLAPI
1494 #ifdef HAVE_ANDROID_PLATFORM
1495    const char *libname = "libglapi.so";
1496 #else
1497    const char *libname = "libglapi.so.0";
1498 #endif
1499 #else
1500    /*
1501     * Both libGL.so and libglapi.so are glapi providers.  There is no way to
1502     * tell which one to load.
1503     */
1504    const char *libname = NULL;
1505 #endif
1506    void *handle;
1507 
1508    /* RTLD_GLOBAL to make sure glapi symbols are visible to DRI drivers */
1509    handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
1510    if (handle) {
1511       dri2_drv->get_proc_address = (_EGLProc (*)(const char *))
1512          dlsym(handle, "_glapi_get_proc_address");
1513       if (!dri2_drv->get_proc_address || !libname) {
1514          /* no need to keep a reference */
1515          dlclose(handle);
1516          handle = NULL;
1517       }
1518    }
1519 
1520    /* if glapi is not available, loading DRI drivers will fail */
1521    if (!dri2_drv->get_proc_address) {
1522       _eglLog(_EGL_WARNING, "DRI2: failed to find _glapi_get_proc_address");
1523       return EGL_FALSE;
1524    }
1525 
1526    dri2_drv->glFlush = (void (*)(void))
1527       dri2_drv->get_proc_address("glFlush");
1528 
1529    dri2_drv->handle = handle;
1530 
1531    return EGL_TRUE;
1532 }
1533 
1534 /**
1535  * This is the main entrypoint into the driver, called by libEGL.
1536  * Create a new _EGLDriver object and init its dispatch table.
1537  */
1538 _EGLDriver *
_eglBuiltInDriverDRI2(const char * args)1539 _eglBuiltInDriverDRI2(const char *args)
1540 {
1541    struct dri2_egl_driver *dri2_drv;
1542 
1543    (void) args;
1544 
1545    dri2_drv = malloc(sizeof *dri2_drv);
1546    if (!dri2_drv)
1547       return NULL;
1548 
1549    memset(dri2_drv, 0, sizeof *dri2_drv);
1550 
1551    if (!dri2_load(&dri2_drv->base)) {
1552       free(dri2_drv);
1553       return NULL;
1554    }
1555 
1556    _eglInitDriverFallbacks(&dri2_drv->base);
1557    dri2_drv->base.API.Initialize = dri2_initialize;
1558    dri2_drv->base.API.Terminate = dri2_terminate;
1559    dri2_drv->base.API.CreateContext = dri2_create_context;
1560    dri2_drv->base.API.DestroyContext = dri2_destroy_context;
1561    dri2_drv->base.API.MakeCurrent = dri2_make_current;
1562    dri2_drv->base.API.GetProcAddress = dri2_get_proc_address;
1563    dri2_drv->base.API.WaitClient = dri2_wait_client;
1564    dri2_drv->base.API.WaitNative = dri2_wait_native;
1565    dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
1566    dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
1567    dri2_drv->base.API.CreateImageKHR = dri2_create_image_khr;
1568    dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr;
1569    dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa;
1570    dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa;
1571 #ifdef HAVE_WAYLAND_PLATFORM
1572    dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;
1573    dri2_drv->base.API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl;
1574    dri2_drv->base.API.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl;
1575 #endif
1576 
1577    dri2_drv->base.Name = "DRI2";
1578    dri2_drv->base.Unload = dri2_unload;
1579 
1580    return &dri2_drv->base;
1581 }
1582