vmwgfx_driver.c revision 34a0776d
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#ifdef HAVE_CONFIG_H 33#include "config.h" 34#endif 35 36#include <unistd.h> 37#include "xorg-server.h" 38#include "xf86.h" 39#include "xf86_OSproc.h" 40#include "compiler.h" 41#include "xf86Pci.h" 42#include "mipointer.h" 43#include "micmap.h" 44#include <X11/extensions/randr.h> 45#include "fb.h" 46#include "edid.h" 47#include "xf86i2c.h" 48#include "xf86Crtc.h" 49#include "miscstruct.h" 50#include "dixstruct.h" 51#include "xf86cmap.h" 52#include "xf86xv.h" 53#include "xorgVersion.h" 54#ifndef XSERVER_LIBPCIACCESS 55#error "libpciaccess needed" 56#endif 57 58#include <pciaccess.h> 59 60#ifdef XSERVER_PLATFORM_BUS 61#include "xf86platformBus.h" 62#endif 63 64#include "vmwgfx_driver.h" 65 66#include <saa.h> 67#include "vmwgfx_saa.h" 68#include "../src/vmware_bootstrap.h" 69#include "../src/vmware_common.h" 70#include "vmwgfx_hosted.h" 71 72/* 73 * We can't incude svga_types.h due to conflicting types for Bool. 74 */ 75typedef int64_t int64; 76typedef uint64_t uint64; 77 78typedef int32_t int32; 79typedef uint32_t uint32; 80 81typedef int16_t int16; 82typedef uint16_t uint16; 83 84typedef int8_t int8; 85typedef uint8_t uint8; 86#include "../src/svga_reg.h" 87 88#define XA_VERSION_MINOR_REQUIRED 0 89#define XA_VERSION_MAJOR_REQUIRED 1 90#define XA_VERSION_MAJOR_COMPAT 2 91 92#define DRM_VERSION_MAJOR_REQUIRED 2 93#define DRM_VERSION_MINOR_REQUIRED 3 94 95/* 96 * Some macros to deal with function wrapping. 97 */ 98#define vmwgfx_wrap(priv, real, mem, func) {\ 99 (priv)->saved_##mem = (real)->mem; \ 100 (real)->mem = func; \ 101} 102 103#define vmwgfx_unwrap(priv, real, mem) {\ 104 (real)->mem = (priv)->saved_##mem; \ 105} 106 107#define vmwgfx_swap(priv, real, mem) {\ 108 void *tmp = (priv)->saved_##mem; \ 109 (priv)->saved_##mem = (real)->mem; \ 110 (real)->mem = tmp; \ 111} 112 113/* 114 * Functions and symbols exported to Xorg via pointers. 115 */ 116 117static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags); 118static Bool drv_screen_init(SCREEN_INIT_ARGS_DECL); 119static Bool drv_switch_mode(SWITCH_MODE_ARGS_DECL); 120static void drv_adjust_frame(ADJUST_FRAME_ARGS_DECL); 121static Bool drv_enter_vt(VT_FUNC_ARGS_DECL); 122static void drv_leave_vt(VT_FUNC_ARGS_DECL); 123static void drv_free_screen(FREE_SCREEN_ARGS_DECL); 124static ModeStatus drv_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, 125 int flags); 126 127extern void xorg_tracker_set_functions(ScrnInfoPtr scrn); 128 129void 130vmwgfx_hookup(ScrnInfoPtr pScrn) 131{ 132 pScrn->PreInit = drv_pre_init; 133 pScrn->ScreenInit = drv_screen_init; 134 pScrn->SwitchMode = drv_switch_mode; 135 pScrn->FreeScreen = drv_free_screen; 136 pScrn->ValidMode = drv_valid_mode; 137} 138 139void 140vmwgfx_modify_flags(uint32_t *flags) 141{ 142 *flags &= ~(HW_IO); 143 vmwgfx_hosted_modify_flags(flags); 144} 145/* 146 * Internal function definitions 147 */ 148 149static Bool drv_close_screen(CLOSE_SCREEN_ARGS_DECL); 150 151/* 152 * Internal functions 153 */ 154 155static Bool 156drv_get_rec(ScrnInfoPtr pScrn) 157{ 158 if (pScrn->driverPrivate) 159 return TRUE; 160 161 pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec)); 162 163 return TRUE; 164} 165 166static void 167drv_free_rec(ScrnInfoPtr pScrn) 168{ 169 if (!pScrn) 170 return; 171 172 if (!pScrn->driverPrivate) 173 return; 174 175 free(pScrn->driverPrivate); 176 177 pScrn->driverPrivate = NULL; 178} 179 180static void 181drv_probe_ddc(ScrnInfoPtr pScrn, int index) 182{ 183 ConfiguredMonitor = NULL; 184} 185 186static Bool 187drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height) 188{ 189 modesettingPtr ms = modesettingPTR(pScrn); 190 ScreenPtr pScreen = pScrn->pScreen; 191 int old_width, old_height; 192 PixmapPtr rootPixmap; 193 194 if (width == pScrn->virtualX && height == pScrn->virtualY) 195 return TRUE; 196 197 if (ms->check_fb_size) { 198 size_t size = width*(pScrn->bitsPerPixel / 8) * height + 1024; 199 200 if (size > ms->max_fb_size) { 201 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 202 "Requested framebuffer size %dx%dx%d will not fit " 203 "in display memory.\n", 204 width, height, pScrn->bitsPerPixel); 205 return FALSE; 206 } 207 } 208 209 old_width = pScrn->virtualX; 210 old_height = pScrn->virtualY; 211 pScrn->virtualX = width; 212 pScrn->virtualY = height; 213 214 /* ms->create_front_buffer will remove the old front buffer */ 215 216 rootPixmap = pScreen->GetScreenPixmap(pScreen); 217 vmwgfx_disable_scanout(pScrn); 218 if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL)) 219 goto error_modify; 220 221 pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8); 222 223 xf86SetDesiredModes(pScrn); 224 return TRUE; 225 226 /* 227 * FIXME: Try out this error recovery path and fix problems. 228 229 */ 230 //error_create: 231 if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL)) 232 FatalError("failed to resize rootPixmap error path\n"); 233 234 pScrn->displayWidth = rootPixmap->devKind / 235 (rootPixmap->drawable.bitsPerPixel / 8); 236 237 238error_modify: 239 pScrn->virtualX = old_width; 240 pScrn->virtualY = old_height; 241 242 if (xf86SetDesiredModes(pScrn)) 243 return FALSE; 244 245 FatalError("failed to setup old framebuffer\n"); 246 return FALSE; 247} 248 249static const xf86CrtcConfigFuncsRec crtc_config_funcs = { 250 .resize = drv_crtc_resize 251}; 252 253static Bool vmwgfx_use_server_fd(modesettingPtr ms) 254{ 255#ifdef XF86_PDEV_SERVER_FD 256 return ms->platform_dev && (ms->platform_dev->flags & XF86_PDEV_SERVER_FD); 257#else 258 return FALSE; 259#endif 260} 261 262static Bool 263drv_init_drm(ScrnInfoPtr pScrn) 264{ 265 modesettingPtr ms = modesettingPTR(pScrn); 266 267 /* deal with server regeneration */ 268 if (ms->fd < 0) { 269 270 ms->fd = vmwgfx_hosted_drm_fd(ms->hdriver, ms->hosted, ms->PciInfo); 271 272#ifdef ODEV_ATTRIB_FD 273 if (ms->fd < 0 && vmwgfx_use_server_fd(ms)) 274 ms->fd = xf86_get_platform_device_int_attrib(ms->platform_dev, 275 ODEV_ATTRIB_FD, -1); 276#endif 277 278 if (ms->fd < 0) { 279 280 char bus_id[64]; 281 282 snprintf(bus_id, sizeof(bus_id), "PCI:%d:%d:%d", 283 ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), 284 ms->PciInfo->dev, ms->PciInfo->func 285 ); 286 287 ms->fd = drmOpen("vmwgfx", bus_id); 288 ms->isMaster = TRUE; 289 290 } 291 292 if (ms->fd >= 0) { 293 drmVersionPtr ver = drmGetVersion(ms->fd); 294 295 if (ver == NULL) { 296 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 297 "Could not determine DRM version.\n"); 298 return FALSE; 299 } 300 301 ms->drm_major = ver->version_major; 302 ms->drm_minor = ver->version_minor; 303 ms->drm_patch = ver->version_patchlevel; 304 305 drmFreeVersion(ver); 306 return TRUE; 307 } 308 309 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 310 "Failed to open drm.\n"); 311 312 return FALSE; 313 } 314 315 return TRUE; 316} 317 318/** 319 * vmwgfx_set_topology - Set the GUI topology according to an option string 320 * 321 * @pScrn: Pointer to a ScrnInfo struct. 322 * @topology: String containing the topology description. 323 * @info: Info describing the option used to invoke this function. 324 * 325 * This function reads a GUI topology according from @topology, and 326 * calls into the kernel to set that topology. 327 */ 328static Bool 329vmwgfx_set_topology(ScrnInfoPtr pScrn, const char *topology, const char *info) 330{ 331 modesettingPtr ms = modesettingPTR(pScrn); 332 unsigned int num_outputs; 333 xXineramaScreenInfo *screen_info; 334 struct drm_vmw_rect *rects; 335 int ret; 336 unsigned int i; 337 338 screen_info = VMWAREParseTopologyString(pScrn, topology, &num_outputs, 339 info); 340 341 if (screen_info == NULL) 342 return FALSE; 343 344 rects = calloc(num_outputs, sizeof(*rects)); 345 if (rects == NULL) { 346 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 347 "Failed to allocate topology data.\n"); 348 goto out_no_rects; 349 } 350 351 for(i = 0; i < num_outputs; ++i) { 352 rects[i].x = screen_info[i].x_org; 353 rects[i].y = screen_info[i].y_org; 354 rects[i].w = screen_info[i].width; 355 rects[i].h = screen_info[i].height; 356 } 357 358 ret = vmwgfx_update_gui_layout(ms->fd, num_outputs, rects); 359 free(rects); 360 free(screen_info); 361 362 return (ret == 0); 363 364 out_no_rects: 365 free(screen_info); 366 return FALSE; 367} 368 369 370static Bool 371vmwgfx_pre_init_mode(ScrnInfoPtr pScrn, int flags) 372{ 373 modesettingPtr ms = modesettingPTR(pScrn); 374 Bool ret = TRUE; 375 376 ms->from_dp = (xf86GetOptValBool(ms->Options, OPTION_DIRECT_PRESENTS, 377 &ms->direct_presents)) ? 378 X_CONFIG : X_DEFAULT; 379 380 ms->from_hwp = (xf86GetOptValBool(ms->Options, OPTION_HW_PRESENTS, 381 &ms->only_hw_presents)) ? 382 X_CONFIG : X_DEFAULT; 383 384 /* Allocate an xf86CrtcConfig */ 385 xf86CrtcConfigInit(pScrn, &crtc_config_funcs); 386 387 /* get max width and height */ 388 { 389 drmModeResPtr res; 390 int max_width, max_height; 391 392 res = drmModeGetResources(ms->fd); 393 max_width = res->max_width; 394 max_height = res->max_height; 395 396 xf86CrtcSetSizeRange(pScrn, res->min_width, 397 res->min_height, max_width, max_height); 398 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 399 "Min width %d, Max Width %d.\n", 400 res->min_width, max_width); 401 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 402 "Min height %d, Max Height %d.\n", 403 res->min_height, max_height); 404 drmModeFreeResources(res); 405 } 406 407 ms->SWCursor = FALSE; 408 if (!xf86ReturnOptValBool(ms->Options, OPTION_HW_CURSOR, TRUE)) { 409 ms->SWCursor = TRUE; 410 } 411 412 if (xf86IsOptionSet(ms->Options, OPTION_GUI_LAYOUT)) { 413 char *topology = 414 xf86GetOptValString(ms->Options, OPTION_GUI_LAYOUT); 415 416 ret = FALSE; 417 if (topology) { 418 ret = vmwgfx_set_topology(pScrn, topology, "gui"); 419 free(topology); 420 } 421 422 } else if (xf86IsOptionSet(ms->Options, OPTION_STATIC_XINERAMA)) { 423 char *topology = 424 xf86GetOptValString(ms->Options, OPTION_STATIC_XINERAMA); 425 426 ret = FALSE; 427 if (topology) { 428 ret = vmwgfx_set_topology(pScrn, topology, "static Xinerama"); 429 free(topology); 430 } 431 } 432 433 if (!ret) 434 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Falied parsing or setting " 435 "gui topology from config file.\n"); 436 437 xorg_crtc_init(pScrn); 438 xorg_output_init(pScrn); 439 440 if (!xf86InitialConfiguration(pScrn, TRUE)) { 441 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); 442 goto out_modes; 443 } 444 445 if (pScrn->modes == NULL) { 446 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No available modes.\n"); 447 goto out_modes; 448 } 449 450 pScrn->currentMode = pScrn->modes; 451 452 return TRUE; 453 454 out_modes: 455 return FALSE; 456} 457 458static Bool 459drv_pre_init(ScrnInfoPtr pScrn, int flags) 460{ 461 modesettingPtr ms; 462 rgb defaultWeight = { 0, 0, 0 }; 463 Gamma zeros = { 0.0, 0.0, 0.0 }; 464 EntityInfoPtr pEnt; 465 uint64_t cap; 466 467 if (pScrn->numEntities != 1) 468 return FALSE; 469 470 pEnt = xf86GetEntityInfo(pScrn->entityList[0]); 471 472 if (flags & PROBE_DETECT) { 473 drv_probe_ddc(pScrn, pEnt->index); 474 return TRUE; 475 } 476 477 pScrn->driverPrivate = NULL; 478 479 /* Allocate driverPrivate */ 480 if (!drv_get_rec(pScrn)) { 481 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 482 "Failed to allocate driver private.\n"); 483 } 484 485 ms = modesettingPTR(pScrn); 486 ms->pEnt = pEnt; 487 488 pScrn->displayWidth = 640; /* default it */ 489 490 ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); 491 if (!ms->PciInfo) { 492 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 493 "Incorrect bus for device.\n"); 494 goto out_err_bus; 495 } 496 497#ifdef XSERVER_PLATFORM_BUS 498 if (pEnt->location.type == BUS_PLATFORM) 499 ms->platform_dev = pEnt->location.id.plat; 500#endif 501 502 xf86SetPrimInitDone(pScrn->entityList[0]); 503 504 ms->hdriver = vmwgfx_hosted_detect(); 505 ms->hosted = vmwgfx_hosted_create(ms->hdriver, pScrn); 506 if (ms->hdriver && !ms->hosted) { 507 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 508 "Failed to set up compositor hosted environment.\n"); 509 goto out_err_bus; 510 } 511 512 pScrn->monitor = pScrn->confScreen->monitor; 513 pScrn->progClock = TRUE; 514 pScrn->rgbBits = 8; 515 516 if (!xf86SetDepthBpp 517 (pScrn, 0, 0, 0, 518 PreferConvert24to32 | SupportConvert24to32 | Support32bppFb)) { 519 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set depth and bpp.\n"); 520 goto out_err_bus; 521 } 522 523 if (!vmwgfx_hosted_pre_init(ms->hdriver, ms->hosted, flags)) 524 goto out_err_bus; 525 526 ms->fd = -1; 527 if (!drv_init_drm(pScrn)) 528 goto out_no_drm; 529 530 if (ms->drm_major != DRM_VERSION_MAJOR_REQUIRED || 531 ms->drm_minor < DRM_VERSION_MINOR_REQUIRED) { 532 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 533 "DRM driver version is %d.%d.%d\n", 534 ms->drm_major, ms->drm_minor, ms->drm_patch); 535 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 536 "But KMS- and 3D functionality needs at least " 537 "%d.%d.0 to work.\n", 538 DRM_VERSION_MAJOR_REQUIRED, 539 DRM_VERSION_MINOR_REQUIRED); 540 goto out_drm_version; 541 } else { 542 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 543 "DRM driver version is %d.%d.%d\n", 544 ms->drm_major, ms->drm_minor, ms->drm_patch); 545 } 546 547 ms->has_screen_targets = ms->drm_major > 2 || 548 (ms->drm_major == 2 && ms->drm_minor >= 7); 549 ms->has_screen_targets = (ms->has_screen_targets && 550 !vmwgfx_get_param(ms->fd, 551 DRM_VMW_PARAM_SCREEN_TARGET, 552 &cap) && 553 cap != 0); 554 555 ms->check_fb_size = (vmwgfx_max_fb_size(ms->fd, &ms->max_fb_size) == 0); 556 557 switch (pScrn->depth) { 558 case 15: 559 case 16: 560 case 24: 561 break; 562 default: 563 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 564 "Given depth (%d) is not supported with KMS enabled.\n", 565 pScrn->depth); 566 goto out_depth; 567 } 568 xf86PrintDepthBpp(pScrn); 569 570 if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) 571 goto out_depth; 572 if (!xf86SetDefaultVisual(pScrn, -1)) 573 goto out_depth; 574 575 /* Process the options */ 576 xf86CollectOptions(pScrn, NULL); 577 if (!(ms->Options = VMWARECopyOptions())) 578 goto out_depth; 579 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); 580 581 ms->accelerate_render = TRUE; 582 ms->from_render = xf86GetOptValBool(ms->Options, OPTION_RENDER_ACCEL, 583 &ms->accelerate_render) ? 584 X_CONFIG : X_PROBED; 585 586 ms->rendercheck = FALSE; 587 ms->from_rendercheck = xf86GetOptValBool(ms->Options, OPTION_RENDERCHECK, 588 &ms->rendercheck) ? 589 X_CONFIG : X_DEFAULT; 590 591 ms->enable_dri = ms->accelerate_render; 592 ms->from_dri = xf86GetOptValBool(ms->Options, OPTION_DRI, 593 &ms->enable_dri) ? 594 X_CONFIG : X_PROBED; 595 596 ms->direct_presents = FALSE; 597 ms->only_hw_presents = FALSE; 598 ms->SWCursor = TRUE; 599 if (!vmwgfx_is_hosted(ms->hdriver)) { 600 if (!vmwgfx_pre_init_mode(pScrn, flags)) 601 goto out_modes; 602 } else { 603 ms->from_dp = X_CONFIG; 604 ms->from_hwp = X_CONFIG; 605 } 606 607 xf86SetDpi(pScrn, 0, 0); 608 609 if (!xf86SetGamma(pScrn, zeros)) { 610 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set gamma.\n"); 611 goto out_modes; 612 } 613 614 /* Load the required sub modules */ 615 if (!xf86LoadSubModule(pScrn, "fb")) { 616 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load fb module.\n"); 617 goto out_modes; 618 } 619 620 if (!xf86LoadSubModule(pScrn, "dri2")) { 621 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load dri2 module.\n"); 622 goto out_modes; 623 } 624 625 return TRUE; 626 627 out_modes: 628 free(ms->Options); 629 out_depth: 630 out_drm_version: 631 if (!vmwgfx_is_hosted(ms->hdriver) && !vmwgfx_use_server_fd(ms)) 632 close(ms->fd); 633 out_no_drm: 634 vmwgfx_hosted_destroy(ms->hdriver, ms->hosted); 635 out_err_bus: 636 drv_free_rec(pScrn); 637 return FALSE; 638 639} 640 641static Bool 642vmwgfx_scanout_update(int drm_fd, int fb_id, RegionPtr dirty) 643{ 644 unsigned num_cliprects = REGION_NUM_RECTS(dirty); 645 drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip)); 646 BoxPtr rect = REGION_RECTS(dirty); 647 int i, ret; 648 649 if (!num_cliprects) 650 return TRUE; 651 652 for (i = 0; i < num_cliprects; i++, rect++) { 653 clip[i].x1 = rect->x1; 654 clip[i].y1 = rect->y1; 655 clip[i].x2 = rect->x2; 656 clip[i].y2 = rect->y2; 657 } 658 659 ret = drmModeDirtyFB(drm_fd, fb_id, clip, num_cliprects); 660 if (ret) 661 LogMessage(X_ERROR, "%s: failed to send dirty (%i, %s)\n", 662 __func__, ret, strerror(-ret)); 663 return (ret == 0); 664} 665 666static Bool 667vmwgfx_scanout_present(ScreenPtr pScreen, int drm_fd, 668 struct vmwgfx_saa_pixmap *vpix, 669 RegionPtr dirty) 670{ 671 uint32_t handle; 672 unsigned int dummy; 673 674 if (!REGION_NOTEMPTY(pScreen, dirty)) 675 return TRUE; 676 677 if (!vpix->hw) { 678 LogMessage(X_ERROR, "No surface to present from.\n"); 679 return FALSE; 680 } 681 682 if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0) { 683 LogMessage(X_ERROR, "Could not get present surface handle.\n"); 684 return FALSE; 685 } 686 687 if (vmwgfx_present(drm_fd, vpix->fb_id, 0, 0, dirty, handle) != 0) { 688 LogMessage(X_ERROR, "Failed present kernel call.\n"); 689 return FALSE; 690 } 691 692 return TRUE; 693} 694 695void xorg_flush(ScreenPtr pScreen) 696{ 697 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 698 modesettingPtr ms = modesettingPTR(pScrn); 699 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 700 PixmapPtr pixmap = NULL; 701 struct vmwgfx_saa_pixmap *vpix; 702 int i; 703 xf86CrtcPtr crtc; 704 PixmapPtr *pixmaps = calloc(config->num_crtc, sizeof(*pixmaps)); 705 unsigned int num_scanout = 0; 706 unsigned int j; 707 708 if (!pixmaps) { 709 LogMessage(X_ERROR, "Failed memory allocation during screen " 710 "update.\n"); 711 return; 712 } 713 714 /* 715 * Get an array of pixmaps from which we scan out. 716 */ 717 for (i=0; i<config->num_crtc; ++i) { 718 crtc = config->crtc[i]; 719 if (crtc->enabled) { 720 pixmap = crtc_get_scanout(crtc); 721 if (pixmap) { 722 723 /* 724 * Remove duplicates. 725 */ 726 for (j=0; j<num_scanout; ++j) { 727 if (pixmap == pixmaps[j]) 728 break; 729 } 730 731 if (j == num_scanout) 732 pixmaps[num_scanout++] = pixmap; 733 } 734 } 735 } 736 737 if (!num_scanout) 738 return; 739 740 for (j=0; j<num_scanout; ++j) { 741 pixmap = pixmaps[j]; 742 vpix = vmwgfx_saa_pixmap(pixmap); 743 744 if (vpix->fb_id != -1) { 745 if (vpix->pending_update) { 746 if (vpix->scanout_hw && 747 REGION_NOTEMPTY(pscreen, vpix->pending_update)) { 748 (void) vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, 749 0, NULL); 750 REGION_UNION(pScreen, vpix->pending_present, 751 vpix->pending_present, vpix->pending_update); 752 } else 753 (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, 754 vpix->pending_update); 755 REGION_EMPTY(pScreen, vpix->pending_update); 756 } 757 if (vpix->pending_present) { 758 if (vpix->scanout_hw) 759 (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, 760 vpix->pending_present); 761 else 762 (void) vmwgfx_scanout_present(pScreen, ms->fd, vpix, 763 vpix->pending_present); 764 REGION_EMPTY(pScreen, vpix->pending_present); 765 } 766 } 767 } 768 free(pixmaps); 769} 770 771static void drv_block_handler(BLOCKHANDLER_ARGS_DECL) 772{ 773 SCREEN_PTR(arg); 774 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen)); 775 776 vmwgfx_swap(ms, pScreen, BlockHandler); 777 pScreen->BlockHandler(BLOCKHANDLER_ARGS); 778 vmwgfx_swap(ms, pScreen, BlockHandler); 779 780 if (vmwgfx_is_hosted(ms->hdriver)) 781 vmwgfx_hosted_post_damage(ms->hdriver, ms->hosted); 782 else 783 xorg_flush(pScreen); 784} 785 786static Bool 787drv_create_screen_resources(ScreenPtr pScreen) 788{ 789 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 790 modesettingPtr ms = modesettingPTR(pScrn); 791 Bool ret; 792 793 vmwgfx_swap(ms, pScreen, CreateScreenResources); 794 ret = pScreen->CreateScreenResources(pScreen); 795 vmwgfx_swap(ms, pScreen, CreateScreenResources); 796 if (!ret) 797 return ret; 798 799 drv_adjust_frame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0)); 800 vmwgfx_uevent_init(pScrn, ms); 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 ms->autoLayout = TRUE; 1025 vmw_ctrl_ext_init(pScrn); 1026 1027 if (ms->accelerate_render) { 1028 ms->xat = xa_tracker_create(ms->fd); 1029 if (!ms->xat) { 1030 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1031 "Failed to initialize Gallium3D Xa. " 1032 "No render acceleration available.\n"); 1033 ms->from_render = X_PROBED; 1034 } else { 1035 int major, minor, patch; 1036 1037 xa_tracker_version(&major, &minor, &patch); 1038 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1039 "Gallium3D XA version: %d.%d.%d.\n", 1040 major, minor, patch); 1041 1042 if (major < XA_VERSION_MAJOR_REQUIRED || 1043 major > XA_VERSION_MAJOR_COMPAT || 1044 (major == XA_VERSION_MAJOR_REQUIRED && 1045 minor < XA_VERSION_MINOR_REQUIRED)) { 1046 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1047 "Expecting %d.%d.x >= XA version < %d.0.0.\n", 1048 XA_VERSION_MAJOR_REQUIRED, 1049 XA_VERSION_MINOR_REQUIRED, 1050 XA_VERSION_MAJOR_COMPAT + 1); 1051 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1052 "No render acceleration available.\n"); 1053 xa_tracker_destroy(ms->xat); 1054 ms->xat = NULL; 1055 ms->from_render = X_PROBED; 1056 } 1057 } 1058 if (ms->xat == NULL && ms->rendercheck) { 1059 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1060 "Turning off renercheck mode.\n"); 1061 ms->rendercheck = FALSE; 1062 ms->from_rendercheck = X_PROBED; 1063 } 1064 } 1065 1066 if (vmwgfx_is_hosted(ms->hdriver) && !ms->xat) { 1067 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1068 "Can't run hosted without XA. Giving up.\n"); 1069 return FALSE; 1070 } 1071 1072 if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush, 1073 ms->direct_presents, 1074 ms->only_hw_presents, 1075 ms->rendercheck, 1076 ms->has_screen_targets)) { 1077 FatalError("Failed to initialize SAA.\n"); 1078 } 1079 1080 ms->dri2_available = FALSE; 1081 if (ms->enable_dri) { 1082 if (ms->xat) { 1083 ms->dri2_available = xorg_dri2_init(pScreen); 1084 if (!ms->dri2_available) 1085 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1086 "Failed to initialize direct rendering.\n"); 1087 } else { 1088 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1089 "Skipped initialization of direct rendering due " 1090 "to lack of render acceleration.\n"); 1091 ms->from_dri = X_PROBED; 1092 } 1093 } 1094 1095 xf86DrvMsg(pScrn->scrnIndex, ms->from_render, "Render acceleration is %s.\n", 1096 (ms->xat != NULL) ? "enabled" : "disabled"); 1097 1098 xf86DrvMsg(pScrn->scrnIndex, ms->from_rendercheck, 1099 "Rendercheck mode is %s.\n", 1100 (ms->rendercheck) ? "enabled" : "disabled"); 1101 1102 xf86DrvMsg(pScrn->scrnIndex, ms->from_dri, "Direct rendering (3D) is %s.\n", 1103 (ms->dri2_available) ? "enabled" : "disabled"); 1104 if (ms->xat != NULL) { 1105 xf86DrvMsg(pScrn->scrnIndex, ms->from_dp, "Direct presents are %s.\n", 1106 (ms->direct_presents) ? "enabled" : "disabled"); 1107 if (ms->only_hw_presents) 1108 xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " 1109 "are enabled.\n"); 1110 else 1111 xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " 1112 "are %s.\n", 1113 (ms->has_screen_targets) ? "automatic per scanout" : 1114 "disabled"); 1115 } 1116 1117 xf86SetBackingStore(pScreen); 1118 xf86SetSilkenMouse(pScreen); 1119 miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); 1120 1121 if (!vmwgfx_hosted_screen_init(ms->hdriver, ms->hosted, pScreen)) { 1122 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1123 "Failed hosted Screen init. Giving up.\n"); 1124 return FALSE; 1125 } 1126 1127 /* Need to extend HWcursor support to handle mask interleave */ 1128 if (!ms->SWCursor) { 1129 xf86_cursors_init(pScreen, 64, 64, 1130 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | 1131 HARDWARE_CURSOR_ARGB | 1132 HARDWARE_CURSOR_UPDATE_UNHIDDEN); 1133 vmwgfx_wrap_use_hw_cursor(pScrn); 1134 } 1135 1136 /* Must force it before EnterVT, so we are in control of VT and 1137 * later memory should be bound when allocating, e.g rotate_mem */ 1138 pScrn->vtSema = TRUE; 1139 1140 pScreen->SaveScreen = xf86SaveScreen; 1141 vmwgfx_wrap(ms, pScreen, CloseScreen, drv_close_screen); 1142 1143 if (!xf86CrtcScreenInit(pScreen)) 1144 return FALSE; 1145 1146 if (!miCreateDefColormap(pScreen)) 1147 return FALSE; 1148 if (!xf86HandleColormaps(pScreen, 256, 8, drv_load_palette, NULL, 1149 CMAP_PALETTED_TRUECOLOR | 1150 CMAP_RELOAD_ON_MODE_SWITCH)) 1151 return FALSE; 1152 1153 xf86DPMSInit(pScreen, xf86DPMSSet, 0); 1154 1155 if (serverGeneration == 1) 1156 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 1157 1158 1159 vmwgfx_wrap(ms, pScrn, EnterVT, drv_enter_vt); 1160 vmwgfx_wrap(ms, pScrn, LeaveVT, drv_leave_vt); 1161 vmwgfx_wrap(ms, pScrn, AdjustFrame, drv_adjust_frame); 1162 1163 /* 1164 * Must be called _after_ function wrapping. 1165 */ 1166 xorg_xv_init(pScreen); 1167 1168 return TRUE; 1169} 1170 1171static void 1172drv_adjust_frame(ADJUST_FRAME_ARGS_DECL) 1173{ 1174 SCRN_INFO_PTR(arg); 1175 modesettingPtr ms = modesettingPTR(pScrn); 1176 xf86CrtcConfigPtr config; 1177 xf86OutputPtr output; 1178 xf86CrtcPtr crtc; 1179 1180 if (vmwgfx_is_hosted(ms->hdriver)) 1181 return; 1182 1183 config = XF86_CRTC_CONFIG_PTR(pScrn); 1184 output = config->output[config->compat_output]; 1185 crtc = output->crtc; 1186 1187 if (crtc && crtc->enabled) { 1188 // crtc->funcs->set_mode_major(crtc, pScrn->currentMode, 1189 // RR_Rotate_0, x, y); 1190 crtc->x = output->initial_x + x; 1191 crtc->y = output->initial_y + y; 1192 } 1193} 1194 1195static void 1196drv_free_screen(FREE_SCREEN_ARGS_DECL) 1197{ 1198 SCRN_INFO_PTR(arg); 1199 modesettingPtr ms = modesettingPTR(pScrn); 1200 1201 vmwgfx_hosted_destroy(ms->hdriver, ms->hosted); 1202 drv_free_rec(pScrn); 1203} 1204 1205static void 1206drv_leave_vt(VT_FUNC_ARGS_DECL) 1207{ 1208 SCRN_INFO_PTR(arg); 1209 modesettingPtr ms = modesettingPTR(pScrn); 1210 1211 if (!vmwgfx_is_hosted(ms->hdriver)) { 1212 vmwgfx_cursor_bypass(ms->fd, 0, 0); 1213 vmwgfx_disable_scanout(pScrn); 1214 } 1215 1216 vmwgfx_saa_drop_master(pScrn->pScreen); 1217 1218 if (!vmwgfx_is_hosted(ms->hdriver) && !vmwgfx_use_server_fd(ms) && 1219 drmDropMaster(ms->fd)) 1220 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1221 "drmDropMaster failed: %s\n", strerror(errno)); 1222 ms->isMaster = FALSE; 1223 pScrn->vtSema = FALSE; 1224} 1225 1226/* 1227 * This gets called when gaining control of the VT, and from ScreenInit(). 1228 */ 1229static Bool 1230drv_enter_vt(VT_FUNC_ARGS_DECL) 1231{ 1232 SCRN_INFO_PTR(arg); 1233 modesettingPtr ms = modesettingPTR(pScrn); 1234 1235 if (!drv_set_master(pScrn)) 1236 return FALSE; 1237 1238 vmwgfx_saa_set_master(pScrn->pScreen); 1239 1240 if (!vmwgfx_is_hosted(ms->hdriver) && !xf86SetDesiredModes(pScrn)) 1241 return FALSE; 1242 1243 return TRUE; 1244} 1245 1246static Bool 1247drv_switch_mode(SWITCH_MODE_ARGS_DECL) 1248{ 1249 SCRN_INFO_PTR(arg); 1250 1251 return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); 1252} 1253 1254static Bool 1255drv_close_screen(CLOSE_SCREEN_ARGS_DECL) 1256{ 1257 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 1258 modesettingPtr ms = modesettingPTR(pScrn); 1259 1260 if (ms->cursor) { 1261 FreeCursor(ms->cursor, None); 1262 ms->cursor = NULL; 1263 } 1264 1265 if (ms->dri2_available) 1266 xorg_dri2_close(pScreen); 1267 1268 if (pScrn->vtSema) 1269 pScrn->LeaveVT(VT_FUNC_ARGS); 1270 1271 vmwgfx_uevent_fini(pScrn, ms); 1272 pScrn->vtSema = FALSE; 1273 1274 vmwgfx_unwrap(ms, pScrn, EnterVT); 1275 vmwgfx_unwrap(ms, pScrn, LeaveVT); 1276 vmwgfx_unwrap(ms, pScrn, AdjustFrame); 1277 vmwgfx_unwrap(ms, pScreen, CloseScreen); 1278 vmwgfx_hosted_screen_close(ms->hdriver, ms->hosted); 1279 vmwgfx_unwrap(ms, pScreen, BlockHandler); 1280 vmwgfx_unwrap(ms, pScreen, CreateScreenResources); 1281 1282 if (ms->xat) 1283 xa_tracker_destroy(ms->xat); 1284 1285 return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS); 1286} 1287 1288static ModeStatus 1289drv_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags) 1290{ 1291 return MODE_OK; 1292} 1293 1294/* vim: set sw=4 ts=8 sts=4: */ 1295