VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/vboxutils.c@ 35267

Last change on this file since 35267 was 35267, checked in by vboxsync, 14 years ago

Additions/x11/vboxvideo: recreate communication structures in guest VRAM after a VT switch, as VRAM contents are undefined at this point

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 41.2 KB
Line 
1/** @file
2 * VirtualBox X11 Additions graphics driver utility functions
3 */
4
5/*
6 * Copyright (C) 2006-2007 Oracle Corporation
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/VMMDev.h>
18#include <VBox/VBoxGuestLib.h>
19
20#ifndef PCIACCESS
21# include <xf86Pci.h>
22# include <Pci.h>
23#endif
24
25#include "xf86.h"
26#define NEED_XF86_TYPES
27#ifdef NO_ANSIC
28# include <string.h>
29#else
30# include "xf86_ansic.h"
31#endif
32#include "compiler.h"
33#include "cursorstr.h"
34
35#include "vboxvideo.h"
36
37#define VBOX_MAX_CURSOR_WIDTH 64
38#define VBOX_MAX_CURSOR_HEIGHT 64
39
40/**************************************************************************
41* Debugging functions and macros *
42**************************************************************************/
43
44/* #define DEBUG_POINTER */
45
46#ifdef DEBUG
47# define PUT_PIXEL(c) ErrorF ("%c", c)
48#else /* DEBUG_VIDEO not defined */
49# define PUT_PIXEL(c) do { } while(0)
50#endif /* DEBUG_VIDEO not defined */
51
52/** Macro to printf an error message and return from a function */
53#define RETERROR(scrnIndex, RetVal, ...) \
54 do \
55 { \
56 xf86DrvMsg(scrnIndex, X_ERROR, __VA_ARGS__); \
57 return RetVal; \
58 } \
59 while (0)
60
61/** Structure to pass cursor image data between realise_cursor() and
62 * load_cursor_image(). The members match the parameters to
63 * @a VBoxHGSMIUpdatePointerShape(). */
64struct vboxCursorImage
65{
66 uint32_t fFlags;
67 uint32_t cHotX;
68 uint32_t cHotY;
69 uint32_t cWidth;
70 uint32_t cHeight;
71 uint8_t *pPixels;
72 uint32_t cbLength;
73};
74
75#ifdef DEBUG_POINTER
76static void
77vbox_show_shape(unsigned short w, unsigned short h, CARD32 bg, unsigned char *image)
78{
79 size_t x, y;
80 unsigned short pitch;
81 CARD32 *color;
82 unsigned char *mask;
83 size_t sizeMask;
84
85 image += sizeof(struct vboxCursorImage);
86 mask = image;
87 pitch = (w + 7) / 8;
88 sizeMask = (pitch * h + 3) & ~3;
89 color = (CARD32 *)(image + sizeMask);
90
91 TRACE_ENTRY();
92 for (y = 0; y < h; ++y, mask += pitch, color += w)
93 {
94 for (x = 0; x < w; ++x)
95 {
96 if (mask[x / 8] & (1 << (7 - (x % 8))))
97 ErrorF (" ");
98 else
99 {
100 CARD32 c = color[x];
101 if (c == bg)
102 ErrorF("Y");
103 else
104 ErrorF("X");
105 }
106 }
107 ErrorF("\n");
108 }
109}
110#endif
111
112/**************************************************************************
113* Helper functions and macros *
114**************************************************************************/
115
116/* This is called by the X server every time it loads a new cursor to see
117 * whether our "cursor hardware" can handle the cursor. This provides us with
118 * a mechanism (the only one!) to switch back from a software to a hardware
119 * cursor. */
120static Bool
121vbox_host_uses_hwcursor(ScrnInfoPtr pScrn)
122{
123 Bool rc = TRUE;
124 uint32_t fFeatures = 0;
125 VBOXPtr pVBox = pScrn->driverPrivate;
126
127 /* We may want to force the use of a software cursor. Currently this is
128 * needed if the guest uses a large virtual resolution, as in this case
129 * the host and guest tend to disagree about the pointer location. */
130 if (pVBox->forceSWCursor)
131 rc = FALSE;
132 /* Query information about mouse integration from the host. */
133 if (rc) {
134 int vrc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
135 if (RT_FAILURE(vrc)) {
136 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
137 "Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", vrc);
138 rc = FALSE;
139 }
140 }
141 /* If we got the information from the host then make sure the host wants
142 * to draw the pointer. */
143 if (rc)
144 {
145 if ( (fFeatures & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
146#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5
147 /* As of this version (server 1.6) all major Linux releases
148 * are known to handle USB tablets correctly. */
149 || (fFeatures & VMMDEV_MOUSE_HOST_HAS_ABS_DEV)
150#endif
151 )
152 /* Assume this will never be unloaded as long as the X session is
153 * running. */
154 pVBox->guestCanAbsolute = TRUE;
155 if ( (fFeatures & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER)
156 || !pVBox->guestCanAbsolute
157 || !(fFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
158 )
159 rc = FALSE;
160 }
161 return rc;
162}
163
164/**************************************************************************
165* Main functions *
166**************************************************************************/
167
168void
169vbox_close(ScrnInfoPtr pScrn, VBOXPtr pVBox)
170{
171 TRACE_ENTRY();
172
173 xf86DestroyCursorInfoRec(pVBox->pCurs);
174 pVBox->pCurs = NULL;
175 TRACE_EXIT();
176}
177
178/**
179 * Callback function called by the X server to tell us about dirty
180 * rectangles in the video buffer.
181 *
182 * @param pScreen pointer to the information structure for the current
183 * screen
184 * @param iRects Number of dirty rectangles to update
185 * @param aRects Array of structures containing the coordinates of the
186 * rectangles
187 */
188static void
189vboxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects)
190{
191 VBVACMDHDR cmdHdr;
192 VBOXPtr pVBox;
193 int i;
194 unsigned j;
195
196 pVBox = pScrn->driverPrivate;
197 if (pVBox->fHaveHGSMI == FALSE || pVBox->vtSwitch)
198 return;
199
200 for (i = 0; i < iRects; ++i)
201 for (j = 0; j < pVBox->cScreens; ++j)
202 {
203 /* Just continue quietly if VBVA is not currently active. */
204 struct VBVABUFFER *pVBVA = pVBox->aVbvaCtx[j].pVBVA;
205 if ( !pVBVA
206 || !(pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
207 continue;
208 if ( aRects[i].x1 > pVBox->aScreenLocation[j].x
209 + pVBox->aScreenLocation[j].cx
210 || aRects[i].y1 > pVBox->aScreenLocation[j].y
211 + pVBox->aScreenLocation[j].cy
212 || aRects[i].x2 < pVBox->aScreenLocation[j].x
213 || aRects[i].y2 < pVBox->aScreenLocation[j].y)
214 continue;
215 cmdHdr.x = (int16_t)aRects[i].x1;
216 cmdHdr.y = (int16_t)aRects[i].y1;
217 cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
218 cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
219
220#if 0
221 TRACE_LOG("display=%u, x=%d, y=%d, w=%d, h=%d\n",
222 j, cmdHdr.x, cmdHdr.y, cmdHdr.w, cmdHdr.h);
223#endif
224
225 if (VBoxVBVABufferBeginUpdate(&pVBox->aVbvaCtx[j],
226 &pVBox->guestCtx))
227 {
228 VBoxVBVAWrite(&pVBox->aVbvaCtx[j], &pVBox->guestCtx, &cmdHdr,
229 sizeof(cmdHdr));
230 VBoxVBVABufferEndUpdate(&pVBox->aVbvaCtx[j]);
231 }
232 }
233}
234
235/** Callback to fill in the view structures */
236static int
237vboxFillViewInfo(void *pvVBox, struct VBVAINFOVIEW *pViews, uint32_t cViews)
238{
239 VBOXPtr pVBox = (VBOXPtr)pvVBox;
240 unsigned i;
241 for (i = 0; i < cViews; ++i)
242 {
243 pViews[i].u32ViewIndex = i;
244 pViews[i].u32ViewOffset = 0;
245 pViews[i].u32ViewSize = pVBox->cbView;
246 pViews[i].u32MaxScreenSize = pVBox->cbFramebuffer;
247 }
248 return VINF_SUCCESS;
249}
250
251/**
252 * Initialise VirtualBox's accelerated video extensions.
253 *
254 * @returns TRUE on success, FALSE on failure
255 */
256static Bool
257vboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
258{
259 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
260 int rc = VINF_SUCCESS;
261
262 pVBox->cScreens = 1;
263 if (!VBoxHGSMIIsSupported())
264 {
265 xf86DrvMsg(scrnIndex, X_ERROR, "The graphics device does not seem to support HGSMI. Disableing video acceleration.\n");
266 return FALSE;
267 }
268
269 /* Set up the dirty rectangle handler. It will be added into a function
270 * chain and gets removed when the screen is cleaned up. */
271 if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
272 {
273 xf86DrvMsg(scrnIndex, X_ERROR,
274 "Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
275 return FALSE;
276 }
277 return TRUE;
278}
279
280/**
281 * Initialise VirtualBox's accelerated video extensions.
282 *
283 * @returns TRUE on success, FALSE on failure
284 */
285static Bool
286vboxSetupVRAMVbva(ScrnInfoPtr pScrn, VBOXPtr pVBox)
287{
288 int rc = VINF_SUCCESS;
289 unsigned i;
290 uint32_t offVRAMBaseMapping, offGuestHeapMemory, cbGuestHeapMemory;
291 void *pvGuestHeapMemory;
292
293 if (!pVBox->fHaveHGSMI)
294 return FALSE;
295 VBoxHGSMIGetBaseMappingInfo(pScrn->videoRam * 1024, &offVRAMBaseMapping,
296 NULL, &offGuestHeapMemory, &cbGuestHeapMemory,
297 NULL);
298 pvGuestHeapMemory = ((uint8_t *)pVBox->base) + offVRAMBaseMapping
299 + offGuestHeapMemory;
300 TRACE_LOG("video RAM: %u KB, guest heap offset: 0x%x, cbGuestHeapMemory: %u\n",
301 pScrn->videoRam, offVRAMBaseMapping + offGuestHeapMemory,
302 cbGuestHeapMemory);
303 rc = VBoxHGSMISetupGuestContext(&pVBox->guestCtx, pvGuestHeapMemory,
304 cbGuestHeapMemory,
305 offVRAMBaseMapping + offGuestHeapMemory);
306 if (RT_FAILURE(rc))
307 {
308 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set up the guest-to-host communication context, rc=%d\n", rc);
309 return FALSE;
310 }
311 pVBox->cbView = pVBox->cbFramebuffer = offVRAMBaseMapping;
312 pVBox->cScreens = VBoxHGSMIGetMonitorCount(&pVBox->guestCtx);
313 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested monitor count: %u\n",
314 pVBox->cScreens);
315 for (i = 0; i < pVBox->cScreens; ++i)
316 {
317 pVBox->cbFramebuffer -= VBVA_MIN_BUFFER_SIZE;
318 pVBox->aoffVBVABuffer[i] = pVBox->cbFramebuffer;
319 TRACE_LOG("VBVA buffer offset for screen %u: 0x%lx\n", i,
320 (unsigned long) pVBox->cbFramebuffer);
321 VBoxVBVASetupBufferContext(&pVBox->aVbvaCtx[i],
322 pVBox->aoffVBVABuffer[i],
323 VBVA_MIN_BUFFER_SIZE);
324 }
325 TRACE_LOG("Maximum framebuffer size: %lu (0x%lx)\n",
326 (unsigned long) pVBox->cbFramebuffer,
327 (unsigned long) pVBox->cbFramebuffer);
328 rc = VBoxHGSMISendViewInfo(&pVBox->guestCtx, pVBox->cScreens,
329 vboxFillViewInfo, (void *)pVBox);
330 if (RT_FAILURE(rc))
331 {
332 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to send the view information to the host, rc=%d\n", rc);
333 return FALSE;
334 }
335 return TRUE;
336}
337
338Bool
339vbox_init(int scrnIndex, VBOXPtr pVBox)
340{
341 Bool rc = TRUE;
342 int vrc;
343 uint32_t fMouseFeatures = 0;
344
345 TRACE_ENTRY();
346 vrc = VbglR3Init();
347 if (RT_FAILURE(vrc))
348 {
349 xf86DrvMsg(scrnIndex, X_ERROR,
350 "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",
351 vrc);
352 rc = FALSE;
353 }
354 pVBox->useDevice = rc;
355 /* We can't switch to a software cursor at will without help from
356 * VBoxClient. So tell that to the host and wait for VBoxClient to
357 * change this. */
358 vrc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
359 if (RT_SUCCESS(vrc))
360 VbglR3SetMouseStatus( fMouseFeatures
361 | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
362 return rc;
363}
364
365Bool
366vbox_open(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
367{
368 TRACE_ENTRY();
369
370 pVBox->fHaveHGSMI = vboxInitVbva(pScrn->scrnIndex, pScreen, pVBox);
371 return pVBox->fHaveHGSMI;
372}
373
374Bool
375vbox_device_available(VBOXPtr pVBox)
376{
377 return pVBox->useDevice;
378}
379
380static void
381vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
382{
383 int rc;
384
385 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, 0, 0, 0, 0, 0, NULL, 0);
386 if (RT_FAILURE(rc))
387 {
388 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not hide the virtual mouse pointer, VBox error %d.\n", rc);
389 /* Play safe, and disable the hardware cursor until the next mode
390 * switch, since obviously something happened that we didn't
391 * anticipate. */
392 pVBox->forceSWCursor = TRUE;
393 }
394}
395
396static void
397vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
398{
399 int rc;
400
401 if (!vbox_host_uses_hwcursor(pScrn))
402 return;
403 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, VBOX_MOUSE_POINTER_VISIBLE,
404 0, 0, 0, 0, NULL, 0);
405 if (RT_FAILURE(rc)) {
406 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
407 /* Play safe, and disable the hardware cursor until the next mode
408 * switch, since obviously something happened that we didn't
409 * anticipate. */
410 pVBox->forceSWCursor = TRUE;
411 }
412}
413
414static void
415vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
416 unsigned char *pvImage)
417{
418 int rc;
419 struct vboxCursorImage *pImage;
420 pImage = (struct vboxCursorImage *)pvImage;
421
422#ifdef DEBUG_POINTER
423 vbox_show_shape(pImage->cWidth, pImage->cHeight, 0, pvImage);
424#endif
425
426 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, pImage->fFlags,
427 pImage->cHotX, pImage->cHotY, pImage->cWidth, pImage->cHeight,
428 pImage->pPixels, pImage->cbLength);
429 if (RT_FAILURE(rc)) {
430 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to set the virtual mouse pointer image.\n");
431 /* Play safe, and disable the hardware cursor until the next mode
432 * switch, since obviously something happened that we didn't
433 * anticipate. */
434 pVBox->forceSWCursor = TRUE;
435 }
436}
437
438static void
439vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
440{
441 NOREF(pScrn);
442 NOREF(bg);
443 NOREF(fg);
444 /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
445}
446
447
448static void
449vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
450{
451 /* Nothing to do here, as we are telling the guest where the mouse is,
452 * not vice versa. */
453 NOREF(pScrn);
454 NOREF(x);
455 NOREF(y);
456}
457
458static void
459vbox_hide_cursor(ScrnInfoPtr pScrn)
460{
461 VBOXPtr pVBox = pScrn->driverPrivate;
462
463 vbox_vmm_hide_cursor(pScrn, pVBox);
464}
465
466static void
467vbox_show_cursor(ScrnInfoPtr pScrn)
468{
469 VBOXPtr pVBox = pScrn->driverPrivate;
470
471 vbox_vmm_show_cursor(pScrn, pVBox);
472}
473
474static void
475vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
476{
477 VBOXPtr pVBox = pScrn->driverPrivate;
478
479 vbox_vmm_load_cursor_image(pScrn, pVBox, image);
480}
481
482static Bool
483vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
484{
485 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
486 return vbox_host_uses_hwcursor(pScrn);
487}
488
489static unsigned char
490color_to_byte(unsigned c)
491{
492 return (c >> 8) & 0xff;
493}
494
495static unsigned char *
496vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
497{
498 VBOXPtr pVBox;
499 CursorBitsPtr bitsp;
500 unsigned short w, h, x, y;
501 unsigned char *c, *p, *pm, *ps, *m;
502 size_t sizeRequest, sizeRgba, sizeMask, srcPitch, dstPitch;
503 CARD32 fc, bc, *cp;
504 int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
505 struct vboxCursorImage *pImage;
506
507 pVBox = infoPtr->pScrn->driverPrivate;
508 bitsp = pCurs->bits;
509 w = bitsp->width;
510 h = bitsp->height;
511
512 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
513 RETERROR(scrnIndex, NULL,
514 "Error invalid cursor dimensions %dx%d\n", w, h);
515
516 if ((bitsp->xhot > w) || (bitsp->yhot > h))
517 RETERROR(scrnIndex, NULL,
518 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
519 bitsp->xhot, bitsp->yhot, w, h);
520
521 srcPitch = PixmapBytePad (bitsp->width, 1);
522 dstPitch = (w + 7) / 8;
523 sizeMask = ((dstPitch * h) + 3) & (size_t) ~3;
524 sizeRgba = w * h * 4;
525 sizeRequest = sizeMask + sizeRgba + sizeof(*pImage);
526
527 p = c = calloc (1, sizeRequest);
528 if (!c)
529 RETERROR(scrnIndex, NULL,
530 "Error failed to alloc %lu bytes for cursor\n",
531 (unsigned long) sizeRequest);
532
533 pImage = (struct vboxCursorImage *)p;
534 pImage->pPixels = m = p + sizeof(*pImage);
535 cp = (CARD32 *)(m + sizeMask);
536
537 TRACE_LOG ("w=%d h=%d sm=%d sr=%d p=%d\n",
538 w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
539 TRACE_LOG ("m=%p c=%p cp=%p\n", m, c, (void *)cp);
540
541 fc = color_to_byte (pCurs->foreBlue)
542 | (color_to_byte (pCurs->foreGreen) << 8)
543 | (color_to_byte (pCurs->foreRed) << 16);
544
545 bc = color_to_byte (pCurs->backBlue)
546 | (color_to_byte (pCurs->backGreen) << 8)
547 | (color_to_byte (pCurs->backRed) << 16);
548
549 /*
550 * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
551 * Xorg:
552 * The mask is a bitmap indicating which parts of the cursor are
553 * transparent and which parts are drawn. The source is a bitmap
554 * indicating which parts of the non-transparent portion of the
555 * the cursor should be painted in the foreground color and which
556 * should be painted in the background color. By default, set bits
557 * indicate the opaque part of the mask bitmap and clear bits
558 * indicate the transparent part.
559 * VBox:
560 * The color data is the XOR mask. The AND mask bits determine
561 * which pixels of the color data (XOR mask) will replace (overwrite)
562 * the screen pixels (AND mask bit = 0) and which ones will be XORed
563 * with existing screen pixels (AND mask bit = 1).
564 * For example when you have the AND mask all 0, then you see the
565 * correct mouse pointer image surrounded by black square.
566 */
567 for (pm = bitsp->mask, ps = bitsp->source, y = 0;
568 y < h;
569 ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
570 {
571 for (x = 0; x < w; ++x)
572 {
573 if (pm[x / 8] & (1 << (x % 8)))
574 {
575 /* opaque, leave AND mask bit at 0 */
576 if (ps[x / 8] & (1 << (x % 8)))
577 {
578 *cp++ = fc;
579 PUT_PIXEL('X');
580 }
581 else
582 {
583 *cp++ = bc;
584 PUT_PIXEL('*');
585 }
586 }
587 else
588 {
589 /* transparent, set AND mask bit */
590 m[x / 8] |= 1 << (7 - (x % 8));
591 /* don't change the screen pixel */
592 *cp++ = 0;
593 PUT_PIXEL(' ');
594 }
595 }
596 PUT_PIXEL('\n');
597 }
598
599 pImage->cWidth = w;
600 pImage->cHeight = h;
601 pImage->cHotX = bitsp->xhot;
602 pImage->cHotY = bitsp->yhot;
603 pImage->fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE;
604 pImage->cbLength = sizeRequest - sizeof(*pImage);
605
606#ifdef DEBUG_POINTER
607 ErrorF("shape = %p\n", p);
608 vbox_show_shape(w, h, bc, c);
609#endif
610
611 return p;
612}
613
614#ifdef ARGB_CURSOR
615static Bool
616vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
617{
618 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
619 Bool rc = TRUE;
620
621 if (!vbox_host_uses_hwcursor(pScrn))
622 rc = FALSE;
623 if ( rc
624 && ( (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
625 || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
626 || (pScrn->bitsPerPixel <= 8)
627 )
628 )
629 rc = FALSE;
630#ifndef VBOXVIDEO_13
631 /* Evil hack - we use this as another way of poking the driver to update
632 * our list of video modes. */
633 vboxWriteHostModes(pScrn, pScrn->currentMode);
634#endif
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 sizeData, sizeMask;
650 CARD8 *p;
651 int scrnIndex;
652 uint32_t fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE
653 | VBOX_MOUSE_POINTER_ALPHA;
654 int rc;
655
656 pVBox = pScrn->driverPrivate;
657 bitsp = pCurs->bits;
658 w = bitsp->width;
659 h = bitsp->height;
660 scrnIndex = pScrn->scrnIndex;
661
662 /* Mask must be generated for alpha cursors, that is required by VBox. */
663 /* note: (michael) the next struct must be 32bit aligned. */
664 sizeMask = ((w + 7) / 8 * h + 3) & ~3;
665
666 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
667 RETERROR(scrnIndex, ,
668 "Error invalid cursor dimensions %dx%d\n", w, h);
669
670 if ((bitsp->xhot > w) || (bitsp->yhot > h))
671 RETERROR(scrnIndex, ,
672 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
673 bitsp->xhot, bitsp->yhot, w, h);
674
675 sizeData = w * h * 4 + sizeMask;
676 p = calloc(1, sizeData);
677 if (!p)
678 RETERROR(scrnIndex, ,
679 "Error failed to alloc %lu bytes for cursor\n",
680 (unsigned long)sizeData);
681
682 memcpy(p + sizeMask, bitsp->argb, w * h * 4);
683
684 /* Emulate the AND mask. */
685 pm = p;
686 pc = bitsp->argb;
687
688 /* Init AND mask to 1 */
689 memset(pm, 0xFF, sizeMask);
690
691 /*
692 * The additions driver must provide the AND mask for alpha cursors. The host frontend
693 * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
694 * But if the host does not support ARGB, then it simply uses the AND mask and the color
695 * data to draw a normal color cursor.
696 */
697 for (cy = 0; cy < h; cy++)
698 {
699 unsigned char bitmask = 0x80;
700
701 for (cx = 0; cx < w; cx++, bitmask >>= 1)
702 {
703 if (bitmask == 0)
704 bitmask = 0x80;
705
706 if (pc[cx] >= 0xF0000000)
707 pm[cx / 8] &= ~bitmask;
708 }
709
710 /* Point to next source and dest scans */
711 pc += w;
712 pm += (w + 7) / 8;
713 }
714
715 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, fFlags, bitsp->xhot,
716 bitsp->yhot, w, h, p, sizeData);
717 free(p);
718}
719#endif
720
721Bool
722vbox_cursor_init(ScreenPtr pScreen)
723{
724 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
725 VBOXPtr pVBox = pScrn->driverPrivate;
726 xf86CursorInfoPtr pCurs = NULL;
727 Bool rc = TRUE;
728
729 TRACE_ENTRY();
730 if (!pVBox->fHaveHGSMI)
731 return FALSE;
732 pVBox->pCurs = pCurs = xf86CreateCursorInfoRec();
733 if (!pCurs) {
734 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
735 "Failed to create X Window cursor information structures for virtual mouse.\n");
736 rc = FALSE;
737 }
738 if (rc) {
739 pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
740 pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
741 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
742 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
743 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
744
745 pCurs->SetCursorColors = vbox_set_cursor_colors;
746 pCurs->SetCursorPosition = vbox_set_cursor_position;
747 pCurs->LoadCursorImage = vbox_load_cursor_image;
748 pCurs->HideCursor = vbox_hide_cursor;
749 pCurs->ShowCursor = vbox_show_cursor;
750 pCurs->UseHWCursor = vbox_use_hw_cursor;
751 pCurs->RealizeCursor = vbox_realize_cursor;
752
753#ifdef ARGB_CURSOR
754 pCurs->UseHWCursorARGB = vbox_use_hw_cursor_argb;
755 pCurs->LoadCursorARGB = vbox_load_cursor_argb;
756#endif
757
758 /* Hide the host cursor before we initialise if we wish to use a
759 * software cursor. */
760 if (pVBox->forceSWCursor)
761 vbox_vmm_hide_cursor(pScrn, pVBox);
762 rc = xf86InitCursor(pScreen, pCurs);
763 }
764 if (!rc)
765 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
766 "Failed to enable mouse pointer integration.\n");
767 if (!rc && (pCurs != NULL))
768 xf86DestroyCursorInfoRec(pCurs);
769 return rc;
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 bool rc = TRUE;
783 int scrnIndex = pScrn->scrnIndex;
784 unsigned i;
785 VBOXPtr pVBox = pScrn->driverPrivate;
786
787 TRACE_ENTRY();
788 if (!vboxSetupVRAMVbva(pScrn, pVBox))
789 return FALSE;
790 for (i = 0; i < pVBox->cScreens; ++i)
791 {
792 struct VBVABUFFER *pVBVA;
793
794 pVBVA = (struct VBVABUFFER *) ( ((uint8_t *)pVBox->base)
795 + pVBox->aoffVBVABuffer[i]);
796 if (!VBoxVBVAEnable(&pVBox->aVbvaCtx[i], &pVBox->guestCtx, pVBVA, i))
797 rc = FALSE;
798 }
799 if (!rc)
800 {
801 /* Request not accepted - disable for old hosts. */
802 xf86DrvMsg(scrnIndex, X_ERROR,
803 "Failed to enable screen update reporting for at least one virtual monitor.\n");
804 vboxDisableVbva(pScrn);
805 }
806 return rc;
807}
808
809/**
810 * Inform VBox that we will stop supplying it with dirty rectangle
811 * information. This function is intended to be called when an X
812 * virtual terminal is disabled, or the X server is terminated.
813 *
814 * @returns TRUE for success, FALSE for failure
815 * @param pScrn Pointer to a structure describing the X screen in use
816 */
817void
818vboxDisableVbva(ScrnInfoPtr pScrn)
819{
820 int rc;
821 int scrnIndex = pScrn->scrnIndex;
822 unsigned i;
823 VBOXPtr pVBox = pScrn->driverPrivate;
824
825 TRACE_ENTRY();
826 if (!pVBox->fHaveHGSMI) /* Ths function should not have been called */
827 return;
828 for (i = 0; i < pVBox->cScreens; ++i)
829 VBoxVBVADisable(&pVBox->aVbvaCtx[i], &pVBox->guestCtx, i);
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 TRACE_ENTRY();
842 if (!pVBox->useDevice)
843 return FALSE;
844 return RT_SUCCESS(VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0));
845}
846
847/**
848 * Inform VBox that we are no longer aware of advanced graphics functions
849 * (i.e. dynamic resizing, seamless).
850 *
851 * @returns TRUE for success, FALSE for failure
852 */
853Bool
854vboxDisableGraphicsCap(VBOXPtr pVBox)
855{
856 TRACE_ENTRY();
857 if (!pVBox->useDevice)
858 return FALSE;
859 return RT_SUCCESS(VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS));
860}
861
862/**
863 * Query the last display change request.
864 *
865 * @returns boolean success indicator.
866 * @param pScrn Pointer to the X screen info structure.
867 * @param pcx Where to store the horizontal pixel resolution (0 = do not change).
868 * @param pcy Where to store the vertical pixel resolution (0 = do not change).
869 * @param pcBits Where to store the bits per pixel (0 = do not change).
870 * @param iDisplay Where to store the display number the request was for - 0 for the
871 * primary display, 1 for the first secondary, etc.
872 */
873Bool
874vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy,
875 uint32_t *pcBits, uint32_t *piDisplay)
876{
877 VBOXPtr pVBox = pScrn->driverPrivate;
878 TRACE_ENTRY();
879 if (!pVBox->useDevice)
880 return FALSE;
881 int rc = VbglR3GetDisplayChangeRequest(pcx, pcy, pcBits, piDisplay, true);
882 if (RT_SUCCESS(rc))
883 return TRUE;
884 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to obtain the last resolution requested by the guest, rc=%d.\n", rc);
885 return FALSE;
886}
887
888
889/**
890 * Query the host as to whether it likes a specific video mode.
891 *
892 * @returns the result of the query
893 * @param cx the width of the mode being queried
894 * @param cy the height of the mode being queried
895 * @param cBits the bpp of the mode being queried
896 */
897Bool
898vboxHostLikesVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
899{
900 VBOXPtr pVBox = pScrn->driverPrivate;
901 TRACE_ENTRY();
902 if (!pVBox->useDevice)
903 return TRUE; /* If we can't ask the host then we like everything. */
904 return VbglR3HostLikesVideoMode(cx, cy, cBits);
905}
906
907/**
908 * Check if any seamless mode is enabled.
909 * Seamless is only relevant for the newer Xorg modules.
910 *
911 * @returns the result of the query
912 * (true = seamless enabled, false = seamless not enabled)
913 * @param pScrn Screen info pointer.
914 */
915Bool
916vboxGuestIsSeamless(ScrnInfoPtr pScrn)
917{
918 VMMDevSeamlessMode mode;
919 VBOXPtr pVBox = pScrn->driverPrivate;
920 TRACE_ENTRY();
921 if (!pVBox->useDevice)
922 return FALSE;
923 if (RT_FAILURE(VbglR3SeamlessGetLastEvent(&mode)))
924 return FALSE;
925 return (mode != VMMDev_Seamless_Disabled);
926}
927
928/**
929 * Save video mode parameters to the registry.
930 *
931 * @returns iprt status value
932 * @param pszName the name to save the mode parameters under
933 * @param cx mode width
934 * @param cy mode height
935 * @param cBits bits per pixel for the mode
936 */
937Bool
938vboxSaveVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
939{
940 VBOXPtr pVBox = pScrn->driverPrivate;
941 TRACE_ENTRY();
942 if (!pVBox->useDevice)
943 return FALSE;
944 return RT_SUCCESS(VbglR3SaveVideoMode("SavedMode", cx, cy, cBits));
945}
946
947/**
948 * Retrieve video mode parameters from the registry.
949 *
950 * @returns iprt status value
951 * @param pszName the name under which the mode parameters are saved
952 * @param pcx where to store the mode width
953 * @param pcy where to store the mode height
954 * @param pcBits where to store the bits per pixel for the mode
955 */
956Bool
957vboxRetrieveVideoMode(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits)
958{
959 VBOXPtr pVBox = pScrn->driverPrivate;
960 TRACE_ENTRY();
961 if (!pVBox->useDevice)
962 return FALSE;
963 int rc = VbglR3RetrieveVideoMode("SavedMode", pcx, pcy, pcBits);
964 if (RT_SUCCESS(rc))
965 TRACE_LOG("Retrieved a video mode of %dx%dx%d\n", *pcx, *pcy, *pcBits);
966 else
967 TRACE_LOG("Failed to retrieve video mode, error %d\n", rc);
968 return (RT_SUCCESS(rc));
969}
970
971/**
972 * Fills a display mode M with a built-in mode of name pszName and dimensions
973 * cx and cy.
974 */
975static void vboxFillDisplayMode(ScrnInfoPtr pScrn, DisplayModePtr m,
976 const char *pszName, unsigned cx, unsigned cy)
977{
978 VBOXPtr pVBox = pScrn->driverPrivate;
979 TRACE_LOG("pszName=%s, cx=%u, cy=%u\n", pszName, cx, cy);
980 m->status = MODE_OK;
981 m->type = M_T_BUILTIN;
982 /* Older versions of VBox only support screen widths which are a multiple
983 * of 8 */
984 if (pVBox->fAnyX)
985 m->HDisplay = cx;
986 else
987 m->HDisplay = cx & ~7;
988 m->HSyncStart = m->HDisplay + 2;
989 m->HSyncEnd = m->HDisplay + 4;
990 m->HTotal = m->HDisplay + 6;
991 m->VDisplay = cy;
992 m->VSyncStart = m->VDisplay + 2;
993 m->VSyncEnd = m->VDisplay + 4;
994 m->VTotal = m->VDisplay + 6;
995 m->Clock = m->HTotal * m->VTotal * 60 / 1000; /* kHz */
996 if (pszName)
997 {
998 if (m->name)
999 free(m->name);
1000 m->name = xnfstrdup(pszName);
1001 }
1002}
1003
1004/** vboxvideo's list of standard video modes */
1005struct
1006{
1007 /** mode width */
1008 uint32_t cx;
1009 /** mode height */
1010 uint32_t cy;
1011} vboxStandardModes[] =
1012{
1013 { 1600, 1200 },
1014 { 1440, 1050 },
1015 { 1280, 960 },
1016 { 1024, 768 },
1017 { 800, 600 },
1018 { 640, 480 },
1019 { 0, 0 }
1020};
1021enum
1022{
1023 vboxNumStdModes = sizeof(vboxStandardModes) / sizeof(vboxStandardModes[0])
1024};
1025
1026/**
1027 * Returns a standard mode which the host likes. Can be called multiple
1028 * times with the index returned by the previous call to get a list of modes.
1029 * @returns the index of the mode in the list, or 0 if no more modes are
1030 * available
1031 * @param pScrn the screen information structure
1032 * @param pScrn->bitsPerPixel
1033 * if this is non-null, only modes with this BPP will be
1034 * returned
1035 * @param cIndex the index of the last mode queried, or 0 to query the
1036 * first mode available. Note: the first index is 1
1037 * @param pcx where to store the mode's width
1038 * @param pcy where to store the mode's height
1039 * @param pcBits where to store the mode's BPP
1040 */
1041static unsigned vboxNextStandardMode(ScrnInfoPtr pScrn, unsigned cIndex,
1042 uint32_t *pcx, uint32_t *pcy,
1043 uint32_t *pcBits)
1044{
1045 XF86ASSERT(cIndex < vboxNumStdModes,
1046 ("cIndex = %d, vboxNumStdModes = %d\n", cIndex,
1047 vboxNumStdModes));
1048 for (unsigned i = cIndex; i < vboxNumStdModes - 1; ++i)
1049 {
1050 uint32_t cBits = pScrn->bitsPerPixel;
1051 uint32_t cx = vboxStandardModes[i].cx;
1052 uint32_t cy = vboxStandardModes[i].cy;
1053
1054 if (cBits != 0 && !vboxHostLikesVideoMode(pScrn, cx, cy, cBits))
1055 continue;
1056 if (vboxHostLikesVideoMode(pScrn, cx, cy, 32))
1057 cBits = 32;
1058 else if (vboxHostLikesVideoMode(pScrn, cx, cy, 16))
1059 cBits = 16;
1060 else
1061 continue;
1062 if (pcx)
1063 *pcx = cx;
1064 if (pcy)
1065 *pcy = cy;
1066 if (pcBits)
1067 *pcBits = cBits;
1068 return i + 1;
1069 }
1070 return 0;
1071}
1072
1073/**
1074 * Returns the preferred video mode. The current order of preference is
1075 * (from highest to least preferred):
1076 * - The mode corresponding to the last size hint from the host
1077 * - The video mode saved from the last session
1078 * - The largest standard mode which the host likes, falling back to
1079 * 640x480x32 as a worst case
1080 * - If the host can't be contacted at all, we return 1024x768x32
1081 *
1082 * The return type is void as we guarantee we will return some mode.
1083 */
1084void vboxGetPreferredMode(ScrnInfoPtr pScrn, uint32_t iScreen, uint32_t *pcx,
1085 uint32_t *pcy, uint32_t *pcBits)
1086{
1087 /* Query the host for the preferred resolution and colour depth */
1088 uint32_t cx = 0, cy = 0, iScreenIn = 0, cBits = 32;
1089 VBOXPtr pVBox = pScrn->driverPrivate;
1090
1091 TRACE_ENTRY();
1092 bool found = false;
1093 if ( pVBox->aPreferredSize[iScreen].cx
1094 && pVBox->aPreferredSize[iScreen].cy)
1095 {
1096 cx = pVBox->aPreferredSize[iScreen].cx;
1097 cy = pVBox->aPreferredSize[iScreen].cy;
1098 found = true;
1099 }
1100 if (pVBox->useDevice)
1101 {
1102 if (!found)
1103 found = vboxGetDisplayChangeRequest(pScrn, &cx, &cy, &cBits,
1104 &iScreenIn);
1105 if ((cx == 0) || (cy == 0) || iScreenIn != iScreen)
1106 found = false;
1107 if (!found)
1108 found = vboxRetrieveVideoMode(pScrn, &cx, &cy, &cBits);
1109 if ((cx == 0) || (cy == 0))
1110 found = false;
1111 if (!found)
1112 found = (vboxNextStandardMode(pScrn, 0, &cx, &cy, &cBits) != 0);
1113 if (!found)
1114 {
1115 /* Last resort */
1116 cx = 640;
1117 cy = 480;
1118 cBits = 32;
1119 }
1120 }
1121 else
1122 {
1123 cx = 1024;
1124 cy = 768;
1125 }
1126 if (pcx)
1127 *pcx = cx;
1128 if (pcy)
1129 *pcy = cy;
1130 if (pcx)
1131 *pcBits = cBits;
1132}
1133
1134/* Move a screen mode found to the end of the list, so that RandR will give
1135 * it the highest priority when a mode switch is requested. Returns the mode
1136 * that was previously before the mode in the list in order to allow the
1137 * caller to continue walking the list. */
1138static DisplayModePtr vboxMoveModeToFront(ScrnInfoPtr pScrn,
1139 DisplayModePtr pMode)
1140{
1141 DisplayModePtr pPrev = pMode->prev;
1142 if (pMode != pScrn->modes)
1143 {
1144 pMode->prev->next = pMode->next;
1145 pMode->next->prev = pMode->prev;
1146 pMode->next = pScrn->modes;
1147 pMode->prev = pScrn->modes->prev;
1148 pMode->next->prev = pMode;
1149 pMode->prev->next = pMode;
1150 pScrn->modes = pMode;
1151 }
1152 return pPrev;
1153}
1154
1155/**
1156 * Rewrites the first dynamic mode found which is not the current screen mode
1157 * to contain the host's currently preferred screen size, then moves that
1158 * mode to the front of the screen information structure's mode list.
1159 * Additionally, if the current mode is not dynamic, the second dynamic mode
1160 * will be set to match the current mode and also added to the front. This
1161 * ensures that the user can always reset the current size to kick the driver
1162 * to update its mode list.
1163 */
1164void vboxWriteHostModes(ScrnInfoPtr pScrn, DisplayModePtr pCurrent)
1165{
1166 uint32_t cx = 0, cy = 0, iDisplay = 0, cBits = 0;
1167 DisplayModePtr pMode;
1168 bool found = false;
1169
1170 TRACE_ENTRY();
1171 vboxGetPreferredMode(pScrn, 0, &cx, &cy, &cBits);
1172#ifdef DEBUG
1173 /* Count the number of modes for sanity */
1174 unsigned cModes = 1, cMode = 0;
1175 DisplayModePtr pCount;
1176 for (pCount = pScrn->modes; ; pCount = pCount->next, ++cModes)
1177 if (pCount->next == pScrn->modes)
1178 break;
1179#endif
1180 for (pMode = pScrn->modes; ; pMode = pMode->next)
1181 {
1182#ifdef DEBUG
1183 XF86ASSERT (cMode++ < cModes, (NULL));
1184#endif
1185 if ( pMode != pCurrent
1186 && !strcmp(pMode->name, "VBoxDynamicMode"))
1187 {
1188 if (!found)
1189 vboxFillDisplayMode(pScrn, pMode, NULL, cx, cy);
1190 else if (pCurrent)
1191 vboxFillDisplayMode(pScrn, pMode, NULL, pCurrent->HDisplay,
1192 pCurrent->VDisplay);
1193 found = true;
1194 pMode = vboxMoveModeToFront(pScrn, pMode);
1195 }
1196 if (pMode->next == pScrn->modes)
1197 break;
1198 }
1199 XF86ASSERT (found,
1200 ("vboxvideo: no free dynamic mode found. Exiting.\n"));
1201 XF86ASSERT ( (pScrn->modes->HDisplay == (long) cx)
1202 || ( (pScrn->modes->HDisplay == pCurrent->HDisplay)
1203 && (pScrn->modes->next->HDisplay == (long) cx)),
1204 ("pScrn->modes->HDisplay=%u, pScrn->modes->next->HDisplay=%u\n",
1205 pScrn->modes->HDisplay, pScrn->modes->next->HDisplay));
1206 XF86ASSERT ( (pScrn->modes->VDisplay == (long) cy)
1207 || ( (pScrn->modes->VDisplay == pCurrent->VDisplay)
1208 && (pScrn->modes->next->VDisplay == (long) cy)),
1209 ("pScrn->modes->VDisplay=%u, pScrn->modes->next->VDisplay=%u\n",
1210 pScrn->modes->VDisplay, pScrn->modes->next->VDisplay));
1211}
1212
1213/**
1214 * Allocates an empty display mode and links it into the doubly linked list of
1215 * modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
1216 * memory.
1217 */
1218static DisplayModePtr vboxAddEmptyScreenMode(ScrnInfoPtr pScrn)
1219{
1220 DisplayModePtr pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
1221
1222 TRACE_ENTRY();
1223 if (!pScrn->modes)
1224 {
1225 pScrn->modes = pMode;
1226 pMode->next = pMode;
1227 pMode->prev = pMode;
1228 }
1229 else
1230 {
1231 pMode->next = pScrn->modes;
1232 pMode->prev = pScrn->modes->prev;
1233 pMode->next->prev = pMode;
1234 pMode->prev->next = pMode;
1235 }
1236 return pMode;
1237}
1238
1239/**
1240 * Create display mode entries in the screen information structure for each
1241 * of the initial graphics modes that we wish to support. This includes:
1242 * - An initial mode, of the size requested by the caller
1243 * - Two dynamic modes, one of which will be updated to match the last size
1244 * hint from the host on each mode switch, but initially also of the
1245 * requested size
1246 * - Several standard modes, if possible ones that the host likes
1247 * - Any modes that the user requested in xorg.conf/XFree86Config
1248 */
1249void vboxAddModes(ScrnInfoPtr pScrn, uint32_t cxInit, uint32_t cyInit)
1250{
1251 unsigned cx = 0, cy = 0, cIndex = 0;
1252 /* For reasons related to the way RandR 1.1 is implemented, we need to
1253 * make sure that the initial mode (more precisely, a mode equal to the
1254 * initial virtual resolution) is always present in the mode list. RandR
1255 * has the assumption build in that there will either be a mode of that
1256 * size present at all times, or that the first mode in the list will
1257 * always be smaller than the initial virtual resolution. Since our
1258 * approach to dynamic resizing isn't quite the way RandR was intended to
1259 * be, and breaks the second assumption, we guarantee the first. */
1260 DisplayModePtr pMode = vboxAddEmptyScreenMode(pScrn);
1261 vboxFillDisplayMode(pScrn, pMode, "VBoxInitialMode", cxInit, cyInit);
1262 /* Create our two dynamic modes. */
1263 pMode = vboxAddEmptyScreenMode(pScrn);
1264 vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
1265 pMode = vboxAddEmptyScreenMode(pScrn);
1266 vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
1267 /* Add standard modes supported by the host */
1268 for ( ; ; )
1269 {
1270 char szName[256];
1271 cIndex = vboxNextStandardMode(pScrn, cIndex, &cx, &cy, NULL);
1272 if (cIndex == 0)
1273 break;
1274 sprintf(szName, "VBox-%ux%u", cx, cy);
1275 pMode = vboxAddEmptyScreenMode(pScrn);
1276 vboxFillDisplayMode(pScrn, pMode, szName, cx, cy);
1277 }
1278 /* And finally any modes specified by the user. We assume here that
1279 * the mode names reflect the mode sizes. */
1280 for (unsigned i = 0; pScrn->display->modes != NULL
1281 && pScrn->display->modes[i] != NULL; i++)
1282 {
1283 if (sscanf(pScrn->display->modes[i], "%ux%u", &cx, &cy) == 2)
1284 {
1285 pMode = vboxAddEmptyScreenMode(pScrn);
1286 vboxFillDisplayMode(pScrn, pMode, pScrn->display->modes[i], cx, cy);
1287 }
1288 }
1289}
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