/* 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 }
/* 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; }
/* 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)); 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; }