VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/xgraphics/vboxutils-new.c@ 6583

Last change on this file since 6583 was 6583, checked in by vboxsync, 17 years ago

r=bird: gxx_personality_v0 can be avoided.

  • Property svn:eol-style set to native
File size: 26.1 KB
Line 
1/** @file
2 * VirtualBox X11 Additions graphics driver utility functions
3 */
4
5/*
6 * Copyright (C) 2006-2007 innotek GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include <VBox/VBoxGuest.h>
18
19#include <xf86Pci.h>
20#include <Pci.h>
21
22#include "xf86.h"
23#define NEED_XF86_TYPES
24#include "xf86_ansic.h"
25#include "compiler.h"
26#include "cursorstr.h"
27
28#include "vboxvideo.h"
29
30#define VBOX_MAX_CURSOR_WIDTH 64
31#define VBOX_MAX_CURSOR_HEIGHT 64
32
33#if 0
34#define DEBUG_X
35#endif
36#ifdef DEBUG_X
37#define TRACE_ENTRY() for (;;) \
38 { \
39 ErrorF ("%s\n", __FUNCTION__); \
40 break; \
41 }
42#define PUT_PIXEL(c) ErrorF ("%c", c)
43#define dolog(...) ErrorF (__VA_ARGS__)
44#else
45#define PUT_PIXEL(c) (void) c
46#define TRACE_ENTRY() (void) 0
47#define dolog(...)
48#endif
49
50/** Macro to printf an error message and return from a function */
51#define RETERROR(scrnIndex, RetVal, ...) \
52 do \
53 { \
54 xf86DrvMsg(scrnIndex, X_ERROR, __VA_ARGS__); \
55 return RetVal; \
56 } \
57 while (0)
58
59#ifdef DEBUG_X
60static void
61vbox_show_shape(unsigned short w, unsigned short h, CARD32 bg, unsigned char *image)
62{
63 size_t x, y;
64 unsigned short pitch;
65 CARD32 *color;
66 unsigned char *mask;
67 size_t sizeMask;
68
69 image += offsetof(VMMDevReqMousePointer, pointerData);
70 mask = image;
71 pitch = (w + 7) / 8;
72 sizeMask = (pitch * h + 3) & ~3;
73 color = (CARD32 *)(image + sizeMask);
74
75 TRACE_ENTRY();
76 for (y = 0; y < h; ++y, mask += pitch, color += w)
77 {
78 for (x = 0; x < w; ++x)
79 {
80 if (mask[x / 8] & (1 << (7 - (x % 8))))
81 ErrorF (" ");
82 else
83 {
84 CARD32 c = color[x];
85 if (c == bg)
86 ErrorF("Y");
87 else
88 ErrorF("X");
89 }
90 }
91 ErrorF("\n");
92 }
93}
94#endif
95
96
97static Bool
98vbox_host_can_hwcursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
99{
100 VMMDevReqMouseStatus req;
101 int rc;
102 int scrnIndex = pScrn->scrnIndex;
103
104 uint32_t fFeatures;
105 NOREF(req);
106 rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
107 if (VBOX_FAILURE(rc))
108 RETERROR(scrnIndex, FALSE,
109 "Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", rc);
110
111 return (fFeatures & VBOXGUEST_MOUSE_HOST_CANNOT_HWPOINTER) ? FALSE : TRUE;
112}
113
114void
115vbox_close(ScrnInfoPtr pScrn, VBOXPtr pVBox)
116{
117 TRACE_ENTRY();
118
119 xfree (pVBox->reqp);
120 pVBox->reqp = NULL;
121
122 VbglR3Term();
123}
124
125/**
126 * Macro to disable VBVA extensions and return, for use when an
127 * unexplained error occurs.
128 */
129#define DISABLE_VBVA_AND_RETURN(pScrn, ...) \
130 do \
131 { \
132 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, __VA_ARGS__); \
133 vboxDisableVbva(pScrn); \
134 pVBox->useVbva = FALSE; \
135 return; \
136 } \
137 while (0)
138
139/**
140 * Callback function called by the X server to tell us about dirty
141 * rectangles in the video buffer.
142 *
143 * @param pScreen pointer to the information structure for the current
144 * screen
145 * @param iRects Number of dirty rectangles to update
146 * @param aRects Array of structures containing the coordinates of the
147 * rectangles
148 */
149static void
150vboxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects)
151{
152 VBVACMDHDR cmdHdr;
153 VBOXPtr pVBox;
154 VBVARECORD *pRecord;
155 VBVAMEMORY *pMem;
156 CARD32 indexRecordNext;
157 CARD32 off32Data;
158 CARD32 off32Free;
159 INT32 i32Diff;
160 CARD32 cbHwBufferAvail;
161 int scrnIndex;
162 int i;
163
164 pVBox = pScrn->driverPrivate;
165 if (pVBox->useVbva == FALSE)
166 return;
167 pMem = pVBox->pVbvaMemory;
168 /* Just return quietly if VBVA is not currently active. */
169 if ((pMem->fu32ModeFlags & VBVA_F_MODE_ENABLED) == 0)
170 return;
171 scrnIndex = pScrn->scrnIndex;
172
173 for (i = 0; i < iRects; i++)
174 {
175 cmdHdr.x = (int16_t)aRects[i].x1;
176 cmdHdr.y = (int16_t)aRects[i].y1;
177 cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
178 cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
179
180 /* Get the active record and move the pointer along */
181 indexRecordNext = (pMem->indexRecordFree + 1) % VBVA_MAX_RECORDS;
182 if (indexRecordNext == pMem->indexRecordFirst)
183 {
184 /* All slots in the records queue are used. */
185 if (VbglR3VideoAccelFlush() < 0)
186 DISABLE_VBVA_AND_RETURN(pScrn,
187 "Unable to clear the VirtualBox graphics acceleration queue "
188 "- the request to the virtual machine failed. Switching to "
189 "unaccelerated mode.\n");
190 }
191 if (indexRecordNext == pMem->indexRecordFirst)
192 DISABLE_VBVA_AND_RETURN(pScrn,
193 "Failed to clear the VirtualBox graphics acceleration queue. "
194 "Switching to unaccelerated mode.\n");
195 pRecord = &pMem->aRecords[pMem->indexRecordFree];
196 /* Mark the record as being updated. */
197 pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
198 pMem->indexRecordFree = indexRecordNext;
199 /* Compute how many bytes we have in the ring buffer. */
200 off32Free = pMem->off32Free;
201 off32Data = pMem->off32Data;
202 /* Free is writing position. Data is reading position.
203 * Data == Free means buffer is free.
204 * There must be always gap between free and data when data
205 * are in the buffer.
206 * Guest only changes free, host only changes data.
207 */
208 i32Diff = off32Data - off32Free;
209 cbHwBufferAvail = i32Diff > 0 ? i32Diff : VBVA_RING_BUFFER_SIZE + i32Diff;
210 if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
211 {
212 if (VbglR3VideoAccelFlush() < 0)
213 DISABLE_VBVA_AND_RETURN(pScrn,
214 "Unable to clear the VirtualBox graphics acceleration queue "
215 "- the request to the virtual machine failed. Switching to "
216 "unaccelerated mode.\n");
217 /* Calculate the free space again. */
218 off32Free = pMem->off32Free;
219 off32Data = pMem->off32Data;
220 i32Diff = off32Data - off32Free;
221 cbHwBufferAvail = i32Diff > 0? i32Diff:
222 VBVA_RING_BUFFER_SIZE + i32Diff;
223 if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
224 DISABLE_VBVA_AND_RETURN(pScrn,
225 "No space left in the VirtualBox graphics acceleration command buffer, "
226 "despite clearing the queue. Switching to unaccelerated mode.\n");
227 }
228 /* Now copy the data into the buffer */
229 if (off32Free + sizeof(cmdHdr) < VBVA_RING_BUFFER_SIZE)
230 {
231 memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr, sizeof(cmdHdr));
232 pMem->off32Free = pMem->off32Free + sizeof(cmdHdr);
233 }
234 else
235 {
236 CARD32 u32First = VBVA_RING_BUFFER_SIZE - off32Free;
237 /* The following is impressively ugly! */
238 CARD8 *pu8Second = (CARD8 *)&cmdHdr + u32First;
239 CARD32 u32Second = sizeof(cmdHdr) - u32First;
240 memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr, u32First);
241 if (u32Second)
242 memcpy(&pMem->au8RingBuffer[0], pu8Second, u32Second);
243 pMem->off32Free = u32Second;
244 }
245 pRecord->cbRecord += sizeof(cmdHdr);
246 /* Mark the record completed. */
247 pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
248 }
249}
250
251
252/**
253 * Initialise VirtualBox's accelerated video extensions.
254 * Note that we assume that the PCI memory is 32bit mapped,
255 * as X doesn't seem to support mapping 64bit memory.
256 *
257 * @returns TRUE on success, FALSE on failure
258 */
259static Bool
260vboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
261{
262 PCITAG pciTag;
263 ADDRESS pciAddress;
264
265 /* Locate the device. It should already have been enabled by
266 the kernel driver. */
267 pciTag = pciFindFirst((unsigned) VMMDEV_DEVICEID << 16 | VMMDEV_VENDORID,
268 (CARD32) ~0);
269 if (pciTag == PCI_NOT_FOUND)
270 {
271 xf86DrvMsg(scrnIndex, X_ERROR,
272 "Could not find the VirtualBox base device on the PCI bus.\n");
273 return FALSE;
274 }
275 /* Read the address and size of the second I/O region. */
276 pciAddress = pciReadLong(pciTag, PCI_MAP_REG_START + 4);
277 if (pciAddress == 0 || pciAddress == (CARD32) ~0)
278 RETERROR(scrnIndex, FALSE,
279 "The VirtualBox base device contains an invalid memory address.\n");
280 if (PCI_MAP_IS64BITMEM(pciAddress))
281 RETERROR(scrnIndex, FALSE,
282 "The VirtualBox base device has a 64bit mapping address. "
283 "This is currently not supported.\n");
284 /* Map it. We hardcode the size as X does not export the
285 function needed to determine it. */
286 pVBox->pVMMDevMemory = xf86MapPciMem(scrnIndex, 0, pciTag, pciAddress,
287 sizeof(VMMDevMemory));
288 if (pVBox->pVMMDevMemory == NULL)
289 {
290 xf86DrvMsg(scrnIndex, X_ERROR,
291 "Failed to map VirtualBox video extension memory.\n");
292 return FALSE;
293 }
294 pVBox->pVbvaMemory = &pVBox->pVMMDevMemory->vbvaMemory;
295 /* Set up the dirty rectangle handler. Since this seems to be a
296 delicate operation, and removing it doubly so, this will
297 remain in place whether it is needed or not, and will simply
298 return if VBVA is not active. I assume that it will be active
299 most of the time. */
300 if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
301 {
302 xf86DrvMsg(scrnIndex, X_ERROR,
303 "Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
304 return FALSE;
305 }
306 return TRUE;
307}
308
309Bool
310vbox_open(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
311{
312 int rc;
313 void *p;
314 size_t size;
315 int scrnIndex = pScrn->scrnIndex;
316
317 TRACE_ENTRY();
318
319 pVBox->useVbva = FALSE;
320
321 if (pVBox->reqp)
322 {
323 /* still open, just re-enable VBVA after CloseScreen was called */
324 pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
325 return TRUE;
326 }
327
328 rc = VbglR3Init();
329 if (RT_FAILURE(rc))
330 {
331 xf86DrvMsg(scrnIndex, X_ERROR, "VbglR3Init failed rc=%d.\n", rc);
332 return FALSE;
333 }
334
335 size = vmmdevGetRequestSize(VMMDevReq_SetPointerShape);
336 p = xcalloc(1, size);
337 if (p)
338 {
339 rc = vmmdevInitRequest(p, VMMDevReq_SetPointerShape);
340 if (RT_SUCCESS(rc))
341 {
342 pVBox->reqp = p;
343 pVBox->pCurs = NULL;
344 pVBox->useHwCursor = vbox_host_can_hwcursor(pScrn, pVBox);
345 pVBox->pointerHeaderSize = size;
346 pVBox->pointerOffscreen = FALSE;
347 pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
348 return TRUE;
349 }
350 xf86DrvMsg(scrnIndex, X_ERROR, "Could not init VMM request: rc = %d\n", rc);
351 xfree(p);
352 }
353 xf86DrvMsg(scrnIndex, X_ERROR, "Could not allocate %lu bytes for VMM request\n", (unsigned long)size);
354 VbglR3Term();
355 return FALSE;
356}
357
358static void
359vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
360{
361 int rc;
362 pVBox->reqp->fFlags = 0;
363 rc = VbglR3SetPointerShapeReq(pVBox->reqp);
364 if (RT_FAILURE(rc))
365 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not hide the virtual mouse pointer.\n");
366}
367
368static void
369vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
370{
371 int rc;
372 pVBox->reqp->fFlags = VBOX_MOUSE_POINTER_VISIBLE;
373 rc = VbglR3SetPointerShapeReq(pVBox->reqp);
374 if (RT_FAILURE(rc))
375 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
376}
377
378static void
379vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
380 unsigned char *image)
381{
382 int rc;
383 VMMDevReqMousePointer *reqp;
384 reqp = (VMMDevReqMousePointer *)image;
385
386 dolog("w=%d h=%d size=%d\n", reqp->width, reqp->height, reqp->header.size);
387#ifdef DEBUG_X
388 vbox_show_shape(reqp->width, reqp->height, 0, image);
389#endif
390
391 rc = VbglR3SetPointerShapeReq(reqp);
392 if (RT_FAILURE(rc))
393 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to set the virtual mouse pointer image.\n");
394}
395
396static void
397vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
398{
399 TRACE_ENTRY();
400
401 NOREF(pScrn);
402 NOREF(bg);
403 NOREF(fg);
404 /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
405}
406
407static void
408vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
409{
410 /* VBOXPtr pVBox = pScrn->driverPrivate; */
411
412 /* TRACE_ENTRY(); */
413
414 /* don't disable the mouse cursor if we go out of our visible area
415 * since the mouse cursor is drawn by the host anyway */
416#if 0
417 if ( (x < 0 || x > pScrn->pScreen->width)
418 || (y < 0 || y > pScrn->pScreen->height))
419 {
420 if (!pVBox->pointerOffscreen)
421 {
422 pVBox->pointerOffscreen = TRUE;
423 vbox_vmm_hide_cursor(pScrn, pVBox);
424 }
425 }
426 else
427 {
428 if (pVBox->pointerOffscreen)
429 {
430 pVBox->pointerOffscreen = FALSE;
431 vbox_vmm_show_cursor(pScrn, pVBox);
432 }
433 }
434#endif
435}
436
437static void
438vbox_hide_cursor(ScrnInfoPtr pScrn)
439{
440 VBOXPtr pVBox = pScrn->driverPrivate;
441
442 TRACE_ENTRY();
443
444 vbox_vmm_hide_cursor(pScrn, pVBox);
445}
446
447static void
448vbox_show_cursor(ScrnInfoPtr pScrn)
449{
450 VBOXPtr pVBox = pScrn->driverPrivate;
451
452 TRACE_ENTRY();
453
454 vbox_vmm_show_cursor(pScrn, pVBox);
455}
456
457static void
458vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
459{
460 VBOXPtr pVBox = pScrn->driverPrivate;
461
462 TRACE_ENTRY();
463
464 vbox_vmm_load_cursor_image(pScrn, pVBox, image);
465}
466
467static Bool
468vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
469{
470 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
471 VBOXPtr pVBox = pScrn->driverPrivate;
472 return pVBox->useHwCursor;
473}
474
475static unsigned char
476color_to_byte(unsigned c)
477{
478 return (c >> 8) & 0xff;
479}
480
481static unsigned char *
482vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
483{
484 VBOXPtr pVBox;
485 CursorBitsPtr bitsp;
486 unsigned short w, h, x, y;
487 unsigned char *c, *p, *pm, *ps, *m;
488 size_t sizeRequest, sizeRgba, sizeMask, srcPitch, dstPitch;
489 CARD32 fc, bc, *cp;
490 int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
491 VMMDevReqMousePointer *reqp;
492
493 pVBox = infoPtr->pScrn->driverPrivate;
494 bitsp = pCurs->bits;
495 w = bitsp->width;
496 h = bitsp->height;
497
498 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
499 RETERROR(scrnIndex, NULL,
500 "Error invalid cursor dimensions %dx%d\n", w, h);
501
502 if ((bitsp->xhot > w) || (bitsp->yhot > h))
503 RETERROR(scrnIndex, NULL,
504 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
505 bitsp->xhot, bitsp->yhot, w, h);
506
507 srcPitch = PixmapBytePad (bitsp->width, 1);
508 dstPitch = (w + 7) / 8;
509 sizeMask = ((dstPitch * h) + 3) & (size_t) ~3;
510 sizeRgba = w * h * 4;
511 pVBox->pointerSize = sizeMask + sizeRgba;
512 sizeRequest = pVBox->pointerSize + pVBox->pointerHeaderSize;
513
514 p = c = xcalloc (1, sizeRequest);
515 if (!c)
516 RETERROR(scrnIndex, NULL,
517 "Error failed to alloc %lu bytes for cursor\n",
518 (unsigned long) sizeRequest);
519
520 rc = vmmdevInitRequest((VMMDevRequestHeader *)p, VMMDevReq_SetPointerShape);
521 if (VBOX_FAILURE(rc))
522 {
523 xf86DrvMsg(scrnIndex, X_ERROR, "Could not init VMM request: rc = %d\n", rc);
524 xfree(p);
525 return NULL;
526 }
527
528 m = p + offsetof(VMMDevReqMousePointer, pointerData);
529 cp = (CARD32 *)(m + sizeMask);
530
531 dolog ("w=%d h=%d sm=%d sr=%d p=%d\n",
532 w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
533 dolog ("m=%p c=%p cp=%p\n", m, c, cp);
534
535 fc = color_to_byte (pCurs->foreBlue)
536 | (color_to_byte (pCurs->foreGreen) << 8)
537 | (color_to_byte (pCurs->foreRed) << 16);
538
539 bc = color_to_byte (pCurs->backBlue)
540 | (color_to_byte (pCurs->backGreen) << 8)
541 | (color_to_byte (pCurs->backRed) << 16);
542
543 /*
544 * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
545 * Xorg:
546 * The mask is a bitmap indicating which parts of the cursor are
547 * transparent and which parts are drawn. The source is a bitmap
548 * indicating which parts of the non-transparent portion of the
549 * the cursor should be painted in the foreground color and which
550 * should be painted in the background color. By default, set bits
551 * indicate the opaque part of the mask bitmap and clear bits
552 * indicate the transparent part.
553 * VBox:
554 * The color data is the XOR mask. The AND mask bits determine
555 * which pixels of the color data (XOR mask) will replace (overwrite)
556 * the screen pixels (AND mask bit = 0) and which ones will be XORed
557 * with existing screen pixels (AND mask bit = 1).
558 * For example when you have the AND mask all 0, then you see the
559 * correct mouse pointer image surrounded by black square.
560 */
561 for (pm = bitsp->mask, ps = bitsp->source, y = 0;
562 y < h;
563 ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
564 {
565 for (x = 0; x < w; ++x)
566 {
567 if (pm[x / 8] & (1 << (x % 8)))
568 {
569 /* opaque, leave AND mask bit at 0 */
570 if (ps[x / 8] & (1 << (x % 8)))
571 {
572 *cp++ = fc;
573 PUT_PIXEL('X');
574 }
575 else
576 {
577 *cp++ = bc;
578 PUT_PIXEL('*');
579 }
580 }
581 else
582 {
583 /* transparent, set AND mask bit */
584 m[x / 8] |= 1 << (7 - (x % 8));
585 /* don't change the screen pixel */
586 *cp++ = 0;
587 PUT_PIXEL(' ');
588 }
589 }
590 PUT_PIXEL('\n');
591 }
592
593 reqp = (VMMDevReqMousePointer *)p;
594 reqp->width = w;
595 reqp->height = h;
596 reqp->xHot = bitsp->xhot;
597 reqp->yHot = bitsp->yhot;
598 reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE;
599 reqp->header.size = sizeRequest;
600
601#ifdef DEBUG_X
602 ErrorF("shape = %p\n", p);
603 vbox_show_shape(w, h, bc, c);
604#endif
605
606 return p;
607}
608
609#ifdef ARGB_CURSOR
610static Bool
611vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
612{
613 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
614 return pCurs->bits->height <= VBOX_MAX_CURSOR_HEIGHT
615 && pCurs->bits->width <= VBOX_MAX_CURSOR_WIDTH
616 && pScrn->bitsPerPixel > 8;
617}
618
619static void
620vbox_load_cursor_argb(ScrnInfoPtr pScrn, CursorPtr pCurs)
621{
622 VBOXPtr pVBox;
623 VMMDevReqMousePointer *reqp;
624 CursorBitsPtr bitsp;
625 unsigned short w, h;
626 unsigned short cx, cy;
627 unsigned char *pm;
628 CARD32 *pc;
629 size_t sizeRequest, sizeMask;
630 CARD8 *p;
631 int scrnIndex;
632
633 pVBox = pScrn->driverPrivate;
634 bitsp = pCurs->bits;
635 w = bitsp->width;
636 h = bitsp->height;
637 scrnIndex = pScrn->scrnIndex;
638
639 /* Mask must be generated for alpha cursors, that is required by VBox. */
640 /* note: (michael) the next struct must be 32bit aligned. */
641 sizeMask = ((w + 7) / 8 * h + 3) & ~3;
642
643 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
644 RETERROR(scrnIndex, ,
645 "Error invalid cursor dimensions %dx%d\n", w, h);
646
647 if ((bitsp->xhot > w) || (bitsp->yhot > h))
648 RETERROR(scrnIndex, ,
649 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
650 bitsp->xhot, bitsp->yhot, w, h);
651
652 pVBox->pointerSize = w * h * 4 + sizeMask;
653 sizeRequest = pVBox->pointerSize + pVBox->pointerHeaderSize;
654 p = xcalloc(1, sizeRequest);
655 if (!p)
656 RETERROR(scrnIndex, ,
657 "Error failed to alloc %lu bytes for cursor\n",
658 (unsigned long)sizeRequest);
659
660 reqp = (VMMDevReqMousePointer *)p;
661 *reqp = *pVBox->reqp;
662 reqp->width = w;
663 reqp->height = h;
664 reqp->xHot = bitsp->xhot;
665 reqp->yHot = bitsp->yhot;
666 reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA;
667 reqp->header.size = sizeRequest;
668
669 memcpy(p + offsetof(VMMDevReqMousePointer, pointerData) + sizeMask, bitsp->argb, w * h * 4);
670
671 /* Emulate the AND mask. */
672 pm = p + offsetof(VMMDevReqMousePointer, pointerData);
673 pc = bitsp->argb;
674
675 /* Init AND mask to 1 */
676 memset(pm, 0xFF, sizeMask);
677
678 /*
679 * The additions driver must provide the AND mask for alpha cursors. The host frontend
680 * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
681 * But if the host does not support ARGB, then it simply uses the AND mask and the color
682 * data to draw a normal color cursor.
683 */
684 for (cy = 0; cy < h; cy++)
685 {
686 unsigned char bitmask = 0x80;
687
688 for (cx = 0; cx < w; cx++, bitmask >>= 1)
689 {
690 if (bitmask == 0)
691 bitmask = 0x80;
692
693 if (pc[cx] >= 0xF0000000)
694 pm[cx / 8] &= ~bitmask;
695 }
696
697 /* Point to next source and dest scans */
698 pc += w;
699 pm += (w + 7) / 8;
700 }
701
702 VbglR3SetPointerShapeReq(reqp);
703 xfree(p);
704}
705#endif
706
707Bool
708vbox_cursor_init(ScreenPtr pScreen)
709{
710 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
711 VBOXPtr pVBox = pScrn->driverPrivate;
712 xf86CursorInfoPtr pCurs;
713 Bool rc;
714
715 if (pVBox->useHwCursor)
716 {
717 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
718 "The host system is drawing the mouse cursor.\n");
719 }
720 else
721 {
722 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
723 "The guest system is drawing the mouse cursor.\n");
724 return TRUE;
725 }
726
727 pVBox->pCurs = pCurs = xf86CreateCursorInfoRec();
728 if (!pCurs)
729 RETERROR(pScrn->scrnIndex, FALSE,
730 "Failed to create X Window cursor information structures for virtual mouse.\n");
731
732 pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
733 pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
734 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
735 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
736 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
737
738 pCurs->SetCursorColors = vbox_set_cursor_colors;
739 pCurs->SetCursorPosition = vbox_set_cursor_position;
740 pCurs->LoadCursorImage = vbox_load_cursor_image;
741 pCurs->HideCursor = vbox_hide_cursor;
742 pCurs->ShowCursor = vbox_show_cursor;
743 pCurs->UseHWCursor = vbox_use_hw_cursor;
744 pCurs->RealizeCursor = vbox_realize_cursor;
745
746#ifdef ARGB_CURSOR
747 pCurs->UseHWCursorARGB = vbox_use_hw_cursor_argb;
748 pCurs->LoadCursorARGB = vbox_load_cursor_argb;
749#endif
750
751 rc = xf86InitCursor(pScreen, pCurs);
752 if (rc == TRUE)
753 return TRUE;
754 RETERROR(pScrn->scrnIndex, FALSE, "Failed to enable mouse pointer integration.\n");
755}
756
757/**
758 * Inform VBox that we will supply it with dirty rectangle information
759 * and install the dirty rectangle handler.
760 *
761 * @returns TRUE for success, FALSE for failure
762 * @param pScrn Pointer to a structure describing the X screen in use
763 */
764Bool
765vboxEnableVbva(ScrnInfoPtr pScrn)
766{
767 int rc;
768 int scrnIndex = pScrn->scrnIndex;
769 VBOXPtr pVBox = pScrn->driverPrivate;
770
771 if (pVBox->useVbva != TRUE)
772 return FALSE;
773 rc = VbglR3VideoAccelEnable(true);
774 if (RT_FAILURE(rc))
775 {
776 /* Request not accepted - disable for old hosts. */
777 xf86DrvMsg(scrnIndex, X_ERROR,
778 "Unable to activate VirtualBox graphics acceleration "
779 "- the request to the virtual machine failed. "
780 "You may be running an old version of VirtualBox.\n");
781 pVBox->useVbva = FALSE;
782 VbglR3VideoAccelEnable(false);
783 return FALSE;
784 }
785 return TRUE;
786}
787
788/**
789 * Inform VBox that we will stop supplying it with dirty rectangle
790 * information. This function is intended to be called when an X
791 * virtual terminal is disabled, or the X server is terminated.
792 *
793 * @returns TRUE for success, FALSE for failure
794 * @param pScrn Pointer to a structure describing the X screen in use
795 */
796Bool
797vboxDisableVbva(ScrnInfoPtr pScrn)
798{
799 int rc;
800 int scrnIndex = pScrn->scrnIndex;
801 VBOXPtr pVBox = pScrn->driverPrivate;
802
803 if (pVBox->useVbva != TRUE) /* Ths function should not have been called */
804 return FALSE;
805 rc = VbglR3VideoAccelEnable(false);
806 if (RT_FAILURE(rc))
807 {
808 xf86DrvMsg(scrnIndex, X_ERROR,
809 "Unable to disable VirtualBox graphics acceleration "
810 "- the request to the virtual machine failed.\n");
811 }
812 else
813 memset(pVBox->pVbvaMemory, 0, sizeof(VBVAMEMORY));
814 return TRUE;
815}
816
817/**
818 * Query the last display change request.
819 *
820 * @returns boolean success indicator.
821 * @param pScrn Pointer to the X screen info structure.
822 * @param pcx Where to store the horizontal pixel resolution (0 = do not change).
823 * @param pcy Where to store the vertical pixel resolution (0 = do not change).
824 * @param pcBits Where to store the bits per pixel (0 = do not change).
825 * @param fEventAck Flag that the request is an acknowlegement for the
826 * VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST.
827 * Values:
828 * 0 - just querying,
829 * VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST - event acknowledged.
830 * @param iDisplay 0 for primary display, 1 for the first secondary, etc.
831 */
832Bool
833vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy,
834 uint32_t *pcBits, uint32_t fEventAck, uint32_t iDisplay)
835{
836 int rc = VbglR3GetDisplayChangeRequest(pcx, pcy, pcBits, fEventAck, iDisplay);
837 if (RT_SUCCESS(rc))
838 return TRUE;
839 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to request the last resolution requested from the guest, rc=%d.\n", rc);
840 return FALSE;
841}
842
843/* Make our C++ libraries happy. */
844/** @todo r=bird: This can be eliminated by -fno-exceptions. We just need to fix
845 * the templates... */
846extern int __gxx_personality_v0;
847int __gxx_personality_v0 = 0xdeadbeef;
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette