diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
|---|---|---|
| committer | <> | 2014-05-08 15:03:54 +0000 |
| commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
| tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Additions/WINNT/Graphics/Video/mp | |
| parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
| download | VirtualBox-master.tar.gz | |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Additions/WINNT/Graphics/Video/mp')
35 files changed, 5712 insertions, 3686 deletions
diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/Makefile.kmk b/src/VBox/Additions/WINNT/Graphics/Video/mp/Makefile.kmk index fa2e1fa4..9cffaf28 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/Makefile.kmk +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/Makefile.kmk @@ -87,13 +87,9 @@ ifdef VBOX_WITH_WDDM VBoxVideoWddm_DEFS += LOG_ENABLED endif VBoxVideoWddm_DEFS += LOG_TO_BACKDOOR - ifdef VBOX_WITH_CROGL - VBoxVideoWddm_DEFS += VBOX_WITH_CROGL - endif ifdef VBOX_VDMA_WITH_WATCHDOG VBoxVideoWddm_DEFS += VBOX_VDMA_WITH_WATCHDOG endif - VBoxVideoWddm_INCS += \ ../../../include \ .. \ @@ -121,14 +117,18 @@ ifdef VBOX_WITH_WDDM common/VBoxMPHGSMI.cpp \ common/VBoxMPVidModes.cpp \ $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp \ - $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/Modesetting.cpp - if defined(VBOX_WITH_CROGL) && defined(VBOX_WDDM_WITH_CRCMD) + $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/Modesetting.cpp \ + $(PATH_ROOT)/src/VBox/GuestHost/OpenGL/util/vreg.cpp + if defined(VBOX_WITH_CROGL) VBoxVideoWddm_SOURCES += \ $(PATH_ROOT)/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c \ $(PATH_ROOT)/src/VBox/GuestHost/OpenGL/packer/pack_bounds.c \ + $(PATH_ROOT)/src/VBox/GuestHost/OpenGL/packer/pack_visibleregion.c \ + $(PATH_ROOT)/src/VBox/GuestHost/OpenGL/packer/pack_misc.c \ $(VBOX_PATH_CROGL_GENFILES)/pack_bounds_swap.c \ wddm/VBoxMPCrUtil.cpp - VBoxVideoWddm_DEFS + VBOX_WDDM_WITH_CRCMD + VBoxVideoWddm_DEFS += VBOX_WITH_CROGL endif ifdef VBOXWDDM_WITH_VBVA VBoxVideoWddm_SOURCES += \ @@ -172,7 +172,7 @@ ifdef VBOX_WITH_WDDM $(PATH_SDK_$(VBOX_WINDDK_GST_W8)_LIB)/displib.lib \ $(PATH_SDK_$(VBOX_WINDDK_GST_W8)_LIB)/BufferOverflowK.lib endif # VBOX_WITH_WDDM_W8 - + endif # VBOX_WITH_WDDM # diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.cpp index 7efb22a3..7ff0edcc 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.h index 406d2965..6fe20d93 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPCommon.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,22 +29,19 @@ typedef bool(*PFNVIDEOIRQSYNC)(void *); bool VBoxMPCmnSyncToVideoIRQ(PVBOXMP_COMMON pCommon, PFNVIDEOIRQSYNC pfnSync, void *pvUser); /* Video modes related */ -#define VBOXMP_MAX_VIDEO_MODES 128 void VBoxMPCmnInitCustomVideoModes(PVBOXMP_DEVEXT pExt); VIDEO_MODE_INFORMATION* VBoxMPCmnGetCustomVideoModeInfo(ULONG ulIndex); -VIDEO_MODE_INFORMATION* VBoxMPCmnGetVideoModeInfo(ULONG ulIndex); #ifdef VBOX_XPDM_MINIPORT +VIDEO_MODE_INFORMATION* VBoxMPCmnGetVideoModeInfo(PVBOXMP_DEVEXT pExt, ULONG ulIndex); VIDEO_MODE_INFORMATION* VBoxMPXpdmCurrentVideoMode(PVBOXMP_DEVEXT pExt); -ULONG VBoxMPXpdmGetVideoModesCount(); +ULONG VBoxMPXpdmGetVideoModesCount(PVBOXMP_DEVEXT pExt); void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt); #endif #ifdef VBOX_WDDM_MINIPORT -void VBoxWddmInvalidateAllVideoModesInfos(PVBOXMP_DEVEXT pExt); -void VBoxWddmInvalidateVideoModesInfo(PVBOXMP_DEVEXT pExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId); PVBOXWDDM_VIDEOMODES_INFO VBoxWddmUpdateVideoModesInfoByMask(PVBOXMP_DEVEXT pExt, uint8_t *pScreenIdMask); -PVBOXWDDM_VIDEOMODES_INFO VBoxWddmUpdateAllVideoModesInfos(PVBOXMP_DEVEXT pExt); +void VBoxWddmInitVideoModes(PVBOXMP_DEVEXT pExt); NTSTATUS VBoxWddmGetModesForResolution(VIDEO_MODE_INFORMATION *pAllModes, uint32_t cAllModes, int iSearchPreferredMode, const D3DKMDT_2DREGION *pResolution, VIDEO_MODE_INFORMATION * pModes, uint32_t cModes, uint32_t *pcModes, int32_t *piPreferrableMode); diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPDevExt.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPDevExt.h index 965cb528..e61818fe 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPDevExt.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPDevExt.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,9 +30,13 @@ #endif #ifdef VBOX_WDDM_MINIPORT +# ifdef VBOX_WDDM_WIN8 +extern DWORD g_VBoxDisplayOnly; +# endif # include "wddm/VBoxMPTypes.h" #endif +#define VBOXMP_MAX_VIDEO_MODES 128 typedef struct VBOXMP_COMMON { int cDisplays; /* Number of displays. */ @@ -60,6 +64,8 @@ typedef struct VBOXMP_COMMON HGSMIHOSTCOMMANDCONTEXT hostCtx; /** Context information needed to submit commands to the host. */ HGSMIGUESTCOMMANDCONTEXT guestCtx; + + BOOLEAN fAnyX; /* Unrestricted horizontal resolution flag. */ } VBOXMP_COMMON, *PVBOXMP_COMMON; typedef struct _VBOXMP_DEVEXT @@ -71,7 +77,13 @@ typedef struct _VBOXMP_DEVEXT struct _VBOXMP_DEVEXT *pPrimary; /* Pointer to the primary device extension. */ ULONG iDevice; /* Device index: 0 for primary, otherwise a secondary device. */ - + /* Standart video modes list. + * Additional space is reserved for a custom video mode for this guest monitor. + * The custom video mode index is alternating for each mode set and 2 indexes are needed for the custom mode. + */ + VIDEO_MODE_INFORMATION aVideoModes[VBOXMP_MAX_VIDEO_MODES + 2]; + /* Number of available video modes, set by VBoxMPCmnBuildVideoModesTable. */ + uint32_t cVideoModes; ULONG CurrentMode; /* Saved information about video modes */ ULONG CurrentModeWidth; ULONG CurrentModeHeight; @@ -79,6 +91,11 @@ typedef struct _VBOXMP_DEVEXT ULONG ulFrameBufferOffset; /* The framebuffer position in the VRAM. */ ULONG ulFrameBufferSize; /* The size of the current framebuffer. */ + + uint8_t iInvocationCounter; + uint32_t Prev_xres; + uint32_t Prev_yres; + uint32_t Prev_bpp; #endif /*VBOX_XPDM_MINIPORT*/ #ifdef VBOX_WDDM_MINIPORT @@ -89,22 +106,37 @@ typedef struct _VBOXMP_DEVEXT uint8_t * pvVisibleVram; VBOXVIDEOCM_MGR CmMgr; + VBOXVIDEOCM_MGR SeamlessCtxMgr; /* hgsmi allocation manager */ VBOXVIDEOCM_ALLOC_MGR AllocMgr; VBOXVDMADDI_NODE aNodes[VBOXWDDM_NUM_NODES]; LIST_ENTRY DpcCmdQueue; LIST_ENTRY SwapchainList3D; /* mutex for context list operations */ - FAST_MUTEX ContextMutex; + KSPIN_LOCK ContextLock; KSPIN_LOCK SynchLock; volatile uint32_t cContexts3D; volatile uint32_t cContexts2D; + volatile uint32_t cContextsDispIfResize; volatile uint32_t cRenderFromShadowDisabledContexts; volatile uint32_t cUnlockedVBVADisabled; + + volatile uint32_t fCompletingCommands; + + DWORD dwDrvCfgFlags; /* this is examined and swicthed by DxgkDdiSubmitCommand only! */ volatile BOOLEAN fRenderToShadowDisabled; + BOOLEAN f3DEnabled; + BOOLEAN fTexPresentEnabled; + BOOLEAN fCmdVbvaEnabled; + + uint32_t u32CrConDefaultClientID; + + VBOXCMDVBVA CmdVbva; + VBOXMP_CRCTLCON CrCtlCon; + VBOXMP_CRSHGSMITRANSPORT CrHgsmiTransport; VBOXWDDM_GLOBAL_POINTER_INFO PointerInfo; @@ -119,7 +151,9 @@ typedef struct _VBOXMP_DEVEXT PKTHREAD pWdThread; KEVENT WdEvent; #endif - + BOOL bVSyncTimerEnabled; + volatile uint32_t fVSyncInVBlank; + volatile LARGE_INTEGER VSyncTime; KTIMER VSyncTimer; KDPC VSyncDpc; @@ -166,7 +200,6 @@ typedef struct _VBOXMP_DEVEXT } u; HGSMIAREA areaDisplay; /* Entire VRAM chunk for this display device. */ - BOOLEAN fAnyX; /* Unrestricted horizontal resolution flag. */ } VBOXMP_DEVEXT, *PVBOXMP_DEVEXT; DECLINLINE(PVBOXMP_DEVEXT) VBoxCommonToPrimaryExt(PVBOXMP_COMMON pCommon) @@ -186,21 +219,21 @@ DECLINLINE(PVBOXMP_COMMON) VBoxCommonFromDeviceExt(PVBOXMP_DEVEXT pExt) #ifdef VBOX_WDDM_MINIPORT DECLINLINE(ULONG) vboxWddmVramCpuVisibleSize(PVBOXMP_DEVEXT pDevExt) { -#ifdef VBOXWDDM_RENDER_FROM_SHADOW - /* all memory layout info should be initialized */ - Assert(pDevExt->aSources[0].Vbva.offVBVA); - /* page aligned */ - Assert(!(pDevExt->aSources[0].Vbva.offVBVA & 0xfff)); - - return (ULONG)(pDevExt->aSources[0].Vbva.offVBVA & ~0xfffULL); -#else + if (pDevExt->fCmdVbvaEnabled) + { + /* all memory layout info should be initialized */ + Assert(pDevExt->CmdVbva.Vbva.offVRAMBuffer); + /* page aligned */ + Assert(!(pDevExt->CmdVbva.Vbva.offVRAMBuffer & 0xfff)); + + return (ULONG)(pDevExt->CmdVbva.Vbva.offVRAMBuffer & ~0xfffULL); + } /* all memory layout info should be initialized */ - Assert(pDevExt->u.primary.Vdma.CmdHeap.Heap.area.offBase); + Assert(pDevExt->aSources[0].Vbva.Vbva.offVRAMBuffer); /* page aligned */ - Assert(!(pDevExt->u.primary.Vdma.CmdHeap.Heap.area.offBase & 0xfff)); + Assert(!(pDevExt->aSources[0].Vbva.Vbva.offVRAMBuffer & 0xfff)); - return pDevExt->u.primary.Vdma.CmdHeap.Heap.area.offBase & ~0xfffUL; -#endif + return (ULONG)(pDevExt->aSources[0].Vbva.Vbva.offVRAMBuffer & ~0xfffULL); } DECLINLINE(ULONG) vboxWddmVramCpuVisibleSegmentSize(PVBOXMP_DEVEXT pDevExt) diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.cpp index 51f03f8f..608abafb 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.h index a607463b..6dda2c7b 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPHGSMI.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.cpp index d9d353e8..bc7c39d8 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -61,7 +61,9 @@ vboxWinVersion_t VBoxQueryWinVersion() if(major == 6) { - if (minor == 2) + if (minor == 3) + s_WinVersion = WIN81; + else if (minor == 2) s_WinVersion = WIN8; else if (minor == 1) s_WinVersion = WIN7; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.h index 4e6512ca..85c711cb 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPUtils.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -27,6 +27,11 @@ #define LOG_GROUP LOG_GROUP_DRV_MINIPORT #include <VBox/log.h> #define VBOX_VIDEO_LOG_NAME "VBoxMP" +#ifdef VBOX_WDDM_MINIPORT +# ifndef VBOX_WDDM_MINIPORT_WITH_FLOW_LOGGING +# define VBOX_VIDEO_LOGFLOW_LOGGER(_m) do {} while (0) +# endif +#endif #include "common/VBoxVideoLog.h" #include <iprt/err.h> #include <iprt/assert.h> @@ -88,7 +93,8 @@ typedef enum WINXP = 3, WINVISTA = 4, WIN7 = 5, - WIN8 = 6 + WIN8 = 6, + WIN81 = 7 } vboxWinVersion_t; RT_C_DECLS_BEGIN 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; } diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.cpp index 7448c7b0..0335de34 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.cpp @@ -71,7 +71,7 @@ typedef struct VBOXVIDEOCM_SESSION /* event used to notify UMD about pending commands */ PKEVENT pUmEvent; /* sync lock */ - FAST_MUTEX Mutex; + KSPIN_LOCK SynchLock; /* indicates whether event signaling is needed on cmd add */ bool bEventNeeded; } VBOXVIDEOCM_SESSION, *PVBOXVIDEOCM_SESSION; @@ -180,8 +180,10 @@ static void vboxVideoCmCmdPostByHdr(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_ pHdr->CmdHdr.cbCmd = cbSize; } - Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); - ExAcquireFastMutex(&pSession->Mutex); + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + KIRQL OldIrql; + KeAcquireSpinLock(&pSession->SynchLock, &OldIrql); InsertHeadList(&pSession->CommandsList, &pHdr->QueueList); if (pSession->bEventNeeded) @@ -190,7 +192,7 @@ static void vboxVideoCmCmdPostByHdr(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_ bSignalEvent = true; } - ExReleaseFastMutex(&pSession->Mutex); + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); if (bSignalEvent) KeSetEvent(pSession->pUmEvent, 0, FALSE); @@ -224,7 +226,8 @@ NTSTATUS vboxVideoCmCmdVisit(PVBOXVIDEOCM_CTX pContext, BOOLEAN bEntireSession, PLIST_ENTRY pCurEntry = NULL; PVBOXVIDEOCM_CMD_DR pHdr; - ExAcquireFastMutex(&pSession->Mutex); + KIRQL OldIrql; + KeAcquireSpinLock(&pSession->SynchLock, &OldIrql); pCurEntry = pSession->CommandsList.Blink; do @@ -259,7 +262,7 @@ NTSTATUS vboxVideoCmCmdVisit(PVBOXVIDEOCM_CTX pContext, BOOLEAN bEntireSession, } while (1); - ExReleaseFastMutex(&pSession->Mutex); + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); return STATUS_SUCCESS; } @@ -279,11 +282,20 @@ static void vboxVideoCmSessionCtxAddLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXV void vboxVideoCmSessionCtxAdd(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext) { - Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); - ExAcquireFastMutex(&pSession->Mutex); + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KIRQL OldIrql; + KeAcquireSpinLock(&pSession->SynchLock, &OldIrql); + vboxVideoCmSessionCtxAddLocked(pSession, pContext); - ExReleaseFastMutex(&pSession->Mutex); + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); +} + +void vboxVideoCmSessionSignalEvent(PVBOXVIDEOCM_SESSION pSession) +{ + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + if (pSession->pUmEvent) + KeSetEvent(pSession->pUmEvent, 0, FALSE); } static void vboxVideoCmSessionDestroyLocked(PVBOXVIDEOCM_SESSION pSession) @@ -345,8 +357,10 @@ bool vboxVideoCmSessionCtxRemoveLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEO LIST_ENTRY *pCur; InitializeListHead(&RemainedList); InitializeListHead(&RemainedPpList); - Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); - ExAcquireFastMutex(&pSession->Mutex); + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KIRQL OldIrql; + KeAcquireSpinLock(&pSession->SynchLock, &OldIrql); + pContext->pSession = NULL; RemoveEntryList(&pContext->SessionEntry); bDestroy = !!(IsListEmpty(&pSession->ContextList)); @@ -361,7 +375,8 @@ bool vboxVideoCmSessionCtxRemoveLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEO vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->CommandsList, pContext, &RemainedList); vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &RemainedPpList); } - ExReleaseFastMutex(&pSession->Mutex); + + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); for (pCur = RemainedList.Flink; pCur != &RemainedList; pCur = RemainedList.Flink) { @@ -392,8 +407,8 @@ NTSTATUS vboxVideoCmSessionCreateLocked(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_SESS InitializeListHead(&pSession->CommandsList); InitializeListHead(&pSession->PpCommandsList); pSession->pUmEvent = pUmEvent; - Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); - ExInitializeFastMutex(&pSession->Mutex); + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KeInitializeSpinLock(&pSession->SynchLock); pSession->bEventNeeded = true; vboxVideoCmSessionCtxAddLocked(pSession, pContext); InsertHeadList(&pMgr->SessionList, &pSession->QueueEntry); @@ -420,44 +435,39 @@ NTSTATUS vboxVideoCmCtxAdd(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext, HAN Assert(Status == STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { - Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode, - FALSE, /* BOOLEAN Alertable */ - NULL /* PLARGE_INTEGER Timeout */ - ); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) + KIRQL OldIrql; + KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql); + + bool bFound = false; + PVBOXVIDEOCM_SESSION pSession = NULL; + for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink) { - bool bFound = false; - PVBOXVIDEOCM_SESSION pSession = NULL; - for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink) + pSession = VBOXCMENTRY_2_SESSION(pEntry); + if (pSession->pUmEvent == pUmEvent) { - pSession = VBOXCMENTRY_2_SESSION(pEntry); - if (pSession->pUmEvent == pUmEvent) - { - bFound = true; - break; - } + bFound = true; + break; } + } - pContext->u64UmData = u64UmData; + pContext->u64UmData = u64UmData; - if (!bFound) - { - Status = vboxVideoCmSessionCreateLocked(pMgr, &pSession, pUmEvent, pContext); - Assert(Status == STATUS_SUCCESS); - } - else - { - /* Status = */vboxVideoCmSessionCtxAdd(pSession, pContext); - /*Assert(Status == STATUS_SUCCESS);*/ - } - LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE); - Assert(!tstL); + if (!bFound) + { + Status = vboxVideoCmSessionCreateLocked(pMgr, &pSession, pUmEvent, pContext); + Assert(Status == STATUS_SUCCESS); + } + else + { + /* Status = */vboxVideoCmSessionCtxAdd(pSession, pContext); + /*Assert(Status == STATUS_SUCCESS);*/ + } - if (Status == STATUS_SUCCESS) - { - return STATUS_SUCCESS; - } + KeReleaseSpinLock(&pMgr->SynchLock, OldIrql); + + if (Status == STATUS_SUCCESS) + { + return STATUS_SUCCESS; } ObDereferenceObject(pUmEvent); @@ -471,24 +481,19 @@ NTSTATUS vboxVideoCmCtxRemove(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext) if (!pSession) return STATUS_SUCCESS; - NTSTATUS Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode, - FALSE, /* BOOLEAN Alertable */ - NULL /* PLARGE_INTEGER Timeout */ - ); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - { - vboxVideoCmSessionCtxRemoveLocked(pSession, pContext); - LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE); - Assert(!tstL); - } + KIRQL OldIrql; + KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql); - return Status; + vboxVideoCmSessionCtxRemoveLocked(pSession, pContext); + + KeReleaseSpinLock(&pMgr->SynchLock, OldIrql); + + return STATUS_SUCCESS; } NTSTATUS vboxVideoCmInit(PVBOXVIDEOCM_MGR pMgr) { - KeInitializeEvent(&pMgr->SynchEvent, SynchronizationEvent, TRUE); + KeInitializeSpinLock(&pMgr->SynchLock); InitializeListHead(&pMgr->SessionList); return STATUS_SUCCESS; } @@ -499,6 +504,25 @@ NTSTATUS vboxVideoCmTerm(PVBOXVIDEOCM_MGR pMgr) return STATUS_SUCCESS; } +NTSTATUS vboxVideoCmSignalEvents(PVBOXVIDEOCM_MGR pMgr) +{ + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + PVBOXVIDEOCM_SESSION pSession = NULL; + + KIRQL OldIrql; + KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql); + + for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink) + { + pSession = VBOXCMENTRY_2_SESSION(pEntry); + vboxVideoCmSessionSignalEvent(pSession); + } + + KeReleaseSpinLock(&pMgr->SynchLock, OldIrql); + + return STATUS_SUCCESS; +} + VOID vboxVideoCmProcessKm(PVBOXVIDEOCM_CTX pContext, PVBOXVIDEOCM_CMD_CTL_KM pCmd) { PVBOXVIDEOCM_SESSION pSession = pContext->pSession; @@ -514,9 +538,10 @@ VOID vboxVideoCmProcessKm(PVBOXVIDEOCM_CTX pContext, PVBOXVIDEOCM_CMD_CTL_KM pCm case VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE: { PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pCmd); - ExAcquireFastMutex(&pSession->Mutex); + KIRQL OldIrql; + KeAcquireSpinLock(&pSession->SynchLock, &OldIrql); InsertTailList(&pSession->PpCommandsList, &pHdr->QueueList); - ExReleaseFastMutex(&pSession->Mutex); + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); break; } @@ -549,8 +574,9 @@ NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXV InitializeListHead(&DetachedPpList); // PVBOXWDDM_GETVBOXVIDEOCMCMD_HDR *pvCmd - Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); - ExAcquireFastMutex(&pSession->Mutex); + Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL); + KIRQL OldIrql; + KeAcquireSpinLock(&pSession->SynchLock, &OldIrql); vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &DetachedPpList); @@ -605,7 +631,7 @@ NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXV } } while (1); - ExReleaseFastMutex(&pSession->Mutex); + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); vboxVideoCmSessionCtxPpList(pContext, &DetachedPpList); @@ -646,103 +672,22 @@ NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXV return STATUS_SUCCESS; } -VOID vboxVideoCmLock(PVBOXVIDEOCM_CTX pContext) -{ - ExAcquireFastMutex(&pContext->pSession->Mutex); -} - -VOID vboxVideoCmUnlock(PVBOXVIDEOCM_CTX pContext) -{ - ExReleaseFastMutex(&pContext->pSession->Mutex); -} - static BOOLEAN vboxVideoCmHasUncompletedCmdsLocked(PVBOXVIDEOCM_MGR pMgr) { PVBOXVIDEOCM_SESSION pSession = NULL; for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink) { pSession = VBOXCMENTRY_2_SESSION(pEntry); - ExAcquireFastMutex(&pSession->Mutex); + KIRQL OldIrql; + KeAcquireSpinLock(&pSession->SynchLock, &OldIrql); + if (pSession->bEventNeeded) { /* commands still being processed */ - ExReleaseFastMutex(&pSession->Mutex); + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); return TRUE; } - ExReleaseFastMutex(&pSession->Mutex); + KeReleaseSpinLock(&pSession->SynchLock, OldIrql); } return FALSE; } - -/* waits for all outstanding commands to completed by client - * assumptions here are: - * 1. no new commands are submitted while we are waiting - * 2. it is assumed that a client completes all previously received commands - * once it queries for the new set of commands */ -NTSTATUS vboxVideoCmWaitCompletedCmds(PVBOXVIDEOCM_MGR pMgr, uint32_t msTimeout) -{ - LARGE_INTEGER Timeout; - PLARGE_INTEGER pTimeout; - uint32_t cIters; - - if (msTimeout != RT_INDEFINITE_WAIT) - { - uint32_t msIter = 2; - cIters = msTimeout/msIter; - if (!cIters) - { - msIter = msTimeout; - cIters = 1; - } - Timeout.QuadPart = -(int64_t) msIter /* ms */ * 10000; - pTimeout = &Timeout; - } - else - { - pTimeout = NULL; - cIters = 1; - } - - Assert(cIters); - do - { - NTSTATUS Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode, - FALSE, /* BOOLEAN Alertable */ - pTimeout /* PLARGE_INTEGER Timeout */ - ); - if (Status == STATUS_TIMEOUT) - { - --cIters; - } - else - { - if (!NT_SUCCESS(Status)) - { - WARN(("KeWaitForSingleObject failed with Status (0x%x)", Status)); - return Status; - } - - /* succeeded */ - if (!vboxVideoCmHasUncompletedCmdsLocked(pMgr)) - { - LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE); - Assert(!tstL); - return STATUS_SUCCESS; - } - - LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE); - Assert(!tstL); - } - - if (!cIters) - break; - - KeDelayExecutionThread(KernelMode, FALSE, pTimeout); - --cIters; - if (!cIters) - break; - } while (0); - - return STATUS_TIMEOUT; -} - diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.h index fcf94bb9..21be672c 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.h @@ -21,7 +21,7 @@ typedef struct VBOXVIDEOCM_MGR { - KEVENT SynchEvent; + KSPIN_LOCK SynchLock; /* session list */ LIST_ENTRY SessionList; } VBOXVIDEOCM_MGR, *PVBOXVIDEOCM_MGR; @@ -40,6 +40,7 @@ NTSTATUS vboxVideoCmCtxAdd(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext, HAN NTSTATUS vboxVideoCmCtxRemove(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext); NTSTATUS vboxVideoCmInit(PVBOXVIDEOCM_MGR pMgr); NTSTATUS vboxVideoCmTerm(PVBOXVIDEOCM_MGR pMgr); +NTSTATUS vboxVideoCmSignalEvents(PVBOXVIDEOCM_MGR pMgr); NTSTATUS vboxVideoCmCmdSubmitCompleteEvent(PVBOXVIDEOCM_CTX pContext, PKEVENT pEvent); void* vboxVideoCmCmdCreate(PVBOXVIDEOCM_CTX pContext, uint32_t cbSize); @@ -57,9 +58,4 @@ NTSTATUS vboxVideoCmCmdVisit(PVBOXVIDEOCM_CTX pContext, BOOLEAN bEntireSession, NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD pCmd, uint32_t cbCmd); -NTSTATUS vboxVideoCmWaitCompletedCmds(PVBOXVIDEOCM_MGR pMgr, uint32_t msTimeout); - -VOID vboxVideoCmLock(PVBOXVIDEOCM_CTX pContext); -VOID vboxVideoCmUnlock(PVBOXVIDEOCM_CTX pContext); - #endif /* #ifndef ___VBoxMPCm_h___ */ diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.cpp index 070eb30f..0c55676d 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.cpp @@ -24,35 +24,18 @@ #ifdef VBOX_WITH_CROGL #include <cr_protocol.h> -# ifdef VBOX_WDDM_WITH_CRCMD -# include <cr_pack.h> +static uint32_t g_VBoxMpCrHostCaps = 0; +static uint32_t g_VBoxMpCr3DSupported = 0; -typedef struct VBOXMP_CRSHGSMICON_BUFDR +uint32_t VBoxMpCrGetHostCaps() { - uint32_t cbBuf; - void *pvBuf; -} VBOXMP_CRSHGSMICON_BUFDR, *PVBOXMP_CRSHGSMICON_BUFDR; - -typedef struct VBOXMP_CRSHGSMICON_BUFDR_CACHE -{ - volatile PVBOXMP_CRSHGSMICON_BUFDR pBufDr; -} VBOXMP_CRSHGSMICON_BUFDR_CACHE, *PVBOXMP_CRSHGSMICON_BUFDR_CACHE; - -typedef struct VBOXMP_CRSHGSMICON -{ - PVBOXMP_DEVEXT pDevExt; - PVBOXMP_CRCTLCON pCtlCon; - uint32_t u32ClientID; - VBOXMP_CRSHGSMICON_BUFDR_CACHE CmdDrCache; - VBOXMP_CRSHGSMICON_BUFDR_CACHE WbDrCache; -} VBOXMP_CRSHGSMICON, *PVBOXMP_CRSHGSMICON; + return g_VBoxMpCrHostCaps; +} -typedef struct VBOXMP_CRSHGSMIPACKER +bool VBoxMpCrCtlConIs3DSupported() { - PVBOXMP_CRSHGSMICON pCon; - CRPackContext CrPacker; - CRPackBuffer CrBuffer; -} VBOXMP_CRSHGSMIPACKER, *PVBOXMP_CRSHGSMIPACKER; + return !!g_VBoxMpCr3DSupported; +} static void* vboxMpCrShgsmiBufferAlloc(PVBOXMP_DEVEXT pDevExt, HGSMISIZE cbData) { @@ -61,7 +44,12 @@ static void* vboxMpCrShgsmiBufferAlloc(PVBOXMP_DEVEXT pDevExt, HGSMISIZE cbData) static VBOXVIDEOOFFSET vboxMpCrShgsmiBufferOffset(PVBOXMP_DEVEXT pDevExt, void *pvBuffer) { - return HGSMIPointerToOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx.Heap.area, (const HGSMIBUFFERHEADER *)pvBuffer); + return (VBOXVIDEOOFFSET)HGSMIPointerToOffset(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx.Heap.area, (const HGSMIBUFFERHEADER *)pvBuffer); +} + +static void* vboxMpCrShgsmiBufferFromOffset(PVBOXMP_DEVEXT pDevExt, VBOXVIDEOOFFSET offBuffer) +{ + return HGSMIOffsetToPointer(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx.Heap.area, (HGSMIOFFSET)offBuffer); } static void vboxMpCrShgsmiBufferFree(PVBOXMP_DEVEXT pDevExt, void *pvBuffer) @@ -69,38 +57,38 @@ static void vboxMpCrShgsmiBufferFree(PVBOXMP_DEVEXT pDevExt, void *pvBuffer) VBoxSHGSMIHeapBufferFree(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, pvBuffer); } -static void* vboxMpCrShgsmiConAlloc(PVBOXMP_CRSHGSMICON pCon, uint32_t cbBuffer) +static VBOXVIDEOOFFSET vboxMpCrShgsmiTransportBufOffset(PVBOXMP_CRSHGSMITRANSPORT pCon, void* pvBuffer) { - return vboxMpCrShgsmiBufferAlloc(pCon->pDevExt, cbBuffer); + return vboxMpCrShgsmiBufferOffset(pCon->pDevExt, pvBuffer); } -static VBOXVIDEOOFFSET vboxMpCrShgsmiConBufOffset(PVBOXMP_CRSHGSMICON pCon, void* pvBuffer) +static void* vboxMpCrShgsmiTransportBufFromOffset(PVBOXMP_CRSHGSMITRANSPORT pCon, VBOXVIDEOOFFSET offBuffer) { - return vboxMpCrShgsmiBufferOffset(pCon->pDevExt, pvBuffer); + return vboxMpCrShgsmiBufferFromOffset(pCon->pDevExt, offBuffer); } +void* VBoxMpCrShgsmiTransportBufAlloc(PVBOXMP_CRSHGSMITRANSPORT pCon, uint32_t cbBuffer) +{ + return vboxMpCrShgsmiBufferAlloc(pCon->pDevExt, cbBuffer); +} -static void vboxMpCrShgsmiConFree(PVBOXMP_CRSHGSMICON pCon, void* pvBuffer) +void VBoxMpCrShgsmiTransportBufFree(PVBOXMP_CRSHGSMITRANSPORT pCon, void* pvBuffer) { vboxMpCrShgsmiBufferFree(pCon->pDevExt, pvBuffer); } -#define VBOXMP_CRSHGSMICON_DR_CMDBUF_OFFSET(_cBuffers) VBOXWDDM_ROUNDBOUND((VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[_cBuffers]))), 8) -#define VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(_pDr, _cBuffers, _type) ((_type*)(((uint8_t*)(_pDr)) + VBOXMP_CRSHGSMICON_DR_CMDBUF_OFFSET(_cBuffers))) -#define VBOXMP_CRSHGSMICON_DR_SIZE(_cBuffers, _cbCmdBuf) ( VBOXMP_CRSHGSMICON_DR_CMDBUF_OFFSET(_cBuffers) + _cbCmdBuf) - -static int vboxMpCrShgsmiBufCacheBufReinit(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, PVBOXMP_CRSHGSMICON_BUFDR pDr, uint32_t cbRequested) +static int vboxMpCrShgsmiBufCacheBufReinit(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, PVBOXMP_CRSHGSMICON_BUFDR pDr, uint32_t cbRequested) { if (pDr->cbBuf >= cbRequested) return VINF_SUCCESS; if (pDr->pvBuf) - vboxMpCrShgsmiConFree(pCon, pDr->pvBuf); + VBoxMpCrShgsmiTransportBufFree(pCon, pDr->pvBuf); - pDr->pvBuf = vboxMpCrShgsmiConAlloc(pCon, cbRequested); + pDr->pvBuf = VBoxMpCrShgsmiTransportBufAlloc(pCon, cbRequested); if (!pDr->pvBuf) { - WARN(("vboxMpCrShgsmiConAlloc failed")); + WARN(("VBoxMpCrShgsmiTransportBufAlloc failed")); pDr->cbBuf = 0; return VERR_NO_MEMORY; } @@ -109,13 +97,13 @@ static int vboxMpCrShgsmiBufCacheBufReinit(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_CRS return VINF_SUCCESS; } -static void vboxMpCrShgsmiBufCacheFree(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, PVBOXMP_CRSHGSMICON_BUFDR pDr) +static void vboxMpCrShgsmiBufCacheFree(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, PVBOXMP_CRSHGSMICON_BUFDR pDr) { if (ASMAtomicCmpXchgPtr(&pCache->pBufDr, pDr, NULL)) return; /* the value is already cached, free the current one */ - vboxMpCrShgsmiConFree(pCon, pDr->pvBuf); + VBoxMpCrShgsmiTransportBufFree(pCon, pDr->pvBuf); vboxWddmMemFree(pDr); } @@ -134,7 +122,7 @@ static PVBOXMP_CRSHGSMICON_BUFDR vboxMpCrShgsmiBufCacheGetAllocDr(PVBOXMP_CRSHGS return pBufDr; } -static PVBOXMP_CRSHGSMICON_BUFDR vboxMpCrShgsmiBufCacheAlloc(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, uint32_t cbBuffer) +static PVBOXMP_CRSHGSMICON_BUFDR vboxMpCrShgsmiBufCacheAlloc(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, uint32_t cbBuffer) { PVBOXMP_CRSHGSMICON_BUFDR pBufDr = vboxMpCrShgsmiBufCacheGetAllocDr(pCache); int rc = vboxMpCrShgsmiBufCacheBufReinit(pCon, pCache, pBufDr, cbBuffer); @@ -147,7 +135,7 @@ static PVBOXMP_CRSHGSMICON_BUFDR vboxMpCrShgsmiBufCacheAlloc(PVBOXMP_CRSHGSMICON return NULL; } -static PVBOXMP_CRSHGSMICON_BUFDR vboxMpCrShgsmiBufCacheAllocAny(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, uint32_t cbBuffer) +static PVBOXMP_CRSHGSMICON_BUFDR vboxMpCrShgsmiBufCacheAllocAny(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache, uint32_t cbBuffer) { PVBOXMP_CRSHGSMICON_BUFDR pBufDr = vboxMpCrShgsmiBufCacheGetAllocDr(pCache); @@ -165,128 +153,396 @@ static PVBOXMP_CRSHGSMICON_BUFDR vboxMpCrShgsmiBufCacheAllocAny(PVBOXMP_CRSHGSMI } -static int vboxMpCrShgsmiBufCacheInit(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache) +static int vboxMpCrShgsmiBufCacheInit(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache) { memset(pCache, 0, sizeof (*pCache)); return VINF_SUCCESS; } -static void vboxMpCrShgsmiBufCacheTerm(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache) +static void vboxMpCrShgsmiBufCacheTerm(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_CRSHGSMICON_BUFDR_CACHE pCache) { if (pCache->pBufDr) vboxMpCrShgsmiBufCacheFree(pCon, pCache, pCache->pBufDr); } -static int vboxMpCrShgsmiConConnect(PVBOXMP_CRSHGSMICON pCon, PVBOXMP_DEVEXT pDevExt, PVBOXMP_CRCTLCON pCrCtlCon) +int VBoxMpCrShgsmiTransportCreate(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_DEVEXT pDevExt) { memset(pCon, 0, sizeof (*pCon)); - int rc = vboxMpCrShgsmiBufCacheInit(pCon, &pCon->CmdDrCache); - if (RT_SUCCESS(rc)) + pCon->pDevExt = pDevExt; + return VINF_SUCCESS; + int rc; +// int rc = vboxMpCrShgsmiBufCacheInit(pCon, &pCon->CmdDrCache); +// if (RT_SUCCESS(rc)) { rc = vboxMpCrShgsmiBufCacheInit(pCon, &pCon->WbDrCache); if (RT_SUCCESS(rc)) { - rc = VBoxMpCrCtlConConnect(pCrCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pCon->u32ClientID); - if (RT_SUCCESS(rc)) - { - pCon->pDevExt = pDevExt; - pCon->pCtlCon = pCrCtlCon; - return VINF_SUCCESS; - } - else - { - WARN(("VBoxMpCrCtlConConnect failed rc %d", rc)); - } - vboxMpCrShgsmiBufCacheTerm(pCon, &pCon->WbDrCache); } else { WARN(("vboxMpCrShgsmiBufCacheInit2 failed rc %d", rc)); } - vboxMpCrShgsmiBufCacheTerm(pCon, &pCon->CmdDrCache); +// vboxMpCrShgsmiBufCacheTerm(pCon, &pCon->CmdDrCache); } - else +// else +// { +// WARN(("vboxMpCrShgsmiBufCacheInit1 failed rc %d", rc)); +// } + + return rc; +} + +void VBoxMpCrShgsmiTransportTerm(PVBOXMP_CRSHGSMITRANSPORT pCon) +{ + vboxMpCrShgsmiBufCacheTerm(pCon, &pCon->WbDrCache); +// vboxMpCrShgsmiBufCacheTerm(pCon, &pCon->CmdDrCache); +} + +typedef struct VBOXMP_CRHGSMICMD_BASE +{ +// VBOXMP_CRHGSMICMD_HDR Hdr; + CRVBOXHGSMIHDR CmdHdr; +} VBOXMP_CRHGSMICMD_BASE, *PVBOXMP_CRHGSMICMD_BASE; + +typedef struct VBOXMP_CRHGSMICMD_WRITEREAD +{ +// VBOXMP_CRHGSMICMD_HDR Hdr; + CRVBOXHGSMIWRITEREAD Cmd; +} VBOXMP_CRHGSMICMD_WRITEREAD, *PVBOXMP_CRHGSMICMD_WRITEREAD; + +typedef struct VBOXMP_CRHGSMICMD_READ +{ +// VBOXMP_CRHGSMICMD_HDR Hdr; + CRVBOXHGSMIREAD Cmd; +} VBOXMP_CRHGSMICMD_READ, *PVBOXMP_CRHGSMICMD_READ; + +typedef struct VBOXMP_CRHGSMICMD_WRITE +{ +// VBOXMP_CRHGSMICMD_HDR Hdr; + CRVBOXHGSMIWRITE Cmd; +} VBOXMP_CRHGSMICMD_WRITE, *PVBOXMP_CRHGSMICMD_WRITE; + +#define VBOXMP_CRSHGSMICON_DR_CMDBUF_OFFSET(_cBuffers) VBOXWDDM_ROUNDBOUND((VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[_cBuffers]))), 8) +#define VBOXMP_CRSHGSMICON_DR_CMDCTX_OFFSET(_cBuffers, _cbCmdBuf) ( VBOXMP_CRSHGSMICON_DR_CMDBUF_OFFSET(_cBuffers) + VBOXWDDM_ROUNDBOUND(_cbCmdBuf, 8)) +#define VBOXMP_CRSHGSMICON_DR_GET_CRCMD(_pDr) (VBOXVDMACMD_BODY((_pDr), VBOXVDMACMD_CHROMIUM_CMD)) +#define VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(_pDr, _cBuffers, _type) ((_type*)(((uint8_t*)(_pDr)) + VBOXMP_CRSHGSMICON_DR_CMDBUF_OFFSET(_cBuffers))) +#define VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(_pDr, _cBuffers, _cbCmdBuf, _type) ((_type*)(((uint8_t*)(_pDr)) + VBOXMP_CRSHGSMICON_DR_CMDCTX_OFFSET(_cBuffers, _cbCmdBuf))) +#define VBOXMP_CRSHGSMICON_DR_GET_FROM_CMDCTX(_pCtx, _cBuffers, _cbCmdBuf) ((VBOXVDMACMD*)(((uint8_t*)(_pCtx)) - VBOXMP_CRSHGSMICON_DR_CMDCTX_OFFSET(_cBuffers, _cbCmdBuf))) +#define VBOXMP_CRSHGSMICON_DR_SIZE(_cBuffers, _cbCmdBuf, _cbCtx) (VBOXMP_CRSHGSMICON_DR_CMDCTX_OFFSET(_cBuffers, _cbCmdBuf) + (_cbCtx)) + + +static int vboxMpCrShgsmiTransportCmdSubmitDr(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXVDMACBUF_DR pDr, PFNVBOXVDMADDICMDCOMPLETE_DPC pfnComplete) +{ + + PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr); + PVBOXMP_DEVEXT pDevExt = pCon->pDevExt; + vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, pfnComplete, pCon); + /* 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); + if (RT_SUCCESS(rc)) { - WARN(("vboxMpCrShgsmiBufCacheInit1 failed rc %d", rc)); + return VINF_SUCCESS; } + WARN(("vboxVdmaCBufDrSubmit failed rc %d", rc)); return rc; } -static int vboxMpCrShgsmiConDisconnect(PVBOXMP_CRSHGSMICON pCon) +static int vboxMpCrShgsmiTransportCmdSubmitDmaCmd(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXVDMACMD pHdr, PFNVBOXVDMADDICMDCOMPLETE_DPC pfnComplete) { - int rc = VBoxMpCrCtlConDisconnect(pCon->pCtlCon, pCon->u32ClientID); - if (RT_FAILURE(rc)) + PVBOXVDMACBUF_DR pDr = VBOXVDMACBUF_DR_FROM_TAIL(pHdr); + return vboxMpCrShgsmiTransportCmdSubmitDr(pCon, pDr, pfnComplete); +} + +static void vboxMpCrShgsmiTransportCmdTermDmaCmd(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXVDMACMD pHdr) +{ + PVBOXVDMACBUF_DR pDr = VBOXVDMACBUF_DR_FROM_TAIL(pHdr); + PVBOXMP_DEVEXT pDevExt = pCon->pDevExt; + vboxVdmaCBufDrFree (&pDevExt->u.primary.Vdma, pDr); +} + + +typedef DECLCALLBACK(void) FNVBOXMP_CRSHGSMITRANSPORT_SENDREADASYNC_COMPLETION(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvRx, uint32_t cbRx, void *pvCtx); +typedef FNVBOXMP_CRSHGSMITRANSPORT_SENDREADASYNC_COMPLETION *PFNVBOXMP_CRSHGSMITRANSPORT_SENDREADASYNC_COMPLETION; + +static DECLCALLBACK(VOID) vboxMpCrShgsmiTransportSendReadAsyncCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pDdiCmd, PVOID pvContext) +{ + /* we should be called from our DPC routine */ + Assert(KeGetCurrentIrql() == DISPATCH_LEVEL); + + PVBOXMP_CRSHGSMITRANSPORT pCon = (PVBOXMP_CRSHGSMITRANSPORT)pvContext; + PVBOXVDMACBUF_DR pDr = VBOXVDMACBUF_DR_FROM_DDI_CMD(pDdiCmd); + PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); + VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXMP_CRSHGSMICON_DR_GET_CRCMD(pHdr); + const UINT cBuffers = 2; + Assert(pBody->cBuffers == cBuffers); + PVBOXMP_CRHGSMICMD_READ pWrData = VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(pHdr, cBuffers, VBOXMP_CRHGSMICMD_READ); + CRVBOXHGSMIREAD *pCmd = &pWrData->Cmd; + VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[0]; + Assert(pBufCmd->cbBuffer == sizeof (CRVBOXHGSMIREAD)); + CRVBOXHGSMIREAD * pWr = (CRVBOXHGSMIREAD*)vboxMpCrShgsmiTransportBufFromOffset(pCon, pBufCmd->offBuffer); + PFNVBOXMP_CRSHGSMITRANSPORT_SENDREADASYNC_COMPLETION pfnCompletion = (PFNVBOXMP_CRSHGSMITRANSPORT_SENDREADASYNC_COMPLETION)pBufCmd->u64GuestData; + VBOXVDMACMD_CHROMIUM_BUFFER *pRxBuf = &pBody->aBuffers[1]; + PVBOXMP_CRSHGSMICON_BUFDR pWbDr = (PVBOXMP_CRSHGSMICON_BUFDR)pRxBuf->u64GuestData; + void *pvRx = NULL; + uint32_t cbRx = 0; + + int rc = pDr->rc; + if (RT_SUCCESS(rc)) { - WARN(("VBoxMpCrCtlConDisconnect failed rc %d", rc)); - return rc; + rc = pWr->hdr.result; + if (RT_SUCCESS(rc)) + { + cbRx = pCmd->cbBuffer; + if (cbRx) + pvRx = pWbDr->pvBuf; + } + else + { + WARN(("CRVBOXHGSMIREAD failed, rc %d", rc)); + } + } + else + { + WARN(("dma command buffer failed rc %d!", rc)); } - vboxMpCrShgsmiBufCacheTerm(pCon, &pCon->WbDrCache); - vboxMpCrShgsmiBufCacheTerm(pCon, &pCon->CmdDrCache); + if (pfnCompletion) + { + void *pvCtx = VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(pHdr, cBuffers, sizeof (VBOXMP_CRHGSMICMD_READ), void); + pfnCompletion(pCon, rc, pvRx, cbRx, pvCtx); + } - return VINF_SUCCESS; + vboxMpCrShgsmiBufCacheFree(pCon, &pCon->WbDrCache, pWbDr); +} + +static void* vboxMpCrShgsmiTransportCmdCreateReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, uint32_t u32ClientID, PVBOXVDMACBUF_DR pDr, uint32_t cbDrData, PVBOXMP_CRSHGSMICON_BUFDR pWbDr, + PFNVBOXMP_CRSHGSMITRANSPORT_SENDREADASYNC_COMPLETION pfnCompletion, uint32_t cbContextData) +{ + const uint32_t cBuffers = 2; + const uint32_t cbCmd = VBOXMP_CRSHGSMICON_DR_SIZE(cBuffers, sizeof (VBOXMP_CRHGSMICMD_READ), cbContextData); + PVBOXMP_DEVEXT pDevExt = pCon->pDevExt; + PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); + VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXMP_CRSHGSMICON_DR_GET_CRCMD(pHdr); + PVBOXMP_CRHGSMICMD_READ pWrData = VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(pHdr, cBuffers, VBOXMP_CRHGSMICMD_READ); + CRVBOXHGSMIREAD *pCmd = &pWrData->Cmd; + + if (cbCmd > cbContextData) + { + ERR(("the passed descriptor is less than needed!")); + return NULL; + } + + memset(pDr, 0, VBOXVDMACBUF_DR_SIZE(cbCmd)); + + pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET; + pDr->cbBuf = cbCmd; + pDr->rc = VERR_NOT_IMPLEMENTED; + pDr->Location.offVramBuf = vboxMpCrShgsmiTransportBufOffset(pCon, pCmd); + + pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD; + pHdr->u32CmdSpecific = 0; + + pBody->cBuffers = cBuffers; + + pCmd->hdr.result = VERR_WRONG_ORDER; + pCmd->hdr.u32ClientID = u32ClientID; + pCmd->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ; + // pCmd->hdr.u32Reserved = 0; + pCmd->iBuffer = 1; + + VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[0]; + pBufCmd->offBuffer = vboxMpCrShgsmiTransportBufOffset(pCon, pCmd); + pBufCmd->cbBuffer = sizeof (*pCmd); + pBufCmd->u32GuestData = 0; + pBufCmd->u64GuestData = (uint64_t)pfnCompletion; + + pBufCmd = &pBody->aBuffers[1]; + pBufCmd->offBuffer = vboxMpCrShgsmiTransportBufOffset(pCon, pWbDr->pvBuf); + pBufCmd->cbBuffer = pWbDr->cbBuf; + pBufCmd->u32GuestData = 0; + pBufCmd->u64GuestData = (uint64_t)pWbDr; + + return VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(pHdr, cBuffers, sizeof (VBOXMP_CRHGSMICMD_READ), void); } -typedef DECLCALLBACK(void) FNVBOXMP_CRSHGSMICON_SEND_COMPLETION(PVBOXMP_CRSHGSMICON pCon, void *pvRx, uint32_t cbRx, void *pvCtx); -typedef FNVBOXMP_CRSHGSMICON_SEND_COMPLETION *PFNVBOXMP_CRSHGSMICON_SEND_COMPLETION; +static int vboxMpCrShgsmiTransportCmdSubmitReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext) +{ + VBOXVDMACMD* pHdr = VBOXMP_CRSHGSMICON_DR_GET_FROM_CMDCTX(pvContext, 2, sizeof (VBOXMP_CRHGSMICMD_READ)); + return vboxMpCrShgsmiTransportCmdSubmitDmaCmd(pCon, pHdr, vboxMpCrShgsmiTransportSendReadAsyncCompletion); +} -typedef struct VBOXMP_CRSHGSMICON_SEND_COMPLETION +typedef struct VBOXMP_CRHGSMICON_WRR_COMPLETION_CTX { - PVBOXMP_CRSHGSMICON pCon; - PFNVBOXMP_CRSHGSMICON_SEND_COMPLETION pvnCompletion; - void *pvCompletion; -} VBOXMP_CRSHGSMICON_SEND_COMPLETION, *PVBOXMP_CRSHGSMICON_SEND_COMPLETION; + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion; + void *pvContext; + +} VBOXMP_CRHGSMICON_WRR_COMPLETION_CTX, *PVBOXMP_CRHGSMICON_WRR_COMPLETION_CTX; -static DECLCALLBACK(VOID) vboxMpCrShgsmiConSendAsyncCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext) +static DECLCALLBACK(void) vboxMpCrShgsmiTransportSendWriteReadReadRepostCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvRx, uint32_t cbRx, void *pvCtx) +{ + PVBOXMP_CRHGSMICON_WRR_COMPLETION_CTX pData = (PVBOXMP_CRHGSMICON_WRR_COMPLETION_CTX)pvCtx; + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion = pData->pfnCompletion; + if (pfnCompletion) + pfnCompletion(pCon, rc, pvRx, cbRx, pData->pvContext); +} + +static DECLCALLBACK(VOID) vboxMpCrShgsmiTransportSendWriteReadAsyncCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pDdiCmd, PVOID pvContext) { /* we should be called from our DPC routine */ Assert(KeGetCurrentIrql() == DISPATCH_LEVEL); - PVBOXMP_CRSHGSMICON_SEND_COMPLETION pData = (PVBOXMP_CRSHGSMICON_SEND_COMPLETION)pvContext; - PVBOXVDMACBUF_DR pDr = VBOXVDMACBUF_DR_FROM_DDI_CMD(pCmd); + PVBOXMP_CRSHGSMITRANSPORT pCon = (PVBOXMP_CRSHGSMITRANSPORT)pvContext; + PVBOXVDMACBUF_DR pDr = VBOXVDMACBUF_DR_FROM_DDI_CMD(pDdiCmd); PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); - VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD); - UINT cBufs = pBody->cBuffers; - /* the first one is a command buffer: obtain it and get the result */ + VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXMP_CRSHGSMICON_DR_GET_CRCMD(pHdr); + const UINT cBuffers = 3; + Assert(pBody->cBuffers == cBuffers); + PVBOXMP_CRHGSMICMD_WRITEREAD pWrData = VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(pHdr, cBuffers, VBOXMP_CRHGSMICMD_WRITEREAD); + CRVBOXHGSMIWRITEREAD *pCmd = &pWrData->Cmd; + VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[0]; + Assert(pBufCmd->cbBuffer == sizeof (CRVBOXHGSMIWRITEREAD)); + CRVBOXHGSMIWRITEREAD * pWr = (CRVBOXHGSMIWRITEREAD*)vboxMpCrShgsmiTransportBufFromOffset(pCon, pBufCmd->offBuffer); + VBOXVDMACMD_CHROMIUM_BUFFER *pRxBuf = &pBody->aBuffers[2]; + PVBOXMP_CRSHGSMICON_BUFDR pWbDr = (PVBOXMP_CRSHGSMICON_BUFDR)pRxBuf->u64GuestData; + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion = (PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION)pBufCmd->u64GuestData; + void *pvRx = NULL; + uint32_t cbRx = 0; + + int rc = pDr->rc; + if (RT_SUCCESS(rc)) + { + rc = pWr->hdr.result; + if (RT_SUCCESS(rc)) + { + cbRx = pCmd->cbWriteback; + if (cbRx) + pvRx = pWbDr->pvBuf; + } + else if (rc == VERR_BUFFER_OVERFLOW) + { + /* issue read */ + void *pvCtx = VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(pHdr, cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITEREAD), void); + vboxMpCrShgsmiBufCacheFree(pCon, &pCon->WbDrCache, pWbDr); + pWbDr = vboxMpCrShgsmiBufCacheAlloc(pCon, &pCon->WbDrCache, pCmd->cbWriteback); + if (pWbDr) + { + /* the Read Command is shorter than WriteRead, so just reuse the Write-Read descriptor here */ + PVBOXMP_CRHGSMICON_WRR_COMPLETION_CTX pReadCtx = (PVBOXMP_CRHGSMICON_WRR_COMPLETION_CTX)vboxMpCrShgsmiTransportCmdCreateReadAsync(pCon, pCmd->hdr.u32ClientID, + pDr, VBOXMP_CRSHGSMICON_DR_SIZE(cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITEREAD), 0), + pWbDr, vboxMpCrShgsmiTransportSendWriteReadReadRepostCompletion, sizeof (*pReadCtx)); + pReadCtx->pfnCompletion = pfnCompletion; + pReadCtx->pvContext = pvCtx; + vboxMpCrShgsmiTransportCmdSubmitReadAsync(pCon, pReadCtx); + /* don't do completion here, the completion will be called from the read completion we issue here */ + pfnCompletion = NULL; + /* the current pWbDr was already freed, and we'll free the Read dr in the Read Completion */ + pWbDr = NULL; + } + else + { + WARN(("vboxMpCrShgsmiBufCacheAlloc failed for %d", pCmd->cbWriteback)); + rc = VERR_NO_MEMORY; + } + } + else + { + WARN(("CRVBOXHGSMIWRITEREAD failed, rc %d", rc)); + } + } + else + { + WARN(("dma command buffer failed rc %d!", rc)); + } + + if (pfnCompletion) + { + void *pvCtx = VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(pHdr, cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITEREAD), void); + pfnCompletion(pCon, rc, pvRx, cbRx, pvCtx); + } + + if (pWbDr) + vboxMpCrShgsmiBufCacheFree(pCon, &pCon->WbDrCache, pWbDr); +} + +static DECLCALLBACK(VOID) vboxMpCrShgsmiTransportSendWriteAsyncCompletion(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pDdiCmd, PVOID pvContext) +{ + /* we should be called from our DPC routine */ + Assert(KeGetCurrentIrql() == DISPATCH_LEVEL); - /* if write back buffer is too small, issue read command. - * we can use exactly the same command buffer for it */ - /* impl */ - Assert(0); + PVBOXMP_CRSHGSMITRANSPORT pCon = (PVBOXMP_CRSHGSMITRANSPORT)pvContext; + PVBOXVDMACBUF_DR pDr = VBOXVDMACBUF_DR_FROM_DDI_CMD(pDdiCmd); + PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); + VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXMP_CRSHGSMICON_DR_GET_CRCMD(pHdr); + const UINT cBuffers = 2; + Assert(pBody->cBuffers == cBuffers); + PVBOXMP_CRHGSMICMD_WRITE pWrData = VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(pHdr, cBuffers, VBOXMP_CRHGSMICMD_WRITE); + CRVBOXHGSMIWRITE *pCmd = &pWrData->Cmd; + VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[0]; + Assert(pBufCmd->cbBuffer == sizeof (CRVBOXHGSMIWRITE)); + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEASYNC_COMPLETION pfnCompletion = (PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEASYNC_COMPLETION)pBufCmd->u64GuestData; + + int rc = pDr->rc; + if (RT_SUCCESS(rc)) + { + rc = pCmd->hdr.result; + if (!RT_SUCCESS(rc)) + { + WARN(("CRVBOXHGSMIWRITE failed, rc %d", rc)); + } + } + else + { + WARN(("dma command buffer failed rc %d!", rc)); + } + + if (pfnCompletion) + { + void *pvCtx = VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(pHdr, cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITE), void); + pfnCompletion(pCon, rc, pvCtx); + } } -static int vboxMpCrShgsmiConSendAsync(PVBOXMP_CRSHGSMICON pCon, void *pvTx, uint32_t cbTx, PFNVBOXMP_CRSHGSMICON_SEND_COMPLETION pfnCompletion, void *pvCompletion) +void* VBoxMpCrShgsmiTransportCmdCreateWriteReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, uint32_t u32ClientID, void *pvBuffer, uint32_t cbBuffer, + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion, uint32_t cbContextData) { const uint32_t cBuffers = 3; - const uint32_t cbCmd = VBOXMP_CRSHGSMICON_DR_SIZE(cBuffers, sizeof (CRVBOXHGSMIWRITEREAD)); - PVBOXMP_CRSHGSMICON_BUFDR pCmdDr = vboxMpCrShgsmiBufCacheAlloc(pCon, &pCon->CmdDrCache, cbCmd); - if (!pCmdDr) + const uint32_t cbCmd = VBOXMP_CRSHGSMICON_DR_SIZE(cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITEREAD), cbContextData); + PVBOXMP_DEVEXT pDevExt = pCon->pDevExt; + PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd); + if (!pDr) { - WARN(("vboxMpCrShgsmiBufCacheAlloc for cmd dr failed")); - return VERR_NO_MEMORY; + WARN(("vboxVdmaCBufDrCreate failed")); + return NULL; } + PVBOXMP_CRSHGSMICON_BUFDR pWbDr = vboxMpCrShgsmiBufCacheAllocAny(pCon, &pCon->WbDrCache, 1000); if (!pWbDr) { WARN(("vboxMpCrShgsmiBufCacheAlloc for wb dr failed")); - vboxMpCrShgsmiBufCacheFree(pCon, &pCon->CmdDrCache, pCmdDr); - return VERR_NO_MEMORY; + vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr); + return NULL; } - PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pCmdDr->pvBuf; + PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); + VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXMP_CRSHGSMICON_DR_GET_CRCMD(pHdr); + PVBOXMP_CRHGSMICMD_WRITEREAD pWrData = VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(pHdr, cBuffers, VBOXMP_CRHGSMICMD_WRITEREAD); + CRVBOXHGSMIWRITEREAD *pCmd = &pWrData->Cmd; + pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR; pDr->cbBuf = cbCmd; pDr->rc = VERR_NOT_IMPLEMENTED; +// pDr->Location.offVramBuf = vboxMpCrShgsmiTransportBufOffset(pCon, pCmd); + - PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD; pHdr->u32CmdSpecific = 0; - VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD); + pBody->cBuffers = cBuffers; - CRVBOXHGSMIWRITEREAD *pCmd = VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(pDr, cBuffers, CRVBOXHGSMIWRITEREAD); + pCmd->hdr.result = VERR_WRONG_ORDER; - pCmd->hdr.u32ClientID = pCon->u32ClientID; + pCmd->hdr.u32ClientID = u32ClientID; pCmd->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ; // pCmd->hdr.u32Reserved = 0; pCmd->iBuffer = 1; @@ -294,105 +550,99 @@ static int vboxMpCrShgsmiConSendAsync(PVBOXMP_CRSHGSMICON pCon, void *pvTx, uint pCmd->cbWriteback = 0; VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[0]; - pBufCmd->offBuffer = vboxMpCrShgsmiConBufOffset(pCon, pCmd); + pBufCmd->offBuffer = vboxVdmaCBufDrPtrOffset(&pDevExt->u.primary.Vdma, pCmd); pBufCmd->cbBuffer = sizeof (*pCmd); pBufCmd->u32GuestData = 0; - pBufCmd->u64GuestData = (uint64_t)pCmdDr; + pBufCmd->u64GuestData = (uint64_t)pfnCompletion; pBufCmd = &pBody->aBuffers[1]; - pBufCmd->offBuffer = vboxMpCrShgsmiConBufOffset(pCon, pvTx); - pBufCmd->cbBuffer = cbTx; + pBufCmd->offBuffer = vboxMpCrShgsmiTransportBufOffset(pCon, pvBuffer); + pBufCmd->cbBuffer = cbBuffer; pBufCmd->u32GuestData = 0; pBufCmd->u64GuestData = 0; pBufCmd = &pBody->aBuffers[2]; - pBufCmd->offBuffer = vboxMpCrShgsmiConBufOffset(pCon, pWbDr->pvBuf); + pBufCmd->offBuffer = vboxMpCrShgsmiTransportBufOffset(pCon, pWbDr->pvBuf); pBufCmd->cbBuffer = pWbDr->cbBuf; pBufCmd->u32GuestData = 0; pBufCmd->u64GuestData = (uint64_t)pWbDr; + return VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(pHdr, cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITEREAD), void); +} + +void* VBoxMpCrShgsmiTransportCmdCreateWriteAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, uint32_t u32ClientID, void *pvBuffer, uint32_t cbBuffer, + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEASYNC_COMPLETION pfnCompletion, uint32_t cbContextData) +{ + const uint32_t cBuffers = 2; + const uint32_t cbCmd = VBOXMP_CRSHGSMICON_DR_SIZE(cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITE), cbContextData); PVBOXMP_DEVEXT pDevExt = pCon->pDevExt; - PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr); - vboxVdmaDdiCmdInit(pDdiCmd, 0, 0, vboxMpCrShgsmiConSendAsyncCompletion, pDr); - /* 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); - if (RT_SUCCESS(rc)) + PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd); + if (!pDr) { - return STATUS_SUCCESS; + WARN(("vboxVdmaCBufDrCreate failed")); + return NULL; } - /* impl failure branch */ - Assert(0); - return rc; -} + PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); + VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXMP_CRSHGSMICON_DR_GET_CRCMD(pHdr); + PVBOXMP_CRHGSMICMD_WRITE pWrData = VBOXMP_CRSHGSMICON_DR_GET_CMDBUF(pHdr, cBuffers, VBOXMP_CRHGSMICMD_WRITE); + CRVBOXHGSMIWRITE *pCmd = &pWrData->Cmd; -static CRMessageOpcodes * -vboxMpCrPackerPrependHeader( CRPackBuffer *buf, unsigned int *len, unsigned int senderID ) -{ - UINT num_opcodes; - CRMessageOpcodes *hdr; + pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR; + pDr->cbBuf = cbCmd; + pDr->rc = VERR_NOT_IMPLEMENTED; +// pDr->Location.offVramBuf = vboxMpCrShgsmiTransportBufOffset(pCon, pCmd); - Assert(buf); - Assert(buf->opcode_current < buf->opcode_start); - Assert(buf->opcode_current >= buf->opcode_end); - Assert(buf->data_current > buf->data_start); - Assert(buf->data_current <= buf->data_end); + pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD; + pHdr->u32CmdSpecific = 0; - num_opcodes = (UINT)(buf->opcode_start - buf->opcode_current); - hdr = (CRMessageOpcodes *) - ( buf->data_start - ( ( num_opcodes + 3 ) & ~0x3 ) - sizeof(*hdr) ); + pBody->cBuffers = cBuffers; - Assert((void *) hdr >= buf->pack); + pCmd->hdr.result = VERR_WRONG_ORDER; + pCmd->hdr.u32ClientID = u32ClientID; + pCmd->hdr.u32Function = SHCRGL_GUEST_FN_WRITE; + // pCmd->hdr.u32Reserved = 0; + pCmd->iBuffer = 1; - hdr->header.type = CR_MESSAGE_OPCODES; - hdr->numOpcodes = num_opcodes; + VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[0]; + pBufCmd->offBuffer = vboxVdmaCBufDrPtrOffset(&pDevExt->u.primary.Vdma, pCmd); + pBufCmd->cbBuffer = sizeof (*pCmd); + pBufCmd->u32GuestData = 0; + pBufCmd->u64GuestData = (uint64_t)pfnCompletion; - *len = (UINT)(buf->data_current - (unsigned char *) hdr); + pBufCmd = &pBody->aBuffers[1]; + pBufCmd->offBuffer = vboxMpCrShgsmiTransportBufOffset(pCon, pvBuffer); + pBufCmd->cbBuffer = cbBuffer; + pBufCmd->u32GuestData = 0; + pBufCmd->u64GuestData = 0; - return hdr; + return VBOXMP_CRSHGSMICON_DR_GET_CMDCTX(pHdr, cBuffers, sizeof (VBOXMP_CRHGSMICMD_WRITE), void); } -static void vboxMpCrShgsmiPackerCbFlush(void *pvFlush) +int VBoxMpCrShgsmiTransportCmdSubmitWriteReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext) { - PVBOXMP_CRSHGSMIPACKER pPacker = (PVBOXMP_CRSHGSMIPACKER)pvFlush; - - crPackReleaseBuffer(&pPacker->CrPacker); - - if (pPacker->CrBuffer.opcode_current != pPacker->CrBuffer.opcode_start) - { - CRMessageOpcodes *pHdr; - unsigned int len; - pHdr = vboxMpCrPackerPrependHeader(&pPacker->CrBuffer, &len, 0); - - /*Send*/ - } - + VBOXVDMACMD* pHdr = VBOXMP_CRSHGSMICON_DR_GET_FROM_CMDCTX(pvContext, 3, sizeof (VBOXMP_CRHGSMICMD_WRITEREAD)); + return vboxMpCrShgsmiTransportCmdSubmitDmaCmd(pCon, pHdr, vboxMpCrShgsmiTransportSendWriteReadAsyncCompletion); +} - crPackSetBuffer(&pPacker->CrPacker, &pPacker->CrBuffer); - crPackResetPointers(&pPacker->CrPacker); +int VBoxMpCrShgsmiTransportCmdSubmitWriteAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext) +{ + VBOXVDMACMD* pHdr = VBOXMP_CRSHGSMICON_DR_GET_FROM_CMDCTX(pvContext, 2, sizeof (VBOXMP_CRHGSMICMD_WRITE)); + return vboxMpCrShgsmiTransportCmdSubmitDmaCmd(pCon, pHdr, vboxMpCrShgsmiTransportSendWriteAsyncCompletion); } -int vboxMpCrShgsmiPackerInit(PVBOXMP_CRSHGSMIPACKER pPacker, PVBOXMP_CRSHGSMICON pCon) +void VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext) { - memset(pPacker, 0, sizeof (*pPacker)); + VBOXVDMACMD* pHdr = VBOXMP_CRSHGSMICON_DR_GET_FROM_CMDCTX(pvContext, 3, sizeof (VBOXMP_CRHGSMICMD_WRITEREAD)); + vboxMpCrShgsmiTransportCmdTermDmaCmd(pCon, pHdr); +} - static const HGSMISIZE cbBuffer = 1000; - void *pvBuffer = vboxMpCrShgsmiConAlloc(pCon, cbBuffer); - if (!pvBuffer) - { - WARN(("vboxMpCrShgsmiConAlloc failed")); - return VERR_NO_MEMORY; - } - pPacker->pCon = pCon; - crPackInitBuffer(&pPacker->CrBuffer, pvBuffer, cbBuffer, cbBuffer); - crPackSetBuffer(&pPacker->CrPacker, &pPacker->CrBuffer); - crPackFlushFunc(&pPacker->CrPacker, vboxMpCrShgsmiPackerCbFlush); - crPackFlushArg(&pPacker->CrPacker, pPacker); -// crPackSendHugeFunc( thread->packer, packspuHuge ); - return VINF_SUCCESS; +void VBoxMpCrShgsmiTransportCmdTermWriteAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext) +{ + VBOXVDMACMD* pHdr = VBOXMP_CRSHGSMICON_DR_GET_FROM_CMDCTX(pvContext, 2, sizeof (VBOXMP_CRHGSMICMD_WRITE)); + vboxMpCrShgsmiTransportCmdTermDmaCmd(pCon, pHdr); } -# endif + #endif static int vboxMpCrCtlAddRef(PVBOXMP_CRCTLCON pCrCtlCon) @@ -464,6 +714,39 @@ static int vboxMpCrCtlConSetVersion(PVBOXMP_CRCTLCON pCrCtlCon, uint32_t u32Clie return VINF_SUCCESS; } +static int vboxMpCrCtlConGetCaps(PVBOXMP_CRCTLCON pCrCtlCon, uint32_t u32ClientID, uint32_t *pu32Caps) +{ + CRVBOXHGCMGETCAPS parms; + int rc; + + parms.hdr.result = VERR_WRONG_ORDER; + parms.hdr.u32ClientID = u32ClientID; + parms.hdr.u32Function = SHCRGL_GUEST_FN_GET_CAPS; + parms.hdr.cParms = SHCRGL_CPARMS_GET_CAPS; + + parms.Caps.type = VMMDevHGCMParmType_32bit; + parms.Caps.u.value32 = 0; + + *pu32Caps = 0; + + rc = vboxCrCtlConCall(pCrCtlCon->hCrCtl, &parms.hdr, sizeof (parms)); + if (RT_FAILURE(rc)) + { + WARN(("vboxCrCtlConCall failed, rc (%d)", rc)); + return rc; + } + + if (RT_FAILURE(parms.hdr.result)) + { + WARN(("SHCRGL_GUEST_FN_GET_CAPS failed, rc (%d)", parms.hdr.result)); + return parms.hdr.result; + } + + *pu32Caps = parms.Caps.u.value32; + + return VINF_SUCCESS; +} + static int vboxMpCrCtlConSetPID(PVBOXMP_CRCTLCON pCrCtlCon, uint32_t u32ClientID) { CRVBOXHGCMSETPID parms; @@ -576,8 +859,11 @@ int VBoxMpCrCtlConCallUserData(PVBOXMP_CRCTLCON pCrCtlCon, VBoxGuestHGCMCallInfo return rc; } -bool VBoxMpCrCtlConIs3DSupported() +void VBoxMpCrCtlConInit() { + g_VBoxMpCr3DSupported = 0; + g_VBoxMpCrHostCaps = 0; + #ifdef VBOX_WITH_CROGL VBOXMP_CRCTLCON CrCtlCon = {0}; uint32_t u32ClientID = 0; @@ -585,15 +871,57 @@ bool VBoxMpCrCtlConIs3DSupported() if (RT_FAILURE(rc)) { LOGREL(("VBoxMpCrCtlConConnect failed with rc(%d), 3D not supported!")); - return false; + return; } - rc = VBoxMpCrCtlConDisconnect(&CrCtlCon, u32ClientID); + g_VBoxMpCr3DSupported = 1; + + rc = vboxMpCrCtlConGetCaps(&CrCtlCon, u32ClientID, &g_VBoxMpCrHostCaps); if (RT_FAILURE(rc)) - WARN(("VBoxMpCrCtlConDisconnect failed, ignoring..")); + { + WARN(("vboxMpCrCtlConGetCaps failed rc (%d), ignoring..", rc)); + g_VBoxMpCrHostCaps = 0; + } - return true; -#else - return false; +#if 1 /*def DEBUG_misha*/ + g_VBoxMpCrHostCaps &= ~CR_VBOX_CAP_CMDVBVA; #endif + + rc = VBoxMpCrCtlConDisconnect(&CrCtlCon, u32ClientID); + if (RT_FAILURE(rc)) + WARN(("VBoxMpCrCtlConDisconnect failed rc (%d), ignoring..", rc)); +#endif +} + +int VBoxMpCrCmdRxReadbackHandler(CRMessageReadback *pRx, uint32_t cbRx) +{ + if (cbRx < sizeof (*pRx)) + { + WARN(("invalid rx size %d", cbRx)); + return VERR_INVALID_PARAMETER; + } + void* pvData = VBoxMpCrCmdRxReadbackData(pRx); + uint32_t cbData = VBoxMpCrCmdRxReadbackDataSize(pRx, cbRx); + void *pvDataPtr = *((void**)&pRx->readback_ptr); + memcpy(pvDataPtr, pvData, cbData); + return VINF_SUCCESS; } + +int VBoxMpCrCmdRxHandler(CRMessageHeader *pRx, uint32_t cbRx) +{ + if (cbRx < sizeof (*pRx)) + { + WARN(("invalid rx size %d", cbRx)); + return VERR_INVALID_PARAMETER; + } + CRMessageHeader *pHdr = (CRMessageHeader*)pRx; + switch (pHdr->type) + { + case CR_MESSAGE_READBACK: + return VBoxMpCrCmdRxReadbackHandler((CRMessageReadback*)pRx, cbRx); + default: + WARN(("unsupported rx message type: %d", pHdr->type)); + return VERR_INVALID_PARAMETER; + } +} + diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.h index 4bf2ab98..cc00f90d 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCr.h @@ -27,6 +27,8 @@ typedef struct VBOXMP_CRCTLCON uint32_t cCrCtlRefs; } VBOXMP_CRCTLCON, *PVBOXMP_CRCTLCON; +void VBoxMpCrCtlConInit(); + bool VBoxMpCrCtlConIs3DSupported(); int VBoxMpCrCtlConConnect(PVBOXMP_CRCTLCON pCrCtlCon, @@ -36,4 +38,214 @@ int VBoxMpCrCtlConDisconnect(PVBOXMP_CRCTLCON pCrCtlCon, uint32_t u32ClientID); int VBoxMpCrCtlConCall(PVBOXMP_CRCTLCON pCrCtlCon, struct VBoxGuestHGCMCallInfo *pData, uint32_t cbData); int VBoxMpCrCtlConCallUserData(PVBOXMP_CRCTLCON pCrCtlCon, struct VBoxGuestHGCMCallInfo *pData, uint32_t cbData); +# include <cr_pack.h> + +typedef struct VBOXMP_CRDATACON +{ + PVBOXMP_CRCTLCON pCtl; + uint32_t u32ClientID; +} VBOXMP_CRDATACON, *PVBOXMP_CRDATACON; + +DECLINLINE(int) VBoxMpCrDataConCreate(PVBOXMP_CRDATACON pDataCon, PVBOXMP_CRCTLCON pCtlCon) +{ + int rc = VBoxMpCrCtlConConnect(pCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pDataCon->u32ClientID); + if (RT_SUCCESS(rc)) + { + Assert(pDataCon->u32ClientID); + pDataCon->pCtl = pCtlCon; + return VINF_SUCCESS; + } + WARN(("VBoxMpCrCtlConConnect failed, rc %d", rc)); + return rc; +} + +DECLINLINE(int) VBoxMpCrDataConDestroy(PVBOXMP_CRDATACON pDataCon) +{ + int rc = VBoxMpCrCtlConDisconnect(pDataCon->pCtl, pDataCon->u32ClientID); + if (RT_SUCCESS(rc)) + { + /* sanity */ + pDataCon->pCtl = NULL; + pDataCon->u32ClientID = 0; + return VINF_SUCCESS; + } + WARN(("VBoxMpCrCtlConDisconnect failed, rc %d", rc)); + return rc; +} + +typedef struct VBOXMP_CRSHGSMICON_BUFDR +{ + uint32_t cbBuf; + void *pvBuf; +} VBOXMP_CRSHGSMICON_BUFDR, *PVBOXMP_CRSHGSMICON_BUFDR; + +typedef struct VBOXMP_CRSHGSMICON_BUFDR_CACHE +{ + volatile PVBOXMP_CRSHGSMICON_BUFDR pBufDr; +} VBOXMP_CRSHGSMICON_BUFDR_CACHE, *PVBOXMP_CRSHGSMICON_BUFDR_CACHE; + +typedef struct VBOXMP_CRSHGSMITRANSPORT +{ + PVBOXMP_DEVEXT pDevExt; + VBOXMP_CRSHGSMICON_BUFDR_CACHE WbDrCache; +} VBOXMP_CRSHGSMITRANSPORT, *PVBOXMP_CRSHGSMITRANSPORT; + +/** the rx buffer passed here is only valid in the context of the callback. + * the callee must NOT free it or use outside of the callback context. + * */ +typedef DECLCALLBACK(void) FNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvRx, uint32_t cbRx, void *pvCtx); +typedef FNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION *PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION; + +typedef DECLCALLBACK(void) FNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEASYNC_COMPLETION(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvCtx); +typedef FNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEASYNC_COMPLETION *PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEASYNC_COMPLETION; + +int VBoxMpCrShgsmiTransportCreate(PVBOXMP_CRSHGSMITRANSPORT pCon, PVBOXMP_DEVEXT pDevExt); +void VBoxMpCrShgsmiTransportTerm(PVBOXMP_CRSHGSMITRANSPORT pCon); +void* VBoxMpCrShgsmiTransportCmdCreateWriteReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, uint32_t u32ClientID, void *pvBuffer, uint32_t cbBuffer, + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion, uint32_t cbContextData); +void* VBoxMpCrShgsmiTransportCmdCreateWriteAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, uint32_t u32ClientID, void *pvBuffer, uint32_t cbBuffer, + PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEASYNC_COMPLETION pfnCompletion, uint32_t cbContextData); +int VBoxMpCrShgsmiTransportCmdSubmitWriteReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext); +int VBoxMpCrShgsmiTransportCmdSubmitWriteAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext); +void VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext); +void VBoxMpCrShgsmiTransportCmdTermWriteAsync(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvContext); + +void* VBoxMpCrShgsmiTransportBufAlloc(PVBOXMP_CRSHGSMITRANSPORT pCon, uint32_t cbBuffer); +void VBoxMpCrShgsmiTransportBufFree(PVBOXMP_CRSHGSMITRANSPORT pCon, void* pvBuffer); + +typedef struct VBOXMP_CRPACKER +{ + CRPackContext CrPacker; + CRPackBuffer CrBuffer; +} VBOXMP_CRPACKER, *PVBOXMP_CRPACKER; + +DECLINLINE(void) VBoxMpCrPackerInit(PVBOXMP_CRPACKER pPacker) +{ + memset(pPacker, 0, sizeof (*pPacker)); +} + +DECLINLINE(void) VBoxMpCrPackerTerm(PVBOXMP_CRPACKER pPacker) +{} + +DECLINLINE(void) VBoxMpCrPackerTxBufferInit(PVBOXMP_CRPACKER pPacker, void *pvBuffer, uint32_t cbBuffer, uint32_t cCommands) +{ + crPackInitBuffer(&pPacker->CrBuffer, pvBuffer, cbBuffer, cbBuffer, cCommands); + crPackSetBuffer(&pPacker->CrPacker, &pPacker->CrBuffer); +} + +DECLINLINE(CRMessageOpcodes*) vboxMpCrPackerPrependHeader( const CRPackBuffer *pBuffer, uint32_t *cbData, void **ppvPackBuffer) +{ + UINT num_opcodes; + CRMessageOpcodes *hdr; + + Assert(pBuffer); + Assert(pBuffer->opcode_current < pBuffer->opcode_start); + Assert(pBuffer->opcode_current >= pBuffer->opcode_end); + Assert(pBuffer->data_current > pBuffer->data_start); + Assert(pBuffer->data_current <= pBuffer->data_end); + + num_opcodes = (UINT)(pBuffer->opcode_start - pBuffer->opcode_current); + hdr = (CRMessageOpcodes *) + ( pBuffer->data_start - ( ( num_opcodes + 3 ) & ~0x3 ) - sizeof(*hdr) ); + + Assert((void *) hdr >= pBuffer->pack); + + hdr->header.type = CR_MESSAGE_OPCODES; + hdr->numOpcodes = num_opcodes; + + *cbData = (UINT)(pBuffer->data_current - (unsigned char *) hdr); + *ppvPackBuffer = pBuffer->pack; + + return hdr; +} + +DECLINLINE(void*) VBoxMpCrPackerTxBufferComplete(PVBOXMP_CRPACKER pPacker, uint32_t *pcbBuffer, void **ppvPackBuffer) +{ + crPackReleaseBuffer(&pPacker->CrPacker); + uint32_t cbData; + CRMessageOpcodes *pHdr; + void *pvPackBuffer; + if (pPacker->CrBuffer.opcode_current != pPacker->CrBuffer.opcode_start) + pHdr = vboxMpCrPackerPrependHeader(&pPacker->CrBuffer, &cbData, &pvPackBuffer); + else + { + cbData = 0; + pHdr = NULL; + pvPackBuffer = NULL; + } + *pcbBuffer = cbData; + *ppvPackBuffer = pvPackBuffer; + return pHdr; +} + +DECLINLINE(uint32_t) VBoxMpCrPackerTxBufferGetFreeBufferSize(PVBOXMP_CRPACKER pPacker) +{ + return (uint32_t)(pPacker->CrBuffer.data_end - pPacker->CrBuffer.data_start); +} + +DECLINLINE(void) vboxMpCrUnpackerRxWriteback(CRMessageWriteback *pWb) +{ + int *pWriteback; + memcpy(&pWriteback, &(pWb->writeback_ptr), sizeof (pWriteback)); + (*pWriteback)--; +} + +DECLINLINE(void) vboxMpCrUnpackerRxReadback(CRMessageReadback *pRb, uint32_t cbRx) +{ + int cbPayload = cbRx - sizeof (*pRb); + int *pWriteback; + void *pDst; + memcpy(&pWriteback, &(pRb->writeback_ptr), sizeof (pWriteback)); + memcpy(&pDst, &(pRb->readback_ptr), sizeof (pDst)); + + (*pWriteback)--; + memcpy(pDst, ((uint8_t*)pRb) + sizeof (*pRb), cbPayload); +} + +DECLINLINE(int) VBoxMpCrUnpackerRxBufferProcess(void *pvBuffer, uint32_t cbBuffer) +{ + CRMessage *pMsg = (CRMessage*)pvBuffer; + switch (pMsg->header.type) + { + case CR_MESSAGE_WRITEBACK: + vboxMpCrUnpackerRxWriteback(&(pMsg->writeback)); + return VINF_SUCCESS; + case CR_MESSAGE_READBACK: + vboxMpCrUnpackerRxReadback(&(pMsg->readback), cbBuffer); + return VINF_SUCCESS; + default: + WARN(("unknown msg code %d", pMsg->header.type)); + return VERR_NOT_SUPPORTED; + } +} + +DECLINLINE(void*) VBoxMpCrCmdRxReadbackData(CRMessageReadback *pRx) +{ + return (void*)(pRx+1); +} + +DECLINLINE(uint32_t) VBoxMpCrCmdRxReadbackDataSize(CRMessageReadback *pRx, uint32_t cbRx) +{ + return cbRx - sizeof (*pRx); +} +int VBoxMpCrCmdRxReadbackHandler(CRMessageReadback *pRx, uint32_t cbRx); +int VBoxMpCrCmdRxHandler(CRMessageHeader *pRx, uint32_t cbRx); + +/* must be called after calling VBoxMpCrCtlConIs3DSupported only */ +uint32_t VBoxMpCrGetHostCaps(); + +#define VBOXMP_CRCMD_HEADER_SIZE sizeof (CRMessageOpcodes) +/* last +4 below is 4-aligned command opcode size (i.e. ((1 + 3) & ~3)) */ +#define VBOXMP_CRCMD_SIZE_WINDOWPOSITION (20 + 4) +#define VBOXMP_CRCMD_SIZE_WINDOWVISIBLEREGIONS(_cRects) (16 + (_cRects) * 4 * sizeof (GLint) + 4) +#define VBOXMP_CRCMD_SIZE_VBOXTEXPRESENT(_cRects) (28 + (_cRects) * 4 * sizeof (GLint) + 4) +#define VBOXMP_CRCMD_SIZE_WINDOWSHOW (16 + 4) +#define VBOXMP_CRCMD_SIZE_WINDOWSIZE (20 + 4) +#define VBOXMP_CRCMD_SIZE_GETCHROMIUMPARAMETERVCR (36 + 4) +#define VBOXMP_CRCMD_SIZE_CHROMIUMPARAMETERICR (16 + 4) +#define VBOXMP_CRCMD_SIZE_WINDOWCREATE (256 + 28 + 4) +#define VBOXMP_CRCMD_SIZE_WINDOWDESTROY (12 + 4) +#define VBOXMP_CRCMD_SIZE_CREATECONTEXT (256 + 32 + 4) +#define VBOXMP_CRCMD_SIZE_DESTROYCONTEXT (12 + 4) + #endif /* #ifndef ___VBoxMPCr_h__ */ diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCrUtil.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCrUtil.cpp index fdcea8d3..0eca622c 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCrUtil.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCrUtil.cpp @@ -31,7 +31,10 @@ DECLEXPORT(void) crMemset( void *ptr, int value, unsigned int bytes ); DECLEXPORT(void) crMemZero( void *ptr, unsigned int bytes ); DECLEXPORT(int) crMemcmp( const void *p1, const void *p2, unsigned int bytes ); DECLEXPORT(void) crDebug(const char *format, ... ); +#ifndef DEBUG_misha DECLEXPORT(void) crWarning(const char *format, ... ); +#endif + DECLEXPORT(void) crInfo(const char *format, ... ); DECLEXPORT(void) crError(const char *format, ... ); @@ -73,10 +76,12 @@ DECLEXPORT(void) crDebug(const char *format, ... ) } +#ifndef DEBUG_misha DECLEXPORT(void) crWarning(const char *format, ... ) { } +#endif DECLEXPORT(void) crInfo(const char *format, ... ) { diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.cpp index 83f8ca21..b6d74cd6 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.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; @@ -193,7 +193,7 @@ PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainCreate(UINT w, UINT h) pSwapchain->Pos.x = pSwapchain->Pos.y = VBOXWDDM_INVALID_COORD; pSwapchain->width = w; pSwapchain->height = h; - VBoxWddmVrListInit(&pSwapchain->VisibleRegions); + VBoxVrListInit(&pSwapchain->VisibleRegions); } return pSwapchain; } @@ -208,7 +208,7 @@ DECLINLINE(BOOLEAN) vboxWddmSwapchainRetainLocked(PVBOXWDDM_SWAPCHAIN pSwapchain return FALSE; } -DECLINLINE(BOOLEAN) vboxWddmSwapchainRetain(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain) +BOOLEAN vboxWddmSwapchainRetain(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain) { KIRQL OldIrql; BOOLEAN bRc; @@ -218,35 +218,40 @@ DECLINLINE(BOOLEAN) vboxWddmSwapchainRetain(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SW return bRc; } -DECLINLINE(VOID) vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain) +VOID vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain) { const uint32_t cRefs = ASMAtomicDecU32(&pSwapchain->cRefs); Assert(cRefs < UINT32_MAX/2); if (!cRefs) { - VBoxWddmVrListClear(&pSwapchain->VisibleRegions); + VBoxVrListClear(&pSwapchain->VisibleRegions); vboxWddmMemFree(pSwapchain); } } -PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc) +PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAllocData(PVBOXMP_DEVEXT pDevExt, const struct VBOXWDDM_ALLOC_DATA *pAllocData) { KIRQL OldIrql; PVBOXWDDM_SWAPCHAIN pSwapchain; KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql); - pSwapchain = pAlloc->pSwapchain; + pSwapchain = pAllocData->pSwapchain; if (pSwapchain && !vboxWddmSwapchainRetainLocked(pSwapchain)) pSwapchain = NULL; KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql); return pSwapchain; } +PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOCATION *pAlloc) +{ + return vboxWddmSwapchainRetainByAllocData(pDevExt, &pAlloc->AllocData); +} + VOID vboxWddmSwapchainAllocRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc) { KIRQL OldIrql; KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql); - Assert(pAlloc->pSwapchain == pSwapchain); - pAlloc->pSwapchain = NULL; + Assert(pAlloc->AllocData.pSwapchain == pSwapchain); + pAlloc->AllocData.pSwapchain = NULL; RemoveEntryList(&pAlloc->SwapchainEntry); KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql); vboxWddmSwapchainRelease(pSwapchain); @@ -256,17 +261,17 @@ BOOLEAN vboxWddmSwapchainAllocAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pS { KIRQL OldIrql; BOOLEAN bRc; - Assert(!pAlloc->pSwapchain); + Assert(!pAlloc->AllocData.pSwapchain); KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql); bRc = vboxWddmSwapchainRetainLocked(pSwapchain); if (bRc) { - if (pAlloc->pSwapchain) + if (pAlloc->AllocData.pSwapchain) { RemoveEntryList(&pAlloc->SwapchainEntry); } InsertTailList(&pSwapchain->AllocList, &pAlloc->SwapchainEntry); - pAlloc->pSwapchain = pSwapchain; + pAlloc->AllocData.pSwapchain = pSwapchain; } KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql); return bRc; @@ -286,8 +291,8 @@ static VOID vboxWddmSwapchainAllocRemoveAllInternal(PVBOXMP_DEVEXT pDevExt, PVBO { PVBOXWDDM_ALLOCATION pAlloc = VBOXSCENTRY_2_ALLOC(pEntry); pEntry = pEntry->Flink; - Assert(pAlloc->pSwapchain == pSwapchain); - pAlloc->pSwapchain = NULL; + Assert(pAlloc->AllocData.pSwapchain == pSwapchain); + pAlloc->AllocData.pSwapchain = NULL; RemoveEntryList(&pAlloc->SwapchainEntry); ++cRemoved; } @@ -312,16 +317,6 @@ VOID vboxWddmSwapchainDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapc { vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, TRUE); - Assert(pSwapchain->pContext); - if (pSwapchain->pContext) - { - NTSTATUS tmpStatus = vboxVdmaGgCmdCancel(pDevExt, pSwapchain->pContext, pSwapchain); - if (tmpStatus != STATUS_SUCCESS) - { - WARN(("vboxVdmaGgCmdCancel returned Status (0x%x)", tmpStatus)); - } - } - vboxWddmSwapchainRelease(pSwapchain); } @@ -347,7 +342,7 @@ static VOID vboxWddmSwapchainCtxRemoveLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_C Assert(pTst == pSwapchain); RemoveEntryList(&pSwapchain->DevExtListEntry); pSwapchain->hSwapchainKm = NULL; - VBoxWddmVrListClear(&pSwapchain->VisibleRegions); + VBoxVrListClear(&pSwapchain->VisibleRegions); vboxWddmSwapchainRelease(pSwapchain); } @@ -356,9 +351,10 @@ static VOID vboxWddmSwapchainCtxRemoveLocked(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_C BOOLEAN vboxWddmSwapchainCtxAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain) { BOOLEAN bRc; - ExAcquireFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_DATA + VBOXWDDM_CTXLOCK_LOCK(pDevExt); bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain); - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); return bRc; } @@ -366,9 +362,10 @@ BOOLEAN vboxWddmSwapchainCtxAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pConte * */ VOID vboxWddmSwapchainCtxRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain) { - ExAcquireFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_DATA + VBOXWDDM_CTXLOCK_LOCK(pDevExt); vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain); - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); } /* destroys all swapchains for the given context @@ -376,9 +373,10 @@ VOID vboxWddmSwapchainCtxRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pConte VOID vboxWddmSwapchainCtxDestroyAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext) { VBOXWDDM_HTABLE_ITERATOR Iter; + VBOXWDDM_CTXLOCK_DATA do { - ExAcquireFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_LOCK(pDevExt); vboxWddmHTableIterInit(&pContext->Swapchains, &Iter); PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableIterNext(&Iter, NULL); if (!pSwapchain) @@ -387,30 +385,48 @@ VOID vboxWddmSwapchainCtxDestroyAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pC /* yes, we can call remove locked even when using iterator */ vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain); - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); /* we must not do vboxWddmSwapchainDestroy inside a context mutex */ vboxWddmSwapchainDestroy(pDevExt, pSwapchain); /* start from the very beginning, we will quit the loop when no swapchains left */ } while (1); /* no swapchains left, we exiteed the while loop via the "break", and we still owning the mutex */ - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); } /* process the swapchain info passed from user-mode display driver & synchronizes the driver state with it */ NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXDISPIFESCAPE_SWAPCHAININFO pSwapchainInfo, UINT cbSize) { - Assert((cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0]))); if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0])) + { + WARN(("invalid cbSize1 %d", cbSize)); return STATUS_INVALID_PARAMETER; - Assert(cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs])); + } + if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs])) + { return STATUS_INVALID_PARAMETER; + WARN(("invalid cbSize2 %d", cbSize)); + } + + if (!pSwapchainInfo->SwapchainInfo.winHostID) + { + WARN(("Zero winHostID specified!")); + return STATUS_INVALID_PARAMETER; + } + + if (!pContext) + { + WARN(("vboxWddmSwapchainCtxEscape: no context specified")); + return STATUS_INVALID_PARAMETER; + } PVBOXWDDM_SWAPCHAIN pSwapchain = NULL; PVBOXWDDM_ALLOCATION *apAlloc = NULL; Assert(KeGetCurrentIrql() == PASSIVE_LEVEL); NTSTATUS Status = STATUS_SUCCESS; + VBOXWDDM_CTXLOCK_DATA do { if (pSwapchainInfo->SwapchainInfo.cAllocs) @@ -452,12 +468,12 @@ NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pC if (pSwapchainInfo->SwapchainInfo.hSwapchainKm) { - ExAcquireFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_LOCK(pDevExt); pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableGet(&pContext->Swapchains, (VBOXWDDM_HANDLE)pSwapchainInfo->SwapchainInfo.hSwapchainKm); Assert(pSwapchain); if (!pSwapchain) { - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); Status = STATUS_INVALID_PARAMETER; break; } @@ -465,7 +481,7 @@ NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pC Assert(pSwapchain->pContext == pContext); if (pSwapchain->pContext != pContext) { - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); Status = STATUS_INVALID_PARAMETER; break; } @@ -479,7 +495,7 @@ NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pC break; } - ExAcquireFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_LOCK(pDevExt); BOOLEAN bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain); Assert(bRc); } @@ -492,7 +508,7 @@ NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pC /* do not zero up the view rect since it may still be valid */ // memset(&pSwapchain->ViewRect, 0, sizeof (pSwapchain->ViewRect)); /* @todo: do we really need to zero this up here ? */ - VBoxWddmVrListClear(&pSwapchain->VisibleRegions); + VBoxVrListClear(&pSwapchain->VisibleRegions); vboxWddmSwapchainAllocRemoveAll(pDevExt, pSwapchain); @@ -503,13 +519,18 @@ NTSTATUS vboxWddmSwapchainCtxEscape(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pC vboxWddmSwapchainAllocAdd(pDevExt, pSwapchain, apAlloc[i]); } pSwapchain->hSwapchainUm = pSwapchainInfo->SwapchainInfo.hSwapchainUm; + if (pSwapchain->winHostID != pSwapchainInfo->SwapchainInfo.winHostID) + { + pSwapchain->fExposed = FALSE; + pSwapchain->winHostID = pSwapchainInfo->SwapchainInfo.winHostID; + } } else { vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain); } - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); if (pSwapchainInfo->SwapchainInfo.cAllocs) { @@ -551,8 +572,6 @@ VOID vboxWddmSwapchainCtxTerm(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext vboxWddmHTableDestroy(&pContext->Swapchains); } -#define VBOXWDDM_REG_DRVKEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" - NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult) { WCHAR fallBackBuf[2]; @@ -585,13 +604,6 @@ NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR return Status; } -#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Control\\VIDEO\\" -#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7 L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\UnitedVideo\\CONTROL\\VIDEO\\" - -#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX L"Attach.RelativeX" -#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY L"Attach.RelativeY" -#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_DESKTOP L"Attach.ToDesktop" - NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult) { @@ -613,7 +625,7 @@ NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_V } else { - Assert(ver == WIN7 || ver == WIN8); + Assert(ver == WIN7 || ver == WIN8 || ver == WIN81); pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7; cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7); } @@ -639,13 +651,61 @@ NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_V return Status; } -#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\" -#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY L"\\Video" - -NTSTATUS vboxWddmRegQueryVideoGuidString(ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult) +NTSTATUS vboxWddmRegQueryVideoGuidString(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult) { - HANDLE hKey; - NTSTATUS Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ); + BOOLEAN fNewMethodSucceeded = FALSE; + HANDLE hKey = NULL; + NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DEVICE, GENERIC_READ, &hKey); + if (NT_SUCCESS(Status)) + { + struct + { + KEY_VALUE_PARTIAL_INFORMATION Info; + UCHAR Buf[1024]; /* should be enough */ + } KeyData; + ULONG cbResult; + UNICODE_STRING RtlStr; + RtlInitUnicodeString(&RtlStr, L"VideoID"); + Status = ZwQueryValueKey(hKey, + &RtlStr, + KeyValuePartialInformation, + &KeyData.Info, + sizeof(KeyData), + &cbResult); + if (NT_SUCCESS(Status)) + { + if (KeyData.Info.Type == REG_SZ) + { + fNewMethodSucceeded = TRUE; + *pcbResult = KeyData.Info.DataLength + 2; + if (cbBuf >= KeyData.Info.DataLength) + { + memcpy(pBuf, KeyData.Info.Data, KeyData.Info.DataLength + 2); + Status = STATUS_SUCCESS; + } + else + Status = STATUS_BUFFER_TOO_SMALL; + } + } + else + { + WARN(("ZwQueryValueKey failed, Status 0x%x", Status)); + } + + NTSTATUS tmpStatus = ZwClose(hKey); + Assert(tmpStatus == STATUS_SUCCESS); + } + else + { + WARN(("IoOpenDeviceRegistryKey failed Status 0x%x", Status)); + } + + if (fNewMethodSucceeded) + return Status; + else + WARN(("failed to acquire the VideoID, falling back to the old impl")); + + Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ); Assert(Status == STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { @@ -727,17 +787,22 @@ NTSTATUS vboxWddmRegQueryVideoGuidString(ULONG cbBuf, PWCHAR pBuf, PULONG pcbRes return Status; } -NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess) +NTSTATUS vboxWddmRegOpenKeyEx(OUT PHANDLE phKey, IN HANDLE hRootKey, IN PWCHAR pName, IN ACCESS_MASK fAccess) { OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING RtlStr; RtlInitUnicodeString(&RtlStr, pName); - InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, hRootKey, NULL); return ZwOpenKey(phKey, fAccess, &ObjAttr); } +NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess) +{ + return vboxWddmRegOpenKeyEx(phKey, NULL, pName, fAccess); +} + NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, OUT PHANDLE phKey) { WCHAR Buf[512]; @@ -813,6 +878,50 @@ NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PVBOXMP_DEVEXT pDeviceExtension, D3D return Status; } +NTSTATUS vboxWddmRegDrvFlagsSet(PVBOXMP_DEVEXT pDevExt, DWORD fVal) +{ + HANDLE hKey = NULL; + NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey); + if (!NT_SUCCESS(Status)) + { + WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status)); + return Status; + } + + Status = vboxWddmRegSetValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, fVal); + if (!NT_SUCCESS(Status)) + WARN(("vboxWddmRegSetValueDword failed, Status = 0x%x", Status)); + + NTSTATUS tmpStatus = ZwClose(hKey); + Assert(tmpStatus == STATUS_SUCCESS); + + return Status; +} + +DWORD vboxWddmRegDrvFlagsGet(PVBOXMP_DEVEXT pDevExt, DWORD fDefault) +{ + HANDLE hKey = NULL; + NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ, &hKey); + if (!NT_SUCCESS(Status)) + { + WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status)); + return fDefault; + } + + DWORD dwVal = 0; + Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, &dwVal); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status)); + dwVal = fDefault; + } + + NTSTATUS tmpStatus = ZwClose(hKey); + Assert(tmpStatus == STATUS_SUCCESS); + + return dwVal; +} + NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword) { struct @@ -842,7 +951,7 @@ NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD return STATUS_INVALID_PARAMETER; } -NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT DWORD val) +NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, IN DWORD val) { UNICODE_STRING RtlStr; RtlInitUnicodeString(&RtlStr, pName); @@ -861,7 +970,7 @@ UNICODE_STRING* vboxWddmVGuidGet(PVBOXMP_DEVEXT pDevExt) Assert(KeGetCurrentIrql() == PASSIVE_LEVEL); WCHAR VideoGuidBuf[512]; ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf); - NTSTATUS Status = vboxWddmRegQueryVideoGuidString(cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf); + NTSTATUS Status = vboxWddmRegQueryVideoGuidString(pDevExt ,cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf); Assert(Status == STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { @@ -1240,7 +1349,7 @@ NTSTATUS vboxVideoAMgrCtxAllocSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_ NTSTATUS Status = STATUS_SUCCESS; UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[cBuffers])); - PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate (&pDevExt->u.primary.Vdma, cbCmd); + PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbCmd); if (pDr) { // vboxVdmaCBufDrCreate zero initializes the pDr @@ -1265,7 +1374,7 @@ NTSTATUS vboxVideoAMgrCtxAllocSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_ #endif pBufCmd->offBuffer = pRef->pAlloc->offData + pBufInfo->Info.offData; pBufCmd->cbBuffer = pBufInfo->Info.cbData; - pBufCmd->u32GuestData = pBufInfo->Info.bDoNotSignalCompletion; + pBufCmd->u32GuestData = 0; pBufCmd->u64GuestData = (uint64_t)pRef; } else @@ -1402,6 +1511,8 @@ NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx) if (!pRef) break; + Assert(0); + Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle); Assert(Status == STATUS_SUCCESS); if (Status != STATUS_SUCCESS) @@ -1598,750 +1709,6 @@ BOOLEAN vboxShRcTreeRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc) } #endif - -/* visible rects */ -typedef struct VBOXWDDMVR_REG -{ - LIST_ENTRY ListEntry; - RECT Rect; -} VBOXWDDMVR_REG, *PVBOXWDDMVR_REG; - -#define PVBOXWDDMVR_REG_FROM_ENTRY(_pEntry) ((PVBOXWDDMVR_REG)(((uint8_t*)(_pEntry)) - RT_OFFSETOF(VBOXWDDMVR_REG, ListEntry))) - -#ifdef DEBUG_misha -//# define VBOXVDBG_VR_LAL_DISABLE -#endif - -#ifndef VBOXVDBG_VR_LAL_DISABLE -static LOOKASIDE_LIST_EX g_VBoxWddmVrLookasideList; -#endif - -static PVBOXWDDMVR_REG vboxWddmVrRegCreate() -{ -#ifndef VBOXVDBG_VR_LAL_DISABLE - PVBOXWDDMVR_REG pReg = (PVBOXWDDMVR_REG)ExAllocateFromLookasideListEx(&g_VBoxWddmVrLookasideList); - if (!pReg) - { - WARN(("ExAllocateFromLookasideListEx failed!")); - } - return pReg; -#else - return (PVBOXWDDMVR_REG)vboxWddmMemAlloc(sizeof (VBOXWDDMVR_REG)); -#endif -} - -static void vboxWddmVrRegTerm(PVBOXWDDMVR_REG pReg) -{ -#ifndef VBOXVDBG_VR_LAL_DISABLE - ExFreeToLookasideListEx(&g_VBoxWddmVrLookasideList, pReg); -#else - vboxWddmMemFree(pReg); -#endif -} - -void VBoxWddmVrListClear(PVBOXWDDMVR_LIST pList) -{ - PLIST_ENTRY pNext; - for (PLIST_ENTRY pEntry = pList->ListHead.Flink; pEntry != &pList->ListHead; pEntry = pNext) - { - pNext = pEntry->Flink; - PVBOXWDDMVR_REG pReg = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry); - vboxWddmVrRegTerm(pReg); - } - VBoxWddmVrListInit(pList); -} - -#define VBOXWDDMVR_MEMTAG 'vDBV' - -NTSTATUS VBoxWddmVrInit() -{ -#ifndef VBOXVDBG_VR_LAL_DISABLE - NTSTATUS Status = ExInitializeLookasideListEx(&g_VBoxWddmVrLookasideList, - NULL, /* PALLOCATE_FUNCTION_EX Allocate */ - NULL, /* PFREE_FUNCTION_EX Free */ - NonPagedPool, - 0, /* ULONG Flags */ - sizeof (VBOXWDDMVR_REG), - VBOXWDDMVR_MEMTAG, - 0 /* USHORT Depth - reserved, must be null */ - ); - if (!NT_SUCCESS(Status)) - { - WARN(("ExInitializeLookasideListEx failed, Status (0x%x)", Status)); - return Status; - } -#endif - - return STATUS_SUCCESS; -} - -void VBoxWddmVrTerm() -{ -#ifndef VBOXVDBG_VR_LAL_DISABLE - ExDeleteLookasideListEx(&g_VBoxWddmVrLookasideList); -#endif -} - -typedef DECLCALLBACK(int) FNVBOXWDDMVR_CB_COMPARATOR(const PVBOXWDDMVR_REG pReg1, const PVBOXWDDMVR_REG pReg2); -typedef FNVBOXWDDMVR_CB_COMPARATOR *PFNVBOXWDDMVR_CB_COMPARATOR; - -static DECLCALLBACK(int) vboxWddmVrRegNonintersectedComparator(const RECT* pRect1, const RECT* pRect2) -{ - Assert(!vboxWddmRectIsIntersect(pRect1, pRect2)); - if (pRect1->top != pRect2->top) - return pRect1->top - pRect2->top; - return pRect1->left - pRect2->left; -} - -#ifdef DEBUG_misha -static void vboxWddmVrDbgListDoVerify(PVBOXWDDMVR_LIST pList) -{ - PLIST_ENTRY pEntry1 = pList->ListHead.Flink; - - for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink) - { - PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1); - for (PLIST_ENTRY pEntry2 = pEntry1->Flink; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->Flink) - { - PVBOXWDDMVR_REG pReg2 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry2); - Assert(vboxWddmVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0); - } - } -} - -#define vboxWddmVrDbgListVerify vboxWddmVrDbgListDoVerify -#else -#define vboxWddmVrDbgListVerify(_p) do {} while (0) -#endif - -static NTSTATUS vboxWddmVrListUniteIntersection(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_LIST pIntersection); - -#define VBOXWDDMVR_INVALID_COORD (~0UL) - -DECLINLINE(void) vboxWddmVrListRegAdd(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_REG pReg, PLIST_ENTRY pPlace, BOOLEAN fAfter) -{ - if (fAfter) - InsertHeadList(pPlace, &pReg->ListEntry); - else - InsertTailList(pPlace, &pReg->ListEntry); - ++pList->cEntries; - vboxWddmVrDbgListVerify(pList); -} - -DECLINLINE(void) vboxWddmVrListRegRemove(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_REG pReg) -{ - RemoveEntryList(&pReg->ListEntry); - --pList->cEntries; -} - -static void vboxWddmVrListRegAddOrder(PVBOXWDDMVR_LIST pList, PLIST_ENTRY pMemberEntry, PVBOXWDDMVR_REG pReg) -{ - do - { - if (pMemberEntry != &pList->ListHead) - { - PVBOXWDDMVR_REG pMemberReg = PVBOXWDDMVR_REG_FROM_ENTRY(pMemberEntry); - if (vboxWddmVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0) - { - pMemberEntry = pMemberEntry->Flink; - continue; - } - } - vboxWddmVrListRegAdd(pList, pReg, pMemberEntry, FALSE); - break; - } while (1); -} - -static void vboxWddmVrListAddNonintersected(PVBOXWDDMVR_LIST pList1, PVBOXWDDMVR_LIST pList2) -{ - PLIST_ENTRY pEntry1 = pList1->ListHead.Flink; - - for (PLIST_ENTRY pEntry2 = pList2->ListHead.Flink; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.Flink) - { - PVBOXWDDMVR_REG pReg2 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry2); - do { - if (pEntry1 != &pList1->ListHead) - { - PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1); - if (vboxWddmVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0) - { - pEntry1 = pEntry1->Flink; - continue; - } - } - vboxWddmVrListRegRemove(pList2, pReg2); - vboxWddmVrListRegAdd(pList1, pReg2, pEntry1, FALSE); - break; - } while (1); - } - - Assert(VBoxWddmVrListIsEmpty(pList2)); -} - -static NTSTATUS vboxWddmVrListRegIntersectSubstNoJoin(PVBOXWDDMVR_LIST pList1, PVBOXWDDMVR_REG pReg1, const RECT * pRect2) -{ - UINT topLim = VBOXWDDMVR_INVALID_COORD; - UINT bottomLim = VBOXWDDMVR_INVALID_COORD; - LIST_ENTRY List; - PVBOXWDDMVR_REG pBottomReg = NULL; -#ifdef DEBUG_misha - RECT tmpRect = pReg1->Rect; - vboxWddmVrDbgListVerify(pList1); -#endif - - InitializeListHead(&List); - - Assert(vboxWddmRectIsIntersect(&pReg1->Rect, pRect2)); - - if (pReg1->Rect.top < pRect2->top) - { - Assert(pRect2->top < pReg1->Rect.bottom); - PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate(); - pRegResult->Rect.top = pReg1->Rect.top; - pRegResult->Rect.left = pReg1->Rect.left; - pRegResult->Rect.bottom = pRect2->top; - pRegResult->Rect.right = pReg1->Rect.right; - topLim = pRect2->top; - InsertTailList(&List, &pRegResult->ListEntry); - } - - if (pReg1->Rect.bottom > pRect2->bottom) - { - Assert(pRect2->bottom > pReg1->Rect.top); - PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate(); - pRegResult->Rect.top = pRect2->bottom; - pRegResult->Rect.left = pReg1->Rect.left; - pRegResult->Rect.bottom = pReg1->Rect.bottom; - pRegResult->Rect.right = pReg1->Rect.right; - bottomLim = pRect2->bottom; - pBottomReg = pRegResult; - } - - if (pReg1->Rect.left < pRect2->left) - { - Assert(pRect2->left < pReg1->Rect.right); - PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate(); - pRegResult->Rect.top = topLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.top : topLim; - pRegResult->Rect.left = pReg1->Rect.left; - pRegResult->Rect.bottom = bottomLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.bottom : bottomLim; - pRegResult->Rect.right = pRect2->left; - InsertTailList(&List, &pRegResult->ListEntry); - } - - if (pReg1->Rect.right > pRect2->right) - { - Assert(pRect2->right > pReg1->Rect.left); - PVBOXWDDMVR_REG pRegResult = vboxWddmVrRegCreate(); - pRegResult->Rect.top = topLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.top : topLim; - pRegResult->Rect.left = pRect2->right; - pRegResult->Rect.bottom = bottomLim == VBOXWDDMVR_INVALID_COORD ? pReg1->Rect.bottom : bottomLim; - pRegResult->Rect.right = pReg1->Rect.right; - InsertTailList(&List, &pRegResult->ListEntry); - } - - if (pBottomReg) - InsertTailList(&List, &pBottomReg->ListEntry); - - PLIST_ENTRY pMemberEntry = pReg1->ListEntry.Flink; - vboxWddmVrListRegRemove(pList1, pReg1); - vboxWddmVrRegTerm(pReg1); - - if (IsListEmpty(&List)) - return STATUS_SUCCESS; /* the region is covered by the pRect2 */ - - PLIST_ENTRY pEntry = List.Flink, pNext; - for (; pEntry != &List; pEntry = pNext) - { - pNext = pEntry->Flink; - PVBOXWDDMVR_REG pReg = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry); - - vboxWddmVrListRegAddOrder(pList1, pMemberEntry, pReg); - pMemberEntry = pEntry->Flink; /* the following elements should go after the given pEntry since they are ordered already */ - } - return STATUS_SUCCESS; -} - -typedef DECLCALLBACK(PLIST_ENTRY) FNVBOXWDDMVR_CB_INTERSECTED_VISITOR(PVBOXWDDMVR_LIST pList1, PVBOXWDDMVR_REG pReg1, const RECT * pRect2, void *pvContext, PLIST_ENTRY *ppNext); -typedef FNVBOXWDDMVR_CB_INTERSECTED_VISITOR *PFNVBOXWDDMVR_CB_INTERSECTED_VISITOR; - -static void vboxWddmVrListVisitIntersected(PVBOXWDDMVR_LIST pList1, UINT cRects, const RECT *aRects, PFNVBOXWDDMVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor) -{ - PLIST_ENTRY pEntry1 = pList1->ListHead.Flink; - PLIST_ENTRY pNext1; - UINT iFirst2 = 0; - - for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1) - { - pNext1 = pEntry1->Flink; - PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1); - for (UINT i = iFirst2; i < cRects; ++i) - { - const RECT *pRect2 = &aRects[i]; - if (pReg1->Rect.bottom <= pRect2->top) - continue; - else if (pRect2->bottom <= pReg1->Rect.top) - continue; - /* y coords intersect */ - else if (pReg1->Rect.right <= pRect2->left) - continue; - else if (pRect2->right <= pReg1->Rect.left) - continue; - /* x coords intersect */ - - /* the visitor can modify the list 1, apply necessary adjustments after it */ - PLIST_ENTRY pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1); - if (pEntry1 == &pList1->ListHead) - break; - } - } -} - - -static void vboxWddmVrListJoinRectsHV(PVBOXWDDMVR_LIST pList, BOOLEAN fHorizontal) -{ - PLIST_ENTRY pNext1, pNext2; - - for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pNext1) - { - PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1); - pNext1 = pEntry1->Flink; - for (PLIST_ENTRY pEntry2 = pEntry1->Flink; pEntry2 != &pList->ListHead; pEntry2 = pNext2) - { - PVBOXWDDMVR_REG pReg2 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry2); - pNext2 = pEntry2->Flink; - if (fHorizontal) - { - if (pReg1->Rect.top == pReg2->Rect.top) - { - if (pReg1->Rect.right == pReg2->Rect.left) - { - /* join rectangles */ - vboxWddmVrListRegRemove(pList, pReg2); - if (pReg1->Rect.bottom > pReg2->Rect.bottom) - { - LONG oldRight1 = pReg1->Rect.right; - LONG oldBottom1 = pReg1->Rect.bottom; - pReg1->Rect.right = pReg2->Rect.right; - pReg1->Rect.bottom = pReg2->Rect.bottom; - - vboxWddmVrDbgListVerify(pList); - - pReg2->Rect.left = pReg1->Rect.left; - pReg2->Rect.top = pReg1->Rect.bottom; - pReg2->Rect.right = oldRight1; - pReg2->Rect.bottom = oldBottom1; - vboxWddmVrListRegAddOrder(pList, pReg1->ListEntry.Flink, pReg2); - /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension - * and thus can match one of the previous rects */ - pNext1 = pList->ListHead.Flink; - break; - } - else if (pReg1->Rect.bottom < pReg2->Rect.bottom) - { - pReg1->Rect.right = pReg2->Rect.right; - vboxWddmVrDbgListVerify(pList); - pReg2->Rect.top = pReg1->Rect.bottom; - vboxWddmVrListRegAddOrder(pList, pReg1->ListEntry.Flink, pReg2); - /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension - * and thus can match one of the previous rects */ - pNext1 = pList->ListHead.Flink; - break; - } - else - { - pReg1->Rect.right = pReg2->Rect.right; - vboxWddmVrDbgListVerify(pList); - /* reset the pNext1 since it could be the pReg2 being destroyed */ - pNext1 = pEntry1->Flink; - /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */ - vboxWddmVrRegTerm(pReg2); - } - } - continue; - } - else if (pReg1->Rect.bottom == pReg2->Rect.bottom) - { - Assert(pReg1->Rect.top < pReg2->Rect.top); /* <- since pReg1 > pReg2 && pReg1->Rect.top != pReg2->Rect.top*/ - if (pReg1->Rect.right == pReg2->Rect.left) - { - /* join rectangles */ - vboxWddmVrListRegRemove(pList, pReg2); - - pReg1->Rect.bottom = pReg2->Rect.top; - vboxWddmVrDbgListVerify(pList); - pReg2->Rect.left = pReg1->Rect.left; - - vboxWddmVrListRegAddOrder(pList, pReg2->ListEntry.Flink, pReg2); - - /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension - * and thus can match one of the previous rects */ - pNext1 = pList->ListHead.Flink; - break; - } - else if (pReg1->Rect.left == pReg2->Rect.right) - { - /* join rectangles */ - vboxWddmVrListRegRemove(pList, pReg2); - - pReg1->Rect.bottom = pReg2->Rect.top; - vboxWddmVrDbgListVerify(pList); - pReg2->Rect.right = pReg1->Rect.right; - - vboxWddmVrListRegAddOrder(pList, pReg2->ListEntry.Flink, pReg2); - - /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension - * and thus can match one of the previous rects */ - pNext1 = pList->ListHead.Flink; - break; - } - continue; - } - } - else - { - if (pReg1->Rect.bottom == pReg2->Rect.top) - { - if (pReg1->Rect.left == pReg2->Rect.left) - { - if (pReg1->Rect.right == pReg2->Rect.right) - { - /* join rects */ - vboxWddmVrListRegRemove(pList, pReg2); - - pReg1->Rect.bottom = pReg2->Rect.bottom; - vboxWddmVrDbgListVerify(pList); - - /* reset the pNext1 since it could be the pReg2 being destroyed */ - pNext1 = pEntry1->Flink; - /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */ - vboxWddmVrRegTerm(pReg2); - continue; - } - /* no more to be done for for pReg1 */ - break; - } - else if (pReg1->Rect.right > pReg2->Rect.left) - { - /* no more to be done for for pReg1 */ - break; - } - - continue; - } - else if (pReg1->Rect.bottom < pReg2->Rect.top) - { - /* no more to be done for for pReg1 */ - break; - } - } - } - } -} - -static void vboxWddmVrListJoinRects(PVBOXWDDMVR_LIST pList) -{ - vboxWddmVrListJoinRectsHV(pList, TRUE); - vboxWddmVrListJoinRectsHV(pList, FALSE); -} - -typedef struct VBOXWDDMVR_CBDATA_SUBST -{ - NTSTATUS Status; - BOOLEAN fChanged; -} VBOXWDDMVR_CBDATA_SUBST, *PVBOXWDDMVR_CBDATA_SUBST; - -static DECLCALLBACK(PLIST_ENTRY) vboxWddmVrListSubstNoJoinCb(PVBOXWDDMVR_LIST pList, PVBOXWDDMVR_REG pReg1, const RECT *pRect2, void *pvContext, PLIST_ENTRY *ppNext) -{ - PVBOXWDDMVR_CBDATA_SUBST pData = (PVBOXWDDMVR_CBDATA_SUBST)pvContext; - /* store the prev to get the new Flink out of it*/ - PLIST_ENTRY pPrev = pReg1->ListEntry.Blink; - pData->fChanged = TRUE; - - Assert(vboxWddmRectIsIntersect(&pReg1->Rect, pRect2)); - - /* NOTE: the pReg1 will be invalid after the vboxWddmVrListRegIntersectSubstNoJoin call!!! */ - NTSTATUS Status = vboxWddmVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2); - if (NT_SUCCESS(Status)) - { - *ppNext = pPrev->Flink; - return &pList->ListHead; - } - WARN(("vboxWddmVrListRegIntersectSubstNoJoin failed!")); - Assert(!NT_SUCCESS(Status)); - pData->Status = Status; - *ppNext = &pList->ListHead; - return &pList->ListHead; -} - -static NTSTATUS vboxWddmVrListSubstNoJoin(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged) -{ - if (VBoxWddmVrListIsEmpty(pList)) - return STATUS_SUCCESS; - - VBOXWDDMVR_CBDATA_SUBST Data; - Data.Status = STATUS_SUCCESS; - Data.fChanged = FALSE; - - *pfChanged = FALSE; - - vboxWddmVrListVisitIntersected(pList, cRects, aRects, vboxWddmVrListSubstNoJoinCb, &Data); - if (!NT_SUCCESS(Data.Status)) - { - WARN(("vboxWddmVrListVisitIntersected failed!")); - return Data.Status; - } - - *pfChanged = Data.fChanged; - return STATUS_SUCCESS; -} - -#if 0 -static const PRECT vboxWddmVrRectsOrder(UINT cRects, const PRECT aRects) -{ -#ifdef DEBUG - { - for (UINT i = 0; i < cRects; ++i) - { - RECT *pRectI = &aRects[i]; - for (UINT j = i + 1; j < cRects; ++j) - { - RECT *pRectJ = &aRects[j]; - Assert(!vboxWddmRectIsIntersect(pRectI, pRectJ)); - } - } - } -#endif - - RECT * pRects = (RECT *)aRects; - /* check if rects are ordered already */ - for (UINT i = 0; i < cRects - 1; ++i) - { - RECT *pRect1 = &pRects[i]; - RECT *pRect2 = &pRects[i+1]; - if (vboxWddmVrRegNonintersectedComparator(pRect1, pRect2) < 0) - continue; - - WARN(("rects are unoreded!")); - - if (pRects == aRects) - { - pRects = (RECT *)vboxWddmMemAlloc(sizeof (RECT) * cRects); - if (!pRects) - { - WARN(("vboxWddmMemAlloc failed!")); - return NULL; - } - - memcpy(pRects, aRects, sizeof (RECT) * cRects); - } - - Assert(pRects != aRects); - - int j = (int)i - 1; - do { - RECT Tmp = *pRect1; - *pRect1 = *pRect2; - *pRect2 = Tmp; - - if (j < 0) - break; - - if (vboxWddmVrRegNonintersectedComparator(pRect1, pRect1-1) > 0) - break; - - pRect2 = pRect1--; - --j; - } while (1); - } - - return pRects; -} -#endif - -void VBoxWddmVrListTranslate(PVBOXWDDMVR_LIST pList, LONG x, LONG y) -{ - for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink) - { - PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1); - vboxWddmRectTranslate(&pReg1->Rect, x, y); - } -} - -NTSTATUS VBoxWddmVrListRectsSubst(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged) -{ -#if 0 - const PRECT pRects = vboxWddmVrRectsOrder(cRects, aRects); - if (!pRects) - { - WARN(("vboxWddmVrRectsOrder failed!")); - return STATUS_NO_MEMORY; - } -#endif - - NTSTATUS Status = vboxWddmVrListSubstNoJoin(pList, cRects, aRects, pfChanged); - if (!NT_SUCCESS(Status)) - { - WARN(("vboxWddmVrListSubstNoJoin failed!")); - goto done; - } - - if (!*pfChanged) - goto done; - - vboxWddmVrListJoinRects(pList); - -done: -#if 0 - if (pRects != aRects) - vboxWddmMemFree(pRects); -#endif - return Status; -} - -NTSTATUS VBoxWddmVrListRectsAdd(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged) -{ - UINT cCovered = 0; - -#if 0 -#ifdef DEBUG - { - for (UINT i = 0; i < cRects; ++i) - { - RECT *pRectI = &aRects[i]; - for (UINT j = i + 1; j < cRects; ++j) - { - RECT *pRectJ = &aRects[j]; - Assert(!vboxWddmRectIsIntersect(pRectI, pRectJ)); - } - } - } -#endif -#endif - - /* early sort out the case when there are no new rects */ - for (UINT i = 0; i < cRects; ++i) - { - for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink) - { - PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1); - if (vboxWddmRectIsCoveres(&pReg1->Rect, &aRects[i])) - { - cCovered++; - break; - } - } - } - - if (cCovered == cRects) - { - *pfChanged = FALSE; - return STATUS_SUCCESS; - } - - /* rects are not covered, need to go the slow way */ - - VBOXWDDMVR_LIST DiffList; - VBoxWddmVrListInit(&DiffList); - PRECT pListRects = NULL; - UINT cAllocatedRects = 0; - BOOLEAN fNeedRectreate = TRUE; - BOOLEAN fChanged = FALSE; - NTSTATUS Status = STATUS_SUCCESS; - - for (UINT i = 0; i < cRects; ++i) - { - PVBOXWDDMVR_REG pReg = vboxWddmVrRegCreate(); - if (!pReg) - { - WARN(("vboxWddmVrRegCreate failed!")); - Status = STATUS_NO_MEMORY; - break; - } - pReg->Rect = aRects[i]; - - UINT cListRects = VBoxWddmVrListRectsCount(pList); - if (!cListRects) - { - vboxWddmVrListRegAdd(pList, pReg, &pList->ListHead, FALSE); - fChanged = TRUE; - continue; - } - else - { - Assert(VBoxWddmVrListIsEmpty(&DiffList)); - vboxWddmVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, FALSE); - } - - if (cAllocatedRects < cListRects) - { - cAllocatedRects = cListRects + cRects; - Assert(fNeedRectreate); - if (pListRects) - vboxWddmMemFree(pListRects); - pListRects = (PRECT)vboxWddmMemAlloc(sizeof (RECT) * cAllocatedRects); - if (!pListRects) - { - WARN(("vboxWddmMemAllocZero failed!")); - Status = STATUS_NO_MEMORY; - break; - } - } - - - if (fNeedRectreate) - { - Status = VBoxWddmVrListRectsGet(pList, cListRects, pListRects); - Assert(Status == STATUS_SUCCESS); - fNeedRectreate = FALSE; - } - - BOOLEAN fDummyChanged = FALSE; - Status = vboxWddmVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged); - if (!NT_SUCCESS(Status)) - { - WARN(("vboxWddmVrListSubstNoJoin failed!")); - Status = STATUS_NO_MEMORY; - break; - } - - if (!VBoxWddmVrListIsEmpty(&DiffList)) - { - vboxWddmVrListAddNonintersected(pList, &DiffList); - fNeedRectreate = TRUE; - fChanged = TRUE; - } - - Assert(VBoxWddmVrListIsEmpty(&DiffList)); - } - - if (pListRects) - vboxWddmMemFree(pListRects); - - Assert(VBoxWddmVrListIsEmpty(&DiffList) || Status != STATUS_SUCCESS); - VBoxWddmVrListClear(&DiffList); - - if (fChanged) - vboxWddmVrListJoinRects(pList); - - *pfChanged = fChanged; - - return STATUS_SUCCESS; -} - -NTSTATUS VBoxWddmVrListRectsGet(PVBOXWDDMVR_LIST pList, UINT cRects, PRECT aRects) -{ - if (cRects < VBoxWddmVrListRectsCount(pList)) - return STATUS_BUFFER_TOO_SMALL; - - UINT i = 0; - for (PLIST_ENTRY pEntry1 = pList->ListHead.Flink; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->Flink, ++i) - { - PVBOXWDDMVR_REG pReg1 = PVBOXWDDMVR_REG_FROM_ENTRY(pEntry1); - aRects[i] = pReg1->Rect; - } - return STATUS_SUCCESS; -} - NTSTATUS vboxWddmDrvCfgInit(PUNICODE_STRING pRegStr) { HANDLE hKey; @@ -2527,16 +1894,24 @@ static int vboxWddmSlConfigure(PVBOXMP_DEVEXT pDevExt, uint32_t fFlags) NTSTATUS VBoxWddmSlEnableVSyncNotification(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable) { + if (!pDevExt->bVSyncTimerEnabled == !fEnable) + return STATUS_SUCCESS; + if (!fEnable) { KeCancelTimer(&pDevExt->VSyncTimer); } else { + KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime); + LARGE_INTEGER DueTime; DueTime.QuadPart = -166666LL; /* 60 Hz */ KeSetTimerEx(&pDevExt->VSyncTimer, DueTime, 16, &pDevExt->VSyncDpc); } + + pDevExt->bVSyncTimerEnabled = !!fEnable; + return STATUS_SUCCESS; } @@ -2547,16 +1922,37 @@ NTSTATUS VBoxWddmSlGetScanLine(PVBOXMP_DEVEXT pDevExt, DXGKARG_GETSCANLINE *pGet Assert(pTarget->HeightTotal); Assert(pTarget->HeightVisible); Assert(pTarget->HeightTotal >= pTarget->HeightVisible); - Assert(pTarget->ScanLineState < pTarget->HeightTotal); if (pTarget->HeightTotal) { - uint32_t curScanLine = pTarget->ScanLineState; - ++pTarget->ScanLineState; - if (pTarget->ScanLineState >= pTarget->HeightTotal) - pTarget->ScanLineState = 0; + uint32_t curScanLine; + BOOL bVBlank; + LARGE_INTEGER DevVSyncTime; + DevVSyncTime.QuadPart = ASMAtomicReadU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart); + LARGE_INTEGER VSyncTime; + KeQuerySystemTime(&VSyncTime); + if (VSyncTime.QuadPart < DevVSyncTime.QuadPart) + { + WARN(("vsync time is less than the one stored in device")); + curScanLine = 0; + } + else + { + VSyncTime.QuadPart = VSyncTime.QuadPart - DevVSyncTime.QuadPart; + /* time is in 100ns, */ + curScanLine = (uint32_t)((pTarget->HeightTotal * VSyncTime.QuadPart) / DevVSyncTime.QuadPart); + if (pDevExt->bVSyncTimerEnabled) + { + if (curScanLine >= pTarget->HeightTotal) + curScanLine = 0; + } + else + { + curScanLine %= pTarget->HeightTotal; + } + } - BOOL bVBlank = (!curScanLine || curScanLine > pTarget->HeightVisible); + bVBlank = (!curScanLine || curScanLine > pTarget->HeightVisible); pGetScanLine->ScanLine = curScanLine; pGetScanLine->InVerticalBlank = bVBlank; } @@ -2568,36 +1964,21 @@ NTSTATUS VBoxWddmSlGetScanLine(PVBOXMP_DEVEXT pDevExt, DXGKARG_GETSCANLINE *pGet return STATUS_SUCCESS; } -static VOID vboxWddmSlVSyncDpc( - __in struct _KDPC *Dpc, - __in_opt PVOID DeferredContext, - __in_opt PVOID SystemArgument1, - __in_opt PVOID SystemArgument2 -) +static BOOLEAN vboxWddmSlVSyncIrqCb(PVOID pvContext) { - PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)DeferredContext; + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext; DXGKARGCB_NOTIFY_INTERRUPT_DATA notify; BOOLEAN bNeedDpc = FALSE; for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) { - PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i]; - PVBOXWDDM_ALLOCATION pPrimary = vboxWddmAquirePrimary(pDevExt, pSource, i); - if (pPrimary) + PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i]; + if (pTarget->fConnected) { - VBOXVIDEOOFFSET offVram = pPrimary->AllocData.Addr.offVram; - if (offVram != VBOXVIDEOOFFSET_VOID) - { - memset(¬ify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA)); - notify.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC; - /* @todo: !!!this is not correct in case we want source[i]->target[i!=j] mapping */ - notify.CrtcVsync.VidPnTargetId = i; - notify.CrtcVsync.PhysicalAddress.QuadPart = offVram; - /* yes, we can report VSync at dispatch */ - pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, ¬ify); - bNeedDpc = TRUE; - } - - vboxWddmAllocationRelease(pPrimary); + memset(¬ify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA)); + notify.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC; + notify.CrtcVsync.VidPnTargetId = i; + pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, ¬ify); + bNeedDpc = TRUE; } } @@ -2605,10 +1986,43 @@ static VOID vboxWddmSlVSyncDpc( { pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle); } + + return FALSE; +} + +static VOID vboxWddmSlVSyncDpc( + __in struct _KDPC *Dpc, + __in_opt PVOID DeferredContext, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 +) +{ + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)DeferredContext; + Assert(!pDevExt->fVSyncInVBlank); + ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 1); + + BOOLEAN bDummy; + NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution( + pDevExt->u.primary.DxgkInterface.DeviceHandle, + vboxWddmSlVSyncIrqCb, + pDevExt, + 0, /* IN ULONG MessageNumber */ + &bDummy); + if (!NT_SUCCESS(Status)) + WARN(("DxgkCbSynchronizeExecution failed Status %#x", Status)); + + LARGE_INTEGER VSyncTime; + KeQuerySystemTime(&VSyncTime); + ASMAtomicWriteU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart, VSyncTime.QuadPart); + + ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 0); } NTSTATUS VBoxWddmSlInit(PVBOXMP_DEVEXT pDevExt) { + pDevExt->bVSyncTimerEnabled = FALSE; + pDevExt->fVSyncInVBlank = 0; + KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime); KeInitializeTimer(&pDevExt->VSyncTimer); KeInitializeDpc(&pDevExt->VSyncDpc, vboxWddmSlVSyncDpc, pDevExt); return STATUS_SUCCESS; @@ -2667,7 +2081,7 @@ void vboxWddmDmAdjustDefaultVramLocations(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_P pSource = &pDevExt->aSources[i]; if (pSource->AllocData.Addr.offVram != PhAddr.QuadPart || pSource->AllocData.Addr.SegmentId != 1) - pSource->bGhSynced = FALSE; + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; pSource->AllocData.Addr.SegmentId = 1; pSource->AllocData.Addr.offVram = PhAddr.QuadPart; } diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.h index 27a919c0..742ecc22 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -71,9 +71,10 @@ PVOID vboxWddmHTableGet(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle); PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainCreate(); -DECLINLINE(BOOLEAN) vboxWddmSwapchainRetain(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain); -DECLINLINE(VOID) vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain); -PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc); +BOOLEAN vboxWddmSwapchainRetain(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain); +VOID vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain); +PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOCATION *pAlloc); +PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAllocData(PVBOXMP_DEVEXT pDevExt, const struct VBOXWDDM_ALLOC_DATA *pAllocData); VOID vboxWddmSwapchainAllocRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc); BOOLEAN vboxWddmSwapchainAllocAdd(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc); VOID vboxWddmSwapchainAllocRemoveAll(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain); @@ -90,13 +91,17 @@ NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PVBOXMP_DEVEXT pDeviceExtension, D NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult); NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult); NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PVBOXMP_DEVEXT pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos); -NTSTATUS vboxWddmRegQueryVideoGuidString(ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult); +NTSTATUS vboxWddmRegQueryVideoGuidString(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult); NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult); +NTSTATUS vboxWddmRegOpenKeyEx(OUT PHANDLE phKey, IN HANDLE hRootKey, IN PWCHAR pName, IN ACCESS_MASK fAccess); NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess); NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword); -NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT DWORD val); +NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, IN DWORD val); + +NTSTATUS vboxWddmRegDrvFlagsSet(PVBOXMP_DEVEXT pDevExt, DWORD fVal); +DWORD vboxWddmRegDrvFlagsGet(PVBOXMP_DEVEXT pDevExt, DWORD fDefault); UNICODE_STRING* vboxWddmVGuidGet(PVBOXMP_DEVEXT pDevExt); VOID vboxWddmVGuidFree(PVBOXMP_DEVEXT pDevExt); @@ -163,40 +168,6 @@ PVBOXWDDM_ALLOCATION vboxShRcTreeGet(PVBOXMP_DEVEXT pDevExt, HANDLE hSharedRc); BOOLEAN vboxShRcTreeRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc); #endif -/* visible rects */ -typedef struct VBOXWDDMVR_LIST -{ - LIST_ENTRY ListHead; - UINT cEntries; -} VBOXWDDMVR_LIST, *PVBOXWDDMVR_LIST; - -DECLINLINE(UINT) VBoxWddmVrListRectsCount(PVBOXWDDMVR_LIST pList) -{ - return pList->cEntries; -} - -DECLINLINE(BOOLEAN) VBoxWddmVrListIsEmpty(PVBOXWDDMVR_LIST pList) -{ - return !VBoxWddmVrListRectsCount(pList); -} - -DECLINLINE(void) VBoxWddmVrListInit(PVBOXWDDMVR_LIST pList) -{ - InitializeListHead(&pList->ListHead); - pList->cEntries = 0; -} - -void VBoxWddmVrListClear(PVBOXWDDMVR_LIST pList); - -void VBoxWddmVrListTranslate(PVBOXWDDMVR_LIST pList, LONG x, LONG y); - -NTSTATUS VBoxWddmVrListRectsAdd(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged); -NTSTATUS VBoxWddmVrListRectsSubst(PVBOXWDDMVR_LIST pList, UINT cRects, const PRECT aRects, BOOLEAN *pfChanged); -NTSTATUS VBoxWddmVrListRectsGet(PVBOXWDDMVR_LIST pList, UINT cRects, PRECT aRects); - -NTSTATUS VBoxWddmVrInit(); -void VBoxWddmVrTerm(); - NTSTATUS vboxWddmDrvCfgInit(PUNICODE_STRING pRegStr); #ifdef VBOX_VDMA_WITH_WATCHDOG @@ -215,4 +186,6 @@ void vboxWddmDiToAllocData(PVBOXMP_DEVEXT pDevExt, const DXGK_DISPLAY_INFORMATIO void vboxWddmDmAdjustDefaultVramLocations(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID ModifiedVidPnSourceId); #endif +NTSTATUS vboxWddmChildStatusConnect(PVBOXMP_DEVEXT pDevExt, uint32_t iChild, BOOLEAN fConnect); + #endif /* #ifndef ___VBoxMPMisc_h__ */ diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.cpp index b38c5587..d10580d7 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.h index 4fdc1f3e..491498f6 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPShgsmi.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -48,11 +48,18 @@ int VBoxSHGSMICommandDoneSynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER* pHeade void VBoxSHGSMICommandCancelAsynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER* pHeader); void VBoxSHGSMICommandCancelSynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER* pHeader); -DECLINLINE(HGSMIOFFSET) VBoxSHGSMICommandOffset(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER* pHeader) +DECLINLINE(HGSMIOFFSET) VBoxSHGSMICommandOffset(const PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER* pHeader) { return HGSMIHeapBufferOffset(&pHeap->Heap, (void*)pHeader); } +/* allows getting VRAM offset of arbitrary pointer within the SHGSMI command + * if invalid pointer is passed in, behavior is undefined */ +DECLINLINE(HGSMIOFFSET) VBoxSHGSMICommandPtrOffset(const PVBOXSHGSMI pHeap, const void * pvPtr) +{ + return HGSMIPointerToOffset (&pHeap->Heap.area, (const HGSMIBUFFERHEADER *)pvPtr); +} + int VBoxSHGSMIInit(PVBOXSHGSMI pHeap, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase, bool fOffsetBased); void VBoxSHGSMITerm(PVBOXSHGSMI pHeap); void* VBoxSHGSMIHeapAlloc(PVBOXSHGSMI pHeap, HGSMISIZE cbData, uint8_t u8Channel, uint16_t u16ChannelInfo); diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPTypes.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPTypes.h index 701dfb78..061bc7f4 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPTypes.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPTypes.h @@ -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; @@ -32,6 +32,12 @@ typedef struct VBOXWDDM_ALLOCATION *PVBOXWDDM_ALLOCATION; #include "VBoxMPVbva.h" #include "VBoxMPCr.h" +#include <cr_vreg.h> + +#ifdef DEBUG_misha +extern DWORD g_VBoxDbgBreakModes; +#endif + #if 0 #include <iprt/avl.h> #endif @@ -100,8 +106,16 @@ typedef struct VBOXWDDM_ALLOC_DATA { VBOXWDDM_SURFACE_DESC SurfDesc; VBOXWDDM_ADDR Addr; + uint32_t hostID; + uint32_t cHostIDRefs; + struct VBOXWDDM_SWAPCHAIN *pSwapchain; } VBOXWDDM_ALLOC_DATA, *PVBOXWDDM_ALLOC_DATA; +#define VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS 0x01 +#define VBOXWDDM_HGSYNC_F_SYNCED_LOCATION 0x02 +#define VBOXWDDM_HGSYNC_F_SYNCED_ALL (VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS | VBOXWDDM_HGSYNC_F_SYNCED_LOCATION) +#define VBOXWDDM_HGSYNC_F_CHANGED_LOCATION_ONLY (VBOXWDDM_HGSYNC_F_SYNCED_ALL & ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION) + typedef struct VBOXWDDM_SOURCE { struct VBOXWDDM_ALLOCATION * pPrimaryAllocation; @@ -109,8 +123,11 @@ typedef struct VBOXWDDM_SOURCE struct VBOXWDDM_ALLOCATION * pShadowAllocation; #endif VBOXWDDM_ALLOC_DATA AllocData; + uint8_t u8SyncState; BOOLEAN bVisible; - BOOLEAN bGhSynced; + /* specifies whether the source has 3D overlay data visible */ + BOOLEAN fHas3DVrs; + VBOXVR_LIST VrList; VBOXVBVAINFO Vbva; #ifdef VBOX_WITH_VIDEOHWACCEL /* @todo: in our case this seems more like a target property, @@ -127,9 +144,13 @@ typedef struct VBOXWDDM_SOURCE typedef struct VBOXWDDM_TARGET { - uint32_t ScanLineState; uint32_t HeightVisible; uint32_t HeightTotal; + /* since there coul be multiple state changes on auto-resize, + * we pend notifying host to avoid flickering */ + volatile bool fStateSyncPening; + bool fConnected; + bool fConfigured; } VBOXWDDM_TARGET, *PVBOXWDDM_TARGET; /* allocation */ @@ -137,7 +158,6 @@ typedef struct VBOXWDDM_TARGET typedef struct VBOXWDDM_ALLOCATION { LIST_ENTRY SwapchainEntry; - struct VBOXWDDM_SWAPCHAIN *pSwapchain; VBOXWDDM_ALLOC_TYPE enmType; volatile uint32_t cRefs; D3DDDI_RESOURCEFLAGS fRcFlags; @@ -166,7 +186,6 @@ typedef struct VBOXWDDM_ALLOCATION AVLPVNODECORE ShRcTreeEntry; #endif VBOXUHGSMI_BUFFER_TYPE_FLAGS fUhgsmiType; - PKEVENT pSynchEvent; } VBOXWDDM_ALLOCATION, *PVBOXWDDM_ALLOCATION; typedef struct VBOXWDDM_RESOURCE @@ -220,10 +239,12 @@ typedef struct VBOXWDDM_SWAPCHAIN volatile uint32_t cRefs; VBOXDISP_UMHANDLE hSwapchainUm; VBOXDISP_KMHANDLE hSwapchainKm; + int32_t winHostID; + BOOLEAN fExposed; POINT Pos; UINT width; UINT height; - VBOXWDDMVR_LIST VisibleRegions; + VBOXVR_LIST VisibleRegions; }VBOXWDDM_SWAPCHAIN, *PVBOXWDDM_SWAPCHAIN; typedef struct VBOXWDDM_CONTEXT @@ -234,7 +255,9 @@ typedef struct VBOXWDDM_CONTEXT UINT NodeOrdinal; UINT EngineAffinity; BOOLEAN fRenderFromShadowDisabled; + int32_t hostID; uint32_t u32CrConClientID; + VBOXMP_CRPACKER CrPacker; VBOXWDDM_HTABLE Swapchains; VBOXVIDEOCM_CTX CmContext; VBOXVIDEOCM_ALLOC_CONTEXT AllocContext; @@ -300,6 +323,7 @@ typedef struct VBOXWDDM_OPENALLOCATION PVBOXWDDM_DEVICE pDevice; uint32_t cShRcRefs; uint32_t cOpens; + uint32_t cHostIDRefs; } VBOXWDDM_OPENALLOCATION, *PVBOXWDDM_OPENALLOCATION; #define VBOXWDDM_MAX_VIDEOMODES 128 diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp index 93ff48f4..ac7e908c 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -19,85 +19,23 @@ #include "VBoxMPWddm.h" #include "common/VBoxMPCommon.h" -static int vboxVBVAInformHost (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO * pVbva, BOOL bEnable) -{ - int rc = VERR_NO_MEMORY; - void *p = VBoxHGSMIBufferAlloc (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, - sizeof (VBVAENABLE_EX), - HGSMI_CH_VBVA, - VBVA_ENABLE); - Assert(p); - if (!p) - { - LOGREL(("HGSMIHeapAlloc failed")); - rc = VERR_NO_MEMORY; - } - else - { - VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)p; - pEnableEx->u32ScreenId = pVbva->srcId; - - VBVAENABLE *pEnable = &pEnableEx->Base; - pEnable->u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE; - pEnable->u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET; - pEnable->u32Offset = (uint32_t)pVbva->offVBVA; - pEnable->i32Result = VERR_NOT_SUPPORTED; - - VBoxHGSMIBufferSubmit (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); - - if (bEnable) - { - rc = pEnable->i32Result; - AssertRC(rc); - } - else - rc = VINF_SUCCESS; - - VBoxHGSMIBufferFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); - } - return rc; -} - /* * Public hardware buffer methods. */ int vboxVbvaEnable (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva) { - VBVABUFFER *pVBVA = pVbva->pVBVA; - -// DISPDBG((1, "VBoxDisp::vboxVbvaEnable screen %p vbva off 0x%x\n", ppdev->pjScreen, ppdev->layout.offVBVABuffer)); - - pVBVA->hostFlags.u32HostEvents = 0; - pVBVA->hostFlags.u32SupportedOrders = 0; - pVBVA->off32Data = 0; - pVBVA->off32Free = 0; - RtlZeroMemory (pVBVA->aRecords, sizeof (pVBVA->aRecords)); - pVBVA->indexRecordFirst = 0; - pVBVA->indexRecordFree = 0; - pVBVA->cbPartialWriteThreshold = 256; - pVBVA->cbData = pVbva->cbVBVA - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data); + if (VBoxVBVAEnable(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, + pVbva->Vbva.pVBVA, pVbva->srcId)) + return VINF_SUCCESS; - pVbva->fHwBufferOverflow = FALSE; - pVbva->pRecord = NULL; - - int rc = vboxVBVAInformHost (pDevExt, pVbva, TRUE); - AssertRC(rc); - - if (!RT_SUCCESS(rc)) - vboxVbvaDisable (pDevExt, pVbva); - - return rc; + WARN(("VBoxVBVAEnable failed!")); + return VERR_GENERAL_FAILURE; } int vboxVbvaDisable (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva) { -// DISPDBG((1, "VBoxDisp::vbvaDisable called.\n")); - - pVbva->fHwBufferOverflow = FALSE; - pVbva->pRecord = NULL; -// ppdev->pVBVA = NULL; - - return vboxVBVAInformHost (pDevExt, pVbva, FALSE); + VBoxVBVADisable(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pVbva->srcId); + return VINF_SUCCESS; } int vboxVbvaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, ULONG offBuffer, ULONG cbBuffer, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId) @@ -107,17 +45,20 @@ int vboxVbvaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, ULONG offBuffer, KeInitializeSpinLock(&pVbva->Lock); int rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), - (void**)&pVbva->pVBVA, + (void**)&pVbva->Vbva.pVBVA, offBuffer, cbBuffer); - AssertRC(rc); if (RT_SUCCESS(rc)) { - Assert(pVbva->pVBVA); - pVbva->offVBVA = offBuffer; - pVbva->cbVBVA = cbBuffer; + Assert(pVbva->Vbva.pVBVA); + VBoxVBVASetupBufferContext(&pVbva->Vbva, offBuffer, cbBuffer); pVbva->srcId = srcId; } + else + { + WARN(("VBoxMPCmnMapAdapterMemory failed rc %d", rc)); + } + return rc; } @@ -125,188 +66,421 @@ int vboxVbvaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, ULONG offBuffer, int vboxVbvaDestroy(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva) { int rc = VINF_SUCCESS; - VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pVbva->pVBVA); - memset(pVbva, 0, sizeof(VBOXVBVAINFO)); + VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pVbva->Vbva.pVBVA); + memset(pVbva, 0, sizeof (VBOXVBVAINFO)); return rc; } -/* - * Private operations. - */ -static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA) +int vboxVbvaReportDirtyRect (PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSrc, RECT *pRectOrig) { - int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free; + VBVACMDHDR hdr; - return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff; + RECT rect = *pRectOrig; + +// if (rect.left < 0) rect.left = 0; +// if (rect.top < 0) rect.top = 0; +// if (rect.right > (int)ppdev->cxScreen) rect.right = ppdev->cxScreen; +// if (rect.bottom > (int)ppdev->cyScreen) rect.bottom = ppdev->cyScreen; + + hdr.x = (int16_t)rect.left; + hdr.y = (int16_t)rect.top; + hdr.w = (uint16_t)(rect.right - rect.left); + hdr.h = (uint16_t)(rect.bottom - rect.top); + + hdr.x += (int16_t)pSrc->VScreenPos.x; + hdr.y += (int16_t)pSrc->VScreenPos.y; + + if (VBoxVBVAWrite(&pSrc->Vbva.Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, &hdr, sizeof(hdr))) + return VINF_SUCCESS; + + WARN(("VBoxVBVAWrite failed")); + return VERR_GENERAL_FAILURE; } -static void vboxHwBufferFlush (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva) +/* command vbva ring buffer */ + +/* customized VBVA implementation */ + +/* Forward declarations of internal functions. */ +static void vboxHwBufferPlaceDataAt(PVBVAEXBUFFERCONTEXT pCtx, const void *p, + uint32_t cb, uint32_t offset); +static bool vboxHwBufferWrite(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + const void *p, uint32_t cb); + +DECLINLINE(void) vboxVBVAExFlush(struct VBVAEXBUFFERCONTEXT *pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx) { - /* Issue the flush command. */ - void *p = VBoxHGSMIBufferAlloc (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, - sizeof (VBVAFLUSH), - HGSMI_CH_VBVA, - VBVA_FLUSH); - Assert(p); - if (!p) + pCtx->pfnFlush(pCtx, pHGSMICtx, pCtx->pvFlush); +} + +static int vboxCmdVbvaSubmitHgsmi(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, HGSMIOFFSET offDr) +{ + VBoxVideoCmnPortWriteUlong(pHGSMICtx->port, offDr); + return VINF_SUCCESS; +} +#define vboxCmdVbvaSubmit vboxCmdVbvaSubmitHgsmi + +static VBOXCMDVBVA_CTL * vboxCmdVbvaCtlCreate(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, uint32_t cbCtl) +{ + Assert(cbCtl >= sizeof (VBOXCMDVBVA_CTL)); + return (VBOXCMDVBVA_CTL*)VBoxSHGSMICommandAlloc(&pHGSMICtx->heapCtx, cbCtl, HGSMI_CH_VBVA, VBVA_CMDVBVA_CTL); +} + +static void vboxCmdVbvaCtlFree(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, VBOXCMDVBVA_CTL * pCtl) +{ + VBoxSHGSMICommandFree(&pHGSMICtx->heapCtx, pCtl); +} + +static int vboxCmdVbvaCtlSubmitSync(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, VBOXCMDVBVA_CTL * pCtl) +{ + const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepSynch(&pHGSMICtx->heapCtx, pCtl); + if (!pHdr) { - LOGREL(("HGSMIHeapAlloc failed")); + WARN(("VBoxSHGSMICommandPrepSynch returnd NULL")); + return VERR_INVALID_PARAMETER; } - else + + HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pHGSMICtx->heapCtx, pHdr); + if (offCmd == HGSMIOFFSET_VOID) { - VBVAFLUSH *pFlush = (VBVAFLUSH *)p; + WARN(("VBoxSHGSMICommandOffset returnd NULL")); + VBoxSHGSMICommandCancelSynch(&pHGSMICtx->heapCtx, pHdr); + return VERR_INVALID_PARAMETER; + } + + int rc = vboxCmdVbvaSubmit(pHGSMICtx, offCmd); + if (RT_SUCCESS(rc)) + { + rc = VBoxSHGSMICommandDoneSynch(&pHGSMICtx->heapCtx, pHdr); + if (RT_SUCCESS(rc)) + { + rc = pCtl->i32Result; + if (!RT_SUCCESS(rc)) + WARN(("pCtl->i32Result %d", pCtl->i32Result)); + + return rc; + } + else + WARN(("VBoxSHGSMICommandDoneSynch returnd %d", rc)); + } + else + WARN(("vboxCmdVbvaSubmit returnd %d", rc)); + + VBoxSHGSMICommandCancelSynch(&pHGSMICtx->heapCtx, pHdr); - pFlush->u32Reserved = 0; + return rc; +} - VBoxHGSMIBufferSubmit (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); +static int vboxCmdVbvaCtlSubmitAsync(PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, VBOXCMDVBVA_CTL * pCtl, PFNVBOXSHGSMICMDCOMPLETION_IRQ pfnCompletionIrq, void *pvCompletionIrq) +{ + const VBOXSHGSMIHEADER* pHdr = VBoxSHGSMICommandPrepAsynchIrq(&pHGSMICtx->heapCtx, pCtl, pfnCompletionIrq, pvCompletionIrq, VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE); + if (!pHdr) + { + WARN(("VBoxSHGSMICommandPrepAsynchIrq returnd NULL")); + return VERR_INVALID_PARAMETER; + } - VBoxHGSMIBufferFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); + HGSMIOFFSET offCmd = VBoxSHGSMICommandOffset(&pHGSMICtx->heapCtx, pHdr); + if (offCmd == HGSMIOFFSET_VOID) + { + WARN(("VBoxSHGSMICommandOffset returnd NULL")); + VBoxSHGSMICommandCancelAsynch(&pHGSMICtx->heapCtx, pHdr); + return VERR_INVALID_PARAMETER; } - return; + int rc = vboxCmdVbvaSubmit(pHGSMICtx, offCmd); + if (RT_SUCCESS(rc)) + { + VBoxSHGSMICommandDoneAsynch(&pHGSMICtx->heapCtx, pHdr); + return rc; + } + else + WARN(("vboxCmdVbvaSubmit returnd %d", rc)); + + VBoxSHGSMICommandCancelAsynch(&pHGSMICtx->heapCtx, pHdr); + + return rc; } -static void vboxHwBufferPlaceDataAt (VBVABUFFER *pVBVA, const void *p, uint32_t cb, uint32_t offset) +static int vboxVBVAExCtlSubmitEnableDisable(PVBVAEXBUFFERCONTEXT pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, bool fEnable) { - uint32_t u32BytesTillBoundary = pVBVA->cbData - offset; - uint8_t *dst = &pVBVA->au8Data[offset]; - int32_t i32Diff = cb - u32BytesTillBoundary; + VBOXCMDVBVA_CTL_ENABLE *pCtl = (VBOXCMDVBVA_CTL_ENABLE*)vboxCmdVbvaCtlCreate(pHGSMICtx, sizeof (*pCtl)); + if (!pCtl) + { + WARN(("vboxCmdVbvaCtlCreate failed")); + return VERR_NO_MEMORY; + } - if (i32Diff <= 0) + pCtl->Hdr.u32Type = VBOXCMDVBVACTL_TYPE_ENABLE; + pCtl->Hdr.i32Result = VERR_NOT_IMPLEMENTED; + memset(&pCtl->Enable, 0, sizeof (pCtl->Enable)); + pCtl->Enable.u32Flags = fEnable? VBVA_F_ENABLE: VBVA_F_DISABLE; + pCtl->Enable.u32Offset = pCtx->offVRAMBuffer; + pCtl->Enable.i32Result = VERR_NOT_SUPPORTED; + pCtl->Enable.u32Flags |= VBVA_F_ABSOFFSET; + + int rc = vboxCmdVbvaCtlSubmitSync(pHGSMICtx, &pCtl->Hdr); + if (RT_SUCCESS(rc)) { - /* Chunk will not cross buffer boundary. */ - memcpy (dst, p, cb); + rc = pCtl->Hdr.i32Result; + if (!RT_SUCCESS(rc)) + WARN(("vboxCmdVbvaCtlSubmitSync Disable failed %d", rc)); } else + WARN(("vboxCmdVbvaCtlSubmitSync returnd %d", rc)); + + vboxCmdVbvaCtlFree(pHGSMICtx, &pCtl->Hdr); + + return rc; +} + +/* + * Public hardware buffer methods. + */ +RTDECL(int) VBoxVBVAExEnable(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + VBVABUFFER *pVBVA) +{ + int rc = VERR_GENERAL_FAILURE; + + LogFlowFunc(("pVBVA %p\n", pVBVA)); + +#if 0 /* All callers check this */ + if (ppdev->bHGSMISupported) +#endif { - /* Chunk crosses buffer boundary. */ - memcpy (dst, p, u32BytesTillBoundary); - memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff); + LogFunc(("pVBVA %p vbva off 0x%x\n", pVBVA, pCtx->offVRAMBuffer)); + + pVBVA->hostFlags.u32HostEvents = 0; + pVBVA->hostFlags.u32SupportedOrders = 0; + pVBVA->off32Data = 0; + pVBVA->off32Free = 0; + memset(pVBVA->aRecords, 0, sizeof (pVBVA->aRecords)); + pVBVA->indexRecordFirst = 0; + pVBVA->indexRecordFree = 0; + pVBVA->cbPartialWriteThreshold = 256; + pVBVA->cbData = pCtx->cbBuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data); + + pCtx->fHwBufferOverflow = false; + pCtx->pRecord = NULL; + pCtx->pVBVA = pVBVA; + + rc = vboxVBVAExCtlSubmitEnableDisable(pCtx, pHGSMICtx, true); + } + + if (!RT_SUCCESS(rc)) + { + WARN(("enable failed %d", rc)); + VBoxVBVAExDisable(pCtx, pHGSMICtx); } + return rc; +} + +RTDECL(void) VBoxVBVAExDisable(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx) +{ + LogFlowFunc(("\n")); + + pCtx->fHwBufferOverflow = false; + pCtx->pRecord = NULL; + pCtx->pVBVA = NULL; + + vboxVBVAExCtlSubmitEnableDisable(pCtx, pHGSMICtx, false); + return; } -BOOL vboxVbvaBufferBeginUpdate (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva) +RTDECL(bool) VBoxVBVAExBufferBeginUpdate(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx) { - BOOL bRc = FALSE; + bool bRc = false; - // DISPDBG((1, "VBoxDisp::vboxHwBufferBeginUpdate called flags = 0x%08X\n", - // ppdev->pVBVA? ppdev->pVBVA->u32HostEvents: -1)); + // LogFunc(("flags = 0x%08X\n", pCtx->pVBVA? pCtx->pVBVA->u32HostEvents: -1)); - if ( pVbva->pVBVA - && (pVbva->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED)) + if ( pCtx->pVBVA + && (pCtx->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED)) { uint32_t indexRecordNext; - Assert (!pVbva->fHwBufferOverflow); - Assert (pVbva->pRecord == NULL); + Assert(!pCtx->fHwBufferOverflow); + Assert(pCtx->pRecord == NULL); - indexRecordNext = (pVbva->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS; + indexRecordNext = (pCtx->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS; - if (indexRecordNext == pVbva->pVBVA->indexRecordFirst) + if (indexRecordNext == pCtx->indexRecordFirstUncompleted) { /* All slots in the records queue are used. */ - vboxHwBufferFlush (pDevExt, pVbva); + vboxVBVAExFlush (pCtx, pHGSMICtx); } - if (indexRecordNext == pVbva->pVBVA->indexRecordFirst) + if (indexRecordNext == pCtx->indexRecordFirstUncompleted) { -// /* Even after flush there is no place. Fail the request. */ -// LOG(("no space in the queue of records!!! first %d, last %d", -// ppdev->pVBVA->indexRecordFirst, ppdev->pVBVA->indexRecordFree)); + /* Even after flush there is no place. Fail the request. */ + LogFunc(("no space in the queue of records!!! first %d, last %d\n", + indexRecordNext, pCtx->pVBVA->indexRecordFree)); } else { /* Initialize the record. */ - VBVARECORD *pRecord = &pVbva->pVBVA->aRecords[pVbva->pVBVA->indexRecordFree]; + VBVARECORD *pRecord = &pCtx->pVBVA->aRecords[pCtx->pVBVA->indexRecordFree]; pRecord->cbRecord = VBVA_F_RECORD_PARTIAL; - pVbva->pVBVA->indexRecordFree = indexRecordNext; + pCtx->pVBVA->indexRecordFree = indexRecordNext; - // LOG(("indexRecordNext = %d\n", indexRecordNext)); + // LogFunc(("indexRecordNext = %d\n", indexRecordNext)); /* Remember which record we are using. */ - pVbva->pRecord = pRecord; + pCtx->pRecord = pRecord; - bRc = TRUE; + bRc = true; } } return bRc; } -void vboxVbvaBufferEndUpdate (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva) +RTDECL(void) VBoxVBVAExBufferEndUpdate(PVBVAEXBUFFERCONTEXT pCtx) { VBVARECORD *pRecord; - // LOG(("VBoxDisp::vboxHwBufferEndUpdate called")); + // LogFunc(("\n")); - Assert(pVbva->pVBVA); + Assert(pCtx->pVBVA); - pRecord = pVbva->pRecord; - Assert (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)); + pRecord = pCtx->pRecord; + Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)); /* Mark the record completed. */ pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL; - pVbva->fHwBufferOverflow = FALSE; - pVbva->pRecord = NULL; + pCtx->fHwBufferOverflow = false; + pCtx->pRecord = NULL; + + return; +} + +DECLINLINE(bool) vboxVBVAExIsEntryInRange(uint32_t u32First, uint32_t u32Entry, uint32_t u32Free) +{ + return ( u32First != u32Free + && ( + (u32First < u32Free && u32Entry >= u32First && u32Entry < u32Free) + || (u32First > u32Free && (u32Entry >= u32First || u32Entry < u32Free)) + ) + ); +} + +#ifdef DEBUG + +DECLINLINE(void) vboxHwBufferVerifyCompleted(PVBVAEXBUFFERCONTEXT pCtx) +{ + VBVABUFFER *pVBVA = pCtx->pVBVA; + if (!vboxVBVAExIsEntryInRange(pCtx->indexRecordFirstUncompleted, pVBVA->indexRecordFirst, pVBVA->indexRecordFree)) + { + WARN(("invalid record set")); + } + + if (!vboxVBVAExIsEntryInRange(pCtx->off32DataUncompleted, pVBVA->off32Data, pVBVA->off32Free)) + { + WARN(("invalid data set")); + } +} +#endif + +/* + * Private operations. + */ +static uint32_t vboxHwBufferAvail(PVBVAEXBUFFERCONTEXT pCtx, const VBVABUFFER *pVBVA) +{ + int32_t i32Diff = pCtx->off32DataUncompleted - pVBVA->off32Free; + + return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff; +} + +static uint32_t vboxHwBufferContiguousAvail(PVBVAEXBUFFERCONTEXT pCtx, const VBVABUFFER *pVBVA) +{ + int32_t i32Diff = pCtx->off32DataUncompleted - pVBVA->off32Free; + + return i32Diff > 0 ? i32Diff: pVBVA->cbData - pVBVA->off32Free; +} + +static void vboxHwBufferPlaceDataAt(PVBVAEXBUFFERCONTEXT pCtx, const void *p, + uint32_t cb, uint32_t offset) +{ + VBVABUFFER *pVBVA = pCtx->pVBVA; + uint32_t u32BytesTillBoundary = pVBVA->cbData - offset; + uint8_t *dst = &pVBVA->au8Data[offset]; + int32_t i32Diff = cb - u32BytesTillBoundary; + + if (i32Diff <= 0) + { + /* Chunk will not cross buffer boundary. */ + memcpy (dst, p, cb); + } + else + { + /* Chunk crosses buffer boundary. */ + memcpy (dst, p, u32BytesTillBoundary); + memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff); + } return; } -static int vboxHwBufferWrite (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, const void *p, uint32_t cb) +static bool vboxHwBufferWrite(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + const void *p, uint32_t cb) { VBVARECORD *pRecord; uint32_t cbHwBufferAvail; uint32_t cbWritten = 0; - VBVABUFFER *pVBVA = pVbva->pVBVA; + VBVABUFFER *pVBVA = pCtx->pVBVA; Assert(pVBVA); - if (!pVBVA || pVbva->fHwBufferOverflow) + if (!pVBVA || pCtx->fHwBufferOverflow) { - return VERR_INVALID_STATE; + return false; } - Assert (pVBVA->indexRecordFirst != pVBVA->indexRecordFree); + Assert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree); + Assert(pCtx->indexRecordFirstUncompleted != pVBVA->indexRecordFree); - pRecord = pVbva->pRecord; - Assert (pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)); + pRecord = pCtx->pRecord; + Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)); -// LOGF(("VW %d", cb)); + // LogFunc(("%d\n", cb)); - cbHwBufferAvail = vboxHwBufferAvail (pVBVA); + cbHwBufferAvail = vboxHwBufferAvail(pCtx, pVBVA); while (cb > 0) { uint32_t cbChunk = cb; - // LOG(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n", - // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten)); + // LogFunc(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n", + // pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten)); if (cbChunk >= cbHwBufferAvail) { - LOGF(("1) avail %d, chunk %d", cbHwBufferAvail, cbChunk)); + LogFunc(("1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk)); - vboxHwBufferFlush (pDevExt, pVbva); + vboxVBVAExFlush(pCtx, pHGSMICtx); - cbHwBufferAvail = vboxHwBufferAvail (pVBVA); + cbHwBufferAvail = vboxHwBufferAvail(pCtx, pVBVA); if (cbChunk >= cbHwBufferAvail) { - LOG(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.", - cb, cbHwBufferAvail)); + WARN(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n", + cb, cbHwBufferAvail)); if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold) { - LOGREL(("Buffer overflow!!!")); - pVbva->fHwBufferOverflow = TRUE; - Assert(FALSE); - return VERR_NO_MEMORY; + WARN(("Buffer overflow!!!\n")); + pCtx->fHwBufferOverflow = true; + Assert(false); + return false; } cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold; @@ -314,9 +488,9 @@ static int vboxHwBufferWrite (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, const } Assert(cbChunk <= cb); - Assert(cbChunk <= vboxHwBufferAvail (pVBVA)); + Assert(cbChunk <= vboxHwBufferAvail(pCtx, pVBVA)); - vboxHwBufferPlaceDataAt (pVbva->pVBVA, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free); + vboxHwBufferPlaceDataAt (pCtx, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free); pVBVA->off32Free = (pVBVA->off32Free + cbChunk) % pVBVA->cbData; pRecord->cbRecord += cbChunk; @@ -326,45 +500,632 @@ static int vboxHwBufferWrite (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, const cbWritten += cbChunk; } - return VINF_SUCCESS; + return true; } /* * Public writer to the hardware buffer. */ -int vboxWrite (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, const void *pv, uint32_t cb) +RTDECL(uint32_t) VBoxVBVAExGetFreeTail(PVBVAEXBUFFERCONTEXT pCtx) { - return vboxHwBufferWrite (pDevExt, pVbva, pv, cb); + VBVABUFFER *pVBVA = pCtx->pVBVA; + if (pVBVA->off32Data <= pVBVA->off32Free) + return pVBVA->cbData - pVBVA->off32Free; + return 0; } - -int vboxVbvaReportDirtyRect (PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSrc, RECT *pRectOrig) +RTDECL(void*) VBoxVBVAExAllocContiguous(PVBVAEXBUFFERCONTEXT pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, uint32_t cb) { - VBVACMDHDR hdr; + VBVARECORD *pRecord; + uint32_t cbHwBufferContiguousAvail; + uint32_t offset; - RECT rect = *pRectOrig; + VBVABUFFER *pVBVA = pCtx->pVBVA; + Assert(pVBVA); -// if (rect.left < 0) rect.left = 0; -// if (rect.top < 0) rect.top = 0; -// if (rect.right > (int)ppdev->cxScreen) rect.right = ppdev->cxScreen; -// if (rect.bottom > (int)ppdev->cyScreen) rect.bottom = ppdev->cyScreen; + if (!pVBVA || pCtx->fHwBufferOverflow) + { + return NULL; + } + + Assert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree); + Assert(pCtx->indexRecordFirstUncompleted != pVBVA->indexRecordFree); - hdr.x = (int16_t)rect.left; - hdr.y = (int16_t)rect.top; - hdr.w = (uint16_t)(rect.right - rect.left); - hdr.h = (uint16_t)(rect.bottom - rect.top); + pRecord = pCtx->pRecord; + Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)); - hdr.x += (int16_t)pSrc->VScreenPos.x; - hdr.y += (int16_t)pSrc->VScreenPos.y; + // LogFunc(("%d\n", cb)); - return vboxWrite (pDevExt, &pSrc->Vbva, &hdr, sizeof(hdr)); + if (pVBVA->cbData < cb) + { + WARN(("requested to allocate buffer of size %d bigger than the VBVA ring buffer size %d", cb, pVBVA->cbData)); + return NULL; + } + + cbHwBufferContiguousAvail = vboxHwBufferContiguousAvail(pCtx, pVBVA); + + if (cbHwBufferContiguousAvail < cb) + { + if (cb < pVBVA->cbData - pVBVA->off32Free) + { + /* the entire contiguous part is smaller than the requested buffer */ + return NULL; + } + + vboxVBVAExFlush(pCtx, pHGSMICtx); + + cbHwBufferContiguousAvail = vboxHwBufferContiguousAvail(pCtx, pVBVA); + if (cbHwBufferContiguousAvail < cb) + { + /* this is really bad - the host did not clean up buffer even after we requested it to flush */ + WARN(("Host did not clean up the buffer!")); + return NULL; + } + } + + offset = pVBVA->off32Free; + + pVBVA->off32Free = (pVBVA->off32Free + cb) % pVBVA->cbData; + pRecord->cbRecord += cb; + + return &pVBVA->au8Data[offset]; } -#ifdef VBOXVDMA_WITH_VBVA -int vboxVbvaReportCmdOffset (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, uint32_t offCmd) +RTDECL(bool) VBoxVBVAExIsProcessing(PVBVAEXBUFFERCONTEXT pCtx) { - VBOXVDMAVBVACMD cmd; - cmd.offCmd = offCmd; - return vboxWrite (pDevExt, pVbva, &cmd, sizeof(cmd)); + uint32_t u32HostEvents = pCtx->pVBVA->hostFlags.u32HostEvents; + return !!(u32HostEvents & VBVA_F_STATE_PROCESSING); } + +RTDECL(void) VBoxVBVAExCBufferCompleted(PVBVAEXBUFFERCONTEXT pCtx) +{ + VBVABUFFER *pVBVA = pCtx->pVBVA; + uint32_t cbBuffer = pVBVA->aRecords[pCtx->indexRecordFirstUncompleted].cbRecord; + pCtx->indexRecordFirstUncompleted = (pCtx->indexRecordFirstUncompleted + 1) % VBVA_MAX_RECORDS; + pCtx->off32DataUncompleted = (pCtx->off32DataUncompleted + cbBuffer) % pVBVA->cbData; +#ifdef DEBUG + vboxHwBufferVerifyCompleted(pCtx); #endif +} + +RTDECL(bool) VBoxVBVAExWrite(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + const void *pv, uint32_t cb) +{ + return vboxHwBufferWrite(pCtx, pHGSMICtx, pv, cb); +} + +RTDECL(bool) VBoxVBVAExOrderSupported(PVBVAEXBUFFERCONTEXT pCtx, unsigned code) +{ + VBVABUFFER *pVBVA = pCtx->pVBVA; + + if (!pVBVA) + { + return false; + } + + if (pVBVA->hostFlags.u32SupportedOrders & (1 << code)) + { + return true; + } + + return false; +} + +RTDECL(void) VBoxVBVAExSetupBufferContext(PVBVAEXBUFFERCONTEXT pCtx, + uint32_t offVRAMBuffer, + uint32_t cbBuffer, + PFNVBVAEXBUFFERFLUSH pfnFlush, + void *pvFlush) +{ + memset(pCtx, 0, RT_OFFSETOF(VBVAEXBUFFERCONTEXT, pVBVA)); + pCtx->offVRAMBuffer = offVRAMBuffer; + pCtx->cbBuffer = cbBuffer; + pCtx->pfnFlush = pfnFlush; + pCtx->pvFlush = pvFlush; +} + +static void* vboxVBVAExIterCur(PVBVAEXBUFFERITERBASE pIter, struct VBVABUFFER *pVBVA, uint32_t *pcbBuffer, bool *pfProcessed) +{ + uint32_t cbRecord = pVBVA->aRecords[pIter->iCurRecord].cbRecord; + if (cbRecord == VBVA_F_RECORD_PARTIAL) + return NULL; + if (pcbBuffer) + *pcbBuffer = cbRecord; + if (pfProcessed) + *pfProcessed = !vboxVBVAExIsEntryInRange(pVBVA->indexRecordFirst, pIter->iCurRecord, pVBVA->indexRecordFree); + return &pVBVA->au8Data[pIter->off32CurCmd]; +} + +DECLINLINE(uint32_t) vboxVBVAExSubst(uint32_t x, uint32_t val, uint32_t maxVal) +{ + int32_t result = (int32_t)(x - val); + return result >= 0 ? (uint32_t)result : maxVal - (((uint32_t)(-result)) % maxVal); +} + +RTDECL(void) VBoxVBVAExBIterInit(PVBVAEXBUFFERCONTEXT pCtx, PVBVAEXBUFFERBACKWARDITER pIter) +{ + struct VBVABUFFER *pVBVA = pCtx->pVBVA; + pIter->Base.pCtx = pCtx; + uint32_t iCurRecord = vboxVBVAExSubst(pVBVA->indexRecordFree, 1, VBVA_MAX_RECORDS); + if (vboxVBVAExIsEntryInRange(pCtx->indexRecordFirstUncompleted, iCurRecord, pVBVA->indexRecordFree)) + { + /* even if the command gets completed by the time we're doing the pCtx->pVBVA->aRecords[iCurRecord].cbRecord below, + * the pCtx->pVBVA->aRecords[iCurRecord].cbRecord will still be valid, as it can only be modified by a submitter, + * and we are in a submitter context now */ + pIter->Base.iCurRecord = iCurRecord; + pIter->Base.off32CurCmd = vboxVBVAExSubst(pVBVA->off32Free, pCtx->pVBVA->aRecords[iCurRecord].cbRecord, pVBVA->cbData); + } + else + { + /* no data */ + pIter->Base.iCurRecord = pVBVA->indexRecordFree; + pIter->Base.off32CurCmd = pVBVA->off32Free; + } +} + +RTDECL(void*) VBoxVBVAExBIterNext(PVBVAEXBUFFERBACKWARDITER pIter, uint32_t *pcbBuffer, bool *pfProcessed) +{ + PVBVAEXBUFFERCONTEXT pCtx = pIter->Base.pCtx; + struct VBVABUFFER *pVBVA = pCtx->pVBVA; + uint32_t indexRecordFirstUncompleted = pCtx->indexRecordFirstUncompleted; + if (!vboxVBVAExIsEntryInRange(indexRecordFirstUncompleted, pIter->Base.iCurRecord, pVBVA->indexRecordFree)) + return NULL; + + void *pvBuffer = vboxVBVAExIterCur(&pIter->Base, pVBVA, pcbBuffer, pfProcessed); + AssertRelease(pvBuffer); + + /* even if the command gets completed by the time we're doing the pCtx->pVBVA->aRecords[pIter->Base.iCurRecord].cbRecord below, + * the pCtx->pVBVA->aRecords[pIter->Base.iCurRecord].cbRecord will still be valid, as it can only be modified by a submitter, + * and we are in a submitter context now */ + pIter->Base.iCurRecord = vboxVBVAExSubst(pIter->Base.iCurRecord, 1, VBVA_MAX_RECORDS); + pIter->Base.off32CurCmd = vboxVBVAExSubst(pIter->Base.off32CurCmd, pCtx->pVBVA->aRecords[pIter->Base.iCurRecord].cbRecord, pVBVA->cbData); + + return pvBuffer; +} + +RTDECL(void) VBoxVBVAExCFIterInit(PVBVAEXBUFFERCONTEXT pCtx, PVBVAEXBUFFERFORWARDITER pIter) +{ + pIter->Base.pCtx = pCtx; + pIter->Base.iCurRecord = pCtx->indexRecordFirstUncompleted; + pIter->Base.off32CurCmd = pCtx->off32DataUncompleted; +} + +RTDECL(void*) VBoxVBVAExCFIterNext(PVBVAEXBUFFERFORWARDITER pIter, uint32_t *pcbBuffer, bool *pfProcessed) +{ + PVBVAEXBUFFERCONTEXT pCtx = pIter->Base.pCtx; + struct VBVABUFFER *pVBVA = pCtx->pVBVA; + uint32_t indexRecordFree = pVBVA->indexRecordFree; + if (!vboxVBVAExIsEntryInRange(pCtx->indexRecordFirstUncompleted, pIter->Base.iCurRecord, indexRecordFree)) + return NULL; + + uint32_t cbBuffer; + void *pvData = vboxVBVAExIterCur(&pIter->Base, pVBVA, &cbBuffer, pfProcessed); + if (!pvData) + return NULL; + + pIter->Base.iCurRecord = (pIter->Base.iCurRecord + 1) % VBVA_MAX_RECORDS; + pIter->Base.off32CurCmd = (pIter->Base.off32CurCmd + cbBuffer) % pVBVA->cbData; + + if (pcbBuffer) + *pcbBuffer = cbBuffer; + + return pvData; +} + +/**/ + +int VBoxCmdVbvaEnable(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva) +{ + return VBoxVBVAExEnable(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pVbva->Vbva.pVBVA); +} + +int VBoxCmdVbvaDisable(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva) +{ + VBoxVBVAExDisable(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx); + return VINF_SUCCESS; +} + +int VBoxCmdVbvaDestroy(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva) +{ + int rc = VINF_SUCCESS; + VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pVbva->Vbva.pVBVA); + memset(pVbva, 0, sizeof (*pVbva)); + return rc; +} + +static void vboxCmdVbvaDdiNotifyCompleteIrq(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, UINT u32FenceId, DXGK_INTERRUPT_TYPE enmComplType) +{ + DXGKARGCB_NOTIFY_INTERRUPT_DATA notify; + memset(¬ify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA)); + switch (enmComplType) + { + case DXGK_INTERRUPT_DMA_COMPLETED: + notify.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED; + notify.DmaCompleted.SubmissionFenceId = u32FenceId; + notify.DmaCompleted.NodeOrdinal = pVbva->idNode; + break; + + case DXGK_INTERRUPT_DMA_PREEMPTED: + notify.InterruptType = DXGK_INTERRUPT_DMA_PREEMPTED; + notify.DmaPreempted.PreemptionFenceId = u32FenceId; + notify.DmaPreempted.NodeOrdinal = pVbva->idNode; + notify.DmaPreempted.LastCompletedFenceId = pVbva->u32FenceCompleted; + break; + + case DXGK_INTERRUPT_DMA_FAULTED: + Assert(0); + notify.InterruptType = DXGK_INTERRUPT_DMA_FAULTED; + notify.DmaFaulted.FaultedFenceId = u32FenceId; + notify.DmaFaulted.Status = STATUS_UNSUCCESSFUL; /* @todo: better status ? */ + notify.DmaFaulted.NodeOrdinal = pVbva->idNode; + break; + + default: + WARN(("unrecognized completion type %d", enmComplType)); + break; + } + + pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, ¬ify); +} + +typedef struct VBOXCMDVBVA_NOTIFYCOMPLETED_CB +{ + PVBOXMP_DEVEXT pDevExt; + VBOXCMDVBVA *pVbva; + volatile UINT *pu32FenceId; + DXGK_INTERRUPT_TYPE enmComplType; +} VBOXCMDVBVA_NOTIFYCOMPLETED_CB, *PVBOXCMDVBVA_NOTIFYCOMPLETED_CB; + +static BOOLEAN vboxCmdVbvaDdiNotifyCompleteCb(PVOID pvContext) +{ + PVBOXCMDVBVA_NOTIFYCOMPLETED_CB pData = (PVBOXCMDVBVA_NOTIFYCOMPLETED_CB)pvContext; + if (*pData->pu32FenceId) + { + UINT u32FenceId = *pData->pu32FenceId; + *pData->pu32FenceId = 0; + + vboxCmdVbvaDdiNotifyCompleteIrq(pData->pDevExt, pData->pVbva, u32FenceId, pData->enmComplType); + + pData->pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pData->pDevExt->u.primary.DxgkInterface.DeviceHandle); + + return TRUE; + } + + return FALSE; +} + +static int vboxCmdVbvaDdiNotifyComplete(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, volatile UINT *pu32FenceId, DXGK_INTERRUPT_TYPE enmComplType) +{ + VBOXCMDVBVA_NOTIFYCOMPLETED_CB Data; + Data.pDevExt = pDevExt; + Data.pVbva = pVbva; + Data.pu32FenceId = pu32FenceId; + Data.enmComplType = enmComplType; + BOOLEAN bDummy; + NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution( + pDevExt->u.primary.DxgkInterface.DeviceHandle, + vboxCmdVbvaDdiNotifyCompleteCb, + &Data, + 0, /* IN ULONG MessageNumber */ + &bDummy); + if (!NT_SUCCESS(Status)) + { + WARN(("DxgkCbSynchronizeExecution failed Status %#x", Status)); + return VERR_GENERAL_FAILURE; + } + return Status; +} + +static int vboxCmdVbvaFlush(PVBOXMP_DEVEXT pDevExt, HGSMIGUESTCOMMANDCONTEXT *pCtx, bool fBufferOverflow) +{ + /* Issue the flush command. */ + VBVACMDVBVAFLUSH *pFlush = (VBVACMDVBVAFLUSH*)VBoxHGSMIBufferAlloc(pCtx, + sizeof (VBVACMDVBVAFLUSH), + HGSMI_CH_VBVA, + VBVA_CMDVBVA_FLUSH); + if (!pFlush) + { + WARN(("VBoxHGSMIBufferAlloc failed\n")); + return VERR_OUT_OF_RESOURCES; + } + + pFlush->u32Flags = fBufferOverflow ? VBVACMDVBVAFLUSH_F_GUEST_BUFFER_OVERFLOW : 0; + + VBoxHGSMIBufferSubmit(pCtx, pFlush); + + VBoxHGSMIBufferFree(pCtx, pFlush); + + return VINF_SUCCESS; +} + +typedef struct VBOXCMDVBVA_CHECK_COMPLETED_CB +{ + PVBOXMP_DEVEXT pDevExt; + VBOXCMDVBVA *pVbva; + uint32_t u32FenceID; +} VBOXCMDVBVA_CHECK_COMPLETED_CB; + +static BOOLEAN vboxCmdVbvaCheckCompletedIrqCb(PVOID pContext) +{ + VBOXCMDVBVA_CHECK_COMPLETED_CB *pCompleted = (VBOXCMDVBVA_CHECK_COMPLETED_CB*)pContext; + BOOLEAN bRc = DxgkDdiInterruptRoutineNew(pCompleted->pDevExt, 0); + if (pCompleted->pVbva) + pCompleted->u32FenceID = pCompleted->pVbva->u32FenceCompleted; + return bRc; +} + + +static uint32_t vboxCmdVbvaCheckCompleted(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, bool fPingHost, HGSMIGUESTCOMMANDCONTEXT *pCtx, bool fBufferOverflow) +{ + if (fPingHost) + vboxCmdVbvaFlush(pDevExt, pCtx, fBufferOverflow); + + VBOXCMDVBVA_CHECK_COMPLETED_CB context; + context.pDevExt = pDevExt; + context.pVbva = pVbva; + context.u32FenceID = 0; + BOOLEAN bRet; + NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution( + pDevExt->u.primary.DxgkInterface.DeviceHandle, + vboxCmdVbvaCheckCompletedIrqCb, + &context, + 0, /* IN ULONG MessageNumber */ + &bRet); + Assert(Status == STATUS_SUCCESS); + + return context.u32FenceID; +} + +DECLCALLBACK(void) voxCmdVbvaFlushCb(struct VBVAEXBUFFERCONTEXT *pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, void *pvFlush) +{ + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvFlush; + + vboxCmdVbvaCheckCompleted(pDevExt, NULL, true /*fPingHost*/, pHGSMICtx, true /*fBufferOverflow*/); +} + +int VBoxCmdVbvaCreate(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, ULONG offBuffer, ULONG cbBuffer) +{ + memset(pVbva, 0, sizeof (*pVbva)); + + int rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), + (void**)&pVbva->Vbva.pVBVA, + offBuffer, + cbBuffer); + if (RT_SUCCESS(rc)) + { + Assert(pVbva->Vbva.pVBVA); + VBoxVBVAExSetupBufferContext(&pVbva->Vbva, offBuffer, cbBuffer, voxCmdVbvaFlushCb, pDevExt); + } + else + { + WARN(("VBoxMPCmnMapAdapterMemory failed rc %d", rc)); + } + + return rc; +} + +int VBoxCmdVbvaSubmit(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, struct VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd) +{ + int rc = VINF_SUCCESS; + + pCmd->u8State = VBOXCMDVBVA_STATE_SUBMITTED; + pVbva->u32FenceSubmitted = pCmd->u32FenceID; + + if (VBoxVBVAExGetSize(&pVbva->Vbva) > cbCmd) + { + WARN(("buffer does not fit the vbva buffer, we do not support splitting buffers")); + return VERR_NOT_SUPPORTED; + } + + if (!VBoxVBVAExBufferBeginUpdate(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx)) + { + WARN(("VBoxVBVAExBufferBeginUpdate failed!")); + return VERR_GENERAL_FAILURE; + } + + void* pvBuffer = VBoxVBVAExAllocContiguous(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, cbCmd); + if (!pvBuffer) + { + WARN(("failed to allocate contiguous buffer, trying nopping the tail")); + uint32_t cbTail = VBoxVBVAExGetFreeTail(&pVbva->Vbva); + if (!cbTail) + { + WARN(("this is not a free tail case, cbTail is NULL")); + return VERR_BUFFER_OVERFLOW; + } + + Assert(cbTail < cbCmd); + + pvBuffer = VBoxVBVAExAllocContiguous(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, cbTail); + + Assert(pvBuffer); + + *((uint8_t*)pvBuffer) = VBOXCMDVBVA_OPTYPE_NOP; + + VBoxVBVAExBufferEndUpdate(&pVbva->Vbva); + + if (!VBoxVBVAExBufferBeginUpdate(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx)) + { + WARN(("VBoxVBVAExBufferBeginUpdate 2 failed!")); + return VERR_GENERAL_FAILURE; + } + + pvBuffer = VBoxVBVAExAllocContiguous(&pVbva->Vbva, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, cbCmd); + if (!pvBuffer) + { + WARN(("failed to allocate contiguous buffer, failing")); + return VERR_GENERAL_FAILURE; + } + } + + Assert(pvBuffer); + + memcpy(pvBuffer, pCmd, cbCmd); + + VBoxVBVAExBufferEndUpdate(&pVbva->Vbva); + + if (!VBoxVBVAExIsProcessing(&pVbva->Vbva)) + { + /* Issue the submit command. */ + HGSMIGUESTCOMMANDCONTEXT *pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx; + VBVACMDVBVASUBMIT *pSubmit = (VBVACMDVBVASUBMIT*)VBoxHGSMIBufferAlloc(pCtx, + sizeof (VBVACMDVBVASUBMIT), + HGSMI_CH_VBVA, + VBVA_CMDVBVA_SUBMIT); + if (!pSubmit) + { + WARN(("VBoxHGSMIBufferAlloc failed\n")); + return VERR_OUT_OF_RESOURCES; + } + + pSubmit->u32Reserved = 0; + + VBoxHGSMIBufferSubmit(pCtx, pSubmit); + + VBoxHGSMIBufferFree(pCtx, pSubmit); + } + + return VINF_SUCCESS; +} + +bool VBoxCmdVbvaPreempt(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, uint32_t u32FenceID) +{ + VBVAEXBUFFERBACKWARDITER Iter; + VBoxVBVAExBIterInit(&pVbva->Vbva, &Iter); + + uint32_t cbBuffer; + bool fProcessed; + uint8_t* pu8Cmd; + + while ((pu8Cmd = (uint8_t*)VBoxVBVAExBIterNext(&Iter, &cbBuffer, &fProcessed)) != NULL) + { + if (*pu8Cmd == VBOXCMDVBVA_OPTYPE_NOP) + continue; + + VBOXCMDVBVA_HDR *pCmd = (VBOXCMDVBVA_HDR*)pu8Cmd; + + if (pCmd->u32FenceID != u32FenceID) + continue; + + if (!ASMAtomicCmpXchgU8(&pCmd->u8State, VBOXCMDVBVA_STATE_CANCELLED, VBOXCMDVBVA_STATE_SUBMITTED)) + { + Assert(pCmd->u8State == VBOXCMDVBVA_STATE_IN_PROGRESS); + break; + } + + /* we have canceled the command successfully */ + vboxCmdVbvaDdiNotifyComplete(pDevExt, pVbva, &pCmd->u32FenceID, DXGK_INTERRUPT_DMA_PREEMPTED); + return true; + } + + return false; +} + +bool VBoxCmdVbvaCheckCompletedIrq(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva) +{ + VBVAEXBUFFERFORWARDITER Iter; + VBoxVBVAExCFIterInit(&pVbva->Vbva, &Iter); + + bool fHasCommandsCompletedPreempted = false; + bool fProcessed; + uint8_t* pu8Cmd; + + + while ((pu8Cmd = (uint8_t*)VBoxVBVAExCFIterNext(&Iter, NULL, &fProcessed)) != NULL) + { + if (!fProcessed) + break; + + if (*pu8Cmd == VBOXCMDVBVA_OPTYPE_NOP) + continue; + + VBOXCMDVBVA_HDR *pCmd = (VBOXCMDVBVA_HDR*)pu8Cmd; + uint8_t u8State = pCmd->u8State; + uint32_t u32FenceID = pCmd->u32FenceID; + + Assert(u8State == VBOXCMDVBVA_STATE_IN_PROGRESS + || u8State == VBOXCMDVBVA_STATE_CANCELLED); + Assert(u32FenceID); + VBoxVBVAExCBufferCompleted(&pVbva->Vbva); + DXGK_INTERRUPT_TYPE enmDdiNotify; + + if (u8State == VBOXCMDVBVA_STATE_IN_PROGRESS) + { + if (u32FenceID) + pVbva->u32FenceCompleted = u32FenceID; + enmDdiNotify = DXGK_INTERRUPT_DMA_COMPLETED; + } + else + { + Assert(u8State == VBOXCMDVBVA_STATE_CANCELLED); + enmDdiNotify = DXGK_INTERRUPT_DMA_PREEMPTED; + /* to prevent concurrent notifications from DdiPreemptCommand */ + pCmd->u32FenceID = 0; + } + + if (u32FenceID) + vboxCmdVbvaDdiNotifyCompleteIrq(pDevExt, pVbva, u32FenceID, enmDdiNotify); + + fHasCommandsCompletedPreempted = true; + } + + return fHasCommandsCompletedPreempted; +} + +uint32_t VBoxCmdVbvaCheckCompleted(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, bool fPingHost) +{ + return vboxCmdVbvaCheckCompleted(pDevExt, pVbva, fPingHost, &VBoxCommonFromDeviceExt(pDevExt)->guestCtx, false /* fBufferOverflow */); +} + + +static uint32_t vboxCVDdiSysMemElBuild(VBOXCMDVBVA_SYSMEMEL *pEl, PMDL pMdl, uint32_t iPfn, uint32_t cPages) +{ + PFN_NUMBER cur = MmGetMdlPfnArray(pMdl)[iPfn]; + uint32_t cbEl = sizeof (*pEl); + uint32_t cStoredPages = 1; + PFN_NUMBER next; + pEl->iPage1 = (uint32_t)(cur & 0xfffff); + pEl->iPage2 = (uint32_t)(cur >> 20); + --cPages; + for ( ; cPages && cStoredPages < VBOXCMDVBVA_SYSMEMEL_CPAGES_MAX; --cPages, ++cStoredPages, cur = next) + { + next = MmGetMdlPfnArray(pMdl)[iPfn+cStoredPages]; + if (next != cur+1) + break; + } + + Assert(cStoredPages); + pEl->cPagesAfterFirst = cStoredPages - 1; + + return cPages; +} + +uint32_t VBoxCVDdiPTransferVRamSysBuildEls(VBOXCMDVBVA_PAGING_TRANSFER *pCmd, PMDL pMdl, uint32_t iPfn, uint32_t cPages, uint32_t cbBuffer, uint32_t *pcPagesWritten) +{ + uint32_t cInitPages = cPages; + uint32_t cbInitBuffer = cbBuffer; + uint32_t cEls = 0; + VBOXCMDVBVA_SYSMEMEL *pEl = pCmd->aSysMem; + + if (cbBuffer < sizeof (VBOXCMDVBVA_PAGING_TRANSFER)) + { + WARN(("cbBuffer < sizeof (VBOXCMDVBVA_PAGING_TRANSFER)")); + goto done; + } + + cbBuffer -= RT_OFFSETOF(VBOXCMDVBVA_PAGING_TRANSFER, aSysMem); + uint32_t i = 0; + + for (; cPages && cbBuffer >= sizeof (VBOXCMDVBVA_PAGING_TRANSFER); ++cEls, cbBuffer-=sizeof (VBOXCMDVBVA_SYSMEMEL), ++pEl, ++i) + { + cPages = vboxCVDdiSysMemElBuild(pEl, pMdl, iPfn + cInitPages - cPages, cPages); + } + + pCmd->cSysMem = i; + +done: + *pcPagesWritten = cInitPages - cPages; + return cbInitBuffer - cbBuffer; +} + diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h index 90b2a911..46bb2459 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVbva.h @@ -21,11 +21,7 @@ typedef struct VBOXVBVAINFO { - VBOXVIDEOOFFSET offVBVA; - uint32_t cbVBVA; - VBVABUFFER *pVBVA; - BOOL fHwBufferOverflow; - VBVARECORD *pRecord; + VBVABUFFERCONTEXT Vbva; D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId; KSPIN_LOCK Lock; } VBOXVBVAINFO; @@ -34,17 +30,14 @@ int vboxVbvaEnable(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva); int vboxVbvaDisable(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva); int vboxVbvaDestroy(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva); int vboxVbvaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, ULONG offBuffer, ULONG cbBuffer, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId); -int vboxVbvaReportCmdOffset(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva, uint32_t offCmd); int vboxVbvaReportDirtyRect(PVBOXMP_DEVEXT pDevExt, struct VBOXWDDM_SOURCE *pSrc, RECT *pRectOrig); -BOOL vboxVbvaBufferBeginUpdate(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva); -void vboxVbvaBufferEndUpdate(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva); #define VBOXVBVA_OP(_op, _pdext, _psrc, _arg) \ do { \ - if (vboxVbvaBufferBeginUpdate(_pdext, &(_psrc)->Vbva)) \ + if (VBoxVBVABufferBeginUpdate(&(_psrc)->Vbva.Vbva, &VBoxCommonFromDeviceExt(_pdext)->guestCtx)) \ { \ vboxVbva##_op(_pdext, _psrc, _arg); \ - vboxVbvaBufferEndUpdate(_pdext, &(_psrc)->Vbva); \ + VBoxVBVABufferEndUpdate(&(_psrc)->Vbva.Vbva); \ } \ } while (0) @@ -65,4 +58,169 @@ void vboxVbvaBufferEndUpdate(PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva); } while (0) +/* customized VBVA implementation */ +struct VBVAEXBUFFERCONTEXT; + +typedef DECLCALLBACKPTR(void, PFNVBVAEXBUFFERFLUSH) (struct VBVAEXBUFFERCONTEXT *pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, void *pvFlush); + +/** + * Structure grouping the context needed for sending graphics acceleration + * information to the host via VBVA. Each screen has its own VBVA buffer. + */ +typedef struct VBVAEXBUFFERCONTEXT +{ + /** Offset of the buffer in the VRAM section for the screen */ + uint32_t offVRAMBuffer; + /** Length of the buffer in bytes */ + uint32_t cbBuffer; + /** This flag is set if we wrote to the buffer faster than the host could + * read it. */ + bool fHwBufferOverflow; + /* the window between indexRecordFirstUncompleted and pVBVA->::indexRecordFirst represents + * command records processed by the host, but not completed by the guest yet */ + volatile uint32_t indexRecordFirstUncompleted; + /* the window between off32DataUncompleted and pVBVA->::off32Data represents + * command data processed by the host, but not completed by the guest yet */ + uint32_t off32DataUncompleted; + /* flush function */ + PFNVBVAEXBUFFERFLUSH pfnFlush; + void *pvFlush; + /** The VBVA record that we are currently preparing for the host, NULL if + * none. */ + struct VBVARECORD *pRecord; + /** Pointer to the VBVA buffer mapped into the current address space. Will + * be NULL if VBVA is not enabled. */ + struct VBVABUFFER *pVBVA; +} VBVAEXBUFFERCONTEXT, *PVBVAEXBUFFERCONTEXT; + +typedef struct VBVAEXBUFFERITERBASE +{ + struct VBVAEXBUFFERCONTEXT *pCtx; + /* index of the current record */ + uint32_t iCurRecord; + /* offset of the current command */ + uint32_t off32CurCmd; +} VBVAEXBUFFERITERBASE, *PVBVAEXBUFFERITERBASE; + +typedef struct VBVAEXBUFFERFORWARDITER +{ + VBVAEXBUFFERITERBASE Base; +} VBVAEXBUFFERFORWARDITER, *PVBVAEXBUFFERFORWARDITER; + +typedef struct VBVAEXBUFFERBACKWARDITER +{ + VBVAEXBUFFERITERBASE Base; +} VBVAEXBUFFERBACKWARDITER, *PVBVAEXBUFFERBACKWARDITER; + +#define VBOXCMDVBVA_BUFFERSIZE(_cbCmdApprox) (RT_OFFSETOF(VBVABUFFER, au8Data) + ((RT_SIZEOFMEMB(VBVABUFFER, aRecords)/RT_SIZEOFMEMB(VBVABUFFER, aRecords[0])) * (_cbCmdApprox))) + +typedef struct VBOXCMDVBVA +{ + VBVAEXBUFFERCONTEXT Vbva; + + /* last completted fence id */ + uint32_t u32FenceCompleted; + /* last submitted fence id */ + uint32_t u32FenceSubmitted; + + /* node ordinal */ + uint32_t idNode; +} VBOXCMDVBVA; + +/** @name VBVAEx APIs + * @{ */ +RTDECL(int) VBoxVBVAExEnable(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + struct VBVABUFFER *pVBVA); +RTDECL(void) VBoxVBVAExDisable(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx); +RTDECL(bool) VBoxVBVAExBufferBeginUpdate(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx); +RTDECL(void) VBoxVBVAExBufferEndUpdate(PVBVAEXBUFFERCONTEXT pCtx); +RTDECL(bool) VBoxVBVAExWrite(PVBVAEXBUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + const void *pv, uint32_t cb); + +RTDECL(bool) VBoxVBVAExOrderSupported(PVBVAEXBUFFERCONTEXT pCtx, unsigned code); + +RTDECL(void) VBoxVBVAExSetupBufferContext(PVBVAEXBUFFERCONTEXT pCtx, + uint32_t offVRAMBuffer, + uint32_t cbBuffer, + PFNVBVAEXBUFFERFLUSH pfnFlush, + void *pvFlush); + +DECLINLINE(uint32_t) VBoxVBVAExGetSize(PVBVAEXBUFFERCONTEXT pCtx) +{ + return pCtx->pVBVA->cbData; +} + +/* can be used to ensure the command will not cross the ring buffer boundary, + * and thus will not be splitted */ +RTDECL(uint32_t) VBoxVBVAExGetFreeTail(PVBVAEXBUFFERCONTEXT pCtx); +/* allocates a contiguous buffer of a given size, i.e. the one that is not splitted across ringbuffer boundaries */ +RTDECL(void*) VBoxVBVAExAllocContiguous(PVBVAEXBUFFERCONTEXT pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, uint32_t cb); +/* answers whether host is in "processing" state now, + * i.e. if "processing" is true after the command is submitted, no notification is required to be posted to host to make the commandbe processed, + * otherwise, host should be notified about the command */ +RTDECL(bool) VBoxVBVAExIsProcessing(PVBVAEXBUFFERCONTEXT pCtx); + +/* initializes iterator that starts with free record, + * i.e. VBoxVBVAExIterNext would return the first uncompleted record. + * + * can be used by submitter only */ +RTDECL(void) VBoxVBVAExBIterInit(PVBVAEXBUFFERCONTEXT pCtx, PVBVAEXBUFFERBACKWARDITER pIter); +/* can be used by submitter only */ +RTDECL(void*) VBoxVBVAExBIterNext(PVBVAEXBUFFERBACKWARDITER pIter, uint32_t *pcbBuffer, bool *pfProcessed); + +/* completer functions + * completer can only use below ones, and submitter is NOT allowed to use them. + * Completter functions are prefixed with VBoxVBVAExC as opposed to submitter ones, + * that do not have the last "C" in the prefix */ +/* initializes iterator that starts with completed record, + * i.e. VBoxVBVAExIterPrev would return the first uncompleted record. + * note that we can not have iterator that starts at processed record + * (i.e. the one processed by host, but not completed by guest, since host modifies + * VBVABUFFER::off32Data and VBVABUFFER::indexRecordFirst concurrently, + * and so we may end up with inconsistent index-offData pair + * + * can be used by completter only */ +RTDECL(void) VBoxVBVAExCFIterInit(PVBVAEXBUFFERCONTEXT pCtx, PVBVAEXBUFFERFORWARDITER pIter); +/* can be used by completter only */ +RTDECL(void*) VBoxVBVAExCFIterNext(PVBVAEXBUFFERFORWARDITER pIter, uint32_t *pcbBuffer, bool *pfProcessed); + +RTDECL(void) VBoxVBVAExCBufferCompleted(PVBVAEXBUFFERCONTEXT pCtx); + +/** @} */ + +struct VBOXCMDVBVA_HDR; + +int VBoxCmdVbvaEnable(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva); +int VBoxCmdVbvaDisable(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva); +int VBoxCmdVbvaDestroy(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva); +int VBoxCmdVbvaCreate(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, ULONG offBuffer, ULONG cbBuffer); +int VBoxCmdVbvaSubmit(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, struct VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd); +bool VBoxCmdVbvaPreempt(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, uint32_t u32FenceID); +uint32_t VBoxCmdVbvaCheckCompleted(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, bool fPingHost); +bool VBoxCmdVbvaCheckCompletedIrq(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva); + +/*helper functions for filling vbva commands */ +DECLINLINE(void) VBoxCVDdiPackRect(VBOXCMDVBVA_RECT *pVbvaRect, const RECT *pRect) +{ + pVbvaRect->xLeft = (int16_t)pRect->left; + pVbvaRect->yTop = (int16_t)pRect->top; + pVbvaRect->xRight = (int16_t)pRect->right; + pVbvaRect->yBottom = (int16_t)pRect->bottom; +} + +DECLINLINE(void) VBoxCVDdiPackRects(VBOXCMDVBVA_RECT *paVbvaRects, const RECT *paRects, uint32_t cRects) +{ + for (uint32_t i = 0; i < cRects; ++i) + { + VBoxCVDdiPackRect(&paVbvaRects[i], &paRects[i]); + } + +} + +uint32_t VBoxCVDdiPTransferVRamSysBuildEls(VBOXCMDVBVA_PAGING_TRANSFER *pCmd, PMDL pMdl, uint32_t iPfn, uint32_t cPages, uint32_t cbBuffer, uint32_t *pcPagesWritten); + #endif /* #ifndef ___VBoxMPVbva_h___ */ diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.cpp index 373a8fcf..0036147e 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,6 +21,9 @@ #include "VBoxMPVdma.h" #include "VBoxMPVhwa.h" #include <iprt/asm.h> +#include "VBoxMPCr.h" + +# include <packer.h> NTSTATUS vboxVdmaPipeConstruct(PVBOXVDMAPIPE pPipe) { @@ -212,106 +215,7 @@ NTSTATUS vboxVdmaPipeCltCmdPut(PVBOXVDMAPIPE pPipe, PVBOXVDMAPIPE_CMD_HDR pCmd) return Status; } -PVBOXVDMAPIPE_CMD_DR vboxVdmaGgCmdCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_TYPE enmType, uint32_t cbCmd) -{ - PVBOXVDMAPIPE_CMD_DR pHdr; -#ifdef VBOX_WDDM_IRQ_COMPLETION - if (enmType == VBOXVDMAPIPE_CMD_TYPE_DMACMD) - { - UINT cbAlloc = VBOXVDMACMD_SIZE_FROMBODYSIZE(cbCmd); - VBOXVDMACBUF_DR* pDr = vboxVdmaCBufDrCreate(&pDevExt->u.primary.Vdma, cbAlloc); - if (!pDr) - { - WARN(("dr allocation failed")); - return NULL; - } - pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR; - pDr->cbBuf = VBOXVDMACMD_HEADER_SIZE(); - pDr->rc = VINF_SUCCESS; - - - PVBOXVDMACMD pDmaHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); - pDmaHdr->enmType = VBOXVDMACMD_TYPE_DMA_NOP; - pDmaHdr->u32CmdSpecific = 0; - - pHdr = VBOXVDMACMD_BODY(pDmaHdr, VBOXVDMAPIPE_CMD_DR); - } - else -#endif - { - pHdr = (PVBOXVDMAPIPE_CMD_DR)vboxWddmMemAllocZero(cbCmd); - if (!pHdr) - { - WARN(("cmd allocation failed")); - return NULL; - } - } - pHdr->enmType = enmType; - pHdr->cRefs = 1; - return pHdr; -} - -#ifdef VBOX_WDDM_IRQ_COMPLETION -DECLINLINE(VBOXVDMACBUF_DR*) vboxVdmaGgCmdDmaGetDr(PVBOXVDMAPIPE_CMD_DMACMD pDr) -{ - VBOXVDMACMD* pDmaCmd = VBOXVDMACMD_FROM_BODY(pDr); - VBOXVDMACBUF_DR* pDmaDr = VBOXVDMACBUF_DR_FROM_TAIL(pDmaCmd); - return pDmaDr; -} - -DECLINLINE(PVBOXVDMADDI_CMD) vboxVdmaGgCmdDmaGetDdiCmd(PVBOXVDMAPIPE_CMD_DMACMD pDr) -{ - VBOXVDMACBUF_DR* pDmaDr = vboxVdmaGgCmdDmaGetDr(pDr); - return VBOXVDMADDI_CMD_FROM_BUF_DR(pDmaDr); -} - -#endif - -void vboxVdmaGgCmdDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pDr) -{ -#ifdef VBOX_WDDM_IRQ_COMPLETION - if (pDr->enmType == VBOXVDMAPIPE_CMD_TYPE_DMACMD) - { - VBOXVDMACBUF_DR* pDmaDr = vboxVdmaGgCmdDmaGetDr((PVBOXVDMAPIPE_CMD_DMACMD)pDr); - vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDmaDr); - return; - } -#endif - vboxWddmMemFree(pDr); -} - -DECLCALLBACK(VOID) vboxVdmaGgDdiCmdRelease(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext) -{ - vboxVdmaGgCmdRelease(pDevExt, (PVBOXVDMAPIPE_CMD_DR)pvContext); -} - -/** - * helper function used for system thread creation - */ -static NTSTATUS vboxVdmaGgThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext) -{ - NTSTATUS fStatus; - HANDLE hThread; - OBJECT_ATTRIBUTES fObjectAttributes; - - Assert(KeGetCurrentIrql() == PASSIVE_LEVEL); - - InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE, - NULL, NULL); - - fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, - &fObjectAttributes, NULL, NULL, - (PKSTART_ROUTINE) pStartRoutine, pStartContext); - if (!NT_SUCCESS(fStatus)) - return fStatus; - - ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL, - KernelMode, (PVOID*) ppThread, NULL); - ZwClose(hThread); - return STATUS_SUCCESS; -} - -DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const PVBOXWDDM_RECTS_INFO pRects, PVBOXWDDM_RECTS_INFO pResult) +DECLINLINE(void) vboxVdmaDirtyRectsCalcIntersection(const RECT *pArea, const VBOXWDDM_RECTS_INFO *pRects, PVBOXWDDM_RECTS_INFO pResult) { uint32_t cRects = 0; for (uint32_t i = 0; i < pRects->cRects; ++i) @@ -379,20 +283,196 @@ NTSTATUS vboxVdmaPostHideSwapchain(PVBOXWDDM_SWAPCHAIN pSwapchain) return STATUS_NO_MEMORY; } +static VOID vboxWddmBltPipeRectsTranslate(VBOXVDMAPIPE_RECTS *pRects, int x, int y) +{ + vboxWddmRectTranslate(&pRects->ContextRect, x, y); + + for (UINT i = 0; i < pRects->UpdateRects.cRects; ++i) + { + vboxWddmRectTranslate(&pRects->UpdateRects.aRects[i], x, y); + } +} + +static VBOXVDMAPIPE_RECTS * vboxWddmBltPipeRectsDup(const VBOXVDMAPIPE_RECTS *pRects) +{ + const size_t cbDup = RT_OFFSETOF(VBOXVDMAPIPE_RECTS, UpdateRects.aRects[pRects->UpdateRects.cRects]); + VBOXVDMAPIPE_RECTS *pDup = (VBOXVDMAPIPE_RECTS*)vboxWddmMemAllocZero(cbDup); + if (!pDup) + { + WARN(("vboxWddmMemAllocZero failed")); + return NULL; + } + memcpy(pDup, pRects, cbDup); + return pDup; +} + +typedef struct VBOXMP_VDMACR_WRITECOMPLETION +{ + void *pvBufferToFree; +} VBOXMP_VDMACR_WRITECOMPLETION, *PVBOXMP_VDMACR_WRITECOMPLETION; + +static DECLCALLBACK(void) vboxVdmaCrWriteCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvCtx) +{ + PVBOXMP_VDMACR_WRITECOMPLETION pData = (PVBOXMP_VDMACR_WRITECOMPLETION)pvCtx; + void* pvBufferToFree = pData->pvBufferToFree; + if (pvBufferToFree) + VBoxMpCrShgsmiTransportBufFree(pCon, pvBufferToFree); + + VBoxMpCrShgsmiTransportCmdTermWriteAsync(pCon, pvCtx); +} + +typedef struct VBOXMP_VDMACR_WRITEREADCOMPLETION +{ + void *pvBufferToFree; + void *pvContext; +} VBOXMP_VDMACR_WRITEREADCOMPLETION, *PVBOXMP_VDMACR_WRITEREADCOMPLETION; + +void vboxVdmaCrSubmitWriteReadAsyncGenericCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, void *pvCtx) +{ + PVBOXMP_VDMACR_WRITEREADCOMPLETION pData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)pvCtx; + void* pvBufferToFree = pData->pvBufferToFree; + if (pvBufferToFree) + VBoxMpCrShgsmiTransportBufFree(pCon, pvBufferToFree); + + VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(pCon, pvCtx); +} + +NTSTATUS vboxVdmaCrSubmitWriteReadAsync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID, PFNVBOXMP_CRSHGSMITRANSPORT_SENDWRITEREADASYNC_COMPLETION pfnCompletion, void *pvCompletion) +{ + Assert(u32CrConClientID); + NTSTATUS Status = STATUS_SUCCESS; + uint32_t cbBuffer; + void * pvPackBuffer; + void * pvBuffer = VBoxMpCrPackerTxBufferComplete(pCrPacker, &cbBuffer, &pvPackBuffer); + if (pvBuffer) + { + PVBOXMP_VDMACR_WRITEREADCOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)VBoxMpCrShgsmiTransportCmdCreateWriteReadAsync(&pDevExt->CrHgsmiTransport, u32CrConClientID, pvBuffer, cbBuffer, + pfnCompletion, sizeof (*pvCompletionData)); + if (pvCompletionData) + { + pvCompletionData->pvBufferToFree = pvPackBuffer; + pvCompletionData->pvContext = pvCompletion; + int rc = VBoxMpCrShgsmiTransportCmdSubmitWriteReadAsync(&pDevExt->CrHgsmiTransport, pvCompletionData); + if (RT_SUCCESS(rc)) + { + return STATUS_SUCCESS; + } + WARN(("VBoxMpCrShgsmiTransportCmdSubmitWriteAsync failed, rc %d", rc)); + Status = STATUS_UNSUCCESSFUL; + VBoxMpCrShgsmiTransportCmdTermWriteReadAsync(&pDevExt->CrHgsmiTransport, pvCompletionData); + } + else + { + WARN(("VBoxMpCrShgsmiTransportCmdCreateWriteAsync failed")); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + return Status; +} + +NTSTATUS vboxVdmaCrSubmitWriteAsync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID) +{ + Assert(u32CrConClientID); + NTSTATUS Status = STATUS_SUCCESS; + uint32_t cbBuffer; + void * pvPackBuffer; + void * pvBuffer = VBoxMpCrPackerTxBufferComplete(pCrPacker, &cbBuffer, &pvPackBuffer); + if (pvBuffer) + { + PVBOXMP_VDMACR_WRITECOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITECOMPLETION)VBoxMpCrShgsmiTransportCmdCreateWriteAsync(&pDevExt->CrHgsmiTransport, u32CrConClientID, pvBuffer, cbBuffer, + vboxVdmaCrWriteCompletion, sizeof (*pvCompletionData)); + if (pvCompletionData) + { + pvCompletionData->pvBufferToFree = pvPackBuffer; + int rc = VBoxMpCrShgsmiTransportCmdSubmitWriteAsync(&pDevExt->CrHgsmiTransport, pvCompletionData); + if (RT_SUCCESS(rc)) + { + return STATUS_SUCCESS; + } + WARN(("VBoxMpCrShgsmiTransportCmdSubmitWriteAsync failed, rc %d", rc)); + Status = STATUS_UNSUCCESSFUL; + VBoxMpCrShgsmiTransportCmdTermWriteAsync(&pDevExt->CrHgsmiTransport, pvCompletionData); + } + else + { + WARN(("VBoxMpCrShgsmiTransportCmdCreateWriteAsync failed")); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + return Status; +} + +static NTSTATUS vboxVdmaVRegGet(PVBOXWDDM_SWAPCHAIN pSwapchain, const RTRECT *pCtxRect, uint32_t *pcVRects, RTRECT **ppVRectsBuff, uint32_t *pcVRectsBuff) +{ + RTRECT *pVRectsBuff = *ppVRectsBuff; + uint32_t cVRectsBuff = *pcVRectsBuff; + uint32_t cVRects = VBoxVrListRectsCount(&pSwapchain->VisibleRegions); + if (cVRectsBuff < cVRects) + { + if (pVRectsBuff) + vboxWddmMemFree(pVRectsBuff); + pVRectsBuff = (RTRECT*)vboxWddmMemAlloc(cVRects * sizeof (pVRectsBuff[0])); + if (!pVRectsBuff) + { + WARN(("vboxWddmMemAlloc failed")); + *pcVRectsBuff = 0; + *ppVRectsBuff = NULL; + *pcVRects = NULL; + return STATUS_NO_MEMORY; + } + + cVRectsBuff = cVRects; + *pcVRectsBuff = cVRectsBuff; + *ppVRectsBuff = pVRectsBuff; + } + + int rc = VBoxVrListRectsGet(&pSwapchain->VisibleRegions, cVRects, pVRectsBuff); + AssertRC(rc); + if (pCtxRect->xLeft || pCtxRect->yTop) + { + for (UINT i = 0; i < cVRects; ++i) + { + VBoxRectTranslate(&pVRectsBuff[i], -pCtxRect->xLeft, -pCtxRect->yTop); + } + } + + *pcVRects = cVRects; + return STATUS_SUCCESS; +} + + /** * @param pDevExt */ -static NTSTATUS vboxVdmaGgDirtyRectsProcess(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain, RECT *pSrcRect, VBOXVDMAPIPE_RECTS *pContextRects) -{ - PVBOXWDDM_RECTS_INFO pRects = &pContextRects->UpdateRects; +static NTSTATUS vboxVdmaProcessVRegCmdLegacy(PVBOXMP_DEVEXT pDevExt, + VBOXMP_CRPACKER *pCrPacker, + uint32_t u32CrConClientID, + PVBOXWDDM_SOURCE pSource, + PVBOXWDDM_SWAPCHAIN pSwapchain, + const RECT *pSrcRect, + const VBOXVDMAPIPE_RECTS *pContextRects) +{ + VBOXVDMAPIPE_RECTS *pRectsToFree = NULL; + POINT pos = pSource->VScreenPos; + if (pos.x || pos.y) + { + pRectsToFree = vboxWddmBltPipeRectsDup(pContextRects); + /* note: do NOT translate the src rect since it is used for screen pos calculation */ + vboxWddmBltPipeRectsTranslate(pRectsToFree, pos.x, pos.y); + pContextRects = pRectsToFree; + } + const VBOXWDDM_RECTS_INFO *pRects = &pContextRects->UpdateRects; NTSTATUS Status = STATUS_SUCCESS; - PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal = NULL; - uint32_t cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects); - BOOLEAN fCurChanged = FALSE, fCurRectChanged = FALSE; + int rc; + bool fCurChanged = FALSE, fCurRectChanged = FALSE; POINT CurPos; - Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); + RTRECT *pVRectsBuff = NULL; + uint32_t cVRectsBuff = 0; + VBOXWDDM_CTXLOCK_DATA - ExAcquireFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_LOCK(pDevExt); if (pSwapchain) { @@ -403,18 +483,19 @@ static NTSTATUS vboxVdmaGgDirtyRectsProcess(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CO { #if 0 if (pSwapchain->Pos.x != VBOXWDDM_INVALID_COORD) - VBoxWddmVrListTranslate(&pSwapchain->VisibleRegions, pSwapchain->Pos.x - CurPos.x, pSwapchain->Pos.y - CurPos.y); + VBoxVrListTranslate(&pSwapchain->VisibleRegions, pSwapchain->Pos.x - CurPos.x, pSwapchain->Pos.y - CurPos.y); else #endif - VBoxWddmVrListClear(&pSwapchain->VisibleRegions); + VBoxVrListClear(&pSwapchain->VisibleRegions); fCurRectChanged = TRUE; pSwapchain->Pos = CurPos; } - Status = VBoxWddmVrListRectsAdd(&pSwapchain->VisibleRegions, pRects->cRects, pRects->aRects, &fCurChanged); - if (!NT_SUCCESS(Status)) + rc = VBoxVrListRectsAdd(&pSwapchain->VisibleRegions, pRects->cRects, (const RTRECT*)pRects->aRects, &fCurChanged); + if (!RT_SUCCESS(rc)) { - WARN(("VBoxWddmVrListRectsAdd failed!")); + WARN(("VBoxWddmVrListRectsAdd failed, rc %d!", rc)); + Status = STATUS_UNSUCCESSFUL; goto done; } @@ -432,113 +513,140 @@ static NTSTATUS vboxVdmaGgDirtyRectsProcess(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_CO if (pCur != &pSwapchain->DevExtListEntry) { PVBOXWDDM_SWAPCHAIN pCurSwapchain = VBOXWDDMENTRY_2_SWAPCHAIN(pCur); - BOOLEAN fChanged = FALSE; + PVBOXWDDM_CONTEXT pCurContext = pCurSwapchain->pContext; + PVBOXMP_CRPACKER pCurPacker = &pCurContext->CrPacker; + bool fChanged = FALSE; - Status = VBoxWddmVrListRectsSubst(&pCurSwapchain->VisibleRegions, pRects->cRects, pRects->aRects, &fChanged); - if (!NT_SUCCESS(Status)) + rc = VBoxVrListRectsSubst(&pCurSwapchain->VisibleRegions, pRects->cRects, (const RTRECT*)pRects->aRects, &fChanged); + if (!RT_SUCCESS(rc)) { - WARN(("vboxWddmVrListRectsAdd failed!")); + WARN(("VBoxWddmVrListRectsAdd failed, rc %d!", rc)); + Status = STATUS_UNSUCCESSFUL; goto done; } if (!fChanged) continue; - if (!pCmdInternal) + uint32_t cVRects; + RTRECT CurCtxRect; + CurCtxRect.xLeft = pCurSwapchain->Pos.x; + CurCtxRect.yTop = pCurSwapchain->Pos.y; + CurCtxRect.xRight = CurCtxRect.xLeft + pCurSwapchain->width; + CurCtxRect.yBottom = CurCtxRect.yTop + pCurSwapchain->height; + Status = vboxVdmaVRegGet(pCurSwapchain, &CurCtxRect, &cVRects, &pVRectsBuff, &cVRectsBuff); + if (!NT_SUCCESS(Status)) { - pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pCurSwapchain->pContext->CmContext, cbCmdInternal); - if (!pCmdInternal) - { - WARN(("vboxVideoCmCmdCreate failed!")); - Status = STATUS_NO_MEMORY; - goto done; - } + WARN(("vboxVdmaVRegGet Status 0x%x", Status)); + goto done; } - else + + void *pvCommandBuffer = NULL; + uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE; + cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWVISIBLEREGIONS(cVRects); + + pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer); + if (!pvCommandBuffer) { - pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pCurSwapchain->pContext->CmContext); + WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!")); + Status = VERR_OUT_OF_RESOURCES; + goto done; } - pCmdInternal->Cmd.fFlags.Value = 0; - pCmdInternal->Cmd.fFlags.bAddHiddenRects = 1; - memcpy(&pCmdInternal->Cmd.RectsInfo, pRects, RT_OFFSETOF(VBOXWDDM_RECTS_INFO, aRects[pRects->cRects])); + VBoxMpCrPackerTxBufferInit(pCurPacker, pvCommandBuffer, cbCommandBuffer, 1); - pCmdInternal->hSwapchainUm = pCurSwapchain->hSwapchainUm; + Assert(pCurSwapchain->winHostID); + crPackWindowVisibleRegion(&pCurPacker->CrPacker, pCurSwapchain->winHostID, cVRects, (GLint*)pVRectsBuff); - vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pCmdInternal->Cmd.RectsInfo.cRects)); - pCmdInternal = NULL; + Status = vboxVdmaCrSubmitWriteAsync(pDevExt, pCurPacker, pCurContext->u32CrConClientID); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status)); + VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pvCommandBuffer); + } } } if (!pSwapchain) goto done; - RECT *pVisRects; + uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE, cCommands = 0; + + uint32_t cVRects; + Status = vboxVdmaVRegGet(pSwapchain, (const RTRECT *)&pContextRects->ContextRect, &cVRects, &pVRectsBuff, &cVRectsBuff); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaVRegGet Status 0x%x", Status)); + goto done; + } + + ++cCommands; + cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWVISIBLEREGIONS(cVRects); if (fCurRectChanged && fCurChanged) { - cbCmdInternal = VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pRects->cRects + 1); - if (pCmdInternal) - vboxVideoCmCmdRelease(pCmdInternal); - pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmdInternal); - pCmdInternal->Cmd.fFlags.Value = 0; - pCmdInternal->Cmd.fFlags.bSetViewRect = 1; - pCmdInternal->Cmd.fFlags.bAddVisibleRects = 1; - pCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects + 1; - pCmdInternal->Cmd.RectsInfo.aRects[0].left = CurPos.x; - pCmdInternal->Cmd.RectsInfo.aRects[0].top = CurPos.y; - pCmdInternal->Cmd.RectsInfo.aRects[0].right = CurPos.x + pSwapchain->width; - pCmdInternal->Cmd.RectsInfo.aRects[0].bottom = CurPos.y + pSwapchain->height; - pVisRects = &pCmdInternal->Cmd.RectsInfo.aRects[1]; + ++cCommands; + cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWPOSITION; } - else + + if (!pSwapchain->fExposed) { - if (!pCmdInternal) - { - Assert(pContext == pSwapchain->pContext); - pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdCreate(&pContext->CmContext, cbCmdInternal); - if (!pCmdInternal) - { - WARN(("vboxVideoCmCmdCreate failed!")); - Status = STATUS_NO_MEMORY; - goto done; - } - } - else - { - pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)vboxVideoCmCmdReinitForContext(pCmdInternal, &pContext->CmContext); - } + ++cCommands; + cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWSHOW; + ++cCommands; + cbCommandBuffer += VBOXMP_CRCMD_SIZE_WINDOWSIZE; + } - pCmdInternal->Cmd.fFlags.Value = 0; - pCmdInternal->Cmd.fFlags.bAddVisibleRects = 1; - pCmdInternal->Cmd.RectsInfo.cRects = pRects->cRects; - pVisRects = &pCmdInternal->Cmd.RectsInfo.aRects[0]; + void *pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer); + if (!pvCommandBuffer) + { + WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!")); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; } - pCmdInternal->hSwapchainUm = pSwapchain->hSwapchainUm; + VBoxMpCrPackerTxBufferInit(pCrPacker, pvCommandBuffer, cbCommandBuffer, cCommands); + + Assert(pSwapchain->winHostID); + + if (fCurRectChanged && fCurChanged) + crPackWindowPosition(&pCrPacker->CrPacker, pSwapchain->winHostID, CurPos.x, CurPos.y); + + if (!pSwapchain->fExposed) + { + crPackWindowSize(&pCrPacker->CrPacker, pSwapchain->winHostID, pSwapchain->width, pSwapchain->height); + crPackWindowShow(&pCrPacker->CrPacker, pSwapchain->winHostID, TRUE); + pSwapchain->fExposed = TRUE; + } - if (pRects->cRects) - memcpy(pVisRects, pRects->aRects, sizeof (RECT) * pRects->cRects); + crPackWindowVisibleRegion(&pCrPacker->CrPacker, pSwapchain->winHostID, cVRects, (GLint*)pVRectsBuff); - vboxVideoCmCmdSubmit(pCmdInternal, VBOXVIDEOCM_CMD_RECTS_INTERNAL_SIZE4CRECTS(pCmdInternal->Cmd.RectsInfo.cRects)); - pCmdInternal = NULL; + Status = vboxVdmaCrSubmitWriteAsync(pDevExt, pCrPacker, u32CrConClientID); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status)); + VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pvCommandBuffer); + } done: - ExReleaseFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_UNLOCK(pDevExt); - if (pCmdInternal) - vboxVideoCmCmdRelease(pCmdInternal); + if (pRectsToFree) + vboxWddmMemFree(pRectsToFree); + + if (pVRectsBuff) + vboxWddmMemFree(pVRectsBuff); return Status; } -static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF) +static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, VBOXVDMA_CLRFILL *pCF) { NTSTATUS Status = STATUS_UNSUCCESSFUL; Assert (pDevExt->pvVisibleVram); if (pDevExt->pvVisibleVram) { - PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc; + PVBOXWDDM_ALLOCATION pAlloc = pCF->Alloc.pAlloc; Assert(pAlloc->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID); if (pAlloc->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID) { @@ -552,9 +660,9 @@ static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD case 32: { uint8_t bytestPP = bpp >> 3; - for (UINT i = 0; i < pCF->ClrFill.Rects.cRects; ++i) + for (UINT i = 0; i < pCF->Rects.cRects; ++i) { - RECT *pRect = &pCF->ClrFill.Rects.aRects[i]; + RECT *pRect = &pCF->Rects.aRects[i]; for (LONG ir = pRect->top; ir < pRect->bottom; ++ir) { uint32_t * pvU32Mem = (uint32_t*)(pvMem + (ir * pAlloc->AllocData.SurfDesc.pitch) + (pRect->left * bytestPP)); @@ -565,7 +673,7 @@ static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD Assert(pRect->bottom <= (LONG)pAlloc->AllocData.SurfDesc.height); for (UINT j = 0; j < cRaw; ++j) { - *pvU32Mem = pCF->ClrFill.Color; + *pvU32Mem = pCF->Color; ++pvU32Mem; } } @@ -590,7 +698,7 @@ static NTSTATUS vboxVdmaGgDmaColorFill(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD { if (!vboxWddmRectIsEmpty(&UnionRect)) { - PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->ClrFill.Alloc.pAlloc->AllocData.SurfDesc.VidPnSourceId]; + PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pCF->Alloc.pAlloc->AllocData.SurfDesc.VidPnSourceId]; uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled); if (!cUnlockedVBVADisabled) { @@ -736,464 +844,524 @@ static NTSTATUS vboxVdmaGgDmaBlt(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_BLT pBlt) return Status; } -static VOID vboxWddmBltPipeRectsTranslate(VBOXVDMAPIPE_RECTS *pRects, int x, int y) +typedef struct VBOXVDMA_CRRXGENERICSYNC { - vboxWddmRectTranslate(&pRects->ContextRect, x, y); + int rc; + KEVENT Event; +} VBOXVDMA_CRRXGENERICSYNC, *PVBOXVDMA_CRRXGENERICSYNC; - for (UINT i = 0; i < pRects->UpdateRects.cRects; ++i) +static DECLCALLBACK(void) vboxVdmaCrRxGenericSyncCompletion(PVBOXMP_CRSHGSMITRANSPORT pCon, int rc, void *pvRx, uint32_t cbRx, void *pvCtx) +{ + PVBOXMP_VDMACR_WRITEREADCOMPLETION pvCompletionData = (PVBOXMP_VDMACR_WRITEREADCOMPLETION)pvCtx; + PVBOXVDMA_CRRXGENERICSYNC pData = (PVBOXVDMA_CRRXGENERICSYNC)pvCompletionData->pvContext; + if (RT_SUCCESS(rc)) { - vboxWddmRectTranslate(&pRects->UpdateRects.aRects[i], x, y); + rc = VBoxMpCrCmdRxHandler((CRMessageHeader*)pvRx, cbRx); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxMpCrCmdRxHandler failed %d", rc)); + } } + else + { + WARN(("rx failure %d", rc)); + } + + pData->rc = rc; + + KeSetEvent(&pData->Event, 0, FALSE); + + vboxVdmaCrSubmitWriteReadAsyncGenericCompletion(pCon, pvCtx); } -static NTSTATUS vboxVdmaGgDmaCmdProcessFast(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_DMACMD *pDmaCmd) +NTSTATUS vboxVdmaCrRxGenericSync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRPACKER *pCrPacker, uint32_t u32CrConClientID) { - NTSTATUS Status = STATUS_SUCCESS; - PVBOXWDDM_CONTEXT pContext = pDmaCmd->pContext; - DXGK_INTERRUPT_TYPE enmComplType = DXGK_INTERRUPT_DMA_COMPLETED; - switch (pDmaCmd->enmCmd) + VBOXVDMA_CRRXGENERICSYNC Data; + Data.rc = VERR_NOT_SUPPORTED; + KeInitializeEvent(&Data.Event, SynchronizationEvent, FALSE); + NTSTATUS Status = vboxVdmaCrSubmitWriteReadAsync(pDevExt, pCrPacker, u32CrConClientID, vboxVdmaCrRxGenericSyncCompletion, &Data); + if (!NT_SUCCESS(Status)) { - case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT: - { - PVBOXVDMAPIPE_CMD_DMACMD_BLT pBlt = (PVBOXVDMAPIPE_CMD_DMACMD_BLT)pDmaCmd; - PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc; - PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc; + WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status)); + return Status; + } - if (pBlt->Hdr.fFlags.fRealOp) - { - vboxVdmaGgDmaBlt(pDevExt, &pBlt->Blt); + Status = KeWaitForSingleObject(&Data.Event, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */); + if (!NT_SUCCESS(Status)) + { + WARN(("KeWaitForSingleObject failed Status 0x%x", Status)); + return Status; + } - if (VBOXWDDM_IS_FB_ALLOCATION(pDevExt, pDstAlloc) - && pDstAlloc->bVisible) - { - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId]; - Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS); - Assert(pSource->pPrimaryAllocation == pDstAlloc); + return STATUS_SUCCESS; +} - RECT UpdateRect; - UpdateRect = pBlt->Blt.DstRects.UpdateRects.aRects[0]; - for (UINT i = 1; i < pBlt->Blt.DstRects.UpdateRects.cRects; ++i) - { - vboxWddmRectUnite(&UpdateRect, &pBlt->Blt.DstRects.UpdateRects.aRects[i]); - } +typedef struct VBOXMP_CRHGSMIMGR +{ + VBOXMP_CRPACKER CrPacker; + void *pvCommandBuffer; +} VBOXMP_CRHGSMIMGR; - uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled); - if (!cUnlockedVBVADisabled) - { - VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &UpdateRect); - } - else - { - VBOXVBVA_OP_WITHLOCK(ReportDirtyRect, pDevExt, pSource, &UpdateRect); - } - } - } +DECLINLINE(CRPackContext*) vboxVdmaCrHmGetPackContext(VBOXMP_CRHGSMIMGR *pMgr) +{ + return &pMgr->CrPacker.CrPacker; +} - if (pBlt->Hdr.fFlags.fVisibleRegions) - { - Status = STATUS_MORE_PROCESSING_REQUIRED; - vboxWddmAllocationRetain(pDstAlloc); - vboxWddmAllocationRetain(pSrcAlloc); - } - break; - } +NTSTATUS vboxVdmaCrHmCreate(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRHGSMIMGR *pMgr, uint32_t cbCommandBuffer, uint32_t cCommands) +{ + pMgr->pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer); + if (!pMgr->pvCommandBuffer) + { + WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!")); + return VERR_OUT_OF_RESOURCES; + } - case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP: - { - PVBOXVDMAPIPE_CMD_DMACMD_FLIP pFlip = (PVBOXVDMAPIPE_CMD_DMACMD_FLIP)pDmaCmd; - Assert(pFlip->Hdr.fFlags.fVisibleRegions); - Assert(!pFlip->Hdr.fFlags.fRealOp); - PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc; - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId]; - vboxWddmAssignPrimary(pDevExt, pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId); - if (pFlip->Hdr.fFlags.fVisibleRegions) - { - Status = STATUS_MORE_PROCESSING_REQUIRED; - vboxWddmAllocationRetain(pFlip->Flip.Alloc.pAlloc); - } + VBoxMpCrPackerInit(&pMgr->CrPacker); - break; - } - case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL: - { - PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCF = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)pDmaCmd; - Assert(pCF->Hdr.fFlags.fRealOp); - Assert(!pCF->Hdr.fFlags.fVisibleRegions); - Status = vboxVdmaGgDmaColorFill(pDevExt, pCF); - Assert(Status == STATUS_SUCCESS); - break; - } + VBoxMpCrPackerTxBufferInit(&pMgr->CrPacker, pMgr->pvCommandBuffer, cbCommandBuffer, cCommands); - default: - Assert(0); - break; + return STATUS_SUCCESS; +} + +NTSTATUS vboxVdmaCrHmSubmitWrSync(PVBOXMP_DEVEXT pDevExt, VBOXMP_CRHGSMIMGR *pMgr, uint32_t u32CrConClientID) +{ + NTSTATUS Status = vboxVdmaCrRxGenericSync(pDevExt, &pMgr->CrPacker, u32CrConClientID); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrRxGenericSync failed Status 0x%x", Status)); + VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pMgr->pvCommandBuffer); + return Status; + } + + return STATUS_SUCCESS; +} +#if 0 +NTSTATUS vboxVdmaCrCmdGetChromiumParametervCR(PVBOXMP_DEVEXT pDevExt, uint32_t u32CrConClientID, GLenum target, GLuint index, GLenum type, GLsizei count, GLvoid * values) +{ + uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_GETCHROMIUMPARAMETERVCR; + uint32_t cCommands = 1; + + VBOXMP_CRHGSMIMGR Mgr; + NTSTATUS Status = vboxVdmaCrHmCreate(pDevExt, &Mgr, cbCommandBuffer, cCommands); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrHmCreate failed Status 0x%x", Status)); + return Status; } - /* Corresponding Release is done by dma command completion handler */ - vboxVdmaGgCmdAddRef(&pDmaCmd->Hdr); + int dummy = 1; - NTSTATUS tmpStatus = vboxVdmaGgCmdDmaNotifyCompleted(pDevExt, pDmaCmd, enmComplType); - if (!NT_SUCCESS(tmpStatus)) + crPackGetChromiumParametervCR(vboxVdmaCrHmGetPackContext(&Mgr), target, index, type, count, values, &dummy); + + Status = vboxVdmaCrHmSubmitWrSync(pDevExt, &Mgr, u32CrConClientID); + if (!NT_SUCCESS(Status)) { - WARN(("vboxVdmaGgCmdDmaNotifyCompleted failed, Status 0x%x", tmpStatus)); - /* the command was NOT submitted, and thus will not be released, release it here */ - vboxVdmaGgCmdRelease(pDevExt, &pDmaCmd->Hdr); - Status = tmpStatus; + WARN(("vboxVdmaCrHmSubmitWrSync failed Status 0x%x", Status)); + return Status; } - return Status; + return STATUS_SUCCESS; } -static NTSTATUS vboxVdmaGgDmaCmdProcessSlow(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_DMACMD *pDmaCmd) +static NTSTATUS vboxVdmaCrCmdCreateContext(PVBOXMP_DEVEXT pDevExt, int32_t visualBits, int32_t *pi32CtxID) { - NTSTATUS Status = STATUS_SUCCESS; - PVBOXWDDM_CONTEXT pContext = pDmaCmd->pContext; - DXGK_INTERRUPT_TYPE enmComplType = DXGK_INTERRUPT_DMA_COMPLETED; + uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_CREATECONTEXT; + uint32_t cCommands = 1; + + VBOXMP_CRHGSMIMGR Mgr; + NTSTATUS Status = vboxVdmaCrHmCreate(pDevExt, &Mgr, cbCommandBuffer, cCommands); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrHmCreate failed Status 0x%x", Status)); + return Status; + } + + int dummy = 1; - Assert(pDmaCmd->fFlags.Value); - Assert(!pDmaCmd->fFlags.fRealOp); + crPackCreateContext(&CrPacker.CrPacker, "", visualBits, 0, &pi32CtxID, &dummy); - switch (pDmaCmd->enmCmd) + Status = vboxVdmaCrHmSubmitWrSync(pDevExt, &Mgr, u32CrConClientID); + if (!NT_SUCCESS(Status)) { - case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT: - { - PVBOXVDMAPIPE_CMD_DMACMD_BLT pBlt = (PVBOXVDMAPIPE_CMD_DMACMD_BLT)pDmaCmd; - PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc; - PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc; - BOOLEAN bComplete = TRUE; - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId]; - Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS); - - if (pBlt->Hdr.fFlags.fVisibleRegions) - { - PVBOXWDDM_SWAPCHAIN pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pSrcAlloc); - POINT pos = pSource->VScreenPos; - if (pos.x || pos.y) - { - /* note: do NOT translate the src rect since it is used for screen pos calculation */ - vboxWddmBltPipeRectsTranslate(&pBlt->Blt.DstRects, pos.x, pos.y); - } + WARN(("vboxVdmaCrHmSubmitWrSync failed Status 0x%x", Status)); + return Status; + } - Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &pBlt->Blt.SrcRect, &pBlt->Blt.DstRects); - Assert(Status == STATUS_SUCCESS); + return STATUS_SUCCESS; +} - if (pSwapchain) - vboxWddmSwapchainRelease(pSwapchain); - } - else - { - WARN(("not expected!")); - } +static NTSTATUS vboxVdmaCrCmdWindowCreate(PVBOXMP_DEVEXT pDevExt, int32_t visualBits, int32_t *pi32WinID) +{ + uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_WINDOWCREATE; + uint32_t cCommands = 1; - vboxWddmAllocationRelease(pDstAlloc); - vboxWddmAllocationRelease(pSrcAlloc); + VBOXMP_CRHGSMIMGR Mgr; + NTSTATUS Status = vboxVdmaCrHmCreate(pDevExt, &Mgr, cbCommandBuffer, cCommands); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrHmCreate failed Status 0x%x", Status)); + return Status; + } - break; + int dummy = 1; + + crPackWindowCreate(&CrPacker.CrPacker, "", visualBits, 0, &pi32CtxID, &dummy); + + Status = vboxVdmaCrHmSubmitWrSync(pDevExt, &Mgr, u32CrConClientID); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrHmSubmitWrSync failed Status 0x%x", Status)); + return Status; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS vboxVdmaCrCtlGetDefaultCtxId(PVBOXMP_DEVEXT pDevExt, int32_t *pi32CtxID) +{ + if (!pDevExt->i32CrConDefaultCtxID) + { + if (!pDevExt->f3DEnabled) + { + WARN(("3D disabled, should not be here!")); + return STATUS_UNSUCCESSFUL; } - case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP: + uint32_t u32ClienID; + NTSTATUS Status = vboxVdmaCrCtlGetDefaultClientId(pDevExt, &u32ClienID); + if (!NT_SUCCESS(Status)) { - PVBOXVDMAPIPE_CMD_DMACMD_FLIP pFlip = (PVBOXVDMAPIPE_CMD_DMACMD_FLIP)pDmaCmd; - PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc; - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId]; - if (pFlip->Hdr.fFlags.fVisibleRegions) - { - PVBOXWDDM_SWAPCHAIN pSwapchain; - pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pAlloc); - if (pSwapchain) - { - POINT pos = pSource->VScreenPos; - RECT SrcRect; - VBOXVDMAPIPE_RECTS Rects; - SrcRect.left = 0; - SrcRect.top = 0; - SrcRect.right = pAlloc->AllocData.SurfDesc.width; - SrcRect.bottom = pAlloc->AllocData.SurfDesc.height; - Rects.ContextRect.left = pos.x; - Rects.ContextRect.top = pos.y; - Rects.ContextRect.right = pAlloc->AllocData.SurfDesc.width + pos.x; - Rects.ContextRect.bottom = pAlloc->AllocData.SurfDesc.height + pos.y; - Rects.UpdateRects.cRects = 1; - Rects.UpdateRects.aRects[0] = Rects.ContextRect; - Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pContext, pSwapchain, &SrcRect, &Rects); - Assert(Status == STATUS_SUCCESS); - vboxWddmSwapchainRelease(pSwapchain); - } - } - else - { - WARN(("not expected!")); - } + WARN(("vboxVdmaCrCtlGetDefaultClientId failed, Status %#x", Status)); + return Status; + } - vboxWddmAllocationRelease(pAlloc); + Status = vboxVdmaCrCmdWindowCreate(PVBOXMP_DEVEXT pDevExt, int32_t visualBits, int32_t *pi32WinID) - break; - } + VBOXMP_CRPACKER CrPacker; + VBoxMpCrPackerInit(&CrPacker); - default: + int rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pDevExt->u32CrConDefaultClientID); + if (!RT_SUCCESS(rc)) { - WARN(("not expected!")); - break; + WARN(("VBoxMpCrCtlConConnect failed, rc %d", rc)); + return STATUS_UNSUCCESSFUL; } } - vboxVdmaGgCmdRelease(pDevExt, &pDmaCmd->Hdr); + *pi32CtxID = pDevExt->i32CrConDefaultCtxID; + return STATUS_SUCCESS; +} +#endif + +static NTSTATUS vboxVdmaTexPresentSubmit(PVBOXMP_DEVEXT pDevExt, + VBOXMP_CRPACKER *pCrPacker, + uint32_t u32CrConClientID, + uint32_t hostID, + uint32_t cfg, + int32_t posX, + int32_t posY, + uint32_t cRects, + const RTRECT*paRects) +{ + Assert(pDevExt->fTexPresentEnabled); + + uint32_t cbCommandBuffer = VBOXMP_CRCMD_HEADER_SIZE + VBOXMP_CRCMD_SIZE_VBOXTEXPRESENT(cRects); + uint32_t cCommands = 1; + void *pvCommandBuffer = VBoxMpCrShgsmiTransportBufAlloc(&pDevExt->CrHgsmiTransport, cbCommandBuffer); + if (!pvCommandBuffer) + { + WARN(("VBoxMpCrShgsmiTransportBufAlloc failed!")); + return VERR_OUT_OF_RESOURCES; + } + + VBoxMpCrPackerTxBufferInit(pCrPacker, pvCommandBuffer, cbCommandBuffer, cCommands); + + crPackVBoxTexPresent(&pCrPacker->CrPacker, hostID, cfg, posX, posY, cRects, (int32_t*)paRects); + + NTSTATUS Status = vboxVdmaCrSubmitWriteAsync(pDevExt, pCrPacker, u32CrConClientID); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVdmaCrSubmitWriteAsync failed Status 0x%x", Status)); + VBoxMpCrShgsmiTransportBufFree(&pDevExt->CrHgsmiTransport, pvCommandBuffer); + } return Status; } -static DECLCALLBACK(UINT) vboxVdmaGgCmdCancelVisitor(PVBOXVIDEOCM_CTX pContext, PVOID pvCmd, uint32_t cbCmd, PVOID pvVisitor) +static NTSTATUS vboxVdmaCrCtlGetDefaultClientId(PVBOXMP_DEVEXT pDevExt, uint32_t *pu32ClienID) { - PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)pvVisitor; - if (!pSwapchain) - return VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD; - PVBOXVIDEOCM_CMD_RECTS_INTERNAL pCmdInternal = (PVBOXVIDEOCM_CMD_RECTS_INTERNAL)pvCmd; - if (pCmdInternal->hSwapchainUm == pSwapchain->hSwapchainUm) - return VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD; - return 0; + if (!pDevExt->u32CrConDefaultClientID) + { + if (!pDevExt->f3DEnabled) + { + WARN(("3D disabled, should not be here!")); + return STATUS_UNSUCCESSFUL; + } + + int rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pDevExt->u32CrConDefaultClientID); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxMpCrCtlConConnect failed, rc %d", rc)); + return STATUS_UNSUCCESSFUL; + } + } + + *pu32ClienID = pDevExt->u32CrConDefaultClientID; + return STATUS_SUCCESS; } -static VOID vboxVdmaGgWorkerThread(PVOID pvUser) +static NTSTATUS vboxVdmaProcessVReg(PVBOXMP_DEVEXT pDevExt, + VBOXMP_CRPACKER *pCrPacker, + uint32_t u32CrConClientID, + const VBOXWDDM_ALLOCATION *pSrcAlloc, + const VBOXWDDM_ALLOCATION *pDstAlloc, + const RECT *pSrcRect, const VBOXVDMAPIPE_RECTS *pDstRects) { - PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvUser; - PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg; + D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId = pDstAlloc->AllocData.SurfDesc.VidPnSourceId; + VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[srcId]; + NTSTATUS Status = STATUS_SUCCESS; - NTSTATUS Status = vboxVdmaPipeSvrOpen(&pVdma->CmdPipe); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) + if (pDevExt->fTexPresentEnabled) { - do + /* we care only about screen regions */ + if (pDstAlloc != pSource->pPrimaryAllocation) { - LIST_ENTRY CmdList; - Status = vboxVdmaPipeSvrCmdGetList(&pVdma->CmdPipe, &CmdList); - Assert(Status == STATUS_SUCCESS || Status == STATUS_PIPE_CLOSING); - if (Status == STATUS_SUCCESS) + WARN(("non-primary allocation passed to vboxWddmSubmitBltCmd!")); + return STATUS_NOT_SUPPORTED; + } + + uint32_t hostID = pSrcAlloc->AllocData.hostID; + int rc; + if (hostID) + { +// Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D); + int32_t posX = pDstRects->ContextRect.left - pSrcRect->left; + int32_t posY = pDstRects->ContextRect.top - pSrcRect->top; + + Status = vboxVdmaTexPresentSubmit(pDevExt, pCrPacker, u32CrConClientID, hostID, srcId, posX, posY, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects); + if (NT_SUCCESS(Status)) { - for (PLIST_ENTRY pCur = CmdList.Blink; pCur != &CmdList;) + rc = VBoxVrListRectsSubst(&pSource->VrList, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects, NULL); + if (RT_SUCCESS(rc)) + pSource->fHas3DVrs = TRUE; + else + WARN(("VBoxVrListRectsSubst failed rc %d, ignoring..", rc)); + } + else + WARN(("vboxVdmaTexPresentSubmit failed Status 0x%x", Status)); + } + else if (pSource->pPrimaryAllocation == pDstAlloc) + { + bool fChanged = false; + Assert(pSource->pPrimaryAllocation->bVisible); + rc = VBoxVrListRectsAdd(&pSource->VrList, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects, &fChanged); + if (RT_SUCCESS(rc)) + { + if (fChanged) { - PVBOXVDMAPIPE_CMD_DR pDr = VBOXVDMAPIPE_CMD_DR_FROM_ENTRY(pCur); - RemoveEntryList(pCur); - pCur = CmdList.Blink; - switch (pDr->enmType) + Status = vboxVdmaTexPresentSubmit(pDevExt, pCrPacker, u32CrConClientID, hostID, srcId, 0, 0, pDstRects->UpdateRects.cRects, (const RTRECT*)pDstRects->UpdateRects.aRects); + if (NT_SUCCESS(Status)) { - case VBOXVDMAPIPE_CMD_TYPE_DMACMD: - { - PVBOXVDMAPIPE_CMD_DMACMD pDmaCmd = (PVBOXVDMAPIPE_CMD_DMACMD)pDr; - Status = vboxVdmaGgDmaCmdProcessSlow(pDevExt, pDmaCmd); - Assert(Status == STATUS_SUCCESS); - } break; -#if 0 - case VBOXVDMAPIPE_CMD_TYPE_RECTSINFO: + if (pSource->fHas3DVrs) { - PVBOXVDMAPIPE_CMD_RECTSINFO pRects = (PVBOXVDMAPIPE_CMD_RECTSINFO)pDr; - Status = vboxVdmaGgDirtyRectsProcess(pDevExt, pRects->pContext, pRects->pSwapchain, &pRects->ContextsRects); - Assert(Status == STATUS_SUCCESS); - vboxVdmaGgCmdRelease(pDevExt, pDr); - break; - } -#endif - case VBOXVDMAPIPE_CMD_TYPE_FINISH: - { - PVBOXVDMAPIPE_CMD_FINISH pCmd = (PVBOXVDMAPIPE_CMD_FINISH)pDr; - PVBOXWDDM_CONTEXT pContext = pCmd->pContext; - Assert(pCmd->pEvent); - Status = vboxVideoCmCmdSubmitCompleteEvent(&pContext->CmContext, pCmd->pEvent); - if (Status != STATUS_SUCCESS) - { - WARN(("vboxVideoCmCmdWaitCompleted failedm Status (0x%x)", Status)); - } - vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr); - break; - } - case VBOXVDMAPIPE_CMD_TYPE_CANCEL: - { - PVBOXVDMAPIPE_CMD_CANCEL pCmd = (PVBOXVDMAPIPE_CMD_CANCEL)pDr; - PVBOXWDDM_CONTEXT pContext = pCmd->pContext; - Status = vboxVideoCmCmdVisit(&pContext->CmContext, FALSE, vboxVdmaGgCmdCancelVisitor, pCmd->pSwapchain); - if (Status != STATUS_SUCCESS) + if (VBoxVrListRectsCount(&pSource->VrList) == 1) { - WARN(("vboxVideoCmCmdWaitCompleted failedm Status (0x%x)", Status)); + RTRECT Rect; + VBoxVrListRectsGet(&pSource->VrList, 1, &Rect); + if (Rect.xLeft == 0 + && Rect.yTop == 0 + && Rect.xRight == pDstAlloc->AllocData.SurfDesc.width + && Rect.yBottom == pDstAlloc->AllocData.SurfDesc.height) + { + pSource->fHas3DVrs = FALSE; + } } - Assert(pCmd->pEvent); - KeSetEvent(pCmd->pEvent, 0, FALSE); - vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr); - break; } - default: - AssertBreakpoint(); } + else + WARN(("vboxVdmaTexPresentSubmit failed Status 0x%x", Status)); } } else - break; - } while (1); + WARN(("VBoxVrListRectsAdd failed rc %d, ignoring..", rc)); + } + else + { + WARN(("unexpected")); + Status = STATUS_INVALID_PARAMETER; + } } + else + { + PVBOXWDDM_SWAPCHAIN pSwapchain = vboxWddmSwapchainRetainByAlloc(pDevExt, pSrcAlloc); - /* always try to close the pipe to make sure the client side is notified */ - Status = vboxVdmaPipeSvrClose(&pVdma->CmdPipe); - Assert(Status == STATUS_SUCCESS); -} + if (pSwapchain) + { + Assert(pSrcAlloc->AllocData.SurfDesc.width == pSwapchain->width); + Assert(pSrcAlloc->AllocData.SurfDesc.height == pSwapchain->height); + } -NTSTATUS vboxVdmaGgConstruct(PVBOXMP_DEVEXT pDevExt) -{ - PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg; - NTSTATUS Status = vboxVdmaPipeConstruct(&pVdma->CmdPipe); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - { - Status = vboxVdmaGgThreadCreate(&pVdma->pThread, vboxVdmaGgWorkerThread, pDevExt); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - return STATUS_SUCCESS; + Status = vboxVdmaProcessVRegCmdLegacy(pDevExt, pCrPacker, u32CrConClientID, pSource, pSwapchain, pSrcRect, pDstRects); + if (!NT_SUCCESS(Status)) + WARN(("vboxVdmaProcessVRegCmdLegacy failed Status 0x%x", Status)); - NTSTATUS tmpStatus = vboxVdmaPipeDestruct(&pVdma->CmdPipe); - Assert(tmpStatus == STATUS_SUCCESS); + if (pSwapchain) + vboxWddmSwapchainRelease(pSwapchain); } - /* we're here ONLY in case of an error */ - Assert(Status != STATUS_SUCCESS); return Status; } -NTSTATUS vboxVdmaGgDestruct(PVBOXMP_DEVEXT pDevExt) +NTSTATUS vboxVdmaTexPresentSetAlloc(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pRealFbAlloc) { - PVBOXVDMAGG pVdma = &pDevExt->u.primary.Vdma.DmaGg; - /* this informs the server thread that it should complete all current commands and exit */ - NTSTATUS Status = vboxVdmaPipeCltClose(&pVdma->CmdPipe); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) + VBOXMP_CRPACKER CrPacker; + VBoxMpCrPackerInit(&CrPacker); + uint32_t u32CrConClientID; + + NTSTATUS Status = vboxVdmaCrCtlGetDefaultClientId(pDevExt, &u32CrConClientID); + if (!NT_SUCCESS(Status)) { - Status = KeWaitForSingleObject(pVdma->pThread, Executive, KernelMode, FALSE, NULL /* PLARGE_INTEGER Timeout */); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - { - Status = vboxVdmaPipeDestruct(&pVdma->CmdPipe); - Assert(Status == STATUS_SUCCESS); - } + WARN(("vboxVdmaCrCtlGetDefaultClientId failed Status 0x%x", Status)); + return Status; } - return Status; -} + RECT Rect; + Rect.left = 0; + Rect.top = 0; + Rect.right = pRealFbAlloc->AllocData.SurfDesc.width; + Rect.bottom = pRealFbAlloc->AllocData.SurfDesc.height; -NTSTATUS vboxVdmaGgCmdSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pCmd) -{ - switch (pCmd->enmType) - { - case VBOXVDMAPIPE_CMD_TYPE_DMACMD: - { - PVBOXVDMAPIPE_CMD_DMACMD pDmaCmd = (PVBOXVDMAPIPE_CMD_DMACMD)pCmd; - NTSTATUS Status = vboxVdmaGgDmaCmdProcessFast(pDevExt, pDmaCmd); - if (Status == STATUS_MORE_PROCESSING_REQUIRED) - break; - return Status; - } - default: - break; - } - /* correspondinf Release is done by the pipe command handler */ - vboxVdmaGgCmdAddRef(pCmd); - return vboxVdmaPipeCltCmdPut(&pDevExt->u.primary.Vdma.DmaGg.CmdPipe, &pCmd->PipeHdr); + VBOXVDMAPIPE_RECTS RectInfo; + RectInfo.ContextRect = Rect; + RectInfo.UpdateRects.cRects = 1; + RectInfo.UpdateRects.aRects[0] = Rect; + + return vboxVdmaProcessVReg(pDevExt, &CrPacker, u32CrConClientID, + pRealFbAlloc, pRealFbAlloc, + &Rect, &RectInfo); } -NTSTATUS vboxVdmaGgCmdDmaNotifySubmitted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD pCmd) +static NTSTATUS vboxVdmaProcessVRegCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, + const VBOXWDDM_DMA_ALLOCINFO *pSrcAllocInfo, + const VBOXWDDM_DMA_ALLOCINFO *pDstAllocInfo, + const RECT *pSrcRect, const VBOXVDMAPIPE_RECTS *pDstRects) { - PVBOXVDMADDI_CMD pDdiCmd; -#ifdef VBOX_WDDM_IRQ_COMPLETION - pDdiCmd = vboxVdmaGgCmdDmaGetDdiCmd(pCmd); -#else - pDdiCmd = &pCmd->DdiCmd; -#endif - NTSTATUS Status = vboxVdmaDdiCmdSubmitted(pDevExt, pDdiCmd); - Assert(Status == STATUS_SUCCESS); - return Status; + return vboxVdmaProcessVReg(pDevExt, &pContext->CrPacker, pContext->u32CrConClientID, + pSrcAllocInfo->pAlloc, pDstAllocInfo->pAlloc, + pSrcRect, pDstRects); } -NTSTATUS vboxVdmaGgCmdDmaNotifyCompleted(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DMACMD pCmd, DXGK_INTERRUPT_TYPE enmComplType) +static void vboxVdmaBltDirtyRectsUpdate(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_SOURCE *pSource, uint32_t cRects, const RECT *paRects) { -#ifdef VBOX_WDDM_IRQ_COMPLETION - VBOXVDMACBUF_DR* pDr = vboxVdmaGgCmdDmaGetDr(pCmd); - int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr); - Assert(rc == VINF_SUCCESS); - if (RT_SUCCESS(rc)) + if (!cRects) { - return STATUS_SUCCESS; + WARN(("vboxVdmaBltDirtyRectsUpdate: no rects specified")); + return; } - return STATUS_UNSUCCESSFUL; -#else - return vboxVdmaDdiCmdCompleted(pDevExt, &pCmd->DdiCmd, enmComplType); -#endif -} -VOID vboxVdmaGgCmdDmaNotifyInit(PVBOXVDMAPIPE_CMD_DMACMD pCmd, - uint32_t u32NodeOrdinal, uint32_t u32FenceId, - PFNVBOXVDMADDICMDCOMPLETE_DPC pfnComplete, PVOID pvComplete) -{ - PVBOXVDMADDI_CMD pDdiCmd; -#ifdef VBOX_WDDM_IRQ_COMPLETION - pDdiCmd = vboxVdmaGgCmdDmaGetDdiCmd(pCmd); -#else - pDdiCmd = &pCmd->DdiCmd; -#endif - vboxVdmaDdiCmdInit(pDdiCmd, u32NodeOrdinal, u32FenceId, pfnComplete, pvComplete); + RECT rect; + rect = paRects[0]; + for (UINT i = 1; i < cRects; ++i) + { + vboxWddmRectUnited(&rect, &rect, &paRects[i]); + } + + uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled); + if (!cUnlockedVBVADisabled) + { + VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &rect); + } + else + { + VBOXVBVA_OP_WITHLOCK_ATDPC(ReportDirtyRect, pDevExt, pSource, &rect); + } } -NTSTATUS vboxVdmaGgCmdFinish(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, PKEVENT pEvent) +NTSTATUS vboxVdmaProcessBltCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_BLT *pBlt) { NTSTATUS Status = STATUS_SUCCESS; + PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc; + PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc; + BOOLEAN fRenderFromSharedDisabled = pDevExt->fRenderToShadowDisabled; + BOOLEAN fVRAMUpdated = FALSE; - PVBOXVDMAPIPE_CMD_FINISH pCmd = (PVBOXVDMAPIPE_CMD_FINISH)vboxVdmaGgCmdCreate(pDevExt, VBOXVDMAPIPE_CMD_TYPE_FINISH, sizeof (*pCmd)); - if (pCmd) + if (!pDstAlloc->AllocData.hostID && !pSrcAlloc->AllocData.hostID) { - pCmd->pContext = pContext; - pCmd->pEvent = pEvent; - Status = vboxVdmaGgCmdSubmit(pDevExt, &pCmd->Hdr); - if (!NT_SUCCESS(Status)) + /* the allocations contain a real data in VRAM, do blitting */ + vboxVdmaGgDmaBlt(pDevExt, &pBlt->Blt); + fVRAMUpdated = TRUE; + } + + if (VBOXWDDM_IS_REAL_FB_ALLOCATION(pDevExt, pDstAlloc) + && pDstAlloc->bVisible) + { + VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId]; + Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS); + Assert(pSource->pPrimaryAllocation == pDstAlloc); + + + if (fVRAMUpdated) + vboxVdmaBltDirtyRectsUpdate(pDevExt, pSource, pBlt->Blt.DstRects.UpdateRects.cRects, pBlt->Blt.DstRects.UpdateRects.aRects); + + if (pSrcAlloc->AllocData.hostID || (pDevExt->fTexPresentEnabled ? pSource->fHas3DVrs : !!pDevExt->cContexts3D)) { - WARN(("vboxVdmaGgCmdSubmit returned 0x%x", Status)); + Status = vboxVdmaProcessVRegCmd(pDevExt, pContext, &pBlt->Blt.SrcAlloc, &pBlt->Blt.DstAlloc, &pBlt->Blt.SrcRect, &pBlt->Blt.DstRects); + if (!NT_SUCCESS(Status)) + WARN(("vboxVdmaProcessVRegCmd failed Status 0x%x", Status)); } - vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr); } - else + + return Status; +} + +NTSTATUS vboxVdmaProcessFlipCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip) +{ + NTSTATUS Status = STATUS_SUCCESS; + PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc; + VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId]; + vboxWddmAssignPrimary(pDevExt, pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId); + if (pAlloc->AllocData.hostID) { - WARN(("vboxVdmaGgCmdCreate failed")); - Status = STATUS_NO_MEMORY; + RECT SrcRect; + VBOXVDMAPIPE_RECTS Rects; + SrcRect.left = 0; + SrcRect.top = 0; + SrcRect.right = pAlloc->AllocData.SurfDesc.width; + SrcRect.bottom = pAlloc->AllocData.SurfDesc.height; + Rects.ContextRect.left = 0; + Rects.ContextRect.top = 0; + Rects.ContextRect.right = pAlloc->AllocData.SurfDesc.width; + Rects.ContextRect.bottom = pAlloc->AllocData.SurfDesc.height; + Rects.UpdateRects.cRects = 1; + Rects.UpdateRects.aRects[0] = Rects.ContextRect; + + Status = vboxVdmaProcessVRegCmd(pDevExt, pContext, &pFlip->Flip.Alloc, &pFlip->Flip.Alloc, &SrcRect, &Rects); + if (!NT_SUCCESS(Status)) + WARN(("vboxVdmaProcessVRegCmd failed Status 0x%x", Status)); } + else + WARN(("unexpected flip request")); + return Status; } -NTSTATUS vboxVdmaGgCmdCancel(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, PVBOXWDDM_SWAPCHAIN pSwapchain) +NTSTATUS vboxVdmaProcessClrFillCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, VBOXWDDM_DMA_PRIVATEDATA_CLRFILL *pCF) { NTSTATUS Status = STATUS_SUCCESS; + PVBOXWDDM_ALLOCATION pAlloc = pCF->ClrFill.Alloc.pAlloc; - PVBOXVDMAPIPE_CMD_CANCEL pCmd = (PVBOXVDMAPIPE_CMD_CANCEL)vboxVdmaGgCmdCreate(pDevExt, VBOXVDMAPIPE_CMD_TYPE_CANCEL, sizeof (*pCmd)); - if (pCmd) + if (!pAlloc->AllocData.hostID) { - KEVENT Event; - KeInitializeEvent(&Event, NotificationEvent, FALSE); - pCmd->pContext = pContext; - pCmd->pSwapchain = pSwapchain; - pCmd->pEvent = &Event; - Status = vboxVdmaGgCmdSubmit(pDevExt, &pCmd->Hdr); - if (NT_SUCCESS(Status)) - { - Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Assert(Status == STATUS_SUCCESS); - } - else - { - WARN(("vboxVdmaGgCmdSubmit returned 0x%x", Status)); - } - vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr); + Status = vboxVdmaGgDmaColorFill(pDevExt, &pCF->ClrFill); + if (!NT_SUCCESS(Status)) + WARN(("vboxVdmaGgDmaColorFill failed Status 0x%x", Status)); } else - { - WARN(("vboxVdmaGgCmdCreate failed")); - Status = STATUS_NO_MEMORY; - } + WARN(("unexpected clrfill request")); + return Status; } -/* end */ #ifdef VBOX_WITH_VDMA /* @@ -1325,11 +1493,7 @@ int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo if(RT_SUCCESS(rc)) #endif { - NTSTATUS Status = vboxVdmaGgConstruct(pDevExt); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - return VINF_SUCCESS; - rc = VERR_GENERAL_FAILURE; + return VINF_SUCCESS; } #ifdef VBOX_WITH_VDMA else @@ -1345,8 +1509,6 @@ int vboxVdmaCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo) { - LOGF((".")); - Assert(pInfo->fEnabled); if (!pInfo->fEnabled) return VINF_ALREADY_INITIALIZED; @@ -1364,8 +1526,6 @@ int vboxVdmaDisable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo) int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo) { - LOGF((".")); - Assert(!pInfo->fEnabled); if (pInfo->fEnabled) return VINF_ALREADY_INITIALIZED; @@ -1384,8 +1544,6 @@ int vboxVdmaEnable (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo) #ifdef VBOX_WITH_VDMA int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo) { - LOGF((".")); - Assert(pInfo->fEnabled); if (!pInfo->fEnabled) return VINF_ALREADY_INITIALIZED; @@ -1400,20 +1558,13 @@ int vboxVdmaFlush (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo) int vboxVdmaDestroy (PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo) { int rc = VINF_SUCCESS; - NTSTATUS Status = vboxVdmaGgDestruct(pDevExt); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - { - Assert(!pInfo->fEnabled); - if (pInfo->fEnabled) - rc = vboxVdmaDisable (pDevExt, pInfo); + Assert(!pInfo->fEnabled); + if (pInfo->fEnabled) + rc = vboxVdmaDisable (pDevExt, pInfo); #ifdef VBOX_WITH_VDMA - VBoxSHGSMITerm(&pInfo->CmdHeap); - VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.Heap.area.pu8Base); + VBoxSHGSMITerm(&pInfo->CmdHeap); + VBoxMPCmnUnmapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pInfo->CmdHeap.Heap.area.pu8Base); #endif - } - else - rc = VERR_GENERAL_FAILURE; return rc; } diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.h index 653520fd..4b544ac5 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVdma.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -211,19 +211,6 @@ typedef struct VBOXVDMAPIPE_CMD_CANCEL PKEVENT pEvent; } VBOXVDMAPIPE_CMD_CANCEL, *PVBOXVDMAPIPE_CMD_CANCEL; -typedef struct VBOXVDMAPIPE_FLAGS_DMACMD -{ - union - { - struct - { - UINT fRealOp : 1; - UINT fVisibleRegions : 1; - UINT Reserve : 30; - }; - UINT Value; - }; -} VBOXVDMAPIPE_FLAGS_DMACMD, *PVBOXVDMAPIPE_FLAGS_DMACMD; typedef struct VBOXVDMAPIPE_CMD_DMACMD { VBOXVDMAPIPE_CMD_DR Hdr; @@ -232,7 +219,7 @@ typedef struct VBOXVDMAPIPE_CMD_DMACMD #endif PVBOXWDDM_CONTEXT pContext; VBOXVDMACMD_TYPE enmCmd; - VBOXVDMAPIPE_FLAGS_DMACMD fFlags; +// VBOXVDMAPIPE_FLAGS_DMACMD fFlags; } VBOXVDMAPIPE_CMD_DMACMD, *PVBOXVDMAPIPE_CMD_DMACMD; typedef struct VBOXVDMA_CLRFILL @@ -294,8 +281,6 @@ typedef struct VBOXVDMAINFO #endif UINT uLastCompletedPagingBufferCmdFenceId; BOOL fEnabled; - /* dma-related commands list processed on the guest w/o host part involvement (guest-guest commands) */ - VBOXVDMAGG DmaGg; } VBOXVDMAINFO, *PVBOXVDMAINFO; int vboxVdmaCreate (PVBOXMP_DEVEXT pDevExt, VBOXVDMAINFO *pInfo @@ -312,6 +297,10 @@ int vboxVdmaDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo); #ifdef VBOX_WITH_VDMA int vboxVdmaFlush(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo); +DECLINLINE(HGSMIOFFSET) vboxVdmaCBufDrPtrOffset(const PVBOXVDMAINFO pInfo, const void* pvPtr) +{ + return VBoxSHGSMICommandPtrOffset(&pInfo->CmdHeap, pvPtr); +} int vboxVdmaCBufDrSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr); int vboxVdmaCBufDrSubmitSynch(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAINFO pInfo, PVBOXVDMACBUF_DR pDr); struct VBOXVDMACBUF_DR* vboxVdmaCBufDrCreate(PVBOXVDMAINFO pInfo, uint32_t cbTrailingData); @@ -326,22 +315,6 @@ AssertCompile(sizeof (VBOXVDMADDI_CMD) <= RT_SIZEOFMEMB(VBOXVDMACBUF_DR, aGuestD #define VBOXVDMACBUF_DR_FROM_DDI_CMD(_pCmd) ((PVBOXVDMACBUF_DR)(((uint8_t*)(_pCmd)) - RT_OFFSETOF(VBOXVDMACBUF_DR, aGuestData))) #endif -NTSTATUS vboxVdmaGgCmdSubmit(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pCmd); -PVBOXVDMAPIPE_CMD_DR vboxVdmaGgCmdCreate(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_TYPE enmType, uint32_t cbCmd); -DECLINLINE(void) vboxVdmaGgCmdAddRef(PVBOXVDMAPIPE_CMD_DR pDr) -{ - ASMAtomicIncU32(&pDr->cRefs); -} -void vboxVdmaGgCmdDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pDr); -DECLINLINE(void) vboxVdmaGgCmdRelease(PVBOXMP_DEVEXT pDevExt, PVBOXVDMAPIPE_CMD_DR pDr) -{ - uint32_t cRefs = ASMAtomicDecU32(&pDr->cRefs); - Assert(cRefs < UINT32_MAX/2); - if (!cRefs) - vboxVdmaGgCmdDestroy(pDevExt, pDr); -} -NTSTATUS vboxVdmaGgCmdFinish(PVBOXMP_DEVEXT pDevExt, struct VBOXWDDM_CONTEXT *pContext, PKEVENT pEvent); -NTSTATUS vboxVdmaGgCmdCancel(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, PVBOXWDDM_SWAPCHAIN pSwapchain); NTSTATUS vboxVdmaPostHideSwapchain(PVBOXWDDM_SWAPCHAIN pSwapchain); @@ -355,5 +328,11 @@ NTSTATUS vboxVdmaGgDmaBltPerform(PVBOXMP_DEVEXT pDevExt, struct VBOXWDDM_ALLOC_D struct VBOXWDDM_ALLOC_DATA *pDstAlloc, RECT* pDstRect); #define VBOXVDMAPIPE_CMD_DR_FROM_DDI_CMD(_pCmd) ((PVBOXVDMAPIPE_CMD_DR)(((uint8_t*)(_pCmd)) - RT_OFFSETOF(VBOXVDMAPIPE_CMD_DR, DdiCmd))) -DECLCALLBACK(VOID) vboxVdmaGgDdiCmdRelease(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext); + +NTSTATUS vboxVdmaProcessBltCmd(PVBOXMP_DEVEXT pDevExt, struct VBOXWDDM_CONTEXT *pContext, struct VBOXWDDM_DMA_PRIVATEDATA_BLT *pBlt); +NTSTATUS vboxVdmaProcessFlipCmd(PVBOXMP_DEVEXT pDevExt, struct VBOXWDDM_CONTEXT *pContext, struct VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip); +NTSTATUS vboxVdmaProcessClrFillCmd(PVBOXMP_DEVEXT pDevExt, struct VBOXWDDM_CONTEXT *pContext, struct VBOXWDDM_DMA_PRIVATEDATA_CLRFILL *pCF); + +NTSTATUS vboxVdmaTexPresentSetAlloc(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pRealFbAlloc); + #endif /* #ifndef ___VBoxMPVdma_h___ */ diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.cpp index d948ea97..a6deff29 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.h index e4279154..ca08d756 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVhwa.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.cpp index 4813f818..a9e1d8e3 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.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; @@ -552,6 +552,10 @@ static DECLCALLBACK(BOOLEAN) vboxFidPnMatchMonitorModesEnum(D3DKMDT_HMONITORSOUR if (!fFound) pInfo->fMatched = FALSE; + if (!pInfo->fMatched) + LOG(("Found non-matching mode (%d X %d)", + pMonitorSMI->VideoSignalInfo.ActiveSize.cx, pMonitorSMI->VideoSignalInfo.ActiveSize.cy)); + pMonitorSMSIf->pfnReleaseModeInfo(hMonitorSMS, pMonitorSMI); return pInfo->fMatched; @@ -596,7 +600,10 @@ NTSTATUS vboxVidPnMatchMonitorModes(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT if (NT_SUCCESS(Status)) { if (cModes < cResolutions) + { *pfMatch = FALSE; + LOG(("num modes(%d) and resolutions(%d) do not match, treat as not matched..", cModes, cResolutions)); + } else { VBOXVIDPNMATCHMONMODESENUM Info; @@ -606,7 +613,12 @@ NTSTATUS vboxVidPnMatchMonitorModes(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT Status = vboxVidPnEnumMonitorSourceModes(hMonitorSMS, pMonitorSMSIf, vboxFidPnMatchMonitorModesEnum, &Info); if (NT_SUCCESS(Status)) + { *pfMatch = Info.fMatched; + LOG(("modes %smatched", Info.fMatched ? "" : "NOT ")); + } + else + WARN(("vboxVidPnEnumMonitorSourceModes failed, Status 0x%x", Status)); } } else @@ -1250,10 +1262,7 @@ static NTSTATUS vboxVidPnCofuncModalityForPathTarget(PVBOXVIDPNCOFUNCMODALITY pC D3DKMDT_HVIDPNTARGETMODESET hNewVidPnTargetModeSet = NULL; const DXGK_VIDPNTARGETMODESET_INTERFACE *pNewVidPnTargetModeSetInterface; - if (VidPnSourceId != VidPnTargetId || pCbContext->apPathInfos[VidPnTargetId].enmState != VBOXVIDPNPATHITEM_STATE_PRESENT) - { - return STATUS_SUCCESS; - } + Assert(VidPnSourceId == VidPnTargetId); D3DKMDT_HVIDPNSOURCEMODESET hCurVidPnSourceModeSet; const DXGK_VIDPNSOURCEMODESET_INTERFACE *pCurVidPnSourceModeSetInterface; @@ -1293,10 +1302,9 @@ static NTSTATUS vboxVidPnCofuncModalityForPathTarget(PVBOXVIDPNCOFUNCMODALITY pC if (NT_SUCCESS(Status)) { Assert(hNewVidPnTargetModeSet); - if (VidPnSourceId == VidPnTargetId && pCbContext->apPathInfos[VidPnTargetId].enmState == VBOXVIDPNPATHITEM_STATE_PRESENT) + Assert(VidPnSourceId == VidPnTargetId); +// if (VidPnSourceId == VidPnTargetId && pCbContext->apPathInfos[VidPnTargetId].enmState == VBOXVIDPNPATHITEM_STATE_PRESENT) { - Assert(VidPnSourceId == VidPnTargetId); - for (uint32_t i = 0; i < pInfo->cResolutions; ++i) { D3DKMDT_2DREGION *pResolution = &pInfo->aResolutions[i]; @@ -1385,10 +1393,7 @@ static NTSTATUS vboxVidPnCofuncModalityForPathSource(PVBOXVIDPNCOFUNCMODALITY pC D3DKMDT_HVIDPNSOURCEMODESET hNewVidPnSourceModeSet = NULL; const DXGK_VIDPNSOURCEMODESET_INTERFACE *pNewVidPnSourceModeSetInterface; - if (VidPnSourceId != VidPnTargetId || pCbContext->apPathInfos[VidPnSourceId].enmState != VBOXVIDPNPATHITEM_STATE_PRESENT) - { - return STATUS_SUCCESS; - } + Assert(VidPnSourceId == VidPnTargetId); D3DKMDT_HVIDPNTARGETMODESET hCurVidPnTargetModeSet; const DXGK_VIDPNTARGETMODESET_INTERFACE *pCurVidPnTargetModeSetInterface; @@ -1428,9 +1433,9 @@ static NTSTATUS vboxVidPnCofuncModalityForPathSource(PVBOXVIDPNCOFUNCMODALITY pC if (NT_SUCCESS(Status)) { Assert(hNewVidPnSourceModeSet); - if (VidPnSourceId == VidPnTargetId && pCbContext->apPathInfos[VidPnSourceId].enmState == VBOXVIDPNPATHITEM_STATE_PRESENT) + Assert(VidPnSourceId == VidPnTargetId); +// if (VidPnSourceId == VidPnTargetId && pCbContext->apPathInfos[VidPnSourceId].enmState == VBOXVIDPNPATHITEM_STATE_PRESENT) { - Assert(VidPnSourceId == VidPnTargetId); for (uint32_t i = 0; i < pInfo->cModes; ++i) { VIDEO_MODE_INFORMATION *pMode = &pInfo->aModes[i]; @@ -1742,7 +1747,7 @@ static DECLCALLBACK(BOOLEAN) vboxVidPnCheckTopologyEnum(D3DKMDT_HVIDPNTOPOLOGY h } else { - AssertFailed(); + WARN(("cItems(%d) <= VidPnSourceId(%d)", pCbContext->cItems, VidPnSourceId)); Status = STATUS_BUFFER_OVERFLOW; break; } @@ -1753,7 +1758,7 @@ static DECLCALLBACK(BOOLEAN) vboxVidPnCheckTopologyEnum(D3DKMDT_HVIDPNTOPOLOGY h } else { - AssertFailed(); + WARN(("cItems(%d) <= VidPnTargetId(%d)", pCbContext->cItems, VidPnTargetId)); Status = STATUS_BUFFER_OVERFLOW; break; } @@ -1762,6 +1767,7 @@ static DECLCALLBACK(BOOLEAN) vboxVidPnCheckTopologyEnum(D3DKMDT_HVIDPNTOPOLOGY h } /* VidPnSourceId == VidPnTargetId */ + Assert(VidPnSourceId == VidPnTargetId); if (pCbContext->cItems > VidPnSourceId) { if (pCbContext->paItems[VidPnSourceId].enmState != VBOXVIDPNPATHITEM_STATE_DISABLED) @@ -1772,7 +1778,7 @@ static DECLCALLBACK(BOOLEAN) vboxVidPnCheckTopologyEnum(D3DKMDT_HVIDPNTOPOLOGY h } else { - AssertFailed(); + WARN(("cItems(%d) <= VidPnSource/TargetId(%d)", pCbContext->cItems, VidPnSourceId)); Status = STATUS_BUFFER_OVERFLOW; break; } @@ -1788,20 +1794,21 @@ static DECLCALLBACK(BOOLEAN) vboxVidPnCheckTopologyEnum(D3DKMDT_HVIDPNTOPOLOGY h /* we currently support only 0 -> 0, 1 -> 1, 2 -> 2 paths, AND 0 -> 0 must be present * this routine disables all paths unsupported */ -NTSTATUS vboxVidPnCheckTopology(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface, - BOOLEAN fBreakOnDisabled, UINT cItems, PVBOXVIDPNPATHITEM paItems, BOOLEAN *pfDisabledFound) +NTSTATUS vboxVidPnCheckTopology(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface, BOOLEAN *pfSupported) { + VBOXVIDPNPATHITEM aItems[VBOX_VIDEO_MAX_SCREENS]; + const uint32_t cItems = RT_ELEMENTS(aItems); UINT i; for (i = 0; i < cItems; ++i) { - paItems[i].enmState = VBOXVIDPNPATHITEM_STATE_NOT_EXISTS; + aItems[i].enmState = VBOXVIDPNPATHITEM_STATE_NOT_EXISTS; } VBOXVIDPNGETPATHSINFO CbContext = {0}; CbContext.Status = STATUS_SUCCESS; - CbContext.fBreakOnDisabled = fBreakOnDisabled; + CbContext.fBreakOnDisabled = FALSE; CbContext.fDisabledFound = FALSE; CbContext.cItems = cItems; - CbContext.paItems = paItems; + CbContext.paItems = aItems; NTSTATUS Status = vboxVidPnEnumPaths(hVidPnTopology, pVidPnTopologyInterface, vboxVidPnCheckTopologyEnum, &CbContext); if (!NT_SUCCESS(Status)) { @@ -1816,22 +1823,22 @@ NTSTATUS vboxVidPnCheckTopology(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXG return Status; } - if (pfDisabledFound) - *pfDisabledFound = CbContext.fDisabledFound; + BOOLEAN fSupported = !CbContext.fDisabledFound; - if (!fBreakOnDisabled) - { - /* now check if 0->0 path is present and enabled, and if not, disable everything */ - if (cItems && paItems[0].enmState != VBOXVIDPNPATHITEM_STATE_PRESENT) - { - LOGREL(("path 0 not set to present\n")); - for (i = 0; i < cItems; ++i) - { - if (paItems[i].enmState == VBOXVIDPNPATHITEM_STATE_PRESENT) - paItems[i].enmState = VBOXVIDPNPATHITEM_STATE_DISABLED; - } - } - } + /* now check if 0->0 path is present and enabled, and if not, disable everything */ +// if (cItems && aItems[0].enmState != VBOXVIDPNPATHITEM_STATE_PRESENT) +// { +// LOG(("path 0 not set to present\n")); +//// for (i = 0; i < cItems; ++i) +//// { +//// if (aItems[i].enmState == VBOXVIDPNPATHITEM_STATE_PRESENT) +//// aItems[i].enmState = VBOXVIDPNPATHITEM_STATE_DISABLED; +//// } +// fSupported = FALSE; +// } + + if (pfSupported) + *pfSupported = fSupported; return Status; } @@ -2050,9 +2057,8 @@ NTSTATUS vboxVidPnEnumPaths(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXGK_VI pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pNextVidPnPresentPathInfo); else { - Assert(Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET); if (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) - LOGREL(("pfnAcquireNextPathInfo Failed Status(0x%x), ignored since callback returned false", Status)); + WARN(("pfnAcquireNextPathInfo Failed Status(0x%x), ignored since callback returned false", Status)); Status = STATUS_SUCCESS; } @@ -2067,8 +2073,7 @@ NTSTATUS vboxVidPnEnumPaths(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXGK_VI } else { - AssertBreakpoint(); - LOGREL(("pfnAcquireNextPathInfo Failed Status(0x%x)", Status)); + WARN(("pfnAcquireNextPathInfo Failed Status(0x%x)", Status)); pNewVidPnPresentPathInfo = NULL; break; } @@ -2077,26 +2082,54 @@ NTSTATUS vboxVidPnEnumPaths(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXGK_VI else if (Status == STATUS_GRAPHICS_DATASET_IS_EMPTY) Status = STATUS_SUCCESS; else - LOGREL(("pfnAcquireFirstModeInfo failed Status(0x%x)", Status)); + WARN(("pfnAcquireFirstModeInfo failed Status(0x%x)", Status)); return Status; } NTSTATUS vboxVidPnSetupSourceInfo(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId, PVBOXWDDM_SOURCE pSource, CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo, PVBOXWDDM_ALLOCATION pAllocation) { - vboxWddmAssignPrimary(pDevExt, pSource, pAllocation, srcId); /* pVidPnSourceModeInfo could be null if STATUS_GRAPHICS_MODE_NOT_PINNED, * see vboxVidPnCommitSourceModeForSrcId */ + uint8_t fChanges = 0; if (pVidPnSourceModeInfo) { - pSource->AllocData.SurfDesc.width = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx; - pSource->AllocData.SurfDesc.height = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy; - pSource->AllocData.SurfDesc.format = pVidPnSourceModeInfo->Format.Graphics.PixelFormat; - pSource->AllocData.SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pVidPnSourceModeInfo->Format.Graphics.PixelFormat); - pSource->AllocData.SurfDesc.pitch = pVidPnSourceModeInfo->Format.Graphics.Stride; + if (pSource->AllocData.SurfDesc.width != pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx) + { + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + pSource->AllocData.SurfDesc.width = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx; + } + if (pSource->AllocData.SurfDesc.height != pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy) + { + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + pSource->AllocData.SurfDesc.height = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy; + } + if (pSource->AllocData.SurfDesc.format != pVidPnSourceModeInfo->Format.Graphics.PixelFormat) + { + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + pSource->AllocData.SurfDesc.format = pVidPnSourceModeInfo->Format.Graphics.PixelFormat; + } + if (pSource->AllocData.SurfDesc.bpp != vboxWddmCalcBitsPerPixel(pVidPnSourceModeInfo->Format.Graphics.PixelFormat)) + { + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + pSource->AllocData.SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pVidPnSourceModeInfo->Format.Graphics.PixelFormat); + } + if(pSource->AllocData.SurfDesc.pitch != pVidPnSourceModeInfo->Format.Graphics.Stride) + { + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + pSource->AllocData.SurfDesc.pitch = pVidPnSourceModeInfo->Format.Graphics.Stride; + } pSource->AllocData.SurfDesc.depth = 1; - pSource->AllocData.SurfDesc.slicePitch = pVidPnSourceModeInfo->Format.Graphics.Stride; - pSource->AllocData.SurfDesc.cbSize = pVidPnSourceModeInfo->Format.Graphics.Stride * pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy; + if (pSource->AllocData.SurfDesc.slicePitch != pVidPnSourceModeInfo->Format.Graphics.Stride) + { + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + pSource->AllocData.SurfDesc.slicePitch = pVidPnSourceModeInfo->Format.Graphics.Stride; + } + if (pSource->AllocData.SurfDesc.cbSize != pVidPnSourceModeInfo->Format.Graphics.Stride * pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy) + { + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + pSource->AllocData.SurfDesc.cbSize = pVidPnSourceModeInfo->Format.Graphics.Stride * pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy; + } #ifdef VBOX_WDDM_WIN8 if (g_VBoxDisplayOnly) { @@ -2107,9 +2140,13 @@ NTSTATUS vboxVidPnSetupSourceInfo(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_S else { Assert(!pAllocation); + fChanges |= VBOXWDDM_HGSYNC_F_SYNCED_ALL; } + + vboxWddmAssignPrimary(pDevExt, pSource, pAllocation, srcId); + Assert(pSource->AllocData.SurfDesc.VidPnSourceId == srcId); - pSource->bGhSynced = FALSE; + pSource->u8SyncState &= ~fChanges; return STATUS_SUCCESS; } @@ -2155,7 +2192,6 @@ DECLCALLBACK(BOOLEAN) vboxVidPnCommitTargetModeEnum(PVBOXMP_DEVEXT pDevExt, D3DK { pTarget->HeightVisible = pPinnedVidPnTargetModeInfo->VideoSignalInfo.ActiveSize.cy; pTarget->HeightTotal = pPinnedVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy; - pTarget->ScanLineState = 0; } pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pPinnedVidPnTargetModeInfo); } @@ -2169,6 +2205,10 @@ DECLCALLBACK(BOOLEAN) vboxVidPnCommitTargetModeEnum(PVBOXMP_DEVEXT pDevExt, D3DK return Status == STATUS_SUCCESS; } +#ifdef DEBUG_misha +DWORD g_VBoxDbgBreakModes = 0; +#endif + NTSTATUS vboxVidPnCommitSourceModeForSrcId(PVBOXMP_DEVEXT pDevExt, const D3DKMDT_HVIDPN hDesiredVidPn, const DXGK_VIDPN_INTERFACE* pVidPnInterface, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId, PVBOXWDDM_ALLOCATION pAllocation) { D3DKMDT_HVIDPNSOURCEMODESET hCurVidPnSourceModeSet; @@ -2222,29 +2262,33 @@ NTSTATUS vboxVidPnCommitSourceModeForSrcId(PVBOXMP_DEVEXT pDevExt, const D3DKMDT Status = STATUS_SUCCESS; } else - LOGREL(("vboxVidPnEnumTargetsForSource failed Status(0x%x)", Status)); + WARN(("vboxVidPnEnumTargetsForSource failed Status(0x%x)", Status)); } else - LOGREL(("pfnGetTopology failed Status(0x%x)", Status)); + WARN(("pfnGetTopology failed Status(0x%x)", Status)); } else - LOGREL(("vboxVidPnCommitSourceMode failed Status(0x%x)", Status)); + WARN(("vboxVidPnCommitSourceMode failed Status(0x%x)", Status)); /* release */ pCurVidPnSourceModeSetInterface->pfnReleaseModeInfo(hCurVidPnSourceModeSet, pPinnedVidPnSourceModeInfo); } else if (Status == STATUS_GRAPHICS_MODE_NOT_PINNED) { +#ifdef DEBUG_misha + Assert(!g_VBoxDbgBreakModes); + ++g_VBoxDbgBreakModes; +#endif Status = vboxVidPnCommitSourceMode(pDevExt, srcId, NULL, pAllocation); Assert(Status == STATUS_SUCCESS); } else - LOGREL(("pfnAcquirePinnedModeInfo failed Status(0x%x)", Status)); + WARN(("pfnAcquirePinnedModeInfo failed Status(0x%x)", Status)); pVidPnInterface->pfnReleaseSourceModeSet(hDesiredVidPn, hCurVidPnSourceModeSet); } else { - LOGREL(("pfnAcquireSourceModeSet failed Status(0x%x)", Status)); + WARN(("pfnAcquireSourceModeSet failed Status(0x%x)", Status)); } return Status; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.h index f9a4d1e1..e51a0287 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPVidPn.h @@ -57,8 +57,8 @@ typedef struct VBOXVIDPNCOFUNCMODALITY const DXGK_VIDPN_INTERFACE* pVidPnInterface; CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* pEnumCofuncModalityArg; PVBOXWDDM_VIDEOMODES_INFO pInfos; - UINT cPathInfos; - PVBOXVIDPNPATHITEM apPathInfos; +// UINT cPathInfos; +// PVBOXVIDPNPATHITEM apPathInfos; } VBOXVIDPNCOFUNCMODALITY, *PVBOXVIDPNCOFUNCMODALITY; typedef struct VBOXVIDPNCOMMIT @@ -145,8 +145,7 @@ NTSTATUS vboxVidPnMatchMonitorModes(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT NTSTATUS vboxVidPnCofuncModalityForPath(PVBOXVIDPNCOFUNCMODALITY pCbContext, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId); -NTSTATUS vboxVidPnCheckTopology(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface, - BOOLEAN fBreakOnDisabled, UINT cItems, PVBOXVIDPNPATHITEM paItems, BOOLEAN *pfDisabledFound); +NTSTATUS vboxVidPnCheckTopology(D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology, const DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface, BOOLEAN *pfSupported); NTSTATUS vboxVidPnPathAdd(D3DKMDT_HVIDPN hVidPn, const DXGK_VIDPN_INTERFACE* pVidPnInterface, const D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, const D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId); diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp index 446d048c..39b66cf1 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp @@ -4,7 +4,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; @@ -30,6 +30,10 @@ #include <VBoxDisplay.h> /* this is from Additions/WINNT/include/ to include escape codes */ #include <VBox/Hardware/VBoxVideoVBE.h> +#include <stdio.h> + +#define VBOXWDDM_DUMMY_DMABUFFER_SIZE sizeof (RECT) + DWORD g_VBoxLogUm = 0; #ifdef VBOX_WDDM_WIN8 DWORD g_VBoxDisplayOnly = 0; @@ -54,12 +58,31 @@ VOID vboxWddmMemFree(PVOID pvMem) ExFreePool(pvMem); } +DECLINLINE(void) VBoxWddmOaHostIDReleaseLocked(PVBOXWDDM_OPENALLOCATION pOa) +{ + Assert(pOa->cHostIDRefs); + PVBOXWDDM_ALLOCATION pAllocation = pOa->pAllocation; + Assert(pAllocation->AllocData.cHostIDRefs >= pOa->cHostIDRefs); + Assert(pAllocation->AllocData.hostID); + --pOa->cHostIDRefs; + --pAllocation->AllocData.cHostIDRefs; + if (!pAllocation->AllocData.cHostIDRefs) + pAllocation->AllocData.hostID = 0; +} + +DECLINLINE(void) VBoxWddmOaHostIDCheckReleaseLocked(PVBOXWDDM_OPENALLOCATION pOa) +{ + if (pOa->cHostIDRefs) + VBoxWddmOaHostIDReleaseLocked(pOa); +} + DECLINLINE(void) VBoxWddmOaRelease(PVBOXWDDM_OPENALLOCATION pOa) { PVBOXWDDM_ALLOCATION pAllocation = pOa->pAllocation; KIRQL OldIrql; KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql); Assert(pAllocation->cOpens); + VBoxWddmOaHostIDCheckReleaseLocked(pOa); --pAllocation->cOpens; uint32_t cOpens = --pOa->cOpens; Assert(cOpens < UINT32_MAX/2); @@ -96,6 +119,47 @@ DECLINLINE(PVBOXWDDM_OPENALLOCATION) VBoxWddmOaSearch(PVBOXWDDM_DEVICE pDevice, return pOa; } +DECLINLINE(int) VBoxWddmOaSetHostID(PVBOXWDDM_DEVICE pDevice, PVBOXWDDM_ALLOCATION pAllocation, uint32_t hostID, uint32_t *pHostID) +{ + PVBOXWDDM_OPENALLOCATION pOa; + KIRQL OldIrql; + int rc = VINF_SUCCESS; + KeAcquireSpinLock(&pAllocation->OpenLock, &OldIrql); + pOa = VBoxWddmOaSearchLocked(pDevice, pAllocation); + if (!pOa) + { + KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql);; + WARN(("no open allocation!")); + return VERR_INVALID_STATE; + } + + if (hostID) + { + if (pAllocation->AllocData.hostID == 0) + { + pAllocation->AllocData.hostID = hostID; + } + else if (pAllocation->AllocData.hostID != hostID) + { + WARN(("hostID differ: alloc(%d), trying to assign(%d)", pAllocation->AllocData.hostID, hostID)); + hostID = pAllocation->AllocData.hostID; + rc = VERR_NOT_EQUAL; + } + + ++pAllocation->AllocData.cHostIDRefs; + ++pOa->cHostIDRefs; + } + else + VBoxWddmOaHostIDCheckReleaseLocked(pOa); + + KeReleaseSpinLock(&pAllocation->OpenLock, OldIrql); + + if (pHostID) + *pHostID = hostID; + + return rc; +} + DECLINLINE(PVBOXWDDM_ALLOCATION) vboxWddmGetAllocationFromHandle(PVBOXMP_DEVEXT pDevExt, D3DKMT_HANDLE hAllocation) { DXGKARGCB_GETHANDLEDATA GhData; @@ -137,7 +201,7 @@ static void vboxWddmPopulateDmaAllocInfoWithOffset(PVBOXWDDM_DMA_ALLOCINFO pInfo pInfo->srcId = pAlloc->AllocData.SurfDesc.VidPnSourceId; } -NTSTATUS vboxWddmGhDisplayPostInfoScreenBySDesc (PVBOXMP_DEVEXT pDevExt, const PVBOXWDDM_SURFACE_DESC pDesc, const POINT * pVScreenPos, uint16_t fFlags) +NTSTATUS vboxWddmGhDisplayPostInfoScreenBySDesc (PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_SURFACE_DESC *pDesc, const POINT * pVScreenPos, uint16_t fFlags) { void *p = VBoxHGSMIBufferAlloc (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, sizeof (VBVAINFOSCREEN), @@ -167,7 +231,7 @@ NTSTATUS vboxWddmGhDisplayPostInfoScreenBySDesc (PVBOXMP_DEVEXT pDevExt, const P } -NTSTATUS vboxWddmGhDisplayPostInfoScreen(PVBOXMP_DEVEXT pDevExt, const PVBOXWDDM_ALLOC_DATA pAllocData, const POINT * pVScreenPos) +NTSTATUS vboxWddmGhDisplayPostInfoScreen(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData, const POINT * pVScreenPos) { NTSTATUS Status = vboxWddmGhDisplayPostInfoScreenBySDesc(pDevExt, &pAllocData->SurfDesc, pVScreenPos, VBVA_SCREEN_F_ACTIVE); if (!NT_SUCCESS(Status)) @@ -177,16 +241,26 @@ NTSTATUS vboxWddmGhDisplayPostInfoScreen(PVBOXMP_DEVEXT pDevExt, const PVBOXWDDM NTSTATUS vboxWddmGhDisplayHideScreen(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId) { - VBOXWDDM_SURFACE_DESC SurfDesc = {0}; + PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnTargetId]; + /* this will force update on re-activation */ + pSource->AllocData.SurfDesc.width = 0; + pSource->AllocData.SurfDesc.height = 0; POINT VScreenPos = {0}; - SurfDesc.VidPnSourceId = VidPnTargetId; - NTSTATUS Status = vboxWddmGhDisplayPostInfoScreenBySDesc(pDevExt, &SurfDesc, &VScreenPos, VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED); + + NTSTATUS Status = vboxWddmGhDisplayPostInfoScreenBySDesc(pDevExt, &pSource->AllocData.SurfDesc, &VScreenPos, VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED); if (!NT_SUCCESS(Status)) WARN(("vboxWddmGhDisplayPostInfoScreenBySDesc failed Status 0x%x", Status)); return Status; } -NTSTATUS vboxWddmGhDisplayPostInfoView(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOC_DATA pAllocData) +BOOL vboxWddmGhDisplayCheckCompletePeningScreenInfo(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId) +{ + if (!ASMAtomicCmpXchgBool(&pDevExt->aTargets[VidPnTargetId].fStateSyncPening, false, true)) + return FALSE; + return vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, &pDevExt->aSources[VidPnTargetId]); +} + +NTSTATUS vboxWddmGhDisplayPostInfoView(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData) { VBOXVIDEOOFFSET offVram = pAllocData->Addr.offVram; if (offVram == VBOXVIDEOOFFSET_VOID) @@ -219,7 +293,7 @@ NTSTATUS vboxWddmGhDisplayPostInfoView(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOC_D return STATUS_SUCCESS; } -NTSTATUS vboxWddmGhDisplaySetMode(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOC_DATA pAllocData) +NTSTATUS vboxWddmGhDisplaySetMode(PVBOXMP_DEVEXT pDevExt, const VBOXWDDM_ALLOC_DATA *pAllocData) { // PVBOXWDDM_ALLOCATION_SHAREDPRIMARYSURFACE pPrimaryInfo = VBOXWDDM_ALLOCATION_BODY(pAllocation, VBOXWDDM_ALLOCATION_SHAREDPRIMARYSURFACE); if (/*pPrimaryInfo->*/pAllocData->SurfDesc.VidPnSourceId) @@ -269,38 +343,77 @@ NTSTATUS vboxWddmGhDisplayUpdateScreenPos(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOUR return Status; } -NTSTATUS vboxWddmGhDisplaySetInfo(PVBOXMP_DEVEXT pDevExt, const PVBOXWDDM_ALLOC_DATA pAllocData, const POINT * pVScreenPos) +NTSTATUS vboxWddmGhDisplaySetInfo(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pRealFbAlloc, const VBOXWDDM_ALLOC_DATA *pAllocData, const POINT * pVScreenPos, uint8_t u8CurCyncState) { - NTSTATUS Status = vboxWddmGhDisplaySetMode(pDevExt, pAllocData); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) + NTSTATUS Status; + + if ((u8CurCyncState & VBOXWDDM_HGSYNC_F_CHANGED_LOCATION_ONLY) == VBOXWDDM_HGSYNC_F_CHANGED_LOCATION_ONLY + && pRealFbAlloc->AllocData.hostID) + { + Status = vboxVdmaTexPresentSetAlloc(pDevExt, pRealFbAlloc); + if (!NT_SUCCESS(Status)) + WARN(("vboxVdmaTexPresentSetAlloc failed, Status 0x%x", Status)); + return Status; + } + + Status = vboxWddmGhDisplaySetMode(pDevExt, pAllocData); + if (NT_SUCCESS(Status)) { Status = vboxWddmGhDisplayPostInfoView(pDevExt, pAllocData); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) + if (NT_SUCCESS(Status)) { Status = vboxWddmGhDisplayPostInfoScreen(pDevExt, pAllocData, pVScreenPos); - Assert(Status == STATUS_SUCCESS); - if (!NT_SUCCESS(Status)) - WARN(("vboxWddmGhDisplayPostInfoScreen failed")); + if (NT_SUCCESS(Status)) + { + if (pDevExt->f3DEnabled) + { + Status = vboxVdmaTexPresentSetAlloc(pDevExt, pRealFbAlloc); + if (NT_SUCCESS(Status)) + return STATUS_SUCCESS; + else + WARN(("vboxVdmaTexPresentSetAlloc failed, Status 0x%x", Status)); + } + } + else + WARN(("vboxWddmGhDisplayPostInfoScreen failed, Status 0x%x", Status)); } else - WARN(("vboxWddmGhDisplayPostInfoView failed")); + WARN(("vboxWddmGhDisplayPostInfoView failed, Status 0x%x", Status)); } else - WARN(("vboxWddmGhDisplaySetMode failed")); + WARN(("vboxWddmGhDisplaySetMode failed, Status 0x%x", Status)); return Status; } -bool vboxWddmGhDisplayCheckSetInfoFromSource(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource) +bool vboxWddmGhDisplaySetInfoFromSourceTarget(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource, PVBOXWDDM_TARGET pTarget) { - Assert(VBOXVIDEOOFFSET_VOID != pSource->AllocData.Addr.offVram); - - if (pSource->bGhSynced) - return false; + if (!pTarget->HeightVisible) + { + vboxWddmGhDisplayHideScreen(pDevExt, pSource->AllocData.SurfDesc.VidPnSourceId); + pSource->u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL; + return true; + } PVBOXWDDM_ALLOCATION pFbAlloc = VBOXWDDM_FB_ALLOCATION(pDevExt, pSource); + PVBOXWDDM_ALLOCATION pRealFbAlloc = pSource->pPrimaryAllocation; +#ifdef VBOXWDDM_RENDER_FROM_SHADOW +# ifdef VBOX_WDDM_WIN8 + if (!g_VBoxDisplayOnly) +# endif + { + if (!pRealFbAlloc) + return false; + + if (!pFbAlloc) + pFbAlloc = pRealFbAlloc; + + if (!pFbAlloc || pFbAlloc->AllocData.Addr.offVram == VBOXVIDEOOFFSET_VOID) + { + return false; + } + } +#endif #ifdef VBOX_WDDM_WIN8 Assert(!g_VBoxDisplayOnly == !!pFbAlloc); @@ -312,15 +425,32 @@ bool vboxWddmGhDisplayCheckSetInfoFromSource(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_S #endif Assert(!pFbAlloc || pFbAlloc->AllocData.Addr.SegmentId == pSource->AllocData.Addr.SegmentId); - NTSTATUS Status = vboxWddmGhDisplaySetInfo(pDevExt, pFbAlloc ? &pFbAlloc->AllocData : &pSource->AllocData, &pSource->VScreenPos); + NTSTATUS Status = vboxWddmGhDisplaySetInfo(pDevExt, pRealFbAlloc, pFbAlloc ? &pFbAlloc->AllocData : &pSource->AllocData, &pSource->VScreenPos, pSource->u8SyncState); if (NT_SUCCESS(Status)) - pSource->bGhSynced = TRUE; + pSource->u8SyncState = VBOXWDDM_HGSYNC_F_SYNCED_ALL; else WARN(("vboxWddmGhDisplaySetInfo failed, Status (0x%x)", Status)); + vboxVideoCmSignalEvents(&pDevExt->SeamlessCtxMgr); + return true; } +bool vboxWddmGhDisplayCheckSetInfoFromSource(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource) +{ + Assert(VBOXVIDEOOFFSET_VOID != pSource->AllocData.Addr.offVram + || !pDevExt->aTargets[pSource->AllocData.SurfDesc.VidPnSourceId].HeightVisible); + + if (pSource->u8SyncState == VBOXWDDM_HGSYNC_F_SYNCED_ALL) + return false; + + PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[pSource->AllocData.SurfDesc.VidPnSourceId]; + if (ASMAtomicUoReadBool(&pTarget->fStateSyncPening)) + return false; + + return vboxWddmGhDisplaySetInfoFromSourceTarget(pDevExt, pSource, pTarget); +} + static VOID vboxWddmModeRenderFromShadowDisableOnSubmitCommand(PVBOXMP_DEVEXT pDevExt, BOOLEAN fDisable) { for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) @@ -354,7 +484,7 @@ static VOID vboxWddmModeRenderFromShadowDisableOnSubmitCommand(PVBOXMP_DEVEXT pD } /* ensure we issue resize command on next update */ - pSource->bGhSynced = FALSE; + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; } } @@ -397,19 +527,6 @@ static VOID vboxWddmModeRenderFromShadowDisableUnregister(PVBOXMP_DEVEXT pDevExt pContext->fRenderFromShadowDisabled = FALSE; } -#ifdef VBOXWDDM_RENDER_FROM_SHADOW -bool vboxWddmCheckUpdateFramebufferAddress(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource) -{ - if (pSource->pPrimaryAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC) - { - Assert(pSource->bGhSynced == FALSE); - return false; - } - - return vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource); -} -#endif - PVBOXSHGSMI vboxWddmHgsmiGetHeapFromCmdOffset(PVBOXMP_DEVEXT pDevExt, HGSMIOFFSET offCmd) { #ifdef VBOX_WITH_VDMA @@ -441,322 +558,6 @@ VBOXWDDM_HGSMICMD_TYPE vboxWddmHgsmiGetCmdTypeFromOffset(PVBOXMP_DEVEXT pDevExt, return VBOXWDDM_HGSMICMD_TYPE_UNDEFINED; } -static NTSTATUS vboxWddmChildStatusReportPerform(PVBOXMP_DEVEXT pDevExt, PVBOXVDMA_CHILD_STATUS pChildStatus, D3DDDI_VIDEO_PRESENT_TARGET_ID iChild) -{ - DXGK_CHILD_STATUS DdiChildStatus; - if (pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_DISCONNECTED) - { - /* report disconnected */ - memset(&DdiChildStatus, 0, sizeof (DdiChildStatus)); - DdiChildStatus.Type = StatusConnection; - if (iChild != D3DDDI_ID_UNINITIALIZED) - { - Assert(iChild < UINT32_MAX/2); - Assert(iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); - DdiChildStatus.ChildUid = iChild; - } - else - { - Assert(pChildStatus->iChild < UINT32_MAX/2); - Assert(pChildStatus->iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); - DdiChildStatus.ChildUid = pChildStatus->iChild; - } - DdiChildStatus.HotPlug.Connected = FALSE; - 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; - } - } - - if (pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_CONNECTED) - { - /* report disconnected */ - memset(&DdiChildStatus, 0, sizeof (DdiChildStatus)); - DdiChildStatus.Type = StatusConnection; - if (iChild != D3DDDI_ID_UNINITIALIZED) - { - Assert(iChild < UINT32_MAX/2); - Assert(iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); - DdiChildStatus.ChildUid = iChild; - } - else - { - Assert(pChildStatus->iChild < UINT32_MAX/2); - Assert(pChildStatus->iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); - DdiChildStatus.ChildUid = pChildStatus->iChild; - } - DdiChildStatus.HotPlug.Connected = TRUE; - 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; - } - } - - if (pChildStatus->fFlags & VBOXVDMA_CHILD_STATUS_F_ROTATED) - { - /* report disconnected */ - memset(&DdiChildStatus, 0, sizeof (DdiChildStatus)); - DdiChildStatus.Type = StatusRotation; - if (iChild != D3DDDI_ID_UNINITIALIZED) - { - Assert(iChild < UINT32_MAX/2); - Assert(iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); - DdiChildStatus.ChildUid = iChild; - } - else - { - Assert(pChildStatus->iChild < UINT32_MAX/2); - Assert(pChildStatus->iChild < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays); - DdiChildStatus.ChildUid = pChildStatus->iChild; - } - DdiChildStatus.Rotation.Angle = pChildStatus->u8RotationAngle; - 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 vboxWddmChildStatusDoReportReconnected(PVBOXMP_DEVEXT pDevExt, VBOXVDMACMD_CHILD_STATUS_IRQ *pBody) -{ - NTSTATUS Status = STATUS_SUCCESS; - - for (UINT i = 0; i < pBody->cInfos; ++i) - { - 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, D3DDDI_ID_UNINITIALIZED); - if (!NT_SUCCESS(Status)) - { - WARN(("vboxWddmChildStatusReportPerform failed with Status (0x%x)", Status)); - break; - } - } - } - - return Status; -} - -typedef struct VBOXWDDMCHILDSTATUSCB -{ - 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); - - vboxWddmChildStatusDoReportReconnected(pDevExt, pBody); - - vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr); - - if (pCtx->pEvent) - { - KeSetEvent(pCtx->pEvent, 0, FALSE); - } -} - -static NTSTATUS vboxWddmChildStatusReportReconnected(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_TARGET_ID idTarget) -{ -#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) - { - // 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 - { - Assert(0); - /* @todo: try flushing.. */ - LOGREL(("vboxVdmaCBufDrCreate returned NULL")); - Status = STATUS_INSUFFICIENT_RESOURCES; - } - - 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 vboxWddmChildStatusDoReportReconnected(pDevExt, &Body); -#endif -} - -static NTSTATUS vboxWddmChildStatusCheckByMask(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_VIDEOMODES_INFO paInfos, uint8_t *pMask) -{ - NTSTATUS Status = STATUS_SUCCESS; - bool bChanged[VBOX_VIDEO_MAX_SCREENS] = {0}; - int i; - - for (i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) - { - if (pMask && !ASMBitTest(pMask, i)) - continue; - - /* @todo: check that we actually need the current source->target */ - PVBOXWDDM_VIDEOMODES_INFO pInfo = &paInfos[i]; - VIDEO_MODE_INFORMATION *pModeInfo = &pInfo->aModes[pInfo->iPreferredMode]; - BOOLEAN fMatch = FALSE; - Status = vboxVidPnMatchMonitorModes(pDevExt, i, pInfo->aResolutions, pInfo->cResolutions, &fMatch); - if (!NT_SUCCESS(Status)) - { - WARN(("vboxVidPnMatchMonitorModes failed Status(0x%x)", Status)); - /* ignore the failures here, although we probably should not?? */ - break; - } - - bChanged[i] = !fMatch; - } - - if (!NT_SUCCESS(Status)) - { - WARN(("updating monitor modes failed, Status(0x%x)", Status)); - return Status; - } - - for (i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) - { - if (bChanged[i]) - { - NTSTATUS tmpStatus = vboxWddmChildStatusReportReconnected(pDevExt, i); - if (!NT_SUCCESS(tmpStatus)) - { - WARN(("vboxWddmChildStatusReportReconnected failed Status(0x%x)", Status)); - /* ignore the failures here, although we probably should not?? */ - break; - } - } - } - - /* wait for the reconnected monitor data to be picked up */ - CONST DXGK_MONITOR_INTERFACE *pMonitorInterface; - Status = pDevExt->u.primary.DxgkInterface.DxgkCbQueryMonitorInterface(pDevExt->u.primary.DxgkInterface.DeviceHandle, DXGK_MONITOR_INTERFACE_VERSION_V1, &pMonitorInterface); - if (!NT_SUCCESS(Status)) - { - WARN(("DxgkCbQueryMonitorInterface failed, Status()0x%x", Status)); - return Status; - } - - for (i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) - { - D3DKMDT_HMONITORSOURCEMODESET hMonitorSMS; - CONST DXGK_MONITORSOURCEMODESET_INTERFACE *pMonitorSMSIf; - if (!bChanged[i]) - continue; - - while (1) - { - Status = pMonitorInterface->pfnAcquireMonitorSourceModeSet(pDevExt->u.primary.DxgkInterface.DeviceHandle, - i, - &hMonitorSMS, - &pMonitorSMSIf); - if (NT_SUCCESS(Status)) - { - NTSTATUS tmpStatus = pMonitorInterface->pfnReleaseMonitorSourceModeSet(pDevExt->u.primary.DxgkInterface.DeviceHandle, hMonitorSMS); - if (!NT_SUCCESS(tmpStatus)) - { - WARN(("pfnReleaseMonitorSourceModeSet failed tmpStatus(0x%x)", tmpStatus)); - } - break; - } - - if (Status != STATUS_GRAPHICS_MONITOR_NOT_CONNECTED) - { - WARN(("DxgkCbQueryMonitorInterface failed, Status()0x%x", Status)); - break; - } - - Assert(KeGetCurrentIrql() < DISPATCH_LEVEL); - - LARGE_INTEGER Interval; - Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000; - NTSTATUS tmpStatus = KeDelayExecutionThread(KernelMode, FALSE, &Interval); - if (!NT_SUCCESS(tmpStatus)) - { - WARN(("KeDelayExecutionThread failed tmpStatus(0x%x)", tmpStatus)); - } - } - } - - return STATUS_SUCCESS; -} - typedef struct VBOXWDDM_HWRESOURCES { PHYSICAL_ADDRESS phVRAM; @@ -856,7 +657,7 @@ static void vboxWddmDevExtZeroinit(PVBOXMP_DEVEXT pDevExt, CONST PDEVICE_OBJECT #endif } -static void vboxWddmSetupDisplays(PVBOXMP_DEVEXT pDevExt) +static void vboxWddmSetupDisplaysLegacy(PVBOXMP_DEVEXT pDevExt) { /* For WDDM, we simply store the number of monitors as we will deal with * VidPN stuff later */ @@ -968,6 +769,74 @@ static void vboxWddmSetupDisplays(PVBOXMP_DEVEXT pDevExt) } } +static NTSTATUS vboxWddmSetupDisplaysNew(PVBOXMP_DEVEXT pDevExt) +{ + if (!VBoxCommonFromDeviceExt(pDevExt)->bHGSMI) + return STATUS_UNSUCCESSFUL; + + ULONG cbAvailable = VBoxCommonFromDeviceExt(pDevExt)->cbVRAM + - VBoxCommonFromDeviceExt(pDevExt)->cbMiniportHeap + - VBVA_ADAPTER_INFORMATION_SIZE; + + ULONG cbCmdVbva = cbAvailable / 2; + ULONG cbCmdVbvaApprox = VBOXCMDVBVA_BUFFERSIZE(4096); + if (cbCmdVbvaApprox > cbCmdVbva) + { + WARN(("too few VRAM memory %d, cmdVbva %d, while approximately needed %d, trying to adjust", cbAvailable, cbCmdVbva, cbCmdVbvaApprox)); + cbCmdVbva = cbCmdVbvaApprox; + } + + cbCmdVbva = VBOXWDDM_ROUNDBOUND(cbCmdVbva, 0x1000); + if (cbCmdVbva > cbAvailable - 0x1000) + { + WARN(("too few VRAM memory fatal, %d, requested for CmdVbva %d", cbAvailable, cbCmdVbva)); + return STATUS_UNSUCCESSFUL; + } + + + ULONG offCmdVbva = cbAvailable - cbCmdVbva; + + int rc = VBoxCmdVbvaCreate(pDevExt, &pDevExt->CmdVbva, offCmdVbva, cbCmdVbva); + if (RT_SUCCESS(rc)) + { + rc = VBoxCmdVbvaEnable(pDevExt, &pDevExt->CmdVbva); + if (RT_SUCCESS(rc)) + { + rc = VBoxMPCmnMapAdapterMemory(VBoxCommonFromDeviceExt(pDevExt), (void**)&pDevExt->pvVisibleVram, + 0, vboxWddmVramCpuVisibleSize(pDevExt)); + if (RT_SUCCESS(rc)) + return STATUS_SUCCESS; + else + WARN(("VBoxMPCmnMapAdapterMemory failed, rc %d", rc)); + + VBoxCmdVbvaDisable(pDevExt, &pDevExt->CmdVbva); + } + else + WARN(("VBoxCmdVbvaEnable failed, rc %d", rc)); + + VBoxCmdVbvaDestroy(pDevExt, &pDevExt->CmdVbva); + } + else + WARN(("VBoxCmdVbvaCreate failed, rc %d", rc)); + + return STATUS_UNSUCCESSFUL; +} + +static NTSTATUS vboxWddmSetupDisplays(PVBOXMP_DEVEXT pDevExt) +{ + if (pDevExt->fCmdVbvaEnabled) + { + NTSTATUS Status = vboxWddmSetupDisplaysNew(pDevExt); + if (!NT_SUCCESS(Status)) + VBoxCommonFromDeviceExt(pDevExt)->bHGSMI = FALSE; + return Status; + } + + vboxWddmSetupDisplaysLegacy(pDevExt); + return VBoxCommonFromDeviceExt(pDevExt)->bHGSMI ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; + return STATUS_UNSUCCESSFUL; +} + static int vboxWddmFreeDisplays(PVBOXMP_DEVEXT pDevExt) { int rc = VINF_SUCCESS; @@ -1095,6 +964,19 @@ NTSTATUS DxgkDdiStartDevice( Status = vboxWddmPickResources(pDevExt, &DeviceInfo, &HwRc); if (Status == STATUS_SUCCESS) { + pDevExt->f3DEnabled = VBoxMpCrCtlConIs3DSupported(); + + if (pDevExt->f3DEnabled) + { + pDevExt->fTexPresentEnabled = !!(VBoxMpCrGetHostCaps() & CR_VBOX_CAP_TEX_PRESENT); + pDevExt->fCmdVbvaEnabled = !!(VBoxMpCrGetHostCaps() & CR_VBOX_CAP_CMDVBVA); + } + else + { + pDevExt->fTexPresentEnabled = FALSE; + pDevExt->fCmdVbvaEnabled = FALSE; + } + /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. * The host will however support both old and new interface to keep compatibility * with old guest additions. @@ -1117,17 +999,18 @@ NTSTATUS DxgkDdiStartDevice( vboxVdmaDdiNodesInit(pDevExt); vboxVideoCmInit(&pDevExt->CmMgr); + vboxVideoCmInit(&pDevExt->SeamlessCtxMgr); InitializeListHead(&pDevExt->SwapchainList3D); pDevExt->cContexts3D = 0; pDevExt->cContexts2D = 0; + pDevExt->cContextsDispIfResize = 0; pDevExt->cUnlockedVBVADisabled = 0; - ExInitializeFastMutex(&pDevExt->ContextMutex); + VBOXWDDM_CTXLOCK_INIT(pDevExt); KeInitializeSpinLock(&pDevExt->SynchLock); VBoxMPCmnInitCustomVideoModes(pDevExt); - VBoxWddmInvalidateAllVideoModesInfos(pDevExt); - pDevExt->fAnyX = VBoxVideoAnyWidthAllowed(); + VBoxCommonFromDeviceExt(pDevExt)->fAnyX = VBoxVideoAnyWidthAllowed(); #if 0 vboxShRcTreeInit(pDevExt); #endif @@ -1137,12 +1020,73 @@ NTSTATUS DxgkDdiStartDevice( #endif VBoxWddmSlInit(pDevExt); + VBoxMpCrShgsmiTransportCreate(&pDevExt->CrHgsmiTransport, pDevExt); + + for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) { PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i]; KeInitializeSpinLock(&pSource->AllocationLock); + VBoxVrListInit(&pSource->VrList); + } + + DWORD dwVal = VBOXWDDM_CFG_DRV_DEFAULT; + HANDLE hKey = NULL; + WCHAR aNameBuf[100]; + + Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ, &hKey); + if (!NT_SUCCESS(Status)) + { + WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status)); + hKey = NULL; + } + + + if (hKey) + { + Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, &dwVal); + if (!NT_SUCCESS(Status)) + { + LOG(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status)); + dwVal = VBOXWDDM_CFG_DRV_DEFAULT; + } + } + + pDevExt->dwDrvCfgFlags = dwVal; + + for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) + { + PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i]; + if (i == 0 || (pDevExt->dwDrvCfgFlags & VBOXWDDM_CFG_DRV_SECONDARY_TARGETS_CONNECTED) || !hKey) + { + pTarget->fConnected = true; + pTarget->fConfigured = true; + } + else if (hKey) + { + swprintf(aNameBuf, L"%s%d", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i); + Status = vboxWddmRegQueryValueDword(hKey, aNameBuf, &dwVal); + if (NT_SUCCESS(Status)) + { + pTarget->fConnected = !!(dwVal & VBOXWDDM_CFG_DRVTARGET_CONNECTED); + pTarget->fConfigured = true; + } + else + { + WARN(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status)); + pTarget->fConnected = false; + pTarget->fConfigured = false; + } + } + } + + if (hKey) + { + NTSTATUS tmpStatus = ZwClose(hKey); + Assert(tmpStatus == STATUS_SUCCESS); } + Status = STATUS_SUCCESS; #ifdef VBOX_WDDM_WIN8 DXGK_DISPLAY_INFORMATION DisplayInfo; Status = pDevExt->u.primary.DxgkInterface.DxgkCbAcquirePostDisplayOwnership(pDevExt->u.primary.DxgkInterface.DeviceHandle, @@ -1181,6 +1125,8 @@ NTSTATUS DxgkDdiStartDevice( WARN(("DxgkCbAcquirePostDisplayOwnership failed, Status 0x%x", Status)); } #endif + + VBoxWddmInitVideoModes(pDevExt); } else { @@ -1226,10 +1172,14 @@ NTSTATUS DxgkDdiStopDevice( PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext; NTSTATUS Status = STATUS_SUCCESS; + VBoxMpCrShgsmiTransportTerm(&pDevExt->CrHgsmiTransport); + VBoxWddmSlTerm(pDevExt); vboxVideoCmTerm(&pDevExt->CmMgr); + vboxVideoCmTerm(&pDevExt->SeamlessCtxMgr); + /* do everything we did on DxgkDdiStartDevice in the reverse order */ #ifdef VBOX_WITH_VIDEOHWACCEL vboxVhwaFree(pDevExt); @@ -1347,7 +1297,148 @@ NTSTATUS DxgkDdiDispatchIoRequest( return STATUS_SUCCESS; } -BOOLEAN DxgkDdiInterruptRoutine( + +BOOLEAN DxgkDdiInterruptRoutineNew( + IN CONST PVOID MiniportDeviceContext, + IN ULONG MessageNumber + ) +{ +// LOGF(("ENTER, context(0x%p), msg(0x%x)", MiniportDeviceContext, MessageNumber)); + + vboxVDbgBreakFv(); + + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext; + BOOLEAN bOur = FALSE; + bool bNeedDpc = FALSE; + if (!VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags) /* If HGSMI is enabled at all. */ + { + WARN(("ISR called with hgsmi disabled!")); + return FALSE; + } + + VBOXVTLIST CtlList; + vboxVtListInit(&CtlList); +#ifdef VBOX_WITH_VIDEOHWACCEL + VBOXVTLIST VhwaCmdList; + vboxVtListInit(&VhwaCmdList); +#endif + + uint32_t flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags; + bOur = (flags & HGSMIHOSTFLAGS_IRQ); + + if (bOur) + VBoxHGSMIClearIrq(&VBoxCommonFromDeviceExt(pDevExt)->hostCtx); + + bNeedDpc |= VBoxCmdVbvaCheckCompletedIrq(pDevExt, &pDevExt->CmdVbva); + + do { + if (flags & HGSMIHOSTFLAGS_GCOMMAND_COMPLETED) + { + /* read the command offset */ + HGSMIOFFSET offCmd = VBoxVideoCmnPortReadUlong(VBoxCommonFromDeviceExt(pDevExt)->guestCtx.port); + if (offCmd == HGSMIOFFSET_VOID) + { + WARN(("void command offset!")); + continue; + } + + uint16_t chInfo; + uint8_t *pvCmd = HGSMIBufferDataAndChInfoFromOffset (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx.Heap.area, offCmd, &chInfo); + if (!pvCmd) + { + WARN(("zero cmd")); + continue; + } + + switch (chInfo) + { + case VBVA_CMDVBVA_CTL: + { + int rc = VBoxSHGSMICommandProcessCompletion (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, (VBOXSHGSMIHEADER*)pvCmd, TRUE /*bool bIrq*/ , &CtlList); + AssertRC(rc); + break; + } +#ifdef VBOX_WITH_VIDEOHWACCEL + case VBVA_VHWA_CMD: + { + vboxVhwaPutList(&VhwaCmdList, (VBOXVHWACMD*)pvCmd); + break; + } +#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */ + default: + AssertBreakpoint(); + } + } + else if (flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) + { + AssertBreakpoint(); + /* @todo: FIXME: implement !!! */ + } + else + break; + + flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags; + + } while (1); + + if (!vboxVtListIsEmpty(&CtlList)) + { + vboxVtListCat(&pDevExt->CtlList, &CtlList); + bNeedDpc = TRUE; + ASMAtomicWriteU32(&pDevExt->fCompletingCommands, 1); + } + + if (!vboxVtListIsEmpty(&VhwaCmdList)) + { + vboxVtListCat(&pDevExt->VhwaCmdList, &VhwaCmdList); + bNeedDpc = TRUE; + ASMAtomicWriteU32(&pDevExt->fCompletingCommands, 1); + } + + bNeedDpc |= !vboxVdmaDdiCmdIsCompletedListEmptyIsr(pDevExt); + + if (bOur) + { +#ifdef VBOX_VDMA_WITH_WATCHDOG + if (flags & HGSMIHOSTFLAGS_WATCHDOG) + { + Assert(0); + } +#endif + if (flags & HGSMIHOSTFLAGS_VSYNC) + { + Assert(0); + DXGKARGCB_NOTIFY_INTERRUPT_DATA notify; + for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) + { + PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i]; + PVBOXWDDM_ALLOCATION pPrimary = pSource->pPrimaryAllocation; + if (pPrimary && pPrimary->AllocData.Addr.offVram != VBOXVIDEOOFFSET_VOID) + { + memset(¬ify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA)); + notify.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC; + /* @todo: !!!this is not correct in case we want source[i]->target[i!=j] mapping */ + notify.CrtcVsync.VidPnTargetId = i; + notify.CrtcVsync.PhysicalAddress.QuadPart = pPrimary->AllocData.Addr.offVram; + pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, ¬ify); + + bNeedDpc = TRUE; + } + } + } + } + + if (pDevExt->bNotifyDxDpc) + bNeedDpc = TRUE; + + if (bNeedDpc) + pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle); + + return bOur; +} + + +static BOOLEAN DxgkDdiInterruptRoutineLegacy( IN CONST PVOID MiniportDeviceContext, IN ULONG MessageNumber ) @@ -1377,6 +1468,10 @@ BOOLEAN DxgkDdiInterruptRoutine( uint32_t flags = VBoxCommonFromDeviceExt(pDevExt)->hostCtx.pfHostFlags->u32HostFlags; bOur = (flags & HGSMIHOSTFLAGS_IRQ); + + if (bOur) + VBoxHGSMIClearIrq(&VBoxCommonFromDeviceExt(pDevExt)->hostCtx); + do { if (flags & HGSMIHOSTFLAGS_GCOMMAND_COMPLETED) @@ -1508,7 +1603,6 @@ BOOLEAN DxgkDdiInterruptRoutine( bNeedDpc = TRUE; } - VBoxHGSMIClearIrq(&VBoxCommonFromDeviceExt(pDevExt)->hostCtx); #if 0 //def DEBUG_misha /* this is not entirely correct since host may concurrently complete some commands and raise a new IRQ while we are here, * still this allows to check that the host flags are correctly cleared after the ISR */ @@ -1552,22 +1646,73 @@ typedef struct VBOXWDDM_GETDPCDATA_CONTEXT BOOLEAN vboxWddmGetDPCDataCallback(PVOID Context) { PVBOXWDDM_GETDPCDATA_CONTEXT pdc = (PVBOXWDDM_GETDPCDATA_CONTEXT)Context; - - vboxVtListDetach2List(&pdc->pDevExt->CtlList, &pdc->data.CtlList); + PVBOXMP_DEVEXT pDevExt = pdc->pDevExt; + vboxVtListDetach2List(&pDevExt->CtlList, &pdc->data.CtlList); #ifdef VBOX_WITH_VDMA - vboxVtListDetach2List(&pdc->pDevExt->DmaCmdList, &pdc->data.DmaCmdList); + vboxVtListDetach2List(&pDevExt->DmaCmdList, &pdc->data.DmaCmdList); #endif #ifdef VBOX_WITH_VIDEOHWACCEL - vboxVtListDetach2List(&pdc->pDevExt->VhwaCmdList, &pdc->data.VhwaCmdList); + vboxVtListDetach2List(&pDevExt->VhwaCmdList, &pdc->data.VhwaCmdList); #endif - vboxVdmaDdiCmdGetCompletedListIsr(pdc->pDevExt, &pdc->data.CompletedDdiCmdQueue); + if (!pDevExt->fCmdVbvaEnabled) + vboxVdmaDdiCmdGetCompletedListIsr(pDevExt, &pdc->data.CompletedDdiCmdQueue); + + pdc->data.bNotifyDpc = pDevExt->bNotifyDxDpc; + pDevExt->bNotifyDxDpc = FALSE; + + ASMAtomicWriteU32(&pDevExt->fCompletingCommands, 0); - pdc->data.bNotifyDpc = pdc->pDevExt->bNotifyDxDpc; - pdc->pDevExt->bNotifyDxDpc = FALSE; return TRUE; } -VOID DxgkDdiDpcRoutine( +static VOID DxgkDdiDpcRoutineNew( + IN CONST PVOID MiniportDeviceContext + ) +{ +// LOGF(("ENTER, context(0x%p)", MiniportDeviceContext)); + + vboxVDbgBreakFv(); + + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext; + + pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle); + + if (ASMAtomicReadU32(&pDevExt->fCompletingCommands)) + { + VBOXWDDM_GETDPCDATA_CONTEXT context = {0}; + BOOLEAN bRet; + + context.pDevExt = pDevExt; + + /* get DPC data at IRQL */ + NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution( + pDevExt->u.primary.DxgkInterface.DeviceHandle, + vboxWddmGetDPCDataCallback, + &context, + 0, /* IN ULONG MessageNumber */ + &bRet); + Assert(Status == STATUS_SUCCESS); + + // if (context.data.bNotifyDpc) + pDevExt->u.primary.DxgkInterface.DxgkCbNotifyDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle); + + if (!vboxVtListIsEmpty(&context.data.CtlList)) + { + int rc = VBoxSHGSMICommandPostprocessCompletion (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx.heapCtx, &context.data.CtlList); + AssertRC(rc); + } +#ifdef VBOX_WITH_VIDEOHWACCEL + if (!vboxVtListIsEmpty(&context.data.VhwaCmdList)) + { + vboxVhwaCompletionListProcess(pDevExt, &context.data.VhwaCmdList); + } +#endif + } +// LOGF(("LEAVE, context(0x%p)", MiniportDeviceContext)); +} + + +static VOID DxgkDdiDpcRoutineLegacy( IN CONST PVOID MiniportDeviceContext ) { @@ -1637,7 +1782,7 @@ NTSTATUS DxgkDdiQueryChildRelations( { ChildRelations[i].ChildDeviceType = TypeVideoOutput; ChildRelations[i].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = D3DKMDT_VOT_HD15; /* VGA */ - ChildRelations[i].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_INTERRUPTIBLE; /* ?? D3DKMDT_MOA_NONE*/ + ChildRelations[i].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE; //D3DKMDT_MOA_INTERRUPTIBLE; /* ?? D3DKMDT_MOA_NONE*/ ChildRelations[i].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE; ChildRelations[i].ChildCapabilities.HpdAwareness = HpdAwarenessInterruptible; /* ?? HpdAwarenessAlwaysConnected; */ ChildRelations[i].AcpiUid = 0; /* */ @@ -1660,20 +1805,24 @@ NTSTATUS DxgkDdiQueryChildStatus( LOGF(("ENTER, context(0x%x)", MiniportDeviceContext)); + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)MiniportDeviceContext; + NTSTATUS Status = STATUS_SUCCESS; switch (ChildStatus->Type) { case StatusConnection: - ChildStatus->HotPlug.Connected = TRUE; + { LOGF(("StatusConnection")); + VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[ChildStatus->ChildUid]; + ChildStatus->HotPlug.Connected = !!pTarget->fConnected; break; + } case StatusRotation: - ChildStatus->Rotation.Angle = 0; LOGF(("StatusRotation")); + ChildStatus->Rotation.Angle = 0; break; default: - LOGREL(("ERROR: status type: %d", ChildStatus->Type)); - AssertBreakpoint(); + WARN(("ERROR: status type: %d", ChildStatus->Type)); Status = STATUS_INVALID_PARAMETER; break; } @@ -1763,7 +1912,7 @@ VOID DxgkDdiUnload( VbglTerminate(); - VBoxWddmVrTerm(); + VBoxVrTerm(); PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL); if (pLogger) @@ -1953,12 +2102,12 @@ NTSTATUS APIENTRY DxgkDdiQueryAdapterInfo( if (!g_VBoxDisplayOnly) #endif { - Assert (pQueryAdapterInfo->OutputDataSize >= sizeof (VBOXWDDM_QI)); - if (pQueryAdapterInfo->OutputDataSize >= sizeof (VBOXWDDM_QI)) + if (pQueryAdapterInfo->OutputDataSize == sizeof (VBOXWDDM_QI)) { VBOXWDDM_QI * pQi = (VBOXWDDM_QI*)pQueryAdapterInfo->pOutputData; memset (pQi, 0, sizeof (VBOXWDDM_QI)); pQi->u32Version = VBOXVIDEOIF_VERSION; + pQi->u32VBox3DCaps = VBoxMpCrGetHostCaps(); pQi->cInfos = VBoxCommonFromDeviceExt(pDevExt)->cDisplays; #ifdef VBOX_WITH_VIDEOHWACCEL for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) @@ -1969,7 +2118,7 @@ NTSTATUS APIENTRY DxgkDdiQueryAdapterInfo( } else { - LOGREL(("buffer too small")); + WARN(("incorrect buffer size %d, expected %d", pQueryAdapterInfo->OutputDataSize, sizeof (VBOXWDDM_QI))); Status = STATUS_BUFFER_TOO_SMALL; } } @@ -2133,8 +2282,6 @@ VOID vboxWddmAllocationCleanup(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAll } case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER: { - if (pAllocation->pSynchEvent) - ObDereferenceObject(pAllocation->pSynchEvent); break; } default: @@ -2237,6 +2384,7 @@ NTSTATUS vboxWddmAllocationCreate(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_RESOURCE pRe { pAllocation->fRcFlags = pAllocInfo->fFlags; pAllocation->AllocData.SurfDesc = pAllocInfo->SurfDesc; + pAllocation->AllocData.hostID = pAllocInfo->hostID; pAllocationInfo->Size = pAllocInfo->SurfDesc.cbSize; @@ -2327,13 +2475,6 @@ NTSTATUS vboxWddmAllocationCreate(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_RESOURCE pRe pAllocationInfo->Flags.CpuVisible = 1; // pAllocationInfo->Flags.SynchronousPaging = 1; pAllocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_MAXIMUM; - if (pAllocInfo->hSynch) - { - Status = ObReferenceObjectByHandle((HANDLE)pAllocInfo->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, - (PVOID*)&pAllocation->pSynchEvent, - NULL); - Assert(Status == STATUS_SUCCESS); - } break; } @@ -2673,9 +2814,59 @@ DxgkDdiReleaseSwizzlingRange( return STATUS_SUCCESS; } -NTSTATUS +static NTSTATUS +APIENTRY +DxgkDdiPatchNew( + CONST HANDLE hAdapter, + CONST DXGKARG_PATCH* pPatch) +{ + /* DxgkDdiPatch should be made pageable. */ + PAGED_CODE(); + + LOGF(("ENTER, context(0x%x)", hAdapter)); + + vboxVDbgBreakFv(); + + uint8_t * pPrivateBuf = (uint8_t*)((uint8_t*)pPatch->pDmaBufferPrivateData + pPatch->DmaBufferPrivateDataSubmissionStartOffset); + UINT cbPatchBuff = pPatch->DmaBufferPrivateDataSubmissionEndOffset - pPatch->DmaBufferPrivateDataSubmissionStartOffset; + + for (UINT i = pPatch->PatchLocationListSubmissionStart; i < pPatch->PatchLocationListSubmissionLength; ++i) + { + const D3DDDI_PATCHLOCATIONLIST* pPatchList = &pPatch->pPatchLocationList[i]; + Assert(pPatchList->AllocationIndex < pPatch->AllocationListSize); + const DXGK_ALLOCATIONLIST *pAllocationList = &pPatch->pAllocationList[pPatchList->AllocationIndex]; + if (!pAllocationList->SegmentId) + { + WARN(("no segment id specified")); + continue; + } + + if (pPatchList->PatchOffset == ~0UL) + { + /* this is a dummy patch request, ignore */ + continue; + } + + if (pPatchList->PatchOffset >= cbPatchBuff) + { + WARN(("pPatchList->PatchOffset(%d) >= cbPatchBuff(%d)", pPatchList->PatchOffset, cbPatchBuff)); + return STATUS_INVALID_PARAMETER; + } + + VBOXCMDVBVAOFFSET *poffVram = (VBOXCMDVBVAOFFSET*)(pPrivateBuf + pPatchList->PatchOffset); + Assert(pAllocationList->SegmentId); + Assert(!pAllocationList->PhysicalAddress.HighPart); + Assert(!(pAllocationList->PhysicalAddress.QuadPart & 0xfffUL)); /* <- just a check to ensure allocation offset does not go here */ + *poffVram = pAllocationList->PhysicalAddress.LowPart + pPatchList->AllocationOffset;; + } + + return STATUS_SUCCESS; +} + + +static NTSTATUS APIENTRY -DxgkDdiPatch( +DxgkDdiPatchLegacy( CONST HANDLE hAdapter, CONST DXGKARG_PATCH* pPatch) { @@ -2815,7 +3006,7 @@ DxgkDdiPatch( else if (pPatch->DmaBufferPrivateDataSubmissionEndOffset == pPatch->DmaBufferPrivateDataSubmissionStartOffset) { /* this is a NOP, just return success */ - WARN(("null data size, treating as NOP")); +// LOG(("null data size, treating as NOP")); return STATUS_SUCCESS; } else @@ -2841,7 +3032,10 @@ typedef struct VBOXWDDM_CALL_ISR static BOOLEAN vboxWddmCallIsrCb(PVOID Context) { PVBOXWDDM_CALL_ISR pdc = (PVBOXWDDM_CALL_ISR)Context; - return DxgkDdiInterruptRoutine(pdc->pDevExt, pdc->MessageNumber); + PVBOXMP_DEVEXT pDevExt = pdc->pDevExt; + if (pDevExt->fCmdVbvaEnabled) + return DxgkDdiInterruptRoutineNew(pDevExt, pdc->MessageNumber); + return DxgkDdiInterruptRoutineLegacy(pDevExt, pdc->MessageNumber); } NTSTATUS vboxWddmCallIsr(PVBOXMP_DEVEXT pDevExt) @@ -2860,54 +3054,6 @@ NTSTATUS vboxWddmCallIsr(PVBOXMP_DEVEXT pDevExt) return Status; } -static NTSTATUS vboxWddmSubmitCmd(PVBOXMP_DEVEXT pDevExt, VBOXVDMAPIPE_CMD_DMACMD *pCmd) -{ - NTSTATUS Status = vboxVdmaGgCmdDmaNotifySubmitted(pDevExt, pCmd); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - { - NTSTATUS submStatus = vboxVdmaGgCmdSubmit(pDevExt, &pCmd->Hdr); - Assert(submStatus == STATUS_SUCCESS); - if (submStatus != STATUS_SUCCESS) - { - vboxVdmaGgCmdDmaNotifyCompleted(pDevExt, pCmd, DXGK_INTERRUPT_DMA_FAULTED); - } - } - else - { - vboxVdmaGgCmdRelease(pDevExt, &pCmd->Hdr); - } - return Status; -} - -static NTSTATUS vboxWddmSubmitBltCmd(PVBOXMP_DEVEXT pDevExt, VBOXWDDM_CONTEXT *pContext, UINT u32FenceId, PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt, VBOXVDMAPIPE_FLAGS_DMACMD fBltFlags) -{ - NTSTATUS Status = STATUS_SUCCESS; - PVBOXVDMAPIPE_CMD_DMACMD_BLT pBltCmd = (PVBOXVDMAPIPE_CMD_DMACMD_BLT)vboxVdmaGgCmdCreate(pDevExt, VBOXVDMAPIPE_CMD_TYPE_DMACMD, RT_OFFSETOF(VBOXVDMAPIPE_CMD_DMACMD_BLT, Blt.DstRects.UpdateRects.aRects[pBlt->Blt.DstRects.UpdateRects.cRects])); - Assert(pBltCmd); - if (pBltCmd) - { - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pBlt->Blt.DstAlloc.srcId]; - vboxVdmaGgCmdDmaNotifyInit(&pBltCmd->Hdr, pContext->NodeOrdinal, u32FenceId, vboxVdmaGgDdiCmdRelease, pBltCmd); - pBltCmd->Hdr.fFlags = fBltFlags; - pBltCmd->Hdr.pContext = pContext; - pBltCmd->Hdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT; - memcpy(&pBltCmd->Blt, &pBlt->Blt, RT_OFFSETOF(VBOXVDMA_BLT, DstRects.UpdateRects.aRects[pBlt->Blt.DstRects.UpdateRects.cRects])); - Status = vboxWddmSubmitCmd(pDevExt, &pBltCmd->Hdr); - if (Status != STATUS_SUCCESS) - { - WARN(("vboxWddmSubmitCmd failed, Status 0x%x", Status)); - Status = STATUS_SUCCESS; - } - vboxVdmaGgCmdRelease(pDevExt, &pBltCmd->Hdr.Hdr); - } - else - { - Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, u32FenceId, DXGK_INTERRUPT_DMA_FAULTED); - } - return Status; -} - #ifdef VBOX_WITH_CRHGSMI DECLCALLBACK(VOID) vboxWddmDmaCompleteChromiumCmd(PVBOXMP_DEVEXT pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext) { @@ -2915,25 +3061,56 @@ DECLCALLBACK(VOID) vboxWddmDmaCompleteChromiumCmd(PVBOXMP_DEVEXT pDevExt, PVBOXV PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD); VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD); UINT cBufs = pBody->cBuffers; - for (UINT i = 0; i < cBufs; ++i) + vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr); +} +#endif + +static NTSTATUS +APIENTRY +DxgkDdiSubmitCommandNew( + CONST HANDLE hAdapter, + CONST DXGKARG_SUBMITCOMMAND* pSubmitCommand) +{ + /* DxgkDdiSubmitCommand runs at dispatch, should not be pageable. */ + +// LOGF(("ENTER, context(0x%x)", hAdapter)); + + vboxVDbgBreakFv(); + + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter; +#ifdef DEBUG + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pSubmitCommand->hContext; + Assert(pContext); + Assert(pContext->pDevice); + Assert(pContext->pDevice->pAdapter == pDevExt); + Assert(!pSubmitCommand->DmaBufferSegmentId); +#endif + + /* the DMA command buffer is located in system RAM, the host will need to pick it from there */ + //BufInfo.fFlags = 0; /* see VBOXVDMACBUF_FLAG_xx */ + uint32_t cbCmd = pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset - pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset; + if (cbCmd < sizeof (VBOXCMDVBVA_HDR)) { - VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i]; - if (!pBufCmd->u32GuestData) - { - /* signal completion */ - PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBufCmd->u64GuestData; - if (pAlloc->pSynchEvent) - KeSetEvent(pAlloc->pSynchEvent, 3, FALSE); - } + WARN(("DmaBufferPrivateDataSubmissionEndOffset (%d) - DmaBufferPrivateDataSubmissionStartOffset (%d) < sizeof (VBOXCMDVBVA_HDR) (%d)", + pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset, + pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset, + sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))); + return STATUS_INVALID_PARAMETER; } - vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr); + VBOXCMDVBVA_HDR *pHdr = (VBOXCMDVBVA_HDR*)((uint8_t*)pSubmitCommand->pDmaBufferPrivateData + pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset); + pHdr->u32FenceID = pSubmitCommand->SubmissionFenceId; + int rc = VBoxCmdVbvaSubmit(pDevExt, &pDevExt->CmdVbva, pHdr, cbCmd); + if (RT_SUCCESS(rc)) + return STATUS_SUCCESS; + + WARN(("VBoxCmdVbvaSubmit failed rc %d", rc)); + return STATUS_UNSUCCESSFUL; } -#endif -NTSTATUS +static NTSTATUS APIENTRY -DxgkDdiSubmitCommand( +DxgkDdiSubmitCommandLegacy( CONST HANDLE hAdapter, CONST DXGKARG_SUBMITCOMMAND* pSubmitCommand) { @@ -2963,7 +3140,6 @@ DxgkDdiSubmitCommand( } else if (pSubmitCommand->DmaBufferPrivateDataSubmissionEndOffset == pSubmitCommand->DmaBufferPrivateDataSubmissionStartOffset) { - WARN(("null data size, treating as NOP")); enmCmd = VBOXVDMACMD_TYPE_DMA_NOP; } else @@ -2978,8 +3154,6 @@ DxgkDdiSubmitCommand( if (pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_2D) vboxWddmModeRenderFromShadowDisableRegister(pDevExt, pContext); - BOOLEAN fRenderFromSharedDisabled = pDevExt->fRenderToShadowDisabled; - switch (enmCmd) { #ifdef VBOXWDDM_RENDER_FROM_SHADOW @@ -2988,10 +3162,12 @@ DxgkDdiSubmitCommand( PVBOXWDDM_DMA_PRIVATEDATA_SHADOW2PRIMARY pS2P = (PVBOXWDDM_DMA_PRIVATEDATA_SHADOW2PRIMARY)pPrivateDataBase; VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pS2P->Shadow2Primary.VidPnSourceId]; PVBOXWDDM_ALLOCATION pSrcAlloc = pS2P->Shadow2Primary.ShadowAlloc.pAlloc; - vboxWddmAddrSetVram(&pSrcAlloc->AllocData.Addr, pS2P->Shadow2Primary.ShadowAlloc.segmentIdAlloc, pS2P->Shadow2Primary.ShadowAlloc.offAlloc); + BOOLEAN fShadowChanged = vboxWddmAddrSetVram(&pSrcAlloc->AllocData.Addr, pS2P->Shadow2Primary.ShadowAlloc.segmentIdAlloc, pS2P->Shadow2Primary.ShadowAlloc.offAlloc); + if (fShadowChanged) + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; vboxWddmAssignShadow(pDevExt, pSource, pSrcAlloc, pS2P->Shadow2Primary.VidPnSourceId); - fRenderFromSharedDisabled = vboxWddmModeRenderFromShadowCheckOnSubmitCommand(pDevExt, NULL); - vboxWddmCheckUpdateFramebufferAddress(pDevExt, pSource); + vboxWddmModeRenderFromShadowCheckOnSubmitCommand(pDevExt, NULL); + vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource); if (pSrcAlloc->bVisible) { uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled); @@ -3014,253 +3190,77 @@ DxgkDdiSubmitCommand( PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateData; PVBOXWDDM_ALLOCATION pDstAlloc = pBlt->Blt.DstAlloc.pAlloc; PVBOXWDDM_ALLOCATION pSrcAlloc = pBlt->Blt.SrcAlloc.pAlloc; + BOOLEAN fSrcChanged; + BOOLEAN fDstChanged; - vboxWddmAddrSetVram(&pDstAlloc->AllocData.Addr, pBlt->Blt.DstAlloc.segmentIdAlloc, pBlt->Blt.DstAlloc.offAlloc); - vboxWddmAddrSetVram(&pSrcAlloc->AllocData.Addr, pBlt->Blt.SrcAlloc.segmentIdAlloc, pBlt->Blt.SrcAlloc.offAlloc); + fDstChanged = vboxWddmAddrSetVram(&pDstAlloc->AllocData.Addr, pBlt->Blt.DstAlloc.segmentIdAlloc, pBlt->Blt.DstAlloc.offAlloc); + fSrcChanged = vboxWddmAddrSetVram(&pSrcAlloc->AllocData.Addr, pBlt->Blt.SrcAlloc.segmentIdAlloc, pBlt->Blt.SrcAlloc.offAlloc); - uint32_t cContexts3D = ASMAtomicReadU32(&pDevExt->cContexts3D); + vboxWddmModeRenderFromShadowCheckOnSubmitCommand(pDevExt, NULL); - VBOXVDMAPIPE_FLAGS_DMACMD fBltFlags; - fBltFlags.Value = 0; - - if (pDstAlloc->bAssigned && - (pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE - || pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE) - ) + if (VBOXWDDM_IS_REAL_FB_ALLOCATION(pDevExt, pDstAlloc)) { VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId]; - Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS); - if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE) - vboxWddmAssignShadow(pDevExt, pSource, pSrcAlloc, pDstAlloc->AllocData.SurfDesc.VidPnSourceId); - fRenderFromSharedDisabled = vboxWddmModeRenderFromShadowCheckOnSubmitCommand(pDevExt, NULL); - if(pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D - || pDstAlloc->enmType !=VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC) - vboxWddmCheckUpdateFramebufferAddress(pDevExt, pSource); - } - else if (pSrcAlloc->bAssigned && - (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE - || pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE) - ) - { - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId]; Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS); - - if (pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE) - vboxWddmAssignShadow(pDevExt, pSource, pDstAlloc, pSrcAlloc->AllocData.SurfDesc.VidPnSourceId); - fRenderFromSharedDisabled = vboxWddmModeRenderFromShadowCheckOnSubmitCommand(pDevExt, NULL); - if(pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D - || pSrcAlloc->enmType !=VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC) - vboxWddmCheckUpdateFramebufferAddress(pDevExt, pSource); - } - - if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D && fRenderFromSharedDisabled) - fBltFlags.fRealOp = 1; - - switch (pDstAlloc->enmType) - { - case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE: - case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC: +#if 0 + if (VBOXWDDM_IS_FB_ALLOCATION(pDevExt, pDstAlloc) && pDstAlloc->AllocData.hostID) { - if (pDstAlloc->bAssigned) + if (pSource->AllocData.hostID != pDstAlloc->AllocData.hostID) { -// Assert(pSource->pPrimaryAllocation == pDstAlloc); - - switch (pSrcAlloc->enmType) - { - case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE: - { - fBltFlags.fVisibleRegions = !!cContexts3D; - Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_SYSTEM); - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pDstAlloc->AllocData.SurfDesc.VidPnSourceId]; - Assert(pDstAlloc->AllocData.SurfDesc.VidPnSourceId < VBOX_VIDEO_MAX_SCREENS); - - if (!fRenderFromSharedDisabled && pSource->bVisible) - { - RECT rect; - if (pBlt->Blt.DstRects.UpdateRects.cRects) - { - rect = pBlt->Blt.DstRects.UpdateRects.aRects[0]; - for (UINT i = 1; i < pBlt->Blt.DstRects.UpdateRects.cRects; ++i) - { - vboxWddmRectUnited(&rect, &rect, &pBlt->Blt.DstRects.UpdateRects.aRects[i]); - } - } - else - rect = pBlt->Blt.DstRects.ContextRect; - - uint32_t cUnlockedVBVADisabled = ASMAtomicReadU32(&pDevExt->cUnlockedVBVADisabled); - if (!cUnlockedVBVADisabled) - { - VBOXVBVA_OP(ReportDirtyRect, pDevExt, pSource, &rect); - } - else - { - VBOXVBVA_OP_WITHLOCK_ATDPC(ReportDirtyRect, pDevExt, pSource, &rect); - } - } - - break; - } - case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC: - { - if(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D) - { - Assert(pSrcAlloc->fRcFlags.RenderTarget); - if (pSrcAlloc->fRcFlags.RenderTarget) - fBltFlags.fVisibleRegions = 1; - } - break; - } - default: - { - AssertBreakpoint(); - break; - } - } + pSource->AllocData.hostID = pDstAlloc->AllocData.hostID; + fDstChanged = TRUE; } - break; - } - case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE: - { -// Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D); - Assert(pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC); - Assert(pSrcAlloc->fRcFlags.RenderTarget); - Assert(vboxWddmRectIsEqual(&pBlt->Blt.SrcRect, &pBlt->Blt.DstRects.ContextRect)); - Assert(pBlt->Blt.DstRects.UpdateRects.cRects == 1); - Assert(vboxWddmRectIsEqual(&pBlt->Blt.SrcRect, pBlt->Blt.DstRects.UpdateRects.aRects)); - break; + if (fDstChanged) + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; } - case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE: + else +#endif + if (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE) { - Assert(pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE); - Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_SYSTEM); - break; + if (fSrcChanged) + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; + + vboxWddmAssignShadow(pDevExt, pSource, pSrcAlloc, pDstAlloc->AllocData.SurfDesc.VidPnSourceId); + vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource); } - default: - AssertBreakpoint(); - break; - } - if (fBltFlags.Value) - { - Status = vboxWddmSubmitBltCmd(pDevExt, pContext, pSubmitCommand->SubmissionFenceId, pBlt, fBltFlags); - } - else - { - Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, DXGK_INTERRUPT_DMA_COMPLETED); + Assert(pSource->u8SyncState == VBOXWDDM_HGSYNC_F_SYNCED_ALL || pDevExt->aTargets[pDstAlloc->AllocData.SurfDesc.VidPnSourceId].fStateSyncPening); } - break; - } - case VBOXVDMACMD_TYPE_CHROMIUM_CMD: - { -#ifdef VBOX_WITH_CRHGSMI - VBOXWDDM_DMA_PRIVATEDATA_CHROMIUM_CMD *pChromiumCmd = (VBOXWDDM_DMA_PRIVATEDATA_CHROMIUM_CMD*)pPrivateDataBase; - UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[pChromiumCmd->Base.u32CmdReserved])); - PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate (&pDevExt->u.primary.Vdma, cbCmd); - if (!pDr) - { - /* @todo: try flushing.. */ - LOGREL(("vboxVdmaCBufDrCreate returned NULL")); - return STATUS_INSUFFICIENT_RESOURCES; - } - // vboxVdmaCBufDrCreate zero initializes the pDr - 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_CHROMIUM_CMD; - pHdr->u32CmdSpecific = 0; - VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD); - pBody->cBuffers = pChromiumCmd->Base.u32CmdReserved; - for (UINT i = 0; i < pChromiumCmd->Base.u32CmdReserved; ++i) - { - VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i]; - VBOXWDDM_UHGSMI_BUFFER_SUBMIT_INFO *pBufInfo = &pChromiumCmd->aBufInfos[i]; - - pBufCmd->offBuffer = pBufInfo->Alloc.offAlloc; - pBufCmd->cbBuffer = pBufInfo->cbData; - pBufCmd->u32GuestData = pBufInfo->bDoNotSignalCompletion; - pBufCmd->u64GuestData = (uint64_t)pBufInfo->Alloc.pAlloc; - } + Status = vboxVdmaProcessBltCmd(pDevExt, pContext, pBlt); + if (!NT_SUCCESS(Status)) + WARN(("vboxVdmaProcessBltCmd failed, Status 0x%x", Status)); - PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr); - vboxVdmaDdiCmdInit(pDdiCmd, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, vboxWddmDmaCompleteChromiumCmd, pDr); - NTSTATUS Status = vboxVdmaDdiCmdSubmitted(pDevExt, pDdiCmd); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - { - int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr); - Assert(rc == VINF_SUCCESS); - } - else - { - vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr); - } -#else - Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, DXGK_INTERRUPT_DMA_COMPLETED); - Assert(Status == STATUS_SUCCESS); -#endif + Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, + NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED); break; } case VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP: { VBOXWDDM_DMA_PRIVATEDATA_FLIP *pFlip = (VBOXWDDM_DMA_PRIVATEDATA_FLIP*)pPrivateDataBase; - vboxWddmAddrSetVram(&pFlip->Flip.Alloc.pAlloc->AllocData.Addr, pFlip->Flip.Alloc.segmentIdAlloc, pFlip->Flip.Alloc.offAlloc); - PVBOXVDMAPIPE_CMD_DMACMD_FLIP pFlipCmd = (PVBOXVDMAPIPE_CMD_DMACMD_FLIP)vboxVdmaGgCmdCreate(pDevExt, - VBOXVDMAPIPE_CMD_TYPE_DMACMD, sizeof (VBOXVDMAPIPE_CMD_DMACMD_FLIP)); - Assert(pFlipCmd); - if (pFlipCmd) - { - VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pFlip->Flip.Alloc.srcId]; - vboxVdmaGgCmdDmaNotifyInit(&pFlipCmd->Hdr, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, vboxVdmaGgDdiCmdRelease, pFlipCmd); - pFlipCmd->Hdr.fFlags.Value = 0; - pFlipCmd->Hdr.fFlags.fVisibleRegions = 1; - pFlipCmd->Hdr.pContext = pContext; - pFlipCmd->Hdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP; - memcpy(&pFlipCmd->Flip, &pFlip->Flip, sizeof (pFlipCmd->Flip)); - Status = vboxWddmSubmitCmd(pDevExt, &pFlipCmd->Hdr); - if (Status != STATUS_SUCCESS) - WARN(("vboxWddmSubmitCmd failed, Status 0x%x", Status)); - vboxVdmaGgCmdRelease(pDevExt, &pFlipCmd->Hdr.Hdr); - } - else - { - Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, DXGK_INTERRUPT_DMA_FAULTED); - Assert(Status == STATUS_SUCCESS); - } + PVBOXWDDM_ALLOCATION pAlloc = pFlip->Flip.Alloc.pAlloc; + VBOXWDDM_SOURCE *pSource = &pDevExt->aSources[pAlloc->AllocData.SurfDesc.VidPnSourceId]; + vboxWddmAddrSetVram(&pAlloc->AllocData.Addr, pFlip->Flip.Alloc.segmentIdAlloc, pFlip->Flip.Alloc.offAlloc); + vboxWddmAssignPrimary(pDevExt, pSource, pAlloc, pAlloc->AllocData.SurfDesc.VidPnSourceId); + vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource); + + Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, + NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED); break; } case VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL: { PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateDataBase; vboxWddmAddrSetVram(&pCF->ClrFill.Alloc.pAlloc->AllocData.Addr, pCF->ClrFill.Alloc.segmentIdAlloc, pCF->ClrFill.Alloc.offAlloc); - PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL pCFCmd = (PVBOXVDMAPIPE_CMD_DMACMD_CLRFILL)vboxVdmaGgCmdCreate(pDevExt, - VBOXVDMAPIPE_CMD_TYPE_DMACMD, RT_OFFSETOF(VBOXVDMAPIPE_CMD_DMACMD_CLRFILL, ClrFill.Rects.aRects[pCF->ClrFill.Rects.cRects])); - Assert(pCFCmd); - if (pCFCmd) - { - vboxVdmaGgCmdDmaNotifyInit(&pCFCmd->Hdr, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, vboxVdmaGgDdiCmdRelease, pCFCmd); - pCFCmd->Hdr.fFlags.Value = 0; - pCFCmd->Hdr.fFlags.fRealOp = 1; - pCFCmd->Hdr.pContext = pContext; - pCFCmd->Hdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL; - memcpy(&pCFCmd->ClrFill, &pCF->ClrFill, RT_OFFSETOF(VBOXVDMA_CLRFILL, Rects.aRects[pCF->ClrFill.Rects.cRects])); - Status = vboxWddmSubmitCmd(pDevExt, &pCFCmd->Hdr); - if (Status != STATUS_SUCCESS) - WARN(("vboxWddmSubmitCmd failed, Status 0x%x", Status)); - vboxVdmaGgCmdRelease(pDevExt, &pCFCmd->Hdr.Hdr); - } - else - { - Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, DXGK_INTERRUPT_DMA_FAULTED); - Assert(Status == STATUS_SUCCESS); - } + Status = vboxVdmaProcessClrFillCmd(pDevExt, pContext, pCF); + if (!NT_SUCCESS(Status)) + WARN(("vboxVdmaProcessClrFillCmd failed, Status 0x%x", Status)); + Status = vboxVdmaDdiCmdFenceComplete(pDevExt, pContext->NodeOrdinal, pSubmitCommand->SubmissionFenceId, + NT_SUCCESS(Status) ? DXGK_INTERRUPT_DMA_COMPLETED : DXGK_INTERRUPT_DMA_FAULTED); break; } case VBOXVDMACMD_TYPE_DMA_NOP: @@ -3302,9 +3302,27 @@ DxgkDdiSubmitCommand( return Status; } -NTSTATUS +static NTSTATUS APIENTRY -DxgkDdiPreemptCommand( +DxgkDdiPreemptCommandNew( + CONST HANDLE hAdapter, + CONST DXGKARG_PREEMPTCOMMAND* pPreemptCommand) +{ + LOGF(("ENTER, hAdapter(0x%x)", hAdapter)); + + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter; + + VBoxCmdVbvaPreempt(pDevExt, &pDevExt->CmdVbva, pPreemptCommand->PreemptionFenceId); + + LOGF(("LEAVE, hAdapter(0x%x)", hAdapter)); + + return STATUS_SUCCESS; +} + + +static NTSTATUS +APIENTRY +DxgkDdiPreemptCommandLegacy( CONST HANDLE hAdapter, CONST DXGKARG_PREEMPTCOMMAND* pPreemptCommand) { @@ -3318,103 +3336,159 @@ DxgkDdiPreemptCommand( return STATUS_SUCCESS; } -#if 0 -static uint32_t vboxWddmSysMemElBuild(PVBOXVDMACMD_SYSMEMEL pEl, PMDL pMdl, uint32_t iPfn, uint32_t cPages, uint32_t cbBuffer, uint32_t *pcPagesRemaining) -{ - uint32_t cbInitialBuffer = cbBuffer; - if (cbBuf >= sizeof (*pEl)) - { - PFN_NUMBER cur = MmGetMdlPfnArray(pMdl)[iPfn]; - uint32_t cbEl = sizeof (*pEl); - uint32_t cBufs = 1; - pEl->phBuf[0] = (cur << 12); - --cPages; - cbBuffer -= sizeof (*pEl); - bool bArrayMode = false; - while (cPages) - { - PFN_NUMBER next = MmGetMdlPfnArray(pMdl)[iPfn+cBufs]; - if (!bArrayMode) +/* + * DxgkDdiBuildPagingBuffer + */ +static NTSTATUS +APIENTRY +DxgkDdiBuildPagingBufferNew( + CONST HANDLE hAdapter, + DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer) +{ + /* DxgkDdiBuildPagingBuffer should be made pageable. */ + PAGED_CODE(); + + vboxVDbgBreakFv(); + + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter; + uint32_t cbBuffer = 0, cbPrivateData = 0; + + LOGF(("ENTER, context(0x%x)", hAdapter)); + + /* paging buffer transfer is nop for hostID allocations */ + if (pBuildPagingBuffer->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_HDR)) + { + WARN(("pBuildPagingBuffer->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_HDR (%d)", pBuildPagingBuffer->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_HDR))); + /* @todo: can this actually happen? what status to return? */ + return STATUS_INVALID_PARAMETER; + } + + switch (pBuildPagingBuffer->Operation) + { + case DXGK_OPERATION_TRANSFER: + { + VBOXCMDVBVA_HDR *pHdr = (VBOXCMDVBVA_HDR*)pBuildPagingBuffer->pDmaBuffer; + pHdr->u8Flags = 0; + pHdr->u8State = VBOXCMDVBVA_STATE_SUBMITTED; + /* sanity */ + pHdr->u32FenceID = 0; + + if ((!pBuildPagingBuffer->Transfer.Source.SegmentId) == (!pBuildPagingBuffer->Transfer.Destination.SegmentId)) { - if (next == cur+1) - { - cur = next; - ++cBufs; - --cPages; - } - else if (cBufs > 1) - { - break; - } - else - { - bArrayMode = true; - } + WARN(("we only support RAM <-> VRAM moves, Src Seg(%d), Dst Seg(%d)", pBuildPagingBuffer->Transfer.Source.SegmentId, pBuildPagingBuffer->Transfer.Destination.SegmentId)); + return STATUS_INVALID_PARAMETER; + } + + PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->Transfer.hAllocation; + if (!pAlloc) + { + WARN(("allocation is null")); + return STATUS_INVALID_PARAMETER; } - /* array mode */ - if (cbBuffer < sizeof (pEl->phBuf[0])) + if (pAlloc->AllocData.hostID) { + pHdr->u8OpCode = VBOXCMDVBVA_OPTYPE_NOPCMD; + cbBuffer = VBOXWDDM_DUMMY_DMABUFFER_SIZE; + cbPrivateData = sizeof (*pHdr); break; } - pEl->phBuf[cBufs] = (next << 12); - cbBuffer -= sizeof (pEl->phBuf[0]); - ++cBufs; - --cPages; - } + if (pBuildPagingBuffer->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_PAGING_TRANSFER)) + { + WARN(("pBuildPagingBuffer->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_PAGING_TRANSFER (%d)", pBuildPagingBuffer->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_PAGING_TRANSFER))); + /* @todo: can this actually happen? what status to return? */ + return STATUS_INVALID_PARAMETER; + } - pEl->cPages = cPages; - if (bArrayMode) - pEl->fFlags = VBOXVDMACMD_SYSMEMEL_F_PAGELIST; - else - pEl->fFlags = 0; - } - else - { - Assert(0); - } + VBOXCMDVBVA_PAGING_TRANSFER *pPaging = (VBOXCMDVBVA_PAGING_TRANSFER*)pBuildPagingBuffer->pDmaBuffer; + pPaging->Hdr.u8OpCode = VBOXCMDVBVA_OPTYPE_PAGING_TRANSFER; - *pcPagesRemaining = cPages; - return cbInitialBuffer - cbBuffer; -} + PMDL pMdl; + uint32_t offVRAM; + BOOLEAN fIn; -static uint32_t vboxWddmBpbTransferVRamSysBuildEls(PVBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS pCmd, PMDL pMdl, uint32_t iPfn, uint32_t cPages, uint32_t cbBuffer, uint32_t *pcPagesRemaining) -{ - uint32_t cInitPages = cPages; - uint32_t cbBufferUsed = vboxWddmSysMemElBuild(&pCmd->FirstEl, pMdl, iPfn, cPages, cbBuffer, &cPages); - if (cbBufferUsed) - { - uint32_t cEls = 1; - PVBOXVDMACMD_SYSMEMEL pEl = &pCmd->FirstEl; - while (cPages) - { - PVBOXVDMACMD_SYSMEMEL pEl = VBOXVDMACMD_SYSMEMEL_NEXT(pEl); - cbBufferUsed = vboxWddmSysMemElBuild(pEl, pMdl, iPfn + cInitPages - cPages, cPages, cbBuffer - cbBufferUsed, &cPages); - if (cbBufferUsed) + if (pBuildPagingBuffer->Transfer.Source.SegmentId) { - ++cEls; + Assert(!pBuildPagingBuffer->Transfer.Destination.SegmentId); + Assert(!pBuildPagingBuffer->Transfer.Source.SegmentAddress.HighPart); + offVRAM = pBuildPagingBuffer->Transfer.Source.SegmentAddress.LowPart; + pMdl = pBuildPagingBuffer->Transfer.Destination.pMdl; + fIn = FALSE; } else - break; + { + Assert(pBuildPagingBuffer->Transfer.Destination.SegmentId); + Assert(!pBuildPagingBuffer->Transfer.Source.SegmentId); + Assert(!pBuildPagingBuffer->Transfer.Destination.SegmentAddress.HighPart); + offVRAM = pBuildPagingBuffer->Transfer.Destination.SegmentAddress.LowPart; + pMdl = pBuildPagingBuffer->Transfer.Source.pMdl; + fIn = TRUE; + } + + uint32_t cPages = (uint32_t)((pBuildPagingBuffer->Transfer.TransferSize + 0xfff) >> PAGE_SHIFT); + uint32_t cTotalPages = cPages; + cPages -= pBuildPagingBuffer->MultipassOffset; + uint32_t iFirstPage = pBuildPagingBuffer->Transfer.MdlOffset + pBuildPagingBuffer->MultipassOffset; + uint32_t cPagesWritten; + offVRAM += pBuildPagingBuffer->Transfer.TransferOffset + pBuildPagingBuffer->MultipassOffset; + + pPaging->Alloc.u.offVRAM = offVRAM; + if (fIn) + pPaging->Hdr.u8Flags |= VBOXCMDVBVA_OPF_PAGING_TRANSFER_IN; + cbPrivateData = VBoxCVDdiPTransferVRamSysBuildEls(pPaging, pMdl, iFirstPage, cPages, pBuildPagingBuffer->DmaBufferPrivateDataSize, &cPagesWritten); + if (cPagesWritten != cPages) + pBuildPagingBuffer->MultipassOffset += cPagesWritten; + else + pBuildPagingBuffer->MultipassOffset = 0; + + cbBuffer = VBOXWDDM_DUMMY_DMABUFFER_SIZE; + break; + } + case DXGK_OPERATION_FILL: + { + Assert(pBuildPagingBuffer->Fill.FillPattern == 0); + PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->Fill.hAllocation; + if (!pAlloc) + { + WARN(("allocation is null")); + return STATUS_INVALID_PARAMETER; + } + /** @todo: add necessary bits */ + WARN(("Impl!")); + break; + } + case DXGK_OPERATION_DISCARD_CONTENT: + { + PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->DiscardContent.hAllocation; + if (!pAlloc) + { + WARN(("allocation is null")); + return STATUS_INVALID_PARAMETER; + } + break; + } + default: + { + WARN(("unsupported op (%d)", pBuildPagingBuffer->Operation)); + break; } } - else - { - Assert(0); - } - pCmd->cTransferPages = (cInitPages - cPages); - *pcPagesRemaining = cPages; - return cbBufferUsed; + pBuildPagingBuffer->pDmaBuffer = ((uint8_t*)pBuildPagingBuffer->pDmaBuffer) + cbBuffer; + pBuildPagingBuffer->pDmaBufferPrivateData = ((uint8_t*)pBuildPagingBuffer->pDmaBufferPrivateData) + cbPrivateData; + + LOGF(("LEAVE, context(0x%x)", hAdapter)); + + if (pBuildPagingBuffer->MultipassOffset) + return STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; + return STATUS_SUCCESS; } -#endif -/* - * DxgkDdiBuildPagingBuffer - */ -NTSTATUS + + +static NTSTATUS APIENTRY -DxgkDdiBuildPagingBuffer( +DxgkDdiBuildPagingBufferLegacy( CONST HANDLE hAdapter, DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer) { @@ -3428,11 +3502,14 @@ DxgkDdiBuildPagingBuffer( LOGF(("ENTER, context(0x%x)", hAdapter)); + uint32_t cbCmdDma = 0; + /* @todo: */ switch (pBuildPagingBuffer->Operation) { case DXGK_OPERATION_TRANSFER: { + cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE; #ifdef VBOX_WITH_VDMA #if 0 if ((!pBuildPagingBuffer->Transfer.Source.SegmentId) != (!pBuildPagingBuffer->Transfer.Destination.SegmentId)) @@ -3583,6 +3660,7 @@ DxgkDdiBuildPagingBuffer( } case DXGK_OPERATION_FILL: { + cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE; Assert(pBuildPagingBuffer->Fill.FillPattern == 0); PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pBuildPagingBuffer->Fill.hAllocation; // pBuildPagingBuffer->pDmaBuffer = (uint8_t*)pBuildPagingBuffer->pDmaBuffer + VBOXVDMACMD_SIZE(VBOXVDMACMD_DMA_BPB_FILL); @@ -3595,12 +3673,16 @@ DxgkDdiBuildPagingBuffer( } default: { - LOGREL(("unsupported op (%d)", pBuildPagingBuffer->Operation)); - AssertBreakpoint(); + WARN(("unsupported op (%d)", pBuildPagingBuffer->Operation)); break; } } + if (cbCmdDma) + { + pBuildPagingBuffer->pDmaBuffer = ((uint8_t*)pBuildPagingBuffer->pDmaBuffer) + cbCmdDma; + } + LOGF(("LEAVE, context(0x%x)", hAdapter)); return Status; @@ -3929,6 +4011,12 @@ DxgkDdiEscape( #ifdef VBOX_WITH_CRHGSMI case VBOXESC_UHGSMI_SUBMIT: { + if (pDevExt->fCmdVbvaEnabled) + { + WARN(("VBOXESC_UHGSMI_SUBMIT not supported for CmdVbva mode")); + Status = STATUS_INVALID_PARAMETER; + break; + } /* submit VBOXUHGSMI command */ PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; PVBOXDISPIFESCAPE_UHGSMI_SUBMIT pSubmit = (PVBOXDISPIFESCAPE_UHGSMI_SUBMIT)pEscapeHdr; @@ -3949,6 +4037,13 @@ DxgkDdiEscape( case VBOXESC_UHGSMI_ALLOCATE: { /* allocate VBOXUHGSMI buffer */ + if (pDevExt->fCmdVbvaEnabled) + { + WARN(("VBOXESC_UHGSMI_ALLOCATE not supported for CmdVbva mode")); + Status = STATUS_INVALID_PARAMETER; + break; + } + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; PVBOXDISPIFESCAPE_UHGSMI_ALLOCATE pAlocate = (PVBOXDISPIFESCAPE_UHGSMI_ALLOCATE)pEscapeHdr; Assert(pEscape->PrivateDriverDataSize == sizeof (VBOXDISPIFESCAPE_UHGSMI_ALLOCATE)); @@ -3965,6 +4060,12 @@ DxgkDdiEscape( case VBOXESC_UHGSMI_DEALLOCATE: { + if (pDevExt->fCmdVbvaEnabled) + { + WARN(("VBOXESC_UHGSMI_DEALLOCATE not supported for CmdVbva mode")); + Status = STATUS_INVALID_PARAMETER; + break; + } /* deallocate VBOXUHGSMI buffer */ PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; PVBOXDISPIFESCAPE_UHGSMI_DEALLOCATE pDealocate = (PVBOXDISPIFESCAPE_UHGSMI_DEALLOCATE)pEscapeHdr; @@ -3982,14 +4083,29 @@ DxgkDdiEscape( case VBOXESC_GETVBOXVIDEOCMCMD: { + if (pDevExt->fCmdVbvaEnabled || pDevExt->fTexPresentEnabled) + { + WARN(("VBOXESC_GETVBOXVIDEOCMCMD not supported for CmdVbva or TexPresent mode")); + Status = STATUS_INVALID_PARAMETER; + break; + } + /* get the list of r0->r3 commands (d3d window visible regions reporting )*/ PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD pRegions = (PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD)pEscapeHdr; Assert(pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD)); if (pEscape->PrivateDriverDataSize >= sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD)) { - Status = vboxVideoCmEscape(&pContext->CmContext, pRegions, pEscape->PrivateDriverDataSize); - Assert(Status == STATUS_SUCCESS); + if (pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D) + { + Status = vboxVideoCmEscape(&pContext->CmContext, pRegions, pEscape->PrivateDriverDataSize); + Assert(Status == STATUS_SUCCESS); + } + else + { + WARN(("VBOXESC_GETVBOXVIDEOCMCMD recieved invalid context type %d", pContext->enmType)); + Status = STATUS_INVALID_PARAMETER; + } } else Status = STATUS_BUFFER_TOO_SMALL; @@ -3999,6 +4115,13 @@ DxgkDdiEscape( case VBOXESC_CRHGSMICTLCON_CALL: { + if (pDevExt->fCmdVbvaEnabled) + { + WARN(("VBOXESC_CRHGSMICTLCON_CALL not supported for CmdVbva mode")); + Status = STATUS_INVALID_PARAMETER; + break; + } + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; PVBOXDISPIFESCAPE_CRHGSMICTLCON_CALL pCall = (PVBOXDISPIFESCAPE_CRHGSMICTLCON_CALL)pEscapeHdr; if (pEscape->PrivateDriverDataSize >= sizeof (*pCall)) @@ -4006,13 +4129,11 @@ DxgkDdiEscape( /* this is true due to the above condition */ Assert(pEscape->PrivateDriverDataSize > RT_OFFSETOF(VBOXDISPIFESCAPE_CRHGSMICTLCON_CALL, CallInfo)); int rc = VBoxMpCrCtlConCallUserData(&pDevExt->CrCtlCon, &pCall->CallInfo, pEscape->PrivateDriverDataSize - RT_OFFSETOF(VBOXDISPIFESCAPE_CRHGSMICTLCON_CALL, CallInfo)); - if (RT_SUCCESS(rc)) - Status = STATUS_SUCCESS; - else - { + pEscapeHdr->u32CmdSpecific = (uint32_t)rc; + Status = STATUS_SUCCESS; /* <- always return success here, otherwise the private data buffer modifications + * i.e. rc status stored in u32CmdSpecific will not be copied to user mode */ + if (!RT_SUCCESS(rc)) WARN(("VBoxMpCrUmCtlConCall failed, rc(%d)", rc)); - Status = STATUS_UNSUCCESSFUL; - } } else { @@ -4042,6 +4163,22 @@ DxgkDdiEscape( case VBOXESC_SETVISIBLEREGION: { + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; +#ifdef VBOX_DISPIF_WITH_OPCONTEXT + if (!pContext) + { + WARN(("VBOXESC_SETVISIBLEREGION no context supplied!")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS) + { + WARN(("VBOXESC_SETVISIBLEREGION invalid context supplied %d!", pContext->enmType)); + Status = STATUS_INVALID_PARAMETER; + break; + } +#endif /* visible regions for seamless */ LPRGNDATA lpRgnData = VBOXDISPIFESCAPE_DATA(pEscapeHdr, RGNDATA); uint32_t cbData = VBOXDISPIFESCAPE_DATA_SIZE(pEscape->PrivateDriverDataSize); @@ -4080,22 +4217,23 @@ DxgkDdiEscape( rc = VbglGRPerform (&req->header); AssertRC(rc); - if (!RT_SUCCESS(rc)) + if (RT_SUCCESS(rc)) + Status = STATUS_SUCCESS; + else { - LOGREL(("VbglGRPerform failed rc (%d)", rc)); + WARN(("VbglGRPerform failed rc (%d)", rc)); Status = STATUS_UNSUCCESSFUL; } } else { - LOGREL(("VbglGRAlloc failed rc (%d)", rc)); + WARN(("VbglGRAlloc failed rc (%d)", rc)); Status = STATUS_UNSUCCESSFUL; } } else { - LOGREL(("VBOXESC_SETVISIBLEREGION: incorrect buffer size (%d), reported count (%d)", cbRects, lpRgnData->rdh.nCount)); - AssertBreakpoint(); + WARN(("VBOXESC_SETVISIBLEREGION: incorrect buffer size (%d), reported count (%d)", cbRects, lpRgnData->rdh.nCount)); Status = STATUS_INVALID_PARAMETER; } break; @@ -4139,6 +4277,43 @@ DxgkDdiEscape( Status = STATUS_SUCCESS; break; } + case VBOXESC_SETCTXHOSTID: + { + /* set swapchain information */ + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; + if (!pContext) + { + WARN(("VBOXESC_SETCTXHOSTID: no context specified")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE)) + { + WARN(("VBOXESC_SETCTXHOSTID: invalid data size %d", pEscape->PrivateDriverDataSize)); + Status = STATUS_INVALID_PARAMETER; + break; + } + + int32_t hostID = (int32_t)pEscapeHdr->u32CmdSpecific; + if (hostID <= 0) + { + WARN(("VBOXESC_SETCTXHOSTID: invalid hostID %d", hostID)); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pContext->hostID) + { + WARN(("VBOXESC_SETCTXHOSTID: context already has hostID specified")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + pContext->hostID = hostID; + Status = STATUS_SUCCESS; + break; + } case VBOXESC_SWAPCHAININFO: { /* set swapchain information */ @@ -4149,46 +4324,171 @@ DxgkDdiEscape( } case VBOXESC_REINITVIDEOMODES: { - if (pEscape->Flags.HardwareAccess) + if (!pEscape->Flags.HardwareAccess) { - WARN(("VBOXESC_REINITVIDEOMODES called with HardwareAccess flag set, failing")); + WARN(("VBOXESC_REINITVIDEOMODESBYMASK called without HardwareAccess flag set, failing")); Status = STATUS_INVALID_PARAMETER; break; } - WARN(("VBOXESC_REINITVIDEOMODESBYMASK should be called instead")); - PVBOXWDDM_VIDEOMODES_INFO pInfos = VBoxWddmUpdateAllVideoModesInfos(pDevExt); - Status = vboxWddmChildStatusCheckByMask(pDevExt, pInfos, NULL); - if (!NT_SUCCESS(Status)) + +#ifdef VBOX_DISPIF_WITH_OPCONTEXT + /* win8.1 does not allow context-based escapes for display-only mode */ + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; + if (!pContext) + { + WARN(("VBOXESC_REINITVIDEOMODES no context supplied!")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE) { - WARN(("vboxWddmChildStatusCheckByMask failed, Status 0x%x", Status)); + WARN(("VBOXESC_REINITVIDEOMODES invalid context supplied %d!", pContext->enmType)); + Status = STATUS_INVALID_PARAMETER; + break; } +#endif + + WARN(("VBOXESC_REINITVIDEOMODESBYMASK should be called instead")); + VBoxWddmUpdateVideoModesInfoByMask(pDevExt, NULL); + Status = STATUS_SUCCESS; break; } case VBOXESC_REINITVIDEOMODESBYMASK: { - BOOLEAN fCheckDisplayRecconect = (pEscapeHdr->u32CmdSpecific & VBOXWDDM_REINITVIDEOMODESBYMASK_F_RECONNECT_DISPLAYS_ON_CHANGE); - if (fCheckDisplayRecconect && pEscape->Flags.HardwareAccess) + if (!pEscape->Flags.HardwareAccess) + { + WARN(("VBOXESC_REINITVIDEOMODESBYMASK called without HardwareAccess flag set, failing")); + Status = STATUS_INVALID_PARAMETER; + break; + } + +#ifdef VBOX_DISPIF_WITH_OPCONTEXT + /* win8.1 does not allow context-based escapes for display-only mode */ + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; + if (!pContext) + { + WARN(("VBOXESC_REINITVIDEOMODESBYMASK no context supplied!")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE) { - WARN(("VBOXESC_REINITVIDEOMODESBYMASK called with HardwareAccess flag set, failing")); + WARN(("VBOXESC_REINITVIDEOMODESBYMASK invalid context supplied %d!", pContext->enmType)); Status = STATUS_INVALID_PARAMETER; break; } +#endif + if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK)) { WARN(("invalid private driver size %d", pEscape->PrivateDriverDataSize)); Status = STATUS_INVALID_PARAMETER; break; } + LOG(("=> VBOXESC_REINITVIDEOMODESBYMASK")); PVBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK pData = (PVBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK)pEscapeHdr; - PVBOXWDDM_VIDEOMODES_INFO pInfos = VBoxWddmUpdateVideoModesInfoByMask(pDevExt, pData->ScreenMask); - if (fCheckDisplayRecconect) + VBoxWddmUpdateVideoModesInfoByMask(pDevExt, pData->ScreenMask); + Status = STATUS_SUCCESS; + LOG(("<= VBOXESC_REINITVIDEOMODESBYMASK")); + break; + } + case VBOXESC_CONFIGURETARGETS: + { + LOG(("=> VBOXESC_CONFIGURETARGETS")); + + if (!pEscape->Flags.HardwareAccess) { - Status = vboxWddmChildStatusCheckByMask(pDevExt, pInfos, pData->ScreenMask); - if (!NT_SUCCESS(Status)) + WARN(("VBOXESC_CONFIGURETARGETS called without HardwareAccess flag set, failing")); + Status = STATUS_INVALID_PARAMETER; + break; + } + +#ifdef VBOX_DISPIF_WITH_OPCONTEXT + /* win8.1 does not allow context-based escapes for display-only mode */ + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)pEscape->hContext; + if (!pContext) + { + WARN(("VBOXESC_CONFIGURETARGETS no context supplied!")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pContext->enmType != VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE) + { + WARN(("VBOXESC_CONFIGURETARGETS invalid context supplied %d!", pContext->enmType)); + Status = STATUS_INVALID_PARAMETER; + break; + } +#endif + + if (pEscape->PrivateDriverDataSize != sizeof (*pEscapeHdr)) + { + WARN(("VBOXESC_CONFIGURETARGETS invalid private driver size %d", pEscape->PrivateDriverDataSize)); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pEscapeHdr->u32CmdSpecific) + { + WARN(("VBOXESC_CONFIGURETARGETS invalid command %d", pEscapeHdr->u32CmdSpecific)); + Status = STATUS_INVALID_PARAMETER; + break; + } + + HANDLE hKey = NULL; + WCHAR aNameBuf[100]; + uint32_t cAdjusted = 0; + + for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) + { + VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[i]; + if (pTarget->fConfigured) + continue; + + pTarget->fConfigured = true; + + if (!pTarget->fConnected) { - WARN(("vboxWddmChildStatusCheckByMask failed, Status 0x%x", Status)); + Status = vboxWddmChildStatusConnect(pDevExt, (uint32_t)i, TRUE); + if (NT_SUCCESS(Status)) + ++cAdjusted; + else + WARN(("VBOXESC_CONFIGURETARGETS vboxWddmChildStatusConnectSecondaries failed Status 0x%x\n", Status)); } + + if (!hKey) + { + Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey); + if (!NT_SUCCESS(Status)) + { + WARN(("VBOXESC_CONFIGURETARGETS IoOpenDeviceRegistryKey failed, Status = 0x%x", Status)); + hKey = NULL; + continue; + } + } + + Assert(hKey); + + swprintf(aNameBuf, L"%s%d", VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX, i); + Status = vboxWddmRegSetValueDword(hKey, aNameBuf, VBOXWDDM_CFG_DRVTARGET_CONNECTED); + if (!NT_SUCCESS(Status)) + WARN(("VBOXESC_CONFIGURETARGETS vboxWddmRegSetValueDword (%d) failed Status 0x%x\n", aNameBuf, Status)); + + } + + if (hKey) + { + NTSTATUS tmpStatus = ZwClose(hKey); + Assert(tmpStatus == STATUS_SUCCESS); } + + pEscapeHdr->u32CmdSpecific = cAdjusted; + + Status = STATUS_SUCCESS; + + LOG(("<= VBOXESC_CONFIGURETARGETS")); break; } case VBOXESC_ADJUSTVIDEOMODES: @@ -4212,11 +4512,57 @@ DxgkDdiEscape( PVBOXDISPIFESCAPE_ADJUSTVIDEOMODES pPodesInfo = (PVBOXDISPIFESCAPE_ADJUSTVIDEOMODES)pEscapeHdr; VBoxWddmAdjustModes(pDevExt, cModes, pPodesInfo->aScreenInfos); Status = STATUS_SUCCESS; + break; + } + case VBOXESC_SETALLOCHOSTID: + { + PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice; + if (!pDevice) + { + WARN(("VBOXESC_SETALLOCHOSTID called without no device specified, failing")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_SETALLOCHOSTID)) + { + WARN(("invalid buffer size for VBOXDISPIFESCAPE_SHRC_REF, was(%d), but expected (%d)", + pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE_SHRC_REF))); + Status = STATUS_INVALID_PARAMETER; + break; + } + + PVBOXDISPIFESCAPE_SETALLOCHOSTID pSetHostID = (PVBOXDISPIFESCAPE_SETALLOCHOSTID)pEscapeHdr; + PVBOXWDDM_ALLOCATION pAlloc = vboxWddmGetAllocationFromHandle(pDevExt, (D3DKMT_HANDLE)pSetHostID->hAlloc); + if (!pAlloc) + { + WARN(("failed to get allocation from handle")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (pAlloc->enmType != VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE) + { + WARN(("setHostID: invalid allocation type: %d", pAlloc->enmType)); + Status = STATUS_INVALID_PARAMETER; + break; + } + + pSetHostID->rc = VBoxWddmOaSetHostID(pDevice, pAlloc, pSetHostID->hostID, &pSetHostID->EscapeHdr.u32CmdSpecific); + Status = STATUS_SUCCESS; + break; } case VBOXESC_SHRC_ADDREF: case VBOXESC_SHRC_RELEASE: { PVBOXWDDM_DEVICE pDevice = (PVBOXWDDM_DEVICE)pEscape->hDevice; + if (!pDevice) + { + WARN(("VBOXESC_SHRC_ADDREF|VBOXESC_SHRC_RELEASE called without no device specified, failing")); + Status = STATUS_INVALID_PARAMETER; + break; + } + /* query whether the allocation represanted by the given [wine-generated] shared resource handle still exists */ if (pEscape->PrivateDriverDataSize != sizeof (VBOXDISPIFESCAPE_SHRC_REF)) { @@ -4282,7 +4628,7 @@ DxgkDdiEscape( } PVBOXDISPIFESCAPE_ISANYX pIsAnyX = (PVBOXDISPIFESCAPE_ISANYX)pEscapeHdr; - pIsAnyX->u32IsAnyX = pDevExt->fAnyX; + pIsAnyX->u32IsAnyX = VBoxCommonFromDeviceExt(pDevExt)->fAnyX; Status = STATUS_SUCCESS; break; } @@ -4313,15 +4659,13 @@ DxgkDdiEscape( break; } default: - Assert(0); - LOGREL(("unsupported escape code (0x%x)", pEscapeHdr->escapeCode)); + WARN(("unsupported escape code (0x%x)", pEscapeHdr->escapeCode)); break; } } else { - LOGREL(("pEscape->PrivateDriverDataSize(%d) < (%d)", pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE))); - AssertBreakpoint(); + WARN(("pEscape->PrivateDriverDataSize(%d) < (%d)", pEscape->PrivateDriverDataSize, sizeof (VBOXDISPIFESCAPE))); Status = STATUS_BUFFER_TOO_SMALL; } @@ -4356,14 +4700,34 @@ typedef struct VBOXWDDM_QUERYCURFENCE_CB static BOOLEAN vboxWddmQueryCurrentFenceCb(PVOID Context) { PVBOXWDDM_QUERYCURFENCE_CB pdc = (PVBOXWDDM_QUERYCURFENCE_CB)Context; - BOOL bRc = DxgkDdiInterruptRoutine(pdc->pDevExt, pdc->MessageNumber); - pdc->uLastCompletedCmdFenceId = pdc->pDevExt->u.primary.Vdma.uLastCompletedPagingBufferCmdFenceId; + PVBOXMP_DEVEXT pDevExt = pdc->pDevExt; + BOOL bRc = DxgkDdiInterruptRoutineLegacy(pDevExt, pdc->MessageNumber); + pdc->uLastCompletedCmdFenceId = pDevExt->u.primary.Vdma.uLastCompletedPagingBufferCmdFenceId; return bRc; } -NTSTATUS +static NTSTATUS +APIENTRY +DxgkDdiQueryCurrentFenceNew( + CONST HANDLE hAdapter, + DXGKARG_QUERYCURRENTFENCE* pCurrentFence) +{ + LOGF(("ENTER, hAdapter(0x%x)", hAdapter)); + + vboxVDbgBreakF(); + + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter; + pCurrentFence->CurrentFence = VBoxCmdVbvaCheckCompleted(pDevExt, &pDevExt->CmdVbva, false); + + LOGF(("LEAVE, hAdapter(0x%x)", hAdapter)); + + return STATUS_SUCCESS; +} + + +static NTSTATUS APIENTRY -DxgkDdiQueryCurrentFence( +DxgkDdiQueryCurrentFenceLegacy( CONST HANDLE hAdapter, DXGKARG_QUERYCURRENTFENCE* pCurrentFence) { @@ -4407,7 +4771,6 @@ DxgkDdiIsSupportedVidPn( vboxVDbgBreakFv(); NTSTATUS Status = STATUS_SUCCESS; - BOOLEAN bSupported = TRUE; PVBOXMP_DEVEXT pContext = (PVBOXMP_DEVEXT)hAdapter; const DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; @@ -4431,23 +4794,18 @@ DxgkDdiIsSupportedVidPn( return Status; } - VBOXVIDPNPATHITEM aItems[VBOX_VIDEO_MAX_SCREENS]; - BOOLEAN fDisabledFound = FALSE; - Status = vboxVidPnCheckTopology(hVidPnTopology, pVidPnTopologyInterface, TRUE /* fBreakOnDisabled */, RT_ELEMENTS(aItems), aItems, &fDisabledFound); - Assert(Status == STATUS_SUCCESS); + BOOLEAN fSupported = FALSE; + Status = vboxVidPnCheckTopology(hVidPnTopology, pVidPnTopologyInterface, &fSupported); if (!NT_SUCCESS(Status)) { WARN(("vboxVidPnCheckTopology failed Status()0x%x\n", Status)); return Status; } - if (fDisabledFound) - { + if (!fSupported) LOG(("found unsupported path")); - bSupported = FALSE; - } - pIsSupportedVidPnArg->IsVidPnSupported = bSupported; + pIsSupportedVidPnArg->IsVidPnSupported = fSupported; #ifdef VBOXWDDM_DEBUG_VIDPN LOGREL(("The Given VidPn is %ssupported\n", pIsSupportedVidPnArg->IsVidPnSupported ? "" : "!!NOT!! ")); @@ -4472,11 +4830,15 @@ DxgkDdiRecommendFunctionalVidPn( vboxVDbgBreakFv(); +#ifdef DEBUG_misha + Assert(0); +#endif + PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter; NTSTATUS Status; PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = pRecommendFunctionalVidPnArg->PrivateDriverDataSize >= sizeof (VBOXWDDM_RECOMMENDVIDPN) ? (PVBOXWDDM_RECOMMENDVIDPN)pRecommendFunctionalVidPnArg->pPrivateDriverData : NULL; - PVBOXWDDM_VIDEOMODES_INFO pInfos = VBoxWddmUpdateAllVideoModesInfos(pDevExt); + PVBOXWDDM_VIDEOMODES_INFO pInfos = VBoxWddmGetAllVideoModesInfos(pDevExt); int i; for (i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) @@ -4621,26 +4983,25 @@ DxgkDdiEnumVidPnCofuncModality( return Status; } - VBOXVIDPNPATHITEM aItems[VBOX_VIDEO_MAX_SCREENS]; - Status = vboxVidPnCheckTopology(hVidPnTopology, pVidPnTopologyInterface, FALSE /* fBreakOnDisabled */, RT_ELEMENTS(aItems), aItems, NULL /* *pfDisabledFound */); - Assert(Status == STATUS_SUCCESS); +#ifdef DEBUG_misha + BOOLEAN fSupported = FALSE; + Status = vboxVidPnCheckTopology(hVidPnTopology, pVidPnTopologyInterface, &fSupported); if (!NT_SUCCESS(Status)) { WARN(("vboxVidPnCheckTopology failed Status()0x%x\n", Status)); return Status; } + Assert(fSupported); +#endif VBOXVIDPNCOFUNCMODALITY CbContext = {0}; CbContext.pDevExt = pDevExt; CbContext.pVidPnInterface = pVidPnInterface; CbContext.pEnumCofuncModalityArg = pEnumCofuncModalityArg; CbContext.pInfos = VBoxWddmGetAllVideoModesInfos(pDevExt); - CbContext.cPathInfos = RT_ELEMENTS(aItems); - CbContext.apPathInfos = aItems; Status = vboxVidPnEnumPaths(hVidPnTopology, pVidPnTopologyInterface, vboxVidPnCofuncModalityPathEnum, &CbContext); - Assert(Status == STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { WARN(("vboxVidPnEnumPaths failed Status()0x%x\n", Status)); @@ -4682,8 +5043,18 @@ DxgkDdiSetVidPnSourceAddress( Assert((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays > pSetVidPnSourceAddress->VidPnSourceId); PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceAddress->VidPnSourceId]; - Status= vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId, &pSource->VScreenPos); + POINT Pos; + Status= vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceAddress->VidPnSourceId, &Pos); Assert(Status == STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + { + if (memcmp(&pSource->VScreenPos, &Pos, sizeof (Pos))) + { + pSource->VScreenPos = Pos; + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + } + } + Status = STATUS_SUCCESS; if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceAddress->VidPnSourceId) @@ -4728,26 +5099,9 @@ DxgkDdiSetVidPnSourceAddress( pSetVidPnSourceAddress->PrimaryAddress.QuadPart); } - pSource->bGhSynced = FALSE; /* force guest->host notification */ + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; - if (pSource->bVisible -#if defined(VBOXWDDM_RENDER_FROM_SHADOW) - && ( -# if defined(VBOX_WDDM_WIN8) - g_VBoxDisplayOnly - || -# endif - pDevExt->fRenderToShadowDisabled - /* only update for UMD_RC_GENERIC when resolution changes to inform host about it - * otherwise keep host using the same VRAM, containing a valid data before the switch (i.e. SHADOW) */ - || (pAllocation - && pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC - && (pAllocation->AllocData.SurfDesc.width != pSource->AllocData.SurfDesc.width - || pAllocation->AllocData.SurfDesc.height != pSource->AllocData.SurfDesc.height) - ) - ) -#endif - ) + if (pSource->bVisible) { vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource); } @@ -4776,8 +5130,17 @@ DxgkDdiSetVidPnSourceVisibility( Assert((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays > pSetVidPnSourceVisibility->VidPnSourceId); PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[pSetVidPnSourceVisibility->VidPnSourceId]; - Status= vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId, &pSource->VScreenPos); + POINT Pos; + Status= vboxWddmDisplaySettingsQueryPos(pDevExt, pSetVidPnSourceVisibility->VidPnSourceId, &Pos); Assert(Status == STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + { + if (memcmp(&pSource->VScreenPos, &Pos, sizeof (Pos))) + { + pSource->VScreenPos = Pos; + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS; + } + } Status = STATUS_SUCCESS; if ((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays <= pSetVidPnSourceVisibility->VidPnSourceId) @@ -4793,24 +5156,7 @@ DxgkDdiSetVidPnSourceVisibility( if (pSource->bVisible != pSetVidPnSourceVisibility->Visible) { pSource->bVisible = pSetVidPnSourceVisibility->Visible; - if (pSource->bVisible -#if defined(VBOXWDDM_RENDER_FROM_SHADOW) - && ( -# if defined(VBOX_WDDM_WIN8) - g_VBoxDisplayOnly - || -# endif - pDevExt->fRenderToShadowDisabled - /* only update for UMD_RC_GENERIC when resolution changes to inform host about it - * otherwise keep host using the same VRAM, containing a valid data before the switch (i.e. SHADOW) */ - || (pAllocation - && pAllocation->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC - && (pAllocation->AllocData.SurfDesc.width != pSource->AllocData.SurfDesc.width - || pAllocation->AllocData.SurfDesc.height != pSource->AllocData.SurfDesc.height) - ) - ) -#endif - ) + if (pSource->bVisible) { vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource); } @@ -4831,7 +5177,6 @@ static DECLCALLBACK(BOOLEAN) vboxWddmVidPnCleanupTargetsForSrcEnum(PVBOXMP_DEVEX return TRUE; } - NTSTATUS APIENTRY DxgkDdiCommitVidPn( @@ -4842,24 +5187,10 @@ DxgkDdiCommitVidPn( LOGF(("ENTER, context(0x%x)", hAdapter)); PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter; - uint32_t au32OldHeightVisible[VBOX_VIDEO_MAX_SCREENS]; NTSTATUS Status; vboxVDbgBreakFv(); - /* we first store the current visible height for each target (monitor) - * and then we will zero up it for targets either for the given source - * (in case pCommitVidPnArg->AffectedVidPnSourceId != D3DDDI_ID_ALL) - * or all targets otherwize. - * In the end we will match the old and new visible height for all targets to see if - * some of them become inactivated and hide them accordingly, - * or we will restore the old height values on failure */ - for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) - { - PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i]; - au32OldHeightVisible[i] = pTarget->HeightVisible; - } - do { const DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; Status = pDevExt->u.primary.DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPnArg->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); @@ -4895,7 +5226,7 @@ DxgkDdiCommitVidPn( break; } - /* this will zero up visible height for all targets of the fiven source, see above comment */ + /* this will zero up visible height for all targets of the given source, see above comment */ Status = vboxVidPnEnumTargetsForSource(pDevExt, hVidPnTopology, pVidPnTopologyInterface, pCommitVidPnArg->AffectedVidPnSourceId, vboxWddmVidPnCleanupTargetsForSrcEnum, NULL); @@ -4966,43 +5297,26 @@ DxgkDdiCommitVidPn( Assert(NT_SUCCESS(Status)); pDevExt->u.primary.hCommittedVidPn = pCommitVidPnArg->hFunctionalVidPn; - for (int i = 1; /* <- never try to hide a primary monitor */ - i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) + for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) { PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i]; - if (!pTarget->HeightVisible && !!au32OldHeightVisible[i]) - { - /* the target was previously visible */ - vboxWddmGhDisplayHideScreen(pDevExt, i); - } - } - -#ifdef VBOX_WDDM_WIN8 - if (g_VBoxDisplayOnly) - { - for (int i = 0; /* <- never try to hide a primary monitor */ - i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) + PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i]; + uint32_t cAutoresizes = pDevExt->cContextsDispIfResize; + if (!cAutoresizes) { - PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[i]; - if (pSource->bVisible && !pSource->bGhSynced) - { + if (pSource->bVisible || !pTarget->HeightVisible) vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource); - } } + else + pTarget->fStateSyncPening = true; } -#endif + LOGF(("LEAVE, SUCCESS status(0x%x), context(0x%x)", Status, hAdapter)); return Status; } while (0); AssertRelease(!NT_SUCCESS(Status)); - /* failure branch restore original visible height values, see comments above */ - for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) - { - PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i]; - pTarget->HeightVisible = au32OldHeightVisible[i]; - } LOGF(("LEAVE, !!FAILURE!! status(0x%x), context(0x%x)", Status, hAdapter)); return Status; @@ -5139,7 +5453,7 @@ DxgkDdiControlInterrupt( { LOGF(("ENTER, hAdapter(0x%x)", hAdapter)); - NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)hAdapter; switch (InterruptType) @@ -5147,7 +5461,9 @@ DxgkDdiControlInterrupt( case DXGK_INTERRUPT_CRTC_VSYNC: { Status = VBoxWddmSlEnableVSyncNotification(pDevExt, Enable); - if (!NT_SUCCESS(Status)) + if (NT_SUCCESS(Status)) + Status = STATUS_SUCCESS; /* <- sanity */ + else WARN(("VSYNC Interrupt control failed Enable(%d), Status(0x%x)", Enable, Status)); break; } @@ -5243,15 +5559,17 @@ DxgkDdiOpenAllocation( PVBOXWDDM_RCINFO pRcInfo = NULL; if (pOpenAllocation->PrivateDriverSize) { - Assert(pOpenAllocation->PrivateDriverSize == sizeof (VBOXWDDM_RCINFO)); Assert(pOpenAllocation->pPrivateDriverData); - if (pOpenAllocation->PrivateDriverSize >= sizeof (VBOXWDDM_RCINFO)) + if (pOpenAllocation->PrivateDriverSize == sizeof (VBOXWDDM_RCINFO)) { pRcInfo = (PVBOXWDDM_RCINFO)pOpenAllocation->pPrivateDriverData; Assert(pRcInfo->cAllocInfos == pOpenAllocation->NumAllocations); } else + { + WARN(("Invalid PrivateDriverSize %d", pOpenAllocation->PrivateDriverSize)); Status = STATUS_INVALID_PARAMETER; + } } if (Status == STATUS_SUCCESS) @@ -5387,26 +5705,24 @@ DxgkDdiCloseAllocation( return STATUS_SUCCESS; } -NTSTATUS +static NTSTATUS APIENTRY -DxgkDdiRender( +DxgkDdiRenderNew( CONST HANDLE hContext, DXGKARG_RENDER *pRender) { // LOGF(("ENTER, hContext(0x%x)", hContext)); - Assert(pRender->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)); - if (pRender->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)) + if (pRender->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_HDR)) { - LOGREL(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)", - pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))); + WARN(("pRender->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_HDR (%d)", + pRender->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_HDR))); /* @todo: can this actually happen? what status to return? */ return STATUS_INVALID_PARAMETER; } if (pRender->CommandLength < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)) { - Assert(0); - LOGREL(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)", + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)", pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))); /* @todo: can this actually happen? what status to return? */ return STATUS_INVALID_PARAMETER; @@ -5414,87 +5730,249 @@ DxgkDdiRender( PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pInputHdr = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pCommand; NTSTATUS Status = STATUS_SUCCESS; + + uint32_t cbBuffer = 0; + uint32_t cbCmdDma = 0; + VBOXCMDVBVA_HDR* pCmd = (VBOXCMDVBVA_HDR*)pRender->pDmaBufferPrivateData; + switch (pInputHdr->enmCmd) { case VBOXVDMACMD_TYPE_CHROMIUM_CMD: { - if (pRender->CommandLength != RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD, aBufInfos[pInputHdr->u32CmdReserved])) + if (pRender->AllocationListSize >= (UINT32_MAX - RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD, aBufInfos))/ RT_SIZEOFMEMB(VBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD, aBufInfos[0])) { - Assert(0); + WARN(("Invalid AllocationListSize %d", pRender->AllocationListSize)); return STATUS_INVALID_PARAMETER; } - PVBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD pUmCmd = (PVBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD)pInputHdr; - PVBOXWDDM_DMA_PRIVATEDATA_CHROMIUM_CMD pChromiumCmd = (PVBOXWDDM_DMA_PRIVATEDATA_CHROMIUM_CMD)pRender->pDmaBufferPrivateData; - const uint32_t cbDma = RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_CHROMIUM_CMD, aBufInfos[pInputHdr->u32CmdReserved]); - if (pRender->DmaBufferPrivateDataSize < cbDma) + + if (pRender->CommandLength != RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD, aBufInfos[pRender->AllocationListSize])) { - Assert(0); + WARN(("pRender->CommandLength (%d) != RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD, aBufInfos[pRender->AllocationListSize](%d)", + pRender->CommandLength, RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD, aBufInfos[pRender->AllocationListSize]))); return STATUS_INVALID_PARAMETER; } - if (pRender->DmaSize < cbDma) + + if (pRender->AllocationListSize >= (UINT32_MAX - RT_OFFSETOF(VBOXCMDVBVA_CRCMD, Cmd.aBuffers))/ RT_SIZEOFMEMB(VBOXCMDVBVA_CRCMD, Cmd.aBuffers[0])) { - Assert(0); + WARN(("Invalid AllocationListSize %d", pRender->AllocationListSize)); return STATUS_INVALID_PARAMETER; } - if (pRender->PatchLocationListOutSize < pInputHdr->u32CmdReserved) + cbBuffer = RT_OFFSETOF(VBOXCMDVBVA_CRCMD, Cmd.aBuffers[pRender->AllocationListSize]); + if (cbBuffer > 4096) { - Assert(0); + /* this should not be bigger actually */ + WARN(("too big command buffer %d", cbBuffer)); + return STATUS_INVALID_PARAMETER; + } + + cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE; + + if (pRender->DmaBufferPrivateDataSize < cbBuffer) + { + WARN(("pRender->DmaBufferPrivateDataSize too small %d, requested %d", pRender->DmaBufferPrivateDataSize, cbBuffer)); + return STATUS_INVALID_PARAMETER; + } + + if (pRender->DmaSize < cbCmdDma) + { + WARN(("dma buffer %d too small", pRender->DmaSize)); + return STATUS_INVALID_PARAMETER; + } + + Assert(pRender->PatchLocationListOutSize == pRender->AllocationListSize); + + if (pRender->PatchLocationListOutSize < pRender->AllocationListSize) + { + WARN(("pRender->PatchLocationListOutSize too small %d, requested %d", pRender->PatchLocationListOutSize, pRender->AllocationListSize)); return STATUS_INVALID_PARAMETER; } + PVBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD pUmCmd = (PVBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD)pInputHdr; + VBOXCMDVBVA_CRCMD* pChromiumCmd = (VBOXCMDVBVA_CRCMD*)pRender->pDmaBufferPrivateData; + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext; PVBOXWDDM_DEVICE pDevice = pContext->pDevice; PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter; - pChromiumCmd->Base.enmCmd = VBOXVDMACMD_TYPE_CHROMIUM_CMD; - pChromiumCmd->Base.u32CmdReserved = pInputHdr->u32CmdReserved; - pRender->pDmaBufferPrivateData = (uint8_t*)pRender->pDmaBufferPrivateData + cbDma; - pRender->pDmaBuffer = ((uint8_t*)pRender->pDmaBuffer) + cbDma; - D3DDDI_PATCHLOCATIONLIST* pPLL = pRender->pPatchLocationListOut; - memset(pPLL, 0, sizeof (*pPLL) * pChromiumCmd->Base.u32CmdReserved); - pRender->pPatchLocationListOut += pInputHdr->u32CmdReserved; - PVBOXWDDM_UHGSMI_BUFFER_SUBMIT_INFO pSubmInfo = pChromiumCmd->aBufInfos; - PVBOXWDDM_UHGSMI_BUFFER_UI_SUBMIT_INFO pSubmUmInfo = pUmCmd->aBufInfos; + pChromiumCmd->Hdr.u8OpCode = VBOXCMDVBVA_OPTYPE_CRCMD; + pChromiumCmd->Hdr.u8Flags = 0; + pChromiumCmd->Cmd.cBuffers = pRender->AllocationListSize; + DXGK_ALLOCATIONLIST *pAllocationList = pRender->pAllocationList; - for (UINT i = 0; i < pChromiumCmd->Base.u32CmdReserved; ++i) + VBOXCMDVBVA_CRCMD_BUFFER *pSubmInfo = pChromiumCmd->Cmd.aBuffers; + PVBOXWDDM_UHGSMI_BUFFER_UI_SUBMIT_INFO pSubmUmInfo = pUmCmd->aBufInfos; + + for (UINT i = 0; i < pRender->AllocationListSize; ++i, ++pRender->pPatchLocationListOut, ++pAllocationList, ++pSubmInfo, ++pSubmUmInfo) { + D3DDDI_PATCHLOCATIONLIST* pPLL = pRender->pPatchLocationListOut; PVBOXWDDM_ALLOCATION pAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pAllocationList); - vboxWddmPopulateDmaAllocInfoWithOffset(&pSubmInfo->Alloc, pAlloc, pAllocationList, pSubmUmInfo->offData); + if (pSubmUmInfo->offData >= pAlloc->AllocData.SurfDesc.cbSize + || pSubmUmInfo->cbData > pAlloc->AllocData.SurfDesc.cbSize + || pSubmUmInfo->offData + pSubmUmInfo->cbData > pAlloc->AllocData.SurfDesc.cbSize) + { + WARN(("invalid data")); + return STATUS_INVALID_PARAMETER; + } + + memset(pPLL, 0, sizeof (*pPLL)); + + if (pAllocationList->SegmentId) + pSubmInfo->offBuffer = pAllocationList->PhysicalAddress.LowPart + pSubmUmInfo->offData; - pSubmInfo->cbData = pSubmUmInfo->cbData; - pSubmInfo->bDoNotSignalCompletion = pSubmUmInfo->bDoNotSignalCompletion; + pSubmInfo->cbBuffer = pSubmUmInfo->cbData; pPLL->AllocationIndex = i; - pPLL->PatchOffset = RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_CHROMIUM_CMD, aBufInfos[i].Alloc); + pPLL->PatchOffset = RT_OFFSETOF(VBOXCMDVBVA_CRCMD, Cmd.aBuffers[i].offBuffer); pPLL->AllocationOffset = pSubmUmInfo->offData; - - ++pPLL; - ++pSubmInfo; - ++pSubmUmInfo; - ++pAllocationList; } break; } case VBOXVDMACMD_TYPE_DMA_NOP: { - PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pDmaBufferPrivateData; - pPrivateData->enmCmd = VBOXVDMACMD_TYPE_DMA_NOP; + cbBuffer = sizeof (VBOXCMDVBVA_HDR); + cbCmdDma = VBOXWDDM_DUMMY_DMABUFFER_SIZE; + + if (pRender->DmaBufferPrivateDataSize < cbBuffer) + { + WARN(("pRender->DmaBufferPrivateDataSize too small %d, requested %d", pRender->DmaBufferPrivateDataSize, cbBuffer)); + return STATUS_INVALID_PARAMETER; + } + + if (pRender->DmaSize < cbCmdDma) + { + WARN(("dma buffer %d too small", pRender->DmaSize)); + return STATUS_INVALID_PARAMETER; + } + + pCmd->u8OpCode = VBOXCMDVBVA_OPTYPE_NOPCMD; + pCmd->u8Flags = 0; + + for (UINT i = 0; i < pRender->AllocationListSize; ++i, ++pRender->pPatchLocationListOut) + { + D3DDDI_PATCHLOCATIONLIST* pPLL = pRender->pPatchLocationListOut; + memset(pPLL, 0, sizeof (*pPLL)); + pPLL->AllocationIndex = i; + pPLL->PatchOffset = ~0UL; + pPLL->AllocationOffset = 0; + } - pRender->pDmaBufferPrivateData = (uint8_t*)pRender->pDmaBufferPrivateData + sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR); - pRender->pDmaBuffer = ((uint8_t*)pRender->pDmaBuffer) + pRender->CommandLength; - Assert(pRender->DmaSize >= pRender->CommandLength); - Assert(pRender->PatchLocationListOutSize >= pRender->PatchLocationListInSize); - UINT cbPLL = pRender->PatchLocationListInSize * sizeof (pRender->pPatchLocationListOut[0]); - memcpy(pRender->pPatchLocationListOut, pRender->pPatchLocationListIn, cbPLL); - pRender->pPatchLocationListOut += pRender->PatchLocationListInSize; break; } default: + { + WARN(("unsupported render command %d", pInputHdr->enmCmd)); return STATUS_INVALID_PARAMETER; + } } + pRender->pDmaBufferPrivateData = ((uint8_t*)pRender->pDmaBufferPrivateData) + cbBuffer; + pRender->pDmaBuffer = ((uint8_t*)pRender->pDmaBuffer) + cbCmdDma; + + pCmd->u8State = VBOXCMDVBVA_STATE_SUBMITTED; + /* sanity */ + pCmd->u32FenceID = 0; + +// LOGF(("LEAVE, hContext(0x%x)", hContext)); + + return STATUS_SUCCESS; +} + +static void vboxWddmPatchLocationInit(D3DDDI_PATCHLOCATIONLIST *pPatchLocationListOut, UINT idx, UINT offPatch) +{ + memset(pPatchLocationListOut, 0, sizeof (*pPatchLocationListOut)); + pPatchLocationListOut->AllocationIndex = idx; + pPatchLocationListOut->PatchOffset = offPatch; +} + +static NTSTATUS +APIENTRY +DxgkDdiRenderLegacy( + CONST HANDLE hContext, + DXGKARG_RENDER *pRender) +{ +// LOGF(("ENTER, hContext(0x%x)", hContext)); + + Assert(pRender->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)); + if (pRender->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)) + { + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)", + pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))); + return STATUS_INVALID_PARAMETER; + } + if (pRender->CommandLength < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)) + { + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_BASEHDR (%d)", + pRender->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR))); + return STATUS_INVALID_PARAMETER; + } + if (pRender->DmaSize < pRender->CommandLength) + { + WARN(("pRender->DmaSize(%d) < pRender->CommandLength(%d)", + pRender->DmaSize, pRender->CommandLength)); + return STATUS_INVALID_PARAMETER; + } + if (pRender->PatchLocationListOutSize < pRender->PatchLocationListInSize) + { + WARN(("pRender->PatchLocationListOutSize(%d) < pRender->PatchLocationListInSize(%d)", + pRender->PatchLocationListOutSize, pRender->PatchLocationListInSize)); + return STATUS_INVALID_PARAMETER; + } + if (pRender->AllocationListSize != pRender->PatchLocationListInSize) + { + WARN(("pRender->AllocationListSize(%d) != pRender->PatchLocationListInSize(%d)", + pRender->AllocationListSize, pRender->PatchLocationListInSize)); + return STATUS_INVALID_PARAMETER; + } + + NTSTATUS Status = STATUS_SUCCESS; + + __try + { + PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pInputHdr = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pCommand; + switch (pInputHdr->enmCmd) + { + case VBOXVDMACMD_TYPE_DMA_NOP: + { + PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pDmaBufferPrivateData; + pPrivateData->enmCmd = VBOXVDMACMD_TYPE_DMA_NOP; + pRender->pDmaBufferPrivateData = (uint8_t*)pRender->pDmaBufferPrivateData + sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR); + pRender->pDmaBuffer = ((uint8_t*)pRender->pDmaBuffer) + pRender->CommandLength; + for (UINT i = 0; i < pRender->PatchLocationListInSize; ++i) + { + UINT offPatch = i * 4; + if (offPatch + 4 > pRender->CommandLength) + { + WARN(("wrong offPatch")); + return STATUS_INVALID_PARAMETER; + } + if (offPatch != pRender->pPatchLocationListIn[i].PatchOffset) + { + WARN(("wrong PatchOffset")); + return STATUS_INVALID_PARAMETER; + } + if (i != pRender->pPatchLocationListIn[i].AllocationIndex) + { + WARN(("wrong AllocationIndex")); + return STATUS_INVALID_PARAMETER; + } + vboxWddmPatchLocationInit(&pRender->pPatchLocationListOut[i], i, offPatch); + } + break; + } + default: + { + WARN(("unsupported command %d", pInputHdr->enmCmd)); + return STATUS_INVALID_PARAMETER; + } + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + Status = STATUS_INVALID_PARAMETER; + WARN(("invalid parameter")); + } // LOGF(("LEAVE, hContext(0x%x)", hContext)); return Status; @@ -5536,12 +6014,27 @@ DECLINLINE(BOOLEAN) vboxWddmPixFormatConversionSupported(D3DDDIFORMAT From, D3DD return From == To; } +DECLINLINE(bool) VBoxCVDdiFillAllocInfo(VBOXCMDVBVA_HDR* pHdr, + VBOXCMDVBVA_ALLOCINFO *pInfo, PVBOXWDDM_ALLOCATION pAlloc, DXGK_ALLOCATIONLIST *pList, bool fDst) +{ + if (pAlloc->AllocData.hostID) + { + pHdr->u8Flags |= (fDst ? VBOXCMDVBVA_OPF_ALLOC_DSTID : VBOXCMDVBVA_OPF_ALLOC_SRCID); + pInfo->u.id = pAlloc->AllocData.hostID; + return false; + } + + Assert(!pList->PhysicalAddress.HighPart); + pInfo->u.offVRAM = pList->PhysicalAddress.LowPart; + return true; +} + /** * DxgkDdiPresent */ -NTSTATUS +static NTSTATUS APIENTRY -DxgkDdiPresent( +DxgkDdiPresentNew( CONST HANDLE hContext, DXGKARG_PRESENT *pPresent) { @@ -5551,24 +6044,32 @@ DxgkDdiPresent( vboxVDbgBreakFv(); - NTSTATUS Status = STATUS_SUCCESS; PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext; PVBOXWDDM_DEVICE pDevice = pContext->pDevice; PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter; - Assert(pPresent->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)); - if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)) + if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_HDR)) { - LOGREL(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR))); - /* @todo: can this actually happen? what status tu return? */ + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_HDR (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_HDR))); + /* @todo: can this actually happen? what status to return? */ return STATUS_INVALID_PARAMETER; } - PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)pPresent->pDmaBufferPrivateData; - pPrivateData->BaseHdr.fFlags.Value = 0; - uint32_t cContexts3D = ASMAtomicReadU32(&pDevExt->cContexts3D); - uint32_t cContexts2D = ASMAtomicReadU32(&pDevExt->cContexts2D); -#define VBOXWDDM_DUMMY_DMABUFFER_SIZE sizeof(RECT) + VBOXCMDVBVA_HDR* pHdr = (VBOXCMDVBVA_HDR*)pPresent->pDmaBufferPrivateData; + + UINT u32SrcPatch = ~0UL; + UINT u32DstPatch = ~0UL; + BOOLEAN fPatchSrc = false; + BOOLEAN fPatchDst = false; + VBOXCMDVBVA_RECT *paRects = NULL; + uint32_t cbMaxRects; + + if (pPresent->DmaSize < VBOXWDDM_DUMMY_DMABUFFER_SIZE) + { + WARN(("Present->DmaSize(%d) < VBOXWDDM_DUMMY_DMABUFFER_SIZE (%d)", pPresent->DmaSize , VBOXWDDM_DUMMY_DMABUFFER_SIZE)); + /* @todo: can this actually happen? what status to return? */ + return STATUS_INVALID_PARAMETER; + } if (pPresent->Flags.Blt) { @@ -5576,348 +6077,348 @@ DxgkDdiPresent( DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX]; DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX]; PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pSrc); - Assert(pSrcAlloc); - if (pSrcAlloc) + if (!pSrcAlloc) { - PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pDst); - Assert(pDstAlloc); - if (pDstAlloc) - { - do - { -#ifdef VBOXWDDM_RENDER_FROM_SHADOW -#if 0 - Assert (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE); - Assert (pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE); -#else - if (pContext->enmType == VBOXWDDM_CONTEXT_TYPE_SYSTEM) - { - Assert ((pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE - && pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE) - || (pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE - && pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE)); - } -#endif - /* issue VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE ONLY in case there are no 3D contexts currently - * otherwise we would need info about all rects being updated on primary for visible rect reporting */ - if (!cContexts3D && !cContexts2D) - { - if (pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE - && pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE) - { - Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_SYSTEM); - Assert(pDstAlloc->bAssigned); - if (pDstAlloc->bAssigned) - { -#ifdef VBOX_WITH_VIDEOHWACCEL -// if (vboxVhwaHlpOverlayListIsEmpty(pDevExt, pDstAlloc->AllocData.SurfDesc.VidPnSourceId)) -#endif - { - Assert(pPresent->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_SHADOW2PRIMARY)); - if (pPresent->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_SHADOW2PRIMARY)) - { - Assert(pPresent->SrcRect.left == pPresent->DstRect.left); - Assert(pPresent->SrcRect.right == pPresent->DstRect.right); - Assert(pPresent->SrcRect.top == pPresent->DstRect.top); - Assert(pPresent->SrcRect.bottom == pPresent->DstRect.bottom); - RECT rect; - if (pPresent->SubRectCnt) - { - rect = pPresent->pDstSubRects[0]; - for (UINT i = 1; i < pPresent->SubRectCnt; ++i) - { - vboxWddmRectUnited(&rect, &rect, &pPresent->pDstSubRects[i]); - } - } - else - rect = pPresent->SrcRect; - - - pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + sizeof (VBOXWDDM_DMA_PRIVATEDATA_SHADOW2PRIMARY); - pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; - Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE); - memset(pPresent->pPatchLocationListOut, 0, 2*sizeof (D3DDDI_PATCHLOCATIONLIST)); - pPresent->pPatchLocationListOut->PatchOffset = 0; - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; - ++pPresent->pPatchLocationListOut; - pPresent->pPatchLocationListOut->PatchOffset = 4; - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; - ++pPresent->pPatchLocationListOut; - - pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_SHADOW2PRIMARY; - PVBOXWDDM_DMA_PRIVATEDATA_SHADOW2PRIMARY pS2P = (PVBOXWDDM_DMA_PRIVATEDATA_SHADOW2PRIMARY)pPrivateData; - /* we do not know the shadow address yet, perform dummy DMA cycle */ - vboxWddmPopulateDmaAllocInfo(&pS2P->Shadow2Primary.ShadowAlloc, pSrcAlloc, pSrc); -// vboxWddmPopulateDmaAllocInfo(&pPrivateData->DstAllocInfo, pDstAlloc, pDst); - pS2P->Shadow2Primary.SrcRect = rect; - pS2P->Shadow2Primary.VidPnSourceId = pDstAlloc->AllocData.SurfDesc.VidPnSourceId; - break; - } - else - { - Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; - break; - } - } - } - } - } + /* this should not happen actually */ + WARN(("failed to get Src Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation)); + return STATUS_INVALID_HANDLE; + } - /* we're here because this is NOT a shadow->primary update - * or because there are d3d contexts and we need to report visible rects - * or because we have overlays active and we need a special handling for primary */ -#endif - UINT cbCmd = pPresent->DmaBufferPrivateDataSize; - pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT; - - PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateData; - - vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.SrcAlloc, pSrcAlloc, pSrc); - vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.DstAlloc, pDstAlloc, pDst); - - ASSERT_WARN(!pSrcAlloc->fRcFlags.SharedResource, ("Shared Allocatoin used in Present!")); - - pBlt->Blt.SrcRect = pPresent->SrcRect; - pBlt->Blt.DstRects.ContextRect = pPresent->DstRect; - pBlt->Blt.DstRects.UpdateRects.cRects = 0; - UINT cbHead = RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_BLT, Blt.DstRects.UpdateRects.aRects[0]); - Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); - UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT); - pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects; - pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; - Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE); - cbCmd -= cbHead; - Assert(cbCmd < UINT32_MAX/2); - Assert(cbCmd > sizeof (RECT)); - if (cbCmd >= cbRects) - { - cbCmd -= cbRects; - memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbRects); - pBlt->Blt.DstRects.UpdateRects.cRects += cbRects/sizeof (RECT); - } - else - { - UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT); - Assert(cbFitingRects); - memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbFitingRects); - cbCmd -= cbFitingRects; - pPresent->MultipassOffset += cbFitingRects/sizeof (RECT); - pBlt->Blt.DstRects.UpdateRects.cRects += cbFitingRects/sizeof (RECT); - Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); - Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; - } + PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pDst); + if (!pDstAlloc) + { + /* this should not happen actually */ + WARN(("failed to get Dst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation)); + return STATUS_INVALID_HANDLE; + } - memset(pPresent->pPatchLocationListOut, 0, 2*sizeof (D3DDDI_PATCHLOCATIONLIST)); - pPresent->pPatchLocationListOut->PatchOffset = 0; - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; - ++pPresent->pPatchLocationListOut; - pPresent->pPatchLocationListOut->PatchOffset = 4; - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; - ++pPresent->pPatchLocationListOut; + fPatchSrc = TRUE; + fPatchDst = TRUE; - break; -#ifdef VBOX_WITH_VDMA - cbCmd = pPresent->DmaSize; - - Assert(pPresent->SubRectCnt); - UINT cmdSize = VBOXVDMACMD_DMA_PRESENT_BLT_SIZE(pPresent->SubRectCnt - pPresent->MultipassOffset); - PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pPresent->pDmaBuffer; - pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + cmdSize; - Assert(cbCmd >= VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE()); - if (cbCmd >= VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE()) - { - if (vboxWddmPixFormatConversionSupported(pSrcAlloc->AllocData.SurfDesc.format, pDstAlloc->AllocData.SurfDesc.format)) - { - memset(pPresent->pPatchLocationListOut, 0, 2*sizeof (D3DDDI_PATCHLOCATIONLIST)); - // pPresent->pPatchLocationListOut->PatchOffset = 0; - // ++pPresent->pPatchLocationListOut; - pPresent->pPatchLocationListOut->PatchOffset = VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, offSrc); - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; - ++pPresent->pPatchLocationListOut; - pPresent->pPatchLocationListOut->PatchOffset = VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, offDst); - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; - ++pPresent->pPatchLocationListOut; - - pCmd->enmType = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT; - pCmd->u32CmdSpecific = 0; - PVBOXVDMACMD_DMA_PRESENT_BLT pTransfer = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT); - pTransfer->offSrc = (VBOXVIDEOOFFSET)pSrc->PhysicalAddress.QuadPart; - pTransfer->offDst = (VBOXVIDEOOFFSET)pDst->PhysicalAddress.QuadPart; - vboxWddmSurfDescFromAllocation(pSrcAlloc, &pTransfer->srcDesc); - vboxWddmSurfDescFromAllocation(pDstAlloc, &pTransfer->dstDesc); - vboxWddmRectlFromRect(&pPresent->SrcRect, &pTransfer->srcRectl); - vboxWddmRectlFromRect(&pPresent->DstRect, &pTransfer->dstRectl); - UINT i = 0; - cbCmd -= VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects); - Assert(cbCmd >= sizeof (VBOXVDMA_RECTL)); - Assert(cbCmd < pPresent->DmaSize); - for (; i < pPresent->SubRectCnt; ++i) - { - if (cbCmd < sizeof (VBOXVDMA_RECTL)) - { - Assert(i); - pPresent->MultipassOffset += i; - Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; - break; - } - vboxWddmRectlFromRect(&pPresent->pDstSubRects[i + pPresent->MultipassOffset], &pTransfer->aDstSubRects[i]); - cbCmd -= sizeof (VBOXVDMA_RECTL); - } - Assert(i); - pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT; - pTransfer->cDstSubRects = i; - pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + sizeof(VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR); - } - else - { - AssertBreakpoint(); - LOGREL(("unsupported format conversion from(%d) to (%d)",pSrcAlloc->AllocData.SurfDesc.format, pDstAlloc->AllocData.SurfDesc.format)); - Status = STATUS_GRAPHICS_CANNOTCOLORCONVERT; - } - } - else - { - /* this should not happen actually */ - LOGREL(("cbCmd too small!! (%d)", cbCmd)); - Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; - } -#endif - } while(0); - } - else + BOOLEAN fDstPrimary = (!pDstAlloc->AllocData.hostID + && pDstAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE + && pDstAlloc->bAssigned); + BOOLEAN fSrcPrimary = (!pSrcAlloc->AllocData.hostID + && pSrcAlloc->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE + && pSrcAlloc->bAssigned); + + pHdr->u8OpCode = VBOXCMDVBVA_OPTYPE_BLT_OFFPRIMSZFMT_OR_ID; + pHdr->u8Flags = 0; + + if (fDstPrimary || fSrcPrimary) + { + if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_BLT_PRIMARY)) { - /* this should not happen actually */ - LOGREL(("failed to get Dst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation)); - Status = STATUS_INVALID_HANDLE; + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_BLT_PRIMARY (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_BLT_PRIMARY))); + /* @todo: can this actually happen? what status to return? */ + return STATUS_INVALID_PARAMETER; } - } - else - { - /* this should not happen actually */ - LOGREL(("failed to get Src Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation)); - Status = STATUS_INVALID_HANDLE; - } -#if 0 - UINT cbCmd = pPresent->DmaSize; - - Assert(pPresent->SubRectCnt); - UINT cmdSize = VBOXVDMACMD_DMA_PRESENT_BLT_SIZE(pPresent->SubRectCnt - pPresent->MultipassOffset); - PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pPresent->pDmaBuffer; - pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + cmdSize; - Assert(cbCmd >= VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE()); - if (cbCmd >= VBOXVDMACMD_DMA_PRESENT_BLT_MINSIZE()) - { - DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX]; - DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX]; - PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pSrc); - Assert(pSrcAlloc); - if (pSrcAlloc) + + VBOXCMDVBVA_BLT_PRIMARY *pBlt = (VBOXCMDVBVA_BLT_PRIMARY*)pHdr; + + /* this is the most common case, so we optimize it a bit with VBOXCMDVBVA_BLT_PRIMARY */ + + if (fSrcPrimary) { - PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pDst); - Assert(pDstAlloc); - if (pDstAlloc) - { - if (vboxWddmPixFormatConversionSupported(pSrcAlloc->AllocData.SurfDesc.format, pDstAlloc->AllocData.SurfDesc.format)) - { - memset(pPresent->pPatchLocationListOut, 0, 2*sizeof (D3DDDI_PATCHLOCATIONLIST)); -// pPresent->pPatchLocationListOut->PatchOffset = 0; -// ++pPresent->pPatchLocationListOut; - pPresent->pPatchLocationListOut->PatchOffset = VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, offSrc); - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; - ++pPresent->pPatchLocationListOut; - pPresent->pPatchLocationListOut->PatchOffset = VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, offDst); - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; - ++pPresent->pPatchLocationListOut; - - pCmd->enmType = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT; - pCmd->u32CmdSpecific = 0; - PVBOXVDMACMD_DMA_PRESENT_BLT pTransfer = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT); - pTransfer->offSrc = (VBOXVIDEOOFFSET)pSrc->PhysicalAddress.QuadPart; - pTransfer->offDst = (VBOXVIDEOOFFSET)pDst->PhysicalAddress.QuadPart; - vboxWddmSurfDescFromAllocation(pSrcAlloc, &pTransfer->srcDesc); - vboxWddmSurfDescFromAllocation(pDstAlloc, &pTransfer->dstDesc); - vboxWddmRectlFromRect(&pPresent->SrcRect, &pTransfer->srcRectl); - vboxWddmRectlFromRect(&pPresent->DstRect, &pTransfer->dstRectl); - UINT i = 0; - cbCmd -= VBOXVDMACMD_BODY_FIELD_OFFSET(UINT, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects); - Assert(cbCmd >= sizeof (VBOXVDMA_RECTL)); - Assert(cbCmd < pPresent->DmaSize); - for (; i < pPresent->SubRectCnt; ++i) - { - if (cbCmd < sizeof (VBOXVDMA_RECTL)) - { - Assert(i); - pPresent->MultipassOffset += i; - Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; - break; - } - vboxWddmRectlFromRect(&pPresent->pDstSubRects[i + pPresent->MultipassOffset], &pTransfer->aDstSubRects[i]); - cbCmd -= sizeof (VBOXVDMA_RECTL); - } - Assert(i); - pTransfer->cDstSubRects = i; - pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + sizeof(VBOXWDDM_DMA_PRIVATEDATA_HDR); - } - else - { - AssertBreakpoint(); - LOGREL(("unsupported format conversion from(%d) to (%d)",pSrcAlloc->AllocData.SurfDesc.format, pDstAlloc->AllocData.SurfDesc.format)); - Status = STATUS_GRAPHICS_CANNOTCOLORCONVERT; - } - } - else + pBlt->Hdr.u8Flags |= VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY; + pBlt->Hdr.u.u8PrimaryID = pSrcAlloc->AllocData.SurfDesc.VidPnSourceId; + + if (fDstPrimary) { - /* this should not happen actually */ - LOGREL(("failed to get Dst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation)); - Status = STATUS_INVALID_HANDLE; + pBlt->Hdr.u8Flags |= VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY; + pBlt->alloc.u.id = pDstAlloc->AllocData.SurfDesc.VidPnSourceId; } + else if (VBoxCVDdiFillAllocInfo(pHdr, &pBlt->alloc, pDstAlloc, pDst, true)) + u32DstPatch = RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, alloc.u.offVRAM); } else { - /* this should not happen actually */ - LOGREL(("failed to get Src Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation)); - Status = STATUS_INVALID_HANDLE; + Assert(fDstPrimary); + pBlt->Hdr.u8Flags |= VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY; + pBlt->Hdr.u.u8PrimaryID = pDstAlloc->AllocData.SurfDesc.VidPnSourceId; + + if (VBoxCVDdiFillAllocInfo(pHdr, &pBlt->alloc, pSrcAlloc, pSrc, false)) + u32SrcPatch = RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, alloc.u.offVRAM); } + + pBlt->Pos.x = (int16_t)(pPresent->DstRect.left - pPresent->SrcRect.left); + pBlt->Pos.y = (int16_t)(pPresent->DstRect.top - pPresent->SrcRect.top); + + paRects = pBlt->aRects; + cbMaxRects = pPresent->DmaBufferPrivateDataSize - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects); } else { - /* this should not happen actually */ - LOGREL(("cbCmd too small!! (%d)", cbCmd)); - Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; + if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID)) + { + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID))); + /* @todo: can this actually happen? what status to return? */ + return STATUS_INVALID_PARAMETER; + } + + VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID *pBlt = (VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID*)pHdr; + + if (VBoxCVDdiFillAllocInfo(pHdr, &pBlt->src, pSrcAlloc, pSrc, false)) + u32SrcPatch = RT_OFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, src.u.offVRAM); + + if (VBoxCVDdiFillAllocInfo(pHdr, &pBlt->dst, pDstAlloc, pDst, true)) + u32DstPatch = RT_OFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, dst.u.offVRAM); + + pBlt->Pos.x = (int16_t)(pPresent->DstRect.left - pPresent->SrcRect.left); + pBlt->Pos.y = (int16_t)(pPresent->DstRect.top - pPresent->SrcRect.top); + + paRects = pBlt->aRects; + cbMaxRects = pPresent->DmaBufferPrivateDataSize - RT_OFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, aRects); } -#endif } else if (pPresent->Flags.Flip) { + if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_FLIP)) + { + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_FLIP (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_FLIP))); + /* @todo: can this actually happen? what status to return? */ + return STATUS_INVALID_PARAMETER; + } + + fPatchSrc = TRUE; + Assert(pPresent->Flags.Value == 4); /* only Blt is set, we do not support anything else for now */ Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D); DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX]; PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pSrc); - Assert(pSrcAlloc); - if (pSrcAlloc) + + if (!pSrcAlloc) { - Assert(cContexts3D); - pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP; - PVBOXWDDM_DMA_PRIVATEDATA_FLIP pFlip = (PVBOXWDDM_DMA_PRIVATEDATA_FLIP)pPrivateData; + /* this should not happen actually */ + WARN(("failed to get pSrc Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation)); + return STATUS_INVALID_HANDLE; + } - vboxWddmPopulateDmaAllocInfo(&pFlip->Flip.Alloc, pSrcAlloc, pSrc); + Assert(pDevExt->cContexts3D); + pHdr->u8OpCode = VBOXCMDVBVA_OPTYPE_FLIP; + pHdr->u8Flags = 0; + VBOXCMDVBVA_FLIP *pFlip = (VBOXCMDVBVA_FLIP*)pHdr; - UINT cbCmd = sizeof (VBOXWDDM_DMA_PRIVATEDATA_FLIP); - pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbCmd; - pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; - Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE); + if (VBoxCVDdiFillAllocInfo(pHdr, &pFlip->src, pSrcAlloc, pSrc, false)) + u32SrcPatch = RT_OFFSETOF(VBOXCMDVBVA_FLIP, src.u.offVRAM); + } + else if (pPresent->Flags.ColorFill) + { + if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXCMDVBVA_CLRFILL)) + { + WARN(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXCMDVBVA_CLRFILL (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXCMDVBVA_CLRFILL))); + /* @todo: can this actually happen? what status to return? */ + return STATUS_INVALID_PARAMETER; + } - memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST)); - pPresent->pPatchLocationListOut->PatchOffset = 0; - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; - ++pPresent->pPatchLocationListOut; + fPatchDst = TRUE; + + Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_2D); + Assert(pPresent->Flags.Value == 2); /* only ColorFill is set, we do not support anything else for now */ + DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX]; + PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pDst); + if (!pDstAlloc) + { + /* this should not happen actually */ + WARN(("failed to get pDst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation)); + return STATUS_INVALID_HANDLE; + } + + pHdr->u8OpCode = VBOXCMDVBVA_OPTYPE_CLRFILL; + pHdr->u8Flags = 0; + VBOXCMDVBVA_CLRFILL *pCFill = (VBOXCMDVBVA_CLRFILL*)pHdr; + + if (VBoxCVDdiFillAllocInfo(pHdr, &pCFill->dst, pDstAlloc, pDst, true)) + u32DstPatch = RT_OFFSETOF(VBOXCMDVBVA_CLRFILL, dst.u.offVRAM); + + paRects = pCFill->aRects; + cbMaxRects = pPresent->DmaBufferPrivateDataSize - RT_OFFSETOF(VBOXCMDVBVA_CLRFILL, aRects); + } + else + { + WARN(("cmd NOT IMPLEMENTED!! Flags(0x%x)", pPresent->Flags.Value)); + return STATUS_NOT_SUPPORTED; + } + + if (paRects) + { + UINT iStartRect = pPresent->MultipassOffset; + UINT cMaxRects = cbMaxRects / sizeof (VBOXCMDVBVA_RECT); + Assert(pPresent->SubRectCnt > iStartRect); + UINT cRects = pPresent->SubRectCnt - iStartRect; + if (cRects > cMaxRects) + { + pPresent->MultipassOffset += cMaxRects; + cRects = cMaxRects; } else + pPresent->MultipassOffset = 0; + + const RECT *paDstSubRects = &pPresent->pDstSubRects[iStartRect]; + VBoxCVDdiPackRects(paRects, paDstSubRects, cRects); + } + + if (fPatchSrc) + { + memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST)); + pPresent->pPatchLocationListOut->PatchOffset = u32SrcPatch; + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; + ++pPresent->pPatchLocationListOut; + } + + if (fPatchDst) + { + memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST)); + pPresent->pPatchLocationListOut->PatchOffset = u32DstPatch; + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; + ++pPresent->pPatchLocationListOut; + } + + pHdr->u8State = VBOXCMDVBVA_STATE_SUBMITTED; + /* sanity */ + pHdr->u32FenceID = 0; + + pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; + + if (pPresent->MultipassOffset) + return STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; + return STATUS_SUCCESS; +} + +/** + * DxgkDdiPresent + */ +static NTSTATUS +APIENTRY +DxgkDdiPresentLegacy( + CONST HANDLE hContext, + DXGKARG_PRESENT *pPresent) +{ + PAGED_CODE(); + +// LOGF(("ENTER, hContext(0x%x)", hContext)); + + vboxVDbgBreakFv(); + + NTSTATUS Status = STATUS_SUCCESS; + PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext; + PVBOXWDDM_DEVICE pDevice = pContext->pDevice; + PVBOXMP_DEVEXT pDevExt = pDevice->pAdapter; + + Assert(pPresent->DmaBufferPrivateDataSize >= sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)); + if (pPresent->DmaBufferPrivateDataSize < sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)) + { + LOGREL(("Present->DmaBufferPrivateDataSize(%d) < sizeof VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR (%d)", pPresent->DmaBufferPrivateDataSize , sizeof (VBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR))); + /* @todo: can this actually happen? what status tu return? */ + return STATUS_INVALID_PARAMETER; + } + + PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR pPrivateData = (PVBOXWDDM_DMA_PRIVATEDATA_PRESENTHDR)pPresent->pDmaBufferPrivateData; + pPrivateData->BaseHdr.fFlags.Value = 0; + uint32_t cContexts2D = ASMAtomicReadU32(&pDevExt->cContexts2D); + + if (pPresent->Flags.Blt) + { + Assert(pPresent->Flags.Value == 1); /* only Blt is set, we do not support anything else for now */ + DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX]; + DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX]; + PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pSrc); + if (!pSrcAlloc) { /* this should not happen actually */ - LOGREL(("failed to get pSrc Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation)); + WARN(("failed to get Src Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation)); Status = STATUS_INVALID_HANDLE; + goto done; } + + PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pDst); + if (!pDstAlloc) + { + /* this should not happen actually */ + WARN(("failed to get Dst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation)); + Status = STATUS_INVALID_HANDLE; + goto done; + } + + + UINT cbCmd = pPresent->DmaBufferPrivateDataSize; + pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_BLT; + + PVBOXWDDM_DMA_PRIVATEDATA_BLT pBlt = (PVBOXWDDM_DMA_PRIVATEDATA_BLT)pPrivateData; + + vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.SrcAlloc, pSrcAlloc, pSrc); + vboxWddmPopulateDmaAllocInfo(&pBlt->Blt.DstAlloc, pDstAlloc, pDst); + + ASSERT_WARN(!pSrcAlloc->fRcFlags.SharedResource, ("Shared Allocatoin used in Present!")); + + pBlt->Blt.SrcRect = pPresent->SrcRect; + pBlt->Blt.DstRects.ContextRect = pPresent->DstRect; + pBlt->Blt.DstRects.UpdateRects.cRects = 0; + UINT cbHead = RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_BLT, Blt.DstRects.UpdateRects.aRects[0]); + Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); + UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT); + pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects; + pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; + Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE); + cbCmd -= cbHead; + Assert(cbCmd < UINT32_MAX/2); + Assert(cbCmd > sizeof (RECT)); + if (cbCmd >= cbRects) + { + cbCmd -= cbRects; + memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[pPresent->MultipassOffset], &pPresent->pDstSubRects[pPresent->MultipassOffset], cbRects); + pBlt->Blt.DstRects.UpdateRects.cRects += cbRects/sizeof (RECT); + } + else + { + UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT); + Assert(cbFitingRects); + memcpy(&pBlt->Blt.DstRects.UpdateRects.aRects[pPresent->MultipassOffset], &pPresent->pDstSubRects[pPresent->MultipassOffset], cbFitingRects); + cbCmd -= cbFitingRects; + pPresent->MultipassOffset += cbFitingRects/sizeof (RECT); + pBlt->Blt.DstRects.UpdateRects.cRects += cbFitingRects/sizeof (RECT); + Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); + Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; + } + + memset(pPresent->pPatchLocationListOut, 0, 2*sizeof (D3DDDI_PATCHLOCATIONLIST)); + pPresent->pPatchLocationListOut->PatchOffset = 0; + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; + ++pPresent->pPatchLocationListOut; + pPresent->pPatchLocationListOut->PatchOffset = 4; + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; + ++pPresent->pPatchLocationListOut; + } + else if (pPresent->Flags.Flip) + { + Assert(pPresent->Flags.Value == 4); /* only Blt is set, we do not support anything else for now */ + Assert(pContext->enmType == VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D); + DXGK_ALLOCATIONLIST *pSrc = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX]; + PVBOXWDDM_ALLOCATION pSrcAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pSrc); + + if (!pSrcAlloc) + { + /* this should not happen actually */ + WARN(("failed to get pSrc Allocation info for hDeviceSpecificAllocation(0x%x)",pSrc->hDeviceSpecificAllocation)); + Status = STATUS_INVALID_HANDLE; + goto done; + } + + Assert(pDevExt->cContexts3D); + pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP; + PVBOXWDDM_DMA_PRIVATEDATA_FLIP pFlip = (PVBOXWDDM_DMA_PRIVATEDATA_FLIP)pPrivateData; + + vboxWddmPopulateDmaAllocInfo(&pFlip->Flip.Alloc, pSrcAlloc, pSrc); + + UINT cbCmd = sizeof (VBOXWDDM_DMA_PRIVATEDATA_FLIP); + pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbCmd; + pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; + Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE); + + memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST)); + pPresent->pPatchLocationListOut->PatchOffset = 0; + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; + ++pPresent->pPatchLocationListOut; } else if (pPresent->Flags.ColorFill) { @@ -5925,63 +6426,62 @@ DxgkDdiPresent( Assert(pPresent->Flags.Value == 2); /* only ColorFill is set, we do not support anything else for now */ DXGK_ALLOCATIONLIST *pDst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX]; PVBOXWDDM_ALLOCATION pDstAlloc = vboxWddmGetAllocationFromAllocList(pDevExt, pDst); - Assert(pDstAlloc); - if (pDstAlloc) + if (!pDstAlloc) { - UINT cbCmd = pPresent->DmaBufferPrivateDataSize; - pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL; - PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateData; - - vboxWddmPopulateDmaAllocInfo(&pCF->ClrFill.Alloc, pDstAlloc, pDst); - pCF->ClrFill.Color = pPresent->Color; - pCF->ClrFill.Rects.cRects = 0; - UINT cbHead = RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_CLRFILL, ClrFill.Rects.aRects[0]); - Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); - UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT); - pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects; - pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; - Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE); - cbCmd -= cbHead; - Assert(cbCmd < UINT32_MAX/2); - Assert(cbCmd > sizeof (RECT)); - if (cbCmd >= cbRects) - { - cbCmd -= cbRects; - memcpy(&pCF->ClrFill.Rects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbRects); - pCF->ClrFill.Rects.cRects += cbRects/sizeof (RECT); - } - else - { - UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT); - Assert(cbFitingRects); - memcpy(&pCF->ClrFill.Rects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbFitingRects); - cbCmd -= cbFitingRects; - pPresent->MultipassOffset += cbFitingRects/sizeof (RECT); - pCF->ClrFill.Rects.cRects += cbFitingRects/sizeof (RECT); - Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); - Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; - } + /* this should not happen actually */ + WARN(("failed to get pDst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation)); + Status = STATUS_INVALID_HANDLE; + goto done; + } - memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST)); - pPresent->pPatchLocationListOut->PatchOffset = 0; - pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; - ++pPresent->pPatchLocationListOut; + UINT cbCmd = pPresent->DmaBufferPrivateDataSize; + pPrivateData->BaseHdr.enmCmd = VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL; + PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL pCF = (PVBOXWDDM_DMA_PRIVATEDATA_CLRFILL)pPrivateData; + + vboxWddmPopulateDmaAllocInfo(&pCF->ClrFill.Alloc, pDstAlloc, pDst); + + pCF->ClrFill.Color = pPresent->Color; + pCF->ClrFill.Rects.cRects = 0; + UINT cbHead = RT_OFFSETOF(VBOXWDDM_DMA_PRIVATEDATA_CLRFILL, ClrFill.Rects.aRects[0]); + Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); + UINT cbRects = (pPresent->SubRectCnt - pPresent->MultipassOffset) * sizeof (RECT); + pPresent->pDmaBufferPrivateData = (uint8_t*)pPresent->pDmaBufferPrivateData + cbHead + cbRects; + pPresent->pDmaBuffer = ((uint8_t*)pPresent->pDmaBuffer) + VBOXWDDM_DUMMY_DMABUFFER_SIZE; + Assert(pPresent->DmaSize >= VBOXWDDM_DUMMY_DMABUFFER_SIZE); + cbCmd -= cbHead; + Assert(cbCmd < UINT32_MAX/2); + Assert(cbCmd > sizeof (RECT)); + if (cbCmd >= cbRects) + { + cbCmd -= cbRects; + memcpy(&pCF->ClrFill.Rects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbRects); + pCF->ClrFill.Rects.cRects += cbRects/sizeof (RECT); } else { - /* this should not happen actually */ - LOGREL(("failed to get pDst Allocation info for hDeviceSpecificAllocation(0x%x)",pDst->hDeviceSpecificAllocation)); - Status = STATUS_INVALID_HANDLE; + UINT cbFitingRects = (cbCmd/sizeof (RECT)) * sizeof (RECT); + Assert(cbFitingRects); + memcpy(&pCF->ClrFill.Rects.aRects[pPresent->MultipassOffset], pPresent->pDstSubRects, cbFitingRects); + cbCmd -= cbFitingRects; + pPresent->MultipassOffset += cbFitingRects/sizeof (RECT); + pCF->ClrFill.Rects.cRects += cbFitingRects/sizeof (RECT); + Assert(pPresent->SubRectCnt > pPresent->MultipassOffset); + Status = STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER; } + memset(pPresent->pPatchLocationListOut, 0, sizeof (D3DDDI_PATCHLOCATIONLIST)); + pPresent->pPatchLocationListOut->PatchOffset = 0; + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; + ++pPresent->pPatchLocationListOut; } else { - LOGREL(("cmd NOT IMPLEMENTED!! Flags(0x%x)", pPresent->Flags.Value)); - AssertBreakpoint(); + WARN(("cmd NOT IMPLEMENTED!! Flags(0x%x)", pPresent->Flags.Value)); + Status = STATUS_NOT_SUPPORTED; } +done: // LOGF(("LEAVE, hContext(0x%x), Status(0x%x)", hContext, Status)); return Status; @@ -6100,10 +6600,20 @@ DxgkDdiCreateContext( pContext->enmType = VBOXWDDM_CONTEXT_TYPE_SYSTEM; for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) { - pDevExt->aSources[i].bGhSynced = FALSE; + pDevExt->aSources[i].u8SyncState = 0; NTSTATUS tmpStatus= vboxWddmDisplaySettingsQueryPos(pDevExt, i, &pDevExt->aSources[i].VScreenPos); Assert(tmpStatus == STATUS_SUCCESS); } + + if (!VBOXWDDM_IS_DISPLAYONLY() && pDevExt->f3DEnabled) + { + VBoxMpCrPackerInit(&pContext->CrPacker); + int rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR, &pContext->u32CrConClientID); + if (!RT_SUCCESS(rc)) + WARN(("VBoxMpCrCtlConConnect failed rc (%d), ignoring for system context", rc)); + } + + Status = STATUS_SUCCESS; } else { @@ -6130,20 +6640,31 @@ DxgkDdiCreateContext( Assert(Status == STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { - int rc = VINF_SUCCESS; if (pInfo->crVersionMajor || pInfo->crVersionMinor) { - rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, - pInfo->crVersionMajor, pInfo->crVersionMinor, - &pContext->u32CrConClientID); - if (!RT_SUCCESS(rc)) + if (pDevExt->f3DEnabled) + { + int rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, + pInfo->crVersionMajor, pInfo->crVersionMinor, + &pContext->u32CrConClientID); + if (RT_SUCCESS(rc)) + { + VBoxMpCrPackerInit(&pContext->CrPacker); + } + else + { + WARN(("VBoxMpCrCtlConConnect failed rc (%d)", rc)); + Status = STATUS_UNSUCCESSFUL; + } + } + else { - WARN(("VBoxMpCrCtlConConnect failed rc (%d)", rc)); + LOG(("3D Not Enabled, failing 3D context creation")); Status = STATUS_UNSUCCESSFUL; } } - if (RT_SUCCESS(rc)) + if (NT_SUCCESS(Status)) { ASMAtomicIncU32(&pDevExt->cContexts3D); break; @@ -6164,20 +6685,27 @@ DxgkDdiCreateContext( Assert(Status == STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { - int rc = VINF_SUCCESS; if (pInfo->crVersionMajor || pInfo->crVersionMinor) { - rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, - pInfo->crVersionMajor, pInfo->crVersionMinor, - &pContext->u32CrConClientID); - if (!RT_SUCCESS(rc)) + if (pDevExt->f3DEnabled) { - WARN(("VBoxMpCrCtlConConnect failed rc (%d)", rc)); + int rc = VBoxMpCrCtlConConnect(&pDevExt->CrCtlCon, + pInfo->crVersionMajor, pInfo->crVersionMinor, + &pContext->u32CrConClientID); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxMpCrCtlConConnect failed rc (%d)", rc)); + Status = STATUS_UNSUCCESSFUL; + } + } + else + { + LOG(("3D Not Enabled, failing 3D (hgsmi) context creation")); Status = STATUS_UNSUCCESSFUL; } } - if (RT_SUCCESS(rc)) + if (NT_SUCCESS(Status)) { ASMAtomicIncU32(&pDevExt->cContexts3D); break; @@ -6192,9 +6720,25 @@ DxgkDdiCreateContext( ASMAtomicIncU32(&pDevExt->cContexts2D); break; } + case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE: + { + pContext->enmType = pInfo->enmType; + ASMAtomicIncU32(&pDevExt->cContextsDispIfResize); + break; + } + case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS: + { + pContext->enmType = pInfo->enmType; + Status = vboxVideoCmCtxAdd(&pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext, (HANDLE)pInfo->hUmEvent, pInfo->u64UmInfo); + if (!NT_SUCCESS(Status)) + { + WARN(("vboxVideoCmCtxAdd failed, Status 0x%x", Status)); + } + break; + } default: { - Assert(0); + WARN(("unsupported context type %d", pInfo->enmType)); Status = STATUS_INVALID_PARAMETER; break; } @@ -6235,6 +6779,8 @@ DxgkDdiDestroyContext( vboxVDbgBreakFv(); PVBOXWDDM_CONTEXT pContext = (PVBOXWDDM_CONTEXT)hContext; PVBOXMP_DEVEXT pDevExt = pContext->pDevice->pAdapter; + NTSTATUS Status = STATUS_SUCCESS; + switch(pContext->enmType) { case VBOXWDDM_CONTEXT_TYPE_CUSTOM_3D: @@ -6243,10 +6789,6 @@ DxgkDdiDestroyContext( { uint32_t cContexts = ASMAtomicDecU32(&pDevExt->cContexts3D); Assert(cContexts < UINT32_MAX/2); - if (pContext->u32CrConClientID) - { - VBoxMpCrCtlConDisconnect(&pDevExt->CrCtlCon, pContext->u32CrConClientID); - } break; } case VBOXWDDM_CONTEXT_TYPE_CUSTOM_2D: @@ -6255,10 +6797,37 @@ DxgkDdiDestroyContext( Assert(cContexts < UINT32_MAX/2); break; } + case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE: + { + uint32_t cContexts = ASMAtomicDecU32(&pDevExt->cContextsDispIfResize); + Assert(cContexts < UINT32_MAX/2); + if (!cContexts) + { + for (int i = 0; i < VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i) + { + vboxWddmGhDisplayCheckCompletePeningScreenInfo(pDevExt, i); + } + } + break; + } + case VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS: + { + Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->SeamlessCtxMgr, &pContext->CmContext); + if (!NT_SUCCESS(Status)) + WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status)); + + Assert(pContext->CmContext.pSession == NULL); + break; + } default: break; } + if (pContext->u32CrConClientID) + { + VBoxMpCrCtlConDisconnect(&pDevExt->CrCtlCon, pContext->u32CrConClientID); + } + vboxWddmModeRenderFromShadowDisableUnregister(pDevExt, pContext); /* first terminate the swapchain, this will also ensure @@ -6266,17 +6835,17 @@ DxgkDdiDestroyContext( * (i.e. visible regions commands) are completed */ vboxWddmSwapchainCtxTerm(pDevExt, pContext); - NTSTATUS Status = vboxVideoAMgrCtxDestroy(&pContext->AllocContext); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) + Status = vboxVideoAMgrCtxDestroy(&pContext->AllocContext); + if (NT_SUCCESS(Status)) { Status = vboxVideoCmCtxRemove(&pContext->pDevice->pAdapter->CmMgr, &pContext->CmContext); - Assert(Status == STATUS_SUCCESS); - if (Status == STATUS_SUCCESS) - { + if (NT_SUCCESS(Status)) vboxWddmMemFree(pContext); - } + else + WARN(("vboxVideoCmCtxRemove failed, Status 0x%x", Status)); } + else + WARN(("vboxVideoAMgrCtxDestroy failed, Status 0x%x", Status)); LOGF(("LEAVE, hContext(0x%x)", hContext)); @@ -6380,6 +6949,8 @@ static NTSTATUS APIENTRY DxgkDdiPresentDisplayOnly( SrcAllocData.SurfDesc.cbSize = ~0UL; SrcAllocData.Addr.SegmentId = 0; SrcAllocData.Addr.pvMem = pPresentDisplayOnly->pSource; + SrcAllocData.hostID = 0; + SrcAllocData.pSwapchain = NULL; RECT UpdateRect; BOOLEAN bUpdateRectInited = FALSE; @@ -6528,8 +7099,8 @@ static NTSTATUS vboxWddmInitDisplayOnlyDriver(IN PDRIVER_OBJECT pDriverObject, I DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice; DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice; DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest; - DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine; - DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine; + DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutineLegacy; + DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutineLegacy; DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations; DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus; DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor; @@ -6575,8 +7146,10 @@ static NTSTATUS vboxWddmInitDisplayOnlyDriver(IN PDRIVER_OBJECT pDriverObject, I } #endif -static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) +static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath, BOOLEAN fCmdVbva) { +#define VBOXWDDM_CALLBACK_NAME(_base, _fCmdVbva) ((_fCmdVbva) ? _base##New : _base##Legacy) + DRIVER_INITIALIZATION_DATA DriverInitializationData = {'\0'}; // Fill in the DriverInitializationData structure and call DxgkInitialize() @@ -6587,8 +7160,8 @@ static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, DriverInitializationData.DxgkDdiStopDevice = DxgkDdiStopDevice; DriverInitializationData.DxgkDdiRemoveDevice = DxgkDdiRemoveDevice; DriverInitializationData.DxgkDdiDispatchIoRequest = DxgkDdiDispatchIoRequest; - DriverInitializationData.DxgkDdiInterruptRoutine = DxgkDdiInterruptRoutine; - DriverInitializationData.DxgkDdiDpcRoutine = DxgkDdiDpcRoutine; + DriverInitializationData.DxgkDdiInterruptRoutine = VBOXWDDM_CALLBACK_NAME(DxgkDdiInterruptRoutine, fCmdVbva); + DriverInitializationData.DxgkDdiDpcRoutine = VBOXWDDM_CALLBACK_NAME(DxgkDdiDpcRoutine, fCmdVbva); DriverInitializationData.DxgkDdiQueryChildRelations = DxgkDdiQueryChildRelations; DriverInitializationData.DxgkDdiQueryChildStatus = DxgkDdiQueryChildStatus; DriverInitializationData.DxgkDdiQueryDeviceDescriptor = DxgkDdiQueryDeviceDescriptor; @@ -6607,10 +7180,10 @@ static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, DriverInitializationData.DxgkDdiGetStandardAllocationDriverData = DxgkDdiGetStandardAllocationDriverData; DriverInitializationData.DxgkDdiAcquireSwizzlingRange = DxgkDdiAcquireSwizzlingRange; DriverInitializationData.DxgkDdiReleaseSwizzlingRange = DxgkDdiReleaseSwizzlingRange; - DriverInitializationData.DxgkDdiPatch = DxgkDdiPatch; - DriverInitializationData.DxgkDdiSubmitCommand = DxgkDdiSubmitCommand; - DriverInitializationData.DxgkDdiPreemptCommand = DxgkDdiPreemptCommand; - DriverInitializationData.DxgkDdiBuildPagingBuffer = DxgkDdiBuildPagingBuffer; + DriverInitializationData.DxgkDdiPatch = VBOXWDDM_CALLBACK_NAME(DxgkDdiPatch, fCmdVbva); + DriverInitializationData.DxgkDdiSubmitCommand = VBOXWDDM_CALLBACK_NAME(DxgkDdiSubmitCommand, fCmdVbva); + DriverInitializationData.DxgkDdiPreemptCommand = VBOXWDDM_CALLBACK_NAME(DxgkDdiPreemptCommand, fCmdVbva); + DriverInitializationData.DxgkDdiBuildPagingBuffer = VBOXWDDM_CALLBACK_NAME(DxgkDdiBuildPagingBuffer, fCmdVbva); DriverInitializationData.DxgkDdiSetPalette = DxgkDdiSetPalette; DriverInitializationData.DxgkDdiSetPointerPosition = DxgkDdiSetPointerPosition; DriverInitializationData.DxgkDdiSetPointerShape = DxgkDdiSetPointerShape; @@ -6618,7 +7191,7 @@ static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, DriverInitializationData.DxgkDdiRestartFromTimeout = DxgkDdiRestartFromTimeout; DriverInitializationData.DxgkDdiEscape = DxgkDdiEscape; DriverInitializationData.DxgkDdiCollectDbgInfo = DxgkDdiCollectDbgInfo; - DriverInitializationData.DxgkDdiQueryCurrentFence = DxgkDdiQueryCurrentFence; + DriverInitializationData.DxgkDdiQueryCurrentFence = VBOXWDDM_CALLBACK_NAME(DxgkDdiQueryCurrentFence, fCmdVbva); DriverInitializationData.DxgkDdiIsSupportedVidPn = DxgkDdiIsSupportedVidPn; DriverInitializationData.DxgkDdiRecommendFunctionalVidPn = DxgkDdiRecommendFunctionalVidPn; DriverInitializationData.DxgkDdiEnumVidPnCofuncModality = DxgkDdiEnumVidPnCofuncModality; @@ -6636,8 +7209,8 @@ static NTSTATUS vboxWddmInitFullGraphicsDriver(IN PDRIVER_OBJECT pDriverObject, DriverInitializationData.DxgkDdiDestroyDevice = DxgkDdiDestroyDevice; DriverInitializationData.DxgkDdiOpenAllocation = DxgkDdiOpenAllocation; DriverInitializationData.DxgkDdiCloseAllocation = DxgkDdiCloseAllocation; - DriverInitializationData.DxgkDdiRender = DxgkDdiRender; - DriverInitializationData.DxgkDdiPresent = DxgkDdiPresent; + DriverInitializationData.DxgkDdiRender = VBOXWDDM_CALLBACK_NAME(DxgkDdiRender, fCmdVbva); + DriverInitializationData.DxgkDdiPresent = VBOXWDDM_CALLBACK_NAME(DxgkDdiPresent, fCmdVbva); DriverInitializationData.DxgkDdiUpdateOverlay = DxgkDdiUpdateOverlay; DriverInitializationData.DxgkDdiFlipOverlay = DxgkDdiFlipOverlay; @@ -6677,14 +7250,14 @@ DriverEntry( vboxVDbgBreakFv(); -#ifdef DEBUG_misha +#if 0//def DEBUG_misha RTLogGroupSettings(0, "+default.e.l.f.l2.l3"); #endif #ifdef VBOX_WDDM_WIN8 - LOGREL(("VBox WDDM Driver for Windows 8; Built %s %s", __DATE__, __TIME__)); + LOGREL(("VBox WDDM Driver for Windows 8, %d bit; Built %s %s", (sizeof (void*) << 3), __DATE__, __TIME__)); #else - LOGREL(("VBox WDDM Driver for Windows Vista and 7; Built %s %s", __DATE__, __TIME__)); + LOGREL(("VBox WDDM Driver for Windows Vista and 7, %d bit; Built %s %s", (sizeof (void*) << 3), __DATE__, __TIME__)); #endif if (! ARGUMENT_PRESENT(DriverObject) || @@ -6697,7 +7270,7 @@ DriverEntry( ULONG major, minor, build; BOOLEAN checkedBuild = PsGetVersion(&major, &minor, &build, NULL); - BOOLEAN f3DCheckRequired = FALSE; + BOOLEAN f3DRequired = FALSE; LOGREL(("OsVersion( %d, %d, %d )", major, minor, build)); @@ -6709,47 +7282,53 @@ DriverEntry( if (major > 6) { WARN(("Unknow win version, newer major release, assuming 3D check is required")); - f3DCheckRequired = TRUE; + f3DRequired = TRUE; } else if (major == 6) { - if (minor > 2) + if (minor > 3) { WARN(("Unknow win version, newer minor release, assuming 3D check is required")); - f3DCheckRequired = TRUE; + f3DRequired = TRUE; } - else if (minor == 2) + else if (minor >= 2) { LOG(("3D check is required!")); - f3DCheckRequired = TRUE; + f3DRequired = TRUE; } else { LOG(("3D is NOT required!")); - f3DCheckRequired = FALSE; + f3DRequired = FALSE; } } else { WARN(("Unsupported OLDER win version, ignore and assume 3D is NOT required")); - f3DCheckRequired = FALSE; + f3DRequired = FALSE; } Status = STATUS_SUCCESS; - if (f3DCheckRequired) + VBoxMpCrCtlConInit(); + + /* always need to do the check to request host caps */ + LOG(("Doing the 3D check..")); + if (!VBoxMpCrCtlConIs3DSupported()) { - LOG(("3D check is required, doing the 3D check..")); - if (!VBoxMpCrCtlConIs3DSupported()) - { #ifdef VBOX_WDDM_WIN8 - LOGREL(("3D is NOT supported by the host, falling back to display-only mode..")); - g_VBoxDisplayOnly = 1; + Assert(f3DRequired); + LOGREL(("3D is NOT supported by the host, falling back to display-only mode..")); + g_VBoxDisplayOnly = 1; #else + if (f3DRequired) + { LOGREL(("3D is NOT supported by the host, but is required for the current guest version using this driver..")); Status = STATUS_UNSUCCESSFUL; -#endif } + else + LOGREL(("3D is NOT supported by the host, but is NOT required for the current guest version using this driver, continuing with Disabled 3D..")); +#endif } #if 0 //defined(DEBUG_misha) && defined(VBOX_WDDM_WIN8) @@ -6760,8 +7339,8 @@ DriverEntry( if (NT_SUCCESS(Status)) { - Status = VBoxWddmVrInit(); - if (NT_SUCCESS(Status)) + rc = VBoxVrInit(); + if (RT_SUCCESS(rc)) { #ifdef VBOX_WDDM_WIN8 if (g_VBoxDisplayOnly) @@ -6771,16 +7350,19 @@ DriverEntry( else #endif { - Status = vboxWddmInitFullGraphicsDriver(DriverObject, RegistryPath); + Status = vboxWddmInitFullGraphicsDriver(DriverObject, RegistryPath, !!(VBoxMpCrGetHostCaps() & CR_VBOX_CAP_CMDVBVA)); } if (NT_SUCCESS(Status)) return Status; - VBoxWddmVrTerm(); + VBoxVrTerm(); } else - WARN(("VBoxWddmVrInit failed, Status(0x%x)", Status)); + { + WARN(("VBoxVrInit failed, rc(%d)", rc)); + Status = STATUS_UNSUCCESSFUL; + } } else LOGREL(("Aborting the video driver load due to 3D support missing")); diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.h index bed17c57..ab50708e 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.h @@ -4,7 +4,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; @@ -36,13 +36,32 @@ //#define VBOXWDDM_DEBUG_VIDPN +#define VBOXWDDM_CFG_DRV_DEFAULT 0 +#define VBOXWDDM_CFG_DRV_SECONDARY_TARGETS_CONNECTED 1 + +#define VBOXWDDM_CFG_DRVTARGET_CONNECTED 1 + #define VBOXWDDM_CFG_LOG_UM_BACKDOOR 0x00000001 #define VBOXWDDM_CFG_LOG_UM_DBGPRINT 0x00000002 #define VBOXWDDM_CFG_STR_LOG_UM L"VBoxLogUm" + +#define VBOXWDDM_REG_DRV_FLAGS_NAME L"VBoxFlags" +#define VBOXWDDM_REG_DRV_DISPFLAGS_PREFIX L"VBoxDispFlags" + +#define VBOXWDDM_REG_DRVKEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" + +#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\" +#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY L"\\Video" + + +#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Control\\VIDEO\\" +#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7 L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\UnitedVideo\\CONTROL\\VIDEO\\" + +#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX L"Attach.RelativeX" +#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY L"Attach.RelativeY" +#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_DESKTOP L"Attach.ToDesktop" + extern DWORD g_VBoxLogUm; -#ifdef VBOX_WDDM_WIN8 -extern DWORD g_VBoxDisplayOnly; -#endif RT_C_DECLS_BEGIN NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath); @@ -83,10 +102,14 @@ DECLINLINE(VOID) vboxWddmAllocationRetain(PVBOXWDDM_ALLOCATION pAllocation) ASMAtomicIncU32(&pAllocation->cRefs); } -DECLINLINE(VOID) vboxWddmAddrSetVram(PVBOXWDDM_ADDR pAddr, UINT SegmentId, VBOXVIDEOOFFSET offVram) +DECLINLINE(BOOLEAN) vboxWddmAddrSetVram(PVBOXWDDM_ADDR pAddr, UINT SegmentId, VBOXVIDEOOFFSET offVram) { + if (pAddr->SegmentId == SegmentId && pAddr->offVram == offVram) + return FALSE; + pAddr->SegmentId = SegmentId; pAddr->offVram = offVram; + return TRUE; } DECLINLINE(bool) vboxWddmAddrVramEqual(PVBOXWDDM_ADDR pAddr1, PVBOXWDDM_ADDR pAddr2) @@ -104,6 +127,12 @@ DECLINLINE(VBOXVIDEOOFFSET) vboxWddmVramAddrToOffset(PVBOXMP_DEVEXT pDevExt, PHY #ifdef VBOXWDDM_RENDER_FROM_SHADOW DECLINLINE(void) vboxWddmAssignShadow(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource, PVBOXWDDM_ALLOCATION pAllocation, D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId) { + if (pDevExt->fCmdVbvaEnabled) + { + WARN(("Trying to assign shadow surface for CmdVbva enabled mode!")); + return; + } + if (pSource->pShadowAllocation == pAllocation) { Assert(pAllocation->bAssigned); @@ -132,9 +161,18 @@ DECLINLINE(void) vboxWddmAssignShadow(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE p pAllocation->bVisible = pSource->bVisible; if(!vboxWddmAddrVramEqual(&pSource->AllocData.Addr, &pAllocation->AllocData.Addr)) - pSource->bGhSynced = FALSE; /* force guest->host notification */ - pSource->AllocData.Addr = pAllocation->AllocData.Addr; + { + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */ + pSource->AllocData.Addr = pAllocation->AllocData.Addr; + } + if (pSource->AllocData.hostID != pAllocation->AllocData.hostID) + { + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */ + pSource->AllocData.hostID = pAllocation->AllocData.hostID; + } } + else + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */ pSource->pShadowAllocation = pAllocation; } @@ -164,11 +202,20 @@ DECLINLINE(VOID) vboxWddmAssignPrimary(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pAllocation->bVisible = pSource->bVisible; if(!vboxWddmAddrVramEqual(&pSource->AllocData.Addr, &pAllocation->AllocData.Addr)) - pSource->bGhSynced = FALSE; /* force guest->host notification */ - pSource->AllocData.Addr = pAllocation->AllocData.Addr; + { + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */ + pSource->AllocData.Addr = pAllocation->AllocData.Addr; + } + if (pSource->AllocData.hostID != pAllocation->AllocData.hostID) + { + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */ + pSource->AllocData.hostID = pAllocation->AllocData.hostID; + } vboxWddmAllocationRetain(pAllocation); } + else + pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */ KIRQL OldIrql; KeAcquireSpinLock(&pSource->AllocationLock, &OldIrql); @@ -188,31 +235,60 @@ DECLINLINE(PVBOXWDDM_ALLOCATION) vboxWddmAquirePrimary(PVBOXMP_DEVEXT pDevExt, P return pPrimary; } +bool vboxWddmGhDisplayCheckSetInfoFromSource(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_SOURCE pSource); + #define VBOXWDDMENTRY_2_SWAPCHAIN(_pE) ((PVBOXWDDM_SWAPCHAIN)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXWDDM_SWAPCHAIN, DevExtListEntry))) +BOOLEAN DxgkDdiInterruptRoutineNew( + IN CONST PVOID MiniportDeviceContext, + IN ULONG MessageNumber + ); + +#ifdef VBOX_WDDM_WIN8 +# define VBOXWDDM_IS_DISPLAYONLY() (g_VBoxDisplayOnly) +#else +# define VBOXWDDM_IS_DISPLAYONLY() (FALSE) +#endif + #ifdef VBOXWDDM_RENDER_FROM_SHADOW -# ifdef VBOX_WDDM_WIN8 -# define VBOXWDDM_IS_FB_ALLOCATION(_pDevExt, _pAlloc) ( (_pAlloc)->bAssigned \ - && ( (_pAlloc)->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC \ + +# define VBOXWDDM_IS_FB_ALLOCATION(_pDevExt, _pAlloc) ( (_pAlloc)->bAssigned \ + && ( (_pAlloc)->AllocData.hostID \ || (_pAlloc)->enmType == \ - ((g_VBoxDisplayOnly || (_pDevExt)->fRenderToShadowDisabled) ? VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE : VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE) \ + ((VBOXWDDM_IS_DISPLAYONLY() || (_pDevExt)->fRenderToShadowDisabled) ? VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE : VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE) \ )) -# else -# define VBOXWDDM_IS_FB_ALLOCATION(_pDevExt, _pAlloc) ( (_pAlloc)->bAssigned \ - && ( (_pAlloc)->enmType == VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC \ - || (_pAlloc)->enmType == \ - (((_pDevExt)->fRenderToShadowDisabled) ? VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE : VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE) \ + +# define VBOXWDDM_IS_REAL_FB_ALLOCATION(_pDevExt, _pAlloc) ( (_pAlloc)->bAssigned \ + && ( (_pAlloc)->AllocData.hostID \ + || (_pAlloc)->enmType == VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE \ )) -# endif + # define VBOXWDDM_FB_ALLOCATION(_pDevExt, _pSrc) ( ((_pSrc)->pPrimaryAllocation && VBOXWDDM_IS_FB_ALLOCATION(_pDevExt, (_pSrc)->pPrimaryAllocation)) ? \ (_pSrc)->pPrimaryAllocation : ( \ ((_pSrc)->pShadowAllocation && VBOXWDDM_IS_FB_ALLOCATION(_pDevExt, (_pSrc)->pShadowAllocation)) ? \ (_pSrc)->pShadowAllocation : NULL \ ) \ ) +# define VBOXWDDM_NONFB_ALLOCATION(_pDevExt, _pSrc) ( !((_pSrc)->pPrimaryAllocation && VBOXWDDM_IS_FB_ALLOCATION(_pDevExt, (_pSrc)->pPrimaryAllocation)) ? \ + (_pSrc)->pPrimaryAllocation : ( \ + ((_pSrc)->pShadowAllocation && VBOXWDDM_IS_FB_ALLOCATION(_pDevExt, (_pSrc)->pShadowAllocation)) ? \ + (_pSrc)->pShadowAllocation : NULL \ + ) \ + ) #else # define VBOXWDDM_FB_ALLOCATION(_pDevExt, _pSrc) ((_pSrc)->pPrimaryAllocation) #endif +#define VBOXWDDM_CTXLOCK_INIT(_p) do { \ + KeInitializeSpinLock(&(_p)->ContextLock); \ + } while (0) +#define VBOXWDDM_CTXLOCK_DATA KIRQL _ctxLockOldIrql; +#define VBOXWDDM_CTXLOCK_LOCK(_p) do { \ + KeAcquireSpinLock(&(_p)->ContextLock, &_ctxLockOldIrql); \ + } while (0) +#define VBOXWDDM_CTXLOCK_UNLOCK(_p) do { \ + KeReleaseSpinLock(&(_p)->ContextLock, _ctxLockOldIrql); \ + } while (0) + #endif /* #ifndef ___VBoxMPWddm_h___ */ diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.rc b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.rc index 435a9a5a..e4d271d9 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.rc +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.rc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxVideoWddm.inf b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxVideoWddm.inf index 6cfda59e..9a2e7c87 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxVideoWddm.inf +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxVideoWddm.inf @@ -1,7 +1,7 @@ ; ; VirtualBox Video Wddm driver ; -; Copyright (C) 2011 Oracle Corporation +; Copyright (C) 2011-2012 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPDriver.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPDriver.cpp index 6bb3d7d0..e448468e 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPDriver.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPDriver.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -147,6 +147,18 @@ VBoxDrvFindAdapter(IN PVOID HwDeviceExtension, IN PVOID HwContext, IN PWSTR Argu */ VBoxSetupDisplaysHGSMI(&pExt->u.primary.commonInfo, phVRAM, ulApertureSize, cbVRAM, 0); + /* Check if the chip restricts horizontal resolution or not. + * Must be done after VBoxSetupDisplaysHGSMI, because it initializes the common structure. + */ + VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID); + VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX); + DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA); + + if (DispiId == VBE_DISPI_ID_ANYX) + VBoxCommonFromDeviceExt(pExt)->fAnyX = TRUE; + else + VBoxCommonFromDeviceExt(pExt)->fAnyX = FALSE; + if (pExt->u.primary.commonInfo.bHGSMI) { LOGREL(("using HGSMI")); @@ -166,7 +178,6 @@ static BOOLEAN VBoxDrvInitialize(PVOID HwDeviceExtension) { PVBOXMP_DEVEXT pExt = (PVBOXMP_DEVEXT) HwDeviceExtension; - USHORT DispiId; PAGED_CODE(); LOGF_ENTER(); @@ -174,16 +185,6 @@ VBoxDrvInitialize(PVOID HwDeviceExtension) /* Initialize the request pointer. */ pExt->u.primary.pvReqFlush = NULL; - /* Check if the chip restricts horizontal resolution or not. */ - VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID); - VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX); - DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA); - - if (DispiId == VBE_DISPI_ID_ANYX) - pExt->fAnyX = TRUE; - else - pExt->fAnyX = FALSE; - VBoxMPCmnInitCustomVideoModes(pExt); LOGF_LEAVE(); @@ -308,7 +309,7 @@ VBoxDrvStartIO(PVOID HwDeviceExtension, PVIDEO_REQUEST_PACKET RequestPacket) { PVIDEO_MODE_INFORMATION pModes = (PVIDEO_MODE_INFORMATION) RequestPacket->OutputBuffer; - if (RequestPacket->OutputBufferLength < VBoxMPXpdmGetVideoModesCount()*sizeof(VIDEO_MODE_INFORMATION)) + if (RequestPacket->OutputBufferLength < VBoxMPXpdmGetVideoModesCount(pExt)*sizeof(VIDEO_MODE_INFORMATION)) { pStatus->Status = ERROR_INSUFFICIENT_BUFFER; break; @@ -538,12 +539,29 @@ VBoxDrvStartIO(PVOID HwDeviceExtension, PVIDEO_REQUEST_PACKET RequestPacket) case IOCTL_VIDEO_VBOX_ISANYX: { STARTIO_OUT(uint32_t, pu32AnyX); - *pu32AnyX = pExt->fAnyX; + *pu32AnyX = VBoxCommonFromDeviceExt(pExt)->fAnyX; pStatus->Information = sizeof (uint32_t); bResult = TRUE; break; } + case IOCTL_VIDEO_QUERY_VBOXVIDEO_INFO: + { + STARTIO_IN(ULONG, pulInfoLevel); + if (*pulInfoLevel == VBOXVIDEO_INFO_LEVEL_REGISTRY_FLAGS) + { + STARTIO_OUT(ULONG, pulFlags); + bResult = VBoxMPQueryRegistryFlags(pExt, pulFlags, pStatus); + } + else + { + pStatus->Status = ERROR_INVALID_PARAMETER; + bResult = FALSE; + } + + break; + } + default: { WARN(("unsupported IOCTL %p, fn(%#x)", diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPIOCTL.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPIOCTL.cpp index 3769fbe1..772f6c92 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPIOCTL.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPIOCTL.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -192,15 +192,15 @@ BOOLEAN VBoxMPSetCurrentMode(PVBOXMP_DEVEXT pExt, PVIDEO_MODE pMode, PSTATUS_BLO WARN(("ignoring set VIDEO_MODE_NO_ZERO_MEMORY or VIDEO_MODE_MAP_MEM_LINEAR")); } - pModeInfo = VBoxMPCmnGetVideoModeInfo(RequestedMode-1); + pModeInfo = VBoxMPCmnGetVideoModeInfo(pExt, RequestedMode-1); if (!pModeInfo) { pStatus->Status = ERROR_INVALID_PARAMETER; return FALSE; } - LOG(("width %d, height %d, bpp %d", - pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, pModeInfo->BitsPerPlane)); + LOG(("screen [%d] mode %d width %d, height %d, bpp %d", + pExt->iDevice, pModeInfo->ModeIndex, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, pModeInfo->BitsPerPlane)); /* Update device info */ pExt->CurrentMode = RequestedMode; @@ -249,7 +249,7 @@ BOOLEAN VBoxMPQueryNumAvailModes(PVBOXMP_DEVEXT pExt, PVIDEO_NUM_MODES pNumModes VBoxMPXpdmBuildVideoModesTable(pExt); - pNumModes->NumModes = VBoxMPXpdmGetVideoModesCount(); + pNumModes->NumModes = VBoxMPXpdmGetVideoModesCount(pExt); pNumModes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION); pStatus->Information = sizeof(VIDEO_NUM_MODES); @@ -264,9 +264,9 @@ BOOLEAN VBoxMPQueryAvailModes(PVBOXMP_DEVEXT pExt, PVIDEO_MODE_INFORMATION pMode { LOGF_ENTER(); - ULONG ulSize = VBoxMPXpdmGetVideoModesCount()*sizeof(VIDEO_MODE_INFORMATION); + ULONG ulSize = VBoxMPXpdmGetVideoModesCount(pExt)*sizeof(VIDEO_MODE_INFORMATION); pStatus->Information = ulSize; - VideoPortMoveMemory(pModes, VBoxMPCmnGetVideoModeInfo(0), ulSize); + VideoPortMoveMemory(pModes, VBoxMPCmnGetVideoModeInfo(pExt, 0), ulSize); LOGF_LEAVE(); return TRUE; @@ -616,3 +616,35 @@ BOOLEAN VBoxMPVhwaQueryInfo(PVBOXMP_DEVEXT pExt, VHWAQUERYINFO *pInfo, PSTATUS_B return bRC; } #endif + +BOOLEAN VBoxMPQueryRegistryFlags(PVBOXMP_DEVEXT pExt, ULONG *pulFlags, PSTATUS_BLOCK pStatus) +{ + BOOLEAN bRC = TRUE; + LOGF_ENTER(); + + VBOXMPCMNREGISTRY Registry; + + int rc = VBoxMPCmnRegInit(pExt, &Registry); + VBOXMP_WARN_VPS_NOBP(rc); + + if (rc == NO_ERROR) + { + uint32_t u32Flags = 0; + rc = VBoxMPCmnRegQueryDword(Registry, L"VBoxVideoFlags", &u32Flags); + VBOXMP_WARN_VPS_NOBP(rc); + if (rc != NO_ERROR) + { + u32Flags = 0; + } + + LOG(("Registry flags 0x%08X", u32Flags)); + *pulFlags = u32Flags; + pStatus->Information = sizeof(ULONG); + } + + rc = VBoxMPCmnRegFini(Registry); + VBOXMP_WARN_VPS_NOBP(rc); + + LOGF_LEAVE(); + return bRC; +} diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.cpp b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.cpp index 97dd0d50..e7841d42 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.cpp +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.cpp @@ -130,7 +130,10 @@ void VBoxCreateDisplays(PVBOXMP_DEVEXT pExt, PVIDEO_PORT_CONFIG_INFO pConfigInfo PVBOXMP_DEVEXT pSExt = NULL; VP_STATUS rc; - rc = pAPI->pfnCreateSecondaryDisplay(pExt, (PVOID*)&pSExt, VIDEO_DUALVIEW_REMOVABLE); + /* If VIDEO_DUALVIEW_REMOVABLE is passed as the 3rd parameter, then + * the guest does not allow to choose the primary screen. + */ + rc = pAPI->pfnCreateSecondaryDisplay(pExt, (PVOID*)&pSExt, 0); VBOXMP_WARN_VPS(rc); if (rc != NO_ERROR) diff --git a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.h b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.h index fd9628b8..14ed1571 100644 --- a/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.h +++ b/src/VBox/Additions/WINNT/Graphics/Video/mp/xpdm/VBoxMPInternal.h @@ -61,5 +61,6 @@ BOOLEAN VBoxMPHGSMIQueryCallbacks(PVBOXMP_DEVEXT pExt, HGSMIQUERYCALLBACKS *pCal BOOLEAN VBoxMPQueryHgsmiInfo(PVBOXMP_DEVEXT pExt, QUERYHGSMIRESULT *pResult, PSTATUS_BLOCK pStatus); BOOLEAN VBoxMPHgsmiHandlerEnable(PVBOXMP_DEVEXT pExt, HGSMIHANDLERENABLE *pChannel, PSTATUS_BLOCK pStatus); BOOLEAN VBoxMPVhwaQueryInfo(PVBOXMP_DEVEXT pExt, VHWAQUERYINFO *pInfo, PSTATUS_BLOCK pStatus); +BOOLEAN VBoxMPQueryRegistryFlags(PVBOXMP_DEVEXT pExt, ULONG *pulFlags, PSTATUS_BLOCK pStatus); #endif /*VBOXMPINTERNAL_H*/ |
