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