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