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