VirtualBox

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

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

Additions/X11, Additions/common: report the maximum supported resolution in the X11 additions

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