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