VirtualBox

Changeset 35843 in vbox


Ignore:
Timestamp:
Feb 3, 2011 4:25:37 PM (14 years ago)
Author:
vboxsync
Message:

Additions/x11/vboxvideo: some splitting up of the code

Location:
trunk/src/VBox/Additions/x11/vboxvideo
Files:
2 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/vboxvideo/Makefile.kmk

    r35840 r35843  
    7272vboxvideo_drv_INCS += $(PATH_ROOT)/src/VBox/Runtime/include
    7373vboxvideo_drv_SOURCES = \
     74        pointer.c \
    7475        vboxutils.c \
    7576        vboxvideo.c \
  • trunk/src/VBox/Additions/x11/vboxvideo/pointer.c

    r35775 r35843  
    172172}
    173173
    174 /**
    175  * Callback function called by the X server to tell us about dirty
    176  * rectangles in the video buffer.
    177  *
    178  * @param pScreen pointer to the information structure for the current
    179  *                screen
    180  * @param iRects  Number of dirty rectangles to update
    181  * @param aRects  Array of structures containing the coordinates of the
    182  *                rectangles
    183  */
    184 static void
    185 vboxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects)
    186 {
    187     VBVACMDHDR cmdHdr;
    188     VBOXPtr pVBox;
    189     int i;
    190     unsigned j;
    191 
    192     pVBox = pScrn->driverPrivate;
    193     if (pVBox->fHaveHGSMI == FALSE || pVBox->vtSwitch)
    194         return;
    195 
    196     for (i = 0; i < iRects; ++i)
    197         for (j = 0; j < pVBox->cScreens; ++j)
    198         {
    199             /* Just continue quietly if VBVA is not currently active. */
    200             struct VBVABUFFER *pVBVA = pVBox->aVbvaCtx[j].pVBVA;
    201             if (   !pVBVA
    202                 || !(pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
    203                 continue;
    204             if (   aRects[i].x1 >   pVBox->aScreenLocation[j].x
    205                                   + pVBox->aScreenLocation[j].cx
    206                 || aRects[i].y1 >   pVBox->aScreenLocation[j].y
    207                                   + pVBox->aScreenLocation[j].cy
    208                 || aRects[i].x2 <   pVBox->aScreenLocation[j].x
    209                 || aRects[i].y2 <   pVBox->aScreenLocation[j].y)
    210                 continue;
    211             cmdHdr.x = (int16_t)aRects[i].x1;
    212             cmdHdr.y = (int16_t)aRects[i].y1;
    213             cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
    214             cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
    215 
    216 #if 0
    217             TRACE_LOG("display=%u, x=%d, y=%d, w=%d, h=%d\n",
    218                       j, cmdHdr.x, cmdHdr.y, cmdHdr.w, cmdHdr.h);
    219 #endif
    220 
    221             if (VBoxVBVABufferBeginUpdate(&pVBox->aVbvaCtx[j],
    222                                           &pVBox->guestCtx))
    223             {
    224                 VBoxVBVAWrite(&pVBox->aVbvaCtx[j], &pVBox->guestCtx, &cmdHdr,
    225                               sizeof(cmdHdr));
    226                 VBoxVBVABufferEndUpdate(&pVBox->aVbvaCtx[j]);
    227             }
    228         }
    229 }
    230 
    231 /** Callback to fill in the view structures */
    232 static int
    233 vboxFillViewInfo(void *pvVBox, struct VBVAINFOVIEW *pViews, uint32_t cViews)
    234 {
    235     VBOXPtr pVBox = (VBOXPtr)pvVBox;
    236     unsigned i;
    237     for (i = 0; i < cViews; ++i)
    238     {
    239         pViews[i].u32ViewIndex = i;
    240         pViews[i].u32ViewOffset = 0;
    241         pViews[i].u32ViewSize = pVBox->cbView;
    242         pViews[i].u32MaxScreenSize = pVBox->cbFBMax;
    243     }
    244     return VINF_SUCCESS;
    245 }
    246 
    247 /**
    248  * Initialise VirtualBox's accelerated video extensions.
    249  *
    250  * @returns TRUE on success, FALSE on failure
    251  */
    252 static Bool
    253 vboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
    254 {
    255     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
    256     int rc = VINF_SUCCESS;
    257 
    258     pVBox->cScreens = 1;
    259     if (!VBoxHGSMIIsSupported())
    260     {
    261         xf86DrvMsg(scrnIndex, X_ERROR, "The graphics device does not seem to support HGSMI.  Disableing video acceleration.\n");
    262         return FALSE;
    263     }
    264 
    265     /* Set up the dirty rectangle handler.  It will be added into a function
    266      * chain and gets removed when the screen is cleaned up. */
    267     if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
    268     {
    269         xf86DrvMsg(scrnIndex, X_ERROR,
    270                    "Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
    271         return FALSE;
    272     }
    273     return TRUE;
    274 }
    275 
    276 /**
    277  * Initialise VirtualBox's accelerated video extensions.
    278  *
    279  * @returns TRUE on success, FALSE on failure
    280  */
    281 static Bool
    282 vboxSetupVRAMVbva(ScrnInfoPtr pScrn, VBOXPtr pVBox)
    283 {
    284     int rc = VINF_SUCCESS;
    285     unsigned i;
    286     uint32_t offVRAMBaseMapping, offGuestHeapMemory, cbGuestHeapMemory;
    287     void *pvGuestHeapMemory;
    288 
    289     if (!pVBox->fHaveHGSMI)
    290         return FALSE;
    291     VBoxHGSMIGetBaseMappingInfo(pScrn->videoRam * 1024, &offVRAMBaseMapping,
    292                                 NULL, &offGuestHeapMemory, &cbGuestHeapMemory,
    293                                 NULL);
    294     pvGuestHeapMemory =   ((uint8_t *)pVBox->base) + offVRAMBaseMapping
    295                         + offGuestHeapMemory;
    296     TRACE_LOG("video RAM: %u KB, guest heap offset: 0x%x, cbGuestHeapMemory: %u\n",
    297               pScrn->videoRam, offVRAMBaseMapping + offGuestHeapMemory,
    298               cbGuestHeapMemory);
    299     rc = VBoxHGSMISetupGuestContext(&pVBox->guestCtx, pvGuestHeapMemory,
    300                                     cbGuestHeapMemory,
    301                                     offVRAMBaseMapping + offGuestHeapMemory);
    302     if (RT_FAILURE(rc))
    303     {
    304         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set up the guest-to-host communication context, rc=%d\n", rc);
    305         return FALSE;
    306     }
    307     pVBox->cbView = pVBox->cbFBMax = offVRAMBaseMapping;
    308     pVBox->cScreens = VBoxHGSMIGetMonitorCount(&pVBox->guestCtx);
    309     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested monitor count: %u\n",
    310                pVBox->cScreens);
    311     for (i = 0; i < pVBox->cScreens; ++i)
    312     {
    313         pVBox->cbFBMax -= VBVA_MIN_BUFFER_SIZE;
    314         pVBox->aoffVBVABuffer[i] = pVBox->cbFBMax;
    315         TRACE_LOG("VBVA buffer offset for screen %u: 0x%lx\n", i,
    316                   (unsigned long) pVBox->cbFBMax);
    317         VBoxVBVASetupBufferContext(&pVBox->aVbvaCtx[i],
    318                                    pVBox->aoffVBVABuffer[i],
    319                                    VBVA_MIN_BUFFER_SIZE);
    320     }
    321     TRACE_LOG("Maximum framebuffer size: %lu (0x%lx)\n",
    322               (unsigned long) pVBox->cbFBMax,
    323               (unsigned long) pVBox->cbFBMax);
    324     rc = VBoxHGSMISendViewInfo(&pVBox->guestCtx, pVBox->cScreens,
    325                                vboxFillViewInfo, (void *)pVBox);
    326     if (RT_FAILURE(rc))
    327     {
    328         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to send the view information to the host, rc=%d\n", rc);
    329         return FALSE;
    330     }
    331     return TRUE;
    332 }
    333 
    334174Bool
    335175vbox_init(int scrnIndex, VBOXPtr pVBox)
     
    357197                             | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
    358198    return rc;
    359 }
    360 
    361 Bool
    362 vbox_open(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
    363 {
    364     TRACE_ENTRY();
    365 
    366     pVBox->fHaveHGSMI = vboxInitVbva(pScrn->scrnIndex, pScreen, pVBox);
    367     return pVBox->fHaveHGSMI;
    368 }
    369 
    370 Bool
    371 vbox_device_available(VBOXPtr pVBox)
    372 {
    373     return pVBox->useDevice;
    374199}
    375200
     
    765590    return rc;
    766591}
    767 
    768 /**
    769  * Inform VBox that we will supply it with dirty rectangle information
    770  * and install the dirty rectangle handler.
    771  *
    772  * @returns TRUE for success, FALSE for failure
    773  * @param   pScrn   Pointer to a structure describing the X screen in use
    774  */
    775 Bool
    776 vboxEnableVbva(ScrnInfoPtr pScrn)
    777 {
    778     bool rc = TRUE;
    779     int scrnIndex = pScrn->scrnIndex;
    780     unsigned i;
    781     VBOXPtr pVBox = pScrn->driverPrivate;
    782 
    783     TRACE_ENTRY();
    784     if (!vboxSetupVRAMVbva(pScrn, pVBox))
    785         return FALSE;
    786     for (i = 0; i < pVBox->cScreens; ++i)
    787     {
    788         struct VBVABUFFER *pVBVA;
    789 
    790         pVBVA = (struct VBVABUFFER *) (  ((uint8_t *)pVBox->base)
    791                                        + pVBox->aoffVBVABuffer[i]);
    792         if (!VBoxVBVAEnable(&pVBox->aVbvaCtx[i], &pVBox->guestCtx, pVBVA, i))
    793             rc = FALSE;
    794     }
    795     if (!rc)
    796     {
    797         /* Request not accepted - disable for old hosts. */
    798         xf86DrvMsg(scrnIndex, X_ERROR,
    799                    "Failed to enable screen update reporting for at least one virtual monitor.\n");
    800          vboxDisableVbva(pScrn);
    801     }
    802     return rc;
    803 }
    804 
    805 /**
    806  * Inform VBox that we will stop supplying it with dirty rectangle
    807  * information. This function is intended to be called when an X
    808  * virtual terminal is disabled, or the X server is terminated.
    809  *
    810  * @returns TRUE for success, FALSE for failure
    811  * @param   pScrn   Pointer to a structure describing the X screen in use
    812  */
    813 void
    814 vboxDisableVbva(ScrnInfoPtr pScrn)
    815 {
    816     int rc;
    817     int scrnIndex = pScrn->scrnIndex;
    818     unsigned i;
    819     VBOXPtr pVBox = pScrn->driverPrivate;
    820 
    821     TRACE_ENTRY();
    822     if (!pVBox->fHaveHGSMI)  /* Ths function should not have been called */
    823         return;
    824     for (i = 0; i < pVBox->cScreens; ++i)
    825         VBoxVBVADisable(&pVBox->aVbvaCtx[i], &pVBox->guestCtx, i);
    826 }
    827 
    828 /**
    829  * Inform VBox that we are aware of advanced graphics functions
    830  * (i.e. dynamic resizing, seamless).
    831  *
    832  * @returns TRUE for success, FALSE for failure
    833  */
    834 Bool
    835 vboxEnableGraphicsCap(VBOXPtr pVBox)
    836 {
    837     TRACE_ENTRY();
    838     if (!pVBox->useDevice)
    839         return FALSE;
    840     return RT_SUCCESS(VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0));
    841 }
    842 
    843 /**
    844  * Inform VBox that we are no longer aware of advanced graphics functions
    845  * (i.e. dynamic resizing, seamless).
    846  *
    847  * @returns TRUE for success, FALSE for failure
    848  */
    849 Bool
    850 vboxDisableGraphicsCap(VBOXPtr pVBox)
    851 {
    852     TRACE_ENTRY();
    853     if (!pVBox->useDevice)
    854         return FALSE;
    855     return RT_SUCCESS(VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS));
    856 }
    857 
    858 /**
    859  * Query the last display change request.
    860  *
    861  * @returns boolean success indicator.
    862  * @param   pScrn       Pointer to the X screen info structure.
    863  * @param   pcx         Where to store the horizontal pixel resolution (0 = do not change).
    864  * @param   pcy         Where to store the vertical pixel resolution (0 = do not change).
    865  * @param   pcBits      Where to store the bits per pixel (0 = do not change).
    866  * @param   iDisplay    Where to store the display number the request was for - 0 for the
    867  *                      primary display, 1 for the first secondary, etc.
    868  */
    869 Bool
    870 vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy,
    871                             uint32_t *pcBits, uint32_t *piDisplay)
    872 {
    873     VBOXPtr pVBox = pScrn->driverPrivate;
    874     TRACE_ENTRY();
    875     if (!pVBox->useDevice)
    876         return FALSE;
    877     int rc = VbglR3GetDisplayChangeRequest(pcx, pcy, pcBits, piDisplay, false);
    878     if (RT_SUCCESS(rc))
    879         return TRUE;
    880     xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to obtain the last resolution requested by the guest, rc=%d.\n", rc);
    881     return FALSE;
    882 }
    883 
    884 
    885 /**
    886  * Query the host as to whether it likes a specific video mode.
    887  *
    888  * @returns the result of the query
    889  * @param   cx     the width of the mode being queried
    890  * @param   cy     the height of the mode being queried
    891  * @param   cBits  the bpp of the mode being queried
    892  */
    893 Bool
    894 vboxHostLikesVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
    895 {
    896     VBOXPtr pVBox = pScrn->driverPrivate;
    897     TRACE_ENTRY();
    898     if (!pVBox->useDevice)
    899         return TRUE;  /* If we can't ask the host then we like everything. */
    900     return VbglR3HostLikesVideoMode(cx, cy, cBits);
    901 }
    902 
    903 /**
    904  * Check if any seamless mode is enabled.
    905  * Seamless is only relevant for the newer Xorg modules.
    906  *
    907  * @returns the result of the query
    908  * (true = seamless enabled, false = seamless not enabled)
    909  * @param   pScrn  Screen info pointer.
    910  */
    911 Bool
    912 vboxGuestIsSeamless(ScrnInfoPtr pScrn)
    913 {
    914     VMMDevSeamlessMode mode;
    915     VBOXPtr pVBox = pScrn->driverPrivate;
    916     TRACE_ENTRY();
    917     if (!pVBox->useDevice)
    918         return FALSE;
    919     if (RT_FAILURE(VbglR3SeamlessGetLastEvent(&mode)))
    920         return FALSE;
    921     return (mode != VMMDev_Seamless_Disabled);
    922 }
    923 
    924 /**
    925  * Save video mode parameters to the registry.
    926  *
    927  * @returns iprt status value
    928  * @param   pszName the name to save the mode parameters under
    929  * @param   cx      mode width
    930  * @param   cy      mode height
    931  * @param   cBits   bits per pixel for the mode
    932  */
    933 Bool
    934 vboxSaveVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
    935 {
    936     VBOXPtr pVBox = pScrn->driverPrivate;
    937     TRACE_ENTRY();
    938     if (!pVBox->useDevice)
    939         return FALSE;
    940     return RT_SUCCESS(VbglR3SaveVideoMode("SavedMode", cx, cy, cBits));
    941 }
    942 
    943 /**
    944  * Retrieve video mode parameters from the registry.
    945  *
    946  * @returns iprt status value
    947  * @param   pszName the name under which the mode parameters are saved
    948  * @param   pcx     where to store the mode width
    949  * @param   pcy     where to store the mode height
    950  * @param   pcBits  where to store the bits per pixel for the mode
    951  */
    952 Bool
    953 vboxRetrieveVideoMode(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits)
    954 {
    955     VBOXPtr pVBox = pScrn->driverPrivate;
    956     TRACE_ENTRY();
    957     if (!pVBox->useDevice)
    958         return FALSE;
    959     int rc = VbglR3RetrieveVideoMode("SavedMode", pcx, pcy, pcBits);
    960     if (RT_SUCCESS(rc))
    961         TRACE_LOG("Retrieved a video mode of %dx%dx%d\n", *pcx, *pcy, *pcBits);
    962     else
    963         TRACE_LOG("Failed to retrieve video mode, error %d\n", rc);
    964     return (RT_SUCCESS(rc));
    965 }
    966 
    967 /**
    968  * Fills a display mode M with a built-in mode of name pszName and dimensions
    969  * cx and cy.
    970  */
    971 static void vboxFillDisplayMode(ScrnInfoPtr pScrn, DisplayModePtr m,
    972                                 const char *pszName, unsigned cx, unsigned cy)
    973 {
    974     VBOXPtr pVBox = pScrn->driverPrivate;
    975     TRACE_LOG("pszName=%s, cx=%u, cy=%u\n", pszName, cx, cy);
    976     m->status        = MODE_OK;
    977     m->type          = M_T_BUILTIN;
    978     /* Older versions of VBox only support screen widths which are a multiple
    979      * of 8 */
    980     if (pVBox->fAnyX)
    981         m->HDisplay  = cx;
    982     else
    983         m->HDisplay  = cx & ~7;
    984     m->HSyncStart    = m->HDisplay + 2;
    985     m->HSyncEnd      = m->HDisplay + 4;
    986     m->HTotal        = m->HDisplay + 6;
    987     m->VDisplay      = cy;
    988     m->VSyncStart    = m->VDisplay + 2;
    989     m->VSyncEnd      = m->VDisplay + 4;
    990     m->VTotal        = m->VDisplay + 6;
    991     m->Clock         = m->HTotal * m->VTotal * 60 / 1000; /* kHz */
    992     if (pszName)
    993     {
    994         if (m->name)
    995             free(m->name);
    996         m->name      = xnfstrdup(pszName);
    997     }
    998 }
    999 
    1000 /** vboxvideo's list of standard video modes */
    1001 struct
    1002 {
    1003     /** mode width */
    1004     uint32_t cx;
    1005     /** mode height */
    1006     uint32_t cy;
    1007 } vboxStandardModes[] =
    1008 {
    1009     { 1600, 1200 },
    1010     { 1440, 1050 },
    1011     { 1280, 960 },
    1012     { 1024, 768 },
    1013     { 800, 600 },
    1014     { 640, 480 },
    1015     { 0, 0 }
    1016 };
    1017 enum
    1018 {
    1019     vboxNumStdModes = sizeof(vboxStandardModes) / sizeof(vboxStandardModes[0])
    1020 };
    1021 
    1022 /**
    1023  * Returns a standard mode which the host likes.  Can be called multiple
    1024  * times with the index returned by the previous call to get a list of modes.
    1025  * @returns  the index of the mode in the list, or 0 if no more modes are
    1026  *           available
    1027  * @param    pScrn   the screen information structure
    1028  * @param    pScrn->bitsPerPixel
    1029  *                   if this is non-null, only modes with this BPP will be
    1030  *                   returned
    1031  * @param    cIndex  the index of the last mode queried, or 0 to query the
    1032  *                   first mode available.  Note: the first index is 1
    1033  * @param    pcx     where to store the mode's width
    1034  * @param    pcy     where to store the mode's height
    1035  * @param    pcBits  where to store the mode's BPP
    1036  */
    1037 unsigned vboxNextStandardMode(ScrnInfoPtr pScrn, unsigned cIndex,
    1038                               uint32_t *pcx, uint32_t *pcy,
    1039                               uint32_t *pcBits)
    1040 {
    1041     XF86ASSERT(cIndex < vboxNumStdModes,
    1042                ("cIndex = %d, vboxNumStdModes = %d\n", cIndex,
    1043                 vboxNumStdModes));
    1044     for (unsigned i = cIndex; i < vboxNumStdModes - 1; ++i)
    1045     {
    1046         uint32_t cBits = pScrn->bitsPerPixel;
    1047         uint32_t cx = vboxStandardModes[i].cx;
    1048         uint32_t cy = vboxStandardModes[i].cy;
    1049 
    1050         if (cBits != 0 && !vboxHostLikesVideoMode(pScrn, cx, cy, cBits))
    1051             continue;
    1052         if (vboxHostLikesVideoMode(pScrn, cx, cy, 32))
    1053             cBits = 32;
    1054         else if (vboxHostLikesVideoMode(pScrn, cx, cy, 16))
    1055             cBits = 16;
    1056         else
    1057             continue;
    1058         if (pcx)
    1059             *pcx = cx;
    1060         if (pcy)
    1061             *pcy = cy;
    1062         if (pcBits)
    1063             *pcBits = cBits;
    1064         return i + 1;
    1065     }
    1066     return 0;
    1067 }
    1068 
    1069 /**
    1070  * Returns the preferred video mode.  The current order of preference is
    1071  * (from highest to least preferred):
    1072  *  - The mode corresponding to the last size hint from the host
    1073  *  - The video mode saved from the last session
    1074  *  - The largest standard mode which the host likes, falling back to
    1075  *    640x480x32 as a worst case
    1076  *  - If the host can't be contacted at all, we return 1024x768x32
    1077  *
    1078  * The return type is void as we guarantee we will return some mode.
    1079  */
    1080 void vboxGetPreferredMode(ScrnInfoPtr pScrn, uint32_t iScreen, uint32_t *pcx,
    1081                           uint32_t *pcy, uint32_t *pcBits)
    1082 {
    1083     /* Query the host for the preferred resolution and colour depth */
    1084     uint32_t cx = 0, cy = 0, iScreenIn = iScreen, cBits = 32;
    1085     VBOXPtr pVBox = pScrn->driverPrivate;
    1086 
    1087     TRACE_LOG("iScreen=%u\n", iScreen);
    1088     bool found = false;
    1089     if (   pVBox->aPreferredSize[iScreen].cx
    1090         && pVBox->aPreferredSize[iScreen].cy)
    1091     {
    1092         cx = pVBox->aPreferredSize[iScreen].cx;
    1093         cy = pVBox->aPreferredSize[iScreen].cy;
    1094         found = true;
    1095     }
    1096     if (pVBox->useDevice)
    1097     {
    1098         if (!found)
    1099             found = vboxGetDisplayChangeRequest(pScrn, &cx, &cy, &cBits,
    1100                                                 &iScreenIn);
    1101         if ((cx == 0) || (cy == 0) || iScreenIn != iScreen)
    1102             found = false;
    1103         if (!found)
    1104             found = vboxRetrieveVideoMode(pScrn, &cx, &cy, &cBits);
    1105         if ((cx == 0) || (cy == 0))
    1106             found = false;
    1107         if (!found)
    1108             found = (vboxNextStandardMode(pScrn, 0, &cx, &cy, &cBits) != 0);
    1109         if (!found)
    1110         {
    1111             /* Last resort */
    1112             cx = 640;
    1113             cy = 480;
    1114             cBits = 32;
    1115         }
    1116     }
    1117     else
    1118     {
    1119         cx = 1024;
    1120         cy = 768;
    1121     }
    1122     if (pcx)
    1123         *pcx = cx;
    1124     if (pcy)
    1125         *pcy = cy;
    1126     if (pcBits)
    1127         *pcBits = cBits;
    1128     TRACE_LOG("cx=%u, cy=%u, cBits=%u\n", cx, cy, cBits);
    1129 }
    1130 
    1131 /* Move a screen mode found to the end of the list, so that RandR will give
    1132  * it the highest priority when a mode switch is requested.  Returns the mode
    1133  * that was previously before the mode in the list in order to allow the
    1134  * caller to continue walking the list. */
    1135 static DisplayModePtr vboxMoveModeToFront(ScrnInfoPtr pScrn,
    1136                                           DisplayModePtr pMode)
    1137 {
    1138     DisplayModePtr pPrev = pMode->prev;
    1139     if (pMode != pScrn->modes)
    1140     {
    1141         pMode->prev->next = pMode->next;
    1142         pMode->next->prev = pMode->prev;
    1143         pMode->next = pScrn->modes;
    1144         pMode->prev = pScrn->modes->prev;
    1145         pMode->next->prev = pMode;
    1146         pMode->prev->next = pMode;
    1147         pScrn->modes = pMode;
    1148     }
    1149     return pPrev;
    1150 }
    1151 
    1152 /**
    1153  * Rewrites the first dynamic mode found which is not the current screen mode
    1154  * to contain the host's currently preferred screen size, then moves that
    1155  * mode to the front of the screen information structure's mode list.
    1156  * Additionally, if the current mode is not dynamic, the second dynamic mode
    1157  * will be set to match the current mode and also added to the front.  This
    1158  * ensures that the user can always reset the current size to kick the driver
    1159  * to update its mode list.
    1160  */
    1161 void vboxWriteHostModes(ScrnInfoPtr pScrn, DisplayModePtr pCurrent)
    1162 {
    1163     uint32_t cx = 0, cy = 0, iDisplay = 0, cBits = 0;
    1164     DisplayModePtr pMode;
    1165     bool found = false;
    1166 
    1167     TRACE_ENTRY();
    1168     vboxGetPreferredMode(pScrn, 0, &cx, &cy, &cBits);
    1169 #ifdef DEBUG
    1170     /* Count the number of modes for sanity */
    1171     unsigned cModes = 1, cMode = 0;
    1172     DisplayModePtr pCount;
    1173     for (pCount = pScrn->modes; ; pCount = pCount->next, ++cModes)
    1174         if (pCount->next == pScrn->modes)
    1175             break;
    1176 #endif
    1177     for (pMode = pScrn->modes; ; pMode = pMode->next)
    1178     {
    1179 #ifdef DEBUG
    1180         XF86ASSERT (cMode++ < cModes, (NULL));
    1181 #endif
    1182         if (   pMode != pCurrent
    1183             && !strcmp(pMode->name, "VBoxDynamicMode"))
    1184         {
    1185             if (!found)
    1186                 vboxFillDisplayMode(pScrn, pMode, NULL, cx, cy);
    1187             else if (pCurrent)
    1188                 vboxFillDisplayMode(pScrn, pMode, NULL, pCurrent->HDisplay,
    1189                                     pCurrent->VDisplay);
    1190             found = true;
    1191             pMode = vboxMoveModeToFront(pScrn, pMode);
    1192         }
    1193         if (pMode->next == pScrn->modes)
    1194             break;
    1195     }
    1196     XF86ASSERT (found,
    1197                 ("vboxvideo: no free dynamic mode found.  Exiting.\n"));
    1198     XF86ASSERT (   (pScrn->modes->HDisplay == (long) cx)
    1199                 || (   (pScrn->modes->HDisplay == pCurrent->HDisplay)
    1200                     && (pScrn->modes->next->HDisplay == (long) cx)),
    1201                 ("pScrn->modes->HDisplay=%u, pScrn->modes->next->HDisplay=%u\n",
    1202                  pScrn->modes->HDisplay, pScrn->modes->next->HDisplay));
    1203     XF86ASSERT (   (pScrn->modes->VDisplay == (long) cy)
    1204                 || (   (pScrn->modes->VDisplay == pCurrent->VDisplay)
    1205                     && (pScrn->modes->next->VDisplay == (long) cy)),
    1206                 ("pScrn->modes->VDisplay=%u, pScrn->modes->next->VDisplay=%u\n",
    1207                  pScrn->modes->VDisplay, pScrn->modes->next->VDisplay));
    1208 }
    1209 
    1210 /**
    1211  * Allocates an empty display mode and links it into the doubly linked list of
    1212  * modes pointed to by pScrn->modes.  Returns a pointer to the newly allocated
    1213  * memory.
    1214  */
    1215 static DisplayModePtr vboxAddEmptyScreenMode(ScrnInfoPtr pScrn)
    1216 {
    1217     DisplayModePtr pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
    1218 
    1219     TRACE_ENTRY();
    1220     if (!pScrn->modes)
    1221     {
    1222         pScrn->modes = pMode;
    1223         pMode->next = pMode;
    1224         pMode->prev = pMode;
    1225     }
    1226     else
    1227     {
    1228         pMode->next = pScrn->modes;
    1229         pMode->prev = pScrn->modes->prev;
    1230         pMode->next->prev = pMode;
    1231         pMode->prev->next = pMode;
    1232     }
    1233     return pMode;
    1234 }
    1235 
    1236 /**
    1237  * Create display mode entries in the screen information structure for each
    1238  * of the initial graphics modes that we wish to support.  This includes:
    1239  *  - An initial mode, of the size requested by the caller
    1240  *  - Two dynamic modes, one of which will be updated to match the last size
    1241  *    hint from the host on each mode switch, but initially also of the
    1242  *    requested size
    1243  *  - Several standard modes, if possible ones that the host likes
    1244  *  - Any modes that the user requested in xorg.conf/XFree86Config
    1245  */
    1246 void vboxAddModes(ScrnInfoPtr pScrn, uint32_t cxInit, uint32_t cyInit)
    1247 {
    1248     unsigned cx = 0, cy = 0, cIndex = 0;
    1249     /* For reasons related to the way RandR 1.1 is implemented, we need to
    1250      * make sure that the initial mode (more precisely, a mode equal to the
    1251      * initial virtual resolution) is always present in the mode list.  RandR
    1252      * has the assumption build in that there will either be a mode of that
    1253      * size present at all times, or that the first mode in the list will
    1254      * always be smaller than the initial virtual resolution.  Since our
    1255      * approach to dynamic resizing isn't quite the way RandR was intended to
    1256      * be, and breaks the second assumption, we guarantee the first. */
    1257     DisplayModePtr pMode = vboxAddEmptyScreenMode(pScrn);
    1258     vboxFillDisplayMode(pScrn, pMode, "VBoxInitialMode", cxInit, cyInit);
    1259     /* Create our two dynamic modes. */
    1260     pMode = vboxAddEmptyScreenMode(pScrn);
    1261     vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
    1262     pMode = vboxAddEmptyScreenMode(pScrn);
    1263     vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
    1264     /* Add standard modes supported by the host */
    1265     for ( ; ; )
    1266     {
    1267         char szName[256];
    1268         cIndex = vboxNextStandardMode(pScrn, cIndex, &cx, &cy, NULL);
    1269         if (cIndex == 0)
    1270             break;
    1271         sprintf(szName, "VBox-%ux%u", cx, cy);
    1272         pMode = vboxAddEmptyScreenMode(pScrn);
    1273         vboxFillDisplayMode(pScrn, pMode, szName, cx, cy);
    1274     }
    1275     /* And finally any modes specified by the user.  We assume here that
    1276      * the mode names reflect the mode sizes. */
    1277     for (unsigned i = 0;    pScrn->display->modes != NULL
    1278                          && pScrn->display->modes[i] != NULL; i++)
    1279     {
    1280         if (sscanf(pScrn->display->modes[i], "%ux%u", &cx, &cy) == 2)
    1281         {
    1282             pMode = vboxAddEmptyScreenMode(pScrn);
    1283             vboxFillDisplayMode(pScrn, pMode, pScrn->display->modes[i], cx, cy);
    1284         }
    1285     }
    1286 }
  • trunk/src/VBox/Additions/x11/vboxvideo/vboxutils.c

    r35775 r35843  
    2727#include <iprt/string.h>
    2828#include "compiler.h"
    29 #include "cursorstr.h"
    3029
    3130#include "vboxvideo.h"
    32 
    33 #define VBOX_MAX_CURSOR_WIDTH 64
    34 #define VBOX_MAX_CURSOR_HEIGHT 64
    35 
    36 /**************************************************************************
    37 * Debugging functions and macros                                          *
    38 **************************************************************************/
    39 
    40 /* #define DEBUG_POINTER */
    41 
    42 #ifdef DEBUG
    43 # define PUT_PIXEL(c) ErrorF ("%c", c)
    44 #else /* DEBUG_VIDEO not defined */
    45 # define PUT_PIXEL(c) do { } while(0)
    46 #endif /* DEBUG_VIDEO not defined */
    47 
    48 /** Macro to printf an error message and return from a function */
    49 #define RETERROR(scrnIndex, RetVal, ...) \
    50     do \
    51     { \
    52         xf86DrvMsg(scrnIndex, X_ERROR, __VA_ARGS__); \
    53         return RetVal; \
    54     } \
    55     while (0)
    56 
    57 /** Structure to pass cursor image data between realise_cursor() and
    58  * load_cursor_image().  The members match the parameters to
    59  * @a VBoxHGSMIUpdatePointerShape(). */
    60 struct vboxCursorImage
    61 {
    62     uint32_t fFlags;
    63     uint32_t cHotX;
    64     uint32_t cHotY;
    65     uint32_t cWidth;
    66     uint32_t cHeight;
    67     uint8_t *pPixels;
    68     uint32_t cbLength;
    69 };
    70 
    71 #ifdef DEBUG_POINTER
    72 static void
    73 vbox_show_shape(unsigned short w, unsigned short h, CARD32 bg, unsigned char *image)
    74 {
    75     size_t x, y;
    76     unsigned short pitch;
    77     CARD32 *color;
    78     unsigned char *mask;
    79     size_t sizeMask;
    80 
    81     image    += sizeof(struct vboxCursorImage);
    82     mask      = image;
    83     pitch     = (w + 7) / 8;
    84     sizeMask  = (pitch * h + 3) & ~3;
    85     color     = (CARD32 *)(image + sizeMask);
    86 
    87     TRACE_ENTRY();
    88     for (y = 0; y < h; ++y, mask += pitch, color += w)
    89     {
    90         for (x = 0; x < w; ++x)
    91         {
    92             if (mask[x / 8] & (1 << (7 - (x % 8))))
    93                 ErrorF (" ");
    94             else
    95             {
    96                 CARD32 c = color[x];
    97                 if (c == bg)
    98                     ErrorF("Y");
    99                 else
    100                     ErrorF("X");
    101             }
    102         }
    103         ErrorF("\n");
    104     }
    105 }
    106 #endif
    107 
    108 /**************************************************************************
    109 * Helper functions and macros                                             *
    110 **************************************************************************/
    111 
    112 /* This is called by the X server every time it loads a new cursor to see
    113  * whether our "cursor hardware" can handle the cursor.  This provides us with
    114  * a mechanism (the only one!) to switch back from a software to a hardware
    115  * cursor. */
    116 static Bool
    117 vbox_host_uses_hwcursor(ScrnInfoPtr pScrn)
    118 {
    119     Bool rc = TRUE;
    120     uint32_t fFeatures = 0;
    121     VBOXPtr pVBox = pScrn->driverPrivate;
    122 
    123     /* We may want to force the use of a software cursor.  Currently this is
    124      * needed if the guest uses a large virtual resolution, as in this case
    125      * the host and guest tend to disagree about the pointer location. */
    126     if (pVBox->forceSWCursor)
    127         rc = FALSE;
    128     /* Query information about mouse integration from the host. */
    129     if (rc) {
    130         int vrc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
    131         if (RT_FAILURE(vrc)) {
    132             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    133                      "Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", vrc);
    134             rc = FALSE;
    135         }
    136     }
    137     /* If we got the information from the host then make sure the host wants
    138      * to draw the pointer. */
    139     if (rc)
    140     {
    141         if (   (fFeatures & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
    142 #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5
    143                 /* As of this version (server 1.6) all major Linux releases
    144                  * are known to handle USB tablets correctly. */
    145             || (fFeatures & VMMDEV_MOUSE_HOST_HAS_ABS_DEV)
    146 #endif
    147             )
    148             /* Assume this will never be unloaded as long as the X session is
    149              * running. */
    150             pVBox->guestCanAbsolute = TRUE;
    151         if (   (fFeatures & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER)
    152             || !pVBox->guestCanAbsolute
    153             || !(fFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
    154            )
    155             rc = FALSE;
    156     }
    157     return rc;
    158 }
    15931
    16032/**************************************************************************
    16133* Main functions                                                          *
    16234**************************************************************************/
    163 
    164 void
    165 vbox_close(ScrnInfoPtr pScrn, VBOXPtr pVBox)
    166 {
    167     TRACE_ENTRY();
    168 
    169     xf86DestroyCursorInfoRec(pVBox->pCurs);
    170     pVBox->pCurs = NULL;
    171     TRACE_EXIT();
    172 }
    17335
    17436/**
     
    333195
    334196Bool
    335 vbox_init(int scrnIndex, VBOXPtr pVBox)
    336 {
    337     Bool rc = TRUE;
    338     int vrc;
    339     uint32_t fMouseFeatures = 0;
    340 
    341     TRACE_ENTRY();
    342     vrc = VbglR3Init();
    343     if (RT_FAILURE(vrc))
    344     {
    345         xf86DrvMsg(scrnIndex, X_ERROR,
    346                    "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",
    347                    vrc);
    348         rc = FALSE;
    349     }
    350     pVBox->useDevice = rc;
    351     /* We can't switch to a software cursor at will without help from
    352      * VBoxClient.  So tell that to the host and wait for VBoxClient to
    353      * change this. */
    354     vrc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
    355     if (RT_SUCCESS(vrc))
    356         VbglR3SetMouseStatus(  fMouseFeatures
    357                              | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
    358     return rc;
    359 }
    360 
    361 Bool
    362197vbox_open(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
    363198{
     
    372207{
    373208    return pVBox->useDevice;
    374 }
    375 
    376 static void
    377 vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
    378 {
    379     int rc;
    380 
    381     rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, 0, 0, 0, 0, 0, NULL, 0);
    382     if (RT_FAILURE(rc))
    383     {
    384         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not hide the virtual mouse pointer, VBox error %d.\n", rc);
    385         /* Play safe, and disable the hardware cursor until the next mode
    386          * switch, since obviously something happened that we didn't
    387          * anticipate. */
    388         pVBox->forceSWCursor = TRUE;
    389     }
    390 }
    391 
    392 static void
    393 vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
    394 {
    395     int rc;
    396 
    397     if (!vbox_host_uses_hwcursor(pScrn))
    398         return;
    399     rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, VBOX_MOUSE_POINTER_VISIBLE,
    400                                      0, 0, 0, 0, NULL, 0);
    401     if (RT_FAILURE(rc)) {
    402         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
    403         /* Play safe, and disable the hardware cursor until the next mode
    404          * switch, since obviously something happened that we didn't
    405          * anticipate. */
    406         pVBox->forceSWCursor = TRUE;
    407     }
    408 }
    409 
    410 static void
    411 vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
    412                            unsigned char *pvImage)
    413 {
    414     int rc;
    415     struct vboxCursorImage *pImage;
    416     pImage = (struct vboxCursorImage *)pvImage;
    417 
    418 #ifdef DEBUG_POINTER
    419     vbox_show_shape(pImage->cWidth, pImage->cHeight, 0, pvImage);
    420 #endif
    421 
    422     rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, pImage->fFlags,
    423              pImage->cHotX, pImage->cHotY, pImage->cWidth, pImage->cHeight,
    424              pImage->pPixels, pImage->cbLength);
    425     if (RT_FAILURE(rc)) {
    426         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,  "Unable to set the virtual mouse pointer image.\n");
    427         /* Play safe, and disable the hardware cursor until the next mode
    428          * switch, since obviously something happened that we didn't
    429          * anticipate. */
    430         pVBox->forceSWCursor = TRUE;
    431     }
    432 }
    433 
    434 static void
    435 vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
    436 {
    437     NOREF(pScrn);
    438     NOREF(bg);
    439     NOREF(fg);
    440     /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
    441 }
    442 
    443 
    444 static void
    445 vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
    446 {
    447     /* Nothing to do here, as we are telling the guest where the mouse is,
    448      * not vice versa. */
    449     NOREF(pScrn);
    450     NOREF(x);
    451     NOREF(y);
    452 }
    453 
    454 static void
    455 vbox_hide_cursor(ScrnInfoPtr pScrn)
    456 {
    457     VBOXPtr pVBox = pScrn->driverPrivate;
    458 
    459     vbox_vmm_hide_cursor(pScrn, pVBox);
    460 }
    461 
    462 static void
    463 vbox_show_cursor(ScrnInfoPtr pScrn)
    464 {
    465     VBOXPtr pVBox = pScrn->driverPrivate;
    466 
    467     vbox_vmm_show_cursor(pScrn, pVBox);
    468 }
    469 
    470 static void
    471 vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
    472 {
    473     VBOXPtr pVBox = pScrn->driverPrivate;
    474 
    475     vbox_vmm_load_cursor_image(pScrn, pVBox, image);
    476 }
    477 
    478 static Bool
    479 vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
    480 {
    481     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    482     return vbox_host_uses_hwcursor(pScrn);
    483 }
    484 
    485 static unsigned char
    486 color_to_byte(unsigned c)
    487 {
    488     return (c >> 8) & 0xff;
    489 }
    490 
    491 static unsigned char *
    492 vbox_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     struct vboxCursorImage *pImage;
    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     sizeRequest = sizeMask + sizeRgba + sizeof(*pImage);
    522 
    523     p = c = calloc (1, sizeRequest);
    524     if (!c)
    525         RETERROR(scrnIndex, NULL,
    526                  "Error failed to alloc %lu bytes for cursor\n",
    527                  (unsigned long) sizeRequest);
    528 
    529     pImage = (struct vboxCursorImage *)p;
    530     pImage->pPixels = m = p + sizeof(*pImage);
    531     cp = (CARD32 *)(m + sizeMask);
    532 
    533     TRACE_LOG ("w=%d h=%d sm=%d sr=%d p=%d\n",
    534            w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
    535     TRACE_LOG ("m=%p c=%p cp=%p\n", m, c, (void *)cp);
    536 
    537     fc = color_to_byte (pCurs->foreBlue)
    538       | (color_to_byte (pCurs->foreGreen) << 8)
    539       | (color_to_byte (pCurs->foreRed)   << 16);
    540 
    541     bc = color_to_byte (pCurs->backBlue)
    542       | (color_to_byte (pCurs->backGreen) << 8)
    543       | (color_to_byte (pCurs->backRed)   << 16);
    544 
    545     /*
    546      * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
    547      * Xorg:
    548      *   The mask is a bitmap indicating which parts of the cursor are
    549      *   transparent and which parts are drawn. The source is a bitmap
    550      *   indicating which parts of the non-transparent portion of the
    551      *   the cursor should be painted in the foreground color and which
    552      *   should be painted in the background color. By default, set bits
    553      *   indicate the opaque part of the mask bitmap and clear bits
    554      *   indicate the transparent part.
    555      * VBox:
    556      *   The color data is the XOR mask. The AND mask bits determine
    557      *   which pixels of the color data (XOR mask) will replace (overwrite)
    558      *   the screen pixels (AND mask bit = 0) and which ones will be XORed
    559      *   with existing screen pixels (AND mask bit = 1).
    560      *   For example when you have the AND mask all 0, then you see the
    561      *   correct mouse pointer image surrounded by black square.
    562      */
    563     for (pm = bitsp->mask, ps = bitsp->source, y = 0;
    564          y < h;
    565          ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
    566     {
    567         for (x = 0; x < w; ++x)
    568         {
    569             if (pm[x / 8] & (1 << (x % 8)))
    570             {
    571                 /* opaque, leave AND mask bit at 0 */
    572                 if (ps[x / 8] & (1 << (x % 8)))
    573                 {
    574                     *cp++ = fc;
    575                     PUT_PIXEL('X');
    576                 }
    577                 else
    578                 {
    579                     *cp++ = bc;
    580                     PUT_PIXEL('*');
    581                 }
    582             }
    583             else
    584             {
    585                 /* transparent, set AND mask bit */
    586                 m[x / 8] |= 1 << (7 - (x % 8));
    587                 /* don't change the screen pixel */
    588                 *cp++ = 0;
    589                 PUT_PIXEL(' ');
    590             }
    591         }
    592         PUT_PIXEL('\n');
    593     }
    594 
    595     pImage->cWidth   = w;
    596     pImage->cHeight  = h;
    597     pImage->cHotX    = bitsp->xhot;
    598     pImage->cHotY    = bitsp->yhot;
    599     pImage->fFlags   = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE;
    600     pImage->cbLength = sizeRequest - sizeof(*pImage);
    601 
    602 #ifdef DEBUG_POINTER
    603     ErrorF("shape = %p\n", p);
    604     vbox_show_shape(w, h, bc, c);
    605 #endif
    606 
    607     return p;
    608 }
    609 
    610 #ifdef ARGB_CURSOR
    611 static Bool
    612 vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
    613 {
    614     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    615     Bool rc = TRUE;
    616 
    617     if (!vbox_host_uses_hwcursor(pScrn))
    618         rc = FALSE;
    619     if (   rc
    620         && (   (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
    621             || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
    622             || (pScrn->bitsPerPixel <= 8)
    623            )
    624        )
    625         rc = FALSE;
    626 #ifndef VBOXVIDEO_13
    627     /* Evil hack - we use this as another way of poking the driver to update
    628      * our list of video modes. */
    629     vboxWriteHostModes(pScrn, pScrn->currentMode);
    630 #endif
    631     return rc;
    632 }
    633 
    634 
    635 static void
    636 vbox_load_cursor_argb(ScrnInfoPtr pScrn, CursorPtr pCurs)
    637 {
    638     VBOXPtr pVBox;
    639     VMMDevReqMousePointer *reqp;
    640     CursorBitsPtr bitsp;
    641     unsigned short w, h;
    642     unsigned short cx, cy;
    643     unsigned char *pm;
    644     CARD32 *pc;
    645     size_t sizeData, sizeMask;
    646     CARD8 *p;
    647     int scrnIndex;
    648     uint32_t fFlags =   VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE
    649                       | VBOX_MOUSE_POINTER_ALPHA;
    650     int rc;
    651 
    652     pVBox = pScrn->driverPrivate;
    653     bitsp = pCurs->bits;
    654     w     = bitsp->width;
    655     h     = bitsp->height;
    656     scrnIndex = pScrn->scrnIndex;
    657 
    658     /* Mask must be generated for alpha cursors, that is required by VBox. */
    659     /* note: (michael) the next struct must be 32bit aligned. */
    660     sizeMask  = ((w + 7) / 8 * h + 3) & ~3;
    661 
    662     if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
    663         RETERROR(scrnIndex, ,
    664                  "Error invalid cursor dimensions %dx%d\n", w, h);
    665 
    666     if ((bitsp->xhot > w) || (bitsp->yhot > h))
    667         RETERROR(scrnIndex, ,
    668                  "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
    669                  bitsp->xhot, bitsp->yhot, w, h);
    670 
    671     sizeData = w * h * 4 + sizeMask;
    672     p = calloc(1, sizeData);
    673     if (!p)
    674         RETERROR(scrnIndex, ,
    675                  "Error failed to alloc %lu bytes for cursor\n",
    676                  (unsigned long)sizeData);
    677 
    678     memcpy(p + sizeMask, bitsp->argb, w * h * 4);
    679 
    680     /* Emulate the AND mask. */
    681     pm = p;
    682     pc = bitsp->argb;
    683 
    684     /* Init AND mask to 1 */
    685     memset(pm, 0xFF, sizeMask);
    686 
    687     /*
    688      * The additions driver must provide the AND mask for alpha cursors. The host frontend
    689      * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
    690      * But if the host does not support ARGB, then it simply uses the AND mask and the color
    691      * data to draw a normal color cursor.
    692      */
    693     for (cy = 0; cy < h; cy++)
    694     {
    695         unsigned char bitmask = 0x80;
    696 
    697         for (cx = 0; cx < w; cx++, bitmask >>= 1)
    698         {
    699             if (bitmask == 0)
    700                 bitmask = 0x80;
    701 
    702             if (pc[cx] >= 0xF0000000)
    703                 pm[cx / 8] &= ~bitmask;
    704         }
    705 
    706         /* Point to next source and dest scans */
    707         pc += w;
    708         pm += (w + 7) / 8;
    709     }
    710 
    711     rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, fFlags, bitsp->xhot,
    712                                      bitsp->yhot, w, h, p, sizeData);
    713     free(p);
    714 }
    715 #endif
    716 
    717 Bool
    718 vbox_cursor_init(ScreenPtr pScreen)
    719 {
    720     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    721     VBOXPtr pVBox = pScrn->driverPrivate;
    722     xf86CursorInfoPtr pCurs = NULL;
    723     Bool rc = TRUE;
    724 
    725     TRACE_ENTRY();
    726     if (!pVBox->fHaveHGSMI)
    727         return FALSE;
    728     pVBox->pCurs = pCurs = xf86CreateCursorInfoRec();
    729     if (!pCurs) {
    730         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    731                    "Failed to create X Window cursor information structures for virtual mouse.\n");
    732         rc = FALSE;
    733     }
    734     if (rc) {
    735         pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
    736         pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
    737         pCurs->Flags =   HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
    738                        | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
    739                        | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
    740 
    741         pCurs->SetCursorColors   = vbox_set_cursor_colors;
    742         pCurs->SetCursorPosition = vbox_set_cursor_position;
    743         pCurs->LoadCursorImage   = vbox_load_cursor_image;
    744         pCurs->HideCursor        = vbox_hide_cursor;
    745         pCurs->ShowCursor        = vbox_show_cursor;
    746         pCurs->UseHWCursor       = vbox_use_hw_cursor;
    747         pCurs->RealizeCursor     = vbox_realize_cursor;
    748 
    749 #ifdef ARGB_CURSOR
    750         pCurs->UseHWCursorARGB   = vbox_use_hw_cursor_argb;
    751         pCurs->LoadCursorARGB    = vbox_load_cursor_argb;
    752 #endif
    753 
    754         /* Hide the host cursor before we initialise if we wish to use a
    755          * software cursor. */
    756         if (pVBox->forceSWCursor)
    757             vbox_vmm_hide_cursor(pScrn, pVBox);
    758         rc = xf86InitCursor(pScreen, pCurs);
    759     }
    760     if (!rc)
    761         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    762                    "Failed to enable mouse pointer integration.\n");
    763     if (!rc && (pCurs != NULL))
    764         xf86DestroyCursorInfoRec(pCurs);
    765     return rc;
    766209}
    767210
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette