1 /* 2 * Copyright 2010 Intel Corporation. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including 13 * the next paragraph) shall be included in all copies or substantial 14 * portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Zhigang Gong <zhigang.gong (at) linux.intel.com> 27 * 28 */ 29 30 #include "dix-config.h" 31 32 #define GLAMOR_FOR_XORG 33 #include <unistd.h> 34 #include <fcntl.h> 35 #include <sys/ioctl.h> 36 #include <errno.h> 37 #include <xf86.h> 38 #include <xf86Priv.h> 39 #include <xf86drm.h> 40 #define EGL_DISPLAY_NO_X_MESA 41 42 #include <gbm.h> 43 #include <drm_fourcc.h> 44 45 #include "glamor_egl.h" 46 47 #include "glamor.h" 48 #include "glamor_priv.h" 49 #include "dri3.h" 50 51 struct glamor_egl_screen_private { 52 EGLDisplay display; 53 EGLContext context; 54 char *device_path; 55 56 CreateScreenResourcesProcPtr CreateScreenResources; 57 CloseScreenProcPtr CloseScreen; 58 int fd; 59 struct gbm_device *gbm; 60 int dmabuf_capable; 61 62 CloseScreenProcPtr saved_close_screen; 63 DestroyPixmapProcPtr saved_destroy_pixmap; 64 xf86FreeScreenProc *saved_free_screen; 65 }; 66 67 int xf86GlamorEGLPrivateIndex = -1; 68 69 70 static struct glamor_egl_screen_private * 71 glamor_egl_get_screen_private(ScrnInfoPtr scrn) 72 { 73 return (struct glamor_egl_screen_private *) 74 scrn->privates[xf86GlamorEGLPrivateIndex].ptr; 75 } 76 77 static void 78 glamor_egl_make_current(struct glamor_context *glamor_ctx) 79 { 80 /* There's only a single global dispatch table in Mesa. EGL, GLX, 81 * and AIGLX's direct dispatch table manipulation don't talk to 82 * each other. We need to set the context to NULL first to avoid 83 * EGL's no-op context change fast path when switching back to 84 * EGL. 85 */ 86 eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE, 87 EGL_NO_SURFACE, EGL_NO_CONTEXT); 88 89 if (!eglMakeCurrent(glamor_ctx->display, 90 EGL_NO_SURFACE, EGL_NO_SURFACE, 91 glamor_ctx->ctx)) { 92 FatalError("Failed to make EGL context current\n"); 93 } 94 } 95 96 static int 97 glamor_get_flink_name(int fd, int handle, int *name) 98 { 99 struct drm_gem_flink flink; 100 101 flink.handle = handle; 102 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 103 104 /* 105 * Assume non-GEM kernels have names identical to the handle 106 */ 107 if (errno == ENODEV) { 108 *name = handle; 109 return TRUE; 110 } else { 111 return FALSE; 112 } 113 } 114 *name = flink.name; 115 return TRUE; 116 } 117 118 static Bool 119 glamor_create_texture_from_image(ScreenPtr screen, 120 EGLImageKHR image, GLuint * texture) 121 { 122 struct glamor_screen_private *glamor_priv = 123 glamor_get_screen_private(screen); 124 125 glamor_make_current(glamor_priv); 126 127 glGenTextures(1, texture); 128 glBindTexture(GL_TEXTURE_2D, *texture); 129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 131 132 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 133 glBindTexture(GL_TEXTURE_2D, 0); 134 135 return TRUE; 136 } 137 138 struct gbm_device * 139 glamor_egl_get_gbm_device(ScreenPtr screen) 140 { 141 struct glamor_egl_screen_private *glamor_egl = 142 glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 143 return glamor_egl->gbm; 144 } 145 146 Bool 147 glamor_egl_create_textured_screen(ScreenPtr screen, int handle, int stride) 148 { 149 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 150 PixmapPtr screen_pixmap; 151 152 screen_pixmap = screen->GetScreenPixmap(screen); 153 154 if (!glamor_egl_create_textured_pixmap(screen_pixmap, handle, stride)) { 155 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 156 "Failed to create textured screen."); 157 return FALSE; 158 } 159 return TRUE; 160 } 161 162 static void 163 glamor_egl_set_pixmap_image(PixmapPtr pixmap, EGLImageKHR image, 164 Bool used_modifiers) 165 { 166 struct glamor_pixmap_private *pixmap_priv = 167 glamor_get_pixmap_private(pixmap); 168 EGLImageKHR old; 169 170 old = pixmap_priv->image; 171 if (old) { 172 ScreenPtr screen = pixmap->drawable.pScreen; 173 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 174 struct glamor_egl_screen_private *glamor_egl = glamor_egl_get_screen_private(scrn); 175 176 eglDestroyImageKHR(glamor_egl->display, old); 177 } 178 pixmap_priv->image = image; 179 pixmap_priv->used_modifiers = used_modifiers; 180 } 181 182 Bool 183 glamor_egl_create_textured_pixmap(PixmapPtr pixmap, int handle, int stride) 184 { 185 ScreenPtr screen = pixmap->drawable.pScreen; 186 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 187 struct glamor_egl_screen_private *glamor_egl = 188 glamor_egl_get_screen_private(scrn); 189 int ret, fd; 190 191 /* GBM doesn't have an import path from handles, so we make a 192 * dma-buf fd from it and then go through that. 193 */ 194 ret = drmPrimeHandleToFD(glamor_egl->fd, handle, O_CLOEXEC, &fd); 195 if (ret) { 196 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 197 "Failed to make prime FD for handle: %d\n", errno); 198 return FALSE; 199 } 200 201 if (!glamor_back_pixmap_from_fd(pixmap, fd, 202 pixmap->drawable.width, 203 pixmap->drawable.height, 204 stride, 205 pixmap->drawable.depth, 206 pixmap->drawable.bitsPerPixel)) { 207 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 208 "Failed to make import prime FD as pixmap: %d\n", errno); 209 close(fd); 210 return FALSE; 211 } 212 213 close(fd); 214 return TRUE; 215 } 216 217 Bool 218 glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap, 219 struct gbm_bo *bo, 220 Bool used_modifiers) 221 { 222 ScreenPtr screen = pixmap->drawable.pScreen; 223 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 224 struct glamor_screen_private *glamor_priv = 225 glamor_get_screen_private(screen); 226 struct glamor_egl_screen_private *glamor_egl; 227 EGLImageKHR image; 228 GLuint texture; 229 Bool ret = FALSE; 230 231 glamor_egl = glamor_egl_get_screen_private(scrn); 232 233 glamor_make_current(glamor_priv); 234 235 image = eglCreateImageKHR(glamor_egl->display, 236 EGL_NO_CONTEXT, 237 EGL_NATIVE_PIXMAP_KHR, bo, NULL); 238 if (image == EGL_NO_IMAGE_KHR) { 239 glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY); 240 goto done; 241 } 242 glamor_create_texture_from_image(screen, image, &texture); 243 glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); 244 glamor_set_pixmap_texture(pixmap, texture); 245 glamor_egl_set_pixmap_image(pixmap, image, used_modifiers); 246 ret = TRUE; 247 248 done: 249 return ret; 250 } 251 252 static void 253 glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name) 254 { 255 union gbm_bo_handle handle; 256 257 handle = gbm_bo_get_handle(bo); 258 if (!glamor_get_flink_name(gbm_fd, handle.u32, name)) 259 *name = -1; 260 } 261 262 static Bool 263 glamor_make_pixmap_exportable(PixmapPtr pixmap, Bool modifiers_ok) 264 { 265 ScreenPtr screen = pixmap->drawable.pScreen; 266 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 267 struct glamor_egl_screen_private *glamor_egl = 268 glamor_egl_get_screen_private(scrn); 269 struct glamor_pixmap_private *pixmap_priv = 270 glamor_get_pixmap_private(pixmap); 271 unsigned width = pixmap->drawable.width; 272 unsigned height = pixmap->drawable.height; 273 uint32_t format; 274 struct gbm_bo *bo = NULL; 275 Bool used_modifiers = FALSE; 276 PixmapPtr exported; 277 GCPtr scratch_gc; 278 279 if (pixmap_priv->image && 280 (modifiers_ok || !pixmap_priv->used_modifiers)) 281 return TRUE; 282 283 switch (pixmap->drawable.depth) { 284 case 30: 285 format = GBM_FORMAT_ARGB2101010; 286 break; 287 case 32: 288 case 24: 289 format = GBM_FORMAT_ARGB8888; 290 break; 291 case 16: 292 format = GBM_FORMAT_RGB565; 293 break; 294 case 15: 295 format = GBM_FORMAT_ARGB1555; 296 break; 297 case 8: 298 format = GBM_FORMAT_R8; 299 break; 300 default: 301 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 302 "Failed to make %d depth, %dbpp pixmap exportable\n", 303 pixmap->drawable.depth, pixmap->drawable.bitsPerPixel); 304 return FALSE; 305 } 306 307 #ifdef GBM_BO_WITH_MODIFIERS 308 if (modifiers_ok && glamor_egl->dmabuf_capable) { 309 uint32_t num_modifiers; 310 uint64_t *modifiers = NULL; 311 312 glamor_get_modifiers(screen, format, &num_modifiers, &modifiers); 313 314 bo = gbm_bo_create_with_modifiers(glamor_egl->gbm, width, height, 315 format, modifiers, num_modifiers); 316 if (bo) 317 used_modifiers = TRUE; 318 free(modifiers); 319 } 320 #endif 321 322 if (!bo) 323 { 324 bo = gbm_bo_create(glamor_egl->gbm, width, height, format, 325 #ifdef GLAMOR_HAS_GBM_LINEAR 326 (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ? 327 GBM_BO_USE_LINEAR : 0) | 328 #endif 329 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); 330 } 331 332 if (!bo) { 333 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 334 "Failed to make %dx%dx%dbpp GBM bo\n", 335 width, height, pixmap->drawable.bitsPerPixel); 336 return FALSE; 337 } 338 339 exported = screen->CreatePixmap(screen, 0, 0, pixmap->drawable.depth, 0); 340 screen->ModifyPixmapHeader(exported, width, height, 0, 0, 341 gbm_bo_get_stride(bo), NULL); 342 if (!glamor_egl_create_textured_pixmap_from_gbm_bo(exported, bo, 343 used_modifiers)) { 344 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 345 "Failed to make %dx%dx%dbpp pixmap from GBM bo\n", 346 width, height, pixmap->drawable.bitsPerPixel); 347 screen->DestroyPixmap(exported); 348 gbm_bo_destroy(bo); 349 return FALSE; 350 } 351 gbm_bo_destroy(bo); 352 353 scratch_gc = GetScratchGC(pixmap->drawable.depth, screen); 354 ValidateGC(&pixmap->drawable, scratch_gc); 355 scratch_gc->ops->CopyArea(&pixmap->drawable, &exported->drawable, 356 scratch_gc, 357 0, 0, width, height, 0, 0); 358 FreeScratchGC(scratch_gc); 359 360 /* Now, swap the tex/gbm/EGLImage/etc. of the exported pixmap into 361 * the original pixmap struct. 362 */ 363 glamor_egl_exchange_buffers(pixmap, exported); 364 365 /* Swap the devKind into the original pixmap, reflecting the bo's stride */ 366 screen->ModifyPixmapHeader(pixmap, 0, 0, 0, 0, exported->devKind, NULL); 367 368 screen->DestroyPixmap(exported); 369 370 return TRUE; 371 } 372 373 static struct gbm_bo * 374 glamor_gbm_bo_from_pixmap_internal(ScreenPtr screen, PixmapPtr pixmap) 375 { 376 struct glamor_egl_screen_private *glamor_egl = 377 glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 378 struct glamor_pixmap_private *pixmap_priv = 379 glamor_get_pixmap_private(pixmap); 380 381 if (!pixmap_priv->image) 382 return NULL; 383 384 return gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, 385 pixmap_priv->image, 0); 386 } 387 388 struct gbm_bo * 389 glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) 390 { 391 if (!glamor_make_pixmap_exportable(pixmap, TRUE)) 392 return NULL; 393 394 return glamor_gbm_bo_from_pixmap_internal(screen, pixmap); 395 } 396 397 int 398 glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, 399 uint32_t *strides, uint32_t *offsets, 400 uint64_t *modifier) 401 { 402 #ifdef GLAMOR_HAS_GBM 403 struct gbm_bo *bo; 404 int num_fds; 405 #ifdef GBM_BO_WITH_MODIFIERS 406 #ifndef GBM_BO_FD_FOR_PLANE 407 int32_t first_handle; 408 #endif 409 int i; 410 #endif 411 412 if (!glamor_make_pixmap_exportable(pixmap, TRUE)) 413 return 0; 414 415 bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); 416 if (!bo) 417 return 0; 418 419 #ifdef GBM_BO_WITH_MODIFIERS 420 num_fds = gbm_bo_get_plane_count(bo); 421 for (i = 0; i < num_fds; i++) { 422 #ifdef GBM_BO_FD_FOR_PLANE 423 fds[i] = gbm_bo_get_fd_for_plane(bo, i); 424 #else 425 union gbm_bo_handle plane_handle = gbm_bo_get_handle_for_plane(bo, i); 426 427 if (i == 0) 428 first_handle = plane_handle.s32; 429 430 /* If all planes point to the same object as the first plane, i.e. they 431 * all have the same handle, we can fall back to the non-planar 432 * gbm_bo_get_fd without losing information. If they point to different 433 * objects we are out of luck and need to give up. 434 */ 435 if (first_handle == plane_handle.s32) 436 fds[i] = gbm_bo_get_fd(bo); 437 else 438 fds[i] = -1; 439 #endif 440 if (fds[i] == -1) { 441 while (--i >= 0) 442 close(fds[i]); 443 return 0; 444 } 445 strides[i] = gbm_bo_get_stride_for_plane(bo, i); 446 offsets[i] = gbm_bo_get_offset(bo, i); 447 } 448 *modifier = gbm_bo_get_modifier(bo); 449 #else 450 num_fds = 1; 451 fds[0] = gbm_bo_get_fd(bo); 452 if (fds[0] == -1) 453 return 0; 454 strides[0] = gbm_bo_get_stride(bo); 455 offsets[0] = 0; 456 *modifier = DRM_FORMAT_MOD_INVALID; 457 #endif 458 459 gbm_bo_destroy(bo); 460 return num_fds; 461 #else 462 return 0; 463 #endif 464 } 465 466 _X_EXPORT int 467 glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, 468 CARD16 *stride, CARD32 *size) 469 { 470 #ifdef GLAMOR_HAS_GBM 471 struct gbm_bo *bo; 472 int fd; 473 474 if (!glamor_make_pixmap_exportable(pixmap, FALSE)) 475 return -1; 476 477 bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); 478 if (!bo) 479 return -1; 480 481 fd = gbm_bo_get_fd(bo); 482 *stride = gbm_bo_get_stride(bo); 483 *size = *stride * gbm_bo_get_height(bo); 484 gbm_bo_destroy(bo); 485 486 return fd; 487 #else 488 return -1; 489 #endif 490 } 491 492 int 493 glamor_egl_fd_name_from_pixmap(ScreenPtr screen, 494 PixmapPtr pixmap, 495 CARD16 *stride, CARD32 *size) 496 { 497 struct glamor_egl_screen_private *glamor_egl; 498 struct gbm_bo *bo; 499 int fd = -1; 500 501 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 502 503 if (!glamor_make_pixmap_exportable(pixmap, FALSE)) 504 goto failure; 505 506 bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); 507 if (!bo) 508 goto failure; 509 510 pixmap->devKind = gbm_bo_get_stride(bo); 511 512 glamor_get_name_from_bo(glamor_egl->fd, bo, &fd); 513 *stride = pixmap->devKind; 514 *size = pixmap->devKind * gbm_bo_get_height(bo); 515 516 gbm_bo_destroy(bo); 517 failure: 518 return fd; 519 } 520 521 static bool 522 gbm_format_for_depth(CARD8 depth, uint32_t *format) 523 { 524 switch (depth) { 525 case 15: 526 *format = GBM_FORMAT_ARGB1555; 527 return true; 528 case 16: 529 *format = GBM_FORMAT_RGB565; 530 return true; 531 case 24: 532 *format = GBM_FORMAT_XRGB8888; 533 return true; 534 case 30: 535 *format = GBM_FORMAT_ARGB2101010; 536 return true; 537 case 32: 538 *format = GBM_FORMAT_ARGB8888; 539 return true; 540 default: 541 ErrorF("unexpected depth: %d\n", depth); 542 return false; 543 } 544 } 545 546 _X_EXPORT Bool 547 glamor_back_pixmap_from_fd(PixmapPtr pixmap, 548 int fd, 549 CARD16 width, 550 CARD16 height, 551 CARD16 stride, CARD8 depth, CARD8 bpp) 552 { 553 ScreenPtr screen = pixmap->drawable.pScreen; 554 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 555 struct glamor_egl_screen_private *glamor_egl; 556 struct gbm_bo *bo; 557 struct gbm_import_fd_data import_data = { 0 }; 558 Bool ret; 559 560 glamor_egl = glamor_egl_get_screen_private(scrn); 561 562 if (!gbm_format_for_depth(depth, &import_data.format) || 563 width == 0 || height == 0) 564 return FALSE; 565 566 import_data.fd = fd; 567 import_data.width = width; 568 import_data.height = height; 569 import_data.stride = stride; 570 bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD, &import_data, 0); 571 if (!bo) 572 return FALSE; 573 574 screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL); 575 576 ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, FALSE); 577 gbm_bo_destroy(bo); 578 return ret; 579 } 580 581 _X_EXPORT PixmapPtr 582 glamor_pixmap_from_fds(ScreenPtr screen, 583 CARD8 num_fds, const int *fds, 584 CARD16 width, CARD16 height, 585 const CARD32 *strides, const CARD32 *offsets, 586 CARD8 depth, CARD8 bpp, 587 uint64_t modifier) 588 { 589 PixmapPtr pixmap; 590 struct glamor_egl_screen_private *glamor_egl; 591 Bool ret = FALSE; 592 int i; 593 594 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 595 596 pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); 597 598 #ifdef GBM_BO_WITH_MODIFIERS 599 if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) { 600 struct gbm_import_fd_modifier_data import_data = { 0 }; 601 struct gbm_bo *bo; 602 603 if (!gbm_format_for_depth(depth, &import_data.format) || 604 width == 0 || height == 0) 605 goto error; 606 607 import_data.width = width; 608 import_data.height = height; 609 import_data.num_fds = num_fds; 610 import_data.modifier = modifier; 611 for (i = 0; i < num_fds; i++) { 612 import_data.fds[i] = fds[i]; 613 import_data.strides[i] = strides[i]; 614 import_data.offsets[i] = offsets[i]; 615 } 616 bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0); 617 if (bo) { 618 screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL); 619 ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, TRUE); 620 gbm_bo_destroy(bo); 621 } 622 } else 623 #endif 624 { 625 if (num_fds == 1) { 626 ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height, 627 strides[0], depth, bpp); 628 } 629 } 630 631 error: 632 if (ret == FALSE) { 633 screen->DestroyPixmap(pixmap); 634 return NULL; 635 } 636 return pixmap; 637 } 638 639 _X_EXPORT PixmapPtr 640 glamor_pixmap_from_fd(ScreenPtr screen, 641 int fd, 642 CARD16 width, 643 CARD16 height, 644 CARD16 stride, CARD8 depth, CARD8 bpp) 645 { 646 PixmapPtr pixmap; 647 Bool ret; 648 649 pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); 650 651 ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height, 652 stride, depth, bpp); 653 654 if (ret == FALSE) { 655 screen->DestroyPixmap(pixmap); 656 return NULL; 657 } 658 return pixmap; 659 } 660 661 _X_EXPORT Bool 662 glamor_get_formats(ScreenPtr screen, 663 CARD32 *num_formats, CARD32 **formats) 664 { 665 #ifdef GLAMOR_HAS_EGL_QUERY_DMABUF 666 struct glamor_egl_screen_private *glamor_egl; 667 EGLint num; 668 669 /* Explicitly zero the count as the caller may ignore the return value */ 670 *num_formats = 0; 671 672 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 673 674 if (!glamor_egl->dmabuf_capable) 675 return TRUE; 676 677 if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num)) 678 return FALSE; 679 680 if (num == 0) 681 return TRUE; 682 683 *formats = calloc(num, sizeof(CARD32)); 684 if (*formats == NULL) 685 return FALSE; 686 687 if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num, 688 (EGLint *) *formats, &num)) { 689 free(*formats); 690 return FALSE; 691 } 692 693 *num_formats = num; 694 return TRUE; 695 #else 696 *num_formats = 0; 697 return TRUE; 698 #endif 699 } 700 701 _X_EXPORT Bool 702 glamor_get_modifiers(ScreenPtr screen, uint32_t format, 703 uint32_t *num_modifiers, uint64_t **modifiers) 704 { 705 #ifdef GLAMOR_HAS_EGL_QUERY_DMABUF 706 struct glamor_egl_screen_private *glamor_egl; 707 EGLint num; 708 709 /* Explicitly zero the count as the caller may ignore the return value */ 710 *num_modifiers = 0; 711 712 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 713 714 if (!glamor_egl->dmabuf_capable) 715 return FALSE; 716 717 if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL, 718 NULL, &num)) 719 return FALSE; 720 721 if (num == 0) 722 return TRUE; 723 724 *modifiers = calloc(num, sizeof(uint64_t)); 725 if (*modifiers == NULL) 726 return FALSE; 727 728 if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num, 729 (EGLuint64KHR *) *modifiers, NULL, &num)) { 730 free(*modifiers); 731 *modifiers = NULL; 732 return FALSE; 733 } 734 735 *num_modifiers = num; 736 return TRUE; 737 #else 738 *num_modifiers = 0; 739 return TRUE; 740 #endif 741 } 742 743 _X_EXPORT const char * 744 glamor_egl_get_driver_name(ScreenPtr screen) 745 { 746 #ifdef GLAMOR_HAS_EGL_QUERY_DRIVER 747 struct glamor_egl_screen_private *glamor_egl; 748 749 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 750 751 if (epoxy_has_egl_extension(glamor_egl->display, "EGL_MESA_query_driver")) 752 return eglGetDisplayDriverName(glamor_egl->display); 753 #endif 754 755 return NULL; 756 } 757 758 759 static Bool 760 glamor_egl_destroy_pixmap(PixmapPtr pixmap) 761 { 762 ScreenPtr screen = pixmap->drawable.pScreen; 763 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 764 struct glamor_egl_screen_private *glamor_egl = 765 glamor_egl_get_screen_private(scrn); 766 Bool ret; 767 768 if (pixmap->refcnt == 1) { 769 struct glamor_pixmap_private *pixmap_priv = 770 glamor_get_pixmap_private(pixmap); 771 772 if (pixmap_priv->image) 773 eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image); 774 } 775 776 screen->DestroyPixmap = glamor_egl->saved_destroy_pixmap; 777 ret = screen->DestroyPixmap(pixmap); 778 glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap; 779 screen->DestroyPixmap = glamor_egl_destroy_pixmap; 780 781 return ret; 782 } 783 784 _X_EXPORT void 785 glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back) 786 { 787 EGLImageKHR temp_img; 788 Bool temp_mod; 789 struct glamor_pixmap_private *front_priv = 790 glamor_get_pixmap_private(front); 791 struct glamor_pixmap_private *back_priv = 792 glamor_get_pixmap_private(back); 793 794 glamor_pixmap_exchange_fbos(front, back); 795 796 temp_img = back_priv->image; 797 temp_mod = back_priv->used_modifiers; 798 back_priv->image = front_priv->image; 799 back_priv->used_modifiers = front_priv->used_modifiers; 800 front_priv->image = temp_img; 801 front_priv->used_modifiers = temp_mod; 802 803 glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM); 804 glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM); 805 } 806 807 static Bool 808 glamor_egl_close_screen(ScreenPtr screen) 809 { 810 ScrnInfoPtr scrn; 811 struct glamor_egl_screen_private *glamor_egl; 812 struct glamor_pixmap_private *pixmap_priv; 813 PixmapPtr screen_pixmap; 814 815 scrn = xf86ScreenToScrn(screen); 816 glamor_egl = glamor_egl_get_screen_private(scrn); 817 screen_pixmap = screen->GetScreenPixmap(screen); 818 pixmap_priv = glamor_get_pixmap_private(screen_pixmap); 819 820 eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image); 821 pixmap_priv->image = NULL; 822 823 screen->CloseScreen = glamor_egl->saved_close_screen; 824 825 return screen->CloseScreen(screen); 826 } 827 828 #ifdef DRI3 829 static int 830 glamor_dri3_open_client(ClientPtr client, 831 ScreenPtr screen, 832 RRProviderPtr provider, 833 int *fdp) 834 { 835 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 836 struct glamor_egl_screen_private *glamor_egl = 837 glamor_egl_get_screen_private(scrn); 838 int fd; 839 drm_magic_t magic; 840 841 fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC); 842 if (fd < 0) 843 return BadAlloc; 844 845 /* Before FD passing in the X protocol with DRI3 (and increased 846 * security of rendering with per-process address spaces on the 847 * GPU), the kernel had to come up with a way to have the server 848 * decide which clients got to access the GPU, which was done by 849 * each client getting a unique (magic) number from the kernel, 850 * passing it to the server, and the server then telling the 851 * kernel which clients were authenticated for using the device. 852 * 853 * Now that we have FD passing, the server can just set up the 854 * authentication on its own and hand the prepared FD off to the 855 * client. 856 */ 857 if (drmGetMagic(fd, &magic) < 0) { 858 if (errno == EACCES) { 859 /* Assume that we're on a render node, and the fd is 860 * already as authenticated as it should be. 861 */ 862 *fdp = fd; 863 return Success; 864 } else { 865 close(fd); 866 return BadMatch; 867 } 868 } 869 870 if (drmAuthMagic(glamor_egl->fd, magic) < 0) { 871 close(fd); 872 return BadMatch; 873 } 874 875 *fdp = fd; 876 return Success; 877 } 878 879 static const dri3_screen_info_rec glamor_dri3_info = { 880 .version = 2, 881 .open_client = glamor_dri3_open_client, 882 .pixmap_from_fds = glamor_pixmap_from_fds, 883 .fd_from_pixmap = glamor_egl_fd_from_pixmap, 884 .fds_from_pixmap = glamor_egl_fds_from_pixmap, 885 .get_formats = glamor_get_formats, 886 .get_modifiers = glamor_get_modifiers, 887 .get_drawable_modifiers = glamor_get_drawable_modifiers, 888 }; 889 #endif /* DRI3 */ 890 891 void 892 glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) 893 { 894 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 895 struct glamor_egl_screen_private *glamor_egl = 896 glamor_egl_get_screen_private(scrn); 897 #ifdef DRI3 898 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 899 #endif 900 901 glamor_egl->saved_close_screen = screen->CloseScreen; 902 screen->CloseScreen = glamor_egl_close_screen; 903 904 glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap; 905 screen->DestroyPixmap = glamor_egl_destroy_pixmap; 906 907 glamor_ctx->ctx = glamor_egl->context; 908 glamor_ctx->display = glamor_egl->display; 909 910 glamor_ctx->make_current = glamor_egl_make_current; 911 912 #ifdef DRI3 913 /* Tell the core that we have the interfaces for import/export 914 * of pixmaps. 915 */ 916 glamor_enable_dri3(screen); 917 918 /* If the driver wants to do its own auth dance (e.g. Xwayland 919 * on pre-3.15 kernels that don't have render nodes and thus 920 * has the wayland compositor as a master), then it needs us 921 * to stay out of the way and let it init DRI3 on its own. 922 */ 923 if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) { 924 /* To do DRI3 device FD generation, we need to open a new fd 925 * to the same device we were handed in originally. 926 */ 927 glamor_egl->device_path = drmGetDeviceNameFromFd2(glamor_egl->fd); 928 929 if (!dri3_screen_init(screen, &glamor_dri3_info)) { 930 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 931 "Failed to initialize DRI3.\n"); 932 } 933 } 934 #endif 935 } 936 937 static void glamor_egl_cleanup(struct glamor_egl_screen_private *glamor_egl) 938 { 939 if (glamor_egl->display != EGL_NO_DISPLAY) { 940 eglMakeCurrent(glamor_egl->display, 941 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 942 /* 943 * Force the next glamor_make_current call to update the context 944 * (on hot unplug another GPU may still be using glamor) 945 */ 946 lastGLContext = NULL; 947 eglTerminate(glamor_egl->display); 948 } 949 if (glamor_egl->gbm) 950 gbm_device_destroy(glamor_egl->gbm); 951 free(glamor_egl->device_path); 952 free(glamor_egl); 953 } 954 955 static void 956 glamor_egl_free_screen(ScrnInfoPtr scrn) 957 { 958 struct glamor_egl_screen_private *glamor_egl; 959 960 glamor_egl = glamor_egl_get_screen_private(scrn); 961 if (glamor_egl != NULL) { 962 scrn->FreeScreen = glamor_egl->saved_free_screen; 963 glamor_egl_cleanup(glamor_egl); 964 scrn->FreeScreen(scrn); 965 } 966 } 967 968 static Bool 969 glamor_egl_try_big_gl_api(ScrnInfoPtr scrn) 970 { 971 struct glamor_egl_screen_private *glamor_egl = 972 glamor_egl_get_screen_private(scrn); 973 974 if (eglBindAPI(EGL_OPENGL_API)) { 975 static const EGLint config_attribs_core[] = { 976 EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, 977 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, 978 EGL_CONTEXT_MAJOR_VERSION_KHR, 979 GLAMOR_GL_CORE_VER_MAJOR, 980 EGL_CONTEXT_MINOR_VERSION_KHR, 981 GLAMOR_GL_CORE_VER_MINOR, 982 EGL_NONE 983 }; 984 static const EGLint config_attribs[] = { 985 EGL_NONE 986 }; 987 988 glamor_egl->context = eglCreateContext(glamor_egl->display, 989 EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, 990 config_attribs_core); 991 992 if (glamor_egl->context == EGL_NO_CONTEXT) 993 glamor_egl->context = eglCreateContext(glamor_egl->display, 994 EGL_NO_CONFIG_KHR, 995 EGL_NO_CONTEXT, 996 config_attribs); 997 } 998 999 if (glamor_egl->context != EGL_NO_CONTEXT) { 1000 if (!eglMakeCurrent(glamor_egl->display, 1001 EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) { 1002 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1003 "Failed to make GL context current\n"); 1004 return FALSE; 1005 } 1006 1007 if (epoxy_gl_version() < 21) { 1008 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1009 "glamor: Ignoring GL < 2.1, falling back to GLES.\n"); 1010 eglDestroyContext(glamor_egl->display, glamor_egl->context); 1011 glamor_egl->context = EGL_NO_CONTEXT; 1012 } 1013 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1014 "glamor: Using OpenGL %d.%d context.\n", 1015 epoxy_gl_version() / 10, 1016 epoxy_gl_version() % 10); 1017 } 1018 return TRUE; 1019 } 1020 1021 static Bool 1022 glamor_egl_try_gles_api(ScrnInfoPtr scrn) 1023 { 1024 struct glamor_egl_screen_private *glamor_egl = 1025 glamor_egl_get_screen_private(scrn); 1026 1027 static const EGLint config_attribs[] = { 1028 EGL_CONTEXT_CLIENT_VERSION, 2, 1029 EGL_NONE 1030 }; 1031 if (!eglBindAPI(EGL_OPENGL_ES_API)) { 1032 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1033 "glamor: Failed to bind GLES API.\n"); 1034 return FALSE; 1035 } 1036 1037 glamor_egl->context = eglCreateContext(glamor_egl->display, 1038 EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, 1039 config_attribs); 1040 1041 if (glamor_egl->context != EGL_NO_CONTEXT) { 1042 if (!eglMakeCurrent(glamor_egl->display, 1043 EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) { 1044 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1045 "Failed to make GLES context current\n"); 1046 return FALSE; 1047 } 1048 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1049 "glamor: Using OpenGL ES %d.%d context.\n", 1050 epoxy_gl_version() / 10, 1051 epoxy_gl_version() % 10); 1052 } 1053 return TRUE; 1054 } 1055 1056 enum { 1057 GLAMOREGLOPT_RENDERING_API, 1058 }; 1059 1060 static const OptionInfoRec GlamorEGLOptions[] = { 1061 { GLAMOREGLOPT_RENDERING_API, "RenderingAPI", OPTV_STRING, {0}, FALSE }, 1062 { -1, NULL, OPTV_NONE, {0}, FALSE }, 1063 }; 1064 1065 Bool 1066 glamor_egl_init(ScrnInfoPtr scrn, int fd) 1067 { 1068 struct glamor_egl_screen_private *glamor_egl; 1069 const GLubyte *renderer; 1070 OptionInfoPtr options; 1071 const char *api = NULL; 1072 Bool es_allowed = TRUE; 1073 Bool force_es = FALSE; 1074 1075 glamor_egl = calloc(sizeof(*glamor_egl), 1); 1076 if (glamor_egl == NULL) 1077 return FALSE; 1078 if (xf86GlamorEGLPrivateIndex == -1) 1079 xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); 1080 1081 options = xnfalloc(sizeof(GlamorEGLOptions)); 1082 memcpy(options, GlamorEGLOptions, sizeof(GlamorEGLOptions)); 1083 xf86ProcessOptions(scrn->scrnIndex, scrn->options, options); 1084 api = xf86GetOptValString(options, GLAMOREGLOPT_RENDERING_API); 1085 if (api && !strncasecmp(api, "es", 2)) 1086 force_es = TRUE; 1087 else if (api && !strncasecmp(api, "gl", 2)) 1088 es_allowed = FALSE; 1089 free(options); 1090 1091 scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl; 1092 glamor_egl->fd = fd; 1093 glamor_egl->gbm = gbm_create_device(glamor_egl->fd); 1094 if (glamor_egl->gbm == NULL) { 1095 ErrorF("couldn't get display device\n"); 1096 goto error; 1097 } 1098 1099 glamor_egl->display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA, 1100 glamor_egl->gbm); 1101 if (!glamor_egl->display) { 1102 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglGetDisplay() failed\n"); 1103 goto error; 1104 } 1105 1106 if (!eglInitialize(glamor_egl->display, NULL, NULL)) { 1107 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n"); 1108 glamor_egl->display = EGL_NO_DISPLAY; 1109 goto error; 1110 } 1111 1112 #define GLAMOR_CHECK_EGL_EXTENSION(EXT) \ 1113 if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) { \ 1114 ErrorF("EGL_" #EXT " required.\n"); \ 1115 goto error; \ 1116 } 1117 1118 #define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2) \ 1119 if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) && \ 1120 !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) { \ 1121 ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n"); \ 1122 goto error; \ 1123 } 1124 1125 GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_context); 1126 1127 if (!force_es) { 1128 if(!glamor_egl_try_big_gl_api(scrn)) 1129 goto error; 1130 } 1131 1132 if (glamor_egl->context == EGL_NO_CONTEXT && es_allowed) { 1133 if(!glamor_egl_try_gles_api(scrn)) 1134 goto error; 1135 } 1136 1137 if (glamor_egl->context == EGL_NO_CONTEXT) { 1138 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1139 "glamor: Failed to create GL or GLES2 contexts\n"); 1140 goto error; 1141 } 1142 1143 renderer = glGetString(GL_RENDERER); 1144 if (!renderer) { 1145 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1146 "glGetString() returned NULL, your GL is broken\n"); 1147 goto error; 1148 } 1149 if (strstr((const char *)renderer, "llvmpipe")) { 1150 if (scrn->confScreen->num_gpu_devices) 1151 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1152 "Allowing glamor on llvmpipe for PRIME\n"); 1153 else { 1154 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1155 "Refusing to try glamor on llvmpipe\n"); 1156 goto error; 1157 } 1158 } 1159 1160 /* 1161 * Force the next glamor_make_current call to set the right context 1162 * (in case of multiple GPUs using glamor) 1163 */ 1164 lastGLContext = NULL; 1165 1166 if (!epoxy_has_gl_extension("GL_OES_EGL_image")) { 1167 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1168 "glamor acceleration requires GL_OES_EGL_image\n"); 1169 goto error; 1170 } 1171 1172 xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n", 1173 renderer); 1174 1175 #ifdef GBM_BO_WITH_MODIFIERS 1176 if (epoxy_has_egl_extension(glamor_egl->display, 1177 "EGL_EXT_image_dma_buf_import") && 1178 epoxy_has_egl_extension(glamor_egl->display, 1179 "EGL_EXT_image_dma_buf_import_modifiers")) { 1180 if (xf86Info.debug != NULL) 1181 glamor_egl->dmabuf_capable = !!strstr(xf86Info.debug, 1182 "dmabuf_capable"); 1183 else 1184 glamor_egl->dmabuf_capable = FALSE; 1185 } 1186 #endif 1187 1188 glamor_egl->saved_free_screen = scrn->FreeScreen; 1189 scrn->FreeScreen = glamor_egl_free_screen; 1190 return TRUE; 1191 1192 error: 1193 glamor_egl_cleanup(glamor_egl); 1194 return FALSE; 1195 } 1196 1197 /** Stub to retain compatibility with pre-server-1.16 ABI. */ 1198 Bool 1199 glamor_egl_init_textured_pixmap(ScreenPtr screen) 1200 { 1201 return TRUE; 1202 } 1203