glamor_egl.c revision 35c4bbdf
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 <xf86drm.h> 39#define EGL_DISPLAY_NO_X_MESA 40 41#ifdef GLAMOR_HAS_GBM 42#include <gbm.h> 43#include <drm_fourcc.h> 44#endif 45 46#define MESA_EGL_NO_X11_HEADERS 47#include <epoxy/gl.h> 48#include <epoxy/egl.h> 49 50#include "glamor.h" 51#include "glamor_priv.h" 52#include "dri3.h" 53 54static const char glamor_name[] = "glamor"; 55 56static void 57glamor_identify(int flags) 58{ 59 xf86Msg(X_INFO, "%s: OpenGL accelerated X.org driver based.\n", 60 glamor_name); 61} 62 63struct glamor_egl_screen_private { 64 EGLDisplay display; 65 EGLContext context; 66 EGLint major, minor; 67 char *device_path; 68 69 CreateScreenResourcesProcPtr CreateScreenResources; 70 CloseScreenProcPtr CloseScreen; 71 int fd; 72 int cpp; 73#ifdef GLAMOR_HAS_GBM 74 struct gbm_device *gbm; 75#endif 76 int has_gem; 77 int gl_context_depth; 78 int dri3_capable; 79 80 CloseScreenProcPtr saved_close_screen; 81 xf86FreeScreenProc *saved_free_screen; 82}; 83 84int xf86GlamorEGLPrivateIndex = -1; 85 86 87static struct glamor_egl_screen_private * 88glamor_egl_get_screen_private(ScrnInfoPtr scrn) 89{ 90 return (struct glamor_egl_screen_private *) 91 scrn->privates[xf86GlamorEGLPrivateIndex].ptr; 92} 93 94static void 95glamor_egl_make_current(struct glamor_context *glamor_ctx) 96{ 97 /* There's only a single global dispatch table in Mesa. EGL, GLX, 98 * and AIGLX's direct dispatch table manipulation don't talk to 99 * each other. We need to set the context to NULL first to avoid 100 * EGL's no-op context change fast path when switching back to 101 * EGL. 102 */ 103 eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE, 104 EGL_NO_SURFACE, EGL_NO_CONTEXT); 105 106 if (!eglMakeCurrent(glamor_ctx->display, 107 EGL_NO_SURFACE, EGL_NO_SURFACE, 108 glamor_ctx->ctx)) { 109 FatalError("Failed to make EGL context current\n"); 110 } 111} 112 113static EGLImageKHR 114_glamor_egl_create_image(struct glamor_egl_screen_private *glamor_egl, 115 int width, int height, int stride, int name, int depth) 116{ 117 EGLImageKHR image; 118 119 EGLint attribs[] = { 120 EGL_WIDTH, 0, 121 EGL_HEIGHT, 0, 122 EGL_DRM_BUFFER_STRIDE_MESA, 0, 123 EGL_DRM_BUFFER_FORMAT_MESA, 124 EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, 125 EGL_DRM_BUFFER_USE_MESA, 126 EGL_DRM_BUFFER_USE_SHARE_MESA | EGL_DRM_BUFFER_USE_SCANOUT_MESA, 127 EGL_NONE 128 }; 129 attribs[1] = width; 130 attribs[3] = height; 131 attribs[5] = stride; 132 if (depth != 32 && depth != 24) 133 return EGL_NO_IMAGE_KHR; 134 image = eglCreateImageKHR(glamor_egl->display, 135 glamor_egl->context, 136 EGL_DRM_BUFFER_MESA, 137 (void *) (uintptr_t) name, 138 attribs); 139 if (image == EGL_NO_IMAGE_KHR) 140 return EGL_NO_IMAGE_KHR; 141 142 return image; 143} 144 145static int 146glamor_get_flink_name(int fd, int handle, int *name) 147{ 148 struct drm_gem_flink flink; 149 150 flink.handle = handle; 151 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) 152 return FALSE; 153 *name = flink.name; 154 return TRUE; 155} 156 157static Bool 158glamor_create_texture_from_image(ScreenPtr screen, 159 EGLImageKHR image, GLuint * texture) 160{ 161 struct glamor_screen_private *glamor_priv = 162 glamor_get_screen_private(screen); 163 164 glamor_make_current(glamor_priv); 165 166 glGenTextures(1, texture); 167 glBindTexture(GL_TEXTURE_2D, *texture); 168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 170 171 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 172 glBindTexture(GL_TEXTURE_2D, 0); 173 174 return TRUE; 175} 176 177void * 178glamor_egl_get_gbm_device(ScreenPtr screen) 179{ 180#ifdef GLAMOR_HAS_GBM 181 struct glamor_egl_screen_private *glamor_egl = 182 glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 183 return glamor_egl->gbm; 184#else 185 return NULL; 186#endif 187} 188 189unsigned int 190glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h, Bool linear) 191{ 192 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 193 struct glamor_egl_screen_private *glamor_egl; 194 EGLImageKHR image; 195 GLuint texture; 196 197#ifdef GLAMOR_HAS_GBM 198 struct gbm_bo *bo; 199 EGLNativePixmapType native_pixmap; 200 201 glamor_egl = glamor_egl_get_screen_private(scrn); 202 bo = gbm_bo_create(glamor_egl->gbm, w, h, GBM_FORMAT_ARGB8888, 203#ifdef GLAMOR_HAS_GBM_LINEAR 204 (linear ? GBM_BO_USE_LINEAR : 0) | 205#endif 206 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); 207 if (!bo) 208 return 0; 209 210 /* If the following assignment raises an error or a warning 211 * then that means EGLNativePixmapType is not struct gbm_bo * 212 * on your platform: This code won't work and you should not 213 * compile with dri3 support enabled */ 214 native_pixmap = bo; 215 216 image = eglCreateImageKHR(glamor_egl->display, 217 EGL_NO_CONTEXT, 218 EGL_NATIVE_PIXMAP_KHR, 219 native_pixmap, NULL); 220 gbm_bo_destroy(bo); 221 if (image == EGL_NO_IMAGE_KHR) 222 return 0; 223 glamor_create_texture_from_image(screen, image, &texture); 224 eglDestroyImageKHR(glamor_egl->display, image); 225 226 return texture; 227#else 228 return 0; /* this path should never happen */ 229#endif 230} 231 232Bool 233glamor_egl_create_textured_screen(ScreenPtr screen, int handle, int stride) 234{ 235 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 236 PixmapPtr screen_pixmap; 237 238 screen_pixmap = screen->GetScreenPixmap(screen); 239 240 if (!glamor_egl_create_textured_pixmap(screen_pixmap, handle, stride)) { 241 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 242 "Failed to create textured screen."); 243 return FALSE; 244 } 245 glamor_set_screen_pixmap(screen_pixmap, NULL); 246 return TRUE; 247} 248 249Bool 250glamor_egl_create_textured_screen_ext(ScreenPtr screen, 251 int handle, 252 int stride, PixmapPtr *back_pixmap) 253{ 254 return glamor_egl_create_textured_screen(screen, handle, stride); 255} 256 257static Bool 258glamor_egl_check_has_gem(int fd) 259{ 260 struct drm_gem_flink flink; 261 262 flink.handle = 0; 263 264 ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink); 265 if (errno == ENOENT || errno == EINVAL) 266 return TRUE; 267 return FALSE; 268} 269 270static void 271glamor_egl_set_pixmap_image(PixmapPtr pixmap, EGLImageKHR image) 272{ 273 struct glamor_pixmap_private *pixmap_priv = 274 glamor_get_pixmap_private(pixmap); 275 EGLImageKHR old; 276 277 old = pixmap_priv->image; 278 if (old) { 279 ScreenPtr screen = pixmap->drawable.pScreen; 280 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 281 struct glamor_egl_screen_private *glamor_egl = glamor_egl_get_screen_private(scrn); 282 283 eglDestroyImageKHR(glamor_egl->display, old); 284 } 285 pixmap_priv->image = image; 286} 287 288Bool 289glamor_egl_create_textured_pixmap(PixmapPtr pixmap, int handle, int stride) 290{ 291 ScreenPtr screen = pixmap->drawable.pScreen; 292 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 293 struct glamor_screen_private *glamor_priv = 294 glamor_get_screen_private(screen); 295 struct glamor_egl_screen_private *glamor_egl; 296 EGLImageKHR image; 297 GLuint texture; 298 int name; 299 Bool ret = FALSE; 300 301 glamor_egl = glamor_egl_get_screen_private(scrn); 302 303 glamor_make_current(glamor_priv); 304 if (glamor_egl->has_gem) { 305 if (!glamor_get_flink_name(glamor_egl->fd, handle, &name)) { 306 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 307 "Couldn't flink pixmap handle\n"); 308 glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY); 309 assert(0); 310 return FALSE; 311 } 312 } 313 else 314 name = handle; 315 316 image = _glamor_egl_create_image(glamor_egl, 317 pixmap->drawable.width, 318 pixmap->drawable.height, 319 ((stride * 8 + 320 7) / pixmap->drawable.bitsPerPixel), 321 name, pixmap->drawable.depth); 322 if (image == EGL_NO_IMAGE_KHR) { 323 glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY); 324 goto done; 325 } 326 glamor_create_texture_from_image(screen, image, &texture); 327 glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); 328 glamor_set_pixmap_texture(pixmap, texture); 329 glamor_egl_set_pixmap_image(pixmap, image); 330 ret = TRUE; 331 332 done: 333 return ret; 334} 335 336Bool 337glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap, void *bo) 338{ 339 ScreenPtr screen = pixmap->drawable.pScreen; 340 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 341 struct glamor_screen_private *glamor_priv = 342 glamor_get_screen_private(screen); 343 struct glamor_egl_screen_private *glamor_egl; 344 EGLImageKHR image; 345 GLuint texture; 346 Bool ret = FALSE; 347 348 glamor_egl = glamor_egl_get_screen_private(scrn); 349 350 glamor_make_current(glamor_priv); 351 352 image = eglCreateImageKHR(glamor_egl->display, 353 glamor_egl->context, 354 EGL_NATIVE_PIXMAP_KHR, bo, NULL); 355 if (image == EGL_NO_IMAGE_KHR) { 356 glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY); 357 goto done; 358 } 359 glamor_create_texture_from_image(screen, image, &texture); 360 glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); 361 glamor_set_pixmap_texture(pixmap, texture); 362 glamor_egl_set_pixmap_image(pixmap, image); 363 ret = TRUE; 364 365 done: 366 return ret; 367} 368 369#ifdef GLAMOR_HAS_GBM 370int glamor_get_fd_from_bo(int gbm_fd, struct gbm_bo *bo, int *fd); 371void glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name); 372int 373glamor_get_fd_from_bo(int gbm_fd, struct gbm_bo *bo, int *fd) 374{ 375 union gbm_bo_handle handle; 376 struct drm_prime_handle args; 377 378 handle = gbm_bo_get_handle(bo); 379 args.handle = handle.u32; 380 args.flags = DRM_CLOEXEC; 381 if (ioctl(gbm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args)) 382 return FALSE; 383 *fd = args.fd; 384 return TRUE; 385} 386 387void 388glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name) 389{ 390 union gbm_bo_handle handle; 391 392 handle = gbm_bo_get_handle(bo); 393 if (!glamor_get_flink_name(gbm_fd, handle.u32, name)) 394 *name = -1; 395} 396#endif 397 398static Bool 399glamor_make_pixmap_exportable(PixmapPtr pixmap) 400{ 401#ifdef GLAMOR_HAS_GBM 402 ScreenPtr screen = pixmap->drawable.pScreen; 403 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 404 struct glamor_egl_screen_private *glamor_egl = 405 glamor_egl_get_screen_private(scrn); 406 struct glamor_pixmap_private *pixmap_priv = 407 glamor_get_pixmap_private(pixmap); 408 unsigned width = pixmap->drawable.width; 409 unsigned height = pixmap->drawable.height; 410 struct gbm_bo *bo; 411 PixmapPtr exported; 412 GCPtr scratch_gc; 413 414 if (pixmap_priv->image) 415 return TRUE; 416 417 if (pixmap->drawable.bitsPerPixel != 32) { 418 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 419 "Failed to make %dbpp pixmap exportable\n", 420 pixmap->drawable.bitsPerPixel); 421 return FALSE; 422 } 423 424 bo = gbm_bo_create(glamor_egl->gbm, width, height, 425 GBM_FORMAT_ARGB8888, 426#ifdef GLAMOR_HAS_GBM_LINEAR 427 (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ? 428 GBM_BO_USE_LINEAR : 0) | 429#endif 430 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); 431 if (!bo) { 432 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 433 "Failed to make %dx%dx%dbpp GBM bo\n", 434 width, height, pixmap->drawable.bitsPerPixel); 435 return FALSE; 436 } 437 438 exported = screen->CreatePixmap(screen, 0, 0, pixmap->drawable.depth, 0); 439 screen->ModifyPixmapHeader(exported, width, height, 0, 0, 440 gbm_bo_get_stride(bo), NULL); 441 if (!glamor_egl_create_textured_pixmap_from_gbm_bo(exported, bo)) { 442 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 443 "Failed to make %dx%dx%dbpp pixmap from GBM bo\n", 444 width, height, pixmap->drawable.bitsPerPixel); 445 screen->DestroyPixmap(exported); 446 gbm_bo_destroy(bo); 447 return FALSE; 448 } 449 gbm_bo_destroy(bo); 450 451 scratch_gc = GetScratchGC(pixmap->drawable.depth, screen); 452 ValidateGC(&pixmap->drawable, scratch_gc); 453 scratch_gc->ops->CopyArea(&pixmap->drawable, &exported->drawable, 454 scratch_gc, 455 0, 0, width, height, 0, 0); 456 FreeScratchGC(scratch_gc); 457 458 /* Now, swap the tex/gbm/EGLImage/etc. of the exported pixmap into 459 * the original pixmap struct. 460 */ 461 glamor_egl_exchange_buffers(pixmap, exported); 462 463 screen->DestroyPixmap(exported); 464 465 return TRUE; 466#else 467 return FALSE; 468#endif 469} 470 471void * 472glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) 473{ 474 struct glamor_egl_screen_private *glamor_egl = 475 glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 476 struct glamor_pixmap_private *pixmap_priv = 477 glamor_get_pixmap_private(pixmap); 478 479 if (!glamor_make_pixmap_exportable(pixmap)) 480 return NULL; 481 482 return gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, 483 pixmap_priv->image, 0); 484} 485 486int 487glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, 488 PixmapPtr pixmap, 489 unsigned int tex, 490 Bool want_name, CARD16 *stride, CARD32 *size) 491{ 492#ifdef GLAMOR_HAS_GBM 493 struct glamor_egl_screen_private *glamor_egl; 494 struct gbm_bo *bo; 495 int fd = -1; 496 497 glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); 498 499 bo = glamor_gbm_bo_from_pixmap(screen, pixmap); 500 if (!bo) 501 goto failure; 502 503 pixmap->devKind = gbm_bo_get_stride(bo); 504 505 if (want_name) { 506 if (glamor_egl->has_gem) 507 glamor_get_name_from_bo(glamor_egl->fd, bo, &fd); 508 } 509 else { 510 if (glamor_get_fd_from_bo(glamor_egl->fd, bo, &fd)) { 511 } 512 } 513 *stride = pixmap->devKind; 514 *size = pixmap->devKind * gbm_bo_get_height(bo); 515 516 gbm_bo_destroy(bo); 517 failure: 518 return fd; 519#else 520 return -1; 521#endif 522} 523 524_X_EXPORT Bool 525glamor_back_pixmap_from_fd(PixmapPtr pixmap, 526 int fd, 527 CARD16 width, 528 CARD16 height, 529 CARD16 stride, CARD8 depth, CARD8 bpp) 530{ 531#ifdef GLAMOR_HAS_GBM 532 ScreenPtr screen = pixmap->drawable.pScreen; 533 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 534 struct glamor_egl_screen_private *glamor_egl; 535 struct gbm_bo *bo; 536 struct gbm_import_fd_data import_data = { 0 }; 537 Bool ret; 538 539 glamor_egl = glamor_egl_get_screen_private(scrn); 540 541 if (!glamor_egl->dri3_capable) 542 return FALSE; 543 544 if (bpp != 32 || !(depth == 24 || depth == 32) || width == 0 || height == 0) 545 return FALSE; 546 547 import_data.fd = fd; 548 import_data.width = width; 549 import_data.height = height; 550 import_data.stride = stride; 551 import_data.format = GBM_FORMAT_ARGB8888; 552 bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD, &import_data, 0); 553 if (!bo) 554 return FALSE; 555 556 screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL); 557 558 ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo); 559 gbm_bo_destroy(bo); 560 return ret; 561#else 562 return FALSE; 563#endif 564} 565 566_X_EXPORT PixmapPtr 567glamor_pixmap_from_fd(ScreenPtr screen, 568 int fd, 569 CARD16 width, 570 CARD16 height, 571 CARD16 stride, CARD8 depth, CARD8 bpp) 572{ 573#ifdef GLAMOR_HAS_GBM 574 PixmapPtr pixmap; 575 Bool ret; 576 577 pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); 578 ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height, 579 stride, depth, bpp); 580 if (ret == FALSE) { 581 screen->DestroyPixmap(pixmap); 582 return NULL; 583 } 584 return pixmap; 585#else 586 return NULL; 587#endif 588} 589 590void 591glamor_egl_destroy_pixmap_image(PixmapPtr pixmap) 592{ 593 struct glamor_pixmap_private *pixmap_priv = 594 glamor_get_pixmap_private(pixmap); 595 596 if (pixmap_priv->image) { 597 ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen); 598 struct glamor_egl_screen_private *glamor_egl = 599 glamor_egl_get_screen_private(scrn); 600 601 eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image); 602 pixmap_priv->image = NULL; 603 } 604} 605 606_X_EXPORT void 607glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back) 608{ 609 EGLImageKHR temp; 610 struct glamor_pixmap_private *front_priv = 611 glamor_get_pixmap_private(front); 612 struct glamor_pixmap_private *back_priv = 613 glamor_get_pixmap_private(back); 614 615 glamor_pixmap_exchange_fbos(front, back); 616 617 temp = back_priv->image; 618 back_priv->image = front_priv->image; 619 front_priv->image = temp; 620 621 glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM); 622 glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM); 623} 624 625void 626glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap) 627{ 628 glamor_destroy_textured_pixmap(pixmap); 629} 630 631static Bool 632glamor_egl_close_screen(ScreenPtr screen) 633{ 634 ScrnInfoPtr scrn; 635 struct glamor_egl_screen_private *glamor_egl; 636 struct glamor_pixmap_private *pixmap_priv; 637 PixmapPtr screen_pixmap; 638 639 scrn = xf86ScreenToScrn(screen); 640 glamor_egl = glamor_egl_get_screen_private(scrn); 641 screen_pixmap = screen->GetScreenPixmap(screen); 642 pixmap_priv = glamor_get_pixmap_private(screen_pixmap); 643 644 eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image); 645 pixmap_priv->image = NULL; 646 647 screen->CloseScreen = glamor_egl->saved_close_screen; 648 649 return screen->CloseScreen(screen); 650} 651 652#ifdef DRI3 653static int 654glamor_dri3_open_client(ClientPtr client, 655 ScreenPtr screen, 656 RRProviderPtr provider, 657 int *fdp) 658{ 659 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 660 struct glamor_egl_screen_private *glamor_egl = 661 glamor_egl_get_screen_private(scrn); 662 int fd; 663 drm_magic_t magic; 664 665 fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC); 666 if (fd < 0) 667 return BadAlloc; 668 669 /* Before FD passing in the X protocol with DRI3 (and increased 670 * security of rendering with per-process address spaces on the 671 * GPU), the kernel had to come up with a way to have the server 672 * decide which clients got to access the GPU, which was done by 673 * each client getting a unique (magic) number from the kernel, 674 * passing it to the server, and the server then telling the 675 * kernel which clients were authenticated for using the device. 676 * 677 * Now that we have FD passing, the server can just set up the 678 * authentication on its own and hand the prepared FD off to the 679 * client. 680 */ 681 if (drmGetMagic(fd, &magic) < 0) { 682 if (errno == EACCES) { 683 /* Assume that we're on a render node, and the fd is 684 * already as authenticated as it should be. 685 */ 686 *fdp = fd; 687 return Success; 688 } else { 689 close(fd); 690 return BadMatch; 691 } 692 } 693 694 if (drmAuthMagic(glamor_egl->fd, magic) < 0) { 695 close(fd); 696 return BadMatch; 697 } 698 699 *fdp = fd; 700 return Success; 701} 702 703static dri3_screen_info_rec glamor_dri3_info = { 704 .version = 1, 705 .open_client = glamor_dri3_open_client, 706 .pixmap_from_fd = glamor_pixmap_from_fd, 707 .fd_from_pixmap = glamor_fd_from_pixmap, 708}; 709#endif /* DRI3 */ 710 711void 712glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) 713{ 714 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 715 struct glamor_egl_screen_private *glamor_egl = 716 glamor_egl_get_screen_private(scrn); 717 718 glamor_egl->saved_close_screen = screen->CloseScreen; 719 screen->CloseScreen = glamor_egl_close_screen; 720 721 glamor_ctx->ctx = glamor_egl->context; 722 glamor_ctx->display = glamor_egl->display; 723 724 glamor_ctx->make_current = glamor_egl_make_current; 725 726#ifdef DRI3 727 if (glamor_egl->dri3_capable) { 728 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 729 /* Tell the core that we have the interfaces for import/export 730 * of pixmaps. 731 */ 732 glamor_enable_dri3(screen); 733 734 /* If the driver wants to do its own auth dance (e.g. Xwayland 735 * on pre-3.15 kernels that don't have render nodes and thus 736 * has the wayland compositor as a master), then it needs us 737 * to stay out of the way and let it init DRI3 on its own. 738 */ 739 if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) { 740 /* To do DRI3 device FD generation, we need to open a new fd 741 * to the same device we were handed in originally. 742 */ 743 glamor_egl->device_path = drmGetDeviceNameFromFd(glamor_egl->fd); 744 745 if (!dri3_screen_init(screen, &glamor_dri3_info)) { 746 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 747 "Failed to initialize DRI3.\n"); 748 } 749 } 750 } 751#endif 752} 753 754static void glamor_egl_cleanup(struct glamor_egl_screen_private *glamor_egl) 755{ 756 if (glamor_egl->display != EGL_NO_DISPLAY) { 757 eglMakeCurrent(glamor_egl->display, 758 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 759 eglTerminate(glamor_egl->display); 760 } 761#ifdef GLAMOR_HAS_GBM 762 if (glamor_egl->gbm) 763 gbm_device_destroy(glamor_egl->gbm); 764#endif 765 free(glamor_egl->device_path); 766 free(glamor_egl); 767} 768 769static void 770glamor_egl_free_screen(ScrnInfoPtr scrn) 771{ 772 struct glamor_egl_screen_private *glamor_egl; 773 774 glamor_egl = glamor_egl_get_screen_private(scrn); 775 if (glamor_egl != NULL) { 776 scrn->FreeScreen = glamor_egl->saved_free_screen; 777 glamor_egl_cleanup(glamor_egl); 778 scrn->FreeScreen(scrn); 779 } 780} 781 782Bool 783glamor_egl_init(ScrnInfoPtr scrn, int fd) 784{ 785 struct glamor_egl_screen_private *glamor_egl; 786 const char *version; 787 788 EGLint config_attribs[] = { 789#ifdef GLAMOR_GLES2 790 EGL_CONTEXT_CLIENT_VERSION, 2, 791#endif 792 EGL_NONE 793 }; 794 static const EGLint config_attribs_core[] = { 795 EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, 796 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, 797 EGL_CONTEXT_MAJOR_VERSION_KHR, 798 GLAMOR_GL_CORE_VER_MAJOR, 799 EGL_CONTEXT_MINOR_VERSION_KHR, 800 GLAMOR_GL_CORE_VER_MINOR, 801 EGL_NONE 802 }; 803 804 glamor_identify(0); 805 glamor_egl = calloc(sizeof(*glamor_egl), 1); 806 if (glamor_egl == NULL) 807 return FALSE; 808 if (xf86GlamorEGLPrivateIndex == -1) 809 xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); 810 811 scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl; 812 glamor_egl->fd = fd; 813#ifdef GLAMOR_HAS_GBM 814 glamor_egl->gbm = gbm_create_device(glamor_egl->fd); 815 if (glamor_egl->gbm == NULL) { 816 ErrorF("couldn't get display device\n"); 817 goto error; 818 } 819 glamor_egl->display = eglGetDisplay(glamor_egl->gbm); 820#else 821 glamor_egl->display = eglGetDisplay((EGLNativeDisplayType) (intptr_t) fd); 822#endif 823 824 glamor_egl->has_gem = glamor_egl_check_has_gem(fd); 825 826 if (!eglInitialize 827 (glamor_egl->display, &glamor_egl->major, &glamor_egl->minor)) { 828 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n"); 829 glamor_egl->display = EGL_NO_DISPLAY; 830 goto error; 831 } 832 833#ifndef GLAMOR_GLES2 834 eglBindAPI(EGL_OPENGL_API); 835#else 836 eglBindAPI(EGL_OPENGL_ES_API); 837#endif 838 839 version = eglQueryString(glamor_egl->display, EGL_VERSION); 840 xf86Msg(X_INFO, "%s: EGL version %s:\n", glamor_name, version); 841 842#define GLAMOR_CHECK_EGL_EXTENSION(EXT) \ 843 if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) { \ 844 ErrorF("EGL_" #EXT " required.\n"); \ 845 goto error; \ 846 } 847 848#define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2) \ 849 if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) && \ 850 !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) { \ 851 ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n"); \ 852 goto error; \ 853 } 854 855 GLAMOR_CHECK_EGL_EXTENSION(MESA_drm_image); 856 GLAMOR_CHECK_EGL_EXTENSION(KHR_gl_renderbuffer_image); 857#ifdef GLAMOR_GLES2 858 GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, KHR_surfaceless_gles2); 859#else 860 GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, 861 KHR_surfaceless_opengl); 862#endif 863 864#ifndef GLAMOR_GLES2 865 glamor_egl->context = eglCreateContext(glamor_egl->display, 866 NULL, EGL_NO_CONTEXT, 867 config_attribs_core); 868#else 869 glamor_egl->context = NULL; 870#endif 871 if (!glamor_egl->context) { 872 glamor_egl->context = eglCreateContext(glamor_egl->display, 873 NULL, EGL_NO_CONTEXT, 874 config_attribs); 875 if (glamor_egl->context == EGL_NO_CONTEXT) { 876 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create EGL context\n"); 877 goto error; 878 } 879 } 880 881 if (!eglMakeCurrent(glamor_egl->display, 882 EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) { 883 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 884 "Failed to make EGL context current\n"); 885 goto error; 886 } 887#ifdef GLAMOR_HAS_GBM 888 if (epoxy_has_egl_extension(glamor_egl->display, 889 "EGL_KHR_gl_texture_2D_image") && 890 epoxy_has_gl_extension("GL_OES_EGL_image")) 891 glamor_egl->dri3_capable = TRUE; 892#endif 893 894 glamor_egl->saved_free_screen = scrn->FreeScreen; 895 scrn->FreeScreen = glamor_egl_free_screen; 896#ifdef GLAMOR_GLES2 897 xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using GLES2.\n"); 898 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 899 "Glamor is using GLES2 but GLX needs GL. " 900 "Indirect GLX may not work correctly.\n"); 901#endif 902 return TRUE; 903 904error: 905 glamor_egl_cleanup(glamor_egl); 906 return FALSE; 907} 908 909/** Stub to retain compatibility with pre-server-1.16 ABI. */ 910Bool 911glamor_egl_init_textured_pixmap(ScreenPtr screen) 912{ 913 return TRUE; 914} 915