diff options
Diffstat (limited to 'src/vmwarecurs.c')
-rw-r--r-- | src/vmwarecurs.c | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/src/vmwarecurs.c b/src/vmwarecurs.c new file mode 100644 index 0000000..93dacc0 --- /dev/null +++ b/src/vmwarecurs.c @@ -0,0 +1,487 @@ +/* ********************************************************** + * Copyright (C) 1998-2001 VMware, Inc. + * All Rights Reserved + * **********************************************************/ +#ifdef VMX86_DEVEL +char rcsId_vmwarecurs[] = + "Id: vmwarecurs.c,v 1.5 2001/01/30 23:33:02 bennett Exp $"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vmware.h" +#include "vmware_common.h" +#include "bits2pixels.h" + +static void VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, + char *pBinImage); +static void VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc); + +#ifdef RENDER +static void VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, + PicturePtr pDst, INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height); +#endif /* RENDER */ + +static void +RedefineCursor(VMWAREPtr pVMWARE) +{ + int i; + + VmwareLog(("RedefineCursor\n")); + + pVMWARE->cursorDefined = FALSE; + + /* Define cursor */ + vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_DEFINE_CURSOR); + vmwareWriteWordToFIFO(pVMWARE, MOUSE_ID); + vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.hotX); + vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.hotY); + vmwareWriteWordToFIFO(pVMWARE, pVMWARE->CursorInfoRec->MaxWidth); + vmwareWriteWordToFIFO(pVMWARE, pVMWARE->CursorInfoRec->MaxHeight); + vmwareWriteWordToFIFO(pVMWARE, 1); + vmwareWriteWordToFIFO(pVMWARE, pVMWARE->bitsPerPixel); + + /* + * Since we have AND and XOR masks rather than 'source' and 'mask', + * color expand 'mask' with all zero as its foreground and all one as + * its background. This makes 'image & 0 ^ 'source' = source. We + * arange for 'image' & 1 ^ 'source' = 'image' below when we clip + * 'source' below. + */ + vmwareRaster_BitsToPixels((uint8 *) pVMWARE->hwcur.mask, + SVGA_BITMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth), + (uint8 *) pVMWARE->hwcur.maskPixmap, + SVGA_PIXMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth, + pVMWARE->bitsPerPixel), + pVMWARE->bitsPerPixel / 8, + pVMWARE->CursorInfoRec->MaxWidth, + pVMWARE->CursorInfoRec->MaxHeight, 0, ~0); + for (i = 0; i < SVGA_BITMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth, + pVMWARE->CursorInfoRec->MaxHeight); i++) { + vmwareWriteWordToFIFO(pVMWARE, ~pVMWARE->hwcur.mask[i]); + } + + vmwareRaster_BitsToPixels((uint8 *) pVMWARE->hwcur.source, + SVGA_BITMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth), + (uint8 *) pVMWARE->hwcur.sourcePixmap, + SVGA_PIXMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth, + pVMWARE->bitsPerPixel), + pVMWARE->bitsPerPixel / 8, + pVMWARE->CursorInfoRec->MaxWidth, + pVMWARE->CursorInfoRec->MaxHeight, + pVMWARE->hwcur.fg, pVMWARE->hwcur.bg); + /* + * As pointed out above, we need to clip the expanded 'source' against + * the expanded 'mask' since we actually have AND and XOR masks in the + * virtual hardware. Effectively, 'source' becomes a three color fg/bg/0 + * pixmap that XORs appropriately. + */ + for (i = 0; i < SVGA_PIXMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth, + pVMWARE->CursorInfoRec->MaxHeight, + pVMWARE->bitsPerPixel); i++) { + pVMWARE->hwcur.sourcePixmap[i] &= ~pVMWARE->hwcur.maskPixmap[i]; + vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.sourcePixmap[i]); + } + + /* Sync the FIFO, so that the definition preceeds any use of the cursor */ + vmwareWaitForFB(pVMWARE); + pVMWARE->cursorDefined = TRUE; +} + +static void +vmwareSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); + TRACEPOINT + + if (pVMWARE->hwcur.fg != fg || pVMWARE->hwcur.bg != bg) { + VmwareLog(("SetCursorColors(0x%08x, 0x%08x)\n", bg, fg)); + pVMWARE->hwcur.fg = fg; + pVMWARE->hwcur.bg = bg; + RedefineCursor(pVMWARE); + } +} + +static Bool +vmwareUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); + VmwareLog(("UseHWCursor new cursor %p refcnt %i old cursor %p refcnt %i\n", + pCurs, pCurs->refcnt, pVMWARE->oldCurs, pVMWARE->oldCurs ? pVMWARE->oldCurs->refcnt : 0)); + pCurs->refcnt++; + if (pVMWARE->oldCurs) + FreeCursor(pVMWARE->oldCurs, None); + pVMWARE->oldCurs = pCurs; + + pVMWARE->hwcur.hotX = pCurs->bits->xhot; + pVMWARE->hwcur.hotY = pCurs->bits->yhot; + + return pScrn->bitsPerPixel > 8; +} + +static void +vmwareLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src ) +{ + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); + const int imageSize = SVGA_BITMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth, + pVMWARE->CursorInfoRec->MaxHeight); + TRACEPOINT + + memcpy(pVMWARE->hwcur.source, src, imageSize * sizeof(uint32)); + memcpy(pVMWARE->hwcur.mask, + src + imageSize * sizeof(uint32), imageSize * sizeof(uint32)); + RedefineCursor(pVMWARE); +} + +#ifdef ARGB_CURSOR +#include "cursorstr.h" + +static Bool +vmwareUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); + VmwareLog(("UseHWCursorARGB new cursor %p refcnt %i old cursor %p refcnt %i\n", + pCurs, pCurs->refcnt, pVMWARE->oldCurs, pVMWARE->oldCurs ? pVMWARE->oldCurs->refcnt : 0)); + pCurs->refcnt++; + if (pVMWARE->oldCurs) + FreeCursor(pVMWARE->oldCurs, None); + pVMWARE->oldCurs = pCurs; + + return pCurs->bits->height <= MAX_CURS && + pCurs->bits->width <= MAX_CURS && + pScrn->bitsPerPixel > 8; +} + +static void +vmwareLoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs) +{ + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); + CARD32 width = pCurs->bits->width; + CARD32 height = pCurs->bits->height; + CARD32* image = pCurs->bits->argb; + CARD32* imageEnd = image + (width * height); + + pVMWARE->cursorDefined = FALSE; + + pVMWARE->hwcur.hotX = pCurs->bits->xhot; + pVMWARE->hwcur.hotY = pCurs->bits->yhot; + + vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_DEFINE_ALPHA_CURSOR); + vmwareWriteWordToFIFO(pVMWARE, MOUSE_ID); + vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->xhot); + vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->yhot); + vmwareWriteWordToFIFO(pVMWARE, width); + vmwareWriteWordToFIFO(pVMWARE, height); + + while (image != imageEnd) { + vmwareWriteWordToFIFO(pVMWARE, *image++); + } + + vmwareWaitForFB(pVMWARE); + pVMWARE->cursorDefined = TRUE; +} +#endif + +void +vmwareWriteCursorRegs(VMWAREPtr pVMWARE, Bool visible, Bool force) +{ + int enableVal; + + vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ID, MOUSE_ID); + if (visible) { + vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_X, + pVMWARE->hwcur.x + pVMWARE->hwcur.hotX); + vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_Y, + pVMWARE->hwcur.y + pVMWARE->hwcur.hotY); + } + + if (force) { + enableVal = visible ? SVGA_CURSOR_ON_SHOW : SVGA_CURSOR_ON_HIDE; + } else { + enableVal = visible ? pVMWARE->cursorRestoreToFB : + pVMWARE->cursorRemoveFromFB; + } + vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ON, enableVal); +} + +/* disabled by default to reduce spew in DEBUG_LOGGING mode. */ +/* #define DEBUG_LOG_MOUSE_HIDE_SHOW */ + +static void +vmwareShowCursor(ScrnInfoPtr pScrn) +{ + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); +#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW + VmwareLog(("Show: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, + pVMWARE->cursorShouldBeHidden)); +#endif + pVMWARE->cursorShouldBeHidden = FALSE; + if (pVMWARE->cursorSema == 0 && pVMWARE->cursorDefined) { + vmwareWriteCursorRegs(pVMWARE, TRUE, TRUE); + } +} + +static void +vmwareHideCursor(ScrnInfoPtr pScrn) +{ + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); +#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW + VmwareLog(("Hide: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, + pVMWARE->cursorShouldBeHidden)); +#endif + if (pVMWARE->cursorDefined) { + vmwareWriteCursorRegs(pVMWARE, FALSE, TRUE); + } + pVMWARE->cursorShouldBeHidden = TRUE; +} + +/* disabled by default to reduce spew in DEBUG_LOGGING mode. */ +/* #define DEBUG_LOG_MOUSE_MOVE */ + +static void +vmwareSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); +#ifdef DEBUG_LOG_MOUSE_MOVE + VmwareLog(("Move: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined, + pVMWARE->cursorShouldBeHidden)); +#endif + /* + * We're bad people. We have no concept of a frame (VMWAREAdjustFrame() + * is a NOP). The hwcursor code expects us to be frame aware though, so + * we have to do this. I'm open to suggestions. I tried not even + * hooking AdjustFrame and it didn't help. + */ + pVMWARE->hwcur.x = x + pScrn->frameX0; + pVMWARE->hwcur.y = y + pScrn->frameY0; + pVMWARE->hwcur.box.x1 = pVMWARE->hwcur.x; + pVMWARE->hwcur.box.x2 = pVMWARE->hwcur.x + pVMWARE->CursorInfoRec->MaxWidth; + pVMWARE->hwcur.box.y1 = pVMWARE->hwcur.y; + pVMWARE->hwcur.box.y2 = pVMWARE->hwcur.y + pVMWARE->CursorInfoRec->MaxHeight; + + vmwareShowCursor(pScrn); +} + +void +vmwareCursorModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); + + if (pVMWARE->cursorDefined) { + vmwareWriteCursorRegs(pVMWARE, !pVMWARE->cursorShouldBeHidden, TRUE); + } +} + +Bool +vmwareCursorInit(ScreenPtr pScreen) +{ + xf86CursorInfoPtr infoPtr; + VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pScreen)); + Bool ret; + + TRACEPOINT + + /* Require cursor bypass for hwcursor. Ignore deprecated FIFO hwcursor */ + if (!(pVMWARE->vmwareCapability & SVGA_CAP_CURSOR_BYPASS)) { + return FALSE; + } + + infoPtr = xf86CreateCursorInfoRec(); + if (!infoPtr) + return FALSE; + + pVMWARE->CursorInfoRec = infoPtr; + pVMWARE->oldCurs = NULL; + + infoPtr->MaxWidth = MAX_CURS; + infoPtr->MaxHeight = MAX_CURS; + infoPtr->Flags = HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | + HARDWARE_CURSOR_UPDATE_UNHIDDEN | + HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED; + infoPtr->SetCursorColors = vmwareSetCursorColors; + infoPtr->SetCursorPosition = vmwareSetCursorPosition; + infoPtr->LoadCursorImage = vmwareLoadCursorImage; + infoPtr->HideCursor = vmwareHideCursor; + infoPtr->ShowCursor = vmwareShowCursor; + infoPtr->UseHWCursor = vmwareUseHWCursor; + +#ifdef ARGB_CURSOR + if (pVMWARE->vmwareCapability & SVGA_CAP_ALPHA_CURSOR) { + infoPtr->UseHWCursorARGB = vmwareUseHWCursorARGB; + infoPtr->LoadCursorARGB = vmwareLoadCursorARGB; + } +#endif + + ret = xf86InitCursor(pScreen, infoPtr); + if (!ret) { + xf86DestroyCursorInfoRec(infoPtr); + pVMWARE->CursorInfoRec = NULL; + } + return ret; +} + +void +vmwareCursorCloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + VMWAREPtr pVMWARE = VMWAREPTR(pScrn); +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + + pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; + pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; +#ifdef RENDER + if (ps) { + ps->Composite = pVMWARE->Composite; + } +#endif /* RENDER */ + + vmwareHideCursor(pScrn); + if (pVMWARE->oldCurs) + FreeCursor(pVMWARE->oldCurs, None); + pVMWARE->oldCurs = NULL; + xf86DestroyCursorInfoRec(pVMWARE->CursorInfoRec); +} + +/*** Wrap functions that read from the framebuffer ***/ + +void +vmwareCursorHookWrappers(ScreenPtr pScreen) +{ + VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pScreen)); +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + + TRACEPOINT + + pVMWARE->ScrnFuncs.GetImage = pScreen->GetImage; + pVMWARE->ScrnFuncs.CopyWindow = pScreen->CopyWindow; + pScreen->GetImage = VMWAREGetImage; + pScreen->CopyWindow = VMWARECopyWindow; + +#ifdef RENDER + if (ps) { + pVMWARE->Composite = ps->Composite; + ps->Composite = VMWAREComposite; + } +#endif /* RENDER */ + +} + +static void +VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *pBinImage) +{ + ScreenPtr pScreen = src->pScreen; + VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(src->pScreen)); + BoxRec box; + Bool hidden = FALSE; + + VmwareLog(("VMWAREGetImage(%p, %d, %d, %d, %d, %d, %d, %p)\n", + src, x, y, w, h, format, planeMask, pBinImage)); + + box.x1 = src->x + x; + box.y1 = src->y + y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + + if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { + PRE_OP_HIDE_CURSOR(); + hidden = TRUE; + } + + pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage; + (*pScreen->GetImage)(src, x, y, w, h, format, planeMask, pBinImage); + pScreen->GetImage = VMWAREGetImage; + + if (hidden) { + POST_OP_SHOW_CURSOR(); + } +} + +static void +VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pWin->drawable.pScreen)); + BoxPtr pBB; + Bool hidden = FALSE; + + /* + * We only worry about the source region here, since shadowfb will + * take care of the destination region. + */ + pBB = REGION_EXTENTS(pWin->drawable.pScreen, prgnSrc); + + VmwareLog(("VMWARECopyWindow(%p, (%d, %d), (%d, %d - %d, %d)\n", + pWin, ptOldOrg.x, ptOldOrg.y, + pBB->x1, pBB->y1, pBB->x2, pBB->y2)); + + if (BOX_INTERSECT(*pBB, pVMWARE->hwcur.box)) { + PRE_OP_HIDE_CURSOR(); + hidden = TRUE; + } + + pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow; + (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); + pScreen->CopyWindow = VMWARECopyWindow; + + if (hidden) { + POST_OP_SHOW_CURSOR(); + } +} + +#ifdef RENDER +static void +VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, + PicturePtr pDst, INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + VMWAREPtr pVMWARE = VMWAREPTR(xf86ScreenToScrn(pScreen)); + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec box; + Bool hidden = FALSE; + + if (pSrc->pDrawable) { + VmwareLog(("VMWAREComposite op = %d, pSrc = %p, pMask = %p, pDst = %p," + " src = (%d, %d), mask = (%d, %d), dst = (%d, %d), w = %d," + " h = %d\n", op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height)); + + /* + * We only worry about the source region here, since shadowfb or XAA + * will take care of the destination region. + */ + box.x1 = pSrc->pDrawable->x + xSrc; + box.y1 = pSrc->pDrawable->y + ySrc; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + + if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) { + PRE_OP_HIDE_CURSOR(); + hidden = TRUE; + } + } + + ps->Composite = pVMWARE->Composite; + (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + ps->Composite = VMWAREComposite; + + if (hidden) { + POST_OP_SHOW_CURSOR(); + } +} +#endif /* RENDER */ |