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