vmwgfx_driver.c revision 22f7e8e5
1/* 2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 3 * Copyright 2011 VMWare, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * 27 * Author: Alan Hourihane <alanh@tungstengraphics.com> 28 * Author: Jakob Bornecrantz <wallbraker@gmail.com> 29 * Author: Thomas Hellstrom <thellstrom@vmware.com> 30 */ 31 32 33#include <unistd.h> 34#include "xorg-server.h" 35#include "xf86.h" 36#include "xf86_OSproc.h" 37#include "compiler.h" 38#include "xf86Pci.h" 39#include "mipointer.h" 40#include "micmap.h" 41#include <X11/extensions/randr.h> 42#include "fb.h" 43#include "edid.h" 44#include "xf86i2c.h" 45#include "xf86Crtc.h" 46#include "miscstruct.h" 47#include "dixstruct.h" 48#include "xf86cmap.h" 49#include "xf86xv.h" 50#include "xorgVersion.h" 51#ifndef XSERVER_LIBPCIACCESS 52#error "libpciaccess needed" 53#endif 54 55#include <pciaccess.h> 56 57#include "vmwgfx_driver.h" 58 59#include <saa.h> 60#include "vmwgfx_saa.h" 61#include "../src/vmware_bootstrap.h" 62#include "../src/vmware_common.h" 63#include "vmwgfx_hosted.h" 64 65/* 66 * We can't incude svga_types.h due to conflicting types for Bool. 67 */ 68typedef int64_t int64; 69typedef uint64_t uint64; 70 71typedef int32_t int32; 72typedef uint32_t uint32; 73 74typedef int16_t int16; 75typedef uint16_t uint16; 76 77typedef int8_t int8; 78typedef uint8_t uint8; 79#include "../src/svga_reg.h" 80 81#define XA_VERSION_MINOR_REQUIRED 0 82#define XA_VERSION_MAJOR_REQUIRED 1 83#define XA_VERSION_MAJOR_COMPAT 2 84 85#define DRM_VERSION_MAJOR_REQUIRED 2 86#define DRM_VERSION_MINOR_REQUIRED 3 87 88/* 89 * Some macros to deal with function wrapping. 90 */ 91#define vmwgfx_wrap(priv, real, mem, func) {\ 92 (priv)->saved_##mem = (real)->mem; \ 93 (real)->mem = func; \ 94} 95 96#define vmwgfx_unwrap(priv, real, mem) {\ 97 (real)->mem = (priv)->saved_##mem; \ 98} 99 100#define vmwgfx_swap(priv, real, mem) {\ 101 void *tmp = (priv)->saved_##mem; \ 102 (priv)->saved_##mem = (real)->mem; \ 103 (real)->mem = tmp; \ 104} 105 106/* 107 * Functions and symbols exported to Xorg via pointers. 108 */ 109 110static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags); 111static Bool drv_screen_init(SCREEN_INIT_ARGS_DECL); 112static Bool drv_switch_mode(SWITCH_MODE_ARGS_DECL); 113static void drv_adjust_frame(ADJUST_FRAME_ARGS_DECL); 114static Bool drv_enter_vt(VT_FUNC_ARGS_DECL); 115static void drv_leave_vt(VT_FUNC_ARGS_DECL); 116static void drv_free_screen(FREE_SCREEN_ARGS_DECL); 117static ModeStatus drv_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, 118 int flags); 119 120extern void xorg_tracker_set_functions(ScrnInfoPtr scrn); 121 122void 123vmwgfx_hookup(ScrnInfoPtr pScrn) 124{ 125 pScrn->PreInit = drv_pre_init; 126 pScrn->ScreenInit = drv_screen_init; 127 pScrn->SwitchMode = drv_switch_mode; 128 pScrn->FreeScreen = drv_free_screen; 129 pScrn->ValidMode = drv_valid_mode; 130} 131 132void 133vmwgfx_modify_flags(uint32_t *flags) 134{ 135 *flags &= ~(HW_IO); 136 vmwgfx_hosted_modify_flags(flags); 137} 138/* 139 * Internal function definitions 140 */ 141 142static Bool drv_close_screen(CLOSE_SCREEN_ARGS_DECL); 143 144/* 145 * Internal functions 146 */ 147 148static Bool 149drv_get_rec(ScrnInfoPtr pScrn) 150{ 151 if (pScrn->driverPrivate) 152 return TRUE; 153 154 pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec)); 155 156 return TRUE; 157} 158 159static void 160drv_free_rec(ScrnInfoPtr pScrn) 161{ 162 if (!pScrn) 163 return; 164 165 if (!pScrn->driverPrivate) 166 return; 167 168 free(pScrn->driverPrivate); 169 170 pScrn->driverPrivate = NULL; 171} 172 173static void 174drv_probe_ddc(ScrnInfoPtr pScrn, int index) 175{ 176 ConfiguredMonitor = NULL; 177} 178 179static Bool 180drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height) 181{ 182 modesettingPtr ms = modesettingPTR(pScrn); 183 ScreenPtr pScreen = pScrn->pScreen; 184 int old_width, old_height; 185 PixmapPtr rootPixmap; 186 187 if (width == pScrn->virtualX && height == pScrn->virtualY) 188 return TRUE; 189 190 if (ms->check_fb_size) { 191 size_t size = width*(pScrn->bitsPerPixel / 8) * height + 1024; 192 193 if (size > ms->max_fb_size) { 194 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 195 "Requested framebuffer size %dx%dx%d will not fit " 196 "in display memory.\n", 197 width, height, pScrn->bitsPerPixel); 198 return FALSE; 199 } 200 } 201 202 old_width = pScrn->virtualX; 203 old_height = pScrn->virtualY; 204 pScrn->virtualX = width; 205 pScrn->virtualY = height; 206 207 /* ms->create_front_buffer will remove the old front buffer */ 208 209 rootPixmap = pScreen->GetScreenPixmap(pScreen); 210 vmwgfx_disable_scanout(pScrn); 211 if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL)) 212 goto error_modify; 213 214 pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8); 215 216 xf86SetDesiredModes(pScrn); 217 return TRUE; 218 219 /* 220 * FIXME: Try out this error recovery path and fix problems. 221 222 */ 223 //error_create: 224 if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL)) 225 FatalError("failed to resize rootPixmap error path\n"); 226 227 pScrn->displayWidth = rootPixmap->devKind / 228 (rootPixmap->drawable.bitsPerPixel / 8); 229 230 231error_modify: 232 pScrn->virtualX = old_width; 233 pScrn->virtualY = old_height; 234 235 if (xf86SetDesiredModes(pScrn)) 236 return FALSE; 237 238 FatalError("failed to setup old framebuffer\n"); 239 return FALSE; 240} 241 242static const xf86CrtcConfigFuncsRec crtc_config_funcs = { 243 .resize = drv_crtc_resize 244}; 245 246static Bool 247drv_init_drm(ScrnInfoPtr pScrn) 248{ 249 modesettingPtr ms = modesettingPTR(pScrn); 250 251 /* deal with server regeneration */ 252 if (ms->fd < 0) { 253 254 ms->fd = vmwgfx_hosted_drm_fd(ms->hdriver, ms->hosted, ms->PciInfo); 255 256 if (ms->fd < 0) { 257 258 char bus_id[64]; 259 260 snprintf(bus_id, sizeof(bus_id), "PCI:%d:%d:%d", 261 ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), 262 ms->PciInfo->dev, ms->PciInfo->func 263 ); 264 265 ms->fd = drmOpen("vmwgfx", bus_id); 266 ms->isMaster = TRUE; 267 268 } 269 270 if (ms->fd >= 0) { 271 drmVersionPtr ver = drmGetVersion(ms->fd); 272 273 if (ver == NULL) { 274 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 275 "Could not determine DRM version.\n"); 276 return FALSE; 277 } 278 279 ms->drm_major = ver->version_major; 280 ms->drm_minor = ver->version_minor; 281 ms->drm_patch = ver->version_patchlevel; 282 283 drmFreeVersion(ver); 284 return TRUE; 285 } 286 287 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 288 "Failed to open drm.\n"); 289 290 return FALSE; 291 } 292 293 return TRUE; 294} 295 296/** 297 * vmwgfx_set_topology - Set the GUI topology according to an option string 298 * 299 * @pScrn: Pointer to a ScrnInfo struct. 300 * @topology: String containing the topology description. 301 * @info: Info describing the option used to invoke this function. 302 * 303 * This function reads a GUI topology according from @topology, and 304 * calls into the kernel to set that topology. 305 */ 306static Bool 307vmwgfx_set_topology(ScrnInfoPtr pScrn, const char *topology, const char *info) 308{ 309 modesettingPtr ms = modesettingPTR(pScrn); 310 unsigned int num_outputs; 311 xXineramaScreenInfo *screen_info; 312 struct drm_vmw_rect *rects; 313 int ret; 314 unsigned int i; 315 316 screen_info = VMWAREParseTopologyString(pScrn, topology, &num_outputs, 317 info); 318 319 if (screen_info == NULL) 320 return FALSE; 321 322 rects = calloc(num_outputs, sizeof(*rects)); 323 if (rects == NULL) { 324 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 325 "Failed to allocate topology data.\n"); 326 goto out_no_rects; 327 } 328 329 for(i = 0; i < num_outputs; ++i) { 330 rects[i].x = screen_info[i].x_org; 331 rects[i].y = screen_info[i].y_org; 332 rects[i].w = screen_info[i].width; 333 rects[i].h = screen_info[i].height; 334 } 335 336 ret = vmwgfx_update_gui_layout(ms->fd, num_outputs, rects); 337 free(rects); 338 free(screen_info); 339 340 return (ret == 0); 341 342 out_no_rects: 343 free(screen_info); 344 return FALSE; 345} 346 347 348static Bool 349vmwgfx_pre_init_mode(ScrnInfoPtr pScrn, int flags) 350{ 351 modesettingPtr ms = modesettingPTR(pScrn); 352 Bool ret = TRUE; 353 354 ms->from_dp = (xf86GetOptValBool(ms->Options, OPTION_DIRECT_PRESENTS, 355 &ms->direct_presents)) ? 356 X_CONFIG : X_DEFAULT; 357 358 ms->from_hwp = (xf86GetOptValBool(ms->Options, OPTION_HW_PRESENTS, 359 &ms->only_hw_presents)) ? 360 X_CONFIG : X_DEFAULT; 361 362 /* Allocate an xf86CrtcConfig */ 363 xf86CrtcConfigInit(pScrn, &crtc_config_funcs); 364 365 /* get max width and height */ 366 { 367 drmModeResPtr res; 368 int max_width, max_height; 369 370 res = drmModeGetResources(ms->fd); 371 max_width = res->max_width; 372 max_height = res->max_height; 373 374 xf86CrtcSetSizeRange(pScrn, res->min_width, 375 res->min_height, max_width, max_height); 376 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 377 "Min width %d, Max Width %d.\n", 378 res->min_width, max_width); 379 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 380 "Min height %d, Max Height %d.\n", 381 res->min_height, max_height); 382 drmModeFreeResources(res); 383 } 384 385 ms->SWCursor = FALSE; 386 if (!xf86ReturnOptValBool(ms->Options, OPTION_HW_CURSOR, TRUE)) { 387 ms->SWCursor = TRUE; 388 } 389 390 if (xf86IsOptionSet(ms->Options, OPTION_GUI_LAYOUT)) { 391 char *topology = 392 xf86GetOptValString(ms->Options, OPTION_GUI_LAYOUT); 393 394 ret = FALSE; 395 if (topology) { 396 ret = vmwgfx_set_topology(pScrn, topology, "gui"); 397 free(topology); 398 } 399 400 } else if (xf86IsOptionSet(ms->Options, OPTION_STATIC_XINERAMA)) { 401 char *topology = 402 xf86GetOptValString(ms->Options, OPTION_STATIC_XINERAMA); 403 404 ret = FALSE; 405 if (topology) { 406 ret = vmwgfx_set_topology(pScrn, topology, "static Xinerama"); 407 free(topology); 408 } 409 } 410 411 if (!ret) 412 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Falied parsing or setting " 413 "gui topology from config file.\n"); 414 415 xorg_crtc_init(pScrn); 416 xorg_output_init(pScrn); 417 418 if (!xf86InitialConfiguration(pScrn, TRUE)) { 419 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); 420 goto out_modes; 421 } 422 423 if (pScrn->modes == NULL) { 424 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No available modes.\n"); 425 goto out_modes; 426 } 427 428 pScrn->currentMode = pScrn->modes; 429 430 return TRUE; 431 432 out_modes: 433 return FALSE; 434} 435 436static Bool 437drv_pre_init(ScrnInfoPtr pScrn, int flags) 438{ 439 modesettingPtr ms; 440 rgb defaultWeight = { 0, 0, 0 }; 441 Gamma zeros = { 0.0, 0.0, 0.0 }; 442 EntityInfoPtr pEnt; 443 uint64_t cap; 444 445 if (pScrn->numEntities != 1) 446 return FALSE; 447 448 pEnt = xf86GetEntityInfo(pScrn->entityList[0]); 449 450 if (flags & PROBE_DETECT) { 451 drv_probe_ddc(pScrn, pEnt->index); 452 return TRUE; 453 } 454 455 pScrn->driverPrivate = NULL; 456 457 /* Allocate driverPrivate */ 458 if (!drv_get_rec(pScrn)) { 459 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 460 "Failed to allocate driver private.\n"); 461 } 462 463 ms = modesettingPTR(pScrn); 464 ms->pEnt = pEnt; 465 466 pScrn->displayWidth = 640; /* default it */ 467 468 if (ms->pEnt->location.type != BUS_PCI) { 469 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 470 "Incorrect bus for device.\n"); 471 goto out_err_bus; 472 } 473 474 ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); 475 xf86SetPrimInitDone(pScrn->entityList[0]); 476 477 ms->hdriver = vmwgfx_hosted_detect(); 478 ms->hosted = vmwgfx_hosted_create(ms->hdriver, pScrn); 479 if (ms->hdriver && !ms->hosted) { 480 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 481 "Failed to set up compositor hosted environment.\n"); 482 goto out_err_bus; 483 } 484 485 pScrn->monitor = pScrn->confScreen->monitor; 486 pScrn->progClock = TRUE; 487 pScrn->rgbBits = 8; 488 489 if (!xf86SetDepthBpp 490 (pScrn, 0, 0, 0, 491 PreferConvert24to32 | SupportConvert24to32 | Support32bppFb)) { 492 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set depth and bpp.\n"); 493 goto out_err_bus; 494 } 495 496 if (!vmwgfx_hosted_pre_init(ms->hdriver, ms->hosted, flags)) 497 goto out_err_bus; 498 499 ms->fd = -1; 500 if (!drv_init_drm(pScrn)) 501 goto out_no_drm; 502 503 if (ms->drm_major != DRM_VERSION_MAJOR_REQUIRED || 504 ms->drm_minor < DRM_VERSION_MINOR_REQUIRED) { 505 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 506 "DRM driver version is %d.%d.%d\n", 507 ms->drm_major, ms->drm_minor, ms->drm_patch); 508 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 509 "But KMS- and 3D functionality needs at least " 510 "%d.%d.0 to work.\n", 511 DRM_VERSION_MAJOR_REQUIRED, 512 DRM_VERSION_MINOR_REQUIRED); 513 goto out_drm_version; 514 } else { 515 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 516 "DRM driver version is %d.%d.%d\n", 517 ms->drm_major, ms->drm_minor, ms->drm_patch); 518 } 519 520 ms->check_fb_size = (vmwgfx_max_fb_size(ms->fd, &ms->max_fb_size) == 0); 521 522 if (vmwgfx_get_param(ms->fd, DRM_VMW_PARAM_HW_CAPS, &cap) != 0) { 523 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to detect device " 524 "screen object capability.\n"); 525 goto out_depth; 526 } 527 528 if ((cap & SVGA_CAP_SCREEN_OBJECT_2) == 0) { 529 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Device is not screen object " 530 "capable.\n"); 531 goto out_depth; 532 } 533 534 switch (pScrn->depth) { 535 case 15: 536 case 16: 537 case 24: 538 break; 539 default: 540 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 541 "Given depth (%d) is not supported with KMS enabled.\n", 542 pScrn->depth); 543 goto out_depth; 544 } 545 xf86PrintDepthBpp(pScrn); 546 547 if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) 548 goto out_depth; 549 if (!xf86SetDefaultVisual(pScrn, -1)) 550 goto out_depth; 551 552 /* Process the options */ 553 xf86CollectOptions(pScrn, NULL); 554 if (!(ms->Options = VMWARECopyOptions())) 555 goto out_depth; 556 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); 557 558 ms->accelerate_render = TRUE; 559 ms->from_render = xf86GetOptValBool(ms->Options, OPTION_RENDER_ACCEL, 560 &ms->accelerate_render) ? 561 X_CONFIG : X_PROBED; 562 563 ms->rendercheck = FALSE; 564 ms->from_rendercheck = xf86GetOptValBool(ms->Options, OPTION_RENDERCHECK, 565 &ms->rendercheck) ? 566 X_CONFIG : X_DEFAULT; 567 568 ms->enable_dri = ms->accelerate_render; 569 ms->from_dri = xf86GetOptValBool(ms->Options, OPTION_DRI, 570 &ms->enable_dri) ? 571 X_CONFIG : X_PROBED; 572 573 ms->direct_presents = FALSE; 574 ms->only_hw_presents = FALSE; 575 ms->SWCursor = TRUE; 576 if (!vmwgfx_is_hosted(ms->hdriver)) { 577 if (!vmwgfx_pre_init_mode(pScrn, flags)) 578 goto out_modes; 579 } else { 580 ms->from_dp = X_CONFIG; 581 ms->from_hwp = X_CONFIG; 582 } 583 584 xf86SetDpi(pScrn, 0, 0); 585 586 if (!xf86SetGamma(pScrn, zeros)) { 587 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set gamma.\n"); 588 goto out_modes; 589 } 590 591 /* Load the required sub modules */ 592 if (!xf86LoadSubModule(pScrn, "fb")) { 593 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load fb module.\n"); 594 goto out_modes; 595 } 596 597 if (!xf86LoadSubModule(pScrn, "dri2")) { 598 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load dri2 module.\n"); 599 goto out_modes; 600 } 601 602 return TRUE; 603 604 out_modes: 605 free(ms->Options); 606 out_depth: 607 out_drm_version: 608 if (!vmwgfx_is_hosted(ms->hdriver)) 609 close(ms->fd); 610 out_no_drm: 611 vmwgfx_hosted_destroy(ms->hdriver, ms->hosted); 612 out_err_bus: 613 drv_free_rec(pScrn); 614 return FALSE; 615 616} 617 618static Bool 619vmwgfx_scanout_update(int drm_fd, int fb_id, RegionPtr dirty) 620{ 621 unsigned num_cliprects = REGION_NUM_RECTS(dirty); 622 drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip)); 623 BoxPtr rect = REGION_RECTS(dirty); 624 int i, ret; 625 626 if (!num_cliprects) 627 return TRUE; 628 629 for (i = 0; i < num_cliprects; i++, rect++) { 630 clip[i].x1 = rect->x1; 631 clip[i].y1 = rect->y1; 632 clip[i].x2 = rect->x2; 633 clip[i].y2 = rect->y2; 634 } 635 636 ret = drmModeDirtyFB(drm_fd, fb_id, clip, num_cliprects); 637 if (ret) 638 LogMessage(X_ERROR, "%s: failed to send dirty (%i, %s)\n", 639 __func__, ret, strerror(-ret)); 640 return (ret == 0); 641} 642 643static Bool 644vmwgfx_scanout_present(ScreenPtr pScreen, int drm_fd, 645 struct vmwgfx_saa_pixmap *vpix, 646 RegionPtr dirty) 647{ 648 uint32_t handle; 649 unsigned int dummy; 650 651 if (!REGION_NOTEMPTY(pScreen, dirty)) 652 return TRUE; 653 654 if (!vpix->hw) { 655 LogMessage(X_ERROR, "No surface to present from.\n"); 656 return FALSE; 657 } 658 659 if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0) { 660 LogMessage(X_ERROR, "Could not get present surface handle.\n"); 661 return FALSE; 662 } 663 664 if (vmwgfx_present(drm_fd, vpix->fb_id, 0, 0, dirty, handle) != 0) { 665 LogMessage(X_ERROR, "Failed present kernel call.\n"); 666 return FALSE; 667 } 668 669 return TRUE; 670} 671 672void xorg_flush(ScreenPtr pScreen) 673{ 674 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 675 modesettingPtr ms = modesettingPTR(pScrn); 676 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 677 PixmapPtr pixmap = NULL; 678 struct vmwgfx_saa_pixmap *vpix; 679 int i; 680 xf86CrtcPtr crtc; 681 PixmapPtr *pixmaps = calloc(config->num_crtc, sizeof(*pixmaps)); 682 unsigned int num_scanout = 0; 683 unsigned int j; 684 685 if (!pixmaps) { 686 LogMessage(X_ERROR, "Failed memory allocation during screen " 687 "update.\n"); 688 return; 689 } 690 691 /* 692 * Get an array of pixmaps from which we scan out. 693 */ 694 for (i=0; i<config->num_crtc; ++i) { 695 crtc = config->crtc[i]; 696 if (crtc->enabled) { 697 pixmap = crtc_get_scanout(crtc); 698 if (pixmap) { 699 700 /* 701 * Remove duplicates. 702 */ 703 for (j=0; j<num_scanout; ++j) { 704 if (pixmap == pixmaps[j]) 705 break; 706 } 707 708 if (j == num_scanout) 709 pixmaps[num_scanout++] = pixmap; 710 } 711 } 712 } 713 714 if (!num_scanout) 715 return; 716 717 for (j=0; j<num_scanout; ++j) { 718 pixmap = pixmaps[j]; 719 vpix = vmwgfx_saa_pixmap(pixmap); 720 721 if (vpix->fb_id != -1) { 722 if (vpix->pending_update) { 723 if (ms->only_hw_presents && 724 REGION_NOTEMPTY(pscreen, vpix->pending_update)) { 725 (void) vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, 726 0, NULL); 727 REGION_UNION(pScreen, vpix->pending_present, 728 vpix->pending_present, vpix->pending_update); 729 } else 730 (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, 731 vpix->pending_update); 732 REGION_EMPTY(pScreen, vpix->pending_update); 733 } 734 if (vpix->pending_present) { 735 if (ms->only_hw_presents) 736 (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, 737 vpix->pending_present); 738 else 739 (void) vmwgfx_scanout_present(pScreen, ms->fd, vpix, 740 vpix->pending_present); 741 REGION_EMPTY(pScreen, vpix->pending_present); 742 } 743 } 744 } 745 free(pixmaps); 746} 747 748static void drv_block_handler(BLOCKHANDLER_ARGS_DECL) 749{ 750 SCREEN_PTR(arg); 751 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen)); 752 753 vmwgfx_swap(ms, pScreen, BlockHandler); 754 pScreen->BlockHandler(BLOCKHANDLER_ARGS); 755 vmwgfx_swap(ms, pScreen, BlockHandler); 756 757 if (vmwgfx_is_hosted(ms->hdriver)) 758 vmwgfx_hosted_post_damage(ms->hdriver, ms->hosted); 759 else 760 xorg_flush(pScreen); 761} 762 763static Bool 764drv_create_screen_resources(ScreenPtr pScreen) 765{ 766 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 767 modesettingPtr ms = modesettingPTR(pScrn); 768 Bool ret; 769 770 vmwgfx_swap(ms, pScreen, CreateScreenResources); 771 ret = pScreen->CreateScreenResources(pScreen); 772 vmwgfx_swap(ms, pScreen, CreateScreenResources); 773 if (!ret) 774 return ret; 775 776 drv_adjust_frame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0)); 777 778 return drv_enter_vt(VT_FUNC_ARGS); 779} 780 781static Bool 782drv_set_master(ScrnInfoPtr pScrn) 783{ 784 modesettingPtr ms = modesettingPTR(pScrn); 785 786 if (!vmwgfx_is_hosted(ms->hdriver) && !ms->isMaster && 787 drmSetMaster(ms->fd) != 0) { 788 if (errno == EINVAL) { 789 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 790 "drmSetMaster failed: 2.6.29 or newer kernel required for " 791 "multi-server DRI\n"); 792 } else { 793 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 794 "drmSetMaster failed: %s\n", strerror(errno)); 795 } 796 return FALSE; 797 } 798 799 ms->isMaster = TRUE; 800 return TRUE; 801} 802 803/** 804 * vmwgfx_use_hw_cursor_argb - wrapper around hw argb cursor check. 805 * 806 * screen: Pointer to the current screen metadata. 807 * cursor: Pointer to the current cursor metadata. 808 * 809 * In addition to the default test, also check whether we might be 810 * needing more than one hw cursor (which we don't support). 811 */ 812static Bool 813vmwgfx_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor) 814{ 815 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 816 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 817 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 818 modesettingPtr ms = modesettingPTR(pScrn); 819 Bool ret; 820 821 vmwgfx_swap(ms, cursor_info, UseHWCursorARGB); 822 ret = cursor_info->UseHWCursorARGB(screen, cursor); 823 vmwgfx_swap(ms, cursor_info, UseHWCursorARGB); 824 if (!ret) 825 return FALSE; 826 827 /* 828 * If there is a chance we might need two cursors, 829 * revert to sw cursor. 830 */ 831 return !vmwgfx_output_explicit_overlap(pScrn); 832} 833 834/** 835 * vmwgfx_use_hw_cursor - wrapper around hw cursor check. 836 * 837 * screen: Pointer to the current screen metadata. 838 * cursor: Pointer to the current cursor metadata. 839 * 840 * In addition to the default test, also check whether we might be 841 * needing more than one hw cursor (which we don't support). 842 */ 843static Bool 844vmwgfx_use_hw_cursor(ScreenPtr screen, CursorPtr cursor) 845{ 846 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 847 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 848 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 849 modesettingPtr ms = modesettingPTR(pScrn); 850 Bool ret; 851 852 vmwgfx_swap(ms, cursor_info, UseHWCursor); 853 ret = cursor_info->UseHWCursor(screen, cursor); 854 vmwgfx_swap(ms, cursor_info, UseHWCursor); 855 if (!ret) 856 return FALSE; 857 858 /* 859 * If there is a chance we might need two simultaneous cursors, 860 * revert to sw cursor. 861 */ 862 return !vmwgfx_output_explicit_overlap(pScrn); 863} 864 865/** 866 * vmwgfx_wrap_use_hw_cursor - Wrap functions that check for hw cursor 867 * support. 868 * 869 * pScrn: Pointer to current screen info. 870 * 871 * Enables the device-specific hw cursor support check functions. 872 */ 873static void vmwgfx_wrap_use_hw_cursor(ScrnInfoPtr pScrn) 874{ 875 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 876 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 877 modesettingPtr ms = modesettingPTR(pScrn); 878 879 vmwgfx_wrap(ms, cursor_info, UseHWCursor, vmwgfx_use_hw_cursor); 880 vmwgfx_wrap(ms, cursor_info, UseHWCursorARGB, vmwgfx_use_hw_cursor_argb); 881} 882 883 884static void drv_load_palette(ScrnInfoPtr pScrn, int numColors, 885 int *indices, LOCO *colors, VisualPtr pVisual) 886{ 887 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 888 modesettingPtr ms = modesettingPTR(pScrn); 889 int index, j, i; 890 int c; 891 892 switch(pScrn->depth) { 893 case 15: 894 for (i = 0; i < numColors; i++) { 895 index = indices[i]; 896 for (j = 0; j < 8; j++) { 897 ms->lut_r[index * 8 + j] = colors[index].red << 8; 898 ms->lut_g[index * 8 + j] = colors[index].green << 8; 899 ms->lut_b[index * 8 + j] = colors[index].blue << 8; 900 } 901 } 902 break; 903 case 16: 904 for (i = 0; i < numColors; i++) { 905 index = indices[i]; 906 907 if (index < 32) { 908 for (j = 0; j < 8; j++) { 909 ms->lut_r[index * 8 + j] = colors[index].red << 8; 910 ms->lut_b[index * 8 + j] = colors[index].blue << 8; 911 } 912 } 913 914 for (j = 0; j < 4; j++) { 915 ms->lut_g[index * 4 + j] = colors[index].green << 8; 916 } 917 } 918 break; 919 default: 920 for (i = 0; i < numColors; i++) { 921 index = indices[i]; 922 ms->lut_r[index] = colors[index].red << 8; 923 ms->lut_g[index] = colors[index].green << 8; 924 ms->lut_b[index] = colors[index].blue << 8; 925 } 926 break; 927 } 928 929 for (c = 0; c < xf86_config->num_crtc; c++) { 930 xf86CrtcPtr crtc = xf86_config->crtc[c]; 931 932 /* Make the change through RandR */ 933#ifdef RANDR_12_INTERFACE 934 if (crtc->randr_crtc) 935 RRCrtcGammaSet(crtc->randr_crtc, ms->lut_r, ms->lut_g, ms->lut_b); 936 else 937#endif 938 crtc->funcs->gamma_set(crtc, ms->lut_r, ms->lut_g, ms->lut_b, 256); 939 } 940} 941 942 943static Bool 944drv_screen_init(SCREEN_INIT_ARGS_DECL) 945{ 946 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 947 modesettingPtr ms = modesettingPTR(pScrn); 948 VisualPtr visual; 949 950 if (!drv_set_master(pScrn)) 951 return FALSE; 952 953 pScrn->pScreen = pScreen; 954 955 /* HW dependent - FIXME */ 956 pScrn->displayWidth = pScrn->virtualX; 957 958 miClearVisualTypes(); 959 960 if (!miSetVisualTypes(pScrn->depth, 961 miGetDefaultVisualMask(pScrn->depth), 962 pScrn->rgbBits, pScrn->defaultVisual)) 963 return FALSE; 964 965 if (!miSetPixmapDepths()) 966 return FALSE; 967 968 pScrn->memPhysBase = 0; 969 pScrn->fbOffset = 0; 970 971 if (!fbScreenInit(pScreen, NULL, 972 pScrn->virtualX, pScrn->virtualY, 973 pScrn->xDpi, pScrn->yDpi, 974 pScrn->displayWidth, pScrn->bitsPerPixel)) 975 return FALSE; 976 977 if (pScrn->bitsPerPixel > 8) { 978 /* Fixup RGB ordering */ 979 visual = pScreen->visuals + pScreen->numVisuals; 980 while (--visual >= pScreen->visuals) { 981 if ((visual->class | DynamicClass) == DirectColor) { 982 visual->offsetRed = pScrn->offset.red; 983 visual->offsetGreen = pScrn->offset.green; 984 visual->offsetBlue = pScrn->offset.blue; 985 visual->redMask = pScrn->mask.red; 986 visual->greenMask = pScrn->mask.green; 987 visual->blueMask = pScrn->mask.blue; 988 } 989 } 990 } 991 992 fbPictureInit(pScreen, NULL, 0); 993 994 vmwgfx_wrap(ms, pScreen, BlockHandler, drv_block_handler); 995 vmwgfx_wrap(ms, pScreen, CreateScreenResources, 996 drv_create_screen_resources); 997 998 xf86SetBlackWhitePixels(pScreen); 999 1000 vmw_ctrl_ext_init(pScrn); 1001 1002 if (ms->accelerate_render) { 1003 ms->xat = xa_tracker_create(ms->fd); 1004 if (!ms->xat) { 1005 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1006 "Failed to initialize Gallium3D Xa. " 1007 "No render acceleration available.\n"); 1008 ms->from_render = X_PROBED; 1009 } else { 1010 int major, minor, patch; 1011 1012 xa_tracker_version(&major, &minor, &patch); 1013 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1014 "Gallium3D XA version: %d.%d.%d.\n", 1015 major, minor, patch); 1016 1017 if (major < XA_VERSION_MAJOR_REQUIRED || 1018 major > XA_VERSION_MAJOR_COMPAT || 1019 (major == XA_VERSION_MAJOR_REQUIRED && 1020 minor < XA_VERSION_MINOR_REQUIRED)) { 1021 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1022 "Expecting %d.%d.x >= XA version < %d.0.0.\n", 1023 XA_VERSION_MAJOR_REQUIRED, 1024 XA_VERSION_MINOR_REQUIRED, 1025 XA_VERSION_MAJOR_COMPAT + 1); 1026 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1027 "No render acceleration available.\n"); 1028 xa_tracker_destroy(ms->xat); 1029 ms->xat = NULL; 1030 ms->from_render = X_PROBED; 1031 } 1032 } 1033 if (ms->xat == NULL && ms->rendercheck) { 1034 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1035 "Turning off renercheck mode.\n"); 1036 ms->rendercheck = FALSE; 1037 ms->from_rendercheck = X_PROBED; 1038 } 1039 } 1040 1041 if (vmwgfx_is_hosted(ms->hdriver) && !ms->xat) { 1042 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1043 "Can't run hosted without XA. Giving up.\n"); 1044 return FALSE; 1045 } 1046 1047 if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush, 1048 ms->direct_presents, 1049 ms->only_hw_presents, 1050 ms->rendercheck)) { 1051 FatalError("Failed to initialize SAA.\n"); 1052 } 1053 1054 ms->dri2_available = FALSE; 1055 if (ms->enable_dri) { 1056 if (ms->xat) { 1057 ms->dri2_available = xorg_dri2_init(pScreen); 1058 if (!ms->dri2_available) 1059 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1060 "Failed to initialize direct rendering.\n"); 1061 } else { 1062 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1063 "Skipped initialization of direct rendering due " 1064 "to lack of render acceleration.\n"); 1065 ms->from_dri = X_PROBED; 1066 } 1067 } 1068 1069 xf86DrvMsg(pScrn->scrnIndex, ms->from_render, "Render acceleration is %s.\n", 1070 (ms->xat != NULL) ? "enabled" : "disabled"); 1071 1072 xf86DrvMsg(pScrn->scrnIndex, ms->from_rendercheck, 1073 "Rendercheck mode is %s.\n", 1074 (ms->rendercheck) ? "enabled" : "disabled"); 1075 1076 xf86DrvMsg(pScrn->scrnIndex, ms->from_dri, "Direct rendering (3D) is %s.\n", 1077 (ms->dri2_available) ? "enabled" : "disabled"); 1078 if (ms->xat != NULL) { 1079 xf86DrvMsg(pScrn->scrnIndex, ms->from_dp, "Direct presents are %s.\n", 1080 (ms->direct_presents) ? "enabled" : "disabled"); 1081 xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " 1082 "are %s.\n", 1083 (ms->only_hw_presents) ? "enabled" : "disabled"); 1084 } 1085 1086 xf86SetBackingStore(pScreen); 1087 xf86SetSilkenMouse(pScreen); 1088 miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); 1089 1090 if (!vmwgfx_hosted_screen_init(ms->hdriver, ms->hosted, pScreen)) { 1091 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1092 "Failed hosted Screen init. Giving up.\n"); 1093 return FALSE; 1094 } 1095 1096 /* Need to extend HWcursor support to handle mask interleave */ 1097 if (!ms->SWCursor) { 1098 xf86_cursors_init(pScreen, 64, 64, 1099 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | 1100 HARDWARE_CURSOR_ARGB | 1101 HARDWARE_CURSOR_UPDATE_UNHIDDEN); 1102 vmwgfx_wrap_use_hw_cursor(pScrn); 1103 } 1104 1105 /* Must force it before EnterVT, so we are in control of VT and 1106 * later memory should be bound when allocating, e.g rotate_mem */ 1107 pScrn->vtSema = TRUE; 1108 1109 pScreen->SaveScreen = xf86SaveScreen; 1110 vmwgfx_wrap(ms, pScreen, CloseScreen, drv_close_screen); 1111 1112 if (!xf86CrtcScreenInit(pScreen)) 1113 return FALSE; 1114 1115 if (!miCreateDefColormap(pScreen)) 1116 return FALSE; 1117 if (!xf86HandleColormaps(pScreen, 256, 8, drv_load_palette, NULL, 1118 CMAP_PALETTED_TRUECOLOR | 1119 CMAP_RELOAD_ON_MODE_SWITCH)) 1120 return FALSE; 1121 1122 xf86DPMSInit(pScreen, xf86DPMSSet, 0); 1123 1124 if (serverGeneration == 1) 1125 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 1126 1127 1128 vmwgfx_wrap(ms, pScrn, EnterVT, drv_enter_vt); 1129 vmwgfx_wrap(ms, pScrn, LeaveVT, drv_leave_vt); 1130 vmwgfx_wrap(ms, pScrn, AdjustFrame, drv_adjust_frame); 1131 1132 /* 1133 * Must be called _after_ function wrapping. 1134 */ 1135 xorg_xv_init(pScreen); 1136 1137 return TRUE; 1138} 1139 1140static void 1141drv_adjust_frame(ADJUST_FRAME_ARGS_DECL) 1142{ 1143 SCRN_INFO_PTR(arg); 1144 modesettingPtr ms = modesettingPTR(pScrn); 1145 xf86CrtcConfigPtr config; 1146 xf86OutputPtr output; 1147 xf86CrtcPtr crtc; 1148 1149 if (vmwgfx_is_hosted(ms->hdriver)) 1150 return; 1151 1152 config = XF86_CRTC_CONFIG_PTR(pScrn); 1153 output = config->output[config->compat_output]; 1154 crtc = output->crtc; 1155 1156 if (crtc && crtc->enabled) { 1157 // crtc->funcs->set_mode_major(crtc, pScrn->currentMode, 1158 // RR_Rotate_0, x, y); 1159 crtc->x = output->initial_x + x; 1160 crtc->y = output->initial_y + y; 1161 } 1162} 1163 1164static void 1165drv_free_screen(FREE_SCREEN_ARGS_DECL) 1166{ 1167 SCRN_INFO_PTR(arg); 1168 modesettingPtr ms = modesettingPTR(pScrn); 1169 1170 vmwgfx_hosted_destroy(ms->hdriver, ms->hosted); 1171 drv_free_rec(pScrn); 1172} 1173 1174static void 1175drv_leave_vt(VT_FUNC_ARGS_DECL) 1176{ 1177 SCRN_INFO_PTR(arg); 1178 modesettingPtr ms = modesettingPTR(pScrn); 1179 1180 if (!vmwgfx_is_hosted(ms->hdriver)) { 1181 vmwgfx_cursor_bypass(ms->fd, 0, 0); 1182 vmwgfx_disable_scanout(pScrn); 1183 } 1184 1185 vmwgfx_saa_drop_master(pScrn->pScreen); 1186 1187 if (!vmwgfx_is_hosted(ms->hdriver) && drmDropMaster(ms->fd)) 1188 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1189 "drmDropMaster failed: %s\n", strerror(errno)); 1190 ms->isMaster = FALSE; 1191 pScrn->vtSema = FALSE; 1192} 1193 1194/* 1195 * This gets called when gaining control of the VT, and from ScreenInit(). 1196 */ 1197static Bool 1198drv_enter_vt(VT_FUNC_ARGS_DECL) 1199{ 1200 SCRN_INFO_PTR(arg); 1201 modesettingPtr ms = modesettingPTR(pScrn); 1202 1203 if (!drv_set_master(pScrn)) 1204 return FALSE; 1205 1206 vmwgfx_saa_set_master(pScrn->pScreen); 1207 1208 if (!vmwgfx_is_hosted(ms->hdriver) && !xf86SetDesiredModes(pScrn)) 1209 return FALSE; 1210 1211 return TRUE; 1212} 1213 1214static Bool 1215drv_switch_mode(SWITCH_MODE_ARGS_DECL) 1216{ 1217 SCRN_INFO_PTR(arg); 1218 1219 return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); 1220} 1221 1222static Bool 1223drv_close_screen(CLOSE_SCREEN_ARGS_DECL) 1224{ 1225 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1226 modesettingPtr ms = modesettingPTR(pScrn); 1227 1228 if (ms->cursor) { 1229 FreeCursor(ms->cursor, None); 1230 ms->cursor = NULL; 1231 } 1232 1233 if (ms->dri2_available) 1234 xorg_dri2_close(pScreen); 1235 1236 if (pScrn->vtSema) 1237 pScrn->LeaveVT(VT_FUNC_ARGS); 1238 1239 pScrn->vtSema = FALSE; 1240 1241 vmwgfx_unwrap(ms, pScrn, EnterVT); 1242 vmwgfx_unwrap(ms, pScrn, LeaveVT); 1243 vmwgfx_unwrap(ms, pScrn, AdjustFrame); 1244 vmwgfx_unwrap(ms, pScreen, CloseScreen); 1245 vmwgfx_hosted_screen_close(ms->hdriver, ms->hosted); 1246 vmwgfx_unwrap(ms, pScreen, BlockHandler); 1247 vmwgfx_unwrap(ms, pScreen, CreateScreenResources); 1248 1249 if (ms->xat) 1250 xa_tracker_destroy(ms->xat); 1251 1252 return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS); 1253} 1254 1255static ModeStatus 1256drv_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags) 1257{ 1258 return MODE_OK; 1259} 1260 1261/* vim: set sw=4 ts=8 sts=4: */ 1262