VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/xgraphics/vboxutils.c@ 7443

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

Additions/X11: make the X11 drivers work again when the kernel module fails to load

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