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