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@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 51struct 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 67int xf86GlamorEGLPrivateIndex = -1; 68 69 70static struct glamor_egl_screen_private * 71glamor_egl_get_screen_private(ScrnInfoPtr scrn) 72{ 73 return (struct glamor_egl_screen_private *) 74 scrn->privates[xf86GlamorEGLPrivateIndex].ptr; 75} 76 77static void 78glamor_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 96static int 97glamor_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 118static Bool 119glamor_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 138struct gbm_device * 139glamor_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 146Bool 147glamor_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 162static void 163glamor_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 182Bool 183glamor_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 217Bool 218glamor_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 252static void 253glamor_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 262static Bool 263glamor_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 373static struct gbm_bo * 374glamor_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 388struct gbm_bo * 389glamor_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 397int 398glamor_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 int i; 407#endif 408 409 if (!glamor_make_pixmap_exportable(pixmap, TRUE)) 410 return 0; 411 412 bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); 413 if (!bo) 414 return 0; 415 416#ifdef GBM_BO_WITH_MODIFIERS 417 num_fds = gbm_bo_get_plane_count(bo); 418 for (i = 0; i < num_fds; i++) { 419 fds[i] = gbm_bo_get_fd(bo); 420 strides[i] = gbm_bo_get_stride_for_plane(bo, i); 421 offsets[i] = gbm_bo_get_offset(bo, i); 422 } 423 *modifier = gbm_bo_get_modifier(bo); 424#else 425 num_fds = 1; 426 fds[0] = gbm_bo_get_fd(bo); 427 strides[0] = gbm_bo_get_stride(bo); 428 offsets[0] = 0; 429 *modifier = DRM_FORMAT_MOD_INVALID; 430#endif 431 432 gbm_bo_destroy(bo); 433 return num_fds; 434#else 435 return 0; 436#endif 437} 438 439_X_EXPORT int 440glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, 441 CARD16 *stride, CARD32 *size) 442{ 443#ifdef GLAMOR_HAS_GBM 444 struct gbm_bo *bo; 445 int fd; 446 447 if (!glamor_make_pixmap_exportable(pixmap, FALSE)) 448 return -1; 449 450 bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); 451 if (!bo) 452 return -1; 453 454 fd = gbm_bo_get_fd(bo); 455 *stride = gbm_bo_get_stride(bo); 456 *size = *stride * gbm_bo_get_height(bo); 457 gbm_bo_destroy(bo); 458 459 return fd; 460#else 461 return -1; 462#endif 463} 464 465int 466glamor_egl_fd_name_from_pixmap(ScreenPtr screen, 467 PixmapPtr pixmap, 468 CARD16 *stride, CARD32 *size) 469{ 470 struct glamor_egl_screen_private *glamor_egl; 471 struct gbm_bo *bo; 472 int fd = -1; 473 474 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 475 476 if (!glamor_make_pixmap_exportable(pixmap, FALSE)) 477 goto failure; 478 479 bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); 480 if (!bo) 481 goto failure; 482 483 pixmap->devKind = gbm_bo_get_stride(bo); 484 485 glamor_get_name_from_bo(glamor_egl->fd, bo, &fd); 486 *stride = pixmap->devKind; 487 *size = pixmap->devKind * gbm_bo_get_height(bo); 488 489 gbm_bo_destroy(bo); 490 failure: 491 return fd; 492} 493 494_X_EXPORT Bool 495glamor_back_pixmap_from_fd(PixmapPtr pixmap, 496 int fd, 497 CARD16 width, 498 CARD16 height, 499 CARD16 stride, CARD8 depth, CARD8 bpp) 500{ 501 ScreenPtr screen = pixmap->drawable.pScreen; 502 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 503 struct glamor_egl_screen_private *glamor_egl; 504 struct gbm_bo *bo; 505 struct gbm_import_fd_data import_data = { 0 }; 506 Bool ret; 507 508 glamor_egl = glamor_egl_get_screen_private(scrn); 509 510 if (bpp != 32 || !(depth == 24 || depth == 32 || depth == 30) || width == 0 || height == 0) 511 return FALSE; 512 513 import_data.fd = fd; 514 import_data.width = width; 515 import_data.height = height; 516 import_data.stride = stride; 517 if (depth == 30) 518 import_data.format = GBM_FORMAT_ARGB2101010; 519 else 520 import_data.format = GBM_FORMAT_ARGB8888; 521 bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD, &import_data, 0); 522 if (!bo) 523 return FALSE; 524 525 screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL); 526 527 ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, FALSE); 528 gbm_bo_destroy(bo); 529 return ret; 530} 531 532static uint32_t 533gbm_format_for_depth(CARD8 depth) 534{ 535 switch (depth) { 536 case 16: 537 return GBM_FORMAT_RGB565; 538 case 24: 539 return GBM_FORMAT_XRGB8888; 540 case 30: 541 return GBM_FORMAT_ARGB2101010; 542 default: 543 ErrorF("unexpected depth: %d\n", depth); 544 case 32: 545 return GBM_FORMAT_ARGB8888; 546 } 547} 548 549_X_EXPORT PixmapPtr 550glamor_pixmap_from_fds(ScreenPtr screen, 551 CARD8 num_fds, const int *fds, 552 CARD16 width, CARD16 height, 553 const CARD32 *strides, const CARD32 *offsets, 554 CARD8 depth, CARD8 bpp, 555 uint64_t modifier) 556{ 557 PixmapPtr pixmap; 558 struct glamor_egl_screen_private *glamor_egl; 559 Bool ret = FALSE; 560 int i; 561 562 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 563 564 pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); 565 566#ifdef GBM_BO_WITH_MODIFIERS 567 if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) { 568 struct gbm_import_fd_modifier_data import_data = { 0 }; 569 struct gbm_bo *bo; 570 571 import_data.width = width; 572 import_data.height = height; 573 import_data.num_fds = num_fds; 574 import_data.modifier = modifier; 575 for (i = 0; i < num_fds; i++) { 576 import_data.fds[i] = fds[i]; 577 import_data.strides[i] = strides[i]; 578 import_data.offsets[i] = offsets[i]; 579 } 580 import_data.format = gbm_format_for_depth(depth); 581 bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0); 582 if (bo) { 583 screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL); 584 ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, TRUE); 585 gbm_bo_destroy(bo); 586 } 587 } else 588#endif 589 { 590 if (num_fds == 1) { 591 ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height, 592 strides[0], depth, bpp); 593 } 594 } 595 596 if (ret == FALSE) { 597 screen->DestroyPixmap(pixmap); 598 return NULL; 599 } 600 return pixmap; 601} 602 603_X_EXPORT PixmapPtr 604glamor_pixmap_from_fd(ScreenPtr screen, 605 int fd, 606 CARD16 width, 607 CARD16 height, 608 CARD16 stride, CARD8 depth, CARD8 bpp) 609{ 610 PixmapPtr pixmap; 611 Bool ret; 612 613 pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); 614 615 ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height, 616 stride, depth, bpp); 617 618 if (ret == FALSE) { 619 screen->DestroyPixmap(pixmap); 620 return NULL; 621 } 622 return pixmap; 623} 624 625_X_EXPORT Bool 626glamor_get_formats(ScreenPtr screen, 627 CARD32 *num_formats, CARD32 **formats) 628{ 629#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF 630 struct glamor_egl_screen_private *glamor_egl; 631 EGLint num; 632 633 /* Explicitly zero the count as the caller may ignore the return value */ 634 *num_formats = 0; 635 636 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 637 638 if (!glamor_egl->dmabuf_capable) 639 return TRUE; 640 641 if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num)) 642 return FALSE; 643 644 if (num == 0) 645 return TRUE; 646 647 *formats = calloc(num, sizeof(CARD32)); 648 if (*formats == NULL) 649 return FALSE; 650 651 if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num, 652 (EGLint *) *formats, &num)) { 653 free(*formats); 654 return FALSE; 655 } 656 657 *num_formats = num; 658 return TRUE; 659#else 660 *num_formats = 0; 661 return TRUE; 662#endif 663} 664 665_X_EXPORT Bool 666glamor_get_modifiers(ScreenPtr screen, uint32_t format, 667 uint32_t *num_modifiers, uint64_t **modifiers) 668{ 669#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF 670 struct glamor_egl_screen_private *glamor_egl; 671 EGLint num; 672 673 /* Explicitly zero the count as the caller may ignore the return value */ 674 *num_modifiers = 0; 675 676 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 677 678 if (!glamor_egl->dmabuf_capable) 679 return FALSE; 680 681 if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL, 682 NULL, &num)) 683 return FALSE; 684 685 if (num == 0) 686 return TRUE; 687 688 *modifiers = calloc(num, sizeof(uint64_t)); 689 if (*modifiers == NULL) 690 return FALSE; 691 692 if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num, 693 (EGLuint64KHR *) *modifiers, NULL, &num)) { 694 free(*modifiers); 695 return FALSE; 696 } 697 698 *num_modifiers = num; 699 return TRUE; 700#else 701 *num_modifiers = 0; 702 return TRUE; 703#endif 704} 705 706_X_EXPORT const char * 707glamor_egl_get_driver_name(ScreenPtr screen) 708{ 709#ifdef GLAMOR_HAS_EGL_QUERY_DRIVER 710 struct glamor_egl_screen_private *glamor_egl; 711 712 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 713 714 if (epoxy_has_egl_extension(glamor_egl->display, "EGL_MESA_query_driver")) 715 return eglGetDisplayDriverName(glamor_egl->display); 716#endif 717 718 return NULL; 719} 720 721 722static Bool 723glamor_egl_destroy_pixmap(PixmapPtr pixmap) 724{ 725 ScreenPtr screen = pixmap->drawable.pScreen; 726 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 727 struct glamor_egl_screen_private *glamor_egl = 728 glamor_egl_get_screen_private(scrn); 729 Bool ret; 730 731 if (pixmap->refcnt == 1) { 732 struct glamor_pixmap_private *pixmap_priv = 733 glamor_get_pixmap_private(pixmap); 734 735 if (pixmap_priv->image) 736 eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image); 737 } 738 739 screen->DestroyPixmap = glamor_egl->saved_destroy_pixmap; 740 ret = screen->DestroyPixmap(pixmap); 741 glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap; 742 screen->DestroyPixmap = glamor_egl_destroy_pixmap; 743 744 return ret; 745} 746 747_X_EXPORT void 748glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back) 749{ 750 EGLImageKHR temp_img; 751 Bool temp_mod; 752 struct glamor_pixmap_private *front_priv = 753 glamor_get_pixmap_private(front); 754 struct glamor_pixmap_private *back_priv = 755 glamor_get_pixmap_private(back); 756 757 glamor_pixmap_exchange_fbos(front, back); 758 759 temp_img = back_priv->image; 760 temp_mod = back_priv->used_modifiers; 761 back_priv->image = front_priv->image; 762 back_priv->used_modifiers = front_priv->used_modifiers; 763 front_priv->image = temp_img; 764 front_priv->used_modifiers = temp_mod; 765 766 glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM); 767 glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM); 768} 769 770static Bool 771glamor_egl_close_screen(ScreenPtr screen) 772{ 773 ScrnInfoPtr scrn; 774 struct glamor_egl_screen_private *glamor_egl; 775 struct glamor_pixmap_private *pixmap_priv; 776 PixmapPtr screen_pixmap; 777 778 scrn = xf86ScreenToScrn(screen); 779 glamor_egl = glamor_egl_get_screen_private(scrn); 780 screen_pixmap = screen->GetScreenPixmap(screen); 781 pixmap_priv = glamor_get_pixmap_private(screen_pixmap); 782 783 eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image); 784 pixmap_priv->image = NULL; 785 786 screen->CloseScreen = glamor_egl->saved_close_screen; 787 788 return screen->CloseScreen(screen); 789} 790 791#ifdef DRI3 792static int 793glamor_dri3_open_client(ClientPtr client, 794 ScreenPtr screen, 795 RRProviderPtr provider, 796 int *fdp) 797{ 798 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 799 struct glamor_egl_screen_private *glamor_egl = 800 glamor_egl_get_screen_private(scrn); 801 int fd; 802 drm_magic_t magic; 803 804 fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC); 805 if (fd < 0) 806 return BadAlloc; 807 808 /* Before FD passing in the X protocol with DRI3 (and increased 809 * security of rendering with per-process address spaces on the 810 * GPU), the kernel had to come up with a way to have the server 811 * decide which clients got to access the GPU, which was done by 812 * each client getting a unique (magic) number from the kernel, 813 * passing it to the server, and the server then telling the 814 * kernel which clients were authenticated for using the device. 815 * 816 * Now that we have FD passing, the server can just set up the 817 * authentication on its own and hand the prepared FD off to the 818 * client. 819 */ 820 if (drmGetMagic(fd, &magic) < 0) { 821 if (errno == EACCES) { 822 /* Assume that we're on a render node, and the fd is 823 * already as authenticated as it should be. 824 */ 825 *fdp = fd; 826 return Success; 827 } else { 828 close(fd); 829 return BadMatch; 830 } 831 } 832 833 if (drmAuthMagic(glamor_egl->fd, magic) < 0) { 834 close(fd); 835 return BadMatch; 836 } 837 838 *fdp = fd; 839 return Success; 840} 841 842static const dri3_screen_info_rec glamor_dri3_info = { 843 .version = 2, 844 .open_client = glamor_dri3_open_client, 845 .pixmap_from_fds = glamor_pixmap_from_fds, 846 .fd_from_pixmap = glamor_egl_fd_from_pixmap, 847 .fds_from_pixmap = glamor_egl_fds_from_pixmap, 848 .get_formats = glamor_get_formats, 849 .get_modifiers = glamor_get_modifiers, 850 .get_drawable_modifiers = glamor_get_drawable_modifiers, 851}; 852#endif /* DRI3 */ 853 854void 855glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) 856{ 857 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 858 struct glamor_egl_screen_private *glamor_egl = 859 glamor_egl_get_screen_private(scrn); 860#ifdef DRI3 861 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 862#endif 863 864 glamor_egl->saved_close_screen = screen->CloseScreen; 865 screen->CloseScreen = glamor_egl_close_screen; 866 867 glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap; 868 screen->DestroyPixmap = glamor_egl_destroy_pixmap; 869 870 glamor_ctx->ctx = glamor_egl->context; 871 glamor_ctx->display = glamor_egl->display; 872 873 glamor_ctx->make_current = glamor_egl_make_current; 874 875#ifdef DRI3 876 /* Tell the core that we have the interfaces for import/export 877 * of pixmaps. 878 */ 879 glamor_enable_dri3(screen); 880 881 /* If the driver wants to do its own auth dance (e.g. Xwayland 882 * on pre-3.15 kernels that don't have render nodes and thus 883 * has the wayland compositor as a master), then it needs us 884 * to stay out of the way and let it init DRI3 on its own. 885 */ 886 if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) { 887 /* To do DRI3 device FD generation, we need to open a new fd 888 * to the same device we were handed in originally. 889 */ 890 glamor_egl->device_path = drmGetDeviceNameFromFd2(glamor_egl->fd); 891 892 if (!dri3_screen_init(screen, &glamor_dri3_info)) { 893 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 894 "Failed to initialize DRI3.\n"); 895 } 896 } 897#endif 898} 899 900static void glamor_egl_cleanup(struct glamor_egl_screen_private *glamor_egl) 901{ 902 if (glamor_egl->display != EGL_NO_DISPLAY) { 903 eglMakeCurrent(glamor_egl->display, 904 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 905 /* 906 * Force the next glamor_make_current call to update the context 907 * (on hot unplug another GPU may still be using glamor) 908 */ 909 lastGLContext = NULL; 910 eglTerminate(glamor_egl->display); 911 } 912 if (glamor_egl->gbm) 913 gbm_device_destroy(glamor_egl->gbm); 914 free(glamor_egl->device_path); 915 free(glamor_egl); 916} 917 918static void 919glamor_egl_free_screen(ScrnInfoPtr scrn) 920{ 921 struct glamor_egl_screen_private *glamor_egl; 922 923 glamor_egl = glamor_egl_get_screen_private(scrn); 924 if (glamor_egl != NULL) { 925 scrn->FreeScreen = glamor_egl->saved_free_screen; 926 glamor_egl_cleanup(glamor_egl); 927 scrn->FreeScreen(scrn); 928 } 929} 930 931Bool 932glamor_egl_init(ScrnInfoPtr scrn, int fd) 933{ 934 struct glamor_egl_screen_private *glamor_egl; 935 const GLubyte *renderer; 936 EGLConfig egl_config; 937 int n; 938 939 glamor_egl = calloc(sizeof(*glamor_egl), 1); 940 if (glamor_egl == NULL) 941 return FALSE; 942 if (xf86GlamorEGLPrivateIndex == -1) 943 xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); 944 945 scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl; 946 glamor_egl->fd = fd; 947 glamor_egl->gbm = gbm_create_device(glamor_egl->fd); 948 if (glamor_egl->gbm == NULL) { 949 ErrorF("couldn't get display device\n"); 950 goto error; 951 } 952 953 glamor_egl->display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA, 954 glamor_egl->gbm); 955 if (!glamor_egl->display) { 956 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglGetDisplay() failed\n"); 957 goto error; 958 } 959 960 if (!eglInitialize(glamor_egl->display, NULL, NULL)) { 961 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n"); 962 glamor_egl->display = EGL_NO_DISPLAY; 963 goto error; 964 } 965 966#define GLAMOR_CHECK_EGL_EXTENSION(EXT) \ 967 if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) { \ 968 ErrorF("EGL_" #EXT " required.\n"); \ 969 goto error; \ 970 } 971 972#define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2) \ 973 if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) && \ 974 !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) { \ 975 ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n"); \ 976 goto error; \ 977 } 978 979 GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_context); 980 981 if (eglBindAPI(EGL_OPENGL_API)) { 982 static const EGLint config_attribs_core[] = { 983 EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, 984 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, 985 EGL_CONTEXT_MAJOR_VERSION_KHR, 986 GLAMOR_GL_CORE_VER_MAJOR, 987 EGL_CONTEXT_MINOR_VERSION_KHR, 988 GLAMOR_GL_CORE_VER_MINOR, 989 EGL_NONE 990 }; 991 static const EGLint config_attribs[] = { 992 EGL_NONE 993 }; 994 995 glamor_egl->context = eglCreateContext(glamor_egl->display, 996 NULL, EGL_NO_CONTEXT, 997 config_attribs_core); 998 999 if (glamor_egl->context == EGL_NO_CONTEXT) 1000 glamor_egl->context = eglCreateContext(glamor_egl->display, 1001 NULL, EGL_NO_CONTEXT, 1002 config_attribs); 1003 } 1004 1005 if (glamor_egl->context != EGL_NO_CONTEXT) { 1006 if (!eglMakeCurrent(glamor_egl->display, 1007 EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) { 1008 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1009 "Failed to make GL context current\n"); 1010 goto error; 1011 } 1012 1013 if (epoxy_gl_version() < 21) { 1014 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1015 "glamor: Ignoring GL < 2.1, falling back to GLES.\n"); 1016 eglDestroyContext(glamor_egl->display, glamor_egl->context); 1017 glamor_egl->context = EGL_NO_CONTEXT; 1018 } 1019 } 1020 1021 if (glamor_egl->context == EGL_NO_CONTEXT) { 1022 static const EGLint config_attribs[] = { 1023 EGL_CONTEXT_CLIENT_VERSION, 2, 1024 EGL_NONE 1025 }; 1026 if (!eglBindAPI(EGL_OPENGL_ES_API)) { 1027 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1028 "glamor: Failed to bind either GL or GLES APIs.\n"); 1029 goto error; 1030 } 1031 1032 if (!eglChooseConfig(glamor_egl->display, NULL, &egl_config, 1, &n)) { 1033 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1034 "glamor: No acceptable EGL configs found\n"); 1035 goto error; 1036 } 1037 1038 glamor_egl->context = eglCreateContext(glamor_egl->display, 1039 egl_config, EGL_NO_CONTEXT, 1040 config_attribs); 1041 1042 if (glamor_egl->context == EGL_NO_CONTEXT) { 1043 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1044 "glamor: Failed to create GL or GLES2 contexts\n"); 1045 goto error; 1046 } 1047 1048 if (!eglMakeCurrent(glamor_egl->display, 1049 EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) { 1050 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1051 "Failed to make GLES2 context current\n"); 1052 goto error; 1053 } 1054 } 1055 1056 renderer = glGetString(GL_RENDERER); 1057 if (!renderer) { 1058 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1059 "glGetString() returned NULL, your GL is broken\n"); 1060 goto error; 1061 } 1062 if (strstr((const char *)renderer, "llvmpipe")) { 1063 if (scrn->confScreen->num_gpu_devices) 1064 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1065 "Allowing glamor on llvmpipe for PRIME\n"); 1066 else { 1067 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1068 "Refusing to try glamor on llvmpipe\n"); 1069 goto error; 1070 } 1071 } 1072 1073 /* 1074 * Force the next glamor_make_current call to set the right context 1075 * (in case of multiple GPUs using glamor) 1076 */ 1077 lastGLContext = NULL; 1078 1079 if (!epoxy_has_gl_extension("GL_OES_EGL_image")) { 1080 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1081 "glamor acceleration requires GL_OES_EGL_image\n"); 1082 goto error; 1083 } 1084 1085 xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n", 1086 renderer); 1087 1088#ifdef GBM_BO_WITH_MODIFIERS 1089 if (epoxy_has_egl_extension(glamor_egl->display, 1090 "EGL_EXT_image_dma_buf_import") && 1091 epoxy_has_egl_extension(glamor_egl->display, 1092 "EGL_EXT_image_dma_buf_import_modifiers")) { 1093 if (xf86Info.debug != NULL) 1094 glamor_egl->dmabuf_capable = !!strstr(xf86Info.debug, 1095 "dmabuf_capable"); 1096 else 1097 glamor_egl->dmabuf_capable = FALSE; 1098 } 1099#endif 1100 1101 glamor_egl->saved_free_screen = scrn->FreeScreen; 1102 scrn->FreeScreen = glamor_egl_free_screen; 1103 return TRUE; 1104 1105error: 1106 glamor_egl_cleanup(glamor_egl); 1107 return FALSE; 1108} 1109 1110/** Stub to retain compatibility with pre-server-1.16 ABI. */ 1111Bool 1112glamor_egl_init_textured_pixmap(ScreenPtr screen) 1113{ 1114 return TRUE; 1115} 1116