driver.c revision 806e81e9
1/* 2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 3 * Copyright 2011 Dave Airlie 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * 27 * Original Author: Alan Hourihane <alanh@tungstengraphics.com> 28 * Rewrite: Dave Airlie <airlied@redhat.com> 29 * 30 */ 31 32#ifdef HAVE_DIX_CONFIG_H 33#include "dix-config.h" 34#endif 35 36#include <unistd.h> 37#include <fcntl.h> 38#include "xf86.h" 39#include "xf86Priv.h" 40#include "xf86_OSproc.h" 41#include "compiler.h" 42#include "xf86Pci.h" 43#include "mipointer.h" 44#include "mipointrst.h" 45#include "micmap.h" 46#include <X11/extensions/randr.h> 47#include "fb.h" 48#include "edid.h" 49#include "xf86i2c.h" 50#include "xf86Crtc.h" 51#include "miscstruct.h" 52#include "dixstruct.h" 53#include "shadow.h" 54#include "xf86xv.h" 55#include <X11/extensions/Xv.h> 56#include <xorg-config.h> 57#ifdef XSERVER_PLATFORM_BUS 58#include "xf86platformBus.h" 59#endif 60#ifdef XSERVER_LIBPCIACCESS 61#include <pciaccess.h> 62#endif 63 64#include "driver.h" 65 66static void AdjustFrame(ScrnInfoPtr pScrn, int x, int y); 67static Bool CloseScreen(ScreenPtr pScreen); 68static Bool EnterVT(ScrnInfoPtr pScrn); 69static void Identify(int flags); 70static const OptionInfoRec *AvailableOptions(int chipid, int busid); 71static ModeStatus ValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode, 72 Bool verbose, int flags); 73static void FreeScreen(ScrnInfoPtr pScrn); 74static void LeaveVT(ScrnInfoPtr pScrn); 75static Bool SwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode); 76static Bool ScreenInit(ScreenPtr pScreen, int argc, char **argv); 77static Bool PreInit(ScrnInfoPtr pScrn, int flags); 78 79static Bool Probe(DriverPtr drv, int flags); 80static Bool ms_pci_probe(DriverPtr driver, 81 int entity_num, struct pci_device *device, 82 intptr_t match_data); 83static Bool ms_driver_func(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data); 84 85#ifdef XSERVER_LIBPCIACCESS 86static const struct pci_id_match ms_device_match[] = { 87 { 88 PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 89 0x00030000, 0x00ff0000, 0}, 90 91 {0, 0, 0}, 92}; 93#endif 94 95#ifndef XSERVER_PLATFORM_BUS 96struct xf86_platform_device; 97#endif 98 99#ifdef XSERVER_PLATFORM_BUS 100static Bool ms_platform_probe(DriverPtr driver, 101 int entity_num, int flags, 102 struct xf86_platform_device *device, 103 intptr_t match_data); 104#endif 105 106_X_EXPORT DriverRec modesetting = { 107 1, 108 "modesetting", 109 Identify, 110 Probe, 111 AvailableOptions, 112 NULL, 113 0, 114 ms_driver_func, 115 ms_device_match, 116 ms_pci_probe, 117#ifdef XSERVER_PLATFORM_BUS 118 ms_platform_probe, 119#endif 120}; 121 122static SymTabRec Chipsets[] = { 123 {0, "kms"}, 124 {-1, NULL} 125}; 126 127static const OptionInfoRec Options[] = { 128 {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, 129 {OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE}, 130 {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE}, 131 {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE}, 132 {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE}, 133 {OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE}, 134 {OPTION_DOUBLE_SHADOW, "DoubleShadow", OPTV_BOOLEAN, {0}, FALSE}, 135 {OPTION_ATOMIC, "Atomic", OPTV_BOOLEAN, {0}, FALSE}, 136 {-1, NULL, OPTV_NONE, {0}, FALSE} 137}; 138 139int ms_entity_index = -1; 140 141static MODULESETUPPROTO(Setup); 142 143static XF86ModuleVersionInfo VersRec = { 144 "modesetting", 145 MODULEVENDORSTRING, 146 MODINFOSTRING1, 147 MODINFOSTRING2, 148 XORG_VERSION_CURRENT, 149 XORG_VERSION_MAJOR, 150 XORG_VERSION_MINOR, 151 XORG_VERSION_PATCH, 152 ABI_CLASS_VIDEODRV, 153 ABI_VIDEODRV_VERSION, 154 MOD_CLASS_VIDEODRV, 155 {0, 0, 0, 0} 156}; 157 158_X_EXPORT XF86ModuleData modesettingModuleData = { &VersRec, Setup, NULL }; 159 160static void * 161Setup(void *module, void *opts, int *errmaj, int *errmin) 162{ 163 static Bool setupDone = 0; 164 165 /* This module should be loaded only once, but check to be sure. 166 */ 167 if (!setupDone) { 168 setupDone = 1; 169 xf86AddDriver(&modesetting, module, HaveDriverFuncs); 170 171 /* 172 * The return value must be non-NULL on success even though there 173 * is no TearDownProc. 174 */ 175 return (void *) 1; 176 } 177 else { 178 if (errmaj) 179 *errmaj = LDR_ONCEONLY; 180 return NULL; 181 } 182} 183 184static void 185Identify(int flags) 186{ 187 xf86PrintChipsets("modesetting", "Driver for Modesetting Kernel Drivers", 188 Chipsets); 189} 190 191modesettingEntPtr ms_ent_priv(ScrnInfoPtr scrn) 192{ 193 DevUnion *pPriv; 194 modesettingPtr ms = modesettingPTR(scrn); 195 pPriv = xf86GetEntityPrivate(ms->pEnt->index, 196 ms_entity_index); 197 return pPriv->ptr; 198} 199 200static int 201get_passed_fd(void) 202{ 203 if (xf86DRMMasterFd >= 0) { 204 xf86DrvMsg(-1, X_INFO, "Using passed DRM master file descriptor %d\n", xf86DRMMasterFd); 205 return dup(xf86DRMMasterFd); 206 } 207 return -1; 208} 209 210static int 211open_hw(const char *dev) 212{ 213 int fd; 214 215 if ((fd = get_passed_fd()) != -1) 216 return fd; 217 218 if (dev) 219 fd = open(dev, O_RDWR | O_CLOEXEC, 0); 220 else { 221 dev = getenv("KMSDEVICE"); 222 if ((NULL == dev) || ((fd = open(dev, O_RDWR | O_CLOEXEC, 0)) == -1)) { 223 dev = "/dev/dri/card0"; 224 fd = open(dev, O_RDWR | O_CLOEXEC, 0); 225 } 226 } 227 if (fd == -1) 228 xf86DrvMsg(-1, X_ERROR, "open %s: %s\n", dev, strerror(errno)); 229 230 return fd; 231} 232 233static int 234check_outputs(int fd, int *count) 235{ 236 drmModeResPtr res = drmModeGetResources(fd); 237 int ret; 238 239 if (!res) 240 return FALSE; 241 242 if (count) 243 *count = res->count_connectors; 244 245 ret = res->count_connectors > 0; 246#if defined(GLAMOR_HAS_GBM_LINEAR) 247 if (ret == FALSE) { 248 uint64_t value = 0; 249 if (drmGetCap(fd, DRM_CAP_PRIME, &value) == 0 && 250 (value & DRM_PRIME_CAP_EXPORT)) 251 ret = TRUE; 252 } 253#endif 254 drmModeFreeResources(res); 255 return ret; 256} 257 258static Bool 259probe_hw(const char *dev, struct xf86_platform_device *platform_dev) 260{ 261 int fd; 262 263#ifdef XF86_PDEV_SERVER_FD 264 if (platform_dev && (platform_dev->flags & XF86_PDEV_SERVER_FD)) { 265 fd = xf86_platform_device_odev_attributes(platform_dev)->fd; 266 if (fd == -1) 267 return FALSE; 268 return check_outputs(fd, NULL); 269 } 270#endif 271 272 fd = open_hw(dev); 273 if (fd != -1) { 274 int ret = check_outputs(fd, NULL); 275 276 close(fd); 277 return ret; 278 } 279 return FALSE; 280} 281 282static char * 283ms_DRICreatePCIBusID(const struct pci_device *dev) 284{ 285 char *busID; 286 287 if (asprintf(&busID, "pci:%04x:%02x:%02x.%d", 288 dev->domain, dev->bus, dev->dev, dev->func) == -1) 289 return NULL; 290 291 return busID; 292} 293 294static Bool 295probe_hw_pci(const char *dev, struct pci_device *pdev) 296{ 297 int ret = FALSE, fd = open_hw(dev); 298 char *id, *devid; 299 drmSetVersion sv; 300 301 if (fd == -1) 302 return FALSE; 303 304 sv.drm_di_major = 1; 305 sv.drm_di_minor = 4; 306 sv.drm_dd_major = -1; 307 sv.drm_dd_minor = -1; 308 if (drmSetInterfaceVersion(fd, &sv)) { 309 close(fd); 310 return FALSE; 311 } 312 313 id = drmGetBusid(fd); 314 devid = ms_DRICreatePCIBusID(pdev); 315 316 if (id && devid && !strcmp(id, devid)) 317 ret = check_outputs(fd, NULL); 318 319 close(fd); 320 free(id); 321 free(devid); 322 return ret; 323} 324 325static const OptionInfoRec * 326AvailableOptions(int chipid, int busid) 327{ 328 return Options; 329} 330 331static Bool 332ms_driver_func(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data) 333{ 334 xorgHWFlags *flag; 335 336 switch (op) { 337 case GET_REQUIRED_HW_INTERFACES: 338 flag = (CARD32 *) data; 339 (*flag) = 0; 340 return TRUE; 341 case SUPPORTS_SERVER_FDS: 342 return TRUE; 343 default: 344 return FALSE; 345 } 346} 347 348static void 349ms_setup_scrn_hooks(ScrnInfoPtr scrn) 350{ 351 scrn->driverVersion = 1; 352 scrn->driverName = "modesetting"; 353 scrn->name = "modeset"; 354 355 scrn->Probe = NULL; 356 scrn->PreInit = PreInit; 357 scrn->ScreenInit = ScreenInit; 358 scrn->SwitchMode = SwitchMode; 359 scrn->AdjustFrame = AdjustFrame; 360 scrn->EnterVT = EnterVT; 361 scrn->LeaveVT = LeaveVT; 362 scrn->FreeScreen = FreeScreen; 363 scrn->ValidMode = ValidMode; 364} 365 366static void 367ms_setup_entity(ScrnInfoPtr scrn, int entity_num) 368{ 369 DevUnion *pPriv; 370 371 xf86SetEntitySharable(entity_num); 372 373 if (ms_entity_index == -1) 374 ms_entity_index = xf86AllocateEntityPrivateIndex(); 375 376 pPriv = xf86GetEntityPrivate(entity_num, 377 ms_entity_index); 378 379 xf86SetEntityInstanceForScreen(scrn, entity_num, xf86GetNumEntityInstances(entity_num) - 1); 380 381 if (!pPriv->ptr) 382 pPriv->ptr = xnfcalloc(sizeof(modesettingEntRec), 1); 383} 384 385#ifdef XSERVER_LIBPCIACCESS 386static Bool 387ms_pci_probe(DriverPtr driver, 388 int entity_num, struct pci_device *dev, intptr_t match_data) 389{ 390 ScrnInfoPtr scrn = NULL; 391 392 scrn = xf86ConfigPciEntity(scrn, 0, entity_num, NULL, 393 NULL, NULL, NULL, NULL, NULL); 394 if (scrn) { 395 const char *devpath; 396 GDevPtr devSection = xf86GetDevFromEntity(scrn->entityList[0], 397 scrn->entityInstanceList[0]); 398 399 devpath = xf86FindOptionValue(devSection->options, "kmsdev"); 400 if (probe_hw_pci(devpath, dev)) { 401 ms_setup_scrn_hooks(scrn); 402 403 xf86DrvMsg(scrn->scrnIndex, X_CONFIG, 404 "claimed PCI slot %d@%d:%d:%d\n", 405 dev->bus, dev->domain, dev->dev, dev->func); 406 xf86DrvMsg(scrn->scrnIndex, X_INFO, 407 "using %s\n", devpath ? devpath : "default device"); 408 409 ms_setup_entity(scrn, entity_num); 410 } 411 else 412 scrn = NULL; 413 } 414 return scrn != NULL; 415} 416#endif 417 418#ifdef XSERVER_PLATFORM_BUS 419static Bool 420ms_platform_probe(DriverPtr driver, 421 int entity_num, int flags, struct xf86_platform_device *dev, 422 intptr_t match_data) 423{ 424 ScrnInfoPtr scrn = NULL; 425 const char *path = xf86_platform_device_odev_attributes(dev)->path; 426 int scr_flags = 0; 427 428 if (flags & PLATFORM_PROBE_GPU_SCREEN) 429 scr_flags = XF86_ALLOCATE_GPU_SCREEN; 430 431 if (probe_hw(path, dev)) { 432 scrn = xf86AllocateScreen(driver, scr_flags); 433 if (xf86IsEntitySharable(entity_num)) 434 xf86SetEntityShared(entity_num); 435 xf86AddEntityToScreen(scrn, entity_num); 436 437 ms_setup_scrn_hooks(scrn); 438 439 xf86DrvMsg(scrn->scrnIndex, X_INFO, 440 "using drv %s\n", path ? path : "default device"); 441 442 ms_setup_entity(scrn, entity_num); 443 } 444 445 return scrn != NULL; 446} 447#endif 448 449static Bool 450Probe(DriverPtr drv, int flags) 451{ 452 int i, numDevSections; 453 GDevPtr *devSections; 454 Bool foundScreen = FALSE; 455 const char *dev; 456 ScrnInfoPtr scrn = NULL; 457 458 /* For now, just bail out for PROBE_DETECT. */ 459 if (flags & PROBE_DETECT) 460 return FALSE; 461 462 /* 463 * Find the config file Device sections that match this 464 * driver, and return if there are none. 465 */ 466 if ((numDevSections = xf86MatchDevice("modesetting", &devSections)) <= 0) { 467 return FALSE; 468 } 469 470 for (i = 0; i < numDevSections; i++) { 471 int entity_num; 472 dev = xf86FindOptionValue(devSections[i]->options, "kmsdev"); 473 if (probe_hw(dev, NULL)) { 474 475 entity_num = xf86ClaimFbSlot(drv, 0, devSections[i], TRUE); 476 scrn = xf86ConfigFbEntity(scrn, 0, entity_num, NULL, NULL, NULL, NULL); 477 } 478 479 if (scrn) { 480 foundScreen = TRUE; 481 ms_setup_scrn_hooks(scrn); 482 scrn->Probe = Probe; 483 484 xf86DrvMsg(scrn->scrnIndex, X_INFO, 485 "using %s\n", dev ? dev : "default device"); 486 ms_setup_entity(scrn, entity_num); 487 } 488 } 489 490 free(devSections); 491 492 return foundScreen; 493} 494 495static Bool 496GetRec(ScrnInfoPtr pScrn) 497{ 498 if (pScrn->driverPrivate) 499 return TRUE; 500 501 pScrn->driverPrivate = xnfcalloc(sizeof(modesettingRec), 1); 502 503 return TRUE; 504} 505 506static int 507dispatch_dirty_region(ScrnInfoPtr scrn, 508 PixmapPtr pixmap, DamagePtr damage, int fb_id) 509{ 510 modesettingPtr ms = modesettingPTR(scrn); 511 RegionPtr dirty = DamageRegion(damage); 512 unsigned num_cliprects = REGION_NUM_RECTS(dirty); 513 int ret = 0; 514 515 if (num_cliprects) { 516 drmModeClip *clip = xallocarray(num_cliprects, sizeof(drmModeClip)); 517 BoxPtr rect = REGION_RECTS(dirty); 518 int i; 519 520 if (!clip) 521 return -ENOMEM; 522 523 /* XXX no need for copy? */ 524 for (i = 0; i < num_cliprects; i++, rect++) { 525 clip[i].x1 = rect->x1; 526 clip[i].y1 = rect->y1; 527 clip[i].x2 = rect->x2; 528 clip[i].y2 = rect->y2; 529 } 530 531 /* TODO query connector property to see if this is needed */ 532 ret = drmModeDirtyFB(ms->fd, fb_id, clip, num_cliprects); 533 534 /* if we're swamping it with work, try one at a time */ 535 if (ret == -EINVAL) { 536 for (i = 0; i < num_cliprects; i++) { 537 if ((ret = drmModeDirtyFB(ms->fd, fb_id, &clip[i], 1)) < 0) 538 break; 539 } 540 } 541 542 free(clip); 543 DamageEmpty(damage); 544 } 545 return ret; 546} 547 548static void 549dispatch_dirty(ScreenPtr pScreen) 550{ 551 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 552 modesettingPtr ms = modesettingPTR(scrn); 553 PixmapPtr pixmap = pScreen->GetScreenPixmap(pScreen); 554 int fb_id = ms->drmmode.fb_id; 555 int ret; 556 557 ret = dispatch_dirty_region(scrn, pixmap, ms->damage, fb_id); 558 if (ret == -EINVAL || ret == -ENOSYS) { 559 ms->dirty_enabled = FALSE; 560 DamageUnregister(ms->damage); 561 DamageDestroy(ms->damage); 562 ms->damage = NULL; 563 xf86DrvMsg(scrn->scrnIndex, X_INFO, 564 "Disabling kernel dirty updates, not required.\n"); 565 return; 566 } 567} 568 569static void 570dispatch_dirty_pixmap(ScrnInfoPtr scrn, xf86CrtcPtr crtc, PixmapPtr ppix) 571{ 572 modesettingPtr ms = modesettingPTR(scrn); 573 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix); 574 DamagePtr damage = ppriv->slave_damage; 575 int fb_id = ppriv->fb_id; 576 577 dispatch_dirty_region(scrn, ppix, damage, fb_id); 578} 579 580static void 581dispatch_slave_dirty(ScreenPtr pScreen) 582{ 583 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 584 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 585 int c; 586 587 for (c = 0; c < xf86_config->num_crtc; c++) { 588 xf86CrtcPtr crtc = xf86_config->crtc[c]; 589 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 590 591 if (!drmmode_crtc) 592 continue; 593 594 if (drmmode_crtc->prime_pixmap) 595 dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap); 596 if (drmmode_crtc->prime_pixmap_back) 597 dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap_back); 598 } 599} 600 601static void 602redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty, int *timeout) 603{ 604 RegionRec pixregion; 605 606 PixmapRegionInit(&pixregion, dirty->slave_dst); 607 DamageRegionAppend(&dirty->slave_dst->drawable, &pixregion); 608 PixmapSyncDirtyHelper(dirty); 609 610 if (!screen->isGPU) { 611#ifdef GLAMOR_HAS_GBM 612 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen)); 613 /* 614 * When copying from the master framebuffer to the shared pixmap, 615 * we must ensure the copy is complete before the slave starts a 616 * copy to its own framebuffer (some slaves scanout directly from 617 * the shared pixmap, but not all). 618 */ 619 if (ms->drmmode.glamor) 620 glamor_finish(screen); 621#endif 622 /* Ensure the slave processes the damage immediately */ 623 if (timeout) 624 *timeout = 0; 625 } 626 627 DamageRegionProcessPending(&dirty->slave_dst->drawable); 628 RegionUninit(&pixregion); 629} 630 631static void 632ms_dirty_update(ScreenPtr screen, int *timeout) 633{ 634 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen)); 635 636 RegionPtr region; 637 PixmapDirtyUpdatePtr ent; 638 639 if (xorg_list_is_empty(&screen->pixmap_dirty_list)) 640 return; 641 642 xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) { 643 region = DamageRegion(ent->damage); 644 if (RegionNotEmpty(region)) { 645 if (!screen->isGPU) { 646 msPixmapPrivPtr ppriv = 647 msGetPixmapPriv(&ms->drmmode, ent->slave_dst->master_pixmap); 648 649 if (ppriv->notify_on_damage) { 650 ppriv->notify_on_damage = FALSE; 651 652 ent->slave_dst->drawable.pScreen-> 653 SharedPixmapNotifyDamage(ent->slave_dst); 654 } 655 656 /* Requested manual updating */ 657 if (ppriv->defer_dirty_update) 658 continue; 659 } 660 661 redisplay_dirty(screen, ent, timeout); 662 DamageEmpty(ent->damage); 663 } 664 } 665} 666 667static PixmapDirtyUpdatePtr 668ms_dirty_get_ent(ScreenPtr screen, PixmapPtr slave_dst) 669{ 670 PixmapDirtyUpdatePtr ent; 671 672 if (xorg_list_is_empty(&screen->pixmap_dirty_list)) 673 return NULL; 674 675 xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) { 676 if (ent->slave_dst == slave_dst) 677 return ent; 678 } 679 680 return NULL; 681} 682 683static void 684msBlockHandler(ScreenPtr pScreen, void *timeout) 685{ 686 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen)); 687 688 pScreen->BlockHandler = ms->BlockHandler; 689 pScreen->BlockHandler(pScreen, timeout); 690 ms->BlockHandler = pScreen->BlockHandler; 691 pScreen->BlockHandler = msBlockHandler; 692 if (pScreen->isGPU && !ms->drmmode.reverse_prime_offload_mode) 693 dispatch_slave_dirty(pScreen); 694 else if (ms->dirty_enabled) 695 dispatch_dirty(pScreen); 696 697 ms_dirty_update(pScreen, timeout); 698} 699 700static void 701msBlockHandler_oneshot(ScreenPtr pScreen, void *pTimeout) 702{ 703 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 704 modesettingPtr ms = modesettingPTR(pScrn); 705 706 msBlockHandler(pScreen, pTimeout); 707 708 drmmode_set_desired_modes(pScrn, &ms->drmmode, TRUE, FALSE); 709} 710 711static void 712FreeRec(ScrnInfoPtr pScrn) 713{ 714 modesettingPtr ms; 715 716 if (!pScrn) 717 return; 718 719 ms = modesettingPTR(pScrn); 720 if (!ms) 721 return; 722 723 if (ms->fd > 0) { 724 modesettingEntPtr ms_ent; 725 int ret; 726 727 ms_ent = ms_ent_priv(pScrn); 728 ms_ent->fd_ref--; 729 if (!ms_ent->fd_ref) { 730 if (ms->pEnt->location.type == BUS_PCI) 731 ret = drmClose(ms->fd); 732 else 733#ifdef XF86_PDEV_SERVER_FD 734 if (!(ms->pEnt->location.type == BUS_PLATFORM && 735 (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD))) 736#endif 737 ret = close(ms->fd); 738 (void) ret; 739 ms_ent->fd = 0; 740 } 741 } 742 pScrn->driverPrivate = NULL; 743 free(ms->drmmode.Options); 744 free(ms); 745 746} 747 748static void 749try_enable_glamor(ScrnInfoPtr pScrn) 750{ 751 modesettingPtr ms = modesettingPTR(pScrn); 752 const char *accel_method_str = xf86GetOptValString(ms->drmmode.Options, 753 OPTION_ACCEL_METHOD); 754 Bool do_glamor = (!accel_method_str || 755 strcmp(accel_method_str, "glamor") == 0); 756 757 ms->drmmode.glamor = FALSE; 758 759#ifdef GLAMOR_HAS_GBM 760 if (ms->drmmode.force_24_32) { 761 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Cannot use glamor with 24bpp packed fb\n"); 762 return; 763 } 764 765 if (!do_glamor) { 766 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "glamor disabled\n"); 767 return; 768 } 769 770 if (xf86LoadSubModule(pScrn, GLAMOR_EGL_MODULE_NAME)) { 771 if (glamor_egl_init(pScrn, ms->fd)) { 772 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "glamor initialized\n"); 773 ms->drmmode.glamor = TRUE; 774 } else { 775 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 776 "glamor initialization failed\n"); 777 } 778 } else { 779 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 780 "Failed to load glamor module.\n"); 781 } 782#else 783 if (do_glamor) { 784 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 785 "No glamor support in the X Server\n"); 786 } 787#endif 788} 789 790static Bool 791msShouldDoubleShadow(ScrnInfoPtr pScrn, modesettingPtr ms) 792{ 793 Bool ret = FALSE, asked; 794 int from; 795 drmVersionPtr v = drmGetVersion(ms->fd); 796 797 if (!ms->drmmode.shadow_enable) 798 return FALSE; 799 800 if (!strcmp(v->name, "mgag200") || 801 !strcmp(v->name, "ast")) /* XXX || rn50 */ 802 ret = TRUE; 803 804 drmFreeVersion(v); 805 806 asked = xf86GetOptValBool(ms->drmmode.Options, OPTION_DOUBLE_SHADOW, &ret); 807 808 if (asked) 809 from = X_CONFIG; 810 else 811 from = X_INFO; 812 813 xf86DrvMsg(pScrn->scrnIndex, from, 814 "Double-buffered shadow updates: %s\n", ret ? "on" : "off"); 815 816 return ret; 817} 818 819static Bool 820ms_get_drm_master_fd(ScrnInfoPtr pScrn) 821{ 822 EntityInfoPtr pEnt; 823 modesettingPtr ms; 824 modesettingEntPtr ms_ent; 825 826 ms = modesettingPTR(pScrn); 827 ms_ent = ms_ent_priv(pScrn); 828 829 pEnt = ms->pEnt; 830 831 if (ms_ent->fd) { 832 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 833 " reusing fd for second head\n"); 834 ms->fd = ms_ent->fd; 835 ms_ent->fd_ref++; 836 return TRUE; 837 } 838 839 ms->fd_passed = FALSE; 840 if ((ms->fd = get_passed_fd()) >= 0) { 841 ms->fd_passed = TRUE; 842 return TRUE; 843 } 844 845#ifdef XSERVER_PLATFORM_BUS 846 if (pEnt->location.type == BUS_PLATFORM) { 847#ifdef XF86_PDEV_SERVER_FD 848 if (pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD) 849 ms->fd = 850 xf86_platform_device_odev_attributes(pEnt->location.id.plat)-> 851 fd; 852 else 853#endif 854 { 855 char *path = 856 xf86_platform_device_odev_attributes(pEnt->location.id.plat)-> 857 path; 858 ms->fd = open_hw(path); 859 } 860 } 861 else 862#endif 863#ifdef XSERVER_LIBPCIACCESS 864 if (pEnt->location.type == BUS_PCI) { 865 char *BusID = NULL; 866 struct pci_device *PciInfo; 867 868 PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); 869 if (PciInfo) { 870 if ((BusID = ms_DRICreatePCIBusID(PciInfo)) != NULL) { 871 ms->fd = drmOpen(NULL, BusID); 872 free(BusID); 873 } 874 } 875 } 876 else 877#endif 878 { 879 const char *devicename; 880 devicename = xf86FindOptionValue(ms->pEnt->device->options, "kmsdev"); 881 ms->fd = open_hw(devicename); 882 } 883 if (ms->fd < 0) 884 return FALSE; 885 886 ms_ent->fd = ms->fd; 887 ms_ent->fd_ref = 1; 888 return TRUE; 889} 890 891static Bool 892PreInit(ScrnInfoPtr pScrn, int flags) 893{ 894 modesettingPtr ms; 895 rgb defaultWeight = { 0, 0, 0 }; 896 EntityInfoPtr pEnt; 897 uint64_t value = 0; 898 int ret; 899 int bppflags, connector_count; 900 int defaultdepth, defaultbpp; 901 902 if (pScrn->numEntities != 1) 903 return FALSE; 904 905 if (flags & PROBE_DETECT) { 906 return FALSE; 907 } 908 909 /* Allocate driverPrivate */ 910 if (!GetRec(pScrn)) 911 return FALSE; 912 913 pEnt = xf86GetEntityInfo(pScrn->entityList[0]); 914 915 ms = modesettingPTR(pScrn); 916 ms->SaveGeneration = -1; 917 ms->pEnt = pEnt; 918 ms->drmmode.is_secondary = FALSE; 919 pScrn->displayWidth = 640; /* default it */ 920 921 if (xf86IsEntityShared(pScrn->entityList[0])) { 922 if (xf86IsPrimInitDone(pScrn->entityList[0])) 923 ms->drmmode.is_secondary = TRUE; 924 else 925 xf86SetPrimInitDone(pScrn->entityList[0]); 926 } 927 928 pScrn->monitor = pScrn->confScreen->monitor; 929 pScrn->progClock = TRUE; 930 pScrn->rgbBits = 8; 931 932 if (!ms_get_drm_master_fd(pScrn)) 933 return FALSE; 934 ms->drmmode.fd = ms->fd; 935 936 if (!check_outputs(ms->fd, &connector_count)) 937 return FALSE; 938 939 drmmode_get_default_bpp(pScrn, &ms->drmmode, &defaultdepth, &defaultbpp); 940 if (defaultdepth == 24 && defaultbpp == 24) { 941 ms->drmmode.force_24_32 = TRUE; 942 ms->drmmode.kbpp = 24; 943 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 944 "Using 24bpp hw front buffer with 32bpp shadow\n"); 945 defaultbpp = 32; 946 } else { 947 ms->drmmode.kbpp = 0; 948 } 949 bppflags = PreferConvert24to32 | SupportConvert24to32 | Support32bppFb; 950 951 if (!xf86SetDepthBpp 952 (pScrn, defaultdepth, defaultdepth, defaultbpp, bppflags)) 953 return FALSE; 954 955 switch (pScrn->depth) { 956 case 15: 957 case 16: 958 case 24: 959 case 30: 960 break; 961 default: 962 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 963 "Given depth (%d) is not supported by the driver\n", 964 pScrn->depth); 965 return FALSE; 966 } 967 xf86PrintDepthBpp(pScrn); 968 if (!ms->drmmode.kbpp) 969 ms->drmmode.kbpp = pScrn->bitsPerPixel; 970 971 /* Process the options */ 972 xf86CollectOptions(pScrn, NULL); 973 if (!(ms->drmmode.Options = malloc(sizeof(Options)))) 974 return FALSE; 975 memcpy(ms->drmmode.Options, Options, sizeof(Options)); 976 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->drmmode.Options); 977 978 if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) 979 return FALSE; 980 if (!xf86SetDefaultVisual(pScrn, -1)) 981 return FALSE; 982 983 if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_SW_CURSOR, FALSE)) { 984 ms->drmmode.sw_cursor = TRUE; 985 } 986 987 ms->cursor_width = 64; 988 ms->cursor_height = 64; 989 ret = drmGetCap(ms->fd, DRM_CAP_CURSOR_WIDTH, &value); 990 if (!ret) { 991 ms->cursor_width = value; 992 } 993 ret = drmGetCap(ms->fd, DRM_CAP_CURSOR_HEIGHT, &value); 994 if (!ret) { 995 ms->cursor_height = value; 996 } 997 998 try_enable_glamor(pScrn); 999 1000 if (!ms->drmmode.glamor) { 1001 Bool prefer_shadow = TRUE; 1002 1003 if (ms->drmmode.force_24_32) { 1004 prefer_shadow = TRUE; 1005 ms->drmmode.shadow_enable = TRUE; 1006 } else { 1007 ret = drmGetCap(ms->fd, DRM_CAP_DUMB_PREFER_SHADOW, &value); 1008 if (!ret) { 1009 prefer_shadow = !!value; 1010 } 1011 1012 ms->drmmode.shadow_enable = 1013 xf86ReturnOptValBool(ms->drmmode.Options, OPTION_SHADOW_FB, 1014 prefer_shadow); 1015 } 1016 1017 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1018 "ShadowFB: preferred %s, enabled %s\n", 1019 prefer_shadow ? "YES" : "NO", 1020 ms->drmmode.force_24_32 ? "FORCE" : 1021 ms->drmmode.shadow_enable ? "YES" : "NO"); 1022 1023 ms->drmmode.shadow_enable2 = msShouldDoubleShadow(pScrn, ms); 1024 } 1025 1026 ms->drmmode.pageflip = 1027 xf86ReturnOptValBool(ms->drmmode.Options, OPTION_PAGEFLIP, TRUE); 1028 1029 pScrn->capabilities = 0; 1030 ret = drmGetCap(ms->fd, DRM_CAP_PRIME, &value); 1031 if (ret == 0) { 1032 if (connector_count && (value & DRM_PRIME_CAP_IMPORT)) { 1033 pScrn->capabilities |= RR_Capability_SinkOutput; 1034 if (ms->drmmode.glamor) 1035 pScrn->capabilities |= RR_Capability_SinkOffload; 1036 } 1037#ifdef GLAMOR_HAS_GBM_LINEAR 1038 if (value & DRM_PRIME_CAP_EXPORT && ms->drmmode.glamor) 1039 pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload; 1040#endif 1041 } 1042 1043 if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_ATOMIC, FALSE)) { 1044 ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 1); 1045 ms->atomic_modeset = (ret == 0); 1046 } else { 1047 ms->atomic_modeset = FALSE; 1048 } 1049 1050 ms->kms_has_modifiers = FALSE; 1051 ret = drmGetCap(ms->fd, DRM_CAP_ADDFB2_MODIFIERS, &value); 1052 if (ret == 0 && value != 0) 1053 ms->kms_has_modifiers = TRUE; 1054 1055 if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) { 1056 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n"); 1057 goto fail; 1058 } 1059 1060 /* 1061 * If the driver can do gamma correction, it should call xf86SetGamma() here. 1062 */ 1063 { 1064 Gamma zeros = { 0.0, 0.0, 0.0 }; 1065 1066 if (!xf86SetGamma(pScrn, zeros)) { 1067 return FALSE; 1068 } 1069 } 1070 1071 if (!(pScrn->is_gpu && connector_count == 0) && pScrn->modes == NULL) { 1072 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); 1073 return FALSE; 1074 } 1075 1076 pScrn->currentMode = pScrn->modes; 1077 1078 /* Set display resolution */ 1079 xf86SetDpi(pScrn, 0, 0); 1080 1081 /* Load the required sub modules */ 1082 if (!xf86LoadSubModule(pScrn, "fb")) { 1083 return FALSE; 1084 } 1085 1086 if (ms->drmmode.shadow_enable) { 1087 if (!xf86LoadSubModule(pScrn, "shadow")) { 1088 return FALSE; 1089 } 1090 } 1091 1092 return TRUE; 1093 fail: 1094 return FALSE; 1095} 1096 1097static void * 1098msShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, int mode, 1099 CARD32 *size, void *closure) 1100{ 1101 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 1102 modesettingPtr ms = modesettingPTR(pScrn); 1103 int stride; 1104 1105 stride = (pScrn->displayWidth * ms->drmmode.kbpp) / 8; 1106 *size = stride; 1107 1108 return ((uint8_t *) ms->drmmode.front_bo.dumb->ptr + row * stride + offset); 1109} 1110 1111/* somewhat arbitrary tile size, in pixels */ 1112#define TILE 16 1113 1114static int 1115msUpdateIntersect(modesettingPtr ms, shadowBufPtr pBuf, BoxPtr box, 1116 xRectangle *prect) 1117{ 1118 int i, dirty = 0, stride = pBuf->pPixmap->devKind, cpp = ms->drmmode.cpp; 1119 int width = (box->x2 - box->x1) * cpp; 1120 unsigned char *old, *new; 1121 1122 old = ms->drmmode.shadow_fb2; 1123 old += (box->y1 * stride) + (box->x1 * cpp); 1124 new = ms->drmmode.shadow_fb; 1125 new += (box->y1 * stride) + (box->x1 * cpp); 1126 1127 for (i = box->y2 - box->y1 - 1; i >= 0; i--) { 1128 unsigned char *o = old + i * stride, 1129 *n = new + i * stride; 1130 if (memcmp(o, n, width) != 0) { 1131 dirty = 1; 1132 memcpy(o, n, width); 1133 } 1134 } 1135 1136 if (dirty) { 1137 prect->x = box->x1; 1138 prect->y = box->y1; 1139 prect->width = box->x2 - box->x1; 1140 prect->height = box->y2 - box->y1; 1141 } 1142 1143 return dirty; 1144} 1145 1146static void 1147msUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf) 1148{ 1149 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1150 modesettingPtr ms = modesettingPTR(pScrn); 1151 Bool use_3224 = ms->drmmode.force_24_32 && pScrn->bitsPerPixel == 32; 1152 1153 if (ms->drmmode.shadow_enable2 && ms->drmmode.shadow_fb2) do { 1154 RegionPtr damage = DamageRegion(pBuf->pDamage), tiles; 1155 BoxPtr extents = RegionExtents(damage); 1156 xRectangle *prect; 1157 int nrects; 1158 int i, j, tx1, tx2, ty1, ty2; 1159 1160 tx1 = extents->x1 / TILE; 1161 tx2 = (extents->x2 + TILE - 1) / TILE; 1162 ty1 = extents->y1 / TILE; 1163 ty2 = (extents->y2 + TILE - 1) / TILE; 1164 1165 nrects = (tx2 - tx1) * (ty2 - ty1); 1166 if (!(prect = calloc(nrects, sizeof(xRectangle)))) 1167 break; 1168 1169 nrects = 0; 1170 for (j = ty2 - 1; j >= ty1; j--) { 1171 for (i = tx2 - 1; i >= tx1; i--) { 1172 BoxRec box; 1173 1174 box.x1 = max(i * TILE, extents->x1); 1175 box.y1 = max(j * TILE, extents->y1); 1176 box.x2 = min((i+1) * TILE, extents->x2); 1177 box.y2 = min((j+1) * TILE, extents->y2); 1178 1179 if (RegionContainsRect(damage, &box) != rgnOUT) { 1180 if (msUpdateIntersect(ms, pBuf, &box, prect + nrects)) { 1181 nrects++; 1182 } 1183 } 1184 } 1185 } 1186 1187 tiles = RegionFromRects(nrects, prect, CT_NONE); 1188 RegionIntersect(damage, damage, tiles); 1189 RegionDestroy(tiles); 1190 free(prect); 1191 } while (0); 1192 1193 if (use_3224) 1194 shadowUpdate32to24(pScreen, pBuf); 1195 else 1196 shadowUpdatePacked(pScreen, pBuf); 1197} 1198 1199static Bool 1200msEnableSharedPixmapFlipping(RRCrtcPtr crtc, PixmapPtr front, PixmapPtr back) 1201{ 1202 ScreenPtr screen = crtc->pScreen; 1203 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1204 modesettingPtr ms = modesettingPTR(scrn); 1205 EntityInfoPtr pEnt = ms->pEnt; 1206 xf86CrtcPtr xf86Crtc = crtc->devPrivate; 1207 1208 if (!xf86Crtc) 1209 return FALSE; 1210 1211 /* Not supported if we can't flip */ 1212 if (!ms->drmmode.pageflip) 1213 return FALSE; 1214 1215 /* Not currently supported with reverse PRIME */ 1216 if (ms->drmmode.reverse_prime_offload_mode) 1217 return FALSE; 1218 1219#ifdef XSERVER_PLATFORM_BUS 1220 if (pEnt->location.type == BUS_PLATFORM) { 1221 char *syspath = 1222 xf86_platform_device_odev_attributes(pEnt->location.id.plat)-> 1223 syspath; 1224 1225 /* Not supported for devices using USB transport due to misbehaved 1226 * vblank events */ 1227 if (syspath && strstr(syspath, "usb")) 1228 return FALSE; 1229 1230 /* EVDI uses USB transport but is platform device, not usb. 1231 * Blacklist it explicitly */ 1232 if (syspath && strstr(syspath, "evdi")) 1233 return FALSE; 1234 } 1235#endif 1236 1237 return drmmode_EnableSharedPixmapFlipping(xf86Crtc, &ms->drmmode, 1238 front, back); 1239} 1240 1241static void 1242msDisableSharedPixmapFlipping(RRCrtcPtr crtc) 1243{ 1244 ScreenPtr screen = crtc->pScreen; 1245 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1246 modesettingPtr ms = modesettingPTR(scrn); 1247 xf86CrtcPtr xf86Crtc = crtc->devPrivate; 1248 1249 if (xf86Crtc) 1250 drmmode_DisableSharedPixmapFlipping(xf86Crtc, &ms->drmmode); 1251} 1252 1253static Bool 1254msStartFlippingPixmapTracking(RRCrtcPtr crtc, DrawablePtr src, 1255 PixmapPtr slave_dst1, PixmapPtr slave_dst2, 1256 int x, int y, int dst_x, int dst_y, 1257 Rotation rotation) 1258{ 1259 ScreenPtr pScreen = src->pScreen; 1260 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen)); 1261 1262 msPixmapPrivPtr ppriv1 = msGetPixmapPriv(&ms->drmmode, slave_dst1->master_pixmap), 1263 ppriv2 = msGetPixmapPriv(&ms->drmmode, slave_dst2->master_pixmap); 1264 1265 if (!PixmapStartDirtyTracking(src, slave_dst1, x, y, 1266 dst_x, dst_y, rotation)) { 1267 return FALSE; 1268 } 1269 1270 if (!PixmapStartDirtyTracking(src, slave_dst2, x, y, 1271 dst_x, dst_y, rotation)) { 1272 PixmapStopDirtyTracking(src, slave_dst1); 1273 return FALSE; 1274 } 1275 1276 ppriv1->slave_src = src; 1277 ppriv2->slave_src = src; 1278 1279 ppriv1->dirty = ms_dirty_get_ent(pScreen, slave_dst1); 1280 ppriv2->dirty = ms_dirty_get_ent(pScreen, slave_dst2); 1281 1282 ppriv1->defer_dirty_update = TRUE; 1283 ppriv2->defer_dirty_update = TRUE; 1284 1285 return TRUE; 1286} 1287 1288static Bool 1289msPresentSharedPixmap(PixmapPtr slave_dst) 1290{ 1291 ScreenPtr pScreen = slave_dst->master_pixmap->drawable.pScreen; 1292 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen)); 1293 1294 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, slave_dst->master_pixmap); 1295 1296 RegionPtr region = DamageRegion(ppriv->dirty->damage); 1297 1298 if (RegionNotEmpty(region)) { 1299 redisplay_dirty(ppriv->slave_src->pScreen, ppriv->dirty, NULL); 1300 DamageEmpty(ppriv->dirty->damage); 1301 1302 return TRUE; 1303 } 1304 1305 return FALSE; 1306} 1307 1308static Bool 1309msStopFlippingPixmapTracking(DrawablePtr src, 1310 PixmapPtr slave_dst1, PixmapPtr slave_dst2) 1311{ 1312 ScreenPtr pScreen = src->pScreen; 1313 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen)); 1314 1315 msPixmapPrivPtr ppriv1 = msGetPixmapPriv(&ms->drmmode, slave_dst1->master_pixmap), 1316 ppriv2 = msGetPixmapPriv(&ms->drmmode, slave_dst2->master_pixmap); 1317 1318 Bool ret = TRUE; 1319 1320 ret &= PixmapStopDirtyTracking(src, slave_dst1); 1321 ret &= PixmapStopDirtyTracking(src, slave_dst2); 1322 1323 if (ret) { 1324 ppriv1->slave_src = NULL; 1325 ppriv2->slave_src = NULL; 1326 1327 ppriv1->dirty = NULL; 1328 ppriv2->dirty = NULL; 1329 1330 ppriv1->defer_dirty_update = FALSE; 1331 ppriv2->defer_dirty_update = FALSE; 1332 } 1333 1334 return ret; 1335} 1336 1337static Bool 1338CreateScreenResources(ScreenPtr pScreen) 1339{ 1340 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1341 modesettingPtr ms = modesettingPTR(pScrn); 1342 PixmapPtr rootPixmap; 1343 Bool ret; 1344 void *pixels = NULL; 1345 int err; 1346 1347 pScreen->CreateScreenResources = ms->createScreenResources; 1348 ret = pScreen->CreateScreenResources(pScreen); 1349 pScreen->CreateScreenResources = CreateScreenResources; 1350 1351 if (!drmmode_set_desired_modes(pScrn, &ms->drmmode, pScrn->is_gpu, FALSE)) 1352 return FALSE; 1353 1354 if (!drmmode_glamor_handle_new_screen_pixmap(&ms->drmmode)) 1355 return FALSE; 1356 1357 drmmode_uevent_init(pScrn, &ms->drmmode); 1358 1359 if (!ms->drmmode.sw_cursor) 1360 drmmode_map_cursor_bos(pScrn, &ms->drmmode); 1361 1362 if (!ms->drmmode.gbm) { 1363 pixels = drmmode_map_front_bo(&ms->drmmode); 1364 if (!pixels) 1365 return FALSE; 1366 } 1367 1368 rootPixmap = pScreen->GetScreenPixmap(pScreen); 1369 1370 if (ms->drmmode.shadow_enable) 1371 pixels = ms->drmmode.shadow_fb; 1372 1373 if (ms->drmmode.shadow_enable2) { 1374 ms->drmmode.shadow_fb2 = calloc(1, pScrn->displayWidth * pScrn->virtualY * ((pScrn->bitsPerPixel + 7) >> 3)); 1375 if (!ms->drmmode.shadow_fb2) 1376 ms->drmmode.shadow_enable2 = FALSE; 1377 } 1378 1379 if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, pixels)) 1380 FatalError("Couldn't adjust screen pixmap\n"); 1381 1382 if (ms->drmmode.shadow_enable) { 1383 if (!shadowAdd(pScreen, rootPixmap, msUpdatePacked, msShadowWindow, 1384 0, 0)) 1385 return FALSE; 1386 } 1387 1388 err = drmModeDirtyFB(ms->fd, ms->drmmode.fb_id, NULL, 0); 1389 1390 if (err != -EINVAL && err != -ENOSYS) { 1391 ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE, 1392 pScreen, rootPixmap); 1393 1394 if (ms->damage) { 1395 DamageRegister(&rootPixmap->drawable, ms->damage); 1396 ms->dirty_enabled = TRUE; 1397 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n"); 1398 } 1399 else { 1400 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1401 "Failed to create screen damage record\n"); 1402 return FALSE; 1403 } 1404 } 1405 1406 if (dixPrivateKeyRegistered(rrPrivKey)) { 1407 rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); 1408 1409 pScrPriv->rrEnableSharedPixmapFlipping = msEnableSharedPixmapFlipping; 1410 pScrPriv->rrDisableSharedPixmapFlipping = msDisableSharedPixmapFlipping; 1411 1412 pScrPriv->rrStartFlippingPixmapTracking = msStartFlippingPixmapTracking; 1413 } 1414 1415 return ret; 1416} 1417 1418static Bool 1419msShadowInit(ScreenPtr pScreen) 1420{ 1421 if (!shadowSetup(pScreen)) { 1422 return FALSE; 1423 } 1424 return TRUE; 1425} 1426 1427static Bool 1428msSharePixmapBacking(PixmapPtr ppix, ScreenPtr screen, void **handle) 1429{ 1430#ifdef GLAMOR_HAS_GBM 1431 int ret; 1432 CARD16 stride; 1433 CARD32 size; 1434 ret = glamor_shareable_fd_from_pixmap(ppix->drawable.pScreen, ppix, 1435 &stride, &size); 1436 if (ret == -1) 1437 return FALSE; 1438 1439 *handle = (void *)(long)(ret); 1440 return TRUE; 1441#endif 1442 return FALSE; 1443} 1444 1445static Bool 1446msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) 1447{ 1448#ifdef GLAMOR_HAS_GBM 1449 ScreenPtr screen = ppix->drawable.pScreen; 1450 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1451 modesettingPtr ms = modesettingPTR(scrn); 1452 Bool ret; 1453 int ihandle = (int) (long) fd_handle; 1454 1455 if (ihandle == -1) 1456 if (!ms->drmmode.reverse_prime_offload_mode) 1457 return drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, 0, 0); 1458 1459 if (ms->drmmode.reverse_prime_offload_mode) { 1460 ret = glamor_back_pixmap_from_fd(ppix, ihandle, 1461 ppix->drawable.width, 1462 ppix->drawable.height, 1463 ppix->devKind, ppix->drawable.depth, 1464 ppix->drawable.bitsPerPixel); 1465 } else { 1466 int size = ppix->devKind * ppix->drawable.height; 1467 ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size); 1468 } 1469 if (ret == FALSE) 1470 return ret; 1471 1472 return TRUE; 1473#else 1474 return FALSE; 1475#endif 1476} 1477 1478static Bool 1479msRequestSharedPixmapNotifyDamage(PixmapPtr ppix) 1480{ 1481 ScreenPtr screen = ppix->drawable.pScreen; 1482 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1483 modesettingPtr ms = modesettingPTR(scrn); 1484 1485 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix->master_pixmap); 1486 1487 ppriv->notify_on_damage = TRUE; 1488 1489 return TRUE; 1490} 1491 1492static Bool 1493msSharedPixmapNotifyDamage(PixmapPtr ppix) 1494{ 1495 Bool ret = FALSE; 1496 int c; 1497 1498 ScreenPtr screen = ppix->drawable.pScreen; 1499 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1500 modesettingPtr ms = modesettingPTR(scrn); 1501 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1502 1503 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix); 1504 1505 if (!ppriv->wait_for_damage) 1506 return ret; 1507 ppriv->wait_for_damage = FALSE; 1508 1509 for (c = 0; c < xf86_config->num_crtc; c++) { 1510 xf86CrtcPtr crtc = xf86_config->crtc[c]; 1511 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1512 1513 if (!drmmode_crtc) 1514 continue; 1515 if (!(drmmode_crtc->prime_pixmap && drmmode_crtc->prime_pixmap_back)) 1516 continue; 1517 1518 // Received damage on master screen pixmap, schedule present on vblank 1519 ret |= drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, &ms->drmmode); 1520 } 1521 1522 return ret; 1523} 1524 1525static Bool 1526SetMaster(ScrnInfoPtr pScrn) 1527{ 1528 modesettingPtr ms = modesettingPTR(pScrn); 1529 int ret; 1530 1531#ifdef XF86_PDEV_SERVER_FD 1532 if (ms->pEnt->location.type == BUS_PLATFORM && 1533 (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD)) 1534 return TRUE; 1535#endif 1536 1537 if (ms->fd_passed) 1538 return TRUE; 1539 1540 ret = drmSetMaster(ms->fd); 1541 if (ret) 1542 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "drmSetMaster failed: %s\n", 1543 strerror(errno)); 1544 1545 return ret == 0; 1546} 1547 1548/* When the root window is created, initialize the screen contents from 1549 * console if -background none was specified on the command line 1550 */ 1551static Bool 1552CreateWindow_oneshot(WindowPtr pWin) 1553{ 1554 ScreenPtr pScreen = pWin->drawable.pScreen; 1555 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1556 modesettingPtr ms = modesettingPTR(pScrn); 1557 Bool ret; 1558 1559 pScreen->CreateWindow = ms->CreateWindow; 1560 ret = pScreen->CreateWindow(pWin); 1561 1562 if (ret) 1563 drmmode_copy_fb(pScrn, &ms->drmmode); 1564 return ret; 1565} 1566 1567static Bool 1568ScreenInit(ScreenPtr pScreen, int argc, char **argv) 1569{ 1570 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1571 modesettingPtr ms = modesettingPTR(pScrn); 1572 VisualPtr visual; 1573 1574 pScrn->pScreen = pScreen; 1575 1576 if (!SetMaster(pScrn)) 1577 return FALSE; 1578 1579#ifdef GLAMOR_HAS_GBM 1580 if (ms->drmmode.glamor) 1581 ms->drmmode.gbm = glamor_egl_get_gbm_device(pScreen); 1582#endif 1583 1584 /* HW dependent - FIXME */ 1585 pScrn->displayWidth = pScrn->virtualX; 1586 if (!drmmode_create_initial_bos(pScrn, &ms->drmmode)) 1587 return FALSE; 1588 1589 if (ms->drmmode.shadow_enable) { 1590 ms->drmmode.shadow_fb = 1591 calloc(1, 1592 pScrn->displayWidth * pScrn->virtualY * 1593 ((pScrn->bitsPerPixel + 7) >> 3)); 1594 if (!ms->drmmode.shadow_fb) 1595 ms->drmmode.shadow_enable = FALSE; 1596 } 1597 1598 miClearVisualTypes(); 1599 1600 if (!miSetVisualTypes(pScrn->depth, 1601 miGetDefaultVisualMask(pScrn->depth), 1602 pScrn->rgbBits, pScrn->defaultVisual)) 1603 return FALSE; 1604 1605 if (!miSetPixmapDepths()) 1606 return FALSE; 1607 1608 if (!dixRegisterScreenSpecificPrivateKey 1609 (pScreen, &ms->drmmode.pixmapPrivateKeyRec, PRIVATE_PIXMAP, 1610 sizeof(msPixmapPrivRec))) { 1611 return FALSE; 1612 } 1613 1614 pScrn->memPhysBase = 0; 1615 pScrn->fbOffset = 0; 1616 1617 if (!fbScreenInit(pScreen, NULL, 1618 pScrn->virtualX, pScrn->virtualY, 1619 pScrn->xDpi, pScrn->yDpi, 1620 pScrn->displayWidth, pScrn->bitsPerPixel)) 1621 return FALSE; 1622 1623 if (pScrn->bitsPerPixel > 8) { 1624 /* Fixup RGB ordering */ 1625 visual = pScreen->visuals + pScreen->numVisuals; 1626 while (--visual >= pScreen->visuals) { 1627 if ((visual->class | DynamicClass) == DirectColor) { 1628 visual->offsetRed = pScrn->offset.red; 1629 visual->offsetGreen = pScrn->offset.green; 1630 visual->offsetBlue = pScrn->offset.blue; 1631 visual->redMask = pScrn->mask.red; 1632 visual->greenMask = pScrn->mask.green; 1633 visual->blueMask = pScrn->mask.blue; 1634 } 1635 } 1636 } 1637 1638 fbPictureInit(pScreen, NULL, 0); 1639 1640 if (drmmode_init(pScrn, &ms->drmmode) == FALSE) { 1641 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1642 "Failed to initialize glamor at ScreenInit() time.\n"); 1643 return FALSE; 1644 } 1645 1646 if (ms->drmmode.shadow_enable && !msShadowInit(pScreen)) { 1647 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "shadow fb init failed\n"); 1648 return FALSE; 1649 } 1650 1651 ms->createScreenResources = pScreen->CreateScreenResources; 1652 pScreen->CreateScreenResources = CreateScreenResources; 1653 1654 xf86SetBlackWhitePixels(pScreen); 1655 1656 xf86SetBackingStore(pScreen); 1657 xf86SetSilkenMouse(pScreen); 1658 miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); 1659 1660 /* If pageflip is enabled hook the screen's cursor-sprite (swcursor) funcs. 1661 * So that we can disabe page-flipping on fallback to a swcursor. */ 1662 if (ms->drmmode.pageflip) { 1663 miPointerScreenPtr PointPriv = 1664 dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); 1665 1666 if (!dixRegisterScreenPrivateKey(&ms->drmmode.spritePrivateKeyRec, 1667 pScreen, PRIVATE_DEVICE, 1668 sizeof(msSpritePrivRec))) 1669 return FALSE; 1670 1671 ms->SpriteFuncs = PointPriv->spriteFuncs; 1672 PointPriv->spriteFuncs = &drmmode_sprite_funcs; 1673 } 1674 1675 /* Need to extend HWcursor support to handle mask interleave */ 1676 if (!ms->drmmode.sw_cursor) 1677 xf86_cursors_init(pScreen, ms->cursor_width, ms->cursor_height, 1678 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | 1679 HARDWARE_CURSOR_UPDATE_UNHIDDEN | 1680 HARDWARE_CURSOR_ARGB); 1681 1682 /* Must force it before EnterVT, so we are in control of VT and 1683 * later memory should be bound when allocating, e.g rotate_mem */ 1684 pScrn->vtSema = TRUE; 1685 1686 if (serverGeneration == 1 && bgNoneRoot && ms->drmmode.glamor) { 1687 ms->CreateWindow = pScreen->CreateWindow; 1688 pScreen->CreateWindow = CreateWindow_oneshot; 1689 } 1690 1691 pScreen->SaveScreen = xf86SaveScreen; 1692 ms->CloseScreen = pScreen->CloseScreen; 1693 pScreen->CloseScreen = CloseScreen; 1694 1695 ms->BlockHandler = pScreen->BlockHandler; 1696 pScreen->BlockHandler = msBlockHandler_oneshot; 1697 1698 pScreen->SharePixmapBacking = msSharePixmapBacking; 1699 pScreen->SetSharedPixmapBacking = msSetSharedPixmapBacking; 1700 pScreen->StartPixmapTracking = PixmapStartDirtyTracking; 1701 pScreen->StopPixmapTracking = PixmapStopDirtyTracking; 1702 1703 pScreen->SharedPixmapNotifyDamage = msSharedPixmapNotifyDamage; 1704 pScreen->RequestSharedPixmapNotifyDamage = 1705 msRequestSharedPixmapNotifyDamage; 1706 1707 pScreen->PresentSharedPixmap = msPresentSharedPixmap; 1708 pScreen->StopFlippingPixmapTracking = msStopFlippingPixmapTracking; 1709 1710 if (!xf86CrtcScreenInit(pScreen)) 1711 return FALSE; 1712 1713 if (!drmmode_setup_colormap(pScreen, pScrn)) 1714 return FALSE; 1715 1716 if (ms->atomic_modeset) 1717 xf86DPMSInit(pScreen, drmmode_set_dpms, 0); 1718 else 1719 xf86DPMSInit(pScreen, xf86DPMSSet, 0); 1720 1721#ifdef GLAMOR_HAS_GBM 1722 if (ms->drmmode.glamor) { 1723 XF86VideoAdaptorPtr glamor_adaptor; 1724 1725 glamor_adaptor = glamor_xv_init(pScreen, 16); 1726 if (glamor_adaptor != NULL) 1727 xf86XVScreenInit(pScreen, &glamor_adaptor, 1); 1728 else 1729 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1730 "Failed to initialize XV support.\n"); 1731 } 1732#endif 1733 1734 if (serverGeneration == 1) 1735 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 1736 1737 if (!ms_vblank_screen_init(pScreen)) { 1738 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1739 "Failed to initialize vblank support.\n"); 1740 return FALSE; 1741 } 1742 1743#ifdef GLAMOR_HAS_GBM 1744 if (ms->drmmode.glamor) { 1745 if (!(ms->drmmode.dri2_enable = ms_dri2_screen_init(pScreen))) { 1746 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1747 "Failed to initialize the DRI2 extension.\n"); 1748 } 1749 1750 if (!(ms->drmmode.present_enable = ms_present_screen_init(pScreen))) { 1751 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1752 "Failed to initialize the Present extension.\n"); 1753 } 1754 /* enable reverse prime if we are a GPU screen, and accelerated, and not 1755 * i915. i915 is happy scanning out from sysmem. */ 1756 if (pScreen->isGPU) { 1757 drmVersionPtr version; 1758 1759 /* enable if we are an accelerated GPU screen */ 1760 ms->drmmode.reverse_prime_offload_mode = TRUE; 1761 1762 /* disable if we detect i915 */ 1763 if ((version = drmGetVersion(ms->drmmode.fd))) { 1764 if (!strncmp("i915", version->name, version->name_len)) { 1765 ms->drmmode.reverse_prime_offload_mode = FALSE; 1766 } 1767 drmFreeVersion(version); 1768 } 1769 } 1770 } 1771#endif 1772 1773 pScrn->vtSema = TRUE; 1774 1775 return TRUE; 1776} 1777 1778static void 1779AdjustFrame(ScrnInfoPtr pScrn, int x, int y) 1780{ 1781 modesettingPtr ms = modesettingPTR(pScrn); 1782 1783 drmmode_adjust_frame(pScrn, &ms->drmmode, x, y); 1784} 1785 1786static void 1787FreeScreen(ScrnInfoPtr pScrn) 1788{ 1789 FreeRec(pScrn); 1790} 1791 1792static void 1793LeaveVT(ScrnInfoPtr pScrn) 1794{ 1795 modesettingPtr ms = modesettingPTR(pScrn); 1796 1797 xf86_hide_cursors(pScrn); 1798 1799 pScrn->vtSema = FALSE; 1800 1801#ifdef XF86_PDEV_SERVER_FD 1802 if (ms->pEnt->location.type == BUS_PLATFORM && 1803 (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD)) 1804 return; 1805#endif 1806 1807 if (!ms->fd_passed) 1808 drmDropMaster(ms->fd); 1809} 1810 1811/* 1812 * This gets called when gaining control of the VT, and from ScreenInit(). 1813 */ 1814static Bool 1815EnterVT(ScrnInfoPtr pScrn) 1816{ 1817 modesettingPtr ms = modesettingPTR(pScrn); 1818 1819 pScrn->vtSema = TRUE; 1820 1821 SetMaster(pScrn); 1822 1823 drmmode_update_kms_state(&ms->drmmode); 1824 1825 /* allow not all modes to be set successfully since some events might have 1826 * happened while not being master that could prevent the previous 1827 * configuration from being re-applied. 1828 */ 1829 if (!drmmode_set_desired_modes(pScrn, &ms->drmmode, TRUE, TRUE)) { 1830 xf86DisableUnusedFunctions(pScrn); 1831 1832 /* TODO: check that at least one screen is on, to allow the user to fix 1833 * their setup if all modeset failed... 1834 */ 1835 1836 /* Tell the desktop environment that something changed, so that they 1837 * can hopefully correct the situation 1838 */ 1839 RRSetChanged(xf86ScrnToScreen(pScrn)); 1840 RRTellChanged(xf86ScrnToScreen(pScrn)); 1841 } 1842 1843 return TRUE; 1844} 1845 1846static Bool 1847SwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode) 1848{ 1849 return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); 1850} 1851 1852static Bool 1853CloseScreen(ScreenPtr pScreen) 1854{ 1855 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1856 modesettingPtr ms = modesettingPTR(pScrn); 1857 modesettingEntPtr ms_ent = ms_ent_priv(pScrn); 1858 1859 /* Clear mask of assigned crtc's in this generation */ 1860 ms_ent->assigned_crtcs = 0; 1861 1862#ifdef GLAMOR_HAS_GBM 1863 if (ms->drmmode.dri2_enable) { 1864 ms_dri2_close_screen(pScreen); 1865 } 1866#endif 1867 1868 ms_vblank_close_screen(pScreen); 1869 1870 if (ms->damage) { 1871 DamageUnregister(ms->damage); 1872 DamageDestroy(ms->damage); 1873 ms->damage = NULL; 1874 } 1875 1876 if (ms->drmmode.shadow_enable) { 1877 shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen)); 1878 free(ms->drmmode.shadow_fb); 1879 ms->drmmode.shadow_fb = NULL; 1880 free(ms->drmmode.shadow_fb2); 1881 ms->drmmode.shadow_fb2 = NULL; 1882 } 1883 1884 drmmode_uevent_fini(pScrn, &ms->drmmode); 1885 1886 drmmode_free_bos(pScrn, &ms->drmmode); 1887 1888 if (ms->drmmode.pageflip) { 1889 miPointerScreenPtr PointPriv = 1890 dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey); 1891 1892 if (PointPriv->spriteFuncs == &drmmode_sprite_funcs) 1893 PointPriv->spriteFuncs = ms->SpriteFuncs; 1894 } 1895 1896 if (pScrn->vtSema) { 1897 LeaveVT(pScrn); 1898 } 1899 1900 pScreen->CreateScreenResources = ms->createScreenResources; 1901 pScreen->BlockHandler = ms->BlockHandler; 1902 1903 pScrn->vtSema = FALSE; 1904 pScreen->CloseScreen = ms->CloseScreen; 1905 return (*pScreen->CloseScreen) (pScreen); 1906} 1907 1908static ModeStatus 1909ValidMode(ScrnInfoPtr arg, DisplayModePtr mode, Bool verbose, int flags) 1910{ 1911 return MODE_OK; 1912} 1913