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