xorg_driver.c revision a7a126bdfa386a4be9dd1f7bac1825edb7ff3fcd
1/* 2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * 26 * Author: Alan Hourihane <alanh@tungstengraphics.com> 27 * Author: Jakob Bornecrantz <wallbraker@gmail.com> 28 * 29 */ 30 31 32#include "xorg-server.h" 33#include "xf86.h" 34#include "xf86_OSproc.h" 35#include "compiler.h" 36#include "xf86PciInfo.h" 37#include "xf86Pci.h" 38#include "mipointer.h" 39#include "micmap.h" 40#include <X11/extensions/randr.h> 41#include "fb.h" 42#include "edid.h" 43#include "xf86i2c.h" 44#include "xf86Crtc.h" 45#include "miscstruct.h" 46#include "dixstruct.h" 47#include "xf86xv.h" 48#ifndef XSERVER_LIBPCIACCESS 49#error "libpciaccess needed" 50#endif 51 52#include <pciaccess.h> 53 54#include "state_tracker/drm_driver.h" 55#include "pipe/p_context.h" 56#include "xorg_tracker.h" 57#include "xorg_winsys.h" 58 59#ifdef HAVE_LIBKMS 60#include "libkms.h" 61#endif 62 63/* 64 * Functions and symbols exported to Xorg via pointers. 65 */ 66 67static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags); 68static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, 69 char **argv); 70static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags); 71static void drv_adjust_frame(int scrnIndex, int x, int y, int flags); 72static Bool drv_enter_vt(int scrnIndex, int flags); 73static void drv_leave_vt(int scrnIndex, int flags); 74static void drv_free_screen(int scrnIndex, int flags); 75static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, 76 int flags); 77 78typedef enum 79{ 80 OPTION_SW_CURSOR, 81 OPTION_2D_ACCEL, 82 OPTION_DEBUG_FALLBACK, 83 OPTION_THROTTLE_SWAP, 84 OPTION_THROTTLE_DIRTY, 85 OPTION_3D_ACCEL 86} drv_option_enums; 87 88static const OptionInfoRec drv_options[] = { 89 {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, 90 {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE}, 91 {OPTION_DEBUG_FALLBACK, "DebugFallback", OPTV_BOOLEAN, {0}, FALSE}, 92 {OPTION_THROTTLE_SWAP, "SwapThrottling", OPTV_BOOLEAN, {0}, FALSE}, 93 {OPTION_THROTTLE_DIRTY, "DirtyThrottling", OPTV_BOOLEAN, {0}, FALSE}, 94 {OPTION_3D_ACCEL, "3DAccel", OPTV_BOOLEAN, {0}, FALSE}, 95 {-1, NULL, OPTV_NONE, {0}, FALSE} 96}; 97 98 99/* 100 * Exported Xorg driver functions to winsys 101 */ 102 103const OptionInfoRec * 104xorg_tracker_available_options(int chipid, int busid) 105{ 106 return drv_options; 107} 108 109void 110xorg_tracker_set_functions(ScrnInfoPtr scrn) 111{ 112 scrn->PreInit = drv_pre_init; 113 scrn->ScreenInit = drv_screen_init; 114 scrn->SwitchMode = drv_switch_mode; 115 scrn->AdjustFrame = drv_adjust_frame; 116 scrn->EnterVT = drv_enter_vt; 117 scrn->LeaveVT = drv_leave_vt; 118 scrn->FreeScreen = drv_free_screen; 119 scrn->ValidMode = drv_valid_mode; 120} 121 122Bool 123xorg_tracker_have_modesetting(ScrnInfoPtr pScrn, struct pci_device *device) 124{ 125 char *BusID = xalloc(64); 126 sprintf(BusID, "pci:%04x:%02x:%02x.%d", 127 device->domain, device->bus, 128 device->dev, device->func); 129 130 if (drmCheckModesettingSupported(BusID)) { 131 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, 132 "Drm modesetting not supported %s\n", BusID); 133 xfree(BusID); 134 return FALSE; 135 } 136 137 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, 138 "Drm modesetting supported on %s\n", BusID); 139 140 xfree(BusID); 141 return TRUE; 142} 143 144 145/* 146 * Internal function definitions 147 */ 148 149static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn); 150static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen); 151 152 153/* 154 * Internal functions 155 */ 156 157static Bool 158drv_get_rec(ScrnInfoPtr pScrn) 159{ 160 if (pScrn->driverPrivate) 161 return TRUE; 162 163 pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec)); 164 165 return TRUE; 166} 167 168static void 169drv_free_rec(ScrnInfoPtr pScrn) 170{ 171 if (!pScrn) 172 return; 173 174 if (!pScrn->driverPrivate) 175 return; 176 177 xfree(pScrn->driverPrivate); 178 179 pScrn->driverPrivate = NULL; 180} 181 182static void 183drv_probe_ddc(ScrnInfoPtr pScrn, int index) 184{ 185 ConfiguredMonitor = NULL; 186} 187 188static Bool 189drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height) 190{ 191 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 192 modesettingPtr ms = modesettingPTR(pScrn); 193 CustomizerPtr cust = ms->cust; 194 ScreenPtr pScreen = pScrn->pScreen; 195 int old_width, old_height; 196 PixmapPtr rootPixmap; 197 int i; 198 199 if (width == pScrn->virtualX && height == pScrn->virtualY) 200 return TRUE; 201 202 if (cust && cust->winsys_check_fb_size && 203 !cust->winsys_check_fb_size(cust, width*pScrn->bitsPerPixel / 8, 204 height)) { 205 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 206 "Requested framebuffer size %dx%dx%d will not fit " 207 "in display memory.\n", 208 width, height, pScrn->bitsPerPixel); 209 return FALSE; 210 } 211 212 old_width = pScrn->virtualX; 213 old_height = pScrn->virtualY; 214 pScrn->virtualX = width; 215 pScrn->virtualY = height; 216 217 /* ms->create_front_buffer will remove the old front buffer */ 218 219 rootPixmap = pScreen->GetScreenPixmap(pScreen); 220 if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL)) 221 goto error_modify; 222 223 pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8); 224 225 if (!ms->create_front_buffer(pScrn) || !ms->bind_front_buffer(pScrn)) 226 goto error_create; 227 228 /* 229 * create && bind will turn off all crtc(s) in the kernel so we need to 230 * re-enable all the crtcs again. For real HW we might want to do this 231 * before destroying the old framebuffer. 232 */ 233 for (i = 0; i < xf86_config->num_crtc; i++) { 234 xf86CrtcPtr crtc = xf86_config->crtc[i]; 235 236 if (!crtc->enabled) 237 continue; 238 239 crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y); 240 } 241 242 return TRUE; 243 244 /* 245 * This is the error recovery path. 246 */ 247error_create: 248 if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL)) 249 FatalError("failed to resize rootPixmap error path\n"); 250 251 pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8); 252 253error_modify: 254 pScrn->virtualX = old_width; 255 pScrn->virtualY = old_height; 256 257 if (ms->create_front_buffer(pScrn) && ms->bind_front_buffer(pScrn)) 258 return FALSE; 259 260 FatalError("failed to setup old framebuffer\n"); 261 return FALSE; 262} 263 264static const xf86CrtcConfigFuncsRec crtc_config_funcs = { 265 .resize = drv_crtc_resize 266}; 267 268static Bool 269drv_init_drm(ScrnInfoPtr pScrn) 270{ 271 modesettingPtr ms = modesettingPTR(pScrn); 272 273 /* deal with server regeneration */ 274 if (ms->fd < 0) { 275 char *BusID; 276 277 BusID = xalloc(64); 278 sprintf(BusID, "PCI:%d:%d:%d", 279 ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), 280 ms->PciInfo->dev, ms->PciInfo->func 281 ); 282 283 284 ms->fd = drmOpen(driver_descriptor.driver_name, BusID); 285 xfree(BusID); 286 287 if (ms->fd >= 0) 288 return TRUE; 289 290 return FALSE; 291 } 292 293 return TRUE; 294} 295 296static Bool 297drv_close_drm(ScrnInfoPtr pScrn) 298{ 299 modesettingPtr ms = modesettingPTR(pScrn); 300 301 drmClose(ms->fd); 302 ms->fd = -1; 303 304 return TRUE; 305} 306 307static Bool 308drv_init_resource_management(ScrnInfoPtr pScrn) 309{ 310 modesettingPtr ms = modesettingPTR(pScrn); 311 /* 312 ScreenPtr pScreen = pScrn->pScreen; 313 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 314 Bool fbAccessDisabled; 315 CARD8 *fbstart; 316 */ 317 318 if (ms->screen || ms->kms) 319 return TRUE; 320 321 if (!ms->no3D) 322 ms->screen = driver_descriptor.create_screen(ms->fd); 323 324 if (ms->screen) 325 return TRUE; 326 327#ifdef HAVE_LIBKMS 328 if (!kms_create(ms->fd, &ms->kms)) 329 return TRUE; 330#endif 331 332 return FALSE; 333} 334 335static Bool 336drv_close_resource_management(ScrnInfoPtr pScrn) 337{ 338 modesettingPtr ms = modesettingPTR(pScrn); 339 340 if (ms->screen) { 341 assert(ms->ctx == NULL); 342 ms->screen->destroy(ms->screen); 343 } 344 ms->screen = NULL; 345 346#ifdef HAVE_LIBKMS 347 if (ms->kms) 348 kms_destroy(&ms->kms); 349#endif 350 351 return TRUE; 352} 353 354static void 355drv_cleanup_fences(ScrnInfoPtr pScrn) 356{ 357 modesettingPtr ms = modesettingPTR(pScrn); 358 int i; 359 360 assert(ms->screen); 361 362 for (i = 0; i < XORG_NR_FENCES; i++) { 363 if (ms->fence[i]) { 364 ms->screen->fence_finish(ms->screen, ms->fence[i], 0); 365 ms->screen->fence_reference(ms->screen, &ms->fence[i], NULL); 366 } 367 } 368} 369 370static Bool 371drv_pre_init(ScrnInfoPtr pScrn, int flags) 372{ 373 xf86CrtcConfigPtr xf86_config; 374 modesettingPtr ms; 375 rgb defaultWeight = { 0, 0, 0 }; 376 EntityInfoPtr pEnt; 377 EntPtr msEnt = NULL; 378 int max_width, max_height; 379 CustomizerPtr cust; 380 381 if (pScrn->numEntities != 1) 382 return FALSE; 383 384 pEnt = xf86GetEntityInfo(pScrn->entityList[0]); 385 386 if (flags & PROBE_DETECT) { 387 drv_probe_ddc(pScrn, pEnt->index); 388 return TRUE; 389 } 390 391 cust = (CustomizerPtr) pScrn->driverPrivate; 392 pScrn->driverPrivate = NULL; 393 394 /* Allocate driverPrivate */ 395 if (!drv_get_rec(pScrn)) 396 return FALSE; 397 398 ms = modesettingPTR(pScrn); 399 ms->pEnt = pEnt; 400 ms->cust = cust; 401 402 pScrn->displayWidth = 640; /* default it */ 403 404 if (ms->pEnt->location.type != BUS_PCI) 405 return FALSE; 406 407 ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); 408 409 /* Allocate an entity private if necessary */ 410 if (xf86IsEntityShared(pScrn->entityList[0])) { 411 FatalError("Entity"); 412#if 0 413 msEnt = xf86GetEntityPrivate(pScrn->entityList[0], 414 modesettingEntityIndex)->ptr; 415 ms->entityPrivate = msEnt; 416#else 417 (void)msEnt; 418#endif 419 } else 420 ms->entityPrivate = NULL; 421 422 if (xf86IsEntityShared(pScrn->entityList[0])) { 423 if (xf86IsPrimInitDone(pScrn->entityList[0])) { 424 /* do something */ 425 } else { 426 xf86SetPrimInitDone(pScrn->entityList[0]); 427 } 428 } 429 430 ms->fd = -1; 431 if (!drv_init_drm(pScrn)) 432 return FALSE; 433 434 pScrn->monitor = pScrn->confScreen->monitor; 435 pScrn->progClock = TRUE; 436 pScrn->rgbBits = 8; 437 438 if (!xf86SetDepthBpp 439 (pScrn, 0, 0, 0, 440 PreferConvert24to32 | SupportConvert24to32 | Support32bppFb)) 441 return FALSE; 442 443 switch (pScrn->depth) { 444 case 15: 445 case 16: 446 case 24: 447 break; 448 default: 449 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 450 "Given depth (%d) is not supported by the driver\n", 451 pScrn->depth); 452 return FALSE; 453 } 454 xf86PrintDepthBpp(pScrn); 455 456 if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) 457 return FALSE; 458 if (!xf86SetDefaultVisual(pScrn, -1)) 459 return FALSE; 460 461 /* Process the options */ 462 xf86CollectOptions(pScrn, NULL); 463 if (!(ms->Options = xalloc(sizeof(drv_options)))) 464 return FALSE; 465 memcpy(ms->Options, drv_options, sizeof(drv_options)); 466 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); 467 468 /* Allocate an xf86CrtcConfig */ 469 xf86CrtcConfigInit(pScrn, &crtc_config_funcs); 470 xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 471 472 max_width = 2048; /* A very low default */ 473 max_height = 2048; /* see screen_init */ 474 xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height); 475 476 if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) { 477 ms->SWCursor = TRUE; 478 } 479 480 xorg_crtc_init(pScrn); 481 xorg_output_init(pScrn); 482 483 if (!xf86InitialConfiguration(pScrn, TRUE)) { 484 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); 485 return FALSE; 486 } 487 488 /* 489 * If the driver can do gamma correction, it should call xf86SetGamma() here. 490 */ 491 { 492 Gamma zeros = { 0.0, 0.0, 0.0 }; 493 494 if (!xf86SetGamma(pScrn, zeros)) { 495 return FALSE; 496 } 497 } 498 499 if (pScrn->modes == NULL) { 500 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); 501 return FALSE; 502 } 503 504 pScrn->currentMode = pScrn->modes; 505 506 /* Set display resolution */ 507 xf86SetDpi(pScrn, 0, 0); 508 509 /* Load the required sub modules */ 510 if (!xf86LoadSubModule(pScrn, "fb")) 511 return FALSE; 512 513 /* XXX: these aren't needed when we are using libkms */ 514 if (!xf86LoadSubModule(pScrn, "exa")) 515 return FALSE; 516 517#ifdef DRI2 518 if (!xf86LoadSubModule(pScrn, "dri2")) 519 return FALSE; 520#endif 521 522 return TRUE; 523} 524 525static void drv_block_handler(int i, pointer blockData, pointer pTimeout, 526 pointer pReadmask) 527{ 528 ScreenPtr pScreen = screenInfo.screens[i]; 529 modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]); 530 531 pScreen->BlockHandler = ms->blockHandler; 532 pScreen->BlockHandler(i, blockData, pTimeout, pReadmask); 533 pScreen->BlockHandler = drv_block_handler; 534 535 if (ms->ctx) { 536 int j; 537 538 ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, 539 ms->dirtyThrottling ? 540 &ms->fence[XORG_NR_FENCES-1] : 541 NULL); 542 543 if (ms->dirtyThrottling) { 544 if (ms->fence[0]) 545 ms->ctx->screen->fence_finish(ms->ctx->screen, 546 ms->fence[0], 0); 547 548 /* The amount of rendering generated by a block handler can be 549 * quite small. Let us get a fair way ahead of hardware before 550 * throttling. 551 */ 552 for (j = 0; j < XORG_NR_FENCES - 1; j++) 553 ms->screen->fence_reference(ms->screen, 554 &ms->fence[j], 555 ms->fence[j+1]); 556 557 ms->screen->fence_reference(ms->screen, 558 &ms->fence[XORG_NR_FENCES-1], 559 NULL); 560 } 561 } 562 563 564#ifdef DRM_MODE_FEATURE_DIRTYFB 565 { 566 RegionPtr dirty = DamageRegion(ms->damage); 567 unsigned num_cliprects = REGION_NUM_RECTS(dirty); 568 569 if (num_cliprects) { 570 drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip)); 571 BoxPtr rect = REGION_RECTS(dirty); 572 int i, ret; 573 574 /* XXX no need for copy? */ 575 for (i = 0; i < num_cliprects; i++, rect++) { 576 clip[i].x1 = rect->x1; 577 clip[i].y1 = rect->y1; 578 clip[i].x2 = rect->x2; 579 clip[i].y2 = rect->y2; 580 } 581 582 /* TODO query connector property to see if this is needed */ 583 ret = drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects); 584 if (ret) { 585 debug_printf("%s: failed to send dirty (%i, %s)\n", 586 __func__, ret, strerror(-ret)); 587 } 588 589 DamageEmpty(ms->damage); 590 } 591 } 592#endif 593} 594 595static Bool 596drv_create_screen_resources(ScreenPtr pScreen) 597{ 598 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 599 modesettingPtr ms = modesettingPTR(pScrn); 600 PixmapPtr rootPixmap; 601 Bool ret; 602 603 ms->noEvict = TRUE; 604 605 pScreen->CreateScreenResources = ms->createScreenResources; 606 ret = pScreen->CreateScreenResources(pScreen); 607 pScreen->CreateScreenResources = drv_create_screen_resources; 608 609 ms->bind_front_buffer(pScrn); 610 611 ms->noEvict = FALSE; 612 613 drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 614 615#ifdef DRM_MODE_FEATURE_DIRTYFB 616 rootPixmap = pScreen->GetScreenPixmap(pScreen); 617 ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE, 618 pScreen, rootPixmap); 619 620 if (ms->damage) { 621 DamageRegister(&rootPixmap->drawable, ms->damage); 622 623 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n"); 624 } else { 625 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 626 "Failed to create screen damage record\n"); 627 return FALSE; 628 } 629#else 630 (void)rootPixmap; 631#endif 632 633 return ret; 634} 635 636static Bool 637drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) 638{ 639 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 640 modesettingPtr ms = modesettingPTR(pScrn); 641 unsigned max_width, max_height; 642 VisualPtr visual; 643 CustomizerPtr cust = ms->cust; 644 MessageType from_st; 645 MessageType from_dt; 646 MessageType from_3D; 647 Bool use3D; 648 649 if (!drv_init_drm(pScrn)) { 650 FatalError("Could not init DRM"); 651 return FALSE; 652 } 653 654 use3D = cust ? !cust->no_3d : TRUE; 655 from_3D = xf86GetOptValBool(ms->Options, OPTION_3D_ACCEL, 656 &use3D) ? 657 X_CONFIG : X_PROBED; 658 659 ms->no3D = !use3D; 660 661 if (!drv_init_resource_management(pScrn)) { 662 FatalError("Could not init resource management (!pipe_screen && !libkms)"); 663 return FALSE; 664 } 665 666 if (!drv_init_front_buffer_functions(pScrn)) { 667 FatalError("Could not init front buffer manager"); 668 return FALSE; 669 } 670 671 /* get max width and height */ 672 { 673 drmModeResPtr res; 674 res = drmModeGetResources(ms->fd); 675 max_width = res->max_width; 676 max_height = res->max_height; 677 drmModeFreeResources(res); 678 } 679 680 if (ms->screen) { 681 int max; 682 max = ms->screen->get_param(ms->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); 683 max = 1 << (max - 1); 684 max_width = max < max_width ? max : max_width; 685 max_height = max < max_height ? max : max_height; 686 } 687 688 xf86CrtcSetSizeRange(pScrn, 1, 1, max_width, max_height); 689 690 pScrn->pScreen = pScreen; 691 692 /* HW dependent - FIXME */ 693 pScrn->displayWidth = pScrn->virtualX; 694 695 miClearVisualTypes(); 696 697 if (!miSetVisualTypes(pScrn->depth, 698 miGetDefaultVisualMask(pScrn->depth), 699 pScrn->rgbBits, pScrn->defaultVisual)) 700 return FALSE; 701 702 if (!miSetPixmapDepths()) 703 return FALSE; 704 705 pScrn->memPhysBase = 0; 706 pScrn->fbOffset = 0; 707 708 if (!fbScreenInit(pScreen, NULL, 709 pScrn->virtualX, pScrn->virtualY, 710 pScrn->xDpi, pScrn->yDpi, 711 pScrn->displayWidth, pScrn->bitsPerPixel)) 712 return FALSE; 713 714 if (pScrn->bitsPerPixel > 8) { 715 /* Fixup RGB ordering */ 716 visual = pScreen->visuals + pScreen->numVisuals; 717 while (--visual >= pScreen->visuals) { 718 if ((visual->class | DynamicClass) == DirectColor) { 719 visual->offsetRed = pScrn->offset.red; 720 visual->offsetGreen = pScrn->offset.green; 721 visual->offsetBlue = pScrn->offset.blue; 722 visual->redMask = pScrn->mask.red; 723 visual->greenMask = pScrn->mask.green; 724 visual->blueMask = pScrn->mask.blue; 725 } 726 } 727 } 728 729 fbPictureInit(pScreen, NULL, 0); 730 731 ms->blockHandler = pScreen->BlockHandler; 732 pScreen->BlockHandler = drv_block_handler; 733 ms->createScreenResources = pScreen->CreateScreenResources; 734 pScreen->CreateScreenResources = drv_create_screen_resources; 735 736 xf86SetBlackWhitePixels(pScreen); 737 738 ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE); 739 ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d); 740 741 if (cust && cust->winsys_screen_init) 742 cust->winsys_screen_init(cust, ms->fd); 743 744 ms->swapThrottling = cust ? cust->swap_throttling : TRUE; 745 from_st = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_SWAP, 746 &ms->swapThrottling) ? 747 X_CONFIG : X_DEFAULT; 748 749 ms->dirtyThrottling = cust ? cust->dirty_throttling : TRUE; 750 from_dt = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_DIRTY, 751 &ms->dirtyThrottling) ? 752 X_CONFIG : X_DEFAULT; 753 754 if (ms->screen) { 755 ms->exa = xorg_exa_init(pScrn, ms->accelerate_2d); 756 757 xorg_xv_init(pScreen); 758#ifdef DRI2 759 xorg_dri2_init(pScreen); 760#endif 761 } 762 763 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n"); 764 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "# Usefull debugging info follows #\n"); 765 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n"); 766 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %s backend\n", 767 ms->screen ? "Gallium3D" : "libkms"); 768 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D Acceleration is %s\n", 769 ms->screen && ms->accelerate_2d ? "enabled" : "disabled"); 770 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Fallback debugging is %s\n", 771 ms->debug_fallback ? "enabled" : "disabled"); 772#ifdef DRI2 773 xf86DrvMsg(pScrn->scrnIndex, from_3D, "3D Acceleration is %s\n", 774 ms->screen ? "enabled" : "disabled"); 775#else 776 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled\n"); 777#endif 778 xf86DrvMsg(pScrn->scrnIndex, from_st, "Swap Throttling is %s.\n", 779 ms->swapThrottling ? "enabled" : "disabled"); 780 xf86DrvMsg(pScrn->scrnIndex, from_dt, "Dirty Throttling is %s.\n", 781 ms->dirtyThrottling ? "enabled" : "disabled"); 782 783 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n"); 784 785 miInitializeBackingStore(pScreen); 786 xf86SetBackingStore(pScreen); 787 xf86SetSilkenMouse(pScreen); 788 miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); 789 790 /* Need to extend HWcursor support to handle mask interleave */ 791 if (!ms->SWCursor) 792 xf86_cursors_init(pScreen, 64, 64, 793 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | 794 HARDWARE_CURSOR_ARGB); 795 796 /* Must force it before EnterVT, so we are in control of VT and 797 * later memory should be bound when allocating, e.g rotate_mem */ 798 pScrn->vtSema = TRUE; 799 800 pScreen->SaveScreen = xf86SaveScreen; 801 ms->CloseScreen = pScreen->CloseScreen; 802 pScreen->CloseScreen = drv_close_screen; 803 804 if (!xf86CrtcScreenInit(pScreen)) 805 return FALSE; 806 807 if (!miCreateDefColormap(pScreen)) 808 return FALSE; 809 810 xf86DPMSInit(pScreen, xf86DPMSSet, 0); 811 812 if (serverGeneration == 1) 813 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 814 815 return drv_enter_vt(scrnIndex, 1); 816} 817 818static void 819drv_adjust_frame(int scrnIndex, int x, int y, int flags) 820{ 821 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 822 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 823 xf86OutputPtr output = config->output[config->compat_output]; 824 xf86CrtcPtr crtc = output->crtc; 825 826 if (crtc && crtc->enabled) { 827 crtc->funcs->set_mode_major(crtc, pScrn->currentMode, 828 RR_Rotate_0, x, y); 829 crtc->x = output->initial_x + x; 830 crtc->y = output->initial_y + y; 831 } 832} 833 834static void 835drv_free_screen(int scrnIndex, int flags) 836{ 837 drv_free_rec(xf86Screens[scrnIndex]); 838} 839 840static void 841drv_leave_vt(int scrnIndex, int flags) 842{ 843 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 844 modesettingPtr ms = modesettingPTR(pScrn); 845 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 846 CustomizerPtr cust = ms->cust; 847 int o; 848 849 if (cust && cust->winsys_leave_vt) 850 cust->winsys_leave_vt(cust); 851 852 for (o = 0; o < config->num_crtc; o++) { 853 xf86CrtcPtr crtc = config->crtc[o]; 854 855 xorg_crtc_cursor_destroy(crtc); 856 857 if (crtc->rotatedPixmap || crtc->rotatedData) { 858 crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, 859 crtc->rotatedData); 860 crtc->rotatedPixmap = NULL; 861 crtc->rotatedData = NULL; 862 } 863 } 864 865 drmModeRmFB(ms->fd, ms->fb_id); 866 ms->fb_id = -1; 867 868 /* idle hardware */ 869 if (!ms->kms) 870 drv_cleanup_fences(pScrn); 871 872 if (drmDropMaster(ms->fd)) 873 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 874 "drmDropMaster failed: %s\n", strerror(errno)); 875 876 pScrn->vtSema = FALSE; 877} 878 879/* 880 * This gets called when gaining control of the VT, and from ScreenInit(). 881 */ 882static Bool 883drv_enter_vt(int scrnIndex, int flags) 884{ 885 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 886 modesettingPtr ms = modesettingPTR(pScrn); 887 CustomizerPtr cust = ms->cust; 888 889 if (drmSetMaster(ms->fd)) { 890 if (errno == EINVAL) { 891 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 892 "drmSetMaster failed: 2.6.29 or newer kernel required for " 893 "multi-server DRI\n"); 894 } else { 895 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 896 "drmSetMaster failed: %s\n", strerror(errno)); 897 } 898 } 899 900 if (!ms->create_front_buffer(pScrn)) 901 return FALSE; 902 903 if (!flags && !ms->bind_front_buffer(pScrn)) 904 return FALSE; 905 906 if (!xf86SetDesiredModes(pScrn)) 907 return FALSE; 908 909 if (cust && cust->winsys_enter_vt) 910 cust->winsys_enter_vt(cust); 911 912 return TRUE; 913} 914 915static Bool 916drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags) 917{ 918 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 919 920 return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); 921} 922 923static Bool 924drv_close_screen(int scrnIndex, ScreenPtr pScreen) 925{ 926 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 927 modesettingPtr ms = modesettingPTR(pScrn); 928 CustomizerPtr cust = ms->cust; 929 930 if (ms->cursor) { 931 FreeCursor(ms->cursor, None); 932 ms->cursor = NULL; 933 } 934 935 if (cust && cust->winsys_screen_close) 936 cust->winsys_screen_close(cust); 937 938#ifdef DRI2 939 if (ms->screen) 940 xorg_dri2_close(pScreen); 941#endif 942 943 pScreen->BlockHandler = ms->blockHandler; 944 pScreen->CreateScreenResources = ms->createScreenResources; 945 946#ifdef DRM_MODE_FEATURE_DIRTYFB 947 if (ms->damage) { 948 DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage); 949 DamageDestroy(ms->damage); 950 ms->damage = NULL; 951 } 952#endif 953 954 drmModeRmFB(ms->fd, ms->fb_id); 955 ms->destroy_front_buffer(pScrn); 956 957 if (ms->exa) 958 xorg_exa_close(pScrn); 959 ms->exa = NULL; 960 961 /* calls drop master make sure we don't talk to 3D HW after that */ 962 if (pScrn->vtSema) { 963 drv_leave_vt(scrnIndex, 0); 964 } 965 966 drv_close_resource_management(pScrn); 967 968 drv_close_drm(pScrn); 969 970 pScrn->vtSema = FALSE; 971 pScreen->CloseScreen = ms->CloseScreen; 972 return (*pScreen->CloseScreen) (scrnIndex, pScreen); 973} 974 975static ModeStatus 976drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) 977{ 978 return MODE_OK; 979} 980 981 982/* 983 * Front buffer backing store functions. 984 */ 985 986static Bool 987drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn) 988{ 989 modesettingPtr ms = modesettingPTR(pScrn); 990 991 if (!ms->root_texture) 992 return TRUE; 993 994 if (ms->fb_id != -1) { 995 drmModeRmFB(ms->fd, ms->fb_id); 996 ms->fb_id = -1; 997 } 998 999 pipe_resource_reference(&ms->root_texture, NULL); 1000 return TRUE; 1001} 1002 1003static Bool 1004drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn) 1005{ 1006 modesettingPtr ms = modesettingPTR(pScrn); 1007 struct pipe_resource *tex; 1008 struct winsys_handle whandle; 1009 unsigned fb_id; 1010 int ret; 1011 1012 ms->noEvict = TRUE; 1013 1014 tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY, 1015 pScrn->depth, pScrn->bitsPerPixel); 1016 1017 if (!tex) 1018 return FALSE; 1019 1020 memset(&whandle, 0, sizeof(whandle)); 1021 whandle.type = DRM_API_HANDLE_TYPE_KMS; 1022 1023 if (!ms->screen->resource_get_handle(ms->screen, tex, &whandle)) 1024 goto err_destroy; 1025 1026 ret = drmModeAddFB(ms->fd, 1027 pScrn->virtualX, 1028 pScrn->virtualY, 1029 pScrn->depth, 1030 pScrn->bitsPerPixel, 1031 whandle.stride, 1032 whandle.handle, 1033 &fb_id); 1034 if (ret) { 1035 debug_printf("%s: failed to create framebuffer (%i, %s)\n", 1036 __func__, ret, strerror(-ret)); 1037 goto err_destroy; 1038 } 1039 1040 if (!drv_destroy_front_buffer_ga3d(pScrn)) 1041 FatalError("%s: failed to take down old framebuffer\n", __func__); 1042 1043 pScrn->frameX0 = 0; 1044 pScrn->frameY0 = 0; 1045 drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 1046 1047 pipe_resource_reference(&ms->root_texture, tex); 1048 pipe_resource_reference(&tex, NULL); 1049 ms->fb_id = fb_id; 1050 1051 return TRUE; 1052 1053err_destroy: 1054 pipe_resource_reference(&tex, NULL); 1055 return FALSE; 1056} 1057 1058static Bool 1059drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn) 1060{ 1061 modesettingPtr ms = modesettingPTR(pScrn); 1062 ScreenPtr pScreen = pScrn->pScreen; 1063 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 1064 struct pipe_resource *check; 1065 1066 xorg_exa_set_displayed_usage(rootPixmap); 1067 xorg_exa_set_shared_usage(rootPixmap); 1068 xorg_exa_set_texture(rootPixmap, ms->root_texture); 1069 if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL)) 1070 FatalError("Couldn't adjust screen pixmap\n"); 1071 1072 check = xorg_exa_get_texture(rootPixmap); 1073 if (ms->root_texture != check) 1074 FatalError("Created new root texture\n"); 1075 1076 pipe_resource_reference(&check, NULL); 1077 return TRUE; 1078} 1079 1080#ifdef HAVE_LIBKMS 1081static Bool 1082drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn) 1083{ 1084 modesettingPtr ms = modesettingPTR(pScrn); 1085 ScreenPtr pScreen = pScrn->pScreen; 1086 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 1087 1088 /* XXX Do something with the rootPixmap. 1089 * This currently works fine but if we are getting crashes in 1090 * the fb functions after VT switches maybe look more into it. 1091 */ 1092 (void)rootPixmap; 1093 1094 if (!ms->root_bo) 1095 return TRUE; 1096 1097 if (ms->fb_id != -1) { 1098 drmModeRmFB(ms->fd, ms->fb_id); 1099 ms->fb_id = -1; 1100 } 1101 1102 kms_bo_unmap(ms->root_bo); 1103 kms_bo_destroy(&ms->root_bo); 1104 return TRUE; 1105} 1106 1107static Bool 1108drv_create_front_buffer_kms(ScrnInfoPtr pScrn) 1109{ 1110 modesettingPtr ms = modesettingPTR(pScrn); 1111 unsigned handle, stride; 1112 struct kms_bo *bo; 1113 unsigned attr[8]; 1114 unsigned fb_id; 1115 int ret; 1116 1117 attr[0] = KMS_BO_TYPE; 1118#ifdef KMS_BO_TYPE_SCANOUT_X8R8G8B8 1119 attr[1] = KMS_BO_TYPE_SCANOUT_X8R8G8B8; 1120#else 1121 attr[1] = KMS_BO_TYPE_SCANOUT; 1122#endif 1123 attr[2] = KMS_WIDTH; 1124 attr[3] = pScrn->virtualX; 1125 attr[4] = KMS_HEIGHT; 1126 attr[5] = pScrn->virtualY; 1127 attr[6] = 0; 1128 1129 if (kms_bo_create(ms->kms, attr, &bo)) 1130 return FALSE; 1131 1132 if (kms_bo_get_prop(bo, KMS_PITCH, &stride)) 1133 goto err_destroy; 1134 1135 if (kms_bo_get_prop(bo, KMS_HANDLE, &handle)) 1136 goto err_destroy; 1137 1138 ret = drmModeAddFB(ms->fd, 1139 pScrn->virtualX, 1140 pScrn->virtualY, 1141 pScrn->depth, 1142 pScrn->bitsPerPixel, 1143 stride, 1144 handle, 1145 &fb_id); 1146 if (ret) { 1147 debug_printf("%s: failed to create framebuffer (%i, %s)", 1148 __func__, ret, strerror(-ret)); 1149 goto err_destroy; 1150 } 1151 1152 if (!drv_destroy_front_buffer_kms(pScrn)) 1153 FatalError("%s: could not takedown old bo", __func__); 1154 1155 pScrn->frameX0 = 0; 1156 pScrn->frameY0 = 0; 1157 drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 1158 ms->root_bo = bo; 1159 ms->fb_id = fb_id; 1160 1161 return TRUE; 1162 1163err_destroy: 1164 kms_bo_destroy(&bo); 1165 return FALSE; 1166} 1167 1168static Bool 1169drv_bind_front_buffer_kms(ScrnInfoPtr pScrn) 1170{ 1171 modesettingPtr ms = modesettingPTR(pScrn); 1172 ScreenPtr pScreen = pScrn->pScreen; 1173 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 1174 unsigned stride; 1175 void *ptr; 1176 1177 if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride)) 1178 return FALSE; 1179 1180 if (kms_bo_map(ms->root_bo, &ptr)) 1181 goto err_destroy; 1182 1183 pScreen->ModifyPixmapHeader(rootPixmap, 1184 pScrn->virtualX, 1185 pScrn->virtualY, 1186 pScreen->rootDepth, 1187 pScrn->bitsPerPixel, 1188 stride, 1189 ptr); 1190 1191 /* This a hack to work around EnableDisableFBAccess setting the pointer 1192 * the real fix would be to replace pScrn->EnableDisableFBAccess hook 1193 * and set the rootPixmap->devPrivate.ptr to something valid before that. 1194 * 1195 * But in its infinit visdome something uses either this some times before 1196 * that, so our hook doesn't get called before the crash happens. 1197 */ 1198 pScrn->pixmapPrivate.ptr = ptr; 1199 1200 return TRUE; 1201 1202err_destroy: 1203 kms_bo_destroy(&ms->root_bo); 1204 return FALSE; 1205} 1206#endif /* HAVE_LIBKMS */ 1207 1208static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn) 1209{ 1210 modesettingPtr ms = modesettingPTR(pScrn); 1211 if (ms->screen) { 1212 ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d; 1213 ms->create_front_buffer = drv_create_front_buffer_ga3d; 1214 ms->bind_front_buffer = drv_bind_front_buffer_ga3d; 1215#ifdef HAVE_LIBKMS 1216 } else if (ms->kms) { 1217 ms->destroy_front_buffer = drv_destroy_front_buffer_kms; 1218 ms->create_front_buffer = drv_create_front_buffer_kms; 1219 ms->bind_front_buffer = drv_bind_front_buffer_kms; 1220#endif 1221 } else 1222 return FALSE; 1223 1224 return TRUE; 1225} 1226 1227CustomizerPtr xorg_customizer(ScrnInfoPtr pScrn) 1228{ 1229 return modesettingPTR(pScrn)->cust; 1230} 1231 1232Bool xorg_has_gallium(ScrnInfoPtr pScrn) 1233{ 1234 return modesettingPTR(pScrn)->screen != NULL; 1235} 1236 1237/* vim: set sw=4 ts=8 sts=4: */ 1238