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