vmwarecurs.c revision 16fd1166
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_UPDATE_UNHIDDEN | 294 HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED; 295 infoPtr->SetCursorColors = vmwareSetCursorColors; 296 infoPtr->SetCursorPosition = vmwareSetCursorPosition; 297 infoPtr->LoadCursorImage = vmwareLoadCursorImage; 298 infoPtr->HideCursor = vmwareHideCursor; 299 infoPtr->ShowCursor = vmwareShowCursor; 300 infoPtr->UseHWCursor = vmwareUseHWCursor; 301 302#ifdef ARGB_CURSOR 303 if (pVMWARE->vmwareCapability & SVGA_CAP_ALPHA_CURSOR) { 304 infoPtr->UseHWCursorARGB = vmwareUseHWCursorARGB; 305 infoPtr->LoadCursorARGB = vmwareLoadCursorARGB; 306 } 307#endif 308 309 ret = xf86InitCursor(pScreen, infoPtr); 310 if (!ret) { 311 xf86DestroyCursorInfoRec(infoPtr); 312 pVMWARE->CursorInfoRec = NULL; 313 } 314 return ret; 315} 316 317void 318vmwareCursorCloseScreen(ScreenPtr pScreen) 319{ 320 ScrnInfoPtr pScrn = infoFromScreen(pScreen); 321 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 322#ifdef RENDER 323 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 324#endif 325 326 pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; 327 pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; 328#ifdef RENDER 329 if (ps) { 330 ps->Composite = pVMWARE->Composite; 331 } 332#endif /* RENDER */ 333 334 vmwareHideCursor(pScrn); 335 xf86DestroyCursorInfoRec(pVMWARE->CursorInfoRec); 336} 337 338/*** Wrap functions that read from the framebuffer ***/ 339 340void 341vmwareCursorHookWrappers(ScreenPtr pScreen) 342{ 343 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen)); 344#ifdef RENDER 345 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); 346#endif 347 348 TRACEPOINT 349 350 pVMWARE->ScrnFuncs.GetImage = pScreen->GetImage; 351 pVMWARE->ScrnFuncs.CopyWindow = pScreen->CopyWindow; 352 pScreen->GetImage = VMWAREGetImage; 353 pScreen->CopyWindow = VMWARECopyWindow; 354 355#ifdef RENDER 356 if (ps) { 357 pVMWARE->Composite = ps->Composite; 358 ps->Composite = VMWAREComposite; 359 } 360#endif /* RENDER */ 361 362} 363 364static void 365VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h, 366 unsigned int format, unsigned long planeMask, char *pBinImage) 367{ 368 ScreenPtr pScreen = src->pScreen; 369 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(src->pScreen)); 370 BoxRec box; 371 Bool hidden = FALSE; 372 373 VmwareLog(("VMWAREGetImage(%p, %d, %d, %d, %d, %d, %d, %p)\n", 374 src, x, y, w, h, format, planeMask, pBinImage)); 375 376 box.x1 = src->x + x; 377 box.y1 = src->y + y; 378 box.x2 = box.x1 + w; 379 box.y2 = box.y1 + h; 380 381 if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { 382 PRE_OP_HIDE_CURSOR(); 383 hidden = TRUE; 384 } 385 386 pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; 387 (*pScreen->GetImage)(src, x, y, w, h, format, planeMask, pBinImage); 388 pScreen->GetImage = VMWAREGetImage; 389 390 if (hidden) { 391 POST_OP_SHOW_CURSOR(); 392 } 393} 394 395static void 396VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 397{ 398 ScreenPtr pScreen = pWin->drawable.pScreen; 399 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pWin->drawable.pScreen)); 400 BoxPtr pBB; 401 Bool hidden = FALSE; 402 403 /* 404 * We only worry about the source region here, since shadowfb will 405 * take care of the destination region. 406 */ 407 pBB = REGION_EXTENTS(pWin->drawable.pScreen, prgnSrc); 408 409 VmwareLog(("VMWARECopyWindow(%p, (%d, %d), (%d, %d - %d, %d)\n", 410 pWin, ptOldOrg.x, ptOldOrg.y, 411 pBB->x1, pBB->y1, pBB->x2, pBB->y2)); 412 413 if (BOX_INTERSECT(*pBB, pVMWARE->hwcur.box)) { 414 PRE_OP_HIDE_CURSOR(); 415 hidden = TRUE; 416 } 417 418 pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; 419 (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); 420 pScreen->CopyWindow = VMWARECopyWindow; 421 422 if (hidden) { 423 POST_OP_SHOW_CURSOR(); 424 } 425} 426 427#ifdef RENDER 428static void 429VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 430 PicturePtr pDst, INT16 xSrc, INT16 ySrc, 431 INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, 432 CARD16 width, CARD16 height) 433{ 434 ScreenPtr pScreen = pDst->pDrawable->pScreen; 435 VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen)); 436 PictureScreenPtr ps = GetPictureScreen(pScreen); 437 BoxRec box; 438 Bool hidden = FALSE; 439 440 VmwareLog(("VMWAREComposite op = %d, pSrc = %p, pMask = %p, pDst = %p," 441 " src = (%d, %d), mask = (%d, %d), dst = (%d, %d), w = %d," 442 " h = %d\n", op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 443 xDst, yDst, width, height)); 444 445 /* 446 * We only worry about the source region here, since shadowfb or XAA will 447 * take care of the destination region. 448 */ 449 box.x1 = pSrc->pDrawable->x + xSrc; 450 box.y1 = pSrc->pDrawable->y + ySrc; 451 box.x2 = box.x1 + width; 452 box.y2 = box.y1 + height; 453 454 if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { 455 PRE_OP_HIDE_CURSOR(); 456 hidden = TRUE; 457 } 458 459 ps->Composite = pVMWARE->Composite; 460 (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, 461 xMask, yMask, xDst, yDst, width, height); 462 ps->Composite = VMWAREComposite; 463 464 if (hidden) { 465 POST_OP_SHOW_CURSOR(); 466 } 467} 468#endif /* RENDER */ 469