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