1/* ********************************************************** 2 * Copyright (C) 1998-2001 VMware, Inc. 3 * All Rights Reserved 4 * **********************************************************/ 5#ifdef VMX86_DEVEL 6char rcsId_vmwarecurs[] = 7 "Id: vmwarecurs.c,v 1.5 2001/01/30 23:33:02 bennett Exp $"; 8#endif 9 10#ifdef HAVE_CONFIG_H 11#include "config.h" 12#endif 13 14#include "vmware.h" 15#include "vmware_common.h" 16#include "bits2pixels.h" 17 18static void VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h, 19 unsigned int format, unsigned long planeMask, 20 char *pBinImage); 21static void VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, 22 RegionPtr prgnSrc); 23 24#ifdef RENDER 25static void VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 26 PicturePtr pDst, INT16 xSrc, INT16 ySrc, 27 INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, 28 CARD16 width, CARD16 height); 29#endif /* RENDER */ 30 31static void 32RedefineCursor(VMWAREPtr pVMWARE) 33{ 34 int i; 35 36 VmwareLog(("RedefineCursor\n")); 37 38 pVMWARE->cursorDefined = FALSE; 39 40 /* Define cursor */ 41 vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_DEFINE_CURSOR); 42 vmwareWriteWordToFIFO(pVMWARE, MOUSE_ID); 43 vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.hotX); 44 vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.hotY); 45 vmwareWriteWordToFIFO(pVMWARE, pVMWARE->CursorInfoRec->MaxWidth); 46 vmwareWriteWordToFIFO(pVMWARE, pVMWARE->CursorInfoRec->MaxHeight); 47 vmwareWriteWordToFIFO(pVMWARE, 1); 48 vmwareWriteWordToFIFO(pVMWARE, pVMWARE->bitsPerPixel); 49 50 /* 51 * Since we have AND and XOR masks rather than 'source' and 'mask', 52 * color expand 'mask' with all zero as its foreground and all one as 53 * its background. This makes 'image & 0 ^ 'source' = source. We 54 * arange for 'image' & 1 ^ 'source' = 'image' below when we clip 55 * 'source' below. 56 */ 57 vmwareRaster_BitsToPixels((uint8 *) pVMWARE->hwcur.mask, 58 SVGA_BITMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth), 59 (uint8 *) pVMWARE->hwcur.maskPixmap, 60 SVGA_PIXMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth, 61 pVMWARE->bitsPerPixel), 62 pVMWARE->bitsPerPixel / 8, 63 pVMWARE->CursorInfoRec->MaxWidth, 64 pVMWARE->CursorInfoRec->MaxHeight, 0, ~0); 65 for (i = 0; i < SVGA_BITMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth, 66 pVMWARE->CursorInfoRec->MaxHeight); i++) { 67 vmwareWriteWordToFIFO(pVMWARE, ~pVMWARE->hwcur.mask[i]); 68 } 69 70 vmwareRaster_BitsToPixels((uint8 *) pVMWARE->hwcur.source, 71 SVGA_BITMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth), 72 (uint8 *) pVMWARE->hwcur.sourcePixmap, 73 SVGA_PIXMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth, 74 pVMWARE->bitsPerPixel), 75 pVMWARE->bitsPerPixel / 8, 76 pVMWARE->CursorInfoRec->MaxWidth, 77 pVMWARE->CursorInfoRec->MaxHeight, 78 pVMWARE->hwcur.fg, pVMWARE->hwcur.bg); 79 /* 80 * As pointed out above, we need to clip the expanded 'source' against 81 * the expanded 'mask' since we actually have AND and XOR masks in the 82 * virtual hardware. Effectively, 'source' becomes a three color fg/bg/0 83 * pixmap that XORs appropriately. 84 */ 85 for (i = 0; i < SVGA_PIXMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth, 86 pVMWARE->CursorInfoRec->MaxHeight, 87 pVMWARE->bitsPerPixel); i++) { 88 pVMWARE->hwcur.sourcePixmap[i] &= ~pVMWARE->hwcur.maskPixmap[i]; 89 vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.sourcePixmap[i]); 90 } 91 92 /* Sync the FIFO, so that the definition precedes any use of the cursor */ 93 vmwareWaitForFB(pVMWARE); 94 pVMWARE->cursorDefined = TRUE; 95} 96 97static void 98vmwareSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) 99{ 100 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 101 TRACEPOINT 102 103 if (pVMWARE->hwcur.fg != fg || pVMWARE->hwcur.bg != bg) { 104 VmwareLog(("SetCursorColors(0x%08x, 0x%08x)\n", bg, fg)); 105 pVMWARE->hwcur.fg = fg; 106 pVMWARE->hwcur.bg = bg; 107 RedefineCursor(pVMWARE); 108 } 109} 110 111static Bool 112vmwareUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) 113{ 114 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 115 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 116 VmwareLog(("UseHWCursor new cursor %p refcnt %i old cursor %p refcnt %i\n", 117 pCurs, pCurs->refcnt, pVMWARE->oldCurs, pVMWARE->oldCurs ? pVMWARE->oldCurs->refcnt : 0)); 118 pCurs->refcnt++; 119 if (pVMWARE->oldCurs) 120 FreeCursor(pVMWARE->oldCurs, None); 121 pVMWARE->oldCurs = pCurs; 122 123 pVMWARE->hwcur.hotX = pCurs->bits->xhot; 124 pVMWARE->hwcur.hotY = pCurs->bits->yhot; 125 126 return pScrn->bitsPerPixel > 8; 127} 128 129static void 130vmwareLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src ) 131{ 132 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 133 const int imageSize = SVGA_BITMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth, 134 pVMWARE->CursorInfoRec->MaxHeight); 135 TRACEPOINT 136 137 memcpy(pVMWARE->hwcur.source, src, imageSize * sizeof(uint32)); 138 memcpy(pVMWARE->hwcur.mask, 139 src + imageSize * sizeof(uint32), imageSize * sizeof(uint32)); 140 RedefineCursor(pVMWARE); 141} 142 143#ifdef ARGB_CURSOR 144#include "cursorstr.h" 145 146static Bool 147vmwareUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs) 148{ 149 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 150 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 151 VmwareLog(("UseHWCursorARGB new cursor %p refcnt %i old cursor %p refcnt %i\n", 152 pCurs, pCurs->refcnt, pVMWARE->oldCurs, pVMWARE->oldCurs ? pVMWARE->oldCurs->refcnt : 0)); 153 pCurs->refcnt++; 154 if (pVMWARE->oldCurs) 155 FreeCursor(pVMWARE->oldCurs, None); 156 pVMWARE->oldCurs = pCurs; 157 158 return pCurs->bits->height <= MAX_CURS && 159 pCurs->bits->width <= MAX_CURS && 160 pScrn->bitsPerPixel > 8; 161} 162 163static void 164vmwareLoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs) 165{ 166 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 167 CARD32 width = pCurs->bits->width; 168 CARD32 height = pCurs->bits->height; 169 CARD32* image = pCurs->bits->argb; 170 CARD32* imageEnd = image + (width * height); 171 172 pVMWARE->cursorDefined = FALSE; 173 174 pVMWARE->hwcur.hotX = pCurs->bits->xhot; 175 pVMWARE->hwcur.hotY = pCurs->bits->yhot; 176 177 vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_DEFINE_ALPHA_CURSOR); 178 vmwareWriteWordToFIFO(pVMWARE, MOUSE_ID); 179 vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->xhot); 180 vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->yhot); 181 vmwareWriteWordToFIFO(pVMWARE, width); 182 vmwareWriteWordToFIFO(pVMWARE, height); 183 184 while (image != imageEnd) { 185 vmwareWriteWordToFIFO(pVMWARE, *image++); 186 } 187 188 vmwareWaitForFB(pVMWARE); 189 pVMWARE->cursorDefined = TRUE; 190} 191#endif 192 193void 194vmwareWriteCursorRegs(VMWAREPtr pVMWARE, Bool visible, Bool force) 195{ 196 int enableVal; 197 198 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ID, MOUSE_ID); 199 if (visible) { 200 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_X, 201 pVMWARE->hwcur.x + pVMWARE->hwcur.hotX); 202 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_Y, 203 pVMWARE->hwcur.y + pVMWARE->hwcur.hotY); 204 } 205 206 if (force) { 207 enableVal = visible ? SVGA_CURSOR_ON_SHOW : SVGA_CURSOR_ON_HIDE; 208 } else { 209 enableVal = visible ? pVMWARE->cursorRestoreToFB : 210 pVMWARE->cursorRemoveFromFB; 211 } 212 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ON, enableVal); 213} 214 215/* disabled by default to reduce spew in DEBUG_LOGGING mode. */ 216/* #define DEBUG_LOG_MOUSE_HIDE_SHOW */ 217 218static void 219vmwareShowCursor(ScrnInfoPtr pScrn) 220{ 221 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 222#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW 223 VmwareLog(("Show: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, 224 pVMWARE->cursorShouldBeHidden)); 225#endif 226 pVMWARE->cursorShouldBeHidden = FALSE; 227 if (pVMWARE->cursorSema == 0 && pVMWARE->cursorDefined) { 228 vmwareWriteCursorRegs(pVMWARE, TRUE, TRUE); 229 } 230} 231 232static void 233vmwareHideCursor(ScrnInfoPtr pScrn) 234{ 235 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 236#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW 237 VmwareLog(("Hide: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, 238 pVMWARE->cursorShouldBeHidden)); 239#endif 240 if (pVMWARE->cursorDefined) { 241 vmwareWriteCursorRegs(pVMWARE, FALSE, TRUE); 242 } 243 pVMWARE->cursorShouldBeHidden = TRUE; 244} 245 246/* disabled by default to reduce spew in DEBUG_LOGGING mode. */ 247/* #define DEBUG_LOG_MOUSE_MOVE */ 248 249static void 250vmwareSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) 251{ 252 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 253#ifdef DEBUG_LOG_MOUSE_MOVE 254 VmwareLog(("Move: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, 255 pVMWARE->cursorShouldBeHidden)); 256#endif 257 /* 258 * We're bad people. We have no concept of a frame (VMWAREAdjustFrame() 259 * is a NOP). The hwcursor code expects us to be frame aware though, so 260 * we have to do this. I'm open to suggestions. I tried not even 261 * hooking AdjustFrame and it didn't help. 262 */ 263 pVMWARE->hwcur.x = x + pScrn->frameX0; 264 pVMWARE->hwcur.y = y + pScrn->frameY0; 265 pVMWARE->hwcur.box.x1 = pVMWARE->hwcur.x; 266 pVMWARE->hwcur.box.x2 = pVMWARE->hwcur.x + pVMWARE->CursorInfoRec->MaxWidth; 267 pVMWARE->hwcur.box.y1 = pVMWARE->hwcur.y; 268 pVMWARE->hwcur.box.y2 = pVMWARE->hwcur.y + pVMWARE->CursorInfoRec->MaxHeight; 269 270 vmwareShowCursor(pScrn); 271} 272 273void 274vmwareCursorModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) 275{ 276 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 277 278 if (pVMWARE->cursorDefined) { 279 vmwareWriteCursorRegs(pVMWARE, !pVMWARE->cursorShouldBeHidden, TRUE); 280 } 281} 282 283Bool 284vmwareCursorInit(ScreenPtr pScreen) 285{ 286 xf86CursorInfoPtr infoPtr; 287 VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pScreen)); 288 Bool ret; 289 290 TRACEPOINT 291 292 /* Require cursor bypass for hwcursor. Ignore deprecated FIFO hwcursor */ 293 if (!(pVMWARE->vmwareCapability & SVGA_CAP_CURSOR_BYPASS)) { 294 return FALSE; 295 } 296 297 infoPtr = xf86CreateCursorInfoRec(); 298 if (!infoPtr) 299 return FALSE; 300 301 pVMWARE->CursorInfoRec = infoPtr; 302 pVMWARE->oldCurs = NULL; 303 304 infoPtr->MaxWidth = MAX_CURS; 305 infoPtr->MaxHeight = MAX_CURS; 306 infoPtr->Flags = HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | 307 HARDWARE_CURSOR_UPDATE_UNHIDDEN | 308 HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED; 309 infoPtr->SetCursorColors = vmwareSetCursorColors; 310 infoPtr->SetCursorPosition = vmwareSetCursorPosition; 311 infoPtr->LoadCursorImage = vmwareLoadCursorImage; 312 infoPtr->HideCursor = vmwareHideCursor; 313 infoPtr->ShowCursor = vmwareShowCursor; 314 infoPtr->UseHWCursor = vmwareUseHWCursor; 315 316#ifdef ARGB_CURSOR 317 if (pVMWARE->vmwareCapability & SVGA_CAP_ALPHA_CURSOR) { 318 infoPtr->UseHWCursorARGB = vmwareUseHWCursorARGB; 319 infoPtr->LoadCursorARGB = vmwareLoadCursorARGB; 320 } 321#endif 322 323 ret = xf86InitCursor(pScreen, infoPtr); 324 if (!ret) { 325 xf86DestroyCursorInfoRec(infoPtr); 326 pVMWARE->CursorInfoRec = NULL; 327 } 328 return ret; 329} 330 331void 332vmwareCursorCloseScreen(ScreenPtr pScreen) 333{ 334 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 335 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 336#ifdef RENDER 337 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 338#endif 339 340 pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; 341 pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; 342#ifdef RENDER 343 if (ps) { 344 ps->Composite = pVMWARE->Composite; 345 } 346#endif /* RENDER */ 347 348 vmwareHideCursor(pScrn); 349 if (pVMWARE->oldCurs) 350 FreeCursor(pVMWARE->oldCurs, None); 351 pVMWARE->oldCurs = NULL; 352 xf86DestroyCursorInfoRec(pVMWARE->CursorInfoRec); 353} 354 355/*** Wrap functions that read from the framebuffer ***/ 356 357void 358vmwareCursorHookWrappers(ScreenPtr pScreen) 359{ 360 VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pScreen)); 361#ifdef RENDER 362 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 363#endif 364 365 TRACEPOINT 366 367 pVMWARE->ScrnFuncs.GetImage = pScreen->GetImage; 368 pVMWARE->ScrnFuncs.CopyWindow = pScreen->CopyWindow; 369 pScreen->GetImage = VMWAREGetImage; 370 pScreen->CopyWindow = VMWARECopyWindow; 371 372#ifdef RENDER 373 if (ps) { 374 pVMWARE->Composite = ps->Composite; 375 ps->Composite = VMWAREComposite; 376 } 377#endif /* RENDER */ 378 379} 380 381static void 382VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h, 383 unsigned int format, unsigned long planeMask, char *pBinImage) 384{ 385 ScreenPtr pScreen = src->pScreen; 386 VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(src->pScreen)); 387 BoxRec box; 388 Bool hidden = FALSE; 389 390 VmwareLog(("VMWAREGetImage(%p, %d, %d, %d, %d, %d, %d, %p)\n", 391 src, x, y, w, h, format, planeMask, pBinImage)); 392 393 box.x1 = src->x + x; 394 box.y1 = src->y + y; 395 box.x2 = box.x1 + w; 396 box.y2 = box.y1 + h; 397 398 if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { 399 PRE_OP_HIDE_CURSOR(); 400 hidden = TRUE; 401 } 402 403 pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; 404 (*pScreen->GetImage)(src, x, y, w, h, format, planeMask, pBinImage); 405 pScreen->GetImage = VMWAREGetImage; 406 407 if (hidden) { 408 POST_OP_SHOW_CURSOR(); 409 } 410} 411 412static void 413VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 414{ 415 ScreenPtr pScreen = pWin->drawable.pScreen; 416 VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pWin->drawable.pScreen)); 417 BoxPtr pBB; 418 Bool hidden = FALSE; 419 420 /* 421 * We only worry about the source region here, since shadowfb will 422 * take care of the destination region. 423 */ 424 pBB = REGION_EXTENTS(pWin->drawable.pScreen, prgnSrc); 425 426 VmwareLog(("VMWARECopyWindow(%p, (%d, %d), (%d, %d - %d, %d)\n", 427 pWin, ptOldOrg.x, ptOldOrg.y, 428 pBB->x1, pBB->y1, pBB->x2, pBB->y2)); 429 430 if (BOX_INTERSECT(*pBB, pVMWARE->hwcur.box)) { 431 PRE_OP_HIDE_CURSOR(); 432 hidden = TRUE; 433 } 434 435 pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; 436 (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); 437 pScreen->CopyWindow = VMWARECopyWindow; 438 439 if (hidden) { 440 POST_OP_SHOW_CURSOR(); 441 } 442} 443 444#ifdef RENDER 445static void 446VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 447 PicturePtr pDst, INT16 xSrc, INT16 ySrc, 448 INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, 449 CARD16 width, CARD16 height) 450{ 451 ScreenPtr pScreen = pDst->pDrawable->pScreen; 452 VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pScreen)); 453 PictureScreenPtr ps = GetPictureScreen(pScreen); 454 BoxRec box; 455 Bool hidden = FALSE; 456 457 if (pSrc->pDrawable) { 458 VmwareLog(("VMWAREComposite op = %d, pSrc = %p, pMask = %p, pDst = %p," 459 " src = (%d, %d), mask = (%d, %d), dst = (%d, %d), w = %d," 460 " h = %d\n", op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 461 xDst, yDst, width, height)); 462 463 /* 464 * We only worry about the source region here, since shadowfb or XAA 465 * will take care of the destination region. 466 */ 467 box.x1 = pSrc->pDrawable->x + xSrc; 468 box.y1 = pSrc->pDrawable->y + ySrc; 469 box.x2 = box.x1 + width; 470 box.y2 = box.y1 + height; 471 472 if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { 473 PRE_OP_HIDE_CURSOR(); 474 hidden = TRUE; 475 } 476 } 477 478 ps->Composite = pVMWARE->Composite; 479 (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, 480 xMask, yMask, xDst, yDst, width, height); 481 ps->Composite = VMWAREComposite; 482 483 if (hidden) { 484 POST_OP_SHOW_CURSOR(); 485 } 486} 487#endif /* RENDER */ 488