/* Updates missing video mode params with current values, * Checks if resulting mode is liked by the host and fits into VRAM. * Returns TRUE if resulting mode could be used. */ static BOOLEAN VBoxMPValidateVideoModeParams(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t &xres, uint32_t &yres, uint32_t &bpp) { /* Make sure all important video mode values are set */ if (VBoxMPIsStartingUp(pExt, iDisplay)) { /* Use stored custom values only if nothing was read from host. */ xres = xres ? xres:g_CustomVideoModes[iDisplay].VisScreenWidth; yres = yres ? yres:g_CustomVideoModes[iDisplay].VisScreenHeight; bpp = bpp ? bpp :g_CustomVideoModes[iDisplay].BitsPerPlane; } else { /* Use current values for field which weren't read from host. */ #ifdef VBOX_XPDM_MINIPORT xres = xres ? xres:pExt->CurrentModeWidth; yres = yres ? yres:pExt->CurrentModeHeight; bpp = bpp ? bpp :pExt->CurrentModeBPP; #else PVBOXWDDM_ALLOC_DATA pAllocData = pExt->aSources[iDisplay].pPrimaryAllocation ? &pExt->aSources[iDisplay].pPrimaryAllocation->AllocData : &pExt->aSources[iDisplay].AllocData; xres = xres ? xres:pAllocData->SurfDesc.width; yres = yres ? yres:pAllocData->SurfDesc.height; /* 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 need to adjust the current mode bpp to the value we actually report as supported */ bpp = bpp ? bpp : VBoxMPAdjustBpp(pAllocData->SurfDesc.bpp); #endif } /* Round down width to be a multiple of 8 if necessary */ if (!VBoxCommonFromDeviceExt(pExt)->fAnyX) { xres &= 0xFFF8; } /* We always need bpp to be set */ if (!bpp) { bpp=32; } if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, xres, yres, bpp)) { WARN(("GUEST does not like special mode %dx%d:%d for display %d", xres, yres, bpp, iDisplay)); return FALSE; } /* Check if host likes this mode */ if (!VBoxLikesVideoMode(iDisplay, xres, yres, bpp)) { WARN_NOBP(("HOST does not like special mode %dx%d:%d for display %d", xres, yres, bpp, iDisplay)); return FALSE; } #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 /* Check that values are valid and mode fits into VRAM */ if (!xres || !yres || !((bpp == 16) #ifdef VBOX_WITH_8BPP_MODES || (bpp == 8) #endif || (bpp == 24) || (bpp == 32))) { LOG(("invalid params for special mode %dx%d:%d", xres, yres, bpp)); return FALSE; } if ((xres * yres * (bpp / 8) >= vramSize)) { /* Store values of last reported release log message to avoid log flooding. */ static uint32_t s_xresNoVRAM=0, s_yresNoVRAM=0, s_bppNoVRAM=0; LOG(("not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.", xres, yres, bpp, vramSize, xres * yres * (bpp / 8))); s_xresNoVRAM = xres; s_yresNoVRAM = yres; s_bppNoVRAM = bpp; return FALSE; } return TRUE; }
/* 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; }
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); }
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); }
/* Updates missing video mode params with current values, * Checks if resulting mode is liked by the host and fits into VRAM. * Returns TRUE if resulting mode could be used. */ static BOOLEAN VBoxMPValidateVideoModeParams(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t &xres, uint32_t &yres, uint32_t &bpp) { /* Make sure all important video mode values are set */ if (VBoxMPIsStartingUp(pExt, iDisplay)) { /* Use stored custom values only if nothing was read from host. */ xres = xres ? xres:g_CustomVideoModes[iDisplay].VisScreenWidth; yres = yres ? yres:g_CustomVideoModes[iDisplay].VisScreenHeight; bpp = bpp ? bpp :g_CustomVideoModes[iDisplay].BitsPerPlane; } else { /* Use current values for field which weren't read from host. */ #ifdef VBOX_XPDM_MINIPORT xres = xres ? xres:pExt->CurrentModeWidth; yres = yres ? yres:pExt->CurrentModeHeight; bpp = bpp ? bpp :pExt->CurrentModeBPP; #else xres = xres ? xres:pExt->aSources[iDisplay].pPrimaryAllocation->SurfDesc.width; yres = yres ? yres:pExt->aSources[iDisplay].pPrimaryAllocation->SurfDesc.height; bpp = bpp ? bpp :pExt->aSources[iDisplay].pPrimaryAllocation->SurfDesc.bpp; #endif } /* Round down width to be a multiple of 8 if necessary */ if (!pExt->fAnyX) { xres &= 0xFFF8; } /* We always need bpp to be set */ if (!bpp) { bpp=32; } if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, xres, yres, bpp)) return FALSE; /* Check if host likes this mode */ if (!VBoxLikesVideoMode(iDisplay, xres, yres, bpp)) { WARN_NOBP(("host does not like special mode %dx%d:%d for display %d", xres, yres, bpp, iDisplay)); return FALSE; } #ifdef VBOX_XPDM_MINIPORT ULONG vramSize = pExt->pPrimary->u.primary.ulMaxFrameBufferSize; #else ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(pExt); /* at least two surfaces will be needed: primary & shadow */ vramSize /= 2 * pExt->u.primary.commonInfo.cDisplays; #endif /* Check that values are valid and mode fits into VRAM */ if (!xres || !yres || !((bpp == 16) #ifdef VBOX_WITH_8BPP_MODES || (bpp == 8) #endif || (bpp == 24) || (bpp == 32))) { LOG(("invalid params for special mode %dx%d:%d", xres, yres, bpp)); return FALSE; } if ((xres * yres * (bpp / 8) >= vramSize)) { /* Store values of last reported release log message to avoid log flooding. */ static uint32_t s_xresNoVRAM=0, s_yresNoVRAM=0, s_bppNoVRAM=0; LOG(("not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.", xres, yres, bpp, vramSize, xres * yres * (bpp / 8))); s_xresNoVRAM = xres; s_yresNoVRAM = yres; s_bppNoVRAM = bpp; return FALSE; } return TRUE; }