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