egl: Add driver for EGL on X with DRI2
[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 int fd;
70
71 __DRIdri2LoaderExtension loader_extension;
72 const __DRIextension *extensions[2];
73 };
74
75 struct dri2_egl_context
76 {
77 _EGLContext base;
78 __DRIcontext *dri_context;
79 };
80
81 struct dri2_egl_surface
82 {
83 _EGLSurface base;
84 __DRIdrawable *dri_drawable;
85 xcb_drawable_t drawable;
86 __DRIbuffer buffers[5];
87 int buffer_count;
88 xcb_xfixes_region_t region;
89 int have_back;
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 static struct dri2_egl_driver *
101 dri2_egl_driver(_EGLDriver *drv)
102 {
103 return (struct dri2_egl_driver *) drv;
104 }
105
106 static struct dri2_egl_display *
107 dri2_egl_display(_EGLDisplay *dpy)
108 {
109 return (struct dri2_egl_display *) dpy->DriverData;
110 }
111
112 static struct dri2_egl_context *
113 dri2_egl_context(_EGLContext *ctx)
114 {
115 return (struct dri2_egl_context *) ctx;
116 }
117
118 static struct dri2_egl_surface *
119 dri2_egl_surface(_EGLSurface *surf)
120 {
121 return (struct dri2_egl_surface *) surf;
122 }
123
124 static struct dri2_egl_config *
125 dri2_egl_config(_EGLConfig *conf)
126 {
127 return (struct dri2_egl_config *) conf;
128 }
129
130 EGLint dri2_to_egl_attribute_map[] = {
131 0,
132 EGL_BUFFER_SIZE, /* __DRI_ATTRIB_BUFFER_SIZE */
133 EGL_LEVEL, /* __DRI_ATTRIB_LEVEL */
134 EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */
135 EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */
136 EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */
137 0, /* __DRI_ATTRIB_LUMINANCE_SIZE */
138 EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */
139 0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */
140 EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */
141 EGL_STENCIL_SIZE, /* __DRI_ATTRIB_STENCIL_SIZE */
142 0, /* __DRI_ATTRIB_ACCUM_RED_SIZE */
143 0, /* __DRI_ATTRIB_ACCUM_GREEN_SIZE */
144 0, /* __DRI_ATTRIB_ACCUM_BLUE_SIZE */
145 0, /* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */
146 EGL_SAMPLE_BUFFERS, /* __DRI_ATTRIB_SAMPLE_BUFFERS */
147 EGL_SAMPLES, /* __DRI_ATTRIB_SAMPLES */
148 0, /* __DRI_ATTRIB_RENDER_TYPE, */
149 0, /* __DRI_ATTRIB_CONFIG_CAVEAT */
150 0, /* __DRI_ATTRIB_CONFORMANT */
151 0, /* __DRI_ATTRIB_DOUBLE_BUFFER */
152 0, /* __DRI_ATTRIB_STEREO */
153 0, /* __DRI_ATTRIB_AUX_BUFFERS */
154 0, /* __DRI_ATTRIB_TRANSPARENT_TYPE */
155 0, /* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */
156 0, /* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */
157 0, /* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */
158 0, /* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */
159 0, /* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */
160 0, /* __DRI_ATTRIB_FLOAT_MODE */
161 0, /* __DRI_ATTRIB_RED_MASK */
162 0, /* __DRI_ATTRIB_GREEN_MASK */
163 0, /* __DRI_ATTRIB_BLUE_MASK */
164 0, /* __DRI_ATTRIB_ALPHA_MASK */
165 EGL_MAX_PBUFFER_WIDTH, /* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */
166 EGL_MAX_PBUFFER_HEIGHT, /* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */
167 EGL_MAX_PBUFFER_PIXELS, /* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */
168 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */
169 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */
170 0, /* __DRI_ATTRIB_VISUAL_SELECT_GROUP */
171 0, /* __DRI_ATTRIB_SWAP_METHOD */
172 EGL_MAX_SWAP_INTERVAL, /* __DRI_ATTRIB_MAX_SWAP_INTERVAL */
173 EGL_MIN_SWAP_INTERVAL, /* __DRI_ATTRIB_MIN_SWAP_INTERVAL */
174 EGL_BIND_TO_TEXTURE_RGB, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */
175 EGL_BIND_TO_TEXTURE_RGBA, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */
176 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */
177 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */
178 0, /* __DRI_ATTRIB_YINVERTED */
179 };
180
181 static void
182 dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id)
183 {
184 struct dri2_egl_config *conf;
185 struct dri2_egl_display *dri2_dpy;
186 unsigned int attrib, value, surface_type;
187 EGLint key;
188 int i;
189
190 dri2_dpy = disp->DriverData;
191 conf = malloc(sizeof *conf);
192 if (conf == NULL)
193 return;
194
195 conf->dri_config = dri_config;
196 _eglInitConfig(&conf->base, disp, id);
197 surface_type = EGL_PBUFFER_BIT | EGL_PIXMAP_BIT;
198
199 i = 0;
200 while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) {
201 switch (attrib) {
202 case 0:
203 break;
204
205 case __DRI_ATTRIB_RENDER_TYPE:
206 if (value & __DRI_ATTRIB_RGBA_BIT)
207 value = EGL_RGB_BUFFER;
208 else if (value & __DRI_ATTRIB_LUMINANCE_BIT)
209 value = EGL_LUMINANCE_BUFFER;
210 else
211 /* not valid */;
212 _eglSetConfigKey(&conf->base, EGL_COLOR_BUFFER_TYPE, value);
213 break;
214
215 case __DRI_ATTRIB_CONFIG_CAVEAT:
216 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
217 value = EGL_NON_CONFORMANT_CONFIG;
218 else if (value & __DRI_ATTRIB_SLOW_BIT)
219 value = EGL_SLOW_CONFIG;
220 else
221 value = EGL_NONE;
222 _eglSetConfigKey(&conf->base, EGL_CONFIG_CAVEAT, value);
223 break;
224
225 case __DRI_ATTRIB_DOUBLE_BUFFER:
226 if (value)
227 surface_type |= EGL_WINDOW_BIT;
228 break;
229
230 default:
231 key = dri2_to_egl_attribute_map[attrib];
232 if (key != 0)
233 _eglSetConfigKey(&conf->base, key, value);
234 break;
235 }
236 }
237
238 /* EGL_SWAP_BEHAVIOR_PRESERVED_BIT */
239 _eglSetConfigKey(&conf->base, EGL_SURFACE_TYPE, surface_type);
240
241 /* EGL_OPENGL_ES_BIT, EGL_OPENVG_BIT, EGL_OPENGL_ES2_BIT */
242 _eglSetConfigKey(&conf->base, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
243 _eglSetConfigKey(&conf->base, EGL_CONFORMANT, EGL_OPENGL_BIT);
244
245 /* FIXME: Figure out how to get the visual ID and types */
246 _eglSetConfigKey(&conf->base, EGL_NATIVE_VISUAL_ID, 0x21);
247 _eglSetConfigKey(&conf->base, EGL_NATIVE_VISUAL_TYPE,
248 XCB_VISUAL_CLASS_TRUE_COLOR);
249
250 _eglSetConfigKey(&conf->base, EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
251 _eglSetConfigKey(&conf->base, EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
252
253 if (!_eglValidateConfig(&conf->base, EGL_FALSE)) {
254 _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", i);
255 free(conf);
256 return;
257 }
258
259 _eglAddConfig(disp, &conf->base);
260 }
261
262 /**
263 * Process list of buffer received from the server
264 *
265 * Processes the list of buffers received in a reply from the server to either
266 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
267 */
268 static void
269 dri2_process_buffers(struct dri2_egl_surface *dri2_surf,
270 xcb_dri2_dri2_buffer_t *buffers, unsigned count)
271 {
272 struct dri2_egl_display *dri2_dpy =
273 dri2_egl_display(dri2_surf->base.Resource.Display);
274 xcb_rectangle_t rectangle;
275 int i;
276
277 dri2_surf->buffer_count = count;
278 dri2_surf->have_fake_front = 0;
279 dri2_surf->have_back = 0;
280
281 /* This assumes the DRI2 buffer attachment tokens matches the
282 * __DRIbuffer tokens. */
283 for (i = 0; i < count; i++) {
284 dri2_surf->buffers[i].attachment = buffers[i].attachment;
285 dri2_surf->buffers[i].name = buffers[i].name;
286 dri2_surf->buffers[i].pitch = buffers[i].pitch;
287 dri2_surf->buffers[i].cpp = buffers[i].cpp;
288 dri2_surf->buffers[i].flags = buffers[i].flags;
289 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
290 dri2_surf->have_fake_front = 1;
291 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
292 dri2_surf->have_back = 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 /**
394 * Called via eglInitialize(), GLX_drv->API.Initialize().
395 */
396 static EGLBoolean
397 dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
398 EGLint *major, EGLint *minor)
399 {
400 const __DRIextension **extensions;
401 const __DRIconfig **driver_configs;
402 struct dri2_egl_display *dri2_dpy;
403 char path[PATH_MAX], *search_paths, *p, *next, *end;
404 xcb_xfixes_query_version_reply_t *xfixes_query;
405 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
406 xcb_dri2_query_version_reply_t *dri2_query;
407 xcb_dri2_query_version_cookie_t dri2_query_cookie;
408 xcb_dri2_connect_reply_t *connect = NULL;
409 xcb_dri2_connect_cookie_t connect_cookie;
410 xcb_dri2_authenticate_reply_t *authenticate;
411 xcb_dri2_authenticate_cookie_t authenticate_cookie;
412 xcb_generic_error_t *error;
413 drm_magic_t magic;
414 xcb_screen_iterator_t s;
415 int i;
416
417 dri2_dpy = malloc(sizeof *dri2_dpy);
418 if (!dri2_dpy)
419 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
420
421 disp->DriverData = (void *) dri2_dpy;
422 dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay);
423 if (!dri2_dpy->conn) {
424 dri2_dpy->conn = xcb_connect(0, 0);
425 if (!dri2_dpy->conn) {
426 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
427 free(dri2_dpy);
428 return EGL_FALSE;
429 }
430 }
431
432 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
433 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
434
435 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
436 XCB_XFIXES_MAJOR_VERSION,
437 XCB_XFIXES_MINOR_VERSION);
438
439 dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
440 XCB_DRI2_MAJOR_VERSION,
441 XCB_DRI2_MINOR_VERSION);
442
443 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
444 connect_cookie = xcb_dri2_connect_unchecked (dri2_dpy->conn,
445 s.data->root,
446 XCB_DRI2_DRIVER_TYPE_DRI);
447
448 xfixes_query =
449 xcb_xfixes_query_version_reply (dri2_dpy->conn,
450 xfixes_query_cookie, &error);
451 if (xfixes_query == NULL ||
452 error != NULL || xfixes_query->major_version < 2) {
453 _eglLog(_EGL_FATAL, "DRI2: failed to query xfixes version");
454 free(error);
455 goto handle_error;
456 }
457 free(xfixes_query);
458
459 dri2_query =
460 xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
461 if (dri2_query == NULL || error != NULL) {
462 _eglLog(_EGL_FATAL, "DRI2: failed to query version");
463 free(error);
464 goto handle_error;
465 }
466 dri2_dpy->dri2_major = dri2_query->major_version;
467 dri2_dpy->dri2_minor = dri2_query->minor_version;
468 free(dri2_query);
469
470 connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
471 if (connect->driver_name_length == 0 && connect->device_name_length == 0) {
472 _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
473 goto handle_error;
474 }
475
476 search_paths = NULL;
477 if (geteuid() == getuid()) {
478 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
479 search_paths = getenv("LIBGL_DRIVERS_PATH");
480 }
481 if (search_paths == NULL)
482 search_paths = DEFAULT_DRIVER_DIR;
483
484 dri2_dpy->driver = NULL;
485 end = search_paths + strlen(search_paths);
486 for (p = search_paths; p < end && dri2_dpy->driver == NULL; p = next + 1) {
487 next = strchr(p, ':');
488 if (next == NULL)
489 next = end;
490
491 snprintf(path, sizeof path,
492 dri_driver_format,
493 next - p, p,
494 xcb_dri2_connect_driver_name_length (connect),
495 xcb_dri2_connect_driver_name (connect));
496
497 dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
498 }
499
500 if (dri2_dpy->driver == NULL) {
501 _eglLog(_EGL_FATAL,
502 "DRI2: failed to open any driver (search paths %s)",
503 search_paths);
504 goto handle_error;
505 }
506
507 _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
508 extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS);
509 if (extensions == NULL) {
510 _eglLog(_EGL_FATAL,
511 "DRI2: driver exports no extensions (%s)", dlerror());
512 goto handle_error;
513 }
514
515 for (i = 0; extensions[i]; i++) {
516 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
517 dri2_dpy->core = (__DRIcoreExtension *) extensions[i];
518 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
519 dri2_dpy->dri2 = (__DRIdri2Extension *) extensions[i];
520 }
521
522 if (dri2_dpy->core == NULL) {
523 _eglLog(_EGL_FATAL, "DRI2: driver has no core extension");
524 goto handle_error;
525 }
526
527 if (dri2_dpy->dri2 == NULL) {
528 _eglLog(_EGL_FATAL, "DRI2: driver has no dri2 extension");
529 goto handle_error;
530 }
531
532 snprintf(path, sizeof path, "%.*s",
533 xcb_dri2_connect_device_name_length (connect),
534 xcb_dri2_connect_device_name (connect));
535 dri2_dpy->fd = open (path, O_RDWR);
536 if (dri2_dpy->fd == -1) {
537 _eglLog(_EGL_FATAL,
538 "DRI2: could not open %s (%s)", path, strerror(errno));
539 goto handle_error;
540 }
541
542 if (drmGetMagic(dri2_dpy->fd, &magic)) {
543 _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic");
544 goto handle_error;
545 }
546
547 authenticate_cookie = xcb_dri2_authenticate_unchecked (dri2_dpy->conn,
548 s.data->root, magic);
549 authenticate = xcb_dri2_authenticate_reply (dri2_dpy->conn,
550 authenticate_cookie, NULL);
551 if (authenticate == NULL || !authenticate->authenticated) {
552 _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
553 goto handle_error;
554 }
555
556 if (dri2_dpy->dri2_minor >= 1) {
557 dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER;
558 dri2_dpy->loader_extension.base.version = 3;
559 dri2_dpy->loader_extension.getBuffers = dri2_get_buffers;
560 dri2_dpy->loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
561 dri2_dpy->loader_extension.getBuffersWithFormat =
562 dri2_get_buffers_with_format;
563 } else {
564 dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER;
565 dri2_dpy->loader_extension.base.version = 2;
566 dri2_dpy->loader_extension.getBuffers = dri2_get_buffers;
567 dri2_dpy->loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
568 dri2_dpy->loader_extension.getBuffersWithFormat = NULL;
569 }
570
571 dri2_dpy->extensions[0] = &dri2_dpy->loader_extension.base;
572 dri2_dpy->extensions[1] = NULL;
573
574 dri2_dpy->dri_screen =
575 dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
576 &driver_configs, dri2_dpy);
577
578 if (dri2_dpy->dri_screen == NULL) {
579 _eglLog(_EGL_FATAL, "DRI2: failed to create dri screen");
580 free(dri2_dpy);
581 goto handle_error;
582 }
583
584 extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
585 for (i = 0; extensions[i]; i++) {
586 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0))
587 dri2_dpy->flush = (__DRI2flushExtension *) extensions[i];
588 }
589
590 if (dri2_dpy->flush == NULL) {
591 _eglLog(_EGL_FATAL, "DRI2: driver doesn't support the flush extension");
592 free(dri2_dpy);
593 goto handle_error;
594 }
595
596 for (i = 0; driver_configs[i]; i++)
597 dri2_add_config(disp, driver_configs[i], i + 1);
598 if (!disp->NumConfigs) {
599 _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
600 goto handle_error;
601 }
602
603 disp->ClientAPIsMask = EGL_OPENGL_BIT;
604
605 /* we're supporting EGL 1.4 */
606 *major = 1;
607 *minor = 4;
608
609 free (connect);
610 return EGL_TRUE;
611
612 handle_error:
613 free(connect);
614 free(dri2_dpy);
615 return EGL_FALSE;
616 }
617
618 /**
619 * Called via eglTerminate(), drv->API.Terminate().
620 */
621 static EGLBoolean
622 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
623 {
624 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
625
626 _eglReleaseDisplayResources(drv, disp);
627 _eglCleanupDisplay(disp);
628
629 close(dri2_dpy->fd);
630 dlclose(dri2_dpy->driver);
631 free(dri2_dpy);
632
633 disp->DriverData = NULL;
634
635 return EGL_TRUE;
636 }
637
638
639 /**
640 * Called via eglCreateContext(), drv->API.CreateContext().
641 */
642 static _EGLContext *
643 dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
644 _EGLContext *share_list, const EGLint *attrib_list)
645 {
646 struct dri2_egl_context *dri2_ctx;
647 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
648 struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
649 struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
650
651 dri2_ctx = malloc(sizeof *dri2_ctx);
652 if (!dri2_ctx) {
653 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
654 return NULL;
655 }
656
657 if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list)) {
658 free(dri2_ctx);
659 return NULL;
660 }
661
662 dri2_ctx->dri_context =
663 dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen,
664 dri2_config->dri_config,
665 dri2_ctx_shared ?
666 dri2_ctx_shared->dri_context : NULL,
667 dri2_ctx);
668
669 if (!dri2_ctx->dri_context) {
670 free(dri2_ctx);
671 return NULL;
672 }
673
674 return &dri2_ctx->base;
675 }
676
677 static EGLBoolean
678 dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
679 {
680 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
681 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
682
683 if (_eglIsSurfaceBound(surf))
684 return EGL_TRUE;
685
686 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
687
688 xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
689
690 if (surf->Type == EGL_PBUFFER_BIT)
691 xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
692
693 free(surf);
694
695 return EGL_TRUE;
696 }
697
698 /**
699 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
700 */
701 static EGLBoolean
702 dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
703 _EGLSurface *rsurf, _EGLContext *ctx)
704 {
705 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
706 struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
707 struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
708 struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
709 __DRIdrawable *ddraw, *rdraw;
710 __DRIcontext *cctx;
711
712 /* bind the new context and return the "orphaned" one */
713 if (!_eglBindContext(&ctx, &dsurf, &rsurf))
714 return EGL_FALSE;
715
716 ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
717 rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL;
718 cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
719
720 if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
721 dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
722 if (dsurf)
723 dri2_destroy_surface(drv, disp, dsurf);
724 if (rsurf && rsurf != dsurf)
725 dri2_destroy_surface(drv, disp, rsurf);
726 if (ctx != NULL)
727 dri2_dpy->core->unbindContext(dri2_egl_context(ctx)->dri_context);
728
729 return EGL_TRUE;
730 } else {
731 _eglBindContext(&ctx, &dsurf, &rsurf);
732
733 return EGL_FALSE;
734 }
735 }
736
737 /**
738 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
739 */
740 static _EGLSurface *
741 dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
742 _EGLConfig *conf, EGLNativeWindowType window,
743 const EGLint *attrib_list)
744 {
745 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
746 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
747 struct dri2_egl_surface *dri2_surf;
748 xcb_get_geometry_cookie_t cookie;
749 xcb_get_geometry_reply_t *reply;
750 xcb_screen_iterator_t s;
751 xcb_generic_error_t *error;
752
753 dri2_surf = malloc(sizeof *dri2_surf);
754 if (!dri2_surf) {
755 _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
756 return NULL;
757 }
758
759 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) {
760 free(dri2_surf);
761 return NULL;
762 }
763
764 dri2_surf->region = XCB_NONE;
765 if (type == EGL_PBUFFER_BIT) {
766 dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
767 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
768 xcb_create_pixmap(dri2_dpy->conn,
769 _eglGetConfigKey(conf, EGL_BUFFER_SIZE),
770 dri2_surf->drawable, s.data->root,
771 dri2_surf->base.Width, dri2_surf->base.Height);
772 } else {
773 dri2_surf->drawable = window;
774 }
775
776 dri2_surf->dri_drawable =
777 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
778 dri2_conf->dri_config, dri2_surf);
779 if (dri2_surf == NULL) {
780 _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
781 free(dri2_surf);
782 return NULL;
783 }
784
785 xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
786
787 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
788 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
789 if (reply == NULL || error != NULL) {
790 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
791 free(dri2_surf);
792 free(error);
793 return NULL;
794 }
795 dri2_surf->base.Width = reply->width;
796 dri2_surf->base.Height = reply->height;
797 free(reply);
798
799 return &dri2_surf->base;
800 }
801
802 /**
803 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
804 */
805 static _EGLSurface *
806 dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
807 _EGLConfig *conf, EGLNativeWindowType window,
808 const EGLint *attrib_list)
809 {
810 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
811 window, attrib_list);
812 }
813
814 static _EGLSurface *
815 dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
816 _EGLConfig *conf, EGLNativePixmapType pixmap,
817 const EGLint *attrib_list)
818 {
819 return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
820 pixmap, attrib_list);
821 }
822
823 static _EGLSurface *
824 dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
825 _EGLConfig *conf, const EGLint *attrib_list)
826 {
827 return dri2_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
828 XCB_WINDOW_NONE, attrib_list);
829 }
830
831 static EGLBoolean
832 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
833 {
834 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
835 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
836 xcb_dri2_copy_region_cookie_t cookie;
837
838 if (dri2_dpy->flush)
839 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
840
841 #if 0
842 /* FIXME: Add support for dri swapbuffers, that'll give us swap
843 * interval and page flipping (at least for fullscreen windows) as
844 * well as the page flip event. */
845 #if __DRI2_FLUSH_VERSION >= 2
846 if (pdraw->psc->f)
847 (*pdraw->psc->f->flushInvalidate)(pdraw->driDrawable);
848 #endif
849 #endif
850
851 if (!dri2_surf->have_back)
852 return EGL_TRUE;
853
854 cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
855 dri2_surf->drawable,
856 dri2_surf->region,
857 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
858 XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
859 free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
860
861 return EGL_TRUE;
862 }
863
864 /*
865 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
866 */
867 static _EGLProc
868 dri2_get_proc_address(_EGLDriver *drv, const char *procname)
869 {
870 /* FIXME: Do we need to support lookup of EGL symbols too? */
871
872 return (_EGLProc) _glapi_get_proc_address(procname);
873 }
874
875 static EGLBoolean
876 dri2_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
877 {
878 /* glXWaitGL(); */
879
880 return EGL_TRUE;
881 }
882
883 static EGLBoolean
884 dri2_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
885 {
886 if (engine != EGL_CORE_NATIVE_ENGINE)
887 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
888 /* glXWaitX(); */
889
890 return EGL_TRUE;
891 }
892
893 static void
894 dri2_unload(_EGLDriver *drv)
895 {
896 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
897 free(dri2_drv);
898 }
899
900 /**
901 * This is the main entrypoint into the driver, called by libEGL.
902 * Create a new _EGLDriver object and init its dispatch table.
903 */
904 _EGLDriver *
905 _eglMain(const char *args)
906 {
907 struct dri2_egl_driver *dri2_drv;
908
909 dri2_drv = malloc(sizeof *dri2_drv);
910 if (!dri2_drv)
911 return NULL;
912
913 _eglInitDriverFallbacks(&dri2_drv->base);
914 dri2_drv->base.API.Initialize = dri2_initialize;
915 dri2_drv->base.API.Terminate = dri2_terminate;
916 dri2_drv->base.API.CreateContext = dri2_create_context;
917 dri2_drv->base.API.MakeCurrent = dri2_make_current;
918 dri2_drv->base.API.CreateWindowSurface = dri2_create_window_surface;
919 dri2_drv->base.API.CreatePixmapSurface = dri2_create_pixmap_surface;
920 dri2_drv->base.API.CreatePbufferSurface = dri2_create_pbuffer_surface;
921 dri2_drv->base.API.DestroySurface = dri2_destroy_surface;
922 dri2_drv->base.API.SwapBuffers = dri2_swap_buffers;
923 dri2_drv->base.API.GetProcAddress = dri2_get_proc_address;
924 dri2_drv->base.API.WaitClient = dri2_wait_client;
925 dri2_drv->base.API.WaitNative = dri2_wait_native;
926
927 dri2_drv->base.Name = "DRI2";
928 dri2_drv->base.Unload = dri2_unload;
929
930 return &dri2_drv->base;
931 }