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