vmwarecurs.c revision a241306c
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
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
14#include "vmware.h"
15#include "bits2pixels.h"
16
17static void VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h,
18                           unsigned int format, unsigned long planeMask,
19                           char *pBinImage);
20static void VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
21                             RegionPtr prgnSrc);
22
23#ifdef RENDER
24static void VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
25			    PicturePtr pDst, INT16 xSrc, INT16 ySrc,
26			    INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst,
27			    CARD16 width, CARD16 height);
28#endif /* RENDER */
29
30static void
31RedefineCursor(VMWAREPtr pVMWARE)
32{
33    int i;
34
35    VmwareLog(("RedefineCursor\n"));
36
37    pVMWARE->cursorDefined = FALSE;
38
39    /* Define cursor */
40    vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_DEFINE_CURSOR);
41    vmwareWriteWordToFIFO(pVMWARE, MOUSE_ID);
42    vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.hotX);
43    vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.hotY);
44    vmwareWriteWordToFIFO(pVMWARE, pVMWARE->CursorInfoRec->MaxWidth);
45    vmwareWriteWordToFIFO(pVMWARE, pVMWARE->CursorInfoRec->MaxHeight);
46    vmwareWriteWordToFIFO(pVMWARE, 1);
47    vmwareWriteWordToFIFO(pVMWARE, pVMWARE->bitsPerPixel);
48
49    /*
50     * Since we have AND and XOR masks rather than 'source' and 'mask',
51     * color expand 'mask' with all zero as its foreground and all one as
52     * its background.  This makes 'image & 0 ^ 'source' = source.  We
53     * arange for 'image' & 1 ^ 'source' = 'image' below when we clip
54     * 'source' below.
55     */
56    vmwareRaster_BitsToPixels((uint8 *) pVMWARE->hwcur.mask,
57                        SVGA_BITMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth),
58                        (uint8 *) pVMWARE->hwcur.maskPixmap,
59                        SVGA_PIXMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth,
60                                              pVMWARE->bitsPerPixel),
61                        pVMWARE->bitsPerPixel / 8,
62                        pVMWARE->CursorInfoRec->MaxWidth,
63                        pVMWARE->CursorInfoRec->MaxHeight, 0, ~0);
64    for (i = 0; i < SVGA_BITMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth,
65                                     pVMWARE->CursorInfoRec->MaxHeight); i++) {
66        vmwareWriteWordToFIFO(pVMWARE, ~pVMWARE->hwcur.mask[i]);
67    }
68
69    vmwareRaster_BitsToPixels((uint8 *) pVMWARE->hwcur.source,
70                        SVGA_BITMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth),
71                        (uint8 *) pVMWARE->hwcur.sourcePixmap,
72                        SVGA_PIXMAP_INCREMENT(pVMWARE->CursorInfoRec->MaxWidth,
73                                              pVMWARE->bitsPerPixel),
74                        pVMWARE->bitsPerPixel / 8,
75                        pVMWARE->CursorInfoRec->MaxWidth,
76                        pVMWARE->CursorInfoRec->MaxHeight,
77                        pVMWARE->hwcur.fg, pVMWARE->hwcur.bg);
78    /*
79     * As pointed out above, we need to clip the expanded 'source' against
80     * the expanded 'mask' since we actually have AND and XOR masks in the
81     * virtual hardware.  Effectively, 'source' becomes a three color fg/bg/0
82     * pixmap that XORs appropriately.
83     */
84    for (i = 0; i < SVGA_PIXMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth,
85                                     pVMWARE->CursorInfoRec->MaxHeight,
86                                     pVMWARE->bitsPerPixel); i++) {
87        pVMWARE->hwcur.sourcePixmap[i] &= ~pVMWARE->hwcur.maskPixmap[i];
88	vmwareWriteWordToFIFO(pVMWARE, pVMWARE->hwcur.sourcePixmap[i]);
89    }
90
91    /* Sync the FIFO, so that the definition preceeds any use of the cursor */
92    vmwareWaitForFB(pVMWARE);
93    pVMWARE->cursorDefined = TRUE;
94}
95
96static void
97vmwareSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
98{
99    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
100    TRACEPOINT
101
102    if (pVMWARE->hwcur.fg != fg || pVMWARE->hwcur.bg != bg) {
103        VmwareLog(("SetCursorColors(0x%08x, 0x%08x)\n", bg, fg));
104        pVMWARE->hwcur.fg = fg;
105        pVMWARE->hwcur.bg = bg;
106        RedefineCursor(pVMWARE);
107    }
108}
109
110static Bool
111vmwareUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
112{
113    ScrnInfoPtr pScrn = infoFromScreen(pScreen);
114    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
115    VmwareLog(("UseHWCursor new cursor %p refcnt %i old cursor %p refcnt %i\n",
116              pCurs, pCurs->refcnt, pVMWARE->oldCurs, pVMWARE->oldCurs ? pVMWARE->oldCurs->refcnt : 0));
117    pCurs->refcnt++;
118    if (pVMWARE->oldCurs)
119       FreeCursor(pVMWARE->oldCurs, None);
120    pVMWARE->oldCurs = pCurs;
121
122    pVMWARE->hwcur.hotX = pCurs->bits->xhot;
123    pVMWARE->hwcur.hotY = pCurs->bits->yhot;
124
125    return pScrn->bitsPerPixel > 8;
126}
127
128static void
129vmwareLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src )
130{
131    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
132    const int imageSize = SVGA_BITMAP_SIZE(pVMWARE->CursorInfoRec->MaxWidth,
133                                           pVMWARE->CursorInfoRec->MaxHeight);
134    TRACEPOINT
135
136    memcpy(pVMWARE->hwcur.source, src, imageSize * sizeof(uint32));
137    memcpy(pVMWARE->hwcur.mask,
138           src + imageSize * sizeof(uint32), imageSize * sizeof(uint32));
139    RedefineCursor(pVMWARE);
140}
141
142#ifdef ARGB_CURSOR
143#include "cursorstr.h"
144
145static Bool
146vmwareUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
147{
148    ScrnInfoPtr pScrn = infoFromScreen(pScreen);
149    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
150    VmwareLog(("UseHWCursorARGB new cursor %p refcnt %i old cursor %p refcnt %i\n",
151              pCurs, pCurs->refcnt, pVMWARE->oldCurs, pVMWARE->oldCurs ? pVMWARE->oldCurs->refcnt : 0));
152    pCurs->refcnt++;
153    if (pVMWARE->oldCurs)
154       FreeCursor(pVMWARE->oldCurs, None);
155    pVMWARE->oldCurs = pCurs;
156
157    return pCurs->bits->height <= MAX_CURS &&
158           pCurs->bits->width <= MAX_CURS &&
159           pScrn->bitsPerPixel > 8;
160}
161
162static void
163vmwareLoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs)
164{
165    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
166    CARD32 width = pCurs->bits->width;
167    CARD32 height = pCurs->bits->height;
168    CARD32* image = pCurs->bits->argb;
169    CARD32* imageEnd = image + (width * height);
170
171    pVMWARE->cursorDefined = FALSE;
172
173    pVMWARE->hwcur.hotX = pCurs->bits->xhot;
174    pVMWARE->hwcur.hotY = pCurs->bits->yhot;
175
176    vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_DEFINE_ALPHA_CURSOR);
177    vmwareWriteWordToFIFO(pVMWARE, MOUSE_ID);
178    vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->xhot);
179    vmwareWriteWordToFIFO(pVMWARE, pCurs->bits->yhot);
180    vmwareWriteWordToFIFO(pVMWARE, width);
181    vmwareWriteWordToFIFO(pVMWARE, height);
182
183    while (image != imageEnd) {
184        vmwareWriteWordToFIFO(pVMWARE, *image++);
185    }
186
187    vmwareWaitForFB(pVMWARE);
188    pVMWARE->cursorDefined = TRUE;
189}
190#endif
191
192void
193vmwareWriteCursorRegs(VMWAREPtr pVMWARE, Bool visible, Bool force)
194{
195    int enableVal;
196
197    vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ID, MOUSE_ID);
198    if (visible) {
199        vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_X,
200                       pVMWARE->hwcur.x + pVMWARE->hwcur.hotX);
201        vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_Y,
202                       pVMWARE->hwcur.y + pVMWARE->hwcur.hotY);
203    }
204
205    if (force) {
206        enableVal = visible ? SVGA_CURSOR_ON_SHOW : SVGA_CURSOR_ON_HIDE;
207    } else {
208        enableVal = visible ? pVMWARE->cursorRestoreToFB :
209            pVMWARE->cursorRemoveFromFB;
210    }
211    vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ON, enableVal);
212}
213
214/* disabled by default to reduce spew in DEBUG_LOGGING mode. */
215/* #define DEBUG_LOG_MOUSE_HIDE_SHOW */
216
217static void
218vmwareShowCursor(ScrnInfoPtr pScrn)
219{
220    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
221#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW
222    VmwareLog(("Show: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined,
223	       pVMWARE->cursorShouldBeHidden));
224#endif
225    pVMWARE->cursorShouldBeHidden = FALSE;
226    if (pVMWARE->cursorSema == 0 && pVMWARE->cursorDefined) {
227        vmwareWriteCursorRegs(pVMWARE, TRUE, TRUE);
228    }
229}
230
231static void
232vmwareHideCursor(ScrnInfoPtr pScrn)
233{
234    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
235#ifdef DEBUG_LOG_MOUSE_HIDE_SHOW
236    VmwareLog(("Hide: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined,
237	       pVMWARE->cursorShouldBeHidden));
238#endif
239    if (pVMWARE->cursorDefined) {
240        vmwareWriteCursorRegs(pVMWARE, FALSE, TRUE);
241    }
242    pVMWARE->cursorShouldBeHidden = TRUE;
243}
244
245/* disabled by default to reduce spew in DEBUG_LOGGING mode. */
246/* #define DEBUG_LOG_MOUSE_MOVE */
247
248static void
249vmwareSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
250{
251    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
252#ifdef DEBUG_LOG_MOUSE_MOVE
253    VmwareLog(("Move: %d %d %d\n", pVMWARE->cursorSema, pVMWARE->cursorDefined,
254	       pVMWARE->cursorShouldBeHidden));
255#endif
256    /*
257     * We're bad people.  We have no concept of a frame (VMWAREAdjustFrame()
258     * is a NOP).  The hwcursor code expects us to be frame aware though, so
259     * we have to do this.  I'm open to suggestions.  I tried not even
260     * hooking AdjustFrame and it didn't help.
261     */
262    pVMWARE->hwcur.x = x + pScrn->frameX0;
263    pVMWARE->hwcur.y = y + pScrn->frameY0;
264    pVMWARE->hwcur.box.x1 = pVMWARE->hwcur.x;
265    pVMWARE->hwcur.box.x2 = pVMWARE->hwcur.x + pVMWARE->CursorInfoRec->MaxWidth;
266    pVMWARE->hwcur.box.y1 = pVMWARE->hwcur.y;
267    pVMWARE->hwcur.box.y2 = pVMWARE->hwcur.y + pVMWARE->CursorInfoRec->MaxHeight;
268
269    vmwareShowCursor(pScrn);
270}
271
272void
273vmwareCursorModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
274{
275    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
276
277    if (pVMWARE->cursorDefined) {
278        vmwareWriteCursorRegs(pVMWARE, !pVMWARE->cursorShouldBeHidden, TRUE);
279    }
280}
281
282Bool
283vmwareCursorInit(ScreenPtr pScreen)
284{
285    xf86CursorInfoPtr infoPtr;
286    VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen));
287    Bool ret;
288
289    TRACEPOINT
290
291    /* Require cursor bypass for hwcursor.  Ignore deprecated FIFO hwcursor */
292    if (!(pVMWARE->vmwareCapability & SVGA_CAP_CURSOR_BYPASS)) {
293        return FALSE;
294    }
295
296    infoPtr = xf86CreateCursorInfoRec();
297    if (!infoPtr)
298        return FALSE;
299
300    pVMWARE->CursorInfoRec = infoPtr;
301    pVMWARE->oldCurs = NULL;
302
303    infoPtr->MaxWidth = MAX_CURS;
304    infoPtr->MaxHeight = MAX_CURS;
305    infoPtr->Flags = HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
306                     HARDWARE_CURSOR_UPDATE_UNHIDDEN |
307                     HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED;
308    infoPtr->SetCursorColors = vmwareSetCursorColors;
309    infoPtr->SetCursorPosition = vmwareSetCursorPosition;
310    infoPtr->LoadCursorImage = vmwareLoadCursorImage;
311    infoPtr->HideCursor = vmwareHideCursor;
312    infoPtr->ShowCursor = vmwareShowCursor;
313    infoPtr->UseHWCursor = vmwareUseHWCursor;
314
315#ifdef ARGB_CURSOR
316    if (pVMWARE->vmwareCapability & SVGA_CAP_ALPHA_CURSOR) {
317        infoPtr->UseHWCursorARGB = vmwareUseHWCursorARGB;
318        infoPtr->LoadCursorARGB = vmwareLoadCursorARGB;
319    }
320#endif
321
322    ret = xf86InitCursor(pScreen, infoPtr);
323    if (!ret) {
324        xf86DestroyCursorInfoRec(infoPtr);
325        pVMWARE->CursorInfoRec = NULL;
326    }
327    return ret;
328}
329
330void
331vmwareCursorCloseScreen(ScreenPtr pScreen)
332{
333    ScrnInfoPtr pScrn = infoFromScreen(pScreen);
334    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
335#ifdef RENDER
336    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
337#endif
338
339    pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage;
340    pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow;
341#ifdef RENDER
342    if (ps) {
343        ps->Composite = pVMWARE->Composite;
344    }
345#endif /* RENDER */
346
347    vmwareHideCursor(pScrn);
348    if (pVMWARE->oldCurs)
349       FreeCursor(pVMWARE->oldCurs, None);
350    pVMWARE->oldCurs = NULL;
351    xf86DestroyCursorInfoRec(pVMWARE->CursorInfoRec);
352}
353
354/***  Wrap functions that read from the framebuffer ***/
355
356void
357vmwareCursorHookWrappers(ScreenPtr pScreen)
358{
359    VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen));
360#ifdef RENDER
361    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
362#endif
363
364    TRACEPOINT
365
366    pVMWARE->ScrnFuncs.GetImage = pScreen->GetImage;
367    pVMWARE->ScrnFuncs.CopyWindow = pScreen->CopyWindow;
368    pScreen->GetImage = VMWAREGetImage;
369    pScreen->CopyWindow = VMWARECopyWindow;
370
371#ifdef RENDER
372    if (ps) {
373        pVMWARE->Composite = ps->Composite;
374        ps->Composite = VMWAREComposite;
375    }
376#endif /* RENDER */
377
378}
379
380static void
381VMWAREGetImage(DrawablePtr src, int x, int y, int w, int h,
382               unsigned int format, unsigned long planeMask, char *pBinImage)
383{
384    ScreenPtr pScreen = src->pScreen;
385    VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(src->pScreen));
386    BoxRec box;
387    Bool hidden = FALSE;
388
389    VmwareLog(("VMWAREGetImage(%p, %d, %d, %d, %d, %d, %d, %p)\n",
390               src, x, y, w, h, format, planeMask, pBinImage));
391
392    box.x1 = src->x + x;
393    box.y1 = src->y + y;
394    box.x2 = box.x1 + w;
395    box.y2 = box.y1 + h;
396
397    if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) {
398        PRE_OP_HIDE_CURSOR();
399        hidden = TRUE;
400    }
401
402    pScreen->GetImage = pVMWARE->ScrnFuncs.GetImage;
403    (*pScreen->GetImage)(src, x, y, w, h, format, planeMask, pBinImage);
404    pScreen->GetImage = VMWAREGetImage;
405
406    if (hidden) {
407        POST_OP_SHOW_CURSOR();
408    }
409}
410
411static void
412VMWARECopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
413{
414    ScreenPtr pScreen = pWin->drawable.pScreen;
415    VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pWin->drawable.pScreen));
416    BoxPtr pBB;
417    Bool hidden = FALSE;
418
419    /*
420     * We only worry about the source region here, since shadowfb will
421     * take care of the destination region.
422     */
423    pBB = REGION_EXTENTS(pWin->drawable.pScreen, prgnSrc);
424
425    VmwareLog(("VMWARECopyWindow(%p, (%d, %d), (%d, %d - %d, %d)\n",
426               pWin, ptOldOrg.x, ptOldOrg.y,
427               pBB->x1, pBB->y1, pBB->x2, pBB->y2));
428
429    if (BOX_INTERSECT(*pBB, pVMWARE->hwcur.box)) {
430        PRE_OP_HIDE_CURSOR();
431        hidden = TRUE;
432    }
433
434    pScreen->CopyWindow = pVMWARE->ScrnFuncs.CopyWindow;
435    (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
436    pScreen->CopyWindow = VMWARECopyWindow;
437
438    if (hidden) {
439        POST_OP_SHOW_CURSOR();
440    }
441}
442
443#ifdef RENDER
444static void
445VMWAREComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
446		PicturePtr pDst, INT16 xSrc, INT16 ySrc,
447		INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst,
448		CARD16 width, CARD16 height)
449{
450    ScreenPtr pScreen = pDst->pDrawable->pScreen;
451    VMWAREPtr pVMWARE = VMWAREPTR(infoFromScreen(pScreen));
452    PictureScreenPtr ps = GetPictureScreen(pScreen);
453    BoxRec box;
454    Bool hidden = FALSE;
455
456    if (pSrc->pDrawable) {
457        VmwareLog(("VMWAREComposite op = %d, pSrc = %p, pMask = %p, pDst = %p,"
458                   " src = (%d, %d), mask = (%d, %d), dst = (%d, %d), w = %d,"
459                   " h = %d\n", op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
460                   xDst, yDst, width, height));
461
462        /*
463         * We only worry about the source region here, since shadowfb or XAA
464         * will take care of the destination region.
465         */
466        box.x1 = pSrc->pDrawable->x + xSrc;
467        box.y1 = pSrc->pDrawable->y + ySrc;
468        box.x2 = box.x1 + width;
469        box.y2 = box.y1 + height;
470
471        if (BOX_INTERSECT(box, pVMWARE->hwcur.box)) {
472            PRE_OP_HIDE_CURSOR();
473            hidden = TRUE;
474        }
475    }
476
477    ps->Composite = pVMWARE->Composite;
478    (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
479		     xMask, yMask, xDst, yDst, width, height);
480    ps->Composite = VMWAREComposite;
481
482    if (hidden) {
483        POST_OP_SHOW_CURSOR();
484    }
485}
486#endif /* RENDER */
487