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