st/xa: Fix crosscompile builds with nonstandard ld locations
[mesa.git] / src / egl / drivers / dri2 / egl_dri2.c
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
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 *
113 dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
114 int depth, EGLint surface_type, const EGLint *attr_list)
115 {
116 struct dri2_egl_config *conf;
117 struct dri2_egl_display *dri2_dpy;
118 _EGLConfig base;
119 unsigned int attrib, value, double_buffer;
120 EGLint key, bind_to_texture_rgb, bind_to_texture_rgba;
121 _EGLConfig *matching_config;
122 EGLint num_configs = 0;
123 EGLint config_id;
124 int i;
125
126 dri2_dpy = disp->DriverData;
127 _eglInitConfig(&base, disp, id);
128
129 i = 0;
130 double_buffer = 0;
131 bind_to_texture_rgb = 0;
132 bind_to_texture_rgba = 0;
133
134 while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) {
135 switch (attrib) {
136 case __DRI_ATTRIB_RENDER_TYPE:
137 if (value & __DRI_ATTRIB_RGBA_BIT)
138 value = EGL_RGB_BUFFER;
139 else if (value & __DRI_ATTRIB_LUMINANCE_BIT)
140 value = EGL_LUMINANCE_BUFFER;
141 else
142 /* not valid */;
143 _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value);
144 break;
145
146 case __DRI_ATTRIB_CONFIG_CAVEAT:
147 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
148 value = EGL_NON_CONFORMANT_CONFIG;
149 else if (value & __DRI_ATTRIB_SLOW_BIT)
150 value = EGL_SLOW_CONFIG;
151 else
152 value = EGL_NONE;
153 _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value);
154 break;
155
156 case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB:
157 bind_to_texture_rgb = value;
158 break;
159
160 case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA:
161 bind_to_texture_rgba = value;
162 break;
163
164 case __DRI_ATTRIB_DOUBLE_BUFFER:
165 double_buffer = value;
166 break;
167
168 default:
169 key = dri2_to_egl_attribute_map[attrib];
170 if (key != 0)
171 _eglSetConfigKey(&base, key, value);
172 break;
173 }
174 }
175
176 if (attr_list)
177 for (i = 0; attr_list[i] != EGL_NONE; i += 2)
178 _eglSetConfigKey(&base, attr_list[i], attr_list[i+1]);
179
180 if (depth > 0 && depth != base.BufferSize)
181 return NULL;
182
183 base.NativeRenderable = EGL_TRUE;
184
185 base.SurfaceType = surface_type;
186 if (surface_type & (EGL_PBUFFER_BIT |
187 (disp->Extensions.NOK_texture_from_pixmap ? EGL_PIXMAP_BIT : 0))) {
188 base.BindToTextureRGB = bind_to_texture_rgb;
189 if (base.AlphaSize > 0)
190 base.BindToTextureRGBA = bind_to_texture_rgba;
191 }
192
193 base.RenderableType = disp->ClientAPIs;
194 base.Conformant = disp->ClientAPIs;
195
196 if (!_eglValidateConfig(&base, EGL_FALSE)) {
197 _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
198 return NULL;
199 }
200
201 config_id = base.ConfigID;
202 base.ConfigID = EGL_DONT_CARE;
203 base.SurfaceType = EGL_DONT_CARE;
204 num_configs = _eglFilterArray(disp->Configs, (void **) &matching_config, 1,
205 (_EGLArrayForEach) dri2_match_config, &base);
206
207 if (num_configs == 1) {
208 conf = (struct dri2_egl_config *) matching_config;
209
210 if (double_buffer && !conf->dri_double_config)
211 conf->dri_double_config = dri_config;
212 else if (!double_buffer && !conf->dri_single_config)
213 conf->dri_single_config = dri_config;
214 else
215 /* a similar config type is already added (unlikely) => discard */
216 return NULL;
217 }
218 else if (num_configs == 0) {
219 conf = malloc(sizeof *conf);
220 if (conf == NULL)
221 return NULL;
222
223 memcpy(&conf->base, &base, sizeof base);
224 if (double_buffer) {
225 conf->dri_double_config = dri_config;
226 conf->dri_single_config = NULL;
227 } else {
228 conf->dri_single_config = dri_config;
229 conf->dri_double_config = NULL;
230 }
231 conf->base.SurfaceType = 0;
232 conf->base.ConfigID = config_id;
233
234 _eglLinkConfig(&conf->base);
235 }
236 else {
237 assert(0);
238 return NULL;
239 }
240
241 conf->base.SurfaceType |= surface_type & (!double_buffer ? EGL_PIXMAP_BIT:
242 (EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT));
243
244 return conf;
245 }
246
247 static __DRIimage *
248 dri2_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
249 {
250 _EGLDisplay *disp = data;
251 struct dri2_egl_image *dri2_img;
252 _EGLImage *img;
253
254 (void) screen;
255
256 img = _eglLookupImage(image, disp);
257 if (img == NULL) {
258 _eglError(EGL_BAD_PARAMETER, "dri2_lookup_egl_image");
259 return NULL;
260 }
261
262 dri2_img = dri2_egl_image(image);
263
264 return dri2_img->dri_image;
265 }
266
267 const __DRIimageLookupExtension image_lookup_extension = {
268 { __DRI_IMAGE_LOOKUP, 1 },
269 dri2_lookup_egl_image
270 };
271
272 static const char dri_driver_path[] = DEFAULT_DRIVER_DIR;
273
274 struct dri2_extension_match {
275 const char *name;
276 int version;
277 int offset;
278 };
279
280 static struct dri2_extension_match dri2_driver_extensions[] = {
281 { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
282 { __DRI_DRI2, 1, offsetof(struct dri2_egl_display, dri2) },
283 { NULL, 0, 0 }
284 };
285
286 static struct dri2_extension_match dri2_core_extensions[] = {
287 { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
288 { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
289 { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
290 { NULL, 0, 0 }
291 };
292
293 static struct dri2_extension_match swrast_driver_extensions[] = {
294 { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
295 { __DRI_SWRAST, 2, offsetof(struct dri2_egl_display, swrast) },
296 { NULL }
297 };
298
299 static struct dri2_extension_match swrast_core_extensions[] = {
300 { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
301 { NULL }
302 };
303
304 static EGLBoolean
305 dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
306 struct dri2_extension_match *matches,
307 const __DRIextension **extensions)
308 {
309 int i, j, ret = EGL_TRUE;
310 void *field;
311
312 for (i = 0; extensions[i]; i++) {
313 _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name);
314 for (j = 0; matches[j].name; j++) {
315 if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
316 extensions[i]->version >= matches[j].version) {
317 field = ((char *) dri2_dpy + matches[j].offset);
318 *(const __DRIextension **) field = extensions[i];
319 _eglLog(_EGL_INFO, "DRI2: found extension %s version %d",
320 extensions[i]->name, extensions[i]->version);
321 }
322 }
323 }
324
325 for (j = 0; matches[j].name; j++) {
326 field = ((char *) dri2_dpy + matches[j].offset);
327 if (*(const __DRIextension **) field == NULL) {
328 _eglLog(_EGL_FATAL, "DRI2: did not find extension %s version %d",
329 matches[j].name, matches[j].version);
330 ret = EGL_FALSE;
331 }
332 }
333
334 return ret;
335 }
336
337 static const __DRIextension **
338 dri2_open_driver(_EGLDisplay *disp)
339 {
340 struct dri2_egl_display *dri2_dpy = disp->DriverData;
341 const __DRIextension **extensions;
342 char path[PATH_MAX], *search_paths, *p, *next, *end;
343
344 search_paths = NULL;
345 if (geteuid() == getuid()) {
346 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
347 search_paths = getenv("LIBGL_DRIVERS_PATH");
348 }
349 if (search_paths == NULL)
350 search_paths = DEFAULT_DRIVER_DIR;
351
352 dri2_dpy->driver = NULL;
353 end = search_paths + strlen(search_paths);
354 for (p = search_paths; p < end && dri2_dpy->driver == NULL; p = next + 1) {
355 int len;
356 next = strchr(p, ':');
357 if (next == NULL)
358 next = end;
359
360 len = next - p;
361 #if GLX_USE_TLS
362 snprintf(path, sizeof path,
363 "%.*s/tls/%s_dri.so", len, p, dri2_dpy->driver_name);
364 dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
365 #endif
366 if (dri2_dpy->driver == NULL) {
367 snprintf(path, sizeof path,
368 "%.*s/%s_dri.so", len, p, dri2_dpy->driver_name);
369 dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
370 if (dri2_dpy->driver == NULL)
371 _eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror());
372 }
373 }
374
375 if (dri2_dpy->driver == NULL) {
376 _eglLog(_EGL_WARNING,
377 "DRI2: failed to open %s (search paths %s)",
378 dri2_dpy->driver_name, search_paths);
379 return NULL;
380 }
381
382 _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
383 extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS);
384 if (extensions == NULL) {
385 _eglLog(_EGL_WARNING,
386 "DRI2: driver exports no extensions (%s)", dlerror());
387 dlclose(dri2_dpy->driver);
388 }
389
390 return extensions;
391 }
392
393 EGLBoolean
394 dri2_load_driver(_EGLDisplay *disp)
395 {
396 struct dri2_egl_display *dri2_dpy = disp->DriverData;
397 const __DRIextension **extensions;
398
399 extensions = dri2_open_driver(disp);
400 if (!extensions)
401 return EGL_FALSE;
402
403 if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) {
404 dlclose(dri2_dpy->driver);
405 return EGL_FALSE;
406 }
407
408 return EGL_TRUE;
409 }
410
411 EGLBoolean
412 dri2_load_driver_swrast(_EGLDisplay *disp)
413 {
414 struct dri2_egl_display *dri2_dpy = disp->DriverData;
415 const __DRIextension **extensions;
416
417 dri2_dpy->driver_name = "swrast";
418 extensions = dri2_open_driver(disp);
419 if (!extensions) {
420 /* try again with swrastg */
421 dri2_dpy->driver_name = "swrastg";
422 extensions = dri2_open_driver(disp);
423 }
424
425 if (!extensions)
426 return EGL_FALSE;
427
428 if (!dri2_bind_extensions(dri2_dpy, swrast_driver_extensions, extensions)) {
429 dlclose(dri2_dpy->driver);
430 return EGL_FALSE;
431 }
432
433 return EGL_TRUE;
434 }
435
436 EGLBoolean
437 dri2_create_screen(_EGLDisplay *disp)
438 {
439 const __DRIextension **extensions;
440 struct dri2_egl_display *dri2_dpy;
441 unsigned int api_mask;
442
443 dri2_dpy = disp->DriverData;
444
445 if (dri2_dpy->dri2) {
446 dri2_dpy->dri_screen =
447 dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
448 &dri2_dpy->driver_configs, disp);
449 } else {
450 assert(dri2_dpy->swrast);
451 dri2_dpy->dri_screen =
452 dri2_dpy->swrast->createNewScreen(0, dri2_dpy->extensions,
453 &dri2_dpy->driver_configs, disp);
454 }
455
456 if (dri2_dpy->dri_screen == NULL) {
457 _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
458 return EGL_FALSE;
459 }
460
461 extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
462
463 if (dri2_dpy->dri2) {
464 if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
465 goto cleanup_dri_screen;
466 } else {
467 assert(dri2_dpy->swrast);
468 if (!dri2_bind_extensions(dri2_dpy, swrast_core_extensions, extensions))
469 goto cleanup_dri_screen;
470 }
471
472 if (dri2_dpy->dri2) {
473 if (dri2_dpy->dri2->base.version >= 2)
474 api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
475 else
476 api_mask = 1 << __DRI_API_OPENGL;
477 } else {
478 assert(dri2_dpy->swrast);
479 if (dri2_dpy->swrast->base.version >= 2)
480 api_mask = 1 << __DRI_API_OPENGL | 1 << __DRI_API_GLES | 1 << __DRI_API_GLES2;
481 else
482 api_mask = 1 << __DRI_API_OPENGL;
483 }
484
485 disp->ClientAPIs = 0;
486 if (api_mask & (1 <<__DRI_API_OPENGL))
487 disp->ClientAPIs |= EGL_OPENGL_BIT;
488 if (api_mask & (1 <<__DRI_API_GLES))
489 disp->ClientAPIs |= EGL_OPENGL_ES_BIT;
490 if (api_mask & (1 << __DRI_API_GLES2))
491 disp->ClientAPIs |= EGL_OPENGL_ES2_BIT;
492
493 if (dri2_dpy->dri2) {
494 if (dri2_dpy->dri2->base.version >= 2) {
495 disp->Extensions.KHR_surfaceless_gles1 = EGL_TRUE;
496 disp->Extensions.KHR_surfaceless_gles2 = EGL_TRUE;
497 disp->Extensions.KHR_surfaceless_opengl = EGL_TRUE;
498 }
499 } else {
500 assert(dri2_dpy->swrast);
501 if (dri2_dpy->swrast->base.version >= 2) {
502 disp->Extensions.KHR_surfaceless_gles1 = EGL_TRUE;
503 disp->Extensions.KHR_surfaceless_gles2 = EGL_TRUE;
504 disp->Extensions.KHR_surfaceless_opengl = EGL_TRUE;
505 }
506 }
507
508 if (dri2_dpy->image) {
509 disp->Extensions.MESA_drm_image = EGL_TRUE;
510 disp->Extensions.KHR_image_base = EGL_TRUE;
511 disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
512 }
513
514 return EGL_TRUE;
515
516 cleanup_dri_screen:
517 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
518
519 return EGL_FALSE;
520 }
521
522 /**
523 * Called via eglInitialize(), GLX_drv->API.Initialize().
524 */
525 static EGLBoolean
526 dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp)
527 {
528 /* not until swrast_dri is supported */
529 if (disp->Options.UseFallback)
530 return EGL_FALSE;
531
532 switch (disp->Platform) {
533 #ifdef HAVE_X11_PLATFORM
534 case _EGL_PLATFORM_X11:
535 if (disp->Options.TestOnly)
536 return EGL_TRUE;
537 return dri2_initialize_x11(drv, disp);
538 #endif
539
540 #ifdef HAVE_LIBUDEV
541 case _EGL_PLATFORM_DRM:
542 if (disp->Options.TestOnly)
543 return EGL_TRUE;
544 return dri2_initialize_drm(drv, disp);
545 #ifdef HAVE_WAYLAND_PLATFORM
546 case _EGL_PLATFORM_WAYLAND:
547 if (disp->Options.TestOnly)
548 return EGL_TRUE;
549 return dri2_initialize_wayland(drv, disp);
550 #endif
551 #endif
552
553 default:
554 return EGL_FALSE;
555 }
556 }
557
558 /**
559 * Called via eglTerminate(), drv->API.Terminate().
560 */
561 static EGLBoolean
562 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
563 {
564 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
565
566 _eglReleaseDisplayResources(drv, disp);
567 _eglCleanupDisplay(disp);
568
569 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
570 if (dri2_dpy->fd)
571 close(dri2_dpy->fd);
572 dlclose(dri2_dpy->driver);
573
574 if (disp->PlatformDisplay == NULL) {
575 switch (disp->Platform) {
576 #ifdef HAVE_X11_PLATFORM
577 case _EGL_PLATFORM_X11:
578 xcb_disconnect(dri2_dpy->conn);
579 break;
580 #endif
581 #ifdef HAVE_WAYLAND_PLATFORM
582 case _EGL_PLATFORM_WAYLAND:
583 wl_display_destroy(dri2_dpy->wl_dpy);
584 break;
585 #endif
586 default:
587 break;
588 }
589 }
590
591 free(dri2_dpy);
592 disp->DriverData = NULL;
593
594 return EGL_TRUE;
595 }
596
597
598 /**
599 * Called via eglCreateContext(), drv->API.CreateContext().
600 */
601 static _EGLContext *
602 dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
603 _EGLContext *share_list, const EGLint *attrib_list)
604 {
605 struct dri2_egl_context *dri2_ctx;
606 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
607 struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
608 struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
609 const __DRIconfig *dri_config;
610 int api;
611
612 (void) drv;
613
614 dri2_ctx = malloc(sizeof *dri2_ctx);
615 if (!dri2_ctx) {
616 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
617 return NULL;
618 }
619
620 if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
621 goto cleanup;
622
623 switch (dri2_ctx->base.ClientAPI) {
624 case EGL_OPENGL_ES_API:
625 switch (dri2_ctx->base.ClientVersion) {
626 case 1:
627 api = __DRI_API_GLES;
628 break;
629 case 2:
630 api = __DRI_API_GLES2;
631 break;
632 default:
633 _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
634 return NULL;
635 }
636 break;
637 case EGL_OPENGL_API:
638 api = __DRI_API_OPENGL;
639 break;
640 default:
641 _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
642 return NULL;
643 }
644
645 if (conf != NULL) {
646 /* The config chosen here isn't necessarily
647 * used for surfaces later.
648 * A pixmap surface will use the single config.
649 * This opportunity depends on disabling the
650 * doubleBufferMode check in
651 * src/mesa/main/context.c:check_compatible()
652 */
653 if (dri2_config->dri_double_config)
654 dri_config = dri2_config->dri_double_config;
655 else
656 dri_config = dri2_config->dri_single_config;
657 }
658 else
659 dri_config = NULL;
660
661 if (dri2_dpy->dri2) {
662 if (dri2_dpy->dri2->base.version >= 2) {
663 dri2_ctx->dri_context =
664 dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
665 api,
666 dri_config,
667 dri2_ctx_shared ?
668 dri2_ctx_shared->dri_context : NULL,
669 dri2_ctx);
670 } else if (api == __DRI_API_OPENGL) {
671 dri2_ctx->dri_context =
672 dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen,
673 dri_config,
674 dri2_ctx_shared ?
675 dri2_ctx_shared->dri_context : NULL,
676 dri2_ctx);
677 } else {
678 /* fail */
679 }
680 } else {
681 assert(dri2_dpy->swrast);
682 if (dri2_dpy->swrast->base.version >= 2) {
683 dri2_ctx->dri_context =
684 dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen,
685 api,
686 dri_config,
687 dri2_ctx_shared ?
688 dri2_ctx_shared->dri_context : NULL,
689 dri2_ctx);
690 } else if (api == __DRI_API_OPENGL) {
691 dri2_ctx->dri_context =
692 dri2_dpy->core->createNewContext(dri2_dpy->dri_screen,
693 dri_config,
694 dri2_ctx_shared ?
695 dri2_ctx_shared->dri_context : NULL,
696 dri2_ctx);
697 } else {
698 /* fail */
699 }
700 }
701
702 if (!dri2_ctx->dri_context)
703 goto cleanup;
704
705 return &dri2_ctx->base;
706
707 cleanup:
708 free(dri2_ctx);
709 return NULL;
710 }
711
712 /**
713 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
714 */
715 static EGLBoolean
716 dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
717 _EGLSurface *rsurf, _EGLContext *ctx)
718 {
719 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
720 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
721 struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
722 struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
723 struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
724 _EGLContext *old_ctx;
725 _EGLSurface *old_dsurf, *old_rsurf;
726 __DRIdrawable *ddraw, *rdraw;
727 __DRIcontext *cctx;
728
729 /* make new bindings */
730 if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
731 return EGL_FALSE;
732
733 /* flush before context switch */
734 if (old_ctx && dri2_drv->glFlush)
735 dri2_drv->glFlush();
736
737 ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
738 rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL;
739 cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
740
741 if (old_ctx) {
742 __DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
743 dri2_dpy->core->unbindContext(old_cctx);
744 }
745
746 if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
747 dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
748 if (old_dsurf)
749 drv->API.DestroySurface(drv, disp, old_dsurf);
750 if (old_rsurf)
751 drv->API.DestroySurface(drv, disp, old_rsurf);
752 /* no destroy? */
753 if (old_ctx)
754 _eglPutContext(old_ctx);
755
756 return EGL_TRUE;
757 } else {
758 /* undo the previous _eglBindContext */
759 _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
760 assert(&dri2_ctx->base == ctx &&
761 &dri2_dsurf->base == dsurf &&
762 &dri2_rsurf->base == rsurf);
763
764 _eglPutSurface(dsurf);
765 _eglPutSurface(rsurf);
766 _eglPutContext(ctx);
767
768 _eglPutSurface(old_dsurf);
769 _eglPutSurface(old_rsurf);
770 _eglPutContext(old_ctx);
771
772 return EGL_FALSE;
773 }
774 }
775
776 /*
777 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
778 */
779 static _EGLProc
780 dri2_get_proc_address(_EGLDriver *drv, const char *procname)
781 {
782 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
783
784 return dri2_drv->get_proc_address(procname);
785 }
786
787 static EGLBoolean
788 dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
789 {
790 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
791 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(ctx->DrawSurface);
792
793 (void) drv;
794
795 /* FIXME: If EGL allows frontbuffer rendering for window surfaces,
796 * we need to copy fake to real here.*/
797
798 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
799
800 return EGL_TRUE;
801 }
802
803 static EGLBoolean
804 dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine)
805 {
806 (void) drv;
807 (void) disp;
808
809 if (engine != EGL_CORE_NATIVE_ENGINE)
810 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
811 /* glXWaitX(); */
812
813 return EGL_TRUE;
814 }
815
816 static EGLBoolean
817 dri2_bind_tex_image(_EGLDriver *drv,
818 _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
819 {
820 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
821 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
822 struct dri2_egl_context *dri2_ctx;
823 _EGLContext *ctx;
824 GLint format, target;
825
826 ctx = _eglGetCurrentContext();
827 dri2_ctx = dri2_egl_context(ctx);
828
829 if (!_eglBindTexImage(drv, disp, surf, buffer))
830 return EGL_FALSE;
831
832 switch (dri2_surf->base.TextureFormat) {
833 case EGL_TEXTURE_RGB:
834 format = __DRI_TEXTURE_FORMAT_RGB;
835 break;
836 case EGL_TEXTURE_RGBA:
837 format = __DRI_TEXTURE_FORMAT_RGBA;
838 break;
839 default:
840 assert(0);
841 }
842
843 switch (dri2_surf->base.TextureTarget) {
844 case EGL_TEXTURE_2D:
845 target = GL_TEXTURE_2D;
846 break;
847 default:
848 assert(0);
849 }
850
851 (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
852 target, format,
853 dri2_surf->dri_drawable);
854
855 return EGL_TRUE;
856 }
857
858 static EGLBoolean
859 dri2_release_tex_image(_EGLDriver *drv,
860 _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
861 {
862 #if __DRI_TEX_BUFFER_VERSION >= 3
863 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
864 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
865 struct dri2_egl_context *dri2_ctx;
866 _EGLContext *ctx;
867 GLint target;
868
869 ctx = _eglGetCurrentContext();
870 dri2_ctx = dri2_egl_context(ctx);
871
872 if (!_eglReleaseTexImage(drv, disp, surf, buffer))
873 return EGL_FALSE;
874
875 switch (dri2_surf->base.TextureTarget) {
876 case EGL_TEXTURE_2D:
877 target = GL_TEXTURE_2D;
878 break;
879 default:
880 assert(0);
881 }
882 if (dri2_dpy->tex_buffer->releaseTexBuffer!=NULL)
883 (*dri2_dpy->tex_buffer->releaseTexBuffer)(dri2_ctx->dri_context,
884 target,
885 dri2_surf->dri_drawable);
886 #endif
887
888 return EGL_TRUE;
889 }
890
891 static _EGLImage *
892 dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
893 EGLClientBuffer buffer,
894 const EGLint *attr_list)
895 {
896 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
897 struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
898 struct dri2_egl_image *dri2_img;
899 GLuint renderbuffer = (GLuint) (uintptr_t) buffer;
900
901 if (renderbuffer == 0) {
902 _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
903 return EGL_NO_IMAGE_KHR;
904 }
905
906 dri2_img = malloc(sizeof *dri2_img);
907 if (!dri2_img) {
908 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
909 return EGL_NO_IMAGE_KHR;
910 }
911
912 if (!_eglInitImage(&dri2_img->base, disp))
913 return EGL_NO_IMAGE_KHR;
914
915 dri2_img->dri_image =
916 dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context,
917 renderbuffer,
918 dri2_img);
919
920 return &dri2_img->base;
921 }
922
923 static _EGLImage *
924 dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
925 EGLClientBuffer buffer, const EGLint *attr_list)
926 {
927 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
928 struct dri2_egl_image *dri2_img;
929 EGLint format, name, pitch, err;
930 _EGLImageAttribs attrs;
931
932 (void) ctx;
933
934 name = (EGLint) (uintptr_t) buffer;
935
936 err = _eglParseImageAttribList(&attrs, disp, attr_list);
937 if (err != EGL_SUCCESS)
938 return NULL;
939
940 if (attrs.Width <= 0 || attrs.Height <= 0 ||
941 attrs.DRMBufferStrideMESA <= 0) {
942 _eglError(EGL_BAD_PARAMETER,
943 "bad width, height or stride");
944 return NULL;
945 }
946
947 switch (attrs.DRMBufferFormatMESA) {
948 case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
949 format = __DRI_IMAGE_FORMAT_ARGB8888;
950 pitch = attrs.DRMBufferStrideMESA;
951 break;
952 default:
953 _eglError(EGL_BAD_PARAMETER,
954 "dri2_create_image_khr: unsupported pixmap depth");
955 return NULL;
956 }
957
958 dri2_img = malloc(sizeof *dri2_img);
959 if (!dri2_img) {
960 _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm");
961 return NULL;
962 }
963
964 if (!_eglInitImage(&dri2_img->base, disp)) {
965 free(dri2_img);
966 return NULL;
967 }
968
969 dri2_img->dri_image =
970 dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
971 attrs.Width,
972 attrs.Height,
973 format,
974 name,
975 pitch,
976 dri2_img);
977 if (dri2_img->dri_image == NULL) {
978 free(dri2_img);
979 _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm");
980 return NULL;
981 }
982
983 return &dri2_img->base;
984 }
985
986 #ifdef HAVE_WAYLAND_PLATFORM
987 static _EGLImage *
988 dri2_reference_drm_image(_EGLDisplay *disp, _EGLContext *ctx,
989 __DRIimage *dri_image, EGLint width, EGLint height)
990 {
991 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
992 EGLint attr_list[] = {
993 EGL_WIDTH, 0,
994 EGL_HEIGHT, 0,
995 EGL_DRM_BUFFER_STRIDE_MESA, 0,
996 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
997 EGL_NONE
998 };
999 EGLint name, stride;
1000
1001 dri2_dpy->image->queryImage(dri_image, __DRI_IMAGE_ATTRIB_NAME, &name);
1002 dri2_dpy->image->queryImage(dri_image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
1003
1004 attr_list[1] = width;
1005 attr_list[3] = height;
1006 attr_list[5] = stride / 4;
1007
1008 return dri2_create_image_mesa_drm_buffer(disp, ctx,
1009 (EGLClientBuffer)(intptr_t) name,
1010 attr_list);
1011 }
1012
1013 static _EGLImage *
1014 dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx,
1015 EGLClientBuffer _buffer,
1016 const EGLint *attr_list)
1017 {
1018 struct wl_buffer *buffer = (struct wl_buffer *) _buffer;
1019 (void) attr_list;
1020
1021 if (!wayland_buffer_is_drm(buffer))
1022 return NULL;
1023
1024 return dri2_reference_drm_image(disp, ctx,
1025 wayland_drm_buffer_get_buffer(buffer),
1026 buffer->width,
1027 buffer->height);
1028 }
1029 #endif
1030
1031 _EGLImage *
1032 dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
1033 _EGLContext *ctx, EGLenum target,
1034 EGLClientBuffer buffer, const EGLint *attr_list)
1035 {
1036 (void) drv;
1037
1038 switch (target) {
1039 case EGL_GL_RENDERBUFFER_KHR:
1040 return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list);
1041 case EGL_DRM_BUFFER_MESA:
1042 return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list);
1043 #ifdef HAVE_WAYLAND_PLATFORM
1044 case EGL_WAYLAND_BUFFER_WL:
1045 return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list);
1046 #endif
1047 default:
1048 _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
1049 return EGL_NO_IMAGE_KHR;
1050 }
1051 }
1052
1053 static EGLBoolean
1054 dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
1055 {
1056 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1057 struct dri2_egl_image *dri2_img = dri2_egl_image(image);
1058
1059 (void) drv;
1060
1061 dri2_dpy->image->destroyImage(dri2_img->dri_image);
1062 free(dri2_img);
1063
1064 return EGL_TRUE;
1065 }
1066
1067 static _EGLImage *
1068 dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
1069 const EGLint *attr_list)
1070 {
1071 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1072 struct dri2_egl_image *dri2_img;
1073 _EGLImageAttribs attrs;
1074 unsigned int dri_use, valid_mask;
1075 int format;
1076 EGLint err = EGL_SUCCESS;
1077
1078 (void) drv;
1079
1080 dri2_img = malloc(sizeof *dri2_img);
1081 if (!dri2_img) {
1082 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1083 return EGL_NO_IMAGE_KHR;
1084 }
1085
1086 if (!attr_list) {
1087 err = EGL_BAD_PARAMETER;
1088 goto cleanup_img;
1089 }
1090
1091 if (!_eglInitImage(&dri2_img->base, disp)) {
1092 err = EGL_BAD_PARAMETER;
1093 goto cleanup_img;
1094 }
1095
1096 err = _eglParseImageAttribList(&attrs, disp, attr_list);
1097 if (err != EGL_SUCCESS)
1098 goto cleanup_img;
1099
1100 if (attrs.Width <= 0 || attrs.Height <= 0) {
1101 _eglLog(_EGL_WARNING, "bad width or height (%dx%d)",
1102 attrs.Width, attrs.Height);
1103 goto cleanup_img;
1104 }
1105
1106 switch (attrs.DRMBufferFormatMESA) {
1107 case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
1108 format = __DRI_IMAGE_FORMAT_ARGB8888;
1109 break;
1110 default:
1111 _eglLog(_EGL_WARNING, "bad image format value 0x%04x",
1112 attrs.DRMBufferFormatMESA);
1113 goto cleanup_img;
1114 }
1115
1116 valid_mask =
1117 EGL_DRM_BUFFER_USE_SCANOUT_MESA |
1118 EGL_DRM_BUFFER_USE_SHARE_MESA |
1119 EGL_DRM_BUFFER_USE_CURSOR_MESA;
1120 if (attrs.DRMBufferUseMESA & ~valid_mask) {
1121 _eglLog(_EGL_WARNING, "bad image use bit 0x%04x",
1122 attrs.DRMBufferUseMESA & ~valid_mask);
1123 goto cleanup_img;
1124 }
1125
1126 dri_use = 0;
1127 if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA)
1128 dri_use |= __DRI_IMAGE_USE_SHARE;
1129 if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
1130 dri_use |= __DRI_IMAGE_USE_SCANOUT;
1131 if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_CURSOR_MESA)
1132 dri_use |= __DRI_IMAGE_USE_CURSOR;
1133
1134 dri2_img->dri_image =
1135 dri2_dpy->image->createImage(dri2_dpy->dri_screen,
1136 attrs.Width, attrs.Height,
1137 format, dri_use, dri2_img);
1138 if (dri2_img->dri_image == NULL) {
1139 err = EGL_BAD_ALLOC;
1140 goto cleanup_img;
1141 }
1142
1143 return &dri2_img->base;
1144
1145 cleanup_img:
1146 free(dri2_img);
1147 _eglError(err, "dri2_create_drm_image_mesa");
1148
1149 return EGL_NO_IMAGE_KHR;
1150 }
1151
1152 static EGLBoolean
1153 dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
1154 EGLint *name, EGLint *handle, EGLint *stride)
1155 {
1156 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1157 struct dri2_egl_image *dri2_img = dri2_egl_image(img);
1158
1159 (void) drv;
1160
1161 if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image,
1162 __DRI_IMAGE_ATTRIB_NAME, name)) {
1163 _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa");
1164 return EGL_FALSE;
1165 }
1166
1167 if (handle)
1168 dri2_dpy->image->queryImage(dri2_img->dri_image,
1169 __DRI_IMAGE_ATTRIB_HANDLE, handle);
1170
1171 if (stride)
1172 dri2_dpy->image->queryImage(dri2_img->dri_image,
1173 __DRI_IMAGE_ATTRIB_STRIDE, stride);
1174
1175 return EGL_TRUE;
1176 }
1177
1178 #ifdef HAVE_WAYLAND_PLATFORM
1179
1180 static void *
1181 dri2_wl_reference_buffer(void *user_data, uint32_t name,
1182 int32_t width, int32_t height,
1183 uint32_t stride, struct wl_visual *visual)
1184 {
1185 _EGLDisplay *disp = user_data;
1186 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1187 __DRIimage *image;
1188
1189 image = dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1190 width, height,
1191 __DRI_IMAGE_FORMAT_ARGB8888,
1192 name, stride / 4,
1193 NULL);
1194
1195 return image;
1196 }
1197
1198 static void
1199 dri2_wl_release_buffer(void *user_data, void *buffer)
1200 {
1201 _EGLDisplay *disp = user_data;
1202 __DRIimage *image = buffer;
1203 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1204
1205 dri2_dpy->image->destroyImage(image);
1206 }
1207
1208 static struct wayland_drm_callbacks wl_drm_callbacks = {
1209 .authenticate = NULL,
1210 .reference_buffer = dri2_wl_reference_buffer,
1211 .release_buffer = dri2_wl_release_buffer
1212 };
1213
1214 static EGLBoolean
1215 dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
1216 struct wl_display *wl_dpy)
1217 {
1218 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1219
1220 (void) drv;
1221
1222 if (dri2_dpy->wl_server_drm)
1223 return EGL_FALSE;
1224
1225 wl_drm_callbacks.authenticate =
1226 (int(*)(void *, uint32_t)) dri2_dpy->authenticate;
1227
1228 dri2_dpy->wl_server_drm =
1229 wayland_drm_init(wl_dpy, dri2_dpy->device_name,
1230 &wl_drm_callbacks, disp);
1231
1232 if (!dri2_dpy->wl_server_drm)
1233 return EGL_FALSE;
1234
1235 return EGL_TRUE;
1236 }
1237
1238 static EGLBoolean
1239 dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
1240 struct wl_display *wl_dpy)
1241 {
1242 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1243
1244 (void) drv;
1245
1246 if (!dri2_dpy->wl_server_drm)
1247 return EGL_FALSE;
1248
1249 wayland_drm_uninit(dri2_dpy->wl_server_drm);
1250 dri2_dpy->wl_server_drm = NULL;
1251
1252 return EGL_TRUE;
1253 }
1254 #endif
1255
1256 static void
1257 dri2_unload(_EGLDriver *drv)
1258 {
1259 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
1260
1261 if (dri2_drv->handle)
1262 dlclose(dri2_drv->handle);
1263 free(dri2_drv);
1264 }
1265
1266 static EGLBoolean
1267 dri2_load(_EGLDriver *drv)
1268 {
1269 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
1270 #ifdef HAVE_SHARED_GLAPI
1271 const char *libname = "libglapi.so.0";
1272 #else
1273 /*
1274 * Both libGL.so and libglapi.so are glapi providers. There is no way to
1275 * tell which one to load.
1276 */
1277 const char *libname = NULL;
1278 #endif
1279 void *handle;
1280
1281 /* RTLD_GLOBAL to make sure glapi symbols are visible to DRI drivers */
1282 handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
1283 if (handle) {
1284 dri2_drv->get_proc_address = (_EGLProc (*)(const char *))
1285 dlsym(handle, "_glapi_get_proc_address");
1286 if (!dri2_drv->get_proc_address || !libname) {
1287 /* no need to keep a reference */
1288 dlclose(handle);
1289 handle = NULL;
1290 }
1291 }
1292
1293 /* if glapi is not available, loading DRI drivers will fail */
1294 if (!dri2_drv->get_proc_address) {
1295 _eglLog(_EGL_WARNING, "DRI2: failed to find _glapi_get_proc_address");
1296 return EGL_FALSE;
1297 }
1298
1299 dri2_drv->glFlush = (void (*)(void))
1300 dri2_drv->get_proc_address("glFlush");
1301
1302 dri2_drv->handle = handle;
1303
1304 return EGL_TRUE;
1305 }
1306
1307 /**
1308 * This is the main entrypoint into the driver, called by libEGL.
1309 * Create a new _EGLDriver object and init its dispatch table.
1310 */
1311 _EGLDriver *
1312 _EGL_MAIN(const char *args)
1313 {
1314 struct dri2_egl_driver *dri2_drv;
1315
1316 (void) args;
1317
1318 dri2_drv = malloc(sizeof *dri2_drv);
1319 if (!dri2_drv)
1320 return NULL;
1321
1322 memset(dri2_drv, 0, sizeof *dri2_drv);
1323
1324 if (!dri2_load(&dri2_drv->base))
1325 return NULL;
1326
1327 _eglInitDriverFallbacks(&dri2_drv->base);
1328 dri2_drv->base.API.Initialize = dri2_initialize;
1329 dri2_drv->base.API.Terminate = dri2_terminate;
1330 dri2_drv->base.API.CreateContext = dri2_create_context;
1331 dri2_drv->base.API.MakeCurrent = dri2_make_current;
1332 dri2_drv->base.API.GetProcAddress = dri2_get_proc_address;
1333 dri2_drv->base.API.WaitClient = dri2_wait_client;
1334 dri2_drv->base.API.WaitNative = dri2_wait_native;
1335 dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
1336 dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
1337 dri2_drv->base.API.CreateImageKHR = dri2_create_image_khr;
1338 dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr;
1339 dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa;
1340 dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa;
1341 #ifdef HAVE_WAYLAND_PLATFORM
1342 dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;
1343 dri2_drv->base.API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl;
1344 #endif
1345
1346 dri2_drv->base.Name = "DRI2";
1347 dri2_drv->base.Unload = dri2_unload;
1348
1349 return &dri2_drv->base;
1350 }