summaryrefslogtreecommitdiff
path: root/src/vmwarecurs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vmwarecurs.c')
-rw-r--r--src/vmwarecurs.c487
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 */