VirtualBox

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

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

Fix for Todo in r27575. added as new function as we cannot use function overloading.

  • Property svn:eol-style set to native
File size: 26.0 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. */
844extern int __gxx_personality_v0;
845int __gxx_personality_v0 = 0xdeadbeef;
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