diff options
Diffstat (limited to 'src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPVidModes.cpp')
-rw-r--r-- | src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPVidModes.cpp | 636 |
1 files changed, 458 insertions, 178 deletions
diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPVidModes.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPVidModes.cpp index 697ce0d3..445aea0d 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPVidModes.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPVidModes.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,22 +23,14 @@ extern "C" int __cdecl swprintf(wchar_t *, const wchar_t *, ...); #endif #include <wchar.h> +#include <VBox/Hardware/VBoxVideoVBE.h> #ifdef VBOX_WITH_WDDM # define VBOX_WITHOUT_24BPP_MODES #endif /* Custom video modes which are being read from registry at driver startup. */ -static VIDEO_MODE_INFORMATION g_CustomVideoModes[64] = { 0 }; - -/* Standart video modes list. - * Additional space is reserved for custom video modes for 64 guest monitors. - * The custom video mode index is alternating and 2 indexes are reserved for the last custom mode. - */ -static VIDEO_MODE_INFORMATION g_VideoModes[VBOXMP_MAX_VIDEO_MODES + 64 + 2] = { 0 }; - -/* Number of available video modes, set by VBoxMPCmnBuildVideoModesTable. */ -static uint32_t g_NumVideoModes = 0; +static VIDEO_MODE_INFORMATION g_CustomVideoModes[VBOX_VIDEO_MAX_SCREENS] = { 0 }; static BOOLEAN VBoxMPValidateVideoModeParamsGuest(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t xres, uint32_t yres, uint32_t bpp) @@ -209,10 +201,12 @@ VIDEO_MODE_INFORMATION *VBoxMPCmnGetCustomVideoModeInfo(ULONG ulIndex) return (ulIndex<RT_ELEMENTS(g_CustomVideoModes)) ? &g_CustomVideoModes[ulIndex] : NULL; } -VIDEO_MODE_INFORMATION* VBoxMPCmnGetVideoModeInfo(ULONG ulIndex) +#ifdef VBOX_XPDM_MINIPORT +VIDEO_MODE_INFORMATION* VBoxMPCmnGetVideoModeInfo(PVBOXMP_DEVEXT pExt, ULONG ulIndex) { - return (ulIndex<RT_ELEMENTS(g_VideoModes)) ? &g_VideoModes[ulIndex] : NULL; + return (ulIndex<RT_ELEMENTS(pExt->aVideoModes)) ? &pExt->aVideoModes[ulIndex] : NULL; } +#endif static bool VBoxMPVideoModesMatch(const PVIDEO_MODE_INFORMATION pMode1, const PVIDEO_MODE_INFORMATION pMode2) { @@ -351,9 +345,13 @@ VBoxMPFillModesTable(PVBOXMP_DEVEXT pExt, int iDisplay, PVIDEO_MODE_INFORMATION * 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 || resolutionMatrix[resIndex].xRes != 1024 || resolutionMatrix[resIndex].yRes != 768) && + ( (VBoxQueryWinVersion() != WIN8 && VBoxQueryWinVersion() != WIN81) + || resolutionMatrix[resIndex].xRes != 1024 + || resolutionMatrix[resIndex].yRes != 768) + && #endif - !VBoxLikesVideoMode(iDisplay, resolutionMatrix[resIndex].xRes, resolutionMatrix[resIndex].yRes - yOffset, bitsPerPixel)) + !VBoxLikesVideoMode(iDisplay, resolutionMatrix[resIndex].xRes, + resolutionMatrix[resIndex].yRes - yOffset, bitsPerPixel)) { /* host doesn't like this mode */ continue; @@ -414,7 +412,7 @@ VBoxMPFillModesTable(PVBOXMP_DEVEXT pExt, int iDisplay, PVIDEO_MODE_INFORMATION LOG(("got custom mode[%u]=%ux%u:%u", curKey, xres, yres, bpp)); /* round down width to be a multiple of 8 if necessary */ - if (!pExt->fAnyX) + if (!VBoxCommonFromDeviceExt(pExt)->fAnyX) { xres &= 0xFFF8; } @@ -491,14 +489,41 @@ static BOOLEAN VBoxMPIsStartingUp(PVBOXMP_DEVEXT pExt, uint32_t iDisplay) { #ifdef VBOX_XPDM_MINIPORT return (pExt->CurrentMode == 0); -#elif defined(VBOX_WDDM_WIN8) - return FALSE; -#else /* VBOX_WDDM_MINIPORT && !VBOX_WDDM_MINIPORT */ - return (!VBoxCommonFromDeviceExt(pExt)->cDisplays - || !pExt->aSources[iDisplay].pPrimaryAllocation); +#else + VBOXWDDM_SOURCE *pSource = &pExt->aSources[iDisplay]; + return !pSource->AllocData.SurfDesc.width || !pSource->AllocData.SurfDesc.height; +#endif +} + +#ifdef VBOX_WDDM_MINIPORT +static const uint32_t g_aVBoxVidModesSupportedBpps[] = { + 32 +#ifndef VBOX_WITHOUT_24BPP_MODES + , 24 +#endif + , 16 +#ifdef VBOX_WITH_8BPP_MODES + , 8 #endif +}; +DECLINLINE(BOOLEAN) VBoxMPIsSupportedBpp(uint32_t bpp) +{ + for (int i = 0; i < RT_ELEMENTS(g_aVBoxVidModesSupportedBpps); ++i) + { + if (bpp == g_aVBoxVidModesSupportedBpps[i]) + return TRUE; + } + return FALSE; } +DECLINLINE(uint32_t) VBoxMPAdjustBpp(uint32_t bpp) +{ + if (VBoxMPIsSupportedBpp(bpp)) + return bpp; + Assert(g_aVBoxVidModesSupportedBpps[0] == 32); + return g_aVBoxVidModesSupportedBpps[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. @@ -527,12 +552,19 @@ VBoxMPValidateVideoModeParams(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t & : &pExt->aSources[iDisplay].AllocData; xres = xres ? xres:pAllocData->SurfDesc.width; yres = yres ? yres:pAllocData->SurfDesc.height; - bpp = bpp ? bpp :pAllocData->SurfDesc.bpp; + /* 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 (!pExt->fAnyX) + if (!VBoxCommonFromDeviceExt(pExt)->fAnyX) { xres &= 0xFFF8; } @@ -544,12 +576,15 @@ VBoxMPValidateVideoModeParams(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t & } 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)); + WARN_NOBP(("HOST does not like special mode %dx%d:%d for display %d", xres, yres, bpp, iDisplay)); return FALSE; } @@ -557,8 +592,14 @@ VBoxMPValidateVideoModeParams(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t & 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; + 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; + } #endif /* Check that values are valid and mode fits into VRAM */ @@ -609,11 +650,13 @@ VBoxMPCheckPendingVideoMode(PVBOXMP_DEVEXT pExt, PVIDEO_MODE_INFORMATION pPendin 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; } @@ -667,12 +710,12 @@ static void VBoxMPRegSaveModeInfo(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, PVIDEO #ifdef VBOX_XPDM_MINIPORT VIDEO_MODE_INFORMATION* VBoxMPXpdmCurrentVideoMode(PVBOXMP_DEVEXT pExt) { - return VBoxMPCmnGetVideoModeInfo(pExt->CurrentMode - 1); + return VBoxMPCmnGetVideoModeInfo(pExt, pExt->CurrentMode - 1); } -ULONG VBoxMPXpdmGetVideoModesCount() +ULONG VBoxMPXpdmGetVideoModesCount(PVBOXMP_DEVEXT pExt) { - return g_NumVideoModes; + return pExt->cVideoModes; } /* Makes a table of video modes consisting of: @@ -683,85 +726,86 @@ ULONG VBoxMPXpdmGetVideoModesCount() */ void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt) { - uint32_t cStandartModes, cCustomModes; + uint32_t cStandartModes; 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); + /* 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 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; - } + /* 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 */ - g_NumVideoModes = cStandartModes + cCustomModes; + /* Update number of modes. Each display has 2 entries for alternating custom mode index. */ + pExt->cVideoModes = cStandartModes + 2; - 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 + 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. */ - 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; - } + BOOLEAN bChanged = (pExt->Prev_xres!=specialMode.VisScreenWidth + || pExt->Prev_yres!=specialMode.VisScreenHeight + || pExt->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; + LOG(("prev %dx%dx%d, special %dx%dx%d", + pExt->Prev_xres, pExt->Prev_yres, pExt->Prev_bpp, + specialMode.VisScreenWidth, specialMode.VisScreenHeight, specialMode.BitsPerPlane)); - while (0 <= (iFoundIdx = VBoxMPFindVideoMode(&g_VideoModes[uiStart], g_NumVideoModes-uiStart, &specialMode))) + if (bChanged) { - memcpy(&g_VideoModes[uiStart+iFoundIdx], &g_VideoModes[2], sizeof(VIDEO_MODE_INFORMATION)); - g_VideoModes[uiStart+iFoundIdx].ModeIndex = uiStart+iFoundIdx+1; - uiStart += iFoundIdx+1; + pExt->Prev_xres = specialMode.VisScreenWidth; + pExt->Prev_yres = specialMode.VisScreenHeight; + pExt->Prev_bpp = specialMode.BitsPerPlane; } /* Check if we need to alternate the index */ @@ -769,46 +813,34 @@ void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt) { if (bChanged) { - s_InvocationCounter++; + pExt->iInvocationCounter++; } - if (s_InvocationCounter % 2) + if (pExt->iInvocationCounter % 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, + 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 = g_NumVideoModes+1; - memcpy(&g_VideoModes[g_NumVideoModes], &specialMode, sizeof(VIDEO_MODE_INFORMATION)); - ++g_NumVideoModes; + 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)); - - /* 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; - } + /* 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); @@ -817,13 +849,13 @@ void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt) #if defined(LOG_ENABLED) do { - LOG(("Filled %d modes", g_NumVideoModes)); + LOG(("Filled %d modes for display %d", pExt->cVideoModes, pExt->iDevice)); - for (uint32_t i=0; i<g_NumVideoModes; ++i) + for (uint32_t i=0; i < pExt->cVideoModes; ++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)); + i, pExt->aVideoModes[i].VisScreenWidth, pExt->aVideoModes[i].VisScreenHeight, + pExt->aVideoModes[i].BitsPerPlane, pExt->aVideoModes[i].ModeIndex)); } } while (0); #endif @@ -832,6 +864,7 @@ void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt) #ifdef VBOX_WDDM_MINIPORT static VBOXWDDM_VIDEOMODES_INFO g_aVBoxVideoModeInfos[VBOX_VIDEO_MAX_SCREENS] = {0}; +static VBOXWDDM_VIDEOMODES_INFO g_VBoxVideoModeTmp; bool VBoxWddmFillMode(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, VIDEO_MODE_INFORMATION *pInfo, D3DDDIFORMAT enmFormat, ULONG w, ULONG h) { @@ -886,6 +919,7 @@ VBoxWddmBuildResolutionTable(PVIDEO_MODE_INFORMATION pModesTable, size_t tableSi uint32_t cResolutions = 0; *piPreferredResolution = -1; + *pcResolutions = 0; for (uint32_t i=0; i<tableSize; ++i) { @@ -935,6 +969,7 @@ static void VBoxWddmBuildResolutionTableForModes(PVBOXWDDM_VIDEOMODES_INFO pMode (SIZE*)((void*)pModes->aResolutions), &pModes->cResolutions, &pModes->iPreferredResolution); Assert(pModes->aResolutions[pModes->iPreferredResolution].cx == pModes->aModes[pModes->iPreferredMode].VisScreenWidth && pModes->aResolutions[pModes->iPreferredResolution].cy == pModes->aModes[pModes->iPreferredMode].VisScreenHeight); + Assert(pModes->cModes >= pModes->cResolutions); } AssertCompile(sizeof (SIZE) == sizeof (D3DKMDT_2DREGION)); @@ -951,6 +986,74 @@ VBoxWddmBuildVideoModesInfo(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID 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)) @@ -1064,7 +1167,7 @@ VBoxWddmBuildVideoModesInfo(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID AssertRelease(RT_ELEMENTS(pModes->aModes) > pModes->cModes); /* if not - the driver state is screwed up, @todo: better do KeBugCheckEx here */ - if (!pExt->fAnyX) + if (!VBoxCommonFromDeviceExt(pExt)->fAnyX) { paAddlModes[i].VisScreenWidth &= 0xFFF8; } @@ -1089,49 +1192,276 @@ VBoxWddmBuildVideoModesInfo(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VBoxWddmBuildResolutionTableForModes(pModes); } -void VBoxWddmInvalidateVideoModesInfo(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId) +static void VBoxWddmInitVideoMode(PVBOXMP_DEVEXT pExt, int i) +{ + VBoxWddmBuildVideoModesInfo(pExt, (D3DDDI_VIDEO_PRESENT_TARGET_ID)i, &g_aVBoxVideoModeInfos[i], NULL, 0); +} + +void VBoxWddmInitVideoModes(PVBOXMP_DEVEXT pExt) +{ + for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i) + { + VBoxWddmInitVideoMode(pExt, i); + } +} + +static NTSTATUS vboxWddmChildStatusReportPerform(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_CHILD_STATUS pChildStatus, D3DDDI_VIDEO_PRESENT_TARGET_ID iChild) { - if (VidPnTargetId != D3DDDI_ID_ALL) + DXGK_CHILD_STATUS DdiChildStatus; + + Assert(iChild < UINT32_MAX/2); + Assert(iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); + + PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[iChild]; + + if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_DISCONNECTED) + && pTarget->fConnected) { - if (VidPnTargetId >= RT_ELEMENTS(g_aVBoxVideoModeInfos)) + /* report disconnected */ + memset(&DdiChildStatus, 0, sizeof (DdiChildStatus)); + DdiChildStatus.Type = StatusConnection; + DdiChildStatus.ChildUid = iChild; + DdiChildStatus.HotPlug.Connected = FALSE; + + LOG(("Reporting DISCONNECT to child %d", DdiChildStatus.ChildUid)); + + NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus); + if (!NT_SUCCESS(Status)) { - WARN(("VidPnTargetId (%d) must be less than (%d)", VidPnTargetId, RT_ELEMENTS(g_aVBoxVideoModeInfos))); - return; + WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status)); + return Status; } - g_aVBoxVideoModeInfos[VidPnTargetId].cModes = 0; - return; + pTarget->fConnected = FALSE; } - for (UINT i = 0; i < RT_ELEMENTS(g_aVBoxVideoModeInfos); ++i) + if ((pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_CONNECTED) + && !pTarget->fConnected) + { + /* report disconnected */ + memset(&DdiChildStatus, 0, sizeof (DdiChildStatus)); + DdiChildStatus.Type = StatusConnection; + DdiChildStatus.ChildUid = iChild; + DdiChildStatus.HotPlug.Connected = TRUE; + + LOG(("Reporting CONNECT to child %d", DdiChildStatus.ChildUid)); + + NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus); + if (!NT_SUCCESS(Status)) + { + WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status)); + return Status; + } + pTarget->fConnected = TRUE; + } + + if (pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_ROTATED) + { + /* report disconnected */ + memset(&DdiChildStatus, 0, sizeof (DdiChildStatus)); + DdiChildStatus.Type = StatusRotation; + DdiChildStatus.ChildUid = iChild; + DdiChildStatus.Rotation.Angle = pChildStatus->u8RotationAngle; + + LOG(("Reporting ROTATED to child %d", DdiChildStatus.ChildUid)); + + NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbIndicateChildStatus(pDevExt->u.primary.DxgkInterface.DeviceHandle, &DdiChildStatus); + if (!NT_SUCCESS(Status)) + { + WARN(("DxgkCbIndicateChildStatus failed with Status (0x%x)", Status)); + return Status; + } + } + + return STATUS_SUCCESS; +} + +static NTSTATUS vboxWddmChildStatusHandleRequest(PVBOXMP_DEVEXT pDevExt, VBOXVDMACMD_CHILD_STATUS_IRQ *pBody) +{ + NTSTATUS Status = STATUS_SUCCESS; + + for (UINT i = 0; i < pBody->cInfos; ++i) { - g_aVBoxVideoModeInfos[i].cModes = 0; + PVBOXVDMA_CHILD_STATUS pInfo = &pBody->aInfos[i]; + if (pBody->fFlags & VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL) + { + for (D3DDDI_VIDEO_PRESENT_TARGET_ID iChild = 0; iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++iChild) + { + Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, iChild); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status)); + break; + } + } + } + else + { + Status = vboxWddmChildStatusReportPerform(pDevExt, pInfo, pInfo->iChild); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status)); + break; + } + } } + + return Status; } -void VBoxWddmInvalidateAllVideoModesInfos(PVBOXMP_DEVEXT pExt) +#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ +typedef struct VBOXWDDMCHILDSTATUSCB { - VBoxWddmInvalidateVideoModesInfo(pExt, D3DDDI_ID_ALL); + PVBOXVDMACBUF_DR pDr; + PKEVENT pEvent; +} VBOXWDDMCHILDSTATUSCB, *PVBOXWDDMCHILDSTATUSCB; + +static DECLCALLBACK(VOID) vboxWddmChildStatusReportCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext) +{ + /* we should be called from our DPC routine */ + Assert(KeGetCurrentIrql() == DISPATCH_LEVEL); + + PVBOXWDDMCHILDSTATUSCB pCtx = (PVBOXWDDMCHILDSTATUSCB)pvContext; + PVBOXVDMACBUF_DR pDr = pCtx->pDr; + PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); + VBOXVDMACMD_CHILD_STATUS_IRQ *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHILD_STATUS_IRQ); + + vboxWddmChildStatusHandleRequest(pDevExt, pBody); + + vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr); + + if (pCtx->pEvent) + { + KeSetEvent(pCtx->pEvent, 0, FALSE); + } } +#endif -PVBOXWDDM_VIDEOMODES_INFO VBoxWddmUpdateVideoModesInfoByMask(PVBOXMP_DEVEXT pExt, uint8_t *pScreenIdMask) +static NTSTATUS vboxWddmChildStatusReportReconnected(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_TARGET_ID idTarget) { - for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i) +#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(sizeof (VBOXVDMACMD_CHILD_STATUS_IRQ)); + + PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd); + if (pDr) { - if (ASMBitTest(pScreenIdMask, i)) - VBoxWddmInvalidateVideoModesInfo(pExt, i); + // vboxVdmaCBufDrCreate zero initializes the pDr + /* the command data follows the descriptor */ + pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR; + pDr->cbBuf = cbCmd; + pDr->rc = VERR_NOT_IMPLEMENTED; + + PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); + pHdr->enmType = VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ; + pHdr->u32CmdSpecific = 0; + PVBOXVDMACMD_CHILD_STATUS_IRQ pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHILD_STATUS_IRQ); + pBody->cInfos = 1; + if (idTarget == D3DDDI_ID_ALL) + { + pBody->fFlags |= VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL; + } + pBody->aInfos[0].iChild = idTarget; + pBody->aInfos[0].fFlags = VBOXVDMA_CHILD_STATUS_F_DISCONNECTED | VBOXVDMA_CHILD_STATUS_F_CONNECTED; + /* we're going to KeWaitForSingleObject */ + Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); + + PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr); + VBOXWDDMCHILDSTATUSCB Ctx; + KEVENT Event; + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Ctx.pDr = pDr; + Ctx.pEvent = &Event; + vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, vboxWddmChildStatusReportCompletion, &Ctx); + /* mark command as submitted & invisible for the dx runtime since dx did not originate it */ + vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd); + int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr); + Assert(rc == VINF_SUCCESS); + if (RT_SUCCESS(rc)) + { + Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Assert(Status == STATUS_SUCCESS); + return STATUS_SUCCESS; + } + + Status = STATUS_UNSUCCESSFUL; + + vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr); + } + else + { + /* @todo: try flushing.. */ + WARN(("vboxVdmaCBufDrCreate returned NULL")); + Status = STATUS_INSUFFICIENT_RESOURCES; } - /* ensure we have all the rest populated */ - VBoxWddmGetAllVideoModesInfos(pExt); - return g_aVBoxVideoModeInfos; + return Status; +#else + VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0}; + Body.cInfos = 1; + if (idTarget == D3DDDI_ID_ALL) + { + Body.fFlags |= VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL; + } + Body.aInfos[0].iChild = idTarget; + Body.aInfos[0].fFlags = VBOXVDMA_CHILD_STATUS_F_DISCONNECTED | VBOXVDMA_CHILD_STATUS_F_CONNECTED; + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + return vboxWddmChildStatusHandleRequest(pDevExt, &Body); +#endif } -PVBOXWDDM_VIDEOMODES_INFO VBoxWddmUpdateAllVideoModesInfos(PVBOXMP_DEVEXT pExt) +NTSTATUS vboxWddmChildStatusConnect(PVBOXMP_DEVEXT pDevExt, uint32_t iChild, BOOLEAN fConnect) { - VBoxWddmInvalidateAllVideoModesInfos(pExt); +#ifdef VBOX_WDDM_MONITOR_REPLUG_IRQ +# error "port me!" +#else + Assert(iChild < (uint32_t)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); + NTSTATUS Status = STATUS_SUCCESS; + VBOXVDMACMD_CHILD_STATUS_IRQ Body = {0}; + Body.cInfos = 1; + Body.aInfos[0].iChild = iChild; + Body.aInfos[0].fFlags = fConnect ? VBOXVDMA_CHILD_STATUS_F_CONNECTED : VBOXVDMA_CHILD_STATUS_F_DISCONNECTED; + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + Status = vboxWddmChildStatusHandleRequest(pDevExt, &Body); + if (!NT_SUCCESS(Status)) + WARN(("vboxWddmChildStatusHandleRequest failed Status 0x%x", Status)); + + return Status; +#endif +} + +void VBoxWddmUpdateVideoMode(PVBOXMP_DEVEXT pExt, int i) +{ + g_VBoxVideoModeTmp = g_aVBoxVideoModeInfos[i]; + + Assert(g_aVBoxVideoModeInfos[i].cModes); + + VBoxWddmInitVideoMode(pExt, i); + + if (!memcmp(&g_VBoxVideoModeTmp, &g_aVBoxVideoModeInfos[i], sizeof (g_VBoxVideoModeTmp))) + return; + +#ifdef DEBUG_misha + g_VBoxDbgBreakModes = 0; +#endif + +#ifdef DEBUG_misha + LOGREL(("modes changed for target %d", i)); +#else + LOG(("modes changed for target %d", i)); +#endif + vboxWddmChildStatusReportReconnected(pExt, (D3DDDI_VIDEO_PRESENT_TARGET_ID)i); +} + +PVBOXWDDM_VIDEOMODES_INFO VBoxWddmUpdateVideoModesInfoByMask(PVBOXMP_DEVEXT pExt, uint8_t *pScreenIdMask) +{ + for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i) + { + if (!pScreenIdMask || ASMBitTest(pScreenIdMask, i)) + { + VBoxWddmUpdateVideoMode(pExt, i); + } + } - /* ensure we have all the rest populated */ - VBoxWddmGetAllVideoModesInfos(pExt); return g_aVBoxVideoModeInfos; } @@ -1149,14 +1479,6 @@ void VBoxWddmAdjustMode(PVBOXMP_DEVEXT pExt, PVBOXWDDM_ADJUSTVIDEOMODE pMode) PVBOXWDDM_TARGET pTarget = &pExt->aTargets[pMode->Mode.Id]; /* @todo: this info should go from the target actually */ PVBOXWDDM_SOURCE pSource = &pExt->aSources[pMode->Mode.Id]; - if (pTarget->HeightVisible /* <- active */ - && pSource->AllocData.SurfDesc.width == pMode->Mode.Width - && pSource->AllocData.SurfDesc.height == pMode->Mode.Height - && pSource->AllocData.SurfDesc.bpp == pMode->Mode.BitsPerPixel) - { - pMode->fFlags = VBOXWDDM_ADJUSTVIDEOMODE_F_CURRENT; - return; - } UINT newWidth = pMode->Mode.Width; UINT newHeight = pMode->Mode.Height; @@ -1165,7 +1487,7 @@ void VBoxWddmAdjustMode(PVBOXMP_DEVEXT pExt, PVBOXWDDM_ADJUSTVIDEOMODE pMode) if (!VBoxMPValidateVideoModeParams(pExt, pMode->Mode.Id, newWidth, newHeight, newBpp)) { PVBOXWDDM_SOURCE pSource = &pExt->aSources[pMode->Mode.Id]; - pMode->fFlags = VBOXWDDM_ADJUSTVIDEOMODE_F_UNSUPPORTED; + pMode->fFlags |= VBOXWDDM_ADJUSTVIDEOMODE_F_UNSUPPORTED; } if (pMode->Mode.Width != newWidth @@ -1186,8 +1508,7 @@ void VBoxWddmAdjustMode(PVBOXMP_DEVEXT pExt, PVBOXWDDM_ADJUSTVIDEOMODE pMode) pMode->fFlags |= VBOXWDDM_ADJUSTVIDEOMODE_F_CURRENT; if (pMode->fFlags & VBOXWDDM_ADJUSTVIDEOMODE_F_UNSUPPORTED) { - WARN(("current mode is reported as unsupported, cleaning the unsupported flag")); - pMode->fFlags &= ~VBOXWDDM_ADJUSTVIDEOMODE_F_UNSUPPORTED; + WARN(("current mode is reported as unsupported")); } } } @@ -1234,49 +1555,8 @@ NTSTATUS VBoxWddmGetModesForResolution(VIDEO_MODE_INFORMATION *pAllModes, uint32 return Status; } -static PVBOXWDDM_VIDEOMODES_INFO vboxWddmGetVideoModesInfoInternal(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId) -{ - Assert(VidPnTargetId < (D3DDDI_VIDEO_PRESENT_TARGET_ID)VBoxCommonFromDeviceExt(pExt)->cDisplays); - if (VidPnTargetId >= (D3DDDI_VIDEO_PRESENT_TARGET_ID)VBoxCommonFromDeviceExt(pExt)->cDisplays) - { - return NULL; - } - - PVBOXWDDM_VIDEOMODES_INFO pInfo = &g_aVBoxVideoModeInfos[VidPnTargetId]; - - if (!pInfo->cModes) - { - VBoxWddmBuildVideoModesInfo(pExt, VidPnTargetId, pInfo, NULL, 0); - Assert(pInfo->cModes); - } - - return pInfo; -} - -static VOID vboxWddmAddVideoModes(PVBOXMP_DEVEXT pExt, PVBOXWDDM_VIDEOMODES_INFO pDstInfo, PVBOXWDDM_VIDEOMODES_INFO pSrcInfo) -{ - for (int i = 0; i < (int)pSrcInfo->cModes; ++i) - { - int foundIdx = VBoxMPFindVideoMode(pDstInfo->aModes, pDstInfo->cModes, &pSrcInfo->aModes[i]); - if (foundIdx >= 0) - continue; - - Assert(0); - pDstInfo->aModes[pDstInfo->cModes] = pSrcInfo->aModes[i]; - ++pDstInfo->cModes; - } - - VBoxWddmBuildResolutionTableForModes(pDstInfo); -} - PVBOXWDDM_VIDEOMODES_INFO VBoxWddmGetAllVideoModesInfos(PVBOXMP_DEVEXT pExt) { - /* ensure all modes are initialized */ - for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i) - { - vboxWddmGetVideoModesInfoInternal(pExt, (D3DDDI_VIDEO_PRESENT_TARGET_ID)i); - } - return g_aVBoxVideoModeInfos; } |