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