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