egl/dri2: Dispatch eglCreateWaylandBufferFromImageWL by display, not driver
[mesa.git] / src / egl / drivers / dri2 / platform_x11.c
1 /*
2 * Copyright © 2011 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 <stdbool.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <limits.h>
33 #include <dlfcn.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #ifdef HAVE_LIBDRM
38 #include <xf86drm.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/stat.h>
42
43 #include "egl_dri2.h"
44 #include "egl_dri2_fallbacks.h"
45
46 static EGLBoolean
47 dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
48 EGLint interval);
49
50 static void
51 swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,
52 struct dri2_egl_surface * dri2_surf,
53 int depth)
54 {
55 uint32_t mask;
56 const uint32_t function = GXcopy;
57 uint32_t valgc[2];
58
59 /* create GC's */
60 dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
61 mask = XCB_GC_FUNCTION;
62 xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);
63
64 dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
65 mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
66 valgc[0] = function;
67 valgc[1] = False;
68 xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);
69 dri2_surf->depth = depth;
70 switch (depth) {
71 case 32:
72 case 24:
73 dri2_surf->bytes_per_pixel = 4;
74 break;
75 case 16:
76 dri2_surf->bytes_per_pixel = 2;
77 break;
78 case 8:
79 dri2_surf->bytes_per_pixel = 1;
80 break;
81 case 0:
82 dri2_surf->bytes_per_pixel = 0;
83 break;
84 default:
85 _eglLog(_EGL_WARNING, "unsupported depth %d", depth);
86 }
87 }
88
89 static void
90 swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,
91 struct dri2_egl_surface * dri2_surf)
92 {
93 xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
94 xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
95 }
96
97 static void
98 swrastGetDrawableInfo(__DRIdrawable * draw,
99 int *x, int *y, int *w, int *h,
100 void *loaderPrivate)
101 {
102 struct dri2_egl_surface *dri2_surf = loaderPrivate;
103 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
104
105 xcb_get_geometry_cookie_t cookie;
106 xcb_get_geometry_reply_t *reply;
107 xcb_generic_error_t *error;
108
109 *w = *h = 0;
110 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
111 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
112 if (reply == NULL)
113 return;
114
115 if (error != NULL) {
116 _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
117 free(error);
118 } else {
119 *w = reply->width;
120 *h = reply->height;
121 }
122 free(reply);
123 }
124
125 static void
126 swrastPutImage(__DRIdrawable * draw, int op,
127 int x, int y, int w, int h,
128 char *data, void *loaderPrivate)
129 {
130 struct dri2_egl_surface *dri2_surf = loaderPrivate;
131 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
132
133 xcb_gcontext_t gc;
134
135 switch (op) {
136 case __DRI_SWRAST_IMAGE_OP_DRAW:
137 gc = dri2_surf->gc;
138 break;
139 case __DRI_SWRAST_IMAGE_OP_SWAP:
140 gc = dri2_surf->swapgc;
141 break;
142 default:
143 return;
144 }
145
146 xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,
147 gc, w, h, x, y, 0, dri2_surf->depth,
148 w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);
149 }
150
151 static void
152 swrastGetImage(__DRIdrawable * read,
153 int x, int y, int w, int h,
154 char *data, void *loaderPrivate)
155 {
156 struct dri2_egl_surface *dri2_surf = loaderPrivate;
157 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
158
159 xcb_get_image_cookie_t cookie;
160 xcb_get_image_reply_t *reply;
161 xcb_generic_error_t *error;
162
163 cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
164 dri2_surf->drawable, x, y, w, h, ~0);
165 reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);
166 if (reply == NULL)
167 return;
168
169 if (error != NULL) {
170 _eglLog(_EGL_WARNING, "error in xcb_get_image");
171 free(error);
172 } else {
173 uint32_t bytes = xcb_get_image_data_length(reply);
174 uint8_t *idata = xcb_get_image_data(reply);
175 memcpy(data, idata, bytes);
176 }
177 free(reply);
178 }
179
180
181 /**
182 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
183 */
184 static _EGLSurface *
185 dri2_x11_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
186 _EGLConfig *conf, EGLNativeWindowType native_window,
187 const EGLint *attrib_list)
188 {
189 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
190 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
191 struct dri2_egl_surface *dri2_surf;
192 xcb_get_geometry_cookie_t cookie;
193 xcb_get_geometry_reply_t *reply;
194 xcb_screen_iterator_t s;
195 xcb_generic_error_t *error;
196 xcb_drawable_t window = (uintptr_t )native_window;
197
198 (void) drv;
199
200 dri2_surf = malloc(sizeof *dri2_surf);
201 if (!dri2_surf) {
202 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
203 return NULL;
204 }
205
206 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
207 goto cleanup_surf;
208
209 dri2_surf->region = XCB_NONE;
210 if (type == EGL_PBUFFER_BIT) {
211 dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
212 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
213 xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
214 dri2_surf->drawable, s.data->root,
215 dri2_surf->base.Width, dri2_surf->base.Height);
216 } else {
217 dri2_surf->drawable = window;
218 }
219
220 if (dri2_dpy->dri2) {
221 dri2_surf->dri_drawable =
222 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
223 type == EGL_WINDOW_BIT ?
224 dri2_conf->dri_double_config :
225 dri2_conf->dri_single_config,
226 dri2_surf);
227 } else {
228 assert(dri2_dpy->swrast);
229 dri2_surf->dri_drawable =
230 (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen,
231 dri2_conf->dri_double_config,
232 dri2_surf);
233 }
234
235 if (dri2_surf->dri_drawable == NULL) {
236 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
237 goto cleanup_pixmap;
238 }
239
240 if (dri2_dpy->dri2) {
241 xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
242 } else {
243 swrastCreateDrawable(dri2_dpy, dri2_surf, _eglGetConfigKey(conf, EGL_BUFFER_SIZE));
244 }
245
246 if (type != EGL_PBUFFER_BIT) {
247 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
248 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
249 if (reply == NULL || error != NULL) {
250 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
251 free(error);
252 goto cleanup_dri_drawable;
253 }
254
255 dri2_surf->base.Width = reply->width;
256 dri2_surf->base.Height = reply->height;
257 free(reply);
258 }
259
260 /* we always copy the back buffer to front */
261 dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;
262
263 return &dri2_surf->base;
264
265 cleanup_dri_drawable:
266 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
267 cleanup_pixmap:
268 if (type == EGL_PBUFFER_BIT)
269 xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
270 cleanup_surf:
271 free(dri2_surf);
272
273 return NULL;
274 }
275
276 /**
277 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
278 */
279 static _EGLSurface *
280 dri2_x11_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
281 _EGLConfig *conf, EGLNativeWindowType window,
282 const EGLint *attrib_list)
283 {
284 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
285 _EGLSurface *surf;
286
287 surf = dri2_x11_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
288 window, attrib_list);
289 if (surf != NULL) {
290 /* When we first create the DRI2 drawable, its swap interval on the
291 * server side is 1.
292 */
293 surf->SwapInterval = 1;
294
295 /* Override that with a driconf-set value. */
296 dri2_x11_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
297 }
298
299 return surf;
300 }
301
302 static _EGLSurface *
303 dri2_x11_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
304 _EGLConfig *conf, EGLNativePixmapType pixmap,
305 const EGLint *attrib_list)
306 {
307 return dri2_x11_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
308 pixmap, attrib_list);
309 }
310
311 static _EGLSurface *
312 dri2_x11_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
313 _EGLConfig *conf, const EGLint *attrib_list)
314 {
315 return dri2_x11_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
316 XCB_WINDOW_NONE, attrib_list);
317 }
318
319 static EGLBoolean
320 dri2_x11_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
321 {
322 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
323 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
324
325 (void) drv;
326
327 if (!_eglPutSurface(surf))
328 return EGL_TRUE;
329
330 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
331
332 if (dri2_dpy->dri2) {
333 xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
334 } else {
335 assert(dri2_dpy->swrast);
336 swrastDestroyDrawable(dri2_dpy, dri2_surf);
337 }
338
339 if (surf->Type == EGL_PBUFFER_BIT)
340 xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
341
342 free(surf);
343
344 return EGL_TRUE;
345 }
346
347 /**
348 * Process list of buffer received from the server
349 *
350 * Processes the list of buffers received in a reply from the server to either
351 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
352 */
353 static void
354 dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf,
355 xcb_dri2_dri2_buffer_t *buffers, unsigned count)
356 {
357 struct dri2_egl_display *dri2_dpy =
358 dri2_egl_display(dri2_surf->base.Resource.Display);
359 xcb_rectangle_t rectangle;
360 unsigned i;
361
362 dri2_surf->buffer_count = count;
363 dri2_surf->have_fake_front = 0;
364
365 /* This assumes the DRI2 buffer attachment tokens matches the
366 * __DRIbuffer tokens. */
367 for (i = 0; i < count; i++) {
368 dri2_surf->buffers[i].attachment = buffers[i].attachment;
369 dri2_surf->buffers[i].name = buffers[i].name;
370 dri2_surf->buffers[i].pitch = buffers[i].pitch;
371 dri2_surf->buffers[i].cpp = buffers[i].cpp;
372 dri2_surf->buffers[i].flags = buffers[i].flags;
373
374 /* We only use the DRI drivers single buffer configs. This
375 * means that if we try to render to a window, DRI2 will give us
376 * the fake front buffer, which we'll use as a back buffer.
377 * Note that EGL doesn't require that several clients rendering
378 * to the same window must see the same aux buffers. */
379 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
380 dri2_surf->have_fake_front = 1;
381 }
382
383 if (dri2_surf->region != XCB_NONE)
384 xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
385
386 rectangle.x = 0;
387 rectangle.y = 0;
388 rectangle.width = dri2_surf->base.Width;
389 rectangle.height = dri2_surf->base.Height;
390 dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
391 xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
392 }
393
394 static __DRIbuffer *
395 dri2_x11_get_buffers(__DRIdrawable * driDrawable,
396 int *width, int *height,
397 unsigned int *attachments, int count,
398 int *out_count, void *loaderPrivate)
399 {
400 struct dri2_egl_surface *dri2_surf = loaderPrivate;
401 struct dri2_egl_display *dri2_dpy =
402 dri2_egl_display(dri2_surf->base.Resource.Display);
403 xcb_dri2_dri2_buffer_t *buffers;
404 xcb_dri2_get_buffers_reply_t *reply;
405 xcb_dri2_get_buffers_cookie_t cookie;
406
407 (void) driDrawable;
408
409 cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
410 dri2_surf->drawable,
411 count, count, attachments);
412 reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
413 buffers = xcb_dri2_get_buffers_buffers (reply);
414 if (buffers == NULL)
415 return NULL;
416
417 *out_count = reply->count;
418 dri2_surf->base.Width = *width = reply->width;
419 dri2_surf->base.Height = *height = reply->height;
420 dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
421
422 free(reply);
423
424 return dri2_surf->buffers;
425 }
426
427 static __DRIbuffer *
428 dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,
429 int *width, int *height,
430 unsigned int *attachments, int count,
431 int *out_count, void *loaderPrivate)
432 {
433 struct dri2_egl_surface *dri2_surf = loaderPrivate;
434 struct dri2_egl_display *dri2_dpy =
435 dri2_egl_display(dri2_surf->base.Resource.Display);
436 xcb_dri2_dri2_buffer_t *buffers;
437 xcb_dri2_get_buffers_with_format_reply_t *reply;
438 xcb_dri2_get_buffers_with_format_cookie_t cookie;
439 xcb_dri2_attach_format_t *format_attachments;
440
441 (void) driDrawable;
442
443 format_attachments = (xcb_dri2_attach_format_t *) attachments;
444 cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
445 dri2_surf->drawable,
446 count, count,
447 format_attachments);
448
449 reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
450 cookie, NULL);
451 if (reply == NULL)
452 return NULL;
453
454 buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
455 dri2_surf->base.Width = *width = reply->width;
456 dri2_surf->base.Height = *height = reply->height;
457 *out_count = reply->count;
458 dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
459
460 free(reply);
461
462 return dri2_surf->buffers;
463 }
464
465 static void
466 dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
467 {
468 (void) driDrawable;
469
470 /* FIXME: Does EGL support front buffer rendering at all? */
471
472 #if 0
473 struct dri2_egl_surface *dri2_surf = loaderPrivate;
474
475 dri2WaitGL(dri2_surf);
476 #else
477 (void) loaderPrivate;
478 #endif
479 }
480
481 static char *
482 dri2_x11_strndup(const char *s, int length)
483 {
484 char *d;
485
486 d = malloc(length + 1);
487 if (d == NULL)
488 return NULL;
489
490 memcpy(d, s, length);
491 d[length] = '\0';
492
493 return d;
494 }
495
496 static EGLBoolean
497 dri2_x11_connect(struct dri2_egl_display *dri2_dpy)
498 {
499 xcb_xfixes_query_version_reply_t *xfixes_query;
500 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
501 xcb_dri2_query_version_reply_t *dri2_query;
502 xcb_dri2_query_version_cookie_t dri2_query_cookie;
503 xcb_dri2_connect_reply_t *connect;
504 xcb_dri2_connect_cookie_t connect_cookie;
505 xcb_generic_error_t *error;
506 xcb_screen_iterator_t s;
507 char *driver_name, *device_name;
508 const xcb_query_extension_reply_t *extension;
509
510 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
511 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
512
513 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
514 if (!(extension && extension->present))
515 return EGL_FALSE;
516
517 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);
518 if (!(extension && extension->present))
519 return EGL_FALSE;
520
521 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
522 XCB_XFIXES_MAJOR_VERSION,
523 XCB_XFIXES_MINOR_VERSION);
524
525 dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
526 XCB_DRI2_MAJOR_VERSION,
527 XCB_DRI2_MINOR_VERSION);
528
529 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
530 connect_cookie = xcb_dri2_connect_unchecked (dri2_dpy->conn,
531 s.data->root,
532 XCB_DRI2_DRIVER_TYPE_DRI);
533
534 xfixes_query =
535 xcb_xfixes_query_version_reply (dri2_dpy->conn,
536 xfixes_query_cookie, &error);
537 if (xfixes_query == NULL ||
538 error != NULL || xfixes_query->major_version < 2) {
539 _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
540 free(error);
541 return EGL_FALSE;
542 }
543 free(xfixes_query);
544
545 dri2_query =
546 xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
547 if (dri2_query == NULL || error != NULL) {
548 _eglLog(_EGL_WARNING, "DRI2: failed to query version");
549 free(error);
550 return EGL_FALSE;
551 }
552 dri2_dpy->dri2_major = dri2_query->major_version;
553 dri2_dpy->dri2_minor = dri2_query->minor_version;
554 free(dri2_query);
555
556 connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
557 if (connect == NULL ||
558 connect->driver_name_length + connect->device_name_length == 0) {
559 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
560 return EGL_FALSE;
561 }
562
563 driver_name = xcb_dri2_connect_driver_name (connect);
564 dri2_dpy->driver_name =
565 dri2_x11_strndup(driver_name,
566 xcb_dri2_connect_driver_name_length(connect));
567
568 device_name = xcb_dri2_connect_device_name (connect);
569
570 dri2_dpy->device_name =
571 dri2_x11_strndup(device_name,
572 xcb_dri2_connect_device_name_length(connect));
573
574 if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) {
575 free(dri2_dpy->device_name);
576 free(dri2_dpy->driver_name);
577 free(connect);
578 return EGL_FALSE;
579 }
580 free(connect);
581
582 return EGL_TRUE;
583 }
584
585 static int
586 dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)
587 {
588 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
589 xcb_dri2_authenticate_reply_t *authenticate;
590 xcb_dri2_authenticate_cookie_t authenticate_cookie;
591 xcb_screen_iterator_t s;
592 int ret = 0;
593
594 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
595 authenticate_cookie =
596 xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, id);
597 authenticate =
598 xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
599
600 if (authenticate == NULL || !authenticate->authenticated)
601 ret = -1;
602
603 free(authenticate);
604
605 return ret;
606 }
607
608 static EGLBoolean
609 dri2_x11_local_authenticate(_EGLDisplay *disp)
610 {
611 #ifdef HAVE_LIBDRM
612 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
613 drm_magic_t magic;
614
615 if (drmGetMagic(dri2_dpy->fd, &magic)) {
616 _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");
617 return EGL_FALSE;
618 }
619
620 if (dri2_x11_authenticate(disp, magic) < 0) {
621 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
622 return EGL_FALSE;
623 }
624 #endif
625 return EGL_TRUE;
626 }
627
628 static EGLBoolean
629 dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
630 _EGLDisplay *disp)
631 {
632 xcb_screen_iterator_t s;
633 xcb_depth_iterator_t d;
634 xcb_visualtype_t *visuals;
635 int i, j, id;
636 unsigned int rgba_masks[4];
637 EGLint surface_type;
638 EGLint config_attrs[] = {
639 EGL_NATIVE_VISUAL_ID, 0,
640 EGL_NATIVE_VISUAL_TYPE, 0,
641 EGL_NONE
642 };
643
644 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
645 d = xcb_screen_allowed_depths_iterator(s.data);
646 id = 1;
647
648 surface_type =
649 EGL_WINDOW_BIT |
650 EGL_PIXMAP_BIT |
651 EGL_PBUFFER_BIT |
652 EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
653
654 while (d.rem > 0) {
655 EGLBoolean class_added[6] = { 0, };
656
657 visuals = xcb_depth_visuals(d.data);
658 for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
659 if (class_added[visuals[i]._class])
660 continue;
661
662 class_added[visuals[i]._class] = EGL_TRUE;
663 for (j = 0; dri2_dpy->driver_configs[j]; j++) {
664 config_attrs[1] = visuals[i].visual_id;
665 config_attrs[3] = visuals[i]._class;
666
667 rgba_masks[0] = visuals[i].red_mask;
668 rgba_masks[1] = visuals[i].green_mask;
669 rgba_masks[2] = visuals[i].blue_mask;
670 rgba_masks[3] = 0;
671 dri2_add_config(disp, dri2_dpy->driver_configs[j], id++,
672 surface_type, config_attrs, rgba_masks);
673
674 /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig.
675 * Otherwise it will only match a 32-bit RGBA visual. On a
676 * composited window manager on X11, this will make all of the
677 * EGLConfigs with destination alpha get blended by the
678 * compositor. This is probably not what the application
679 * wants... especially on drivers that only have 32-bit RGBA
680 * EGLConfigs! */
681 if (d.data->depth == 24) {
682 rgba_masks[3] =
683 ~(rgba_masks[0] | rgba_masks[1] | rgba_masks[2]);
684 dri2_add_config(disp, dri2_dpy->driver_configs[j], id++,
685 surface_type, config_attrs, rgba_masks);
686 }
687 }
688 }
689
690 xcb_depth_next(&d);
691 }
692
693 if (!_eglGetArraySize(disp->Configs)) {
694 _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
695 return EGL_FALSE;
696 }
697
698 return EGL_TRUE;
699 }
700
701 static EGLBoolean
702 dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
703 _EGLSurface *draw, xcb_xfixes_region_t region)
704 {
705 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
706 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
707 enum xcb_dri2_attachment_t render_attachment;
708 xcb_dri2_copy_region_cookie_t cookie;
709
710 /* No-op for a pixmap or pbuffer surface */
711 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
712 return EGL_TRUE;
713
714 if (dri2_dpy->flush)
715 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
716
717 if (dri2_surf->have_fake_front)
718 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
719 else
720 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
721
722 cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
723 dri2_surf->drawable,
724 region,
725 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
726 render_attachment);
727 free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
728
729 return EGL_TRUE;
730 }
731
732 static int64_t
733 dri2_x11_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
734 int64_t msc, int64_t divisor, int64_t remainder)
735 {
736 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
737 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
738 uint32_t msc_hi = msc >> 32;
739 uint32_t msc_lo = msc & 0xffffffff;
740 uint32_t divisor_hi = divisor >> 32;
741 uint32_t divisor_lo = divisor & 0xffffffff;
742 uint32_t remainder_hi = remainder >> 32;
743 uint32_t remainder_lo = remainder & 0xffffffff;
744 xcb_dri2_swap_buffers_cookie_t cookie;
745 xcb_dri2_swap_buffers_reply_t *reply;
746 int64_t swap_count = -1;
747
748 /* No-op for a pixmap or pbuffer surface */
749 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
750 return 0;
751
752 if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available)
753 return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1;
754
755 if (dri2_dpy->flush)
756 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
757
758 cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable,
759 msc_hi, msc_lo, divisor_hi, divisor_lo, remainder_hi, remainder_lo);
760
761 reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);
762
763 if (reply) {
764 swap_count = (((int64_t)reply->swap_hi) << 32) | reply->swap_lo;
765 free(reply);
766 }
767
768 /* Since we aren't watching for the server's invalidate events like we're
769 * supposed to (due to XCB providing no mechanism for filtering the events
770 * the way xlib does), and SwapBuffers is a common cause of invalidate
771 * events, just shove one down to the driver, even though we haven't told
772 * the driver that we're the kind of loader that provides reliable
773 * invalidate events. This causes the driver to request buffers again at
774 * its next draw, so that we get the correct buffers if a pageflip
775 * happened. The driver should still be using the viewport hack to catch
776 * window resizes.
777 */
778 if (dri2_dpy->flush &&
779 dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
780 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
781
782 return swap_count;
783 }
784
785 static EGLBoolean
786 dri2_x11_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
787 {
788 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
789 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
790
791 if (dri2_dpy->dri2) {
792 return dri2_x11_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1;
793 } else {
794 assert(dri2_dpy->swrast);
795
796 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
797 return EGL_TRUE;
798 }
799 }
800
801 static EGLBoolean
802 dri2_x11_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp,
803 _EGLSurface *draw,
804 EGLint numRects, const EGLint *rects)
805 {
806 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
807 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
808 EGLBoolean ret;
809 xcb_xfixes_region_t region;
810 xcb_rectangle_t rectangles[16];
811 int i;
812
813 if (numRects > (int)ARRAY_SIZE(rectangles))
814 return dri2_copy_region(drv, disp, draw, dri2_surf->region);
815
816 for (i = 0; i < numRects; i++) {
817 rectangles[i].x = rects[i * 4];
818 rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];
819 rectangles[i].width = rects[i * 4 + 2];
820 rectangles[i].height = rects[i * 4 + 3];
821 }
822
823 region = xcb_generate_id(dri2_dpy->conn);
824 xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
825 ret = dri2_copy_region(drv, disp, draw, region);
826 xcb_xfixes_destroy_region(dri2_dpy->conn, region);
827
828 return ret;
829 }
830
831 static EGLBoolean
832 dri2_x11_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
833 EGLint x, EGLint y, EGLint width, EGLint height)
834 {
835 const EGLint rect[4] = { x, y, width, height };
836
837 if (x < 0 || y < 0 || width < 0 || height < 0)
838 _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
839
840 return dri2_x11_swap_buffers_region(drv, disp, draw, 1, rect);
841 }
842
843 static EGLBoolean
844 dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
845 EGLint interval)
846 {
847 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
848 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
849
850 if (interval > surf->Config->MaxSwapInterval)
851 interval = surf->Config->MaxSwapInterval;
852 else if (interval < surf->Config->MinSwapInterval)
853 interval = surf->Config->MinSwapInterval;
854
855 if (interval != surf->SwapInterval && dri2_dpy->swap_available)
856 xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);
857
858 surf->SwapInterval = interval;
859
860 return EGL_TRUE;
861 }
862
863 static EGLBoolean
864 dri2_x11_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
865 EGLNativePixmapType native_target)
866 {
867 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
868 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
869 xcb_gcontext_t gc;
870 xcb_pixmap_t target = (uintptr_t )native_target;
871
872 (void) drv;
873
874 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
875
876 gc = xcb_generate_id(dri2_dpy->conn);
877 xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
878 xcb_copy_area(dri2_dpy->conn,
879 dri2_surf->drawable,
880 target,
881 gc,
882 0, 0,
883 0, 0,
884 dri2_surf->base.Width,
885 dri2_surf->base.Height);
886 xcb_free_gc(dri2_dpy->conn, gc);
887
888 return EGL_TRUE;
889 }
890
891 static _EGLImage *
892 dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
893 EGLClientBuffer buffer, const EGLint *attr_list)
894 {
895 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
896 struct dri2_egl_image *dri2_img;
897 unsigned int attachments[1];
898 xcb_drawable_t drawable;
899 xcb_dri2_get_buffers_cookie_t buffers_cookie;
900 xcb_dri2_get_buffers_reply_t *buffers_reply;
901 xcb_dri2_dri2_buffer_t *buffers;
902 xcb_get_geometry_cookie_t geometry_cookie;
903 xcb_get_geometry_reply_t *geometry_reply;
904 xcb_generic_error_t *error;
905 int stride, format;
906
907 (void) ctx;
908
909 drawable = (xcb_drawable_t) (uintptr_t) buffer;
910 xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
911 attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
912 buffers_cookie =
913 xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
914 drawable, 1, 1, attachments);
915 geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
916 buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
917 buffers_cookie, NULL);
918 buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
919 if (buffers == NULL) {
920 return NULL;
921 }
922
923 geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
924 geometry_cookie, &error);
925 if (geometry_reply == NULL || error != NULL) {
926 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
927 free(error);
928 free(buffers_reply);
929 return NULL;
930 }
931
932 switch (geometry_reply->depth) {
933 case 16:
934 format = __DRI_IMAGE_FORMAT_RGB565;
935 break;
936 case 24:
937 format = __DRI_IMAGE_FORMAT_XRGB8888;
938 break;
939 case 32:
940 format = __DRI_IMAGE_FORMAT_ARGB8888;
941 break;
942 default:
943 _eglError(EGL_BAD_PARAMETER,
944 "dri2_create_image_khr: unsupported pixmap depth");
945 free(buffers_reply);
946 free(geometry_reply);
947 return NULL;
948 }
949
950 dri2_img = malloc(sizeof *dri2_img);
951 if (!dri2_img) {
952 free(buffers_reply);
953 free(geometry_reply);
954 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
955 return EGL_NO_IMAGE_KHR;
956 }
957
958 if (!_eglInitImage(&dri2_img->base, disp)) {
959 free(buffers_reply);
960 free(geometry_reply);
961 free(dri2_img);
962 return EGL_NO_IMAGE_KHR;
963 }
964
965 stride = buffers[0].pitch / buffers[0].cpp;
966 dri2_img->dri_image =
967 dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
968 buffers_reply->width,
969 buffers_reply->height,
970 format,
971 buffers[0].name,
972 stride,
973 dri2_img);
974
975 free(buffers_reply);
976 free(geometry_reply);
977
978 return &dri2_img->base;
979 }
980
981 static _EGLImage *
982 dri2_x11_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
983 _EGLContext *ctx, EGLenum target,
984 EGLClientBuffer buffer, const EGLint *attr_list)
985 {
986 (void) drv;
987
988 switch (target) {
989 case EGL_NATIVE_PIXMAP_KHR:
990 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
991 default:
992 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
993 }
994 }
995
996 static struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {
997 .authenticate = NULL,
998 .create_window_surface = dri2_x11_create_window_surface,
999 .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1000 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1001 .destroy_surface = dri2_x11_destroy_surface,
1002 .swap_interval = dri2_fallback_swap_interval,
1003 .swap_buffers = dri2_x11_swap_buffers,
1004 .swap_buffers_region = dri2_fallback_swap_buffers_region,
1005 .post_sub_buffer = dri2_fallback_post_sub_buffer,
1006 .copy_buffers = dri2_x11_copy_buffers,
1007 .query_buffer_age = dri2_fallback_query_buffer_age,
1008 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1009 };
1010
1011 static struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {
1012 .authenticate = dri2_x11_authenticate,
1013 .create_window_surface = dri2_x11_create_window_surface,
1014 .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1015 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1016 .destroy_surface = dri2_x11_destroy_surface,
1017 .swap_interval = dri2_x11_swap_interval,
1018 .swap_buffers = dri2_x11_swap_buffers,
1019 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
1020 .swap_buffers_region = dri2_x11_swap_buffers_region,
1021 .post_sub_buffer = dri2_x11_post_sub_buffer,
1022 .copy_buffers = dri2_x11_copy_buffers,
1023 .query_buffer_age = dri2_fallback_query_buffer_age,
1024 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1025 };
1026
1027 static EGLBoolean
1028 dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)
1029 {
1030 struct dri2_egl_display *dri2_dpy;
1031
1032 drv->API.CreateImageKHR = NULL;
1033 drv->API.DestroyImageKHR = NULL;
1034 drv->API.CreateDRMImageMESA = NULL;
1035 drv->API.ExportDRMImageMESA = NULL;
1036
1037 dri2_dpy = calloc(1, sizeof *dri2_dpy);
1038 if (!dri2_dpy)
1039 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1040
1041 disp->DriverData = (void *) dri2_dpy;
1042 if (disp->PlatformDisplay == NULL) {
1043 dri2_dpy->conn = xcb_connect(0, 0);
1044 dri2_dpy->own_device = true;
1045 } else {
1046 dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay);
1047 }
1048
1049 if (xcb_connection_has_error(dri2_dpy->conn)) {
1050 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
1051 goto cleanup_dpy;
1052 }
1053
1054 if (!dri2_load_driver_swrast(disp))
1055 goto cleanup_conn;
1056
1057 dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER;
1058 dri2_dpy->swrast_loader_extension.base.version = __DRI_SWRAST_LOADER_VERSION;
1059 dri2_dpy->swrast_loader_extension.getDrawableInfo = swrastGetDrawableInfo;
1060 dri2_dpy->swrast_loader_extension.putImage = swrastPutImage;
1061 dri2_dpy->swrast_loader_extension.getImage = swrastGetImage;
1062
1063 dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base;
1064 dri2_dpy->extensions[1] = NULL;
1065 dri2_dpy->extensions[2] = NULL;
1066
1067 if (!dri2_create_screen(disp))
1068 goto cleanup_driver;
1069
1070 if (dri2_dpy->conn) {
1071 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
1072 goto cleanup_configs;
1073 }
1074
1075 /* we're supporting EGL 1.4 */
1076 disp->VersionMajor = 1;
1077 disp->VersionMinor = 4;
1078
1079 /* Fill vtbl last to prevent accidentally calling virtual function during
1080 * initialization.
1081 */
1082 dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl;
1083
1084 return EGL_TRUE;
1085
1086 cleanup_configs:
1087 _eglCleanupDisplay(disp);
1088 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1089 cleanup_driver:
1090 dlclose(dri2_dpy->driver);
1091 cleanup_conn:
1092 if (disp->PlatformDisplay == NULL)
1093 xcb_disconnect(dri2_dpy->conn);
1094 cleanup_dpy:
1095 free(dri2_dpy);
1096
1097 return EGL_FALSE;
1098 }
1099
1100 static void
1101 dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
1102 {
1103 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1104 int arbitrary_max_interval = 1000;
1105
1106 /* default behavior for no SwapBuffers support: no vblank syncing
1107 * either.
1108 */
1109 dri2_dpy->min_swap_interval = 0;
1110 dri2_dpy->max_swap_interval = 0;
1111
1112 if (!dri2_dpy->swap_available)
1113 return;
1114
1115 /* If we do have swapbuffers, then we can support pretty much any swap
1116 * interval, but we allow driconf to override applications.
1117 */
1118 if (dri2_dpy->config)
1119 dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
1120 "vblank_mode", &vblank_mode);
1121 switch (vblank_mode) {
1122 case DRI_CONF_VBLANK_NEVER:
1123 dri2_dpy->min_swap_interval = 0;
1124 dri2_dpy->max_swap_interval = 0;
1125 dri2_dpy->default_swap_interval = 0;
1126 break;
1127 case DRI_CONF_VBLANK_ALWAYS_SYNC:
1128 dri2_dpy->min_swap_interval = 1;
1129 dri2_dpy->max_swap_interval = arbitrary_max_interval;
1130 dri2_dpy->default_swap_interval = 1;
1131 break;
1132 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
1133 dri2_dpy->min_swap_interval = 0;
1134 dri2_dpy->max_swap_interval = arbitrary_max_interval;
1135 dri2_dpy->default_swap_interval = 0;
1136 break;
1137 default:
1138 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
1139 dri2_dpy->min_swap_interval = 0;
1140 dri2_dpy->max_swap_interval = arbitrary_max_interval;
1141 dri2_dpy->default_swap_interval = 1;
1142 break;
1143 }
1144 }
1145
1146 static EGLBoolean
1147 dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
1148 {
1149 struct dri2_egl_display *dri2_dpy;
1150
1151 drv->API.CreateImageKHR = dri2_x11_create_image_khr;
1152
1153 dri2_dpy = calloc(1, sizeof *dri2_dpy);
1154 if (!dri2_dpy)
1155 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1156
1157 disp->DriverData = (void *) dri2_dpy;
1158 if (disp->PlatformDisplay == NULL) {
1159 dri2_dpy->conn = xcb_connect(0, 0);
1160 dri2_dpy->own_device = true;
1161 } else {
1162 dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay);
1163 }
1164
1165 if (xcb_connection_has_error(dri2_dpy->conn)) {
1166 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
1167 goto cleanup_dpy;
1168 }
1169
1170 if (dri2_dpy->conn) {
1171 if (!dri2_x11_connect(dri2_dpy))
1172 goto cleanup_conn;
1173 }
1174
1175 if (!dri2_load_driver(disp))
1176 goto cleanup_conn;
1177
1178 #ifdef O_CLOEXEC
1179 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
1180 if (dri2_dpy->fd == -1 && errno == EINVAL)
1181 #endif
1182 {
1183 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
1184 if (dri2_dpy->fd != -1)
1185 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
1186 FD_CLOEXEC);
1187 }
1188 if (dri2_dpy->fd == -1) {
1189 _eglLog(_EGL_WARNING,
1190 "DRI2: could not open %s (%s)", dri2_dpy->device_name,
1191 strerror(errno));
1192 goto cleanup_driver;
1193 }
1194
1195 if (dri2_dpy->conn) {
1196 if (!dri2_x11_local_authenticate(disp))
1197 goto cleanup_fd;
1198 }
1199
1200 if (dri2_dpy->dri2_minor >= 1) {
1201 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1202 dri2_dpy->dri2_loader_extension.base.version = 3;
1203 dri2_dpy->dri2_loader_extension.getBuffers = dri2_x11_get_buffers;
1204 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_x11_flush_front_buffer;
1205 dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
1206 dri2_x11_get_buffers_with_format;
1207 } else {
1208 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1209 dri2_dpy->dri2_loader_extension.base.version = 2;
1210 dri2_dpy->dri2_loader_extension.getBuffers = dri2_x11_get_buffers;
1211 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_x11_flush_front_buffer;
1212 dri2_dpy->dri2_loader_extension.getBuffersWithFormat = NULL;
1213 }
1214
1215 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
1216 dri2_dpy->extensions[1] = &image_lookup_extension.base;
1217 dri2_dpy->extensions[2] = NULL;
1218
1219 dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
1220 dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
1221
1222 if (!dri2_create_screen(disp))
1223 goto cleanup_fd;
1224
1225 dri2_x11_setup_swap_interval(dri2_dpy);
1226
1227 if (dri2_dpy->conn) {
1228 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
1229 goto cleanup_configs;
1230 }
1231
1232 disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1233 disp->Extensions.NOK_swap_region = EGL_TRUE;
1234 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1235 disp->Extensions.NV_post_sub_buffer = EGL_TRUE;
1236
1237 #ifdef HAVE_WAYLAND_PLATFORM
1238 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
1239 #endif
1240
1241 if (dri2_dpy->conn) {
1242 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
1243 goto cleanup_configs;
1244 }
1245
1246 /* we're supporting EGL 1.4 */
1247 disp->VersionMajor = 1;
1248 disp->VersionMinor = 4;
1249
1250 /* Fill vtbl last to prevent accidentally calling virtual function during
1251 * initialization.
1252 */
1253 dri2_dpy->vtbl = &dri2_x11_display_vtbl;
1254
1255 return EGL_TRUE;
1256
1257 cleanup_configs:
1258 _eglCleanupDisplay(disp);
1259 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1260 cleanup_fd:
1261 close(dri2_dpy->fd);
1262 cleanup_driver:
1263 dlclose(dri2_dpy->driver);
1264 cleanup_conn:
1265 if (disp->PlatformDisplay == NULL)
1266 xcb_disconnect(dri2_dpy->conn);
1267 cleanup_dpy:
1268 free(dri2_dpy);
1269
1270 return EGL_FALSE;
1271 }
1272
1273 EGLBoolean
1274 dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
1275 {
1276 EGLBoolean initialized = EGL_TRUE;
1277
1278 int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
1279
1280 if (x11_dri2_accel) {
1281 if (!dri2_initialize_x11_dri2(drv, disp)) {
1282 initialized = dri2_initialize_x11_swrast(drv, disp);
1283 }
1284 } else {
1285 initialized = dri2_initialize_x11_swrast(drv, disp);
1286 }
1287
1288 return initialized;
1289 }
1290