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