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