vmwarecurs.c revision 6df26cac
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/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/vmware/vmwarecurs.c,v 1.10 2003/02/04 01:39:53 dawes Exp $ */ 10 11#ifdef HAVE_CONFIG_H 12#include "config.h" 13#endif 14 15#include "vmware.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 preceeds 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 = infoFromScreen(pScreen); 115 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 116 117 pVMWARE->hwcur.hotX = pCurs->bits->xhot; 118 pVMWARE->hwcur.hotY = pCurs->bits->yhot; 119 120 return pScrn->bitsPerPixel > 8; 121} 122 123static void 124vmwareLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src ) 125{ 126 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 127 const int imageSize = SVGA_BITMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth, 128 pVMWARE->CursorInfoRec->MaxHeight); 129 TRACEPOINT 130 131 memcpy(pVMWARE->hwcur.source, src, imageSize * sizeof(uint32)); 132 memcpy(pVMWARE->hwcur.mask, 133 src + imageSize * sizeof(uint32), imageSize * sizeof(uint32)); 134 RedefineCursor(pVMWARE); 135} 136 137#ifdef ARGB_CURSOR 138#include "cursorstr.h" 139 140static Bool 141vmwareUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs) 142{ 143 ScrnInfoPtr pScrn = infoFromScreen(pScreen); 144 145 return pCurs->bits->height <= MAX_CURS && 146 pCurs->bits->width <= MAX_CURS && 147 pScrn->bitsPerPixel > 8; 148} 149 150static void 151vmwareLoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs) 152{ 153 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 154 CARD32 width = pCurs->bits->width; 155 CARD32 height = pCurs->bits->height; 156 CARD32* image = pCurs->bits->argb; 157 CARD32* imageEnd = image + (width * height); 158 159 pVMWARE->cursorDefined = FALSE; 160 161 pVMWARE->hwcur.hotX = pCurs->bits->xhot; 162 pVMWARE->hwcur.hotY = pCurs->bits->yhot; 163 164 vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_DEFINE_ALPHA_CURSOR); 165 vmwareWriteWordToFIFO(pVMWARE, MOUSE_ID); 166 vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->xhot); 167 vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->yhot); 168 vmwareWriteWordToFIFO(pVMWARE, width); 169 vmwareWriteWordToFIFO(pVMWARE, height); 170 171 while (image != imageEnd) { 172 vmwareWriteWordToFIFO(pVMWARE, *image++); 173 } 174 175 vmwareWaitForFB(pVMWARE); 176 pVMWARE->cursorDefined = TRUE; 177} 178#endif 179 180void 181vmwareWriteCursorRegs(VMWAREPtr pVMWARE, Bool visible, Bool force) 182{ 183 int enableVal; 184 185 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ID, MOUSE_ID); 186 if (visible) { 187 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_X, 188 pVMWARE->hwcur.x + pVMWARE->hwcur.hotX); 189 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_Y, 190 pVMWARE->hwcur.y + pVMWARE->hwcur.hotY); 191 } 192 193 if (force) { 194 enableVal = visible ? SVGA_CURSOR_ON_SHOW : SVGA_CURSOR_ON_HIDE; 195 } else { 196 enableVal = visible ? pVMWARE->cursorRestoreToFB : 197 pVMWARE->cursorRemoveFromFB; 198 } 199 vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ON, enableVal); 200} 201 202/* disabled by default to reduce spew in DEBUG_LOGGING mode. */ 203/* #define DEBUG_LOG_MOUSE_HIDE_SHOW */ 204 205static void 206vmwareShowCursor(ScrnInfoPtr pScrn) 207{ 208 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 209#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW 210 VmwareLog(("Show: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, 211 pVMWARE->cursorShouldBeHidden)); 212#endif 213 pVMWARE->cursorShouldBeHidden = FALSE; 214 if (pVMWARE->cursorSema == 0 && pVMWARE->cursorDefined) { 215 vmwareWriteCursorRegs(pVMWARE, TRUE, TRUE); 216 } 217} 218 219static void 220vmwareHideCursor(ScrnInfoPtr pScrn) 221{ 222 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 223#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW 224 VmwareLog(("Hide: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, 225 pVMWARE->cursorShouldBeHidden)); 226#endif 227 if (pVMWARE->cursorDefined) { 228 vmwareWriteCursorRegs(pVMWARE, FALSE, TRUE); 229 } 230 pVMWARE->cursorShouldBeHidden = TRUE; 231} 232 233/* disabled by default to reduce spew in DEBUG_LOGGING mode. */ 234/* #define DEBUG_LOG_MOUSE_MOVE */ 235 236static void 237vmwareSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) 238{ 239 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 240#ifdef DEBUG_LOG_MOUSE_MOVE 241 VmwareLog(("Move: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, 242 pVMWARE->cursorShouldBeHidden)); 243#endif 244 /* 245 * We're bad people. We have no concept of a frame (VMWAREAdjustFrame() 246 * is a NOP). The hwcursor code expects us to be frame aware though, so 247 * we have to do this. I'm open to suggestions. I tried not even 248 * hooking AdjustFrame and it didn't help. 249 */ 250 pVMWARE->hwcur.x = x + pScrn->frameX0; 251 pVMWARE->hwcur.y = y + pScrn->frameY0; 252 pVMWARE->hwcur.box.x1 = pVMWARE->hwcur.x; 253 pVMWARE->hwcur.box.x2 = pVMWARE->hwcur.x + pVMWARE->CursorInfoRec->MaxWidth; 254 pVMWARE->hwcur.box.y1 = pVMWARE->hwcur.y; 255 pVMWARE->hwcur.box.y2 = pVMWARE->hwcur.y + pVMWARE->CursorInfoRec->MaxHeight; 256 257 vmwareShowCursor(pScrn); 258} 259 260void 261vmwareCursorModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) 262{ 263 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 264 265 if (pVMWARE->cursorDefined) { 266 vmwareWriteCursorRegs(pVMWARE, !pVMWARE->cursorShouldBeHidden, TRUE); 267 } 268} 269 270Bool 271vmwareCursorInit(ScreenPtr pScreen) 272{ 273 xf86CursorInfoPtr infoPtr; 274 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen)); 275 Bool ret; 276 277 TRACEPOINT 278 279 /* Require cursor bypass for hwcursor. Ignore deprecated FIFO hwcursor */ 280 if (!(pVMWARE->vmwareCapability & SVGA_CAP_CURSOR_BYPASS)) { 281 return FALSE; 282 } 283 284 infoPtr = xf86CreateCursorInfoRec(); 285 if (!infoPtr) 286 return FALSE; 287 288 pVMWARE->CursorInfoRec = infoPtr; 289 290 infoPtr->MaxWidth = MAX_CURS; 291 infoPtr->MaxHeight = MAX_CURS; 292 infoPtr->Flags = HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | 293 HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED; 294 infoPtr->SetCursorColors = vmwareSetCursorColors; 295 infoPtr->SetCursorPosition = vmwareSetCursorPosition; 296 infoPtr->LoadCursorImage = vmwareLoadCursorImage; 297 infoPtr->HideCursor = vmwareHideCursor; 298 infoPtr->ShowCursor = vmwareShowCursor; 299 infoPtr->UseHWCursor = vmwareUseHWCursor; 300 301#ifdef ARGB_CURSOR 302 if (pVMWARE->vmwareCapability & SVGA_CAP_ALPHA_CURSOR) { 303 infoPtr->UseHWCursorARGB = vmwareUseHWCursorARGB; 304 infoPtr->LoadCursorARGB = vmwareLoadCursorARGB; 305 } 306#endif 307 308 ret = xf86InitCursor(pScreen, infoPtr); 309 if (!ret) { 310 xf86DestroyCursorInfoRec(infoPtr); 311 pVMWARE->CursorInfoRec = NULL; 312 } 313 return ret; 314} 315 316void 317vmwareCursorCloseScreen(ScreenPtr pScreen) 318{ 319 ScrnInfoPtr pScrn = infoFromScreen(pScreen); 320 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 321#ifdef RENDER 322 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 323#endif 324 325 pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; 326 pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; 327#ifdef RENDER 328 if (ps) { 329 ps->Composite = pVMWARE->Composite; 330 } 331#endif /* RENDER */ 332 333 vmwareHideCursor(pScrn); 334 xf86DestroyCursorInfoRec(pVMWARE->CursorInfoRec); 335} 336 337/*** Wrap functions that read from the framebuffer ***/ 338 339void 340vmwareCursorHookWrappers(ScreenPtr pScreen) 341{ 342 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen)); 343#ifdef RENDER 344 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 345#endif 346 347 TRACEPOINT 348 349 pVMWARE->ScrnFuncs.GetImage = pScreen->GetImage; 350 pVMWARE->ScrnFuncs.CopyWindow = pScreen->CopyWindow; 351 pScreen->GetImage = VMWAREGetImage; 352 pScreen->CopyWindow = VMWARECopyWindow; 353 354#ifdef RENDER 355 if (ps) { 356 pVMWARE->Composite = ps->Composite; 357 ps->Composite = VMWAREComposite; 358 } 359#endif /* RENDER */ 360 361} 362 363static void 364VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h, 365 unsigned int format, unsigned long planeMask, char *pBinImage) 366{ 367 ScreenPtr pScreen = src->pScreen; 368 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(src->pScreen)); 369 BoxRec box; 370 Bool hidden = FALSE; 371 372 VmwareLog(("VMWAREGetImage(%p, %d, %d, %d, %d, %d, %d, %p)\n", 373 src, x, y, w, h, format, planeMask, pBinImage)); 374 375 box.x1 = src->x + x; 376 box.y1 = src->y + y; 377 box.x2 = box.x1 + w; 378 box.y2 = box.y1 + h; 379 380 if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { 381 PRE_OP_HIDE_CURSOR(); 382 hidden = TRUE; 383 } 384 385 pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; 386 (*pScreen->GetImage)(src, x, y, w, h, format, planeMask, pBinImage); 387 pScreen->GetImage = VMWAREGetImage; 388 389 if (hidden) { 390 POST_OP_SHOW_CURSOR(); 391 } 392} 393 394static void 395VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 396{ 397 ScreenPtr pScreen = pWin->drawable.pScreen; 398 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pWin->drawable.pScreen)); 399 BoxPtr pBB; 400 Bool hidden = FALSE; 401 402 /* 403 * We only worry about the source region here, since shadowfb will 404 * take care of the destination region. 405 */ 406 pBB = REGION_EXTENTS(pWin->drawable.pScreen, prgnSrc); 407 408 VmwareLog(("VMWARECopyWindow(%p, (%d, %d), (%d, %d - %d, %d)\n", 409 pWin, ptOldOrg.x, ptOldOrg.y, 410 pBB->x1, pBB->y1, pBB->x2, pBB->y2)); 411 412 if (BOX_INTERSECT(*pBB, pVMWARE->hwcur.box)) { 413 PRE_OP_HIDE_CURSOR(); 414 hidden = TRUE; 415 } 416 417 pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; 418 (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); 419 pScreen->CopyWindow = VMWARECopyWindow; 420 421 if (hidden) { 422 POST_OP_SHOW_CURSOR(); 423 } 424} 425 426#ifdef RENDER 427static void 428VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 429 PicturePtr pDst, INT16 xSrc, INT16 ySrc, 430 INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, 431 CARD16 width, CARD16 height) 432{ 433 ScreenPtr pScreen = pDst->pDrawable->pScreen; 434 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen)); 435 PictureScreenPtr ps = GetPictureScreen(pScreen); 436 BoxRec box; 437 Bool hidden = FALSE; 438 439 VmwareLog(("VMWAREComposite op = %d, pSrc = %p, pMask = %p, pDst = %p," 440 " src = (%d, %d), mask = (%d, %d), dst = (%d, %d), w = %d," 441 " h = %d\n", op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 442 xDst, yDst, width, height)); 443 444 /* 445 * We only worry about the source region here, since shadowfb or XAA will 446 * take care of the destination region. 447 */ 448 box.x1 = pSrc->pDrawable->x + xSrc; 449 box.y1 = pSrc->pDrawable->y + ySrc; 450 box.x2 = box.x1 + width; 451 box.y2 = box.y1 + height; 452 453 if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { 454 PRE_OP_HIDE_CURSOR(); 455 hidden = TRUE; 456 } 457 458 ps->Composite = pVMWARE->Composite; 459 (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, 460 xMask, yMask, xDst, yDst, width, height); 461 ps->Composite = VMWAREComposite; 462 463 if (hidden) { 464 POST_OP_SHOW_CURSOR(); 465 } 466} 467#endif /* RENDER */ 468