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