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