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