Пример #1
0
/* Checks if there's a pending video mode change hint,
 * and fills pPendingMode with associated info.
 * returns TRUE if there's a pending change. Otherwise returns FALSE.
 */
static BOOLEAN
VBoxMPCheckPendingVideoMode(PVBOXMP_DEVEXT pExt, PVIDEO_MODE_INFORMATION pPendingMode)
{
    uint32_t xres=0, yres=0, bpp=0, display=0;

    /* Check if there's a pending display change request for this display */
    if (VBoxQueryDisplayRequest(&xres, &yres, &bpp, &display) && (xres || yres || bpp))
    {
        if (display >= RT_ELEMENTS(g_CustomVideoModes))
        {
            /*display = RT_ELEMENTS(g_CustomVideoModes) - 1;*/
            WARN(("VBoxQueryDisplayRequest returned invalid display number %d", display));
            return FALSE;
        }
    }
    else
    {
        LOG(("no pending request"));
        return FALSE;
    }

    /* Correct video mode params and check if host likes it */
    if (VBoxMPValidateVideoModeParams(pExt, display, xres, yres, bpp))
    {
        VBoxFillVidModeInfo(pPendingMode, xres, yres, bpp, display, 0);
        return TRUE;
    }

    return FALSE;
}
Пример #2
0
bool VBoxWddmFillMode(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, VIDEO_MODE_INFORMATION *pInfo, D3DDDIFORMAT enmFormat, ULONG w, ULONG h)
{
    switch (enmFormat)
    {
        case D3DDDIFMT_A8R8G8B8:
            if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, w, h, 32))
            {
                WARN(("unsupported mode info for format(%d)", enmFormat));
                return false;
            }
            VBoxFillVidModeInfo(pInfo, w, h, 32, 0, 0);
            return true;
        case D3DDDIFMT_R8G8B8:
            if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, w, h, 24))
            {
                WARN(("unsupported mode info for format(%d)", enmFormat));
                return false;
            }
            VBoxFillVidModeInfo(pInfo, w, h, 24, 0, 0);
            return true;
        case D3DDDIFMT_R5G6B5:
            if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, w, h, 16))
            {
                WARN(("unsupported mode info for format(%d)", enmFormat));
                return false;
            }
            VBoxFillVidModeInfo(pInfo, w, h, 16, 0, 0);
            return true;
        case D3DDDIFMT_P8:
            if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, w, h, 8))
            {
                WARN(("unsupported mode info for format(%d)", enmFormat));
                return false;
            }
            VBoxFillVidModeInfo(pInfo, w, h, 8, 0, 0);
            return true;
        default:
            WARN(("unsupported enmFormat(%d)", enmFormat));
            AssertBreakpoint();
            break;
    }

    return false;
}
Пример #3
0
/* Makes a table of video modes consisting of:
 * Default modes
 * Custom modes manually added to registry
 * Custom modes for all displays (either from a display change hint or stored in registry)
 * 2 special modes, for a pending display change for this adapter. See comments below.
 */
void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt)
{
    uint32_t cStandartModes;
    BOOLEAN bPending, bHaveSpecial;
    VIDEO_MODE_INFORMATION specialMode;

    /* Fill table with standart modes and ones manually added to registry.
     * Up to VBOXMP_MAX_VIDEO_MODES elements can be used, the rest is reserved
     * for custom mode alternating indexes.
     */
    cStandartModes = VBoxMPFillModesTable(pExt, pExt->iDevice, pExt->aVideoModes, VBOXMP_MAX_VIDEO_MODES, NULL);

    /* Add custom mode for this display to the table */
    /* Make 2 entries in the video mode table. */
    uint32_t iModeBase = cStandartModes;

    /* Take the alternating index into account. */
    BOOLEAN bAlternativeIndex = (pExt->iInvocationCounter % 2)? TRUE: FALSE;

    uint32_t iSpecialMode = iModeBase + (bAlternativeIndex? 1: 0);
    uint32_t iStandardMode = iModeBase + (bAlternativeIndex? 0: 1);

    /* Fill the special mode. */
    memcpy(&pExt->aVideoModes[iSpecialMode], &g_CustomVideoModes[pExt->iDevice], sizeof(VIDEO_MODE_INFORMATION));
    pExt->aVideoModes[iSpecialMode].ModeIndex = iSpecialMode + 1;

    /* Wipe the other entry so it is not selected. */
    memcpy(&pExt->aVideoModes[iStandardMode], &pExt->aVideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
    pExt->aVideoModes[iStandardMode].ModeIndex = iStandardMode + 1;

    LOG(("added special mode[%d] %dx%d:%d for display %d\n",
         iSpecialMode,
         pExt->aVideoModes[iSpecialMode].VisScreenWidth,
         pExt->aVideoModes[iSpecialMode].VisScreenHeight,
         pExt->aVideoModes[iSpecialMode].BitsPerPlane,
         pExt->iDevice));

    /* Check if host wants us to switch video mode and it's for this adapter */
    bPending = VBoxMPCheckPendingVideoMode(pExt, &specialMode);
    bHaveSpecial = bPending && (pExt->iDevice == specialMode.ModeIndex);
    LOG(("bPending %d, pExt->iDevice %d, specialMode.ModeIndex %d",
          bPending, pExt->iDevice, specialMode.ModeIndex));

    /* Check the startup case */
    if (!bHaveSpecial && VBoxMPIsStartingUp(pExt, pExt->iDevice))
    {
        uint32_t xres=0, yres=0, bpp=0;
        LOG(("Startup for screen %d", pExt->iDevice));
        /* Check if we could make valid mode from values stored to registry */
        if (VBoxMPValidateVideoModeParams(pExt, pExt->iDevice, xres, yres, bpp))
        {
            LOG(("Startup for screen %d validated %dx%d %d", pExt->iDevice, xres, yres, bpp));
            VBoxFillVidModeInfo(&specialMode, xres, yres, bpp, 0, 0);
            bHaveSpecial = TRUE;
        }
    }

    /* Update number of modes. Each display has 2 entries for alternating custom mode index. */
    pExt->cVideoModes = cStandartModes + 2;

    if (bHaveSpecial)
    {
        /* We need to alternate mode index entry for a pending mode change,
         * else windows will ignore actual mode change call.
         * Only alternate index if one of mode parameters changed and
         * regardless of conditions always add 2 entries to the table.
         */
        BOOLEAN bAlternativeIndex = FALSE;

        BOOLEAN bChanged = (pExt->Prev_xres!=specialMode.VisScreenWidth
                            || pExt->Prev_yres!=specialMode.VisScreenHeight
                            || pExt->Prev_bpp!=specialMode.BitsPerPlane);

        LOG(("prev %dx%dx%d, special %dx%dx%d",
             pExt->Prev_xres, pExt->Prev_yres, pExt->Prev_bpp,
             specialMode.VisScreenWidth, specialMode.VisScreenHeight, specialMode.BitsPerPlane));

        if (bChanged)
        {
            pExt->Prev_xres = specialMode.VisScreenWidth;
            pExt->Prev_yres = specialMode.VisScreenHeight;
            pExt->Prev_bpp = specialMode.BitsPerPlane;
        }

        /* Check if we need to alternate the index */
        if (!VBoxMPIsStartingUp(pExt, pExt->iDevice))
        {
            if (bChanged)
            {
                pExt->iInvocationCounter++;
            }

            if (pExt->iInvocationCounter % 2)
            {
                bAlternativeIndex = TRUE;
            }
        }

        uint32_t iSpecialModeElement = cStandartModes + (bAlternativeIndex? 1: 0);
        uint32_t iSpecialModeElementOld = cStandartModes + (bAlternativeIndex? 0: 1);

        LOG(("add special mode[%d] %dx%d:%d for display %d (bChanged=%d, bAlternativeIndex=%d)",
             iSpecialModeElement, specialMode.VisScreenWidth, specialMode.VisScreenHeight, specialMode.BitsPerPlane,
             pExt->iDevice, bChanged, bAlternativeIndex));

        /* Add special mode to the table
         * Note: Y offset isn't used for a host-supplied modes
         */
        specialMode.ModeIndex = iSpecialModeElement + 1;
        memcpy(&pExt->aVideoModes[iSpecialModeElement], &specialMode, sizeof(VIDEO_MODE_INFORMATION));

        /* Save special mode in the custom modes table */
        memcpy(&g_CustomVideoModes[pExt->iDevice], &specialMode, sizeof(VIDEO_MODE_INFORMATION));

        /* Wipe the old entry so the special mode will be found in the new positions. */
        memcpy(&pExt->aVideoModes[iSpecialModeElementOld], &pExt->aVideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
        pExt->aVideoModes[iSpecialModeElementOld].ModeIndex = iSpecialModeElementOld + 1;

        /* Save special mode info to registry */
        VBoxMPRegSaveModeInfo(pExt, pExt->iDevice, &specialMode);
    }

#if defined(LOG_ENABLED)
    do
    {
        LOG(("Filled %d modes for display %d", pExt->cVideoModes, pExt->iDevice));

        for (uint32_t i=0; i < pExt->cVideoModes; ++i)
        {
            LOG(("Mode[%2d]: %4dx%4d:%2d (idx=%d)",
                 i, pExt->aVideoModes[i].VisScreenWidth, pExt->aVideoModes[i].VisScreenHeight,
                 pExt->aVideoModes[i].BitsPerPlane, pExt->aVideoModes[i].ModeIndex));
        }
    } while (0);
#endif
}
Пример #4
0
/* Helper function to dynamically build our table of standard video
 * modes. We take the amount of VRAM and create modes with standard
 * geometries until we've either reached the maximum number of modes
 * or the available VRAM does not allow for additional modes.
 * We also check registry for manually added video modes.
 * Returns number of modes added to the table.
 */
static uint32_t
VBoxMPFillModesTable(PVBOXMP_DEVEXT pExt, int iDisplay, PVIDEO_MODE_INFORMATION pModesTable, size_t tableSize,
                     int32_t *pPrefModeIdx)
{
    /* the resolution matrix */
    struct
    {
        uint16_t xRes;
        uint16_t yRes;
    } resolutionMatrix[] =
    {
        /* standard modes */
        { 640,   480 },
        { 800,   600 },
        { 1024,  768 },
        { 1152,  864 },
        { 1280,  960 },
        { 1280, 1024 },
        { 1400, 1050 },
        { 1600, 1200 },
        { 1920, 1440 },
#ifndef VBOX_WITH_WDDM
        /* multi screen modes with 1280x1024 */
        { 2560, 1024 },
        { 3840, 1024 },
        { 5120, 1024 },
        /* multi screen modes with 1600x1200 */
        { 3200, 1200 },
        { 4800, 1200 },
        { 6400, 1200 },
#endif
    };

#ifdef VBOX_XPDM_MINIPORT
    ULONG vramSize = pExt->pPrimary->u.primary.ulMaxFrameBufferSize;
#else
    ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(pExt);
    vramSize /= pExt->u.primary.commonInfo.cDisplays;
# ifdef VBOX_WDDM_WIN8
    if (!g_VBoxDisplayOnly)
# endif
    {
        /* at least two surfaces will be needed: primary & shadow */
        vramSize /= 2;
    }
    vramSize &= ~PAGE_OFFSET_MASK;
#endif

    uint32_t iMode=0, iPrefIdx=0;
    /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
    size_t   maxModesPerColorDepth = VBOXMP_MAX_VIDEO_MODES / 2 / 4;

    /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
     * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
     * This resolution could be rejected by a low resolution host (netbooks, etc).
     */
#ifdef VBOX_WITH_8BPP_MODES
    int bytesPerPixel=1;
#else
    int bytesPerPixel=2;
#endif
    for (; bytesPerPixel<=4; bytesPerPixel++)
    {
        int bitsPerPixel = 8*bytesPerPixel;

        if (800*600*bytesPerPixel > (LONG)vramSize)
        {
            /* we don't have enough VRAM for this mode */
            continue;
        }

        if (!VBoxMPValidateVideoModeParamsGuest(pExt, iMode, 800, 600, bitsPerPixel))
            continue;

        VBoxFillVidModeInfo(&pModesTable[iMode], 800, 600, bitsPerPixel, iMode+1, 0);

        if (32==bitsPerPixel)
        {
            iPrefIdx = iMode;
        }
        ++iMode;
    }

    /* Query yoffset from the host */
    ULONG yOffset = VBoxGetHeightReduction();

    /* Iterate through our static resolution table and add supported video modes for different bpp's */
#ifdef VBOX_WITH_8BPP_MODES
    bytesPerPixel=1;
#else
    bytesPerPixel=2;
#endif
    for (; bytesPerPixel<=4; bytesPerPixel++)
    {
        int bitsPerPixel = 8*bytesPerPixel;
        size_t cAdded, resIndex;

        for (cAdded=0, resIndex=0; resIndex<RT_ELEMENTS(resolutionMatrix) && cAdded<maxModesPerColorDepth; resIndex++)
        {
            if (resolutionMatrix[resIndex].xRes * resolutionMatrix[resIndex].yRes * bytesPerPixel > (LONG)vramSize)
            {
                /* we don't have enough VRAM for this mode */
                continue;
            }

            if (yOffset == 0 && resolutionMatrix[resIndex].xRes == 800 && resolutionMatrix[resIndex].yRes == 600)
            {
                /* this mode was already added */
                continue;
            }

            if (
#ifdef VBOX_WDDM_MINIPORT
                    /* 1024x768 resolution is a minimal resolutions for win8 to make most metro apps run.
                     * For small host display resolutions, host will dislike the mode 1024x768 and above
                     * if the framebuffer window requires scrolling to fit the guest resolution.
                     * So add 1024x768 resolution for win8 guest to allow user switch to it */
                       (   (VBoxQueryWinVersion() != WIN8 && VBoxQueryWinVersion() != WIN81)
                        || resolutionMatrix[resIndex].xRes != 1024
                        || resolutionMatrix[resIndex].yRes != 768)
                    &&
#endif
                       !VBoxLikesVideoMode(iDisplay, resolutionMatrix[resIndex].xRes,
                                           resolutionMatrix[resIndex].yRes - yOffset, bitsPerPixel))
            {
                /* host doesn't like this mode */
                continue;
            }

            if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, resolutionMatrix[resIndex].xRes, resolutionMatrix[resIndex].yRes, bitsPerPixel))
            {
                /* guest does not like this mode */
                continue;
            }

            /* Sanity check, we shouldn't ever get here */
            if (iMode >= tableSize)
            {
                WARN(("video modes table overflow!"));
                break;
            }

            VBoxFillVidModeInfo(&pModesTable[iMode], resolutionMatrix[resIndex].xRes, resolutionMatrix[resIndex].yRes, bitsPerPixel, iMode+1, yOffset);
            ++iMode;
            ++cAdded;
        }
    }

    /* Check registry for manually added modes, up to 128 entries is supported
     * Give up on the first error encountered.
     */
    VBOXMPCMNREGISTRY Registry;
    int fPrefSet=0;
    VP_STATUS rc;

    rc = VBoxMPCmnRegInit(pExt, &Registry);
    VBOXMP_WARN_VPS(rc);

    for (int curKey=0; curKey<128; curKey++)
    {
        if (iMode>=tableSize)
        {
            WARN(("ignoring possible custom mode(s), table is full!"));
            break;
        }

        wchar_t keyname[24];
        uint32_t xres, yres, bpp = 0;

        swprintf(keyname, L"CustomMode%dWidth", curKey);
        rc = VBoxMPCmnRegQueryDword(Registry, keyname, &xres);
        VBOXMP_CHECK_VPS_BREAK(rc);

        swprintf(keyname, L"CustomMode%dHeight", curKey);
        rc = VBoxMPCmnRegQueryDword(Registry, keyname, &yres);
        VBOXMP_CHECK_VPS_BREAK(rc);

        swprintf(keyname, L"CustomMode%dBPP", curKey);
        rc = VBoxMPCmnRegQueryDword(Registry, keyname, &bpp);
        VBOXMP_CHECK_VPS_BREAK(rc);

        LOG(("got custom mode[%u]=%ux%u:%u", curKey, xres, yres, bpp));

        /* round down width to be a multiple of 8 if necessary */
        if (!VBoxCommonFromDeviceExt(pExt)->fAnyX)
        {
            xres &= 0xFFF8;
        }

        if (   (xres > (1 << 16))
            || (yres > (1 << 16))
            || (   (bpp != 16)
                && (bpp != 24)
                && (bpp != 32)))
        {
            /* incorrect values */
            break;
        }

        /* does it fit within our VRAM? */
        if (xres * yres * (bpp / 8) > vramSize)
        {
            /* we don't have enough VRAM for this mode */
            break;
        }

        if (!VBoxLikesVideoMode(iDisplay, xres, yres, bpp))
        {
            /* host doesn't like this mode */
            break;
        }

        if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, xres, yres, bpp))
        {
            /* guest does not like this mode */
            continue;
        }

        LOG(("adding video mode from registry."));

        VBoxFillVidModeInfo(&pModesTable[iMode], xres, yres, bpp, iMode+1, yOffset);

        if (!fPrefSet)
        {
            fPrefSet = 1;
            iPrefIdx = iMode;
        }
#ifdef VBOX_WDDM_MINIPORT
        /*check if the same mode has been added to the table already*/
        int foundIdx = VBoxMPFindVideoMode(pModesTable, iMode, &pModesTable[iMode]);

        if (foundIdx>=0)
        {
            if (iPrefIdx==iMode)
            {
                iPrefIdx=foundIdx;
            }
        }
        else
#endif
        {
            ++iMode;
        }
    }

    rc = VBoxMPCmnRegFini(Registry);
    VBOXMP_WARN_VPS(rc);

    if (pPrefModeIdx)
    {
        *pPrefModeIdx = iPrefIdx;
    }

    return iMode;
}
Пример #5
0
void VBoxMPCmnInitCustomVideoModes(PVBOXMP_DEVEXT pExt)
{
    VBOXMPCMNREGISTRY Registry;
    VP_STATUS rc;
    int iMode;

    LOGF_ENTER();

    rc = VBoxMPCmnRegInit(pExt, &Registry);
    VBOXMP_WARN_VPS(rc);

    /* Initialize all custom modes to the 800x600x32 */
    VBoxFillVidModeInfo(&g_CustomVideoModes[0], 800, 600, 32, 0, 0);
    for (iMode=1; iMode<RT_ELEMENTS(g_CustomVideoModes); ++iMode)
    {
        g_CustomVideoModes[iMode] = g_CustomVideoModes[0];
    }

    /* Read stored custom resolution info from registry */
    for (iMode=0; iMode<VBoxCommonFromDeviceExt(pExt)->cDisplays; ++iMode)
    {
        uint32_t CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;

        if (iMode==0)
        {
            /*First name without a suffix*/
            rc = VBoxMPCmnRegQueryDword(Registry, L"CustomXRes", &CustomXRes);
            VBOXMP_WARN_VPS_NOBP(rc);
            rc = VBoxMPCmnRegQueryDword(Registry, L"CustomYRes", &CustomYRes);
            VBOXMP_WARN_VPS_NOBP(rc);
            rc = VBoxMPCmnRegQueryDword(Registry, L"CustomBPP", &CustomBPP);
            VBOXMP_WARN_VPS_NOBP(rc);
        }
        else
        {
            wchar_t keyname[32];
            swprintf(keyname, L"CustomXRes%d", iMode);
            rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomXRes);
            VBOXMP_WARN_VPS_NOBP(rc);
            swprintf(keyname, L"CustomYRes%d", iMode);
            rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomYRes);
            VBOXMP_WARN_VPS_NOBP(rc);
            swprintf(keyname, L"CustomBPP%d", iMode);
            rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomBPP);
            VBOXMP_WARN_VPS_NOBP(rc);
        }

        LOG(("got stored custom resolution[%d] %dx%dx%d", iMode, CustomXRes, CustomYRes, CustomBPP));

        if (CustomXRes || CustomYRes || CustomBPP)
        {
            if (CustomXRes == 0)
            {
                CustomXRes = g_CustomVideoModes[iMode].VisScreenWidth;
            }
            if (CustomYRes == 0)
            {
                CustomYRes = g_CustomVideoModes[iMode].VisScreenHeight;
            }
            if (CustomBPP == 0)
            {
                CustomBPP = g_CustomVideoModes[iMode].BitsPerPlane;
            }

            if (VBoxMPValidateVideoModeParamsGuest(pExt, iMode, CustomXRes, CustomYRes, CustomBPP))
            {
                VBoxFillVidModeInfo(&g_CustomVideoModes[iMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
            }
        }
    }

    rc = VBoxMPCmnRegFini(Registry);
    VBOXMP_WARN_VPS(rc);
    LOGF_LEAVE();
}
Пример #6
0
static void
VBoxWddmBuildVideoModesInfo(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId,
                            PVBOXWDDM_VIDEOMODES_INFO pModes, VIDEO_MODE_INFORMATION *paAddlModes,
                            UINT cAddlModes)
{
    pModes->cResolutions = RT_ELEMENTS(pModes->aResolutions);

    /* Add default modes and ones read from registry. */
    pModes->cModes = VBoxMPFillModesTable(pExt, VidPnTargetId, pModes->aModes, RT_ELEMENTS(pModes->aModes), &pModes->iPreferredMode);
    Assert(pModes->cModes<=RT_ELEMENTS(pModes->aModes));

    if (!VBoxMPIsStartingUp(pExt, VidPnTargetId))
    {
        /* make sure we keep the current mode to avoid mode flickering */
        PVBOXWDDM_ALLOC_DATA pAllocData = pExt->aSources[VidPnTargetId].pPrimaryAllocation ?
                  &pExt->aSources[VidPnTargetId].pPrimaryAllocation->AllocData
                : &pExt->aSources[VidPnTargetId].AllocData;
        if (pModes->cModes < RT_ELEMENTS(pModes->aModes))
        {
            /* VBox WDDM driver does not allow 24 modes since OS could choose the 24bit mode as default in that case,
             * the pExt->aSources[iDisplay].AllocData.SurfDesc.bpp could be initially 24 though,
             * i.e. when driver occurs the current mode on driver load via DxgkCbAcquirePostDisplayOwnership
             * and until driver reports the supported modes
             * This is true for Win8 Display-Only driver currently since DxgkCbAcquirePostDisplayOwnership is only used by it
             *
             * This is why we check the bpp to be supported here and add the current mode to the list only in that case */
            if (VBoxMPIsSupportedBpp(pAllocData->SurfDesc.bpp))
            {
                int foundIdx;
                VBoxFillVidModeInfo(&pModes->aModes[pModes->cModes], pAllocData->SurfDesc.width, pAllocData->SurfDesc.height, pAllocData->SurfDesc.bpp, 1/*index*/, 0);
                if ((foundIdx=VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &pModes->aModes[pModes->cModes]))>=0)
                {
                    pModes->iPreferredMode = foundIdx;
                }
                else
                {
                    pModes->iPreferredMode = pModes->cModes;
                    ++pModes->cModes;
                }

#ifdef VBOX_WITH_8BPP_MODES
                int bytesPerPixel=1;
#else
                int bytesPerPixel=2;
#endif
                for (; bytesPerPixel<=4; bytesPerPixel++)
                {
                    int bpp = 8*bytesPerPixel;

                    if (bpp == pAllocData->SurfDesc.bpp)
                        continue;

                    if (!VBoxMPValidateVideoModeParamsGuest(pExt, VidPnTargetId,
                            pAllocData->SurfDesc.width, pAllocData->SurfDesc.height,
                            bpp))
                        continue;

                    if (pModes->cModes >= RT_ELEMENTS(pModes->aModes))
                    {
                        WARN(("ran out of video modes 2"));
                        break;
                    }

                    VBoxFillVidModeInfo(&pModes->aModes[pModes->cModes],
                                            pAllocData->SurfDesc.width, pAllocData->SurfDesc.height,
                                            bpp, pModes->cModes, 0);
                    if (VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &pModes->aModes[pModes->cModes]) < 0)
                    {
                        ++pModes->cModes;
                    }
                }
            }
        }
        else
        {
            WARN(("ran out of video modes 1"));
        }
    }

    /* Check if there's a pending display change request for this adapter */
    VIDEO_MODE_INFORMATION specialMode;
    if (VBoxMPCheckPendingVideoMode(pExt, &specialMode) && (specialMode.ModeIndex==VidPnTargetId))
    {
        /*Minor hack, ModeIndex!=0 Means this mode has been validated already and not just read from registry */
        specialMode.ModeIndex = 1;
        memcpy(&g_CustomVideoModes[VidPnTargetId], &specialMode, sizeof(VIDEO_MODE_INFORMATION));

        /* Save mode to registry */
        VBoxMPRegSaveModeInfo(pExt, VidPnTargetId, &specialMode);
    }

    /* Validate the mode which has been read from registry */
    if (!g_CustomVideoModes[VidPnTargetId].ModeIndex)
    {
        uint32_t xres, yres, bpp;

        xres = g_CustomVideoModes[VidPnTargetId].VisScreenWidth;
        yres = g_CustomVideoModes[VidPnTargetId].VisScreenHeight;
        bpp = g_CustomVideoModes[VidPnTargetId].BitsPerPlane;

        if (VBoxMPValidateVideoModeParams(pExt, VidPnTargetId, xres, yres, bpp))
        {
            VBoxFillVidModeInfo(&g_CustomVideoModes[VidPnTargetId], xres, yres, bpp, 1/*index*/, 0);
            Assert(g_CustomVideoModes[VidPnTargetId].ModeIndex == 1);
        }
    }

    /* Add custom mode to the table */
    if (g_CustomVideoModes[VidPnTargetId].ModeIndex)
    {
        if (RT_ELEMENTS(pModes->aModes) > pModes->cModes)
        {
            g_CustomVideoModes[VidPnTargetId].ModeIndex = pModes->cModes;
            pModes->aModes[pModes->cModes] = g_CustomVideoModes[VidPnTargetId];

            /* Check if we already have this mode in the table */
            int foundIdx;
            if ((foundIdx=VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &pModes->aModes[pModes->cModes]))>=0)
            {
                pModes->iPreferredMode = foundIdx;
            }
            else
            {
                pModes->iPreferredMode = pModes->cModes;
                ++pModes->cModes;
            }

            /* Add other bpp modes for this custom resolution */
#ifdef VBOX_WITH_8BPP_MODES
        UINT bpp=8;
#else
        UINT bpp=16;
#endif
            for (; bpp<=32; bpp+=8)
            {
                if (RT_ELEMENTS(pModes->aModes) == pModes->cModes)
                {
                    WARN(("table full, can't add other bpp for specail mode!"));
#ifdef DEBUG_misha
                    /* this is definitely something we do not expect */
                    AssertFailed();
#endif
                    break;
                }

                AssertRelease(RT_ELEMENTS(pModes->aModes) > pModes->cModes); /* if not - the driver state is screwed up, @todo: better do KeBugCheckEx here */

                if (pModes->aModes[pModes->iPreferredMode].BitsPerPlane == bpp)
                    continue;

                if (!VBoxMPValidateVideoModeParamsGuest(pExt, VidPnTargetId,
                        pModes->aModes[pModes->iPreferredMode].VisScreenWidth,
                        pModes->aModes[pModes->iPreferredMode].VisScreenHeight,
                        bpp))
                    continue;

                VBoxFillVidModeInfo(&pModes->aModes[pModes->cModes],
                                        pModes->aModes[pModes->iPreferredMode].VisScreenWidth,
                                        pModes->aModes[pModes->iPreferredMode].VisScreenHeight,
                                        bpp, pModes->cModes, 0);
                if (VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &pModes->aModes[pModes->cModes]) < 0)
                {
                    ++pModes->cModes;
                }
            }
        }
        else
        {
            AssertRelease(RT_ELEMENTS(pModes->aModes) == pModes->cModes); /* if not - the driver state is screwed up, @todo: better do KeBugCheckEx here */
            WARN(("table full, can't add video mode for a host request!"));
#ifdef DEBUG_misha
            /* this is definitely something we do not expect */
            AssertFailed();
#endif
        }
    }

    /* Check and Add additional modes passed in paAddlModes */
    for (UINT i=0; i<cAddlModes; ++i)
    {
        if (RT_ELEMENTS(pModes->aModes) == pModes->cModes)
        {
           WARN(("table full, can't add addl modes!"));
#ifdef DEBUG_misha
            /* this is definitely something we do not expect */
            AssertFailed();
#endif
           break;
        }

        AssertRelease(RT_ELEMENTS(pModes->aModes) > pModes->cModes); /* if not - the driver state is screwed up, @todo: better do KeBugCheckEx here */

        if (!pExt->fAnyX)
        {
            paAddlModes[i].VisScreenWidth &= 0xFFF8;
        }

        if (VBoxLikesVideoMode(VidPnTargetId, paAddlModes[i].VisScreenWidth, paAddlModes[i].VisScreenHeight, paAddlModes[i].BitsPerPlane))
        {
            int foundIdx;
            if ((foundIdx=VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &paAddlModes[i]))>=0)
            {
                pModes->iPreferredMode = foundIdx;
            }
            else
            {
                memcpy(&pModes->aModes[pModes->cModes], &paAddlModes[i], sizeof(VIDEO_MODE_INFORMATION));
                pModes->aModes[pModes->cModes].ModeIndex = pModes->cModes;
                ++pModes->cModes;
            }
        }
    }

    /* Build resolution table */
    VBoxWddmBuildResolutionTableForModes(pModes);
}
Пример #7
0
/* Makes a table of video modes consisting of:
 * Default modes
 * Custom modes manually added to registry
 * Custom modes for all displays (either from a display change hint or stored in registry)
 * 2 special modes, for a pending display change for this adapter. See comments below.
 */
void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt)
{
    uint32_t cStandartModes, cCustomModes;
    BOOLEAN bPending, bHaveSpecial;
    VIDEO_MODE_INFORMATION specialMode;

    /* Fill table with standart modes and ones manually added to registry */
    cStandartModes = VBoxMPFillModesTable(pExt, pExt->iDevice, g_VideoModes, RT_ELEMENTS(g_VideoModes), NULL);

    /* Add custom modes for all displays to the table */
    cCustomModes = VBoxCommonFromDeviceExt(pExt)->cDisplays;
    for (uint32_t i=0; i<cCustomModes; i++)
    {
        memcpy(&g_VideoModes[cStandartModes+i], &g_CustomVideoModes[i], sizeof(VIDEO_MODE_INFORMATION));
        g_VideoModes[cStandartModes+i].ModeIndex = cStandartModes+i+1;
    }

    /* Check if host wants us to switch video mode and it's for this adapter */
    bPending = VBoxMPCheckPendingVideoMode(pExt, &specialMode);
    bHaveSpecial = bPending && (pExt->iDevice == specialMode.ModeIndex);

    /* Check the startup case */
    if (!bHaveSpecial && VBoxMPIsStartingUp(pExt, pExt->iDevice))
    {
        uint32_t xres=0, yres=0, bpp=0;
        /* Check if we could make valid mode from values stored to registry */
        if (VBoxMPValidateVideoModeParams(pExt, pExt->iDevice, xres, yres, bpp))
        {
            VBoxFillVidModeInfo(&specialMode, xres, yres, bpp, 0, 0);
            bHaveSpecial = TRUE;
        }
    }

    /* Update number of modes */
    g_NumVideoModes = cStandartModes + cCustomModes;

    if (!bHaveSpecial)
    {
        /* Just add 2 dummy modes to maintain table size. */
        memcpy(&g_VideoModes[g_NumVideoModes], &g_VideoModes[2], sizeof(VIDEO_MODE_INFORMATION));
        g_VideoModes[g_NumVideoModes].ModeIndex = g_NumVideoModes+1;
        g_NumVideoModes++;
        memcpy(&g_VideoModes[g_NumVideoModes], &g_VideoModes[2], sizeof(VIDEO_MODE_INFORMATION));
        g_VideoModes[g_NumVideoModes].ModeIndex = g_NumVideoModes+1;
        g_NumVideoModes++;
    }
    else
    {
        /* We need to alternate mode index entry for a pending mode change,
         * else windows will ignore actual mode change call.
         * Only alternate index if one of mode parameters changed and
         * regardless of conditions always add 2 entries to the table.
         */
        static int s_InvocationCounter=0;
        BOOLEAN bAlternativeIndex = FALSE;

        static uint32_t s_Prev_xres=0;
        static uint32_t s_Prev_yres=0;
        static uint32_t s_Prev_bpp=0;
        BOOLEAN bChanged = (s_Prev_xres!=specialMode.VisScreenWidth
                            || s_Prev_yres!=specialMode.VisScreenHeight
                            || s_Prev_bpp!=specialMode.BitsPerPlane);
        if (bChanged)
        {
            s_Prev_xres = specialMode.VisScreenWidth;
            s_Prev_yres = specialMode.VisScreenHeight;
            s_Prev_bpp = specialMode.BitsPerPlane;
        }

        /* Make sure there's no other mode in the table with same parameters,
         * because we need windows to pick up a new video mode index otherwise
         * actual mode change wouldn't happen.
         */
        int iFoundIdx;
        uint32_t uiStart=0;

        while (0 <= (iFoundIdx = VBoxMPFindVideoMode(&g_VideoModes[uiStart], g_NumVideoModes-uiStart, &specialMode)))
        {
            memcpy(&g_VideoModes[uiStart+iFoundIdx], &g_VideoModes[2], sizeof(VIDEO_MODE_INFORMATION));
            g_VideoModes[uiStart+iFoundIdx].ModeIndex = uiStart+iFoundIdx+1;
            uiStart += iFoundIdx+1;
        }

        /* Check if we need to alternate the index */
        if (!VBoxMPIsStartingUp(pExt, pExt->iDevice))
        {
            if (bChanged)
            {
                s_InvocationCounter++;
            }

            if (s_InvocationCounter % 2)
            {
                bAlternativeIndex = TRUE;
                memcpy(&g_VideoModes[g_NumVideoModes], &g_VideoModes[2], sizeof(VIDEO_MODE_INFORMATION));
                g_VideoModes[g_NumVideoModes].ModeIndex = g_NumVideoModes+1;
                ++g_NumVideoModes;
            }
        }

        LOG(("add special mode[%d] %dx%d:%d for display %d (bChanged=%d, bAlretnativeIndex=%d)",
             g_NumVideoModes, specialMode.VisScreenWidth, specialMode.VisScreenHeight, specialMode.BitsPerPlane,
             pExt->iDevice, bChanged, bAlternativeIndex));

        /* Add special mode to the table
         * Note: Y offset isn't used for a host-supplied modes
         */
        specialMode.ModeIndex = g_NumVideoModes+1;
        memcpy(&g_VideoModes[g_NumVideoModes], &specialMode, sizeof(VIDEO_MODE_INFORMATION));
        ++g_NumVideoModes;

        /* Save special mode in the custom modes table */
        memcpy(&g_CustomVideoModes[pExt->iDevice], &specialMode, sizeof(VIDEO_MODE_INFORMATION));


        /* Make sure we've added 2nd mode if necessary to maintain table size */
        if (VBoxMPIsStartingUp(pExt, pExt->iDevice))
        {
            memcpy(&g_VideoModes[g_NumVideoModes], &g_VideoModes[g_NumVideoModes-1], sizeof(VIDEO_MODE_INFORMATION));
            g_VideoModes[g_NumVideoModes].ModeIndex = g_NumVideoModes+1;
            ++g_NumVideoModes;
        }
        else if (!bAlternativeIndex)
        {
            memcpy(&g_VideoModes[g_NumVideoModes], &g_VideoModes[2], sizeof(VIDEO_MODE_INFORMATION));
            g_VideoModes[g_NumVideoModes].ModeIndex = g_NumVideoModes+1;
            ++g_NumVideoModes;
        }

        /* Save special mode info to registry */
        VBoxMPRegSaveModeInfo(pExt, pExt->iDevice, &specialMode);
    }

#if defined(LOG_ENABLED)
    do
    {
        LOG(("Filled %d modes", g_NumVideoModes));

        for (uint32_t i=0; i<g_NumVideoModes; ++i)
        {
            LOG(("Mode[%2d]: %4dx%4d:%2d (idx=%d)",
                i, g_VideoModes[i].VisScreenWidth, g_VideoModes[i].VisScreenHeight,
                g_VideoModes[i].BitsPerPlane, g_VideoModes[i].ModeIndex));
        }
    } while (0);
#endif
}
static void
VBoxWddmBuildVideoModesInfo(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId,
                            PVBOXWDDM_VIDEOMODES_INFO pModes, VIDEO_MODE_INFORMATION *paAddlModes,
                            UINT cAddlModes)
{
    pModes->cResolutions = RT_ELEMENTS(pModes->aResolutions);

    /* Add default modes and ones read from registry. */
    pModes->cModes = VBoxMPFillModesTable(pExt, VidPnTargetId, pModes->aModes, RT_ELEMENTS(pModes->aModes), &pModes->iPreferredMode);
    Assert(pModes->cModes<=RT_ELEMENTS(pModes->aModes));

    /* Check if there's a pending display change request for this adapter */
    VIDEO_MODE_INFORMATION specialMode;
    if (VBoxMPCheckPendingVideoMode(pExt, &specialMode) && (specialMode.ModeIndex==VidPnTargetId))
    {
        /*Minor hack, ModeIndex!=0 Means this mode has been validated already and not just read from registry */
        specialMode.ModeIndex = 1;
        memcpy(&g_CustomVideoModes[VidPnTargetId], &specialMode, sizeof(VIDEO_MODE_INFORMATION));

        /* Save mode to registry */
        VBoxMPRegSaveModeInfo(pExt, VidPnTargetId, &specialMode);
    }

    /* Validate the mode which has been read from registry */
    if (!g_CustomVideoModes[VidPnTargetId].ModeIndex)
    {
        uint32_t xres, yres, bpp;

        xres = g_CustomVideoModes[VidPnTargetId].VisScreenWidth;
        yres = g_CustomVideoModes[VidPnTargetId].VisScreenHeight;
        bpp = g_CustomVideoModes[VidPnTargetId].BitsPerPlane;

        if (VBoxMPValidateVideoModeParams(pExt, VidPnTargetId, xres, yres, bpp))
        {
            VBoxFillVidModeInfo(&g_CustomVideoModes[VidPnTargetId], xres, yres, bpp, 1/*index*/, 0);
            Assert(g_CustomVideoModes[VidPnTargetId].ModeIndex == 1);
        }
    }

    /* Add custom mode to the table */
    if (g_CustomVideoModes[VidPnTargetId].ModeIndex)
    {
        if (RT_ELEMENTS(pModes->aModes) > pModes->cModes)
        {
            g_CustomVideoModes[VidPnTargetId].ModeIndex = pModes->cModes;
            pModes->aModes[pModes->cModes] = g_CustomVideoModes[VidPnTargetId];

            /* Check if we already have this mode in the table */
            int foundIdx;
            if ((foundIdx=VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &pModes->aModes[pModes->cModes]))>=0)
            {
                pModes->iPreferredMode = foundIdx;
            }
            else
            {
                pModes->iPreferredMode = pModes->cModes;
                ++pModes->cModes;
            }

            /* Add other bpp modes for this custom resolution */
#ifdef VBOX_WITH_8BPP_MODES
        UINT bpp=8;
#else
        UINT bpp=16;
#endif
            for (; bpp<=32; bpp+=8)
            {
                if (RT_ELEMENTS(pModes->aModes) == pModes->cModes)
                {
                    WARN(("table full, can't add other bpp for specail mode!"));
#ifdef DEBUG_misha
                    /* this is definitely something we do not expect */
                    AssertFailed();
#endif
                    break;
                }

                AssertRelease(RT_ELEMENTS(pModes->aModes) > pModes->cModes); /* if not - the driver state is screwed up, @todo: better do KeBugCheckEx here */

                if (pModes->aModes[pModes->iPreferredMode].BitsPerPlane == bpp)
                    continue;

                if (!VBoxMPValidateVideoModeParamsGuest(pExt, VidPnTargetId,
                        pModes->aModes[pModes->iPreferredMode].VisScreenWidth,
                        pModes->aModes[pModes->iPreferredMode].VisScreenHeight,
                        bpp))
                    continue;

                VBoxFillVidModeInfo(&pModes->aModes[pModes->cModes],
                                        pModes->aModes[pModes->iPreferredMode].VisScreenWidth,
                                        pModes->aModes[pModes->iPreferredMode].VisScreenHeight,
                                        bpp, pModes->cModes, 0);
                if (VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &pModes->aModes[pModes->cModes]) < 0)
                {
                    ++pModes->cModes;
                }
            }
        }
        else
        {
            AssertRelease(RT_ELEMENTS(pModes->aModes) == pModes->cModes); /* if not - the driver state is screwed up, @todo: better do KeBugCheckEx here */
            WARN(("table full, can't add video mode for a host request!"));
#ifdef DEBUG_misha
            /* this is definitely something we do not expect */
            AssertFailed();
#endif
        }
    }

    /* Check and Add additional modes passed in paAddlModes */
    for (UINT i=0; i<cAddlModes; ++i)
    {
        if (RT_ELEMENTS(pModes->aModes) == pModes->cModes)
        {
           WARN(("table full, can't add addl modes!"));
#ifdef DEBUG_misha
            /* this is definitely something we do not expect */
            AssertFailed();
#endif
           break;
        }

        AssertRelease(RT_ELEMENTS(pModes->aModes) > pModes->cModes); /* if not - the driver state is screwed up, @todo: better do KeBugCheckEx here */

        if (!pExt->fAnyX)
        {
            paAddlModes[i].VisScreenWidth &= 0xFFF8;
        }

        if (VBoxLikesVideoMode(VidPnTargetId, paAddlModes[i].VisScreenWidth, paAddlModes[i].VisScreenHeight, paAddlModes[i].BitsPerPlane))
        {
            int foundIdx;
            if ((foundIdx=VBoxMPFindVideoMode(pModes->aModes, pModes->cModes, &paAddlModes[i]))>=0)
            {
                pModes->iPreferredMode = foundIdx;
            }
            else
            {
                memcpy(&pModes->aModes[pModes->cModes], &paAddlModes[i], sizeof(VIDEO_MODE_INFORMATION));
                pModes->aModes[pModes->cModes].ModeIndex = pModes->cModes;
                ++pModes->cModes;
            }
        }
    }

    /* Build resolution table */
    VBoxWddmBuildResolutionTableForModes(pModes);
}