Merge branch 'gallium-dynamicstencilref'
[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 <xcb/xcb.h>
40 #include <xcb/dri2.h>
41 #include <xcb/xfixes.h>
42 #include <X11/Xlib-xcb.h>
43
44 #include <glapi/glapi.h>
45 #include "eglconfigutil.h"
46 #include "eglconfig.h"
47 #include "eglcontext.h"
48 #include "egldisplay.h"
49 #include "egldriver.h"
50 #include "eglcurrent.h"
51 #include "egllog.h"
52 #include "eglsurface.h"
53
54 struct dri2_egl_driver
55 {
56 _EGLDriver base;
57 };
58
59 struct dri2_egl_display
60 {
61 xcb_connection_t *conn;
62 int dri2_major;
63 int dri2_minor;
64 __DRIscreen *dri_screen;
65 void *driver;
66 __DRIcoreExtension *core;
67 __DRIdri2Extension *dri2;
68 __DRI2flushExtension *flush;
69 __DRItexBufferExtension *tex_buffer;
70 int fd;
71
72 __DRIdri2LoaderExtension loader_extension;
73 const __DRIextension *extensions[2];
74 };
75
76 struct dri2_egl_context
77 {
78 _EGLContext base;
79 __DRIcontext *dri_context;
80 };
81
82 struct dri2_egl_surface
83 {
84 _EGLSurface base;
85 __DRIdrawable *dri_drawable;
86 xcb_drawable_t drawable;
87 __DRIbuffer buffers[5];
88 int buffer_count;
89 xcb_xfixes_region_t region;
90 int have_fake_front;
91 int swap_interval;
92 };
93
94 struct dri2_egl_config
95 {
96 _EGLConfig base;
97 const __DRIconfig *dri_config;
98 };
99
100 /* standard typecasts */
101 _EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl)
102
103 EGLint dri2_to_egl_attribute_map[] = {
104 0,
105 EGL_BUFFER_SIZE, /* __DRI_ATTRIB_BUFFER_SIZE */
106 EGL_LEVEL, /* __DRI_ATTRIB_LEVEL */
107 EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */
108 EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */
109 EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */
110 EGL_LUMINANCE_SIZE, /* __DRI_ATTRIB_LUMINANCE_SIZE */
111 EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */
112 0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */
113 EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */
114 EGL_STENCIL_SIZE, /* __DRI_ATTRIB_STENCIL_SIZE */
115 0, /* __DRI_ATTRIB_ACCUM_RED_SIZE */
116 0, /* __DRI_ATTRIB_ACCUM_GREEN_SIZE */
117 0, /* __DRI_ATTRIB_ACCUM_BLUE_SIZE */
118 0, /* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */
119 EGL_SAMPLE_BUFFERS, /* __DRI_ATTRIB_SAMPLE_BUFFERS */
120 EGL_SAMPLES, /* __DRI_ATTRIB_SAMPLES */
121 0, /* __DRI_ATTRIB_RENDER_TYPE, */
122 0, /* __DRI_ATTRIB_CONFIG_CAVEAT */
123 0, /* __DRI_ATTRIB_CONFORMANT */
124 0, /* __DRI_ATTRIB_DOUBLE_BUFFER */
125 0, /* __DRI_ATTRIB_STEREO */
126 0, /* __DRI_ATTRIB_AUX_BUFFERS */
127 0, /* __DRI_ATTRIB_TRANSPARENT_TYPE */
128 0, /* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */
129 0, /* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */
130 0, /* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */
131 0, /* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */
132 0, /* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */
133 0, /* __DRI_ATTRIB_FLOAT_MODE */
134 0, /* __DRI_ATTRIB_RED_MASK */
135 0, /* __DRI_ATTRIB_GREEN_MASK */
136 0, /* __DRI_ATTRIB_BLUE_MASK */
137 0, /* __DRI_ATTRIB_ALPHA_MASK */
138 EGL_MAX_PBUFFER_WIDTH, /* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */
139 EGL_MAX_PBUFFER_HEIGHT, /* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */
140 EGL_MAX_PBUFFER_PIXELS, /* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */
141 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */
142 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */
143 0, /* __DRI_ATTRIB_VISUAL_SELECT_GROUP */
144 0, /* __DRI_ATTRIB_SWAP_METHOD */
145 EGL_MAX_SWAP_INTERVAL, /* __DRI_ATTRIB_MAX_SWAP_INTERVAL */
146 EGL_MIN_SWAP_INTERVAL, /* __DRI_ATTRIB_MIN_SWAP_INTERVAL */
147 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */
148 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */
149 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */
150 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */
151 0, /* __DRI_ATTRIB_YINVERTED */
152 };
153
154 static void
155 dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
156 int depth, xcb_visualtype_t *visual)
157 {
158 struct dri2_egl_config *conf;
159 struct dri2_egl_display *dri2_dpy;
160 _EGLConfig base;
161 unsigned int attrib, value, double_buffer;
162 EGLint key, bind_to_texture_rgb, bind_to_texture_rgba;
163 int i;
164
165 dri2_dpy = disp->DriverData;
166 _eglInitConfig(&base, disp, id);
167
168 i = 0;
169 while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) {
170 switch (attrib) {
171 case __DRI_ATTRIB_RENDER_TYPE:
172 if (value & __DRI_ATTRIB_RGBA_BIT)
173 value = EGL_RGB_BUFFER;
174 else if (value & __DRI_ATTRIB_LUMINANCE_BIT)
175 value = EGL_LUMINANCE_BUFFER;
176 else
177 /* not valid */;
178 _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value);
179 break;
180
181 case __DRI_ATTRIB_CONFIG_CAVEAT:
182 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
183 value = EGL_NON_CONFORMANT_CONFIG;
184 else if (value & __DRI_ATTRIB_SLOW_BIT)
185 value = EGL_SLOW_CONFIG;
186 else
187 value = EGL_NONE;
188 _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value);
189 break;
190
191 case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB:
192 bind_to_texture_rgb = value;
193 break;
194
195 case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA:
196 bind_to_texture_rgba = value;
197 break;
198
199 case __DRI_ATTRIB_DOUBLE_BUFFER:
200 double_buffer = value;
201 break;
202
203 default:
204 key = dri2_to_egl_attribute_map[attrib];
205 if (key != 0)
206 _eglSetConfigKey(&base, key, value);
207 break;
208 }
209 }
210
211 /* In EGL, double buffer or not isn't a config attribute. Pixmaps
212 * surfaces are always single buffered, pbuffer surfaces are always
213 * back buffers and windows can be either, selected by passing an
214 * attribute at window surface construction time. To support this
215 * we ignore all double buffer configs and manipulate the buffer we
216 * return in the getBuffer callback to get the behaviour we want. */
217
218 if (double_buffer)
219 return;
220
221 if (visual != NULL) {
222 if (depth != _eglGetConfigKey(&base, EGL_BUFFER_SIZE))
223 return;
224
225 _eglSetConfigKey(&base, EGL_SURFACE_TYPE,
226 EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT |
227 EGL_SWAP_BEHAVIOR_PRESERVED_BIT);
228
229 _eglSetConfigKey(&base, EGL_NATIVE_VISUAL_ID, visual->visual_id);
230 _eglSetConfigKey(&base, EGL_NATIVE_VISUAL_TYPE, visual->_class);
231 } else {
232 _eglSetConfigKey(&base, EGL_SURFACE_TYPE,
233 EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
234 }
235
236 _eglSetConfigKey(&base, EGL_NATIVE_RENDERABLE, EGL_TRUE);
237 _eglSetConfigKey(&base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb);
238 if (_eglGetConfigKey(&base, EGL_ALPHA_SIZE) > 0)
239 _eglSetConfigKey(&base,
240 EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba);
241
242 /* EGL_OPENGL_ES_BIT, EGL_OPENVG_BIT, EGL_OPENGL_ES2_BIT */
243 _eglSetConfigKey(&base, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
244 _eglSetConfigKey(&base, EGL_CONFORMANT, EGL_OPENGL_BIT);
245
246 if (!_eglValidateConfig(&base, EGL_FALSE)) {
247 _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
248 return;
249 }
250
251 conf = malloc(sizeof *conf);
252 if (conf != NULL) {
253 memcpy(&conf->base, &base, sizeof base);
254 conf->dri_config = dri_config;
255 _eglAddConfig(disp, &conf->base);
256 }
257 }
258
259 /**
260 * Process list of buffer received from the server
261 *
262 * Processes the list of buffers received in a reply from the server to either
263 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
264 */
265 static void
266 dri2_process_buffers(struct dri2_egl_surface *dri2_surf,
267 xcb_dri2_dri2_buffer_t *buffers, unsigned count)
268 {
269 struct dri2_egl_display *dri2_dpy =
270 dri2_egl_display(dri2_surf->base.Resource.Display);
271 xcb_rectangle_t rectangle;
272 int i;
273
274 dri2_surf->buffer_count = count;
275 dri2_surf->have_fake_front = 0;
276
277 /* This assumes the DRI2 buffer attachment tokens matches the
278 * __DRIbuffer tokens. */
279 for (i = 0; i < count; i++) {
280 dri2_surf->buffers[i].attachment = buffers[i].attachment;
281 dri2_surf->buffers[i].name = buffers[i].name;
282 dri2_surf->buffers[i].pitch = buffers[i].pitch;
283 dri2_surf->buffers[i].cpp = buffers[i].cpp;
284 dri2_surf->buffers[i].flags = buffers[i].flags;
285
286 /* We only use the DRI drivers single buffer configs. This
287 * means that if we try to render to a window, DRI2 will give us
288 * the fake front buffer, which we'll use as a back buffer.
289 * Note that EGL doesn't require that several clients rendering
290 * to the same window must see the same aux buffers. */
291 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
292 dri2_surf->have_fake_front = 1;
293 }
294
295 if (dri2_surf->region != XCB_NONE)
296 xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
297
298 rectangle.x = 0;
299 rectangle.y = 0;
300 rectangle.width = dri2_surf->base.Width;
301 rectangle.height = dri2_surf->base.Height;
302 dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
303 xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
304 }
305
306 static __DRIbuffer *
307 dri2_get_buffers(__DRIdrawable * driDrawable,
308 int *width, int *height,
309 unsigned int *attachments, int count,
310 int *out_count, void *loaderPrivate)
311 {
312 struct dri2_egl_surface *dri2_surf = loaderPrivate;
313 struct dri2_egl_display *dri2_dpy =
314 dri2_egl_display(dri2_surf->base.Resource.Display);
315 xcb_dri2_dri2_buffer_t *buffers;
316 xcb_dri2_get_buffers_reply_t *reply;
317 xcb_dri2_get_buffers_cookie_t cookie;
318
319 cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
320 dri2_surf->drawable,
321 count, count, attachments);
322 reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
323 buffers = xcb_dri2_get_buffers_buffers (reply);
324 if (buffers == NULL)
325 return NULL;
326
327 *out_count = reply->count;
328 dri2_surf->base.Width = *width = reply->width;
329 dri2_surf->base.Height = *height = reply->height;
330 dri2_process_buffers(dri2_surf, buffers, *out_count);
331
332 free(reply);
333
334 return dri2_surf->buffers;
335 }
336
337 static void
338 dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
339 {
340 /* FIXME: Does EGL support front buffer rendering at all? */
341
342 #if 0
343 struct dri2_egl_surface *dri2_surf = loaderPrivate;
344
345 dri2WaitGL(dri2_surf);
346 #endif
347 }
348
349 static __DRIbuffer *
350 dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
351 int *width, int *height,
352 unsigned int *attachments, int count,
353 int *out_count, void *loaderPrivate)
354 {
355 struct dri2_egl_surface *dri2_surf = loaderPrivate;
356 struct dri2_egl_display *dri2_dpy =
357 dri2_egl_display(dri2_surf->base.Resource.Display);
358 xcb_dri2_dri2_buffer_t *buffers;
359 xcb_dri2_get_buffers_with_format_reply_t *reply;
360 xcb_dri2_get_buffers_with_format_cookie_t cookie;
361 xcb_dri2_attach_format_t *format_attachments;
362
363 format_attachments = (xcb_dri2_attach_format_t *) attachments;
364 cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
365 dri2_surf->drawable,
366 count, count,
367 format_attachments);
368
369 reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
370 cookie, NULL);
371 if (reply == NULL)
372 return NULL;
373
374 buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
375 dri2_surf->base.Width = *width = reply->width;
376 dri2_surf->base.Height = *height = reply->height;
377 *out_count = reply->count;
378 dri2_process_buffers(dri2_surf, buffers, *out_count);
379
380 free(reply);
381
382 return dri2_surf->buffers;
383 }
384
385 #ifdef GLX_USE_TLS
386 static const char dri_driver_format[] = "%.*s/tls/%.*s_dri.so";
387 #else
388 static const char dri_driver_format[] = "%.*s/%.*s_dri.so";
389 #endif
390
391 static const char dri_driver_path[] = DEFAULT_DRIVER_DIR;
392
393 struct dri2_extension_match {
394 const char *name;
395 int version;
396 int offset;
397 };
398
399 static struct dri2_extension_match dri2_driver_extensions[] = {
400 { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
401 { __DRI_DRI2, 1, offsetof(struct dri2_egl_display, dri2) },
402 { NULL }
403 };
404
405 static struct dri2_extension_match dri2_core_extensions[] = {
406 { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
407 { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
408 { NULL }
409 };
410
411 static EGLBoolean
412 dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
413 struct dri2_extension_match *matches,
414 const __DRIextension **extensions)
415 {
416 int i, j, ret = EGL_TRUE;
417 void *field;
418
419 for (i = 0; extensions[i]; i++) {
420 _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name);
421 for (j = 0; matches[j].name; j++) {
422 if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
423 extensions[i]->version >= matches[j].version) {
424 field = ((char *) dri2_dpy + matches[j].offset);
425 *(const __DRIextension **) field = extensions[i];
426 _eglLog(_EGL_INFO, "DRI2: found extension %s version %d",
427 extensions[i]->name, extensions[i]->version);
428 }
429 }
430 }
431
432 for (j = 0; matches[j].name; j++) {
433 field = ((char *) dri2_dpy + matches[j].offset);
434 if (*(const __DRIextension **) field == NULL) {
435 _eglLog(_EGL_FATAL, "DRI2: did not find extension %s version %d",
436 matches[j].name, matches[j].version);
437 ret = EGL_FALSE;
438 }
439 }
440
441 return ret;
442 }
443
444 /**
445 * Called via eglInitialize(), GLX_drv->API.Initialize().
446 */
447 static EGLBoolean
448 dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
449 EGLint *major, EGLint *minor)
450 {
451 const __DRIextension **extensions;
452 const __DRIconfig **driver_configs;
453 struct dri2_egl_display *dri2_dpy;
454 char path[PATH_MAX], *search_paths, *p, *next, *end;
455 xcb_xfixes_query_version_reply_t *xfixes_query;
456 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
457 xcb_dri2_query_version_reply_t *dri2_query;
458 xcb_dri2_query_version_cookie_t dri2_query_cookie;
459 xcb_dri2_connect_reply_t *connect;
460 xcb_dri2_connect_cookie_t connect_cookie;
461 xcb_dri2_authenticate_reply_t *authenticate;
462 xcb_dri2_authenticate_cookie_t authenticate_cookie;
463 xcb_generic_error_t *error;
464 drm_magic_t magic;
465 xcb_screen_iterator_t s;
466 xcb_depth_iterator_t d;
467 xcb_visualtype_t *visuals;
468 int i, j, id;
469
470 dri2_dpy = malloc(sizeof *dri2_dpy);
471 if (!dri2_dpy)
472 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
473
474 disp->DriverData = (void *) dri2_dpy;
475 if (disp->NativeDisplay != NULL)
476 dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay);
477 else
478 dri2_dpy->conn = xcb_connect(0, 0);
479 if (!dri2_dpy->conn) {
480 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
481 goto cleanup_dpy;
482 }
483
484 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
485 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
486
487 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
488 XCB_XFIXES_MAJOR_VERSION,
489 XCB_XFIXES_MINOR_VERSION);
490
491 dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
492 XCB_DRI2_MAJOR_VERSION,
493 XCB_DRI2_MINOR_VERSION);
494
495 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
496 connect_cookie = xcb_dri2_connect_unchecked (dri2_dpy->conn,
497 s.data->root,
498 XCB_DRI2_DRIVER_TYPE_DRI);
499
500 xfixes_query =
501 xcb_xfixes_query_version_reply (dri2_dpy->conn,
502 xfixes_query_cookie, &error);
503 if (xfixes_query == NULL ||
504 error != NULL || xfixes_query->major_version < 2) {
505 _eglLog(_EGL_FATAL, "DRI2: failed to query xfixes version");
506 free(error);
507 goto cleanup_conn;
508 }
509 free(xfixes_query);
510
511 dri2_query =
512 xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
513 if (dri2_query == NULL || error != NULL) {
514 _eglLog(_EGL_FATAL, "DRI2: failed to query version");
515 free(error);
516 goto cleanup_conn;
517 }
518 dri2_dpy->dri2_major = dri2_query->major_version;
519 dri2_dpy->dri2_minor = dri2_query->minor_version;
520 free(dri2_query);
521
522 connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
523 if (connect == NULL ||
524 connect->driver_name_length + connect->device_name_length == 0) {
525 _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
526 goto cleanup_connect;
527 }
528
529 search_paths = NULL;
530 if (geteuid() == getuid()) {
531 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
532 search_paths = getenv("LIBGL_DRIVERS_PATH");
533 }
534 if (search_paths == NULL)
535 search_paths = DEFAULT_DRIVER_DIR;
536
537 dri2_dpy->driver = NULL;
538 end = search_paths + strlen(search_paths);
539 for (p = search_paths; p < end && dri2_dpy->driver == NULL; p = next + 1) {
540 next = strchr(p, ':');
541 if (next == NULL)
542 next = end;
543
544 snprintf(path, sizeof path,
545 dri_driver_format,
546 (int) (next - p), p,
547 xcb_dri2_connect_driver_name_length (connect),
548 xcb_dri2_connect_driver_name (connect));
549
550 dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
551 }
552
553 if (dri2_dpy->driver == NULL) {
554 _eglLog(_EGL_FATAL,
555 "DRI2: failed to open any driver (search paths %s)",
556 search_paths);
557 goto cleanup_connect;
558 }
559
560 _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
561 extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS);
562 if (extensions == NULL) {
563 _eglLog(_EGL_FATAL,
564 "DRI2: driver exports no extensions (%s)", dlerror());
565 goto cleanup_driver;
566 }
567
568 if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions))
569 goto cleanup_driver;
570
571 snprintf(path, sizeof path, "%.*s",
572 xcb_dri2_connect_device_name_length (connect),
573 xcb_dri2_connect_device_name (connect));
574 dri2_dpy->fd = open (path, O_RDWR);
575 if (dri2_dpy->fd == -1) {
576 _eglLog(_EGL_FATAL,
577 "DRI2: could not open %s (%s)", path, strerror(errno));
578 goto cleanup_driver;
579 }
580
581 if (drmGetMagic(dri2_dpy->fd, &magic)) {
582 _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic");
583 goto cleanup_fd;
584 }
585
586 authenticate_cookie = xcb_dri2_authenticate_unchecked (dri2_dpy->conn,
587 s.data->root, magic);
588 authenticate = xcb_dri2_authenticate_reply (dri2_dpy->conn,
589 authenticate_cookie, NULL);
590 if (authenticate == NULL || !authenticate->authenticated) {
591 _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
592 free(authenticate);
593 goto cleanup_fd;
594 }
595
596 free(authenticate);
597 if (dri2_dpy->dri2_minor >= 1) {
598 dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER;
599 dri2_dpy->loader_extension.base.version = 3;
600 dri2_dpy->loader_extension.getBuffers = dri2_get_buffers;
601 dri2_dpy->loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
602 dri2_dpy->loader_extension.getBuffersWithFormat =
603 dri2_get_buffers_with_format;
604 } else {
605 dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER;
606 dri2_dpy->loader_extension.base.version = 2;
607 dri2_dpy->loader_extension.getBuffers = dri2_get_buffers;
608 dri2_dpy->loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
609 dri2_dpy->loader_extension.getBuffersWithFormat = NULL;
610 }
611
612 dri2_dpy->extensions[0] = &dri2_dpy->loader_extension.base;
613 dri2_dpy->extensions[1] = NULL;
614
615 dri2_dpy->dri_screen =
616 dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
617 &driver_configs, dri2_dpy);
618
619 if (dri2_dpy->dri_screen == NULL) {
620 _eglLog(_EGL_FATAL, "DRI2: failed to create dri screen");
621 goto cleanup_fd;
622 }
623
624 extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
625 if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
626 goto cleanup_dri_screen;
627
628 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
629 d = xcb_screen_allowed_depths_iterator(s.data);
630 id = 1;
631 while (d.rem > 0) {
632 EGLBoolean class_added[6] = { 0, };
633
634 visuals = xcb_depth_visuals(d.data);
635 for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
636 if (class_added[visuals[i]._class])
637 continue;
638
639 class_added[visuals[i]._class] = EGL_TRUE;
640 for (j = 0; driver_configs[j]; j++)
641 dri2_add_config(disp, driver_configs[j],
642 id++, d.data->depth, &visuals[i]);
643
644 }
645
646 xcb_depth_next(&d);
647 }
648
649 if (!disp->NumConfigs) {
650 _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
651 goto cleanup_configs;
652 }
653
654 disp->ClientAPIsMask = EGL_OPENGL_BIT;
655
656 /* we're supporting EGL 1.4 */
657 *major = 1;
658 *minor = 4;
659 free (connect);
660 return EGL_TRUE;
661
662 cleanup_configs:
663 _eglCleanupDisplay(disp);
664 cleanup_dri_screen:
665 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
666 cleanup_fd:
667 close(dri2_dpy->fd);
668 cleanup_driver:
669 dlclose(dri2_dpy->driver);
670 cleanup_connect:
671 free(connect);
672 cleanup_conn:
673 if (disp->NativeDisplay == NULL)
674 xcb_disconnect(dri2_dpy->conn);
675 cleanup_dpy:
676 free(dri2_dpy);
677
678 return EGL_FALSE;
679 }
680
681 /**
682 * Called via eglTerminate(), drv->API.Terminate().
683 */
684 static EGLBoolean
685 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
686 {
687 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
688
689 _eglReleaseDisplayResources(drv, disp);
690 _eglCleanupDisplay(disp);
691
692 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
693 close(dri2_dpy->fd);
694 dlclose(dri2_dpy->driver);
695 if (disp->NativeDisplay == NULL)
696 xcb_disconnect(dri2_dpy->conn);
697 free(dri2_dpy);
698 disp->DriverData = NULL;
699
700 return EGL_TRUE;
701 }
702
703
704 /**
705 * Called via eglCreateContext(), drv->API.CreateContext().
706 */
707 static _EGLContext *
708 dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
709 _EGLContext *share_list, const EGLint *attrib_list)
710 {
711 struct dri2_egl_context *dri2_ctx;
712 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
713 struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
714 struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
715
716 dri2_ctx = malloc(sizeof *dri2_ctx);
717 if (!dri2_ctx) {
718 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
719 return NULL;
720 }
721
722 if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
723 goto cleanup;
724
725 dri2_ctx->dri_context =
726 dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen,
727 dri2_config->dri_config,
728 dri2_ctx_shared ?
729 dri2_ctx_shared->dri_context : NULL,
730 dri2_ctx);
731
732 if (!dri2_ctx->dri_context)
733 goto cleanup;
734
735 return &dri2_ctx->base;
736
737 cleanup:
738 free(dri2_ctx);
739 return NULL;
740 }
741
742 static EGLBoolean
743 dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
744 {
745 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
746 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
747
748 if (_eglIsSurfaceBound(surf))
749 return EGL_TRUE;
750
751 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
752
753 xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
754
755 if (surf->Type == EGL_PBUFFER_BIT)
756 xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
757
758 free(surf);
759
760 return EGL_TRUE;
761 }
762
763 /**
764 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
765 */
766 static EGLBoolean
767 dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
768 _EGLSurface *rsurf, _EGLContext *ctx)
769 {
770 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
771 struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
772 struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
773 struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
774 __DRIdrawable *ddraw, *rdraw;
775 __DRIcontext *cctx;
776
777 /* bind the new context and return the "orphaned" one */
778 if (!_eglBindContext(&ctx, &dsurf, &rsurf))
779 return EGL_FALSE;
780
781 ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
782 rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL;
783 cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
784
785 if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
786 dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
787 if (dsurf && !_eglIsSurfaceLinked(dsurf))
788 dri2_destroy_surface(drv, disp, dsurf);
789 if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(dsurf))
790 dri2_destroy_surface(drv, disp, rsurf);
791 if (ctx != NULL && !_eglIsContextLinked(ctx))
792 dri2_dpy->core->unbindContext(dri2_egl_context(ctx)->dri_context);
793
794 return EGL_TRUE;
795 } else {
796 _eglBindContext(&ctx, &dsurf, &rsurf);
797
798 return EGL_FALSE;
799 }
800 }
801
802 /**
803 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
804 */
805 static _EGLSurface *
806 dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
807 _EGLConfig *conf, EGLNativeWindowType window,
808 const EGLint *attrib_list)
809 {
810 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
811 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
812 struct dri2_egl_surface *dri2_surf;
813 xcb_get_geometry_cookie_t cookie;
814 xcb_get_geometry_reply_t *reply;
815 xcb_screen_iterator_t s;
816 xcb_generic_error_t *error;
817
818 dri2_surf = malloc(sizeof *dri2_surf);
819 if (!dri2_surf) {
820 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
821 return NULL;
822 }
823
824 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
825 goto cleanup_surf;
826
827 dri2_surf->region = XCB_NONE;
828 if (type == EGL_PBUFFER_BIT) {
829 dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
830 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
831 xcb_create_pixmap(dri2_dpy->conn,
832 _eglGetConfigKey(conf, EGL_BUFFER_SIZE),
833 dri2_surf->drawable, s.data->root,
834 dri2_surf->base.Width, dri2_surf->base.Height);
835 } else {
836 dri2_surf->drawable = window;
837 }
838
839 dri2_surf->dri_drawable =
840 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
841 dri2_conf->dri_config, dri2_surf);
842 if (dri2_surf->dri_drawable == NULL) {
843 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
844 goto cleanup_pixmap;
845 }
846
847 xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
848
849 if (type != EGL_PBUFFER_BIT) {
850 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
851 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
852 if (reply == NULL || error != NULL) {
853 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
854 free(error);
855 goto cleanup_dri_drawable;
856 }
857
858 dri2_surf->base.Width = reply->width;
859 dri2_surf->base.Height = reply->height;
860 free(reply);
861 }
862
863 return &dri2_surf->base;
864
865 cleanup_dri_drawable:
866 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
867 cleanup_pixmap:
868 if (type == EGL_PBUFFER_BIT)
869 xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
870 cleanup_surf:
871 free(dri2_surf);
872
873 return NULL;
874 }
875
876 /**
877 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
878 */
879 static _EGLSurface *
880 dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
881 _EGLConfig *conf, EGLNativeWindowType window,
882 const EGLint *attrib_list)
883 {
884 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
885 window, attrib_list);
886 }
887
888 static _EGLSurface *
889 dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
890 _EGLConfig *conf, EGLNativePixmapType pixmap,
891 const EGLint *attrib_list)
892 {
893 return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
894 pixmap, attrib_list);
895 }
896
897 static _EGLSurface *
898 dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
899 _EGLConfig *conf, const EGLint *attrib_list)
900 {
901 return dri2_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
902 XCB_WINDOW_NONE, attrib_list);
903 }
904
905 static EGLBoolean
906 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
907 {
908 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
909 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
910 xcb_dri2_copy_region_cookie_t cookie;
911
912 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
913
914 #if 0
915 /* FIXME: Add support for dri swapbuffers, that'll give us swap
916 * interval and page flipping (at least for fullscreen windows) as
917 * well as the page flip event. Unless surface->SwapBehavior is
918 * EGL_BUFFER_PRESERVED. */
919 #if __DRI2_FLUSH_VERSION >= 2
920 if (pdraw->psc->f)
921 (*pdraw->psc->f->flushInvalidate)(pdraw->driDrawable);
922 #endif
923 #endif
924
925 if (!dri2_surf->have_fake_front)
926 return EGL_TRUE;
927
928 cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
929 dri2_surf->drawable,
930 dri2_surf->region,
931 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
932 XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT);
933 free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
934
935 return EGL_TRUE;
936 }
937
938 /*
939 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
940 */
941 static _EGLProc
942 dri2_get_proc_address(_EGLDriver *drv, const char *procname)
943 {
944 /* FIXME: Do we need to support lookup of EGL symbols too? */
945
946 return (_EGLProc) _glapi_get_proc_address(procname);
947 }
948
949 static EGLBoolean
950 dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
951 {
952 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
953 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(ctx->DrawSurface);
954
955 /* FIXME: If EGL allows frontbuffer rendering for window surfaces,
956 * we need to copy fake to real here.*/
957
958 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
959
960 return EGL_TRUE;
961 }
962
963 static EGLBoolean
964 dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine)
965 {
966 if (engine != EGL_CORE_NATIVE_ENGINE)
967 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
968 /* glXWaitX(); */
969
970 return EGL_TRUE;
971 }
972
973 static void
974 dri2_unload(_EGLDriver *drv)
975 {
976 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
977 free(dri2_drv);
978 }
979
980 static EGLBoolean
981 dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
982 EGLNativePixmapType target)
983 {
984 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
985 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
986 xcb_gcontext_t gc;
987
988 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
989
990 gc = xcb_generate_id(dri2_dpy->conn);
991 xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
992 xcb_copy_area(dri2_dpy->conn,
993 dri2_surf->drawable,
994 target,
995 gc,
996 0, 0,
997 0, 0,
998 dri2_surf->base.Width,
999 dri2_surf->base.Height);
1000 xcb_free_gc(dri2_dpy->conn, gc);
1001
1002 return EGL_TRUE;
1003 }
1004
1005 static EGLBoolean
1006 dri2_bind_tex_image(_EGLDriver *drv,
1007 _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
1008 {
1009 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1010 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1011 struct dri2_egl_context *dri2_ctx;
1012 _EGLContext *ctx;
1013 GLint format, target;
1014
1015 ctx = _eglGetCurrentContext();
1016 dri2_ctx = dri2_egl_context(ctx);
1017
1018 if (buffer != EGL_BACK_BUFFER) {
1019 _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
1020 return EGL_FALSE;
1021 }
1022
1023 /* We allow binding pixmaps too... Not conformat, but we can do it
1024 * for free and it's useful for X compositors. Supposedly there's
1025 * a EGL_NOKIA_texture_from_pixmap extension that allows that, but
1026 * I couldn't find it at this time. */
1027 if ((dri2_surf->base.Type & (EGL_PBUFFER_BIT | EGL_PIXMAP_BIT)) == 0) {
1028 _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
1029 return EGL_FALSE;
1030 }
1031
1032 switch (dri2_surf->base.TextureFormat) {
1033 case EGL_TEXTURE_RGB:
1034 format = __DRI_TEXTURE_FORMAT_RGB;
1035 break;
1036 case EGL_TEXTURE_RGBA:
1037 format = __DRI_TEXTURE_FORMAT_RGBA;
1038 break;
1039 default:
1040 _eglError(EGL_BAD_MATCH, "eglBindTexImage");
1041 return EGL_FALSE;
1042 }
1043
1044 switch (dri2_surf->base.TextureTarget) {
1045 case EGL_TEXTURE_2D:
1046 target = GL_TEXTURE_2D;
1047 break;
1048 default:
1049 _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
1050 return EGL_FALSE;
1051 }
1052
1053 (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
1054 target, format,
1055 dri2_surf->dri_drawable);
1056
1057 return dri2_surf->base.BoundToTexture = EGL_TRUE;
1058 }
1059
1060 static EGLBoolean
1061 dri2_release_tex_image(_EGLDriver *drv,
1062 _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
1063 {
1064 return EGL_TRUE;
1065 }
1066
1067
1068 /**
1069 * This is the main entrypoint into the driver, called by libEGL.
1070 * Create a new _EGLDriver object and init its dispatch table.
1071 */
1072 _EGLDriver *
1073 _eglMain(const char *args)
1074 {
1075 struct dri2_egl_driver *dri2_drv;
1076
1077 dri2_drv = malloc(sizeof *dri2_drv);
1078 if (!dri2_drv)
1079 return NULL;
1080
1081 _eglInitDriverFallbacks(&dri2_drv->base);
1082 dri2_drv->base.API.Initialize = dri2_initialize;
1083 dri2_drv->base.API.Terminate = dri2_terminate;
1084 dri2_drv->base.API.CreateContext = dri2_create_context;
1085 dri2_drv->base.API.MakeCurrent = dri2_make_current;
1086 dri2_drv->base.API.CreateWindowSurface = dri2_create_window_surface;
1087 dri2_drv->base.API.CreatePixmapSurface = dri2_create_pixmap_surface;
1088 dri2_drv->base.API.CreatePbufferSurface = dri2_create_pbuffer_surface;
1089 dri2_drv->base.API.DestroySurface = dri2_destroy_surface;
1090 dri2_drv->base.API.SwapBuffers = dri2_swap_buffers;
1091 dri2_drv->base.API.GetProcAddress = dri2_get_proc_address;
1092 dri2_drv->base.API.WaitClient = dri2_wait_client;
1093 dri2_drv->base.API.WaitNative = dri2_wait_native;
1094 dri2_drv->base.API.CopyBuffers = dri2_copy_buffers;
1095 dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
1096 dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
1097
1098 dri2_drv->base.Name = "DRI2";
1099 dri2_drv->base.Unload = dri2_unload;
1100
1101 return &dri2_drv->base;
1102 }