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