VirtualBox

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

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

Additions/x11: set the graphics capability correctly for X.org 1.3 and 1.4

  • Property svn:eol-style set to native
File size: 26.2 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)
318{
319 Bool rc = TRUE;
320 int vrc = VbglR3Init();
321 if (RT_FAILURE(vrc))
322 {
323 xf86DrvMsg(scrnIndex, X_ERROR, "VbglR3Init failed rc=%d.\n", rc);
324 rc = FALSE;
325 }
326 return rc;
327}
328
329Bool
330vbox_open(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
331{
332 int rc;
333 void *p;
334 size_t size;
335 int scrnIndex = pScrn->scrnIndex;
336
337 TRACE_ENTRY();
338
339 pVBox->useVbva = FALSE;
340
341 if (pVBox->reqp)
342 {
343 /* still open, just re-enable VBVA after CloseScreen was called */
344 pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
345 return TRUE;
346 }
347
348 size = vmmdevGetRequestSize(VMMDevReq_SetPointerShape);
349 p = xcalloc(1, size);
350 if (p)
351 {
352 rc = vmmdevInitRequest(p, VMMDevReq_SetPointerShape);
353 if (RT_SUCCESS(rc))
354 {
355 pVBox->reqp = p;
356 pVBox->pCurs = NULL;
357 pVBox->pointerHeaderSize = size;
358 pVBox->pointerOffscreen = FALSE;
359 pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
360 return TRUE;
361 }
362 xf86DrvMsg(scrnIndex, X_ERROR, "Could not init VMM request: rc = %d\n", rc);
363 xfree(p);
364 }
365 xf86DrvMsg(scrnIndex, X_ERROR, "Could not allocate %lu bytes for VMM request\n", (unsigned long)size);
366 return FALSE;
367}
368
369static void
370vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
371{
372 int rc;
373 pVBox->reqp->fFlags = 0;
374 rc = VbglR3SetPointerShapeReq(pVBox->reqp);
375 if (RT_FAILURE(rc))
376 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not hide the virtual mouse pointer.\n");
377}
378
379static void
380vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
381{
382 int rc;
383 pVBox->reqp->fFlags = VBOX_MOUSE_POINTER_VISIBLE;
384 rc = VbglR3SetPointerShapeReq(pVBox->reqp);
385 if (RT_FAILURE(rc))
386 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
387}
388
389static void
390vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
391 unsigned char *image)
392{
393 int rc;
394 VMMDevReqMousePointer *reqp;
395 reqp = (VMMDevReqMousePointer *)image;
396
397 dolog("w=%d h=%d size=%d\n", reqp->width, reqp->height, reqp->header.size);
398#ifdef DEBUG_X
399 vbox_show_shape(reqp->width, reqp->height, 0, image);
400#endif
401
402 rc = VbglR3SetPointerShapeReq(reqp);
403 if (RT_FAILURE(rc))
404 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to set the virtual mouse pointer image.\n");
405}
406
407static void
408vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
409{
410 TRACE_ENTRY();
411
412 NOREF(pScrn);
413 NOREF(bg);
414 NOREF(fg);
415 /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
416}
417
418static void
419vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
420{
421 /* VBOXPtr pVBox = pScrn->driverPrivate; */
422
423 /* TRACE_ENTRY(); */
424
425 /* don't disable the mouse cursor if we go out of our visible area
426 * since the mouse cursor is drawn by the host anyway */
427#if 0
428 if ( (x < 0 || x > pScrn->pScreen->width)
429 || (y < 0 || y > pScrn->pScreen->height))
430 {
431 if (!pVBox->pointerOffscreen)
432 {
433 pVBox->pointerOffscreen = TRUE;
434 vbox_vmm_hide_cursor(pScrn, pVBox);
435 }
436 }
437 else
438 {
439 if (pVBox->pointerOffscreen)
440 {
441 pVBox->pointerOffscreen = FALSE;
442 vbox_vmm_show_cursor(pScrn, pVBox);
443 }
444 }
445#endif
446}
447
448static void
449vbox_hide_cursor(ScrnInfoPtr pScrn)
450{
451 VBOXPtr pVBox = pScrn->driverPrivate;
452
453 TRACE_ENTRY();
454
455 vbox_vmm_hide_cursor(pScrn, pVBox);
456}
457
458static void
459vbox_show_cursor(ScrnInfoPtr pScrn)
460{
461 VBOXPtr pVBox = pScrn->driverPrivate;
462
463 TRACE_ENTRY();
464
465 vbox_vmm_show_cursor(pScrn, pVBox);
466}
467
468static void
469vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
470{
471 VBOXPtr pVBox = pScrn->driverPrivate;
472
473 TRACE_ENTRY();
474
475 vbox_vmm_load_cursor_image(pScrn, pVBox, image);
476}
477
478static Bool
479vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
480{
481 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
482 return vbox_host_uses_hwcursor(pScrn);
483}
484
485static unsigned char
486color_to_byte(unsigned c)
487{
488 return (c >> 8) & 0xff;
489}
490
491static unsigned char *
492vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
493{
494 VBOXPtr pVBox;
495 CursorBitsPtr bitsp;
496 unsigned short w, h, x, y;
497 unsigned char *c, *p, *pm, *ps, *m;
498 size_t sizeRequest, sizeRgba, sizeMask, srcPitch, dstPitch;
499 CARD32 fc, bc, *cp;
500 int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
501 VMMDevReqMousePointer *reqp;
502
503 pVBox = infoPtr->pScrn->driverPrivate;
504 bitsp = pCurs->bits;
505 w = bitsp->width;
506 h = bitsp->height;
507
508 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
509 RETERROR(scrnIndex, NULL,
510 "Error invalid cursor dimensions %dx%d\n", w, h);
511
512 if ((bitsp->xhot > w) || (bitsp->yhot > h))
513 RETERROR(scrnIndex, NULL,
514 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
515 bitsp->xhot, bitsp->yhot, w, h);
516
517 srcPitch = PixmapBytePad (bitsp->width, 1);
518 dstPitch = (w + 7) / 8;
519 sizeMask = ((dstPitch * h) + 3) & (size_t) ~3;
520 sizeRgba = w * h * 4;
521 pVBox->pointerSize = sizeMask + sizeRgba;
522 sizeRequest = pVBox->pointerSize + pVBox->pointerHeaderSize;
523
524 p = c = xcalloc (1, sizeRequest);
525 if (!c)
526 RETERROR(scrnIndex, NULL,
527 "Error failed to alloc %lu bytes for cursor\n",
528 (unsigned long) sizeRequest);
529
530 rc = vmmdevInitRequest((VMMDevRequestHeader *)p, VMMDevReq_SetPointerShape);
531 if (VBOX_FAILURE(rc))
532 {
533 xf86DrvMsg(scrnIndex, X_ERROR, "Could not init VMM request: rc = %d\n", rc);
534 xfree(p);
535 return NULL;
536 }
537
538 m = p + offsetof(VMMDevReqMousePointer, pointerData);
539 cp = (CARD32 *)(m + sizeMask);
540
541 dolog ("w=%d h=%d sm=%d sr=%d p=%d\n",
542 w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
543 dolog ("m=%p c=%p cp=%p\n", m, c, (void *)cp);
544
545 fc = color_to_byte (pCurs->foreBlue)
546 | (color_to_byte (pCurs->foreGreen) << 8)
547 | (color_to_byte (pCurs->foreRed) << 16);
548
549 bc = color_to_byte (pCurs->backBlue)
550 | (color_to_byte (pCurs->backGreen) << 8)
551 | (color_to_byte (pCurs->backRed) << 16);
552
553 /*
554 * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
555 * Xorg:
556 * The mask is a bitmap indicating which parts of the cursor are
557 * transparent and which parts are drawn. The source is a bitmap
558 * indicating which parts of the non-transparent portion of the
559 * the cursor should be painted in the foreground color and which
560 * should be painted in the background color. By default, set bits
561 * indicate the opaque part of the mask bitmap and clear bits
562 * indicate the transparent part.
563 * VBox:
564 * The color data is the XOR mask. The AND mask bits determine
565 * which pixels of the color data (XOR mask) will replace (overwrite)
566 * the screen pixels (AND mask bit = 0) and which ones will be XORed
567 * with existing screen pixels (AND mask bit = 1).
568 * For example when you have the AND mask all 0, then you see the
569 * correct mouse pointer image surrounded by black square.
570 */
571 for (pm = bitsp->mask, ps = bitsp->source, y = 0;
572 y < h;
573 ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
574 {
575 for (x = 0; x < w; ++x)
576 {
577 if (pm[x / 8] & (1 << (x % 8)))
578 {
579 /* opaque, leave AND mask bit at 0 */
580 if (ps[x / 8] & (1 << (x % 8)))
581 {
582 *cp++ = fc;
583 PUT_PIXEL('X');
584 }
585 else
586 {
587 *cp++ = bc;
588 PUT_PIXEL('*');
589 }
590 }
591 else
592 {
593 /* transparent, set AND mask bit */
594 m[x / 8] |= 1 << (7 - (x % 8));
595 /* don't change the screen pixel */
596 *cp++ = 0;
597 PUT_PIXEL(' ');
598 }
599 }
600 PUT_PIXEL('\n');
601 }
602
603 reqp = (VMMDevReqMousePointer *)p;
604 reqp->width = w;
605 reqp->height = h;
606 reqp->xHot = bitsp->xhot;
607 reqp->yHot = bitsp->yhot;
608 reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE;
609 reqp->header.size = sizeRequest;
610
611#ifdef DEBUG_X
612 ErrorF("shape = %p\n", p);
613 vbox_show_shape(w, h, bc, c);
614#endif
615
616 return p;
617}
618
619#ifdef ARGB_CURSOR
620static Bool
621vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
622{
623 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
624 Bool rc = TRUE;
625
626 if (!vbox_host_uses_hwcursor(pScrn))
627 rc = FALSE;
628 if ( rc
629 && ( (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
630 || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
631 || (pScrn->bitsPerPixel <= 8)
632 )
633 )
634 rc = FALSE;
635 return rc;
636}
637
638
639static void
640vbox_load_cursor_argb(ScrnInfoPtr pScrn, CursorPtr pCurs)
641{
642 VBOXPtr pVBox;
643 VMMDevReqMousePointer *reqp;
644 CursorBitsPtr bitsp;
645 unsigned short w, h;
646 unsigned short cx, cy;
647 unsigned char *pm;
648 CARD32 *pc;
649 size_t sizeRequest, sizeMask;
650 CARD8 *p;
651 int scrnIndex;
652
653 pVBox = pScrn->driverPrivate;
654 bitsp = pCurs->bits;
655 w = bitsp->width;
656 h = bitsp->height;
657 scrnIndex = pScrn->scrnIndex;
658
659 /* Mask must be generated for alpha cursors, that is required by VBox. */
660 /* note: (michael) the next struct must be 32bit aligned. */
661 sizeMask = ((w + 7) / 8 * h + 3) & ~3;
662
663 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
664 RETERROR(scrnIndex, ,
665 "Error invalid cursor dimensions %dx%d\n", w, h);
666
667 if ((bitsp->xhot > w) || (bitsp->yhot > h))
668 RETERROR(scrnIndex, ,
669 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
670 bitsp->xhot, bitsp->yhot, w, h);
671
672 pVBox->pointerSize = w * h * 4 + sizeMask;
673 sizeRequest = pVBox->pointerSize + pVBox->pointerHeaderSize;
674 p = xcalloc(1, sizeRequest);
675 if (!p)
676 RETERROR(scrnIndex, ,
677 "Error failed to alloc %lu bytes for cursor\n",
678 (unsigned long)sizeRequest);
679
680 reqp = (VMMDevReqMousePointer *)p;
681 *reqp = *pVBox->reqp;
682 reqp->width = w;
683 reqp->height = h;
684 reqp->xHot = bitsp->xhot;
685 reqp->yHot = bitsp->yhot;
686 reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA;
687 reqp->header.size = sizeRequest;
688
689 memcpy(p + offsetof(VMMDevReqMousePointer, pointerData) + sizeMask, bitsp->argb, w * h * 4);
690
691 /* Emulate the AND mask. */
692 pm = p + offsetof(VMMDevReqMousePointer, pointerData);
693 pc = bitsp->argb;
694
695 /* Init AND mask to 1 */
696 memset(pm, 0xFF, sizeMask);
697
698 /*
699 * The additions driver must provide the AND mask for alpha cursors. The host frontend
700 * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
701 * But if the host does not support ARGB, then it simply uses the AND mask and the color
702 * data to draw a normal color cursor.
703 */
704 for (cy = 0; cy < h; cy++)
705 {
706 unsigned char bitmask = 0x80;
707
708 for (cx = 0; cx < w; cx++, bitmask >>= 1)
709 {
710 if (bitmask == 0)
711 bitmask = 0x80;
712
713 if (pc[cx] >= 0xF0000000)
714 pm[cx / 8] &= ~bitmask;
715 }
716
717 /* Point to next source and dest scans */
718 pc += w;
719 pm += (w + 7) / 8;
720 }
721
722 VbglR3SetPointerShapeReq(reqp);
723 xfree(p);
724}
725#endif
726
727Bool
728vbox_cursor_init(ScreenPtr pScreen)
729{
730 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
731 VBOXPtr pVBox = pScrn->driverPrivate;
732 xf86CursorInfoPtr pCurs;
733 Bool rc;
734
735 pVBox->pCurs = pCurs = xf86CreateCursorInfoRec();
736 if (!pCurs)
737 RETERROR(pScrn->scrnIndex, FALSE,
738 "Failed to create X Window cursor information structures for virtual mouse.\n");
739
740 pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
741 pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
742 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
743 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
744 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
745
746 pCurs->SetCursorColors = vbox_set_cursor_colors;
747 pCurs->SetCursorPosition = vbox_set_cursor_position;
748 pCurs->LoadCursorImage = vbox_load_cursor_image;
749 pCurs->HideCursor = vbox_hide_cursor;
750 pCurs->ShowCursor = vbox_show_cursor;
751 pCurs->UseHWCursor = vbox_use_hw_cursor;
752 pCurs->RealizeCursor = vbox_realize_cursor;
753
754#ifdef ARGB_CURSOR
755 pCurs->UseHWCursorARGB = vbox_use_hw_cursor_argb;
756 pCurs->LoadCursorARGB = vbox_load_cursor_argb;
757#endif
758
759 rc = xf86InitCursor(pScreen, pCurs);
760 if (rc == TRUE)
761 return TRUE;
762 RETERROR(pScrn->scrnIndex, FALSE, "Failed to enable mouse pointer integration.\n");
763}
764
765/**
766 * Inform VBox that we will supply it with dirty rectangle information
767 * and install the dirty rectangle handler.
768 *
769 * @returns TRUE for success, FALSE for failure
770 * @param pScrn Pointer to a structure describing the X screen in use
771 */
772Bool
773vboxEnableVbva(ScrnInfoPtr pScrn)
774{
775 int rc;
776 int scrnIndex = pScrn->scrnIndex;
777 VBOXPtr pVBox = pScrn->driverPrivate;
778
779 if (pVBox->useVbva != TRUE)
780 return FALSE;
781 rc = VbglR3VideoAccelEnable(true);
782 if (RT_FAILURE(rc))
783 {
784 /* Request not accepted - disable for old hosts. */
785 xf86DrvMsg(scrnIndex, X_ERROR,
786 "Unable to activate VirtualBox graphics acceleration "
787 "- the request to the virtual machine failed. "
788 "You may be running an old version of VirtualBox.\n");
789 pVBox->useVbva = FALSE;
790 VbglR3VideoAccelEnable(false);
791 return FALSE;
792 }
793 return TRUE;
794}
795
796/**
797 * Inform VBox that we will stop supplying it with dirty rectangle
798 * information. This function is intended to be called when an X
799 * virtual terminal is disabled, or the X server is terminated.
800 *
801 * @returns TRUE for success, FALSE for failure
802 * @param pScrn Pointer to a structure describing the X screen in use
803 */
804Bool
805vboxDisableVbva(ScrnInfoPtr pScrn)
806{
807 int rc;
808 int scrnIndex = pScrn->scrnIndex;
809 VBOXPtr pVBox = pScrn->driverPrivate;
810
811 if (pVBox->useVbva != TRUE) /* Ths function should not have been called */
812 return FALSE;
813 rc = VbglR3VideoAccelEnable(false);
814 if (RT_FAILURE(rc))
815 {
816 xf86DrvMsg(scrnIndex, X_ERROR,
817 "Unable to disable VirtualBox graphics acceleration "
818 "- the request to the virtual machine failed.\n");
819 }
820 else
821 memset(pVBox->pVbvaMemory, 0, sizeof(VBVAMEMORY));
822 return TRUE;
823}
824
825/**
826 * Inform VBox that we are aware of advanced graphics functions
827 * (i.e. dynamic resizing, seamless).
828 *
829 * @returns TRUE for success, FALSE for failure
830 */
831Bool
832vboxEnableGraphicsCap(void)
833{
834 return RT_SUCCESS(VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0));
835}
836
837/**
838 * Inform VBox that we are no longer aware of advanced graphics functions
839 * (i.e. dynamic resizing, seamless).
840 *
841 * @returns TRUE for success, FALSE for failure
842 */
843Bool
844vboxDisableGraphicsCap(void)
845{
846 return RT_SUCCESS(VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS));
847}
848
849/**
850 * Query the last display change request.
851 *
852 * @returns boolean success indicator.
853 * @param pScrn Pointer to the X screen info structure.
854 * @param pcx Where to store the horizontal pixel resolution (0 = do not change).
855 * @param pcy Where to store the vertical pixel resolution (0 = do not change).
856 * @param pcBits Where to store the bits per pixel (0 = do not change).
857 * @param iDisplay Where to store the display number the request was for - 0 for the
858 * primary display, 1 for the first secondary, etc.
859 */
860Bool
861vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy,
862 uint32_t *pcBits, uint32_t *piDisplay)
863{
864 int rc = VbglR3GetLastDisplayChangeRequest(pcx, pcy, pcBits, piDisplay);
865 if (RT_SUCCESS(rc))
866 return TRUE;
867 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to obtain the last resolution requested by the guest, rc=%d.\n", rc);
868 return FALSE;
869}
870
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