VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/xgraphics/vboxutils.c@ 424

Last change on this file since 424 was 374, checked in by vboxsync, 18 years ago

Fixed a couple of warnings in the Linux guest graphic driver

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

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