egl/x11_dri3: implement EGL_KHR_swap_buffers_with_damage
[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 <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <limits.h>
34 #include <dlfcn.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #ifdef HAVE_LIBDRM
39 #include <xf86drm.h>
40 #endif
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include "util/debug.h"
44 #include "util/macros.h"
45 #include "util/bitscan.h"
46
47 #include "egl_dri2.h"
48 #include "loader.h"
49
50 #ifdef HAVE_DRI3
51 #include "platform_x11_dri3.h"
52 #endif
53
54 static EGLBoolean
55 dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval);
56
57 uint32_t
58 dri2_format_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth);
59
60 static void
61 swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,
62 struct dri2_egl_surface * dri2_surf)
63 {
64 uint32_t mask;
65 const uint32_t function = GXcopy;
66 uint32_t valgc[2];
67
68 /* create GC's */
69 dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
70 mask = XCB_GC_FUNCTION;
71 xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);
72
73 dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
74 mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
75 valgc[0] = function;
76 valgc[1] = False;
77 xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);
78 switch (dri2_surf->depth) {
79 case 32:
80 case 30:
81 case 24:
82 dri2_surf->bytes_per_pixel = 4;
83 break;
84 case 16:
85 dri2_surf->bytes_per_pixel = 2;
86 break;
87 case 8:
88 dri2_surf->bytes_per_pixel = 1;
89 break;
90 case 0:
91 dri2_surf->bytes_per_pixel = 0;
92 break;
93 default:
94 _eglLog(_EGL_WARNING, "unsupported depth %d", dri2_surf->depth);
95 }
96 }
97
98 static void
99 swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,
100 struct dri2_egl_surface * dri2_surf)
101 {
102 xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
103 xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
104 }
105
106 static bool
107 x11_get_drawable_info(__DRIdrawable * draw,
108 int *x, int *y, int *w, int *h,
109 void *loaderPrivate)
110 {
111 struct dri2_egl_surface *dri2_surf = loaderPrivate;
112 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
113
114 xcb_get_geometry_cookie_t cookie;
115 xcb_get_geometry_reply_t *reply;
116 xcb_generic_error_t *error;
117 bool ret;
118
119 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
120 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
121 if (reply == NULL)
122 return false;
123
124 if (error != NULL) {
125 ret = false;
126 _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
127 free(error);
128 } else {
129 *x = reply->x;
130 *y = reply->y;
131 *w = reply->width;
132 *h = reply->height;
133 ret = true;
134 }
135 free(reply);
136 return ret;
137 }
138
139 static void
140 swrastGetDrawableInfo(__DRIdrawable * draw,
141 int *x, int *y, int *w, int *h,
142 void *loaderPrivate)
143 {
144 *x = *y = *w = *h = 0;
145 x11_get_drawable_info(draw, x, y, w, h, loaderPrivate);
146 }
147
148 static void
149 swrastPutImage(__DRIdrawable * draw, int op,
150 int x, int y, int w, int h,
151 char *data, void *loaderPrivate)
152 {
153 struct dri2_egl_surface *dri2_surf = loaderPrivate;
154 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
155
156 xcb_gcontext_t gc;
157
158 switch (op) {
159 case __DRI_SWRAST_IMAGE_OP_DRAW:
160 gc = dri2_surf->gc;
161 break;
162 case __DRI_SWRAST_IMAGE_OP_SWAP:
163 gc = dri2_surf->swapgc;
164 break;
165 default:
166 return;
167 }
168
169 xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,
170 gc, w, h, x, y, 0, dri2_surf->depth,
171 w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);
172 }
173
174 static void
175 swrastGetImage(__DRIdrawable * read,
176 int x, int y, int w, int h,
177 char *data, void *loaderPrivate)
178 {
179 struct dri2_egl_surface *dri2_surf = loaderPrivate;
180 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
181
182 xcb_get_image_cookie_t cookie;
183 xcb_get_image_reply_t *reply;
184 xcb_generic_error_t *error;
185
186 cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
187 dri2_surf->drawable, x, y, w, h, ~0);
188 reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);
189 if (reply == NULL)
190 return;
191
192 if (error != NULL) {
193 _eglLog(_EGL_WARNING, "error in xcb_get_image");
194 free(error);
195 } else {
196 uint32_t bytes = xcb_get_image_data_length(reply);
197 uint8_t *idata = xcb_get_image_data(reply);
198 memcpy(data, idata, bytes);
199 }
200 free(reply);
201 }
202
203
204 static xcb_screen_t *
205 get_xcb_screen(xcb_screen_iterator_t iter, int screen)
206 {
207 for (; iter.rem; --screen, xcb_screen_next(&iter))
208 if (screen == 0)
209 return iter.data;
210
211 return NULL;
212 }
213
214 static xcb_visualtype_t *
215 get_xcb_visualtype_for_depth(struct dri2_egl_display *dri2_dpy, int depth)
216 {
217 xcb_visualtype_iterator_t visual_iter;
218 xcb_screen_t *screen = dri2_dpy->screen;
219 xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen);
220
221 for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
222 if (depth_iter.data->depth != depth)
223 continue;
224
225 visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
226 if (visual_iter.rem)
227 return visual_iter.data;
228 }
229
230 return NULL;
231 }
232
233 /* Get red channel mask for given depth. */
234 unsigned int
235 dri2_x11_get_red_mask_for_depth(struct dri2_egl_display *dri2_dpy, int depth)
236 {
237 xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(dri2_dpy, depth);
238
239 if (visual)
240 return visual->red_mask;
241
242 return 0;
243 }
244
245 /**
246 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
247 */
248 static _EGLSurface *
249 dri2_x11_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
250 void *native_surface, const EGLint *attrib_list)
251 {
252 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
253 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
254 struct dri2_egl_surface *dri2_surf;
255 xcb_get_geometry_cookie_t cookie;
256 xcb_get_geometry_reply_t *reply;
257 xcb_generic_error_t *error;
258 const __DRIconfig *config;
259
260 dri2_surf = calloc(1, sizeof *dri2_surf);
261 if (!dri2_surf) {
262 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
263 return NULL;
264 }
265
266 if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
267 false, native_surface))
268 goto cleanup_surf;
269
270 dri2_surf->region = XCB_NONE;
271 if (type == EGL_PBUFFER_BIT) {
272 dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
273 xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
274 dri2_surf->drawable, dri2_dpy->screen->root,
275 dri2_surf->base.Width, dri2_surf->base.Height);
276 } else {
277 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
278 dri2_surf->drawable = (uintptr_t) native_surface;
279 }
280
281 config = dri2_get_dri_config(dri2_conf, type,
282 dri2_surf->base.GLColorspace);
283
284 if (!config) {
285 _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
286 goto cleanup_pixmap;
287 }
288
289 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
290 goto cleanup_pixmap;
291
292 if (type != EGL_PBUFFER_BIT) {
293 cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
294 reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
295 if (error != NULL) {
296 if (error->error_code == BadAlloc)
297 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
298 else if (type == EGL_WINDOW_BIT)
299 _eglError(EGL_BAD_NATIVE_WINDOW, "xcb_get_geometry");
300 else
301 _eglError(EGL_BAD_NATIVE_PIXMAP, "xcb_get_geometry");
302 free(error);
303 goto cleanup_dri_drawable;
304 } else if (reply == NULL) {
305 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
306 goto cleanup_dri_drawable;
307 }
308
309 dri2_surf->base.Width = reply->width;
310 dri2_surf->base.Height = reply->height;
311 dri2_surf->depth = reply->depth;
312 free(reply);
313 }
314
315 if (dri2_dpy->dri2) {
316 xcb_void_cookie_t cookie;
317 int conn_error;
318
319 cookie = xcb_dri2_create_drawable_checked(dri2_dpy->conn,
320 dri2_surf->drawable);
321 error = xcb_request_check(dri2_dpy->conn, cookie);
322 conn_error = xcb_connection_has_error(dri2_dpy->conn);
323 if (conn_error || error != NULL) {
324 if (type == EGL_PBUFFER_BIT || conn_error || error->error_code == BadAlloc)
325 _eglError(EGL_BAD_ALLOC, "xcb_dri2_create_drawable_checked");
326 else if (type == EGL_WINDOW_BIT)
327 _eglError(EGL_BAD_NATIVE_WINDOW,
328 "xcb_dri2_create_drawable_checked");
329 else
330 _eglError(EGL_BAD_NATIVE_PIXMAP,
331 "xcb_dri2_create_drawable_checked");
332 free(error);
333 goto cleanup_dri_drawable;
334 }
335 } else {
336 if (type == EGL_PBUFFER_BIT) {
337 dri2_surf->depth = conf->BufferSize;
338 }
339 swrastCreateDrawable(dri2_dpy, dri2_surf);
340 }
341
342 /* we always copy the back buffer to front */
343 dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;
344
345 return &dri2_surf->base;
346
347 cleanup_dri_drawable:
348 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
349 cleanup_pixmap:
350 if (type == EGL_PBUFFER_BIT)
351 xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
352 cleanup_surf:
353 free(dri2_surf);
354
355 return NULL;
356 }
357
358 /**
359 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
360 */
361 static _EGLSurface *
362 dri2_x11_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
363 void *native_window, const EGLint *attrib_list)
364 {
365 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
366 _EGLSurface *surf;
367
368 surf = dri2_x11_create_surface(disp, EGL_WINDOW_BIT, conf,
369 native_window, attrib_list);
370 if (surf != NULL) {
371 /* When we first create the DRI2 drawable, its swap interval on the
372 * server side is 1.
373 */
374 surf->SwapInterval = 1;
375
376 /* Override that with a driconf-set value. */
377 dri2_x11_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
378 }
379
380 return surf;
381 }
382
383 static _EGLSurface *
384 dri2_x11_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
385 void *native_pixmap, const EGLint *attrib_list)
386 {
387 return dri2_x11_create_surface(disp, EGL_PIXMAP_BIT, conf,
388 native_pixmap, attrib_list);
389 }
390
391 static _EGLSurface *
392 dri2_x11_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
393 const EGLint *attrib_list)
394 {
395 return dri2_x11_create_surface(disp, EGL_PBUFFER_BIT, conf,
396 NULL, attrib_list);
397 }
398
399 static EGLBoolean
400 dri2_x11_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
401 {
402 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
403 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
404
405 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
406
407 if (dri2_dpy->dri2) {
408 xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
409 } else {
410 assert(dri2_dpy->swrast);
411 swrastDestroyDrawable(dri2_dpy, dri2_surf);
412 }
413
414 if (surf->Type == EGL_PBUFFER_BIT)
415 xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
416
417 dri2_fini_surface(surf);
418 free(surf);
419
420 return EGL_TRUE;
421 }
422
423 /**
424 * Function utilizes swrastGetDrawableInfo to get surface
425 * geometry from x server and calls default query surface
426 * implementation that returns the updated values.
427 *
428 * In case of errors we still return values that we currently
429 * have.
430 */
431 static EGLBoolean
432 dri2_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
433 EGLint attribute, EGLint *value)
434 {
435 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
436 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
437 int x, y, w, h;
438
439 __DRIdrawable *drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
440
441 switch (attribute) {
442 case EGL_WIDTH:
443 case EGL_HEIGHT:
444 if (x11_get_drawable_info(drawable, &x, &y, &w, &h, dri2_surf)) {
445 surf->Width = w;
446 surf->Height = h;
447 }
448 break;
449 default:
450 break;
451 }
452 return _eglQuerySurface(disp, surf, attribute, value);
453 }
454
455 /**
456 * Process list of buffer received from the server
457 *
458 * Processes the list of buffers received in a reply from the server to either
459 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
460 */
461 static void
462 dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf,
463 xcb_dri2_dri2_buffer_t *buffers, unsigned count)
464 {
465 struct dri2_egl_display *dri2_dpy =
466 dri2_egl_display(dri2_surf->base.Resource.Display);
467 xcb_rectangle_t rectangle;
468
469 dri2_surf->have_fake_front = false;
470
471 /* This assumes the DRI2 buffer attachment tokens matches the
472 * __DRIbuffer tokens. */
473 for (unsigned i = 0; i < count; i++) {
474 dri2_surf->buffers[i].attachment = buffers[i].attachment;
475 dri2_surf->buffers[i].name = buffers[i].name;
476 dri2_surf->buffers[i].pitch = buffers[i].pitch;
477 dri2_surf->buffers[i].cpp = buffers[i].cpp;
478 dri2_surf->buffers[i].flags = buffers[i].flags;
479
480 /* We only use the DRI drivers single buffer configs. This
481 * means that if we try to render to a window, DRI2 will give us
482 * the fake front buffer, which we'll use as a back buffer.
483 * Note that EGL doesn't require that several clients rendering
484 * to the same window must see the same aux buffers. */
485 if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
486 dri2_surf->have_fake_front = true;
487 }
488
489 if (dri2_surf->region != XCB_NONE)
490 xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
491
492 rectangle.x = 0;
493 rectangle.y = 0;
494 rectangle.width = dri2_surf->base.Width;
495 rectangle.height = dri2_surf->base.Height;
496 dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
497 xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
498 }
499
500 static __DRIbuffer *
501 dri2_x11_get_buffers(__DRIdrawable * driDrawable,
502 int *width, int *height,
503 unsigned int *attachments, int count,
504 int *out_count, void *loaderPrivate)
505 {
506 struct dri2_egl_surface *dri2_surf = loaderPrivate;
507 struct dri2_egl_display *dri2_dpy =
508 dri2_egl_display(dri2_surf->base.Resource.Display);
509 xcb_dri2_dri2_buffer_t *buffers;
510 xcb_dri2_get_buffers_reply_t *reply;
511 xcb_dri2_get_buffers_cookie_t cookie;
512
513 (void) driDrawable;
514
515 cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
516 dri2_surf->drawable,
517 count, count, attachments);
518 reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
519 if (reply == NULL)
520 return NULL;
521 buffers = xcb_dri2_get_buffers_buffers (reply);
522 if (buffers == NULL)
523 return NULL;
524
525 *out_count = reply->count;
526 dri2_surf->base.Width = *width = reply->width;
527 dri2_surf->base.Height = *height = reply->height;
528 dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
529
530 free(reply);
531
532 return dri2_surf->buffers;
533 }
534
535 static __DRIbuffer *
536 dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,
537 int *width, int *height,
538 unsigned int *attachments, int count,
539 int *out_count, void *loaderPrivate)
540 {
541 struct dri2_egl_surface *dri2_surf = loaderPrivate;
542 struct dri2_egl_display *dri2_dpy =
543 dri2_egl_display(dri2_surf->base.Resource.Display);
544 xcb_dri2_dri2_buffer_t *buffers;
545 xcb_dri2_get_buffers_with_format_reply_t *reply;
546 xcb_dri2_get_buffers_with_format_cookie_t cookie;
547 xcb_dri2_attach_format_t *format_attachments;
548
549 (void) driDrawable;
550
551 format_attachments = (xcb_dri2_attach_format_t *) attachments;
552 cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
553 dri2_surf->drawable,
554 count, count,
555 format_attachments);
556
557 reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
558 cookie, NULL);
559 if (reply == NULL)
560 return NULL;
561
562 buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
563 dri2_surf->base.Width = *width = reply->width;
564 dri2_surf->base.Height = *height = reply->height;
565 *out_count = reply->count;
566 dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
567
568 free(reply);
569
570 return dri2_surf->buffers;
571 }
572
573 static void
574 dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
575 {
576 (void) driDrawable;
577
578 /* FIXME: Does EGL support front buffer rendering at all? */
579
580 #if 0
581 struct dri2_egl_surface *dri2_surf = loaderPrivate;
582
583 dri2WaitGL(dri2_surf);
584 #else
585 (void) loaderPrivate;
586 #endif
587 }
588
589 static int
590 dri2_x11_do_authenticate(struct dri2_egl_display *dri2_dpy, uint32_t id)
591 {
592 xcb_dri2_authenticate_reply_t *authenticate;
593 xcb_dri2_authenticate_cookie_t authenticate_cookie;
594 int ret = 0;
595
596 authenticate_cookie =
597 xcb_dri2_authenticate_unchecked(dri2_dpy->conn, dri2_dpy->screen->root, id);
598 authenticate =
599 xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
600
601 if (authenticate == NULL || !authenticate->authenticated)
602 ret = -1;
603
604 free(authenticate);
605
606 return ret;
607 }
608
609 static EGLBoolean
610 dri2_x11_local_authenticate(struct dri2_egl_display *dri2_dpy)
611 {
612 #ifdef HAVE_LIBDRM
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_do_authenticate(dri2_dpy, 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_connect(struct dri2_egl_display *dri2_dpy)
630 {
631 xcb_xfixes_query_version_reply_t *xfixes_query;
632 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
633 xcb_dri2_query_version_reply_t *dri2_query;
634 xcb_dri2_query_version_cookie_t dri2_query_cookie;
635 xcb_dri2_connect_reply_t *connect;
636 xcb_dri2_connect_cookie_t connect_cookie;
637 xcb_generic_error_t *error;
638 char *driver_name, *loader_driver_name, *device_name;
639 const xcb_query_extension_reply_t *extension;
640
641 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
642 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
643
644 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
645 if (!(extension && extension->present))
646 return EGL_FALSE;
647
648 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);
649 if (!(extension && extension->present))
650 return EGL_FALSE;
651
652 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
653 XCB_XFIXES_MAJOR_VERSION,
654 XCB_XFIXES_MINOR_VERSION);
655
656 dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
657 XCB_DRI2_MAJOR_VERSION,
658 XCB_DRI2_MINOR_VERSION);
659
660 connect_cookie = xcb_dri2_connect_unchecked(dri2_dpy->conn, dri2_dpy->screen->root,
661 XCB_DRI2_DRIVER_TYPE_DRI);
662
663 xfixes_query =
664 xcb_xfixes_query_version_reply (dri2_dpy->conn,
665 xfixes_query_cookie, &error);
666 if (xfixes_query == NULL ||
667 error != NULL || xfixes_query->major_version < 2) {
668 _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
669 free(error);
670 free(xfixes_query);
671 return EGL_FALSE;
672 }
673 free(xfixes_query);
674
675 dri2_query =
676 xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
677 if (dri2_query == NULL || error != NULL) {
678 _eglLog(_EGL_WARNING, "DRI2: failed to query version");
679 free(error);
680 return EGL_FALSE;
681 }
682 dri2_dpy->dri2_major = dri2_query->major_version;
683 dri2_dpy->dri2_minor = dri2_query->minor_version;
684 free(dri2_query);
685
686 connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
687 if (connect == NULL ||
688 connect->driver_name_length + connect->device_name_length == 0) {
689 _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
690 return EGL_FALSE;
691 }
692
693 device_name = xcb_dri2_connect_device_name (connect);
694
695 dri2_dpy->fd = loader_open_device(device_name);
696 if (dri2_dpy->fd == -1) {
697 _eglLog(_EGL_WARNING,
698 "DRI2: could not open %s (%s)", device_name, strerror(errno));
699 free(connect);
700 return EGL_FALSE;
701 }
702
703 if (!dri2_x11_local_authenticate(dri2_dpy)) {
704 close(dri2_dpy->fd);
705 free(connect);
706 return EGL_FALSE;
707 }
708
709 driver_name = xcb_dri2_connect_driver_name (connect);
710
711 /* If Mesa knows about the appropriate driver for this fd, then trust it.
712 * Otherwise, default to the server's value.
713 */
714 loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
715 if (loader_driver_name) {
716 dri2_dpy->driver_name = loader_driver_name;
717 } else {
718 dri2_dpy->driver_name =
719 strndup(driver_name,
720 xcb_dri2_connect_driver_name_length(connect));
721 }
722
723 if (dri2_dpy->driver_name == NULL) {
724 close(dri2_dpy->fd);
725 free(connect);
726 return EGL_FALSE;
727 }
728
729 #ifdef HAVE_WAYLAND_PLATFORM
730 dri2_dpy->device_name =
731 strndup(device_name,
732 xcb_dri2_connect_device_name_length(connect));
733 #endif
734
735 free(connect);
736
737 return EGL_TRUE;
738 }
739
740 static int
741 dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)
742 {
743 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
744
745 return dri2_x11_do_authenticate(dri2_dpy, id);
746 }
747
748 static EGLBoolean
749 dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
750 _EGLDisplay *disp, bool supports_preserved)
751 {
752 xcb_depth_iterator_t d;
753 xcb_visualtype_t *visuals;
754 int config_count = 0;
755 EGLint surface_type;
756
757 d = xcb_screen_allowed_depths_iterator(dri2_dpy->screen);
758
759 surface_type =
760 EGL_WINDOW_BIT |
761 EGL_PIXMAP_BIT |
762 EGL_PBUFFER_BIT;
763
764 if (supports_preserved)
765 surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
766
767 while (d.rem > 0) {
768 EGLBoolean class_added[6] = { 0, };
769
770 visuals = xcb_depth_visuals(d.data);
771
772 for (int i = 0; i < xcb_depth_visuals_length(d.data); i++) {
773 if (class_added[visuals[i]._class])
774 continue;
775
776 class_added[visuals[i]._class] = EGL_TRUE;
777
778 for (int j = 0; dri2_dpy->driver_configs[j]; j++) {
779 struct dri2_egl_config *dri2_conf;
780 const __DRIconfig *config = dri2_dpy->driver_configs[j];
781
782 const EGLint config_attrs[] = {
783 EGL_NATIVE_VISUAL_ID, visuals[i].visual_id,
784 EGL_NATIVE_VISUAL_TYPE, visuals[i]._class,
785 EGL_NONE
786 };
787
788 int rgba_shifts[4] = {
789 ffs(visuals[i].red_mask) - 1,
790 ffs(visuals[i].green_mask) - 1,
791 ffs(visuals[i].blue_mask) - 1,
792 -1,
793 };
794
795 unsigned int rgba_sizes[4] = {
796 util_bitcount(visuals[i].red_mask),
797 util_bitcount(visuals[i].green_mask),
798 util_bitcount(visuals[i].blue_mask),
799 0,
800 };
801
802 dri2_conf = dri2_add_config(disp, config, config_count + 1,
803 surface_type, config_attrs,
804 rgba_shifts, rgba_sizes);
805 if (dri2_conf)
806 if (dri2_conf->base.ConfigID == config_count + 1)
807 config_count++;
808
809 /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig.
810 * Ditto for 30-bit RGB visuals to match a 32-bit RGBA EGLConfig.
811 * Otherwise it will only match a 32-bit RGBA visual. On a
812 * composited window manager on X11, this will make all of the
813 * EGLConfigs with destination alpha get blended by the
814 * compositor. This is probably not what the application
815 * wants... especially on drivers that only have 32-bit RGBA
816 * EGLConfigs! */
817 if (d.data->depth == 24 || d.data->depth == 30) {
818 unsigned int rgba_mask = ~(visuals[i].red_mask |
819 visuals[i].green_mask |
820 visuals[i].blue_mask);
821 rgba_shifts[3] = ffs(rgba_mask) - 1;
822 rgba_sizes[3] = util_bitcount(rgba_mask);
823 dri2_conf = dri2_add_config(disp, config, config_count + 1,
824 surface_type, config_attrs,
825 rgba_shifts, rgba_sizes);
826 if (dri2_conf)
827 if (dri2_conf->base.ConfigID == config_count + 1)
828 config_count++;
829 }
830 }
831 }
832
833 xcb_depth_next(&d);
834 }
835
836 if (!config_count) {
837 _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
838 return EGL_FALSE;
839 }
840
841 return EGL_TRUE;
842 }
843
844 static EGLBoolean
845 dri2_copy_region(_EGLDisplay *disp,
846 _EGLSurface *draw, xcb_xfixes_region_t region)
847 {
848 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
849 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
850 enum xcb_dri2_attachment_t render_attachment;
851 xcb_dri2_copy_region_cookie_t cookie;
852
853 /* No-op for a pixmap or pbuffer surface */
854 if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
855 return EGL_TRUE;
856
857 dri2_dpy->flush->flush(dri2_surf->dri_drawable);
858
859 if (dri2_surf->have_fake_front)
860 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
861 else
862 render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
863
864 cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
865 dri2_surf->drawable,
866 region,
867 XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
868 render_attachment);
869 free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
870
871 return EGL_TRUE;
872 }
873
874 static int64_t
875 dri2_x11_swap_buffers_msc(_EGLDisplay *disp, _EGLSurface *draw,
876 int64_t msc, int64_t divisor, int64_t remainder)
877 {
878 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
879 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
880 uint32_t msc_hi = msc >> 32;
881 uint32_t msc_lo = msc & 0xffffffff;
882 uint32_t divisor_hi = divisor >> 32;
883 uint32_t divisor_lo = divisor & 0xffffffff;
884 uint32_t remainder_hi = remainder >> 32;
885 uint32_t remainder_lo = remainder & 0xffffffff;
886 xcb_dri2_swap_buffers_cookie_t cookie;
887 xcb_dri2_swap_buffers_reply_t *reply;
888 int64_t swap_count = -1;
889
890 if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available) {
891 swap_count = dri2_copy_region(disp, draw, dri2_surf->region) ? 0 : -1;
892 } else {
893 dri2_flush_drawable_for_swapbuffers(disp, draw);
894
895 cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn,
896 dri2_surf->drawable, msc_hi,
897 msc_lo, divisor_hi, divisor_lo,
898 remainder_hi, remainder_lo);
899
900 reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);
901
902 if (reply) {
903 swap_count = combine_u32_into_u64(reply->swap_hi, reply->swap_lo);
904 free(reply);
905 }
906 }
907
908 /* Since we aren't watching for the server's invalidate events like we're
909 * supposed to (due to XCB providing no mechanism for filtering the events
910 * the way xlib does), and SwapBuffers is a common cause of invalidate
911 * events, just shove one down to the driver, even though we haven't told
912 * the driver that we're the kind of loader that provides reliable
913 * invalidate events. This causes the driver to request buffers again at
914 * its next draw, so that we get the correct buffers if a pageflip
915 * happened. The driver should still be using the viewport hack to catch
916 * window resizes.
917 */
918 if (dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
919 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
920
921 return swap_count;
922 }
923
924 static EGLBoolean
925 dri2_x11_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
926 {
927 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
928 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
929
930 if (!dri2_dpy->flush) {
931 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
932 return EGL_TRUE;
933 }
934
935 if (dri2_x11_swap_buffers_msc(disp, draw, 0, 0, 0) == -1) {
936 /* Swap failed with a window drawable. */
937 return _eglError(EGL_BAD_NATIVE_WINDOW, __func__);
938 }
939 return EGL_TRUE;
940 }
941
942 static EGLBoolean
943 dri2_x11_swap_buffers_region(_EGLDisplay *disp, _EGLSurface *draw,
944 EGLint numRects, const EGLint *rects)
945 {
946 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
947 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
948 EGLBoolean ret;
949 xcb_xfixes_region_t region;
950 xcb_rectangle_t rectangles[16];
951
952 if (numRects > (int)ARRAY_SIZE(rectangles))
953 return dri2_copy_region(disp, draw, dri2_surf->region);
954
955 for (int i = 0; i < numRects; i++) {
956 rectangles[i].x = rects[i * 4];
957 rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];
958 rectangles[i].width = rects[i * 4 + 2];
959 rectangles[i].height = rects[i * 4 + 3];
960 }
961
962 region = xcb_generate_id(dri2_dpy->conn);
963 xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
964 ret = dri2_copy_region(disp, draw, region);
965 xcb_xfixes_destroy_region(dri2_dpy->conn, region);
966
967 return ret;
968 }
969
970 static EGLBoolean
971 dri2_x11_post_sub_buffer(_EGLDisplay *disp, _EGLSurface *draw,
972 EGLint x, EGLint y, EGLint width, EGLint height)
973 {
974 const EGLint rect[4] = { x, y, width, height };
975
976 if (x < 0 || y < 0 || width < 0 || height < 0)
977 _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
978
979 return dri2_x11_swap_buffers_region(disp, draw, 1, rect);
980 }
981
982 static EGLBoolean
983 dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
984 {
985 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
986 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
987
988 if (dri2_dpy->swap_available)
989 xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);
990
991 return EGL_TRUE;
992 }
993
994 static EGLBoolean
995 dri2_x11_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
996 {
997 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
998 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
999 xcb_gcontext_t gc;
1000 xcb_pixmap_t target;
1001
1002 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
1003 target = (uintptr_t) native_pixmap_target;
1004
1005 dri2_dpy->flush->flush(dri2_surf->dri_drawable);
1006
1007 gc = xcb_generate_id(dri2_dpy->conn);
1008 xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
1009 xcb_copy_area(dri2_dpy->conn,
1010 dri2_surf->drawable,
1011 target,
1012 gc,
1013 0, 0,
1014 0, 0,
1015 dri2_surf->base.Width,
1016 dri2_surf->base.Height);
1017 xcb_free_gc(dri2_dpy->conn, gc);
1018
1019 return EGL_TRUE;
1020 }
1021
1022 uint32_t
1023 dri2_format_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth)
1024 {
1025 switch (depth) {
1026 case 16:
1027 return __DRI_IMAGE_FORMAT_RGB565;
1028 case 24:
1029 return __DRI_IMAGE_FORMAT_XRGB8888;
1030 case 30:
1031 /* Different preferred formats for different hw */
1032 if (dri2_x11_get_red_mask_for_depth(dri2_dpy, 30) == 0x3ff)
1033 return __DRI_IMAGE_FORMAT_XBGR2101010;
1034 else
1035 return __DRI_IMAGE_FORMAT_XRGB2101010;
1036 case 32:
1037 return __DRI_IMAGE_FORMAT_ARGB8888;
1038 default:
1039 return __DRI_IMAGE_FORMAT_NONE;
1040 }
1041 }
1042
1043 static _EGLImage *
1044 dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
1045 EGLClientBuffer buffer, const EGLint *attr_list)
1046 {
1047 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1048 struct dri2_egl_image *dri2_img;
1049 unsigned int attachments[1];
1050 xcb_drawable_t drawable;
1051 xcb_dri2_get_buffers_cookie_t buffers_cookie;
1052 xcb_dri2_get_buffers_reply_t *buffers_reply;
1053 xcb_dri2_dri2_buffer_t *buffers;
1054 xcb_get_geometry_cookie_t geometry_cookie;
1055 xcb_get_geometry_reply_t *geometry_reply;
1056 xcb_generic_error_t *error;
1057 int stride, format;
1058
1059 (void) ctx;
1060
1061 drawable = (xcb_drawable_t) (uintptr_t) buffer;
1062 xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
1063 attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
1064 buffers_cookie =
1065 xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
1066 drawable, 1, 1, attachments);
1067 geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
1068 buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
1069 buffers_cookie, NULL);
1070 if (buffers_reply == NULL)
1071 return NULL;
1072
1073 buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
1074 if (buffers == NULL) {
1075 return NULL;
1076 }
1077
1078 geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
1079 geometry_cookie, &error);
1080 if (geometry_reply == NULL || error != NULL) {
1081 _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
1082 free(error);
1083 free(buffers_reply);
1084 return NULL;
1085 }
1086
1087 format = dri2_format_for_depth(dri2_dpy, geometry_reply->depth);
1088 if (format == __DRI_IMAGE_FORMAT_NONE) {
1089 _eglError(EGL_BAD_PARAMETER,
1090 "dri2_create_image_khr: unsupported pixmap depth");
1091 free(buffers_reply);
1092 free(geometry_reply);
1093 return NULL;
1094 }
1095
1096 dri2_img = malloc(sizeof *dri2_img);
1097 if (!dri2_img) {
1098 free(buffers_reply);
1099 free(geometry_reply);
1100 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1101 return EGL_NO_IMAGE_KHR;
1102 }
1103
1104 _eglInitImage(&dri2_img->base, disp);
1105
1106 stride = buffers[0].pitch / buffers[0].cpp;
1107 dri2_img->dri_image =
1108 dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1109 buffers_reply->width,
1110 buffers_reply->height,
1111 format,
1112 buffers[0].name,
1113 stride,
1114 dri2_img);
1115
1116 free(buffers_reply);
1117 free(geometry_reply);
1118
1119 return &dri2_img->base;
1120 }
1121
1122 static _EGLImage *
1123 dri2_x11_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
1124 EGLClientBuffer buffer, const EGLint *attr_list)
1125 {
1126 switch (target) {
1127 case EGL_NATIVE_PIXMAP_KHR:
1128 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
1129 default:
1130 return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
1131 }
1132 }
1133
1134 static EGLBoolean
1135 dri2_x11_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
1136 EGLuint64KHR *ust, EGLuint64KHR *msc,
1137 EGLuint64KHR *sbc)
1138 {
1139 struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);
1140 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
1141 xcb_dri2_get_msc_cookie_t cookie;
1142 xcb_dri2_get_msc_reply_t *reply;
1143
1144 cookie = xcb_dri2_get_msc(dri2_dpy->conn, dri2_surf->drawable);
1145 reply = xcb_dri2_get_msc_reply(dri2_dpy->conn, cookie, NULL);
1146
1147 if (!reply)
1148 return _eglError(EGL_BAD_ACCESS, __func__);
1149
1150 *ust = ((EGLuint64KHR) reply->ust_hi << 32) | reply->ust_lo;
1151 *msc = ((EGLuint64KHR) reply->msc_hi << 32) | reply->msc_lo;
1152 *sbc = ((EGLuint64KHR) reply->sbc_hi << 32) | reply->sbc_lo;
1153 free(reply);
1154
1155 return EGL_TRUE;
1156 }
1157
1158 static const struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {
1159 .authenticate = NULL,
1160 .create_window_surface = dri2_x11_create_window_surface,
1161 .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1162 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1163 .destroy_surface = dri2_x11_destroy_surface,
1164 .create_image = dri2_create_image_khr,
1165 .swap_buffers = dri2_x11_swap_buffers,
1166 /* XXX: should really implement this since X11 has pixmaps */
1167 .query_surface = dri2_query_surface,
1168 .get_dri_drawable = dri2_surface_get_dri_drawable,
1169 };
1170
1171 static const struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {
1172 .authenticate = dri2_x11_authenticate,
1173 .create_window_surface = dri2_x11_create_window_surface,
1174 .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1175 .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1176 .destroy_surface = dri2_x11_destroy_surface,
1177 .create_image = dri2_x11_create_image_khr,
1178 .swap_interval = dri2_x11_swap_interval,
1179 .swap_buffers = dri2_x11_swap_buffers,
1180 .swap_buffers_region = dri2_x11_swap_buffers_region,
1181 .post_sub_buffer = dri2_x11_post_sub_buffer,
1182 .copy_buffers = dri2_x11_copy_buffers,
1183 .query_surface = dri2_query_surface,
1184 .get_sync_values = dri2_x11_get_sync_values,
1185 .get_dri_drawable = dri2_surface_get_dri_drawable,
1186 };
1187
1188 static const __DRIswrastLoaderExtension swrast_loader_extension = {
1189 .base = { __DRI_SWRAST_LOADER, 1 },
1190
1191 .getDrawableInfo = swrastGetDrawableInfo,
1192 .putImage = swrastPutImage,
1193 .getImage = swrastGetImage,
1194 };
1195
1196 static const __DRIextension *swrast_loader_extensions[] = {
1197 &swrast_loader_extension.base,
1198 &image_lookup_extension.base,
1199 NULL,
1200 };
1201
1202 static int
1203 dri2_find_screen_for_display(const _EGLDisplay *disp, int fallback_screen)
1204 {
1205 const EGLAttrib *attr;
1206
1207 for (attr = disp->Options.Attribs; attr; attr += 2) {
1208 if (attr[0] == EGL_PLATFORM_X11_SCREEN_EXT)
1209 return attr[1];
1210 }
1211
1212 return fallback_screen;
1213 }
1214
1215 static EGLBoolean
1216 dri2_get_xcb_connection(_EGLDisplay *disp,
1217 struct dri2_egl_display *dri2_dpy)
1218 {
1219 xcb_screen_iterator_t s;
1220 int screen;
1221 const char *msg;
1222
1223 disp->DriverData = (void *) dri2_dpy;
1224 if (disp->PlatformDisplay == NULL) {
1225 dri2_dpy->conn = xcb_connect(NULL, &screen);
1226 dri2_dpy->own_device = true;
1227 screen = dri2_find_screen_for_display(disp, screen);
1228 } else {
1229 Display *dpy = disp->PlatformDisplay;
1230 dri2_dpy->conn = XGetXCBConnection(dpy);
1231 screen = DefaultScreen(dpy);
1232 }
1233
1234 if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) {
1235 msg = "xcb_connect failed";
1236 goto disconnect;
1237 }
1238
1239 s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
1240 dri2_dpy->screen = get_xcb_screen(s, screen);
1241 if (!dri2_dpy->screen) {
1242 msg = "failed to get xcb screen";
1243 goto disconnect;
1244 }
1245
1246 return EGL_TRUE;
1247 disconnect:
1248 if (disp->PlatformDisplay == NULL)
1249 xcb_disconnect(dri2_dpy->conn);
1250
1251 return _eglError(EGL_BAD_ALLOC, msg);
1252 }
1253
1254 static EGLBoolean
1255 dri2_initialize_x11_swrast(_EGLDisplay *disp)
1256 {
1257 _EGLDevice *dev;
1258 struct dri2_egl_display *dri2_dpy;
1259
1260 dri2_dpy = calloc(1, sizeof *dri2_dpy);
1261 if (!dri2_dpy)
1262 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1263
1264 dri2_dpy->fd = -1;
1265 if (!dri2_get_xcb_connection(disp, dri2_dpy))
1266 goto cleanup;
1267
1268 dev = _eglAddDevice(dri2_dpy->fd, true);
1269 if (!dev) {
1270 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
1271 goto cleanup;
1272 }
1273
1274 disp->Device = dev;
1275
1276 /*
1277 * Every hardware driver_name is set using strdup. Doing the same in
1278 * here will allow is to simply free the memory at dri2_terminate().
1279 */
1280 dri2_dpy->driver_name = strdup("swrast");
1281 if (!dri2_load_driver_swrast(disp))
1282 goto cleanup;
1283
1284 dri2_dpy->loader_extensions = swrast_loader_extensions;
1285
1286 if (!dri2_create_screen(disp))
1287 goto cleanup;
1288
1289 if (!dri2_setup_extensions(disp))
1290 goto cleanup;
1291
1292 dri2_setup_screen(disp);
1293
1294 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))
1295 goto cleanup;
1296
1297 /* Fill vtbl last to prevent accidentally calling virtual function during
1298 * initialization.
1299 */
1300 dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl;
1301
1302 return EGL_TRUE;
1303
1304 cleanup:
1305 dri2_display_destroy(disp);
1306 return EGL_FALSE;
1307 }
1308
1309 static void
1310 dri2_x11_setup_swap_interval(_EGLDisplay *disp)
1311 {
1312 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1313 int arbitrary_max_interval = 1000;
1314
1315 /* default behavior for no SwapBuffers support: no vblank syncing
1316 * either.
1317 */
1318 dri2_dpy->min_swap_interval = 0;
1319 dri2_dpy->max_swap_interval = 0;
1320 dri2_dpy->default_swap_interval = 0;
1321
1322 if (!dri2_dpy->swap_available)
1323 return;
1324
1325 /* If we do have swapbuffers, then we can support pretty much any swap
1326 * interval.
1327 */
1328 dri2_setup_swap_interval(disp, arbitrary_max_interval);
1329 }
1330
1331 #ifdef HAVE_DRI3
1332
1333 static const __DRIextension *dri3_image_loader_extensions[] = {
1334 &dri3_image_loader_extension.base,
1335 &image_lookup_extension.base,
1336 &use_invalidate.base,
1337 &background_callable_extension.base,
1338 NULL,
1339 };
1340
1341 static EGLBoolean
1342 dri2_initialize_x11_dri3(_EGLDisplay *disp)
1343 {
1344 _EGLDevice *dev;
1345 struct dri2_egl_display *dri2_dpy;
1346
1347 dri2_dpy = calloc(1, sizeof *dri2_dpy);
1348 if (!dri2_dpy)
1349 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1350
1351 dri2_dpy->fd = -1;
1352 if (!dri2_get_xcb_connection(disp, dri2_dpy))
1353 goto cleanup;
1354
1355 if (!dri3_x11_connect(dri2_dpy))
1356 goto cleanup;
1357
1358 dev = _eglAddDevice(dri2_dpy->fd, false);
1359 if (!dev) {
1360 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
1361 goto cleanup;
1362 }
1363
1364 disp->Device = dev;
1365
1366 if (!dri2_load_driver_dri3(disp))
1367 goto cleanup;
1368
1369 dri2_dpy->loader_extensions = dri3_image_loader_extensions;
1370
1371 dri2_dpy->swap_available = true;
1372 dri2_dpy->invalidate_available = true;
1373
1374 if (!dri2_create_screen(disp))
1375 goto cleanup;
1376
1377 if (!dri2_setup_extensions(disp))
1378 goto cleanup;
1379
1380 dri2_setup_screen(disp);
1381
1382 dri2_x11_setup_swap_interval(disp);
1383
1384 if (!dri2_dpy->is_different_gpu)
1385 disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1386 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1387 disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1388 disp->Extensions.EXT_buffer_age = EGL_TRUE;
1389 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1390
1391 dri2_set_WL_bind_wayland_display(disp);
1392
1393 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false))
1394 goto cleanup;
1395
1396 dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;
1397 dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;
1398 dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;
1399 dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer;
1400 dri2_dpy->loader_dri3_ext.image = dri2_dpy->image;
1401 dri2_dpy->loader_dri3_ext.config = dri2_dpy->config;
1402
1403 /* Fill vtbl last to prevent accidentally calling virtual function during
1404 * initialization.
1405 */
1406 dri2_dpy->vtbl = &dri3_x11_display_vtbl;
1407
1408 _eglLog(_EGL_INFO, "Using DRI3");
1409
1410 return EGL_TRUE;
1411
1412 cleanup:
1413 dri2_display_destroy(disp);
1414 return EGL_FALSE;
1415 }
1416 #endif
1417
1418 static const __DRIdri2LoaderExtension dri2_loader_extension_old = {
1419 .base = { __DRI_DRI2_LOADER, 2 },
1420
1421 .getBuffers = dri2_x11_get_buffers,
1422 .flushFrontBuffer = dri2_x11_flush_front_buffer,
1423 .getBuffersWithFormat = NULL,
1424 };
1425
1426 static const __DRIdri2LoaderExtension dri2_loader_extension = {
1427 .base = { __DRI_DRI2_LOADER, 3 },
1428
1429 .getBuffers = dri2_x11_get_buffers,
1430 .flushFrontBuffer = dri2_x11_flush_front_buffer,
1431 .getBuffersWithFormat = dri2_x11_get_buffers_with_format,
1432 };
1433
1434 static const __DRIextension *dri2_loader_extensions_old[] = {
1435 &dri2_loader_extension_old.base,
1436 &image_lookup_extension.base,
1437 &background_callable_extension.base,
1438 NULL,
1439 };
1440
1441 static const __DRIextension *dri2_loader_extensions[] = {
1442 &dri2_loader_extension.base,
1443 &image_lookup_extension.base,
1444 &use_invalidate.base,
1445 &background_callable_extension.base,
1446 NULL,
1447 };
1448
1449 static EGLBoolean
1450 dri2_initialize_x11_dri2(_EGLDisplay *disp)
1451 {
1452 _EGLDevice *dev;
1453 struct dri2_egl_display *dri2_dpy;
1454
1455 dri2_dpy = calloc(1, sizeof *dri2_dpy);
1456 if (!dri2_dpy)
1457 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1458
1459 dri2_dpy->fd = -1;
1460 if (!dri2_get_xcb_connection(disp, dri2_dpy))
1461 goto cleanup;
1462
1463 if (!dri2_x11_connect(dri2_dpy))
1464 goto cleanup;
1465
1466 dev = _eglAddDevice(dri2_dpy->fd, false);
1467 if (!dev) {
1468 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
1469 goto cleanup;
1470 }
1471
1472 disp->Device = dev;
1473
1474 if (!dri2_load_driver(disp))
1475 goto cleanup;
1476
1477 if (dri2_dpy->dri2_minor >= 1)
1478 dri2_dpy->loader_extensions = dri2_loader_extensions;
1479 else
1480 dri2_dpy->loader_extensions = dri2_loader_extensions_old;
1481
1482 dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
1483 dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
1484
1485 if (!dri2_create_screen(disp))
1486 goto cleanup;
1487
1488 if (!dri2_setup_extensions(disp))
1489 goto cleanup;
1490
1491 dri2_setup_screen(disp);
1492
1493 dri2_x11_setup_swap_interval(disp);
1494
1495 disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1496 disp->Extensions.NOK_swap_region = EGL_TRUE;
1497 disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1498 disp->Extensions.NV_post_sub_buffer = EGL_TRUE;
1499 disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1500
1501 dri2_set_WL_bind_wayland_display(disp);
1502
1503 if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))
1504 goto cleanup;
1505
1506 /* Fill vtbl last to prevent accidentally calling virtual function during
1507 * initialization.
1508 */
1509 dri2_dpy->vtbl = &dri2_x11_display_vtbl;
1510
1511 _eglLog(_EGL_INFO, "Using DRI2");
1512
1513 return EGL_TRUE;
1514
1515 cleanup:
1516 dri2_display_destroy(disp);
1517 return EGL_FALSE;
1518 }
1519
1520 EGLBoolean
1521 dri2_initialize_x11(_EGLDisplay *disp)
1522 {
1523 EGLBoolean initialized = EGL_FALSE;
1524
1525 if (!disp->Options.ForceSoftware) {
1526 #ifdef HAVE_DRI3
1527 if (!env_var_as_boolean("LIBGL_DRI3_DISABLE", false))
1528 initialized = dri2_initialize_x11_dri3(disp);
1529 #endif
1530
1531 if (!initialized)
1532 initialized = dri2_initialize_x11_dri2(disp);
1533 }
1534
1535 if (!initialized)
1536 initialized = dri2_initialize_x11_swrast(disp);
1537
1538 return initialized;
1539 }
1540
1541 void
1542 dri2_teardown_x11(struct dri2_egl_display *dri2_dpy)
1543 {
1544 if (dri2_dpy->own_device)
1545 xcb_disconnect(dri2_dpy->conn);
1546 }