xorg_driver.c revision 53e314cb8057797ae75187d91836a50f61170dd7
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#include <X11/extensions/Xv.h> 49#ifndef XSERVER_LIBPCIACCESS 50#error "libpciaccess needed" 51#endif 52 53#include <pciaccess.h> 54 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} drv_option_enums; 83 84static const OptionInfoRec drv_options[] = { 85 {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, 86 {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE}, 87 {-1, NULL, OPTV_NONE, {0}, FALSE} 88}; 89 90 91/* 92 * Exported Xorg driver functions to winsys 93 */ 94 95const OptionInfoRec * 96xorg_tracker_available_options(int chipid, int busid) 97{ 98 return drv_options; 99} 100 101void 102xorg_tracker_set_functions(ScrnInfoPtr scrn) 103{ 104 scrn->PreInit = drv_pre_init; 105 scrn->ScreenInit = drv_screen_init; 106 scrn->SwitchMode = drv_switch_mode; 107 scrn->AdjustFrame = drv_adjust_frame; 108 scrn->EnterVT = drv_enter_vt; 109 scrn->LeaveVT = drv_leave_vt; 110 scrn->FreeScreen = drv_free_screen; 111 scrn->ValidMode = drv_valid_mode; 112} 113 114 115/* 116 * Internal function definitions 117 */ 118 119static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn); 120static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen); 121static Bool drv_save_hw_state(ScrnInfoPtr pScrn); 122static Bool drv_restore_hw_state(ScrnInfoPtr pScrn); 123 124 125/* 126 * Internal functions 127 */ 128 129static Bool 130drv_get_rec(ScrnInfoPtr pScrn) 131{ 132 if (pScrn->driverPrivate) 133 return TRUE; 134 135 pScrn->driverPrivate = xnfcalloc(sizeof(modesettingRec), 1); 136 137 return TRUE; 138} 139 140static void 141drv_free_rec(ScrnInfoPtr pScrn) 142{ 143 if (!pScrn) 144 return; 145 146 if (!pScrn->driverPrivate) 147 return; 148 149 xfree(pScrn->driverPrivate); 150 151 pScrn->driverPrivate = NULL; 152} 153 154static void 155drv_probe_ddc(ScrnInfoPtr pScrn, int index) 156{ 157 ConfiguredMonitor = NULL; 158} 159 160static Bool 161drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height) 162{ 163 modesettingPtr ms = modesettingPTR(pScrn); 164 PixmapPtr rootPixmap; 165 ScreenPtr pScreen = pScrn->pScreen; 166 167 if (width == pScrn->virtualX && height == pScrn->virtualY) 168 return TRUE; 169 170 pScrn->virtualX = width; 171 pScrn->virtualY = height; 172 173 /* 174 * Remove the old framebuffer & texture. 175 */ 176 drmModeRmFB(ms->fd, ms->fb_id); 177 if (!ms->destroy_front_buffer(pScrn)) 178 FatalError("failed to destroy front buffer\n"); 179 180 rootPixmap = pScreen->GetScreenPixmap(pScreen); 181 if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL)) 182 return FALSE; 183 184 /* HW dependent - FIXME */ 185 pScrn->displayWidth = pScrn->virtualX; 186 187 /* now create new frontbuffer */ 188 return ms->create_front_buffer(pScrn) && ms->bind_front_buffer(pScrn); 189} 190 191static const xf86CrtcConfigFuncsRec crtc_config_funcs = { 192 .resize = drv_crtc_resize 193}; 194 195static Bool 196drv_init_drm(ScrnInfoPtr pScrn) 197{ 198 modesettingPtr ms = modesettingPTR(pScrn); 199 200 /* deal with server regeneration */ 201 if (ms->fd < 0) { 202 char *BusID; 203 204 BusID = xalloc(64); 205 sprintf(BusID, "PCI:%d:%d:%d", 206 ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), 207 ms->PciInfo->dev, ms->PciInfo->func 208 ); 209 210 ms->fd = drmOpen(NULL, BusID); 211 212 if (ms->fd < 0) 213 return FALSE; 214 } 215 216 return TRUE; 217} 218 219static Bool 220drv_init_resource_management(ScrnInfoPtr pScrn) 221{ 222 modesettingPtr ms = modesettingPTR(pScrn); 223 /* 224 ScreenPtr pScreen = pScrn->pScreen; 225 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 226 Bool fbAccessDisabled; 227 CARD8 *fbstart; 228 */ 229 230 if (ms->screen || ms->kms) 231 return TRUE; 232 233 ms->api = drm_api_create(); 234 if (ms->api) { 235 ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL); 236 237 if (ms->screen) 238 return TRUE; 239 240 if (ms->api->destroy) 241 ms->api->destroy(ms->api); 242 243 ms->api = NULL; 244 } 245 246#ifdef HAVE_LIBKMS 247 if (!kms_create(ms->fd, &ms->kms)) 248 return TRUE; 249#endif 250 251 return FALSE; 252} 253 254static Bool 255drv_close_resource_management(ScrnInfoPtr pScrn) 256{ 257 modesettingPtr ms = modesettingPTR(pScrn); 258 259 if (ms->screen) 260 ms->screen->destroy(ms->screen); 261 ms->screen = NULL; 262 263 if (ms->api && ms->api->destroy) 264 ms->api->destroy(ms->api); 265 ms->api = NULL; 266 267#ifdef HAVE_LIBKMS 268 if (ms->kms) 269 kms_destroy(&ms->kms); 270#endif 271 272 return TRUE; 273} 274 275static Bool 276drv_pre_init(ScrnInfoPtr pScrn, int flags) 277{ 278 xf86CrtcConfigPtr xf86_config; 279 modesettingPtr ms; 280 rgb defaultWeight = { 0, 0, 0 }; 281 EntityInfoPtr pEnt; 282 EntPtr msEnt = NULL; 283 int max_width, max_height; 284 285 if (pScrn->numEntities != 1) 286 return FALSE; 287 288 pEnt = xf86GetEntityInfo(pScrn->entityList[0]); 289 290 if (flags & PROBE_DETECT) { 291 drv_probe_ddc(pScrn, pEnt->index); 292 return TRUE; 293 } 294 295 /* Allocate driverPrivate */ 296 if (!drv_get_rec(pScrn)) 297 return FALSE; 298 299 ms = modesettingPTR(pScrn); 300 ms->SaveGeneration = -1; 301 ms->pEnt = pEnt; 302 303 pScrn->displayWidth = 640; /* default it */ 304 305 if (ms->pEnt->location.type != BUS_PCI) 306 return FALSE; 307 308 ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); 309 310 /* Allocate an entity private if necessary */ 311 if (xf86IsEntityShared(pScrn->entityList[0])) { 312 FatalError("Entity"); 313#if 0 314 msEnt = xf86GetEntityPrivate(pScrn->entityList[0], 315 modesettingEntityIndex)->ptr; 316 ms->entityPrivate = msEnt; 317#else 318 (void)msEnt; 319#endif 320 } else 321 ms->entityPrivate = NULL; 322 323 if (xf86IsEntityShared(pScrn->entityList[0])) { 324 if (xf86IsPrimInitDone(pScrn->entityList[0])) { 325 /* do something */ 326 } else { 327 xf86SetPrimInitDone(pScrn->entityList[0]); 328 } 329 } 330 331 ms->fd = -1; 332 ms->api = NULL; 333 if (!drv_init_drm(pScrn)) 334 return FALSE; 335 336 pScrn->monitor = pScrn->confScreen->monitor; 337 pScrn->progClock = TRUE; 338 pScrn->rgbBits = 8; 339 340 if (!xf86SetDepthBpp 341 (pScrn, 0, 0, 0, 342 PreferConvert24to32 | SupportConvert24to32 | Support32bppFb)) 343 return FALSE; 344 345 switch (pScrn->depth) { 346 case 15: 347 case 16: 348 case 24: 349 break; 350 default: 351 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 352 "Given depth (%d) is not supported by the driver\n", 353 pScrn->depth); 354 return FALSE; 355 } 356 xf86PrintDepthBpp(pScrn); 357 358 if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) 359 return FALSE; 360 if (!xf86SetDefaultVisual(pScrn, -1)) 361 return FALSE; 362 363 /* Process the options */ 364 xf86CollectOptions(pScrn, NULL); 365 if (!(ms->Options = xalloc(sizeof(drv_options)))) 366 return FALSE; 367 memcpy(ms->Options, drv_options, sizeof(drv_options)); 368 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); 369 370 /* Allocate an xf86CrtcConfig */ 371 xf86CrtcConfigInit(pScrn, &crtc_config_funcs); 372 xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 373 374 max_width = 8192; 375 max_height = 8192; 376 xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height); 377 378 if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) { 379 ms->SWCursor = TRUE; 380 } 381 382 drv_save_hw_state(pScrn); 383 384 xorg_crtc_init(pScrn); 385 xorg_output_init(pScrn); 386 387 if (!xf86InitialConfiguration(pScrn, TRUE)) { 388 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); 389 drv_restore_hw_state(pScrn); 390 return FALSE; 391 } 392 393 drv_restore_hw_state(pScrn); 394 395 /* 396 * If the driver can do gamma correction, it should call xf86SetGamma() here. 397 */ 398 { 399 Gamma zeros = { 0.0, 0.0, 0.0 }; 400 401 if (!xf86SetGamma(pScrn, zeros)) { 402 return FALSE; 403 } 404 } 405 406 if (pScrn->modes == NULL) { 407 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); 408 return FALSE; 409 } 410 411 pScrn->currentMode = pScrn->modes; 412 413 /* Set display resolution */ 414 xf86SetDpi(pScrn, 0, 0); 415 416 /* Load the required sub modules */ 417 if (!xf86LoadSubModule(pScrn, "fb")) 418 return FALSE; 419 420 /* XXX: these aren't needed when we are using libkms */ 421 if (!xf86LoadSubModule(pScrn, "exa")) 422 return FALSE; 423 424#ifdef DRI2 425 if (!xf86LoadSubModule(pScrn, "dri2")) 426 return FALSE; 427#endif 428 429 return TRUE; 430} 431 432static Bool 433drv_save_hw_state(ScrnInfoPtr pScrn) 434{ 435 /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/ 436 437 return TRUE; 438} 439 440static Bool 441drv_restore_hw_state(ScrnInfoPtr pScrn) 442{ 443 /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/ 444 445 return TRUE; 446} 447 448static void drv_block_handler(int i, pointer blockData, pointer pTimeout, 449 pointer pReadmask) 450{ 451 ScreenPtr pScreen = screenInfo.screens[i]; 452 modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]); 453 454 pScreen->BlockHandler = ms->blockHandler; 455 pScreen->BlockHandler(i, blockData, pTimeout, pReadmask); 456 pScreen->BlockHandler = drv_block_handler; 457 458 if (ms->ctx) { 459 int j; 460 461 ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, &ms->fence[XORG_NR_FENCES-1]); 462 463 if (ms->fence[0]) 464 ms->ctx->screen->fence_finish(ms->ctx->screen, ms->fence[0], 0); 465 466 /* The amount of rendering generated by a block handler can be 467 * quite small. Let us get a fair way ahead of hardware before 468 * throttling. 469 */ 470 for (j = 0; j < XORG_NR_FENCES - 1; j++) 471 ms->screen->fence_reference(ms->screen, 472 &ms->fence[j], 473 ms->fence[j+1]); 474 475 ms->screen->fence_reference(ms->screen, 476 &ms->fence[XORG_NR_FENCES-1], 477 NULL); 478 } 479 480 481#ifdef DRM_MODE_FEATURE_DIRTYFB 482 { 483 RegionPtr dirty = DamageRegion(ms->damage); 484 unsigned num_cliprects = REGION_NUM_RECTS(dirty); 485 486 if (num_cliprects) { 487 drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip)); 488 BoxPtr rect = REGION_RECTS(dirty); 489 int i, ret; 490 491 /* XXX no need for copy? */ 492 for (i = 0; i < num_cliprects; i++, rect++) { 493 clip[i].x1 = rect->x1; 494 clip[i].y1 = rect->y1; 495 clip[i].x2 = rect->x2; 496 clip[i].y2 = rect->y2; 497 } 498 499 /* TODO query connector property to see if this is needed */ 500 ret = drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects); 501 if (ret) { 502 debug_printf("%s: failed to send dirty (%i, %s)\n", 503 __func__, ret, strerror(-ret)); 504 } 505 506 DamageEmpty(ms->damage); 507 } 508 } 509#endif 510} 511 512static Bool 513drv_create_screen_resources(ScreenPtr pScreen) 514{ 515 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 516 modesettingPtr ms = modesettingPTR(pScrn); 517 PixmapPtr rootPixmap; 518 Bool ret; 519 520 ms->noEvict = TRUE; 521 522 pScreen->CreateScreenResources = ms->createScreenResources; 523 ret = pScreen->CreateScreenResources(pScreen); 524 pScreen->CreateScreenResources = drv_create_screen_resources; 525 526 ms->bind_front_buffer(pScrn); 527 528 ms->noEvict = FALSE; 529 530 drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 531 532#ifdef DRM_MODE_FEATURE_DIRTYFB 533 rootPixmap = pScreen->GetScreenPixmap(pScreen); 534 ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE, 535 pScreen, rootPixmap); 536 537 if (ms->damage) { 538 DamageRegister(&rootPixmap->drawable, ms->damage); 539 540 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n"); 541 } else { 542 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 543 "Failed to create screen damage record\n"); 544 return FALSE; 545 } 546#else 547 (void)rootPixmap; 548#endif 549 550 return ret; 551} 552 553static Bool 554drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) 555{ 556 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 557 modesettingPtr ms = modesettingPTR(pScrn); 558 VisualPtr visual; 559 560 if (!drv_init_drm(pScrn)) { 561 FatalError("Could not init DRM"); 562 return FALSE; 563 } 564 565 if (!drv_init_resource_management(pScrn)) { 566 FatalError("Could not init resource management (!pipe_screen && !libkms)"); 567 return FALSE; 568 } 569 570 if (!drv_init_front_buffer_functions(pScrn)) { 571 FatalError("Could not init front buffer manager"); 572 return FALSE; 573 } 574 575 pScrn->pScreen = pScreen; 576 577 /* HW dependent - FIXME */ 578 pScrn->displayWidth = pScrn->virtualX; 579 580 miClearVisualTypes(); 581 582 if (!miSetVisualTypes(pScrn->depth, 583 miGetDefaultVisualMask(pScrn->depth), 584 pScrn->rgbBits, pScrn->defaultVisual)) 585 return FALSE; 586 587 if (!miSetPixmapDepths()) 588 return FALSE; 589 590 pScrn->memPhysBase = 0; 591 pScrn->fbOffset = 0; 592 593 if (!fbScreenInit(pScreen, NULL, 594 pScrn->virtualX, pScrn->virtualY, 595 pScrn->xDpi, pScrn->yDpi, 596 pScrn->displayWidth, pScrn->bitsPerPixel)) 597 return FALSE; 598 599 if (pScrn->bitsPerPixel > 8) { 600 /* Fixup RGB ordering */ 601 visual = pScreen->visuals + pScreen->numVisuals; 602 while (--visual >= pScreen->visuals) { 603 if ((visual->class | DynamicClass) == DirectColor) { 604 visual->offsetRed = pScrn->offset.red; 605 visual->offsetGreen = pScrn->offset.green; 606 visual->offsetBlue = pScrn->offset.blue; 607 visual->redMask = pScrn->mask.red; 608 visual->greenMask = pScrn->mask.green; 609 visual->blueMask = pScrn->mask.blue; 610 } 611 } 612 } 613 614 fbPictureInit(pScreen, NULL, 0); 615 616 ms->blockHandler = pScreen->BlockHandler; 617 pScreen->BlockHandler = drv_block_handler; 618 ms->createScreenResources = pScreen->CreateScreenResources; 619 pScreen->CreateScreenResources = drv_create_screen_resources; 620 621 xf86SetBlackWhitePixels(pScreen); 622 623 if (ms->screen) { 624 ms->exa = xorg_exa_init(pScrn, xf86ReturnOptValBool(ms->Options, 625 OPTION_2D_ACCEL, TRUE)); 626 ms->debug_fallback = debug_get_bool_option("XORG_DEBUG_FALLBACK", TRUE); 627 628 xorg_xv_init(pScreen); 629#ifdef DRI2 630 xorg_dri2_init(pScreen); 631#endif 632 } 633 634 miInitializeBackingStore(pScreen); 635 xf86SetBackingStore(pScreen); 636 xf86SetSilkenMouse(pScreen); 637 miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); 638 639 /* Need to extend HWcursor support to handle mask interleave */ 640 if (!ms->SWCursor) 641 xf86_cursors_init(pScreen, 64, 64, 642 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | 643 HARDWARE_CURSOR_ARGB); 644 645 /* Must force it before EnterVT, so we are in control of VT and 646 * later memory should be bound when allocating, e.g rotate_mem */ 647 pScrn->vtSema = TRUE; 648 649 pScreen->SaveScreen = xf86SaveScreen; 650 ms->CloseScreen = pScreen->CloseScreen; 651 pScreen->CloseScreen = drv_close_screen; 652 653 if (!xf86CrtcScreenInit(pScreen)) 654 return FALSE; 655 656 if (!miCreateDefColormap(pScreen)) 657 return FALSE; 658 659 xf86DPMSInit(pScreen, xf86DPMSSet, 0); 660 661 if (serverGeneration == 1) 662 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 663 664 if (ms->winsys_screen_init) 665 ms->winsys_screen_init(pScrn); 666 667 return drv_enter_vt(scrnIndex, 1); 668} 669 670static void 671drv_adjust_frame(int scrnIndex, int x, int y, int flags) 672{ 673 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 674 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 675 xf86OutputPtr output = config->output[config->compat_output]; 676 xf86CrtcPtr crtc = output->crtc; 677 678 if (crtc && crtc->enabled) { 679 crtc->funcs->set_mode_major(crtc, pScrn->currentMode, 680 RR_Rotate_0, x, y); 681 crtc->x = output->initial_x + x; 682 crtc->y = output->initial_y + y; 683 } 684} 685 686static void 687drv_free_screen(int scrnIndex, int flags) 688{ 689 drv_free_rec(xf86Screens[scrnIndex]); 690} 691 692static void 693drv_leave_vt(int scrnIndex, int flags) 694{ 695 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 696 modesettingPtr ms = modesettingPTR(pScrn); 697 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 698 int o; 699 700 if (ms->winsys_leave_vt) 701 ms->winsys_leave_vt(pScrn); 702 703 for (o = 0; o < config->num_crtc; o++) { 704 xf86CrtcPtr crtc = config->crtc[o]; 705 706 xorg_crtc_cursor_destroy(crtc); 707 708 if (crtc->rotatedPixmap || crtc->rotatedData) { 709 crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, 710 crtc->rotatedData); 711 crtc->rotatedPixmap = NULL; 712 crtc->rotatedData = NULL; 713 } 714 } 715 716 drmModeRmFB(ms->fd, ms->fb_id); 717 718 drv_restore_hw_state(pScrn); 719 720 if (drmDropMaster(ms->fd)) 721 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 722 "drmDropMaster failed: %s\n", strerror(errno)); 723 724 pScrn->vtSema = FALSE; 725} 726 727/* 728 * This gets called when gaining control of the VT, and from ScreenInit(). 729 */ 730static Bool 731drv_enter_vt(int scrnIndex, int flags) 732{ 733 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 734 modesettingPtr ms = modesettingPTR(pScrn); 735 736 if (drmSetMaster(ms->fd)) { 737 if (errno == EINVAL) { 738 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 739 "drmSetMaster failed: 2.6.29 or newer kernel required for " 740 "multi-server DRI\n"); 741 } else { 742 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 743 "drmSetMaster failed: %s\n", strerror(errno)); 744 } 745 } 746 747 /* 748 * Only save state once per server generation since that's what most 749 * drivers do. Could change this to save state at each VT enter. 750 */ 751 if (ms->SaveGeneration != serverGeneration) { 752 ms->SaveGeneration = serverGeneration; 753 drv_save_hw_state(pScrn); 754 } 755 756 if (!ms->create_front_buffer(pScrn)) 757 return FALSE; 758 759 if (!flags && !ms->bind_front_buffer(pScrn)) 760 return FALSE; 761 762 if (!xf86SetDesiredModes(pScrn)) 763 return FALSE; 764 765 if (ms->winsys_enter_vt) 766 ms->winsys_enter_vt(pScrn); 767 768 return TRUE; 769} 770 771static Bool 772drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags) 773{ 774 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 775 776 return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); 777} 778 779static Bool 780drv_close_screen(int scrnIndex, ScreenPtr pScreen) 781{ 782 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 783 modesettingPtr ms = modesettingPTR(pScrn); 784 785 if (pScrn->vtSema) { 786 drv_leave_vt(scrnIndex, 0); 787 } 788 789 if (ms->winsys_screen_close) 790 ms->winsys_screen_close(pScrn); 791 792#ifdef DRI2 793 if (ms->screen) 794 xorg_dri2_close(pScreen); 795#endif 796 797 pScreen->BlockHandler = ms->blockHandler; 798 pScreen->CreateScreenResources = ms->createScreenResources; 799 800#ifdef DRM_MODE_FEATURE_DIRTYFB 801 if (ms->damage) { 802 DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage); 803 DamageDestroy(ms->damage); 804 ms->damage = NULL; 805 } 806#endif 807 808 drmModeRmFB(ms->fd, ms->fb_id); 809 ms->destroy_front_buffer(pScrn); 810 811 if (ms->exa) 812 xorg_exa_close(pScrn); 813 ms->exa = NULL; 814 815 drv_close_resource_management(pScrn); 816 817 drmClose(ms->fd); 818 ms->fd = -1; 819 820 pScrn->vtSema = FALSE; 821 pScreen->CloseScreen = ms->CloseScreen; 822 return (*pScreen->CloseScreen) (scrnIndex, pScreen); 823} 824 825static ModeStatus 826drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) 827{ 828 return MODE_OK; 829} 830 831 832/* 833 * Front buffer backing store functions. 834 */ 835 836static Bool 837drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn) 838{ 839 modesettingPtr ms = modesettingPTR(pScrn); 840 pipe_texture_reference(&ms->root_texture, NULL); 841 return TRUE; 842} 843 844static Bool 845drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn) 846{ 847 modesettingPtr ms = modesettingPTR(pScrn); 848 unsigned handle, stride; 849 struct pipe_texture *tex; 850 int ret; 851 852 ms->noEvict = TRUE; 853 854 tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY, 855 pScrn->depth, pScrn->bitsPerPixel); 856 857 if (!tex) 858 return FALSE; 859 860 if (!ms->api->local_handle_from_texture(ms->api, ms->screen, 861 tex, 862 &stride, 863 &handle)) 864 goto err_destroy; 865 866 ret = drmModeAddFB(ms->fd, 867 pScrn->virtualX, 868 pScrn->virtualY, 869 pScrn->depth, 870 pScrn->bitsPerPixel, 871 stride, 872 handle, 873 &ms->fb_id); 874 if (ret) { 875 debug_printf("%s: failed to create framebuffer (%i, %s)", 876 __func__, ret, strerror(-ret)); 877 goto err_destroy; 878 } 879 880 pScrn->frameX0 = 0; 881 pScrn->frameY0 = 0; 882 drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 883 884 pipe_texture_reference(&ms->root_texture, tex); 885 pipe_texture_reference(&tex, NULL); 886 887 return TRUE; 888 889err_destroy: 890 pipe_texture_reference(&tex, NULL); 891 return FALSE; 892} 893 894static Bool 895drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn) 896{ 897 modesettingPtr ms = modesettingPTR(pScrn); 898 ScreenPtr pScreen = pScrn->pScreen; 899 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 900 struct pipe_texture *check; 901 902 xorg_exa_set_displayed_usage(rootPixmap); 903 xorg_exa_set_shared_usage(rootPixmap); 904 xorg_exa_set_texture(rootPixmap, ms->root_texture); 905 if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL)) 906 FatalError("Couldn't adjust screen pixmap\n"); 907 908 check = xorg_exa_get_texture(rootPixmap); 909 if (ms->root_texture != check) 910 FatalError("Created new root texture\n"); 911 912 pipe_texture_reference(&check, NULL); 913 return TRUE; 914} 915 916#ifdef HAVE_LIBKMS 917static Bool 918drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn) 919{ 920 modesettingPtr ms = modesettingPTR(pScrn); 921 ScreenPtr pScreen = pScrn->pScreen; 922 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 923 924 if (!ms->root_bo) 925 return TRUE; 926 927 kms_bo_unmap(ms->root_bo); 928 kms_bo_destroy(&ms->root_bo); 929 return TRUE; 930} 931 932static Bool 933drv_create_front_buffer_kms(ScrnInfoPtr pScrn) 934{ 935 modesettingPtr ms = modesettingPTR(pScrn); 936 unsigned handle, stride; 937 struct kms_bo *bo; 938 unsigned attr[8]; 939 int ret; 940 941 attr[0] = KMS_BO_TYPE; 942 attr[1] = KMS_BO_TYPE_SCANOUT; 943 attr[2] = KMS_WIDTH; 944 attr[3] = pScrn->virtualX; 945 attr[4] = KMS_HEIGHT; 946 attr[5] = pScrn->virtualY; 947 attr[6] = 0; 948 949 if (kms_bo_create(ms->kms, attr, &bo)) 950 return FALSE; 951 952 if (kms_bo_get_prop(bo, KMS_PITCH, &stride)) 953 goto err_destroy; 954 955 if (kms_bo_get_prop(bo, KMS_HANDLE, &handle)) 956 goto err_destroy; 957 958 ret = drmModeAddFB(ms->fd, 959 pScrn->virtualX, 960 pScrn->virtualY, 961 pScrn->depth, 962 pScrn->bitsPerPixel, 963 stride, 964 handle, 965 &ms->fb_id); 966 if (ret) { 967 debug_printf("%s: failed to create framebuffer (%i, %s)", 968 __func__, ret, strerror(-ret)); 969 goto err_destroy; 970 } 971 972 pScrn->frameX0 = 0; 973 pScrn->frameY0 = 0; 974 drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 975 ms->root_bo = bo; 976 977 return TRUE; 978 979err_destroy: 980 kms_bo_destroy(&bo); 981 return FALSE; 982} 983 984static Bool 985drv_bind_front_buffer_kms(ScrnInfoPtr pScrn) 986{ 987 modesettingPtr ms = modesettingPTR(pScrn); 988 ScreenPtr pScreen = pScrn->pScreen; 989 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); 990 unsigned stride; 991 void *ptr; 992 993 if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride)) 994 return FALSE; 995 996 if (kms_bo_map(ms->root_bo, &ptr)) 997 goto err_destroy; 998 999 pScreen->ModifyPixmapHeader(rootPixmap, 1000 pScreen->width, 1001 pScreen->height, 1002 pScreen->rootDepth, 1003 pScrn->bitsPerPixel, 1004 stride, 1005 ptr); 1006 return TRUE; 1007 1008err_destroy: 1009 kms_bo_destroy(&ms->root_bo); 1010 return FALSE; 1011} 1012#endif /* HAVE_LIBKMS */ 1013 1014static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn) 1015{ 1016 modesettingPtr ms = modesettingPTR(pScrn); 1017 if (ms->screen) { 1018 ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d; 1019 ms->create_front_buffer = drv_create_front_buffer_ga3d; 1020 ms->bind_front_buffer = drv_bind_front_buffer_ga3d; 1021#ifdef HAVE_LIBKMS 1022 } else if (ms->kms) { 1023 ms->destroy_front_buffer = drv_destroy_front_buffer_kms; 1024 ms->create_front_buffer = drv_create_front_buffer_kms; 1025 ms->bind_front_buffer = drv_bind_front_buffer_kms; 1026#endif 1027 } else 1028 return FALSE; 1029 1030 return TRUE; 1031} 1032 1033/* vim: set sw=4 ts=8 sts=4: */ 1034