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