diff options
Diffstat (limited to 'src/VBox/Main/src-client/DisplayImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-client/DisplayImpl.cpp | 1649 |
1 files changed, 1204 insertions, 445 deletions
diff --git a/src/VBox/Main/src-client/DisplayImpl.cpp b/src/VBox/Main/src-client/DisplayImpl.cpp index fc261019..3477a07c 100644 --- a/src/VBox/Main/src-client/DisplayImpl.cpp +++ b/src/VBox/Main/src-client/DisplayImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-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,10 +30,11 @@ #include <iprt/semaphore.h> #include <iprt/thread.h> #include <iprt/asm.h> +#include <iprt/time.h> #include <iprt/cpp/utils.h> #include <VBox/vmm/pdmdrv.h> -#ifdef DEBUG /* for VM_ASSERT_EMT(). */ +#if defined(DEBUG) || defined(VBOX_STRICT) /* for VM_ASSERT_EMT(). */ # include <VBox/vmm/vm.h> #endif @@ -48,9 +49,18 @@ #include <VBox/com/array.h> #ifdef VBOX_WITH_VPX +# include <iprt/path.h> # include "VideoRec.h" #endif +#ifdef VBOX_WITH_CROGL +typedef enum +{ + CRVREC_STATE_IDLE, + CRVREC_STATE_SUBMITTED +} CRVREC_STATE; +#endif + /** * Display driver instance data. * @@ -76,8 +86,8 @@ typedef struct DRVMAINDISPLAY #define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector) #ifdef DEBUG_sunlover -static STAMPROFILE StatDisplayRefresh; -static int stam = 0; +static STAMPROFILE g_StatDisplayRefresh; +static int g_stam = 0; #endif /* DEBUG_sunlover */ // constructor / destructor @@ -105,6 +115,9 @@ HRESULT Display::FinalConstruct() mfPendingVideoAccelEnable = false; mfMachineRunning = false; +#ifdef VBOX_WITH_CROGL + mfCrOglDataHidden = false; +#endif mpu8VbvaPartial = NULL; mcbVbvaPartial = 0; @@ -121,11 +134,34 @@ HRESULT Display::FinalConstruct() int rc = RTCritSectInit(&mVBVALock); AssertRC(rc); + + rc = RTCritSectInit(&mSaveSeamlessRectLock); + AssertRC(rc); + mfu32PendingVideoAccelDisable = false; #ifdef VBOX_WITH_HGSMI mu32UpdateVBVAFlags = 0; #endif +#ifdef VBOX_WITH_VPX + mpVideoRecCtx = NULL; + for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++) + maVideoRecEnabled[i] = true; +#endif + +#ifdef VBOX_WITH_CRHGSMI + mhCrOglSvc = NULL; +#endif +#ifdef VBOX_WITH_CROGL + RT_ZERO(mCrOglCallbacks); + RT_ZERO(mCrOglScreenshotData); + mfCrOglVideoRecState = CRVREC_STATE_IDLE; + mCrOglScreenshotData.u32Screen = CRSCREEN_ALL; + mCrOglScreenshotData.pvContext = this; + mCrOglScreenshotData.pfnScreenshotBegin = displayCrVRecScreenshotBegin; + mCrOglScreenshotData.pfnScreenshotPerform = displayCrVRecScreenshotPerform; + mCrOglScreenshotData.pfnScreenshotEnd = displayCrVRecScreenshotEnd; +#endif return BaseFinalConstruct(); } @@ -137,7 +173,13 @@ void Display::FinalRelease() if (RTCritSectIsInitialized (&mVBVALock)) { RTCritSectDelete (&mVBVALock); - memset (&mVBVALock, 0, sizeof (mVBVALock)); + RT_ZERO(mVBVALock); + } + + if (RTCritSectIsInitialized(&mSaveSeamlessRectLock)) + { + RTCritSectDelete(&mSaveSeamlessRectLock); + RT_ZERO(mSaveSeamlessRectLock); } BaseFinalRelease(); } @@ -205,6 +247,47 @@ static int displayMakeThumbnail(uint8_t *pu8Data, uint32_t cx, uint32_t cy, return rc; } +#ifdef VBOX_WITH_CROGL +typedef struct +{ + CRVBOXHGCMTAKESCREENSHOT Base; + + /* 32bpp small RGB image. */ + uint8_t *pu8Thumbnail; + uint32_t cbThumbnail; + uint32_t cxThumbnail; + uint32_t cyThumbnail; + + /* PNG screenshot. */ + uint8_t *pu8PNG; + uint32_t cbPNG; + uint32_t cxPNG; + uint32_t cyPNG; +} VBOX_DISPLAY_SAVESCREENSHOT_DATA; + +static DECLCALLBACK(void) displaySaveScreenshotReport(void *pvCtx, uint32_t uScreen, + uint32_t x, uint32_t y, uint32_t uBitsPerPixel, + uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp) +{ + VBOX_DISPLAY_SAVESCREENSHOT_DATA *pData = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)pvCtx; + displayMakeThumbnail(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8Thumbnail, &pData->cbThumbnail, &pData->cxThumbnail, &pData->cyThumbnail); + int rc = DisplayMakePNG(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8PNG, &pData->cbPNG, &pData->cxPNG, &pData->cyPNG, 1); + if (RT_FAILURE(rc)) + { + AssertMsgFailed(("DisplayMakePNG failed %d\n", rc)); + if (pData->pu8PNG) + { + RTMemFree(pData->pu8PNG); + pData->pu8PNG = NULL; + } + pData->cbPNG = 0; + pData->cxPNG = 0; + pData->cyPNG = 0; + } +} +#endif + DECLCALLBACK(void) Display::displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser) { @@ -222,8 +305,8 @@ Display::displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser) uint32_t cxPNG = 0; uint32_t cyPNG = 0; - Console::SafeVMPtr pVM (that->mParent); - if (SUCCEEDED(pVM.rc())) + Console::SafeVMPtr ptrVM(that->mParent); + if (ptrVM.isOk()) { /* Query RGB bitmap. */ uint8_t *pu8Data = NULL; @@ -231,39 +314,101 @@ Display::displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser) uint32_t cx = 0; uint32_t cy = 0; - /* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */ - int rc = Display::displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy); +#ifdef VBOX_WITH_CROGL + BOOL f3DSnapshot = FALSE; + BOOL is3denabled; + that->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + if (is3denabled && that->mCrOglCallbacks.pfnHasData()) + { + VMMDev *pVMMDev = that->mParent->getVMMDev(); + if (pVMMDev) + { + VBOX_DISPLAY_SAVESCREENSHOT_DATA *pScreenshot = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)RTMemAllocZ(sizeof (*pScreenshot)); + if (pScreenshot) + { + /* screen id or CRSCREEN_ALL to specify all enabled */ + pScreenshot->Base.u32Screen = 0; + pScreenshot->Base.u32Width = 0; + pScreenshot->Base.u32Height = 0; + pScreenshot->Base.u32Pitch = 0; + pScreenshot->Base.pvBuffer = NULL; + pScreenshot->Base.pvContext = pScreenshot; + pScreenshot->Base.pfnScreenshotBegin = NULL; + pScreenshot->Base.pfnScreenshotPerform = displaySaveScreenshotReport; + pScreenshot->Base.pfnScreenshotEnd = NULL; + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = &pScreenshot->Base; + parm.u.pointer.size = sizeof (pScreenshot->Base); + + int rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_TAKE_SCREENSHOT, 1, &parm); + if (RT_SUCCESS(rc)) + { + if (pScreenshot->pu8PNG) + { + pu8Thumbnail = pScreenshot->pu8Thumbnail; + cbThumbnail = pScreenshot->cbThumbnail; + cxThumbnail = pScreenshot->cxThumbnail; + cyThumbnail = pScreenshot->cyThumbnail; + + /* PNG screenshot. */ + pu8PNG = pScreenshot->pu8PNG; + cbPNG = pScreenshot->cbPNG; + cxPNG = pScreenshot->cxPNG; + cyPNG = pScreenshot->cyPNG; + f3DSnapshot = TRUE; + } + else + AssertMsgFailed(("no png\n")); + } + else + AssertMsgFailed(("SHCRGL_HOST_FN_TAKE_SCREENSHOT failed %d\n", rc)); - /* - * It is possible that success is returned but everything is 0 or NULL. - * (no display attached if a VM is running with VBoxHeadless on OSE for example) - */ - if (RT_SUCCESS(rc) && pu8Data) + + RTMemFree(pScreenshot); + } + } + } + + if (!f3DSnapshot) +#endif { - Assert(cx && cy); + /* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */ + int rc = Display::displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy); - /* Prepare a small thumbnail and a PNG screenshot. */ - displayMakeThumbnail(pu8Data, cx, cy, &pu8Thumbnail, &cbThumbnail, &cxThumbnail, &cyThumbnail); - rc = DisplayMakePNG(pu8Data, cx, cy, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 1); - if (RT_FAILURE(rc)) + /* + * It is possible that success is returned but everything is 0 or NULL. + * (no display attached if a VM is running with VBoxHeadless on OSE for example) + */ + if (RT_SUCCESS(rc) && pu8Data) { - if (pu8PNG) + Assert(cx && cy); + + /* Prepare a small thumbnail and a PNG screenshot. */ + displayMakeThumbnail(pu8Data, cx, cy, &pu8Thumbnail, &cbThumbnail, &cxThumbnail, &cyThumbnail); + rc = DisplayMakePNG(pu8Data, cx, cy, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 1); + if (RT_FAILURE(rc)) { - RTMemFree(pu8PNG); - pu8PNG = NULL; + if (pu8PNG) + { + RTMemFree(pu8PNG); + pu8PNG = NULL; + } + cbPNG = 0; + cxPNG = 0; + cyPNG = 0; } - cbPNG = 0; - cxPNG = 0; - cyPNG = 0; - } - /* This can be called from any thread. */ - that->mpDrv->pUpPort->pfnFreeScreenshot(that->mpDrv->pUpPort, pu8Data); + /* This can be called from any thread. */ + that->mpDrv->pUpPort->pfnFreeScreenshot(that->mpDrv->pUpPort, pu8Data); + } } } else { - LogFunc(("Failed to get VM pointer 0x%x\n", pVM.rc())); + LogFunc(("Failed to get VM pointer 0x%x\n", ptrVM.rc())); } /* Regardless of rc, save what is available: @@ -436,40 +581,8 @@ HRESULT Display::init(Console *aParent) unconst(mParent) = aParent; - // by default, we have an internal framebuffer which is - // NULL, i.e. a black hole for no display output - mFramebufferOpened = false; - ULONG ul; mParent->machine()->COMGETTER(MonitorCount)(&ul); - -#ifdef VBOX_WITH_VPX - if (VideoRecContextCreate(&mpVideoRecContext)) - { - LogFlow(("Failed to create Video Recording Context\n")); - return E_FAIL; - } - - BOOL fEnabled = false; - mParent->machine()->COMGETTER(VideoCaptureEnabled)(&fEnabled); - if (fEnabled) - { - ULONG ulVideoCaptureHorzRes; - mParent->machine()->COMGETTER(VideoCaptureWidth)(&ulVideoCaptureHorzRes); - ULONG ulVideoCaptureVertRes; - mParent->machine()->COMGETTER(VideoCaptureHeight)(&ulVideoCaptureVertRes); - BSTR strVideoCaptureFile; - mParent->machine()->COMGETTER(VideoCaptureFile)(&strVideoCaptureFile); - LogFlow(("VidoeRecording VPX enabled\n")); - if (VideoRecContextInit(mpVideoRecContext, strVideoCaptureFile, - ulVideoCaptureHorzRes, ulVideoCaptureVertRes)) - { - LogFlow(("Failed to initialize video recording context\n")); - return E_FAIL; - } - } -#endif - mcMonitors = ul; for (ul = 0; ul < mcMonitors; ul++) @@ -500,14 +613,20 @@ HRESULT Display::init(Console *aParent) maFramebuffers[ul].fDefaultFormat = false; - memset (&maFramebuffers[ul].dirtyRect, 0 , sizeof (maFramebuffers[ul].dirtyRect)); - memset (&maFramebuffers[ul].pendingResize, 0 , sizeof (maFramebuffers[ul].pendingResize)); + maFramebuffers[ul].mcSavedVisibleRegion = 0; + maFramebuffers[ul].mpSavedVisibleRegion = NULL; + + RT_ZERO(maFramebuffers[ul].dirtyRect); + RT_ZERO(maFramebuffers[ul].pendingResize); #ifdef VBOX_WITH_HGSMI maFramebuffers[ul].fVBVAEnabled = false; maFramebuffers[ul].cVBVASkipUpdate = 0; - memset (&maFramebuffers[ul].vbvaSkippedRect, 0, sizeof (maFramebuffers[ul].vbvaSkippedRect)); + RT_ZERO(maFramebuffers[ul].vbvaSkippedRect); maFramebuffers[ul].pVBVAHostFlags = NULL; #endif /* VBOX_WITH_HGSMI */ +#ifdef VBOX_WITH_CROGL + RT_ZERO(maFramebuffers[ul].pendingViewportInfo); +#endif } { @@ -557,23 +676,18 @@ void Display::uninit() mpDrv = NULL; mpVMMDev = NULL; mfVMMDevInited = true; - -#ifdef VBOX_WITH_VPX - if (mpVideoRecContext) - VideoRecContextClose(mpVideoRecContext); -#endif } /** * Register the SSM methods. Called by the power up thread to be able to * pass pVM */ -int Display::registerSSM(PVM pVM) +int Display::registerSSM(PUVM pUVM) { /* Version 2 adds width and height of the framebuffer; version 3 adds * the framebuffer offset in the virtual desktop and the framebuffer flags. */ - int rc = SSMR3RegisterExternal(pVM, "DisplayData", 0, sSSMDisplayVer3, + int rc = SSMR3RegisterExternal(pUVM, "DisplayData", 0, sSSMDisplayVer3, mcMonitors * sizeof(uint32_t) * 8 + sizeof(uint32_t), NULL, NULL, NULL, NULL, displaySSMSave, NULL, @@ -584,20 +698,20 @@ int Display::registerSSM(PVM pVM) * Register loaders for old saved states where iInstance was * 3 * sizeof(uint32_t *) due to a code mistake. */ - rc = SSMR3RegisterExternal(pVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, + rc = SSMR3RegisterExternal(pUVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, NULL, NULL, NULL, NULL, NULL, NULL, NULL, displaySSMLoad, NULL, this); AssertRCReturn(rc, rc); - rc = SSMR3RegisterExternal(pVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, + rc = SSMR3RegisterExternal(pUVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/, NULL, NULL, NULL, NULL, NULL, NULL, NULL, displaySSMLoad, NULL, this); AssertRCReturn(rc, rc); /* uInstance is an arbitrary value greater than 1024. Such a value will ensure a quick seek in saved state file. */ - rc = SSMR3RegisterExternal(pVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/, + rc = SSMR3RegisterExternal(pUVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/, NULL, NULL, NULL, NULL, displaySSMSaveScreenshot, NULL, NULL, displaySSMLoadScreenshot, NULL, this); @@ -607,6 +721,46 @@ int Display::registerSSM(PVM pVM) return VINF_SUCCESS; } +#ifdef VBOX_WITH_CROGL +int Display::crOglWindowsShow(bool fShow) +{ + if (!mfCrOglDataHidden == !!fShow) + return VINF_SUCCESS; + + if (!mhCrOglSvc) + { + /* no 3D */ +#ifdef DEBUG + BOOL is3denabled; + mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + Assert(!is3denabled); +#endif + return VERR_INVALID_STATE; + } + + VMMDev *pVMMDev = mParent->getVMMDev(); + if (!pVMMDev) + { + AssertMsgFailed(("no vmmdev\n")); + return VERR_INVALID_STATE; + } + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_32BIT; + parm.u.uint32 = (uint32_t)fShow; + + int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_WINDOWS_SHOW, &parm, NULL, NULL); + if (RT_SUCCESS(rc)) + mfCrOglDataHidden = !fShow; + else + AssertMsgFailed(("hgcmHostFastCallAsync failed rc %n", rc)); + + return rc; +} +#endif + + // IEventListener method STDMETHODIMP Display::HandleEvent(IEvent * aEvent) { @@ -629,9 +783,20 @@ STDMETHODIMP Display::HandleEvent(IEvent * aEvent) LogRelFlowFunc(("Machine is running.\n")); mfMachineRunning = true; + +#ifdef VBOX_WITH_CROGL + crOglWindowsShow(true); +#endif } else + { mfMachineRunning = false; + +#ifdef VBOX_WITH_CROGL + if (machineState == MachineState_Paused) + crOglWindowsShow(false); +#endif + } break; } default: @@ -650,7 +815,7 @@ STDMETHODIMP Display::HandleEvent(IEvent * aEvent) static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId, ULONG pixelFormat, void *pvVRAM, uint32_t bpp, uint32_t cbLine, - int w, int h) + uint32_t w, uint32_t h) { Assert (pFramebuffer); @@ -662,13 +827,53 @@ static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId if (!finished) { - LogRelFlowFunc (("External framebuffer wants us to wait!\n")); + LogRelFlowFunc(("External framebuffer wants us to wait!\n")); return VINF_VGA_RESIZE_IN_PROGRESS; } return VINF_SUCCESS; } +int Display::notifyCroglResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM) +{ +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + BOOL is3denabled; + mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + + if (is3denabled) + { + int rc = VERR_INVALID_STATE; + if (mhCrOglSvc) + { + VMMDev *pVMMDev = mParent->getVMMDev(); + if (pVMMDev) + { + CRVBOXHGCMDEVRESIZE *pData = (CRVBOXHGCMDEVRESIZE*)RTMemAlloc(sizeof (*pData)); + if (pData) + { + pData->Screen = *pScreen; + pData->pvVRAM = pvVRAM; + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pData; + parm.u.pointer.size = sizeof (*pData); + + rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_DEV_RESIZE, &parm, displayCrAsyncCmdCompletion, this); + AssertRC(rc); + } + else + rc = VERR_NO_MEMORY; + } + } + + return rc; + } +#endif /* #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */ + return VINF_SUCCESS; +} + /** * Handles display resize event. * Disables access to VGA device; @@ -682,11 +887,11 @@ static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId * @thread EMT */ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM, - uint32_t cbLine, int w, int h, uint16_t flags) + uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags) { - LogRel (("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p " - "w=%d h=%d bpp=%d cbLine=0x%X, flags=0x%X\n", - uScreenId, pvVRAM, w, h, bpp, cbLine, flags)); + LogRel(("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p " + "w=%d h=%d bpp=%d cbLine=0x%X, flags=0x%X\n", + uScreenId, pvVRAM, w, h, bpp, cbLine, flags)); /* If there is no framebuffer, this call is not interesting. */ if ( uScreenId >= mcMonitors @@ -695,12 +900,15 @@ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM return VINF_SUCCESS; } - mLastAddress = pvVRAM; - mLastBytesPerLine = cbLine; - mLastBitsPerPixel = bpp, - mLastWidth = w; - mLastHeight = h; - mLastFlags = flags; + if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + { + mLastAddress = pvVRAM; + mLastBytesPerLine = cbLine; + mLastBitsPerPixel = bpp; + mLastWidth = w; + mLastHeight = h; + mLastFlags = flags; + } ULONG pixelFormat; @@ -732,7 +940,7 @@ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM * * Note: the resize information is only accessed on EMT so no serialization is required. */ - LogRel (("Display::handleDisplayResize(): Warning: resize postponed.\n")); + LogRel(("Display::handleDisplayResize(): Warning: resize postponed.\n")); maFramebuffers[uScreenId].pendingResize.fPending = true; maFramebuffers[uScreenId].pendingResize.pixelFormat = pixelFormat; @@ -746,6 +954,10 @@ int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM return VINF_VGA_RESIZE_IN_PROGRESS; } + /* Framebuffer will be invalid during resize, make sure that it is not accessed. */ + if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, false); + int rc = callFramebufferResize (maFramebuffers[uScreenId].pFramebuffer, uScreenId, pixelFormat, pvVRAM, bpp, cbLine, w, h); if (rc == VINF_VGA_RESIZE_IN_PROGRESS) @@ -810,11 +1022,17 @@ void Display::handleResizeCompletedEMT (void) continue; } + /* Inform VRDP server about the change of display parameters. + * Must be done before calling NotifyUpdate below. + */ + LogRelFlowFunc(("Calling VRDP\n")); + mParent->consoleVRDPServer()->SendResize(); + /* @todo Merge these two 'if's within one 'if (!pFBInfo->pFramebuffer.isNull())' */ if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && !pFBInfo->pFramebuffer.isNull()) { /* Primary framebuffer has completed the resize. Update the connector data for VGA device. */ - updateDisplayData(); + int rc2 = updateDisplayData(); /* Check the framebuffer pixel format to setup the rendering in VGA device. */ BOOL usesGuestVRAM = FALSE; @@ -825,7 +1043,7 @@ void Display::handleResizeCompletedEMT (void) /* If the primary framebuffer is disabled, tell the VGA device to not to copy * pixels from VRAM to the framebuffer. */ - if (pFBInfo->fDisabled) + if (pFBInfo->fDisabled || RT_FAILURE(rc2)) mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, false); else mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, @@ -854,22 +1072,33 @@ void Display::handleResizeCompletedEMT (void) } LogRelFlow(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat)); -#ifdef DEBUG_sunlover - if (!stam) + /* Handle the case if there are some saved visible region that needs to be + * applied after the resize of the framebuffer is completed + */ + SaveSeamlessRectLock(); + PRTRECT pSavedVisibleRegion = pFBInfo->mpSavedVisibleRegion; + uint32_t cSavedVisibleRegion = pFBInfo->mcSavedVisibleRegion; + pFBInfo->mpSavedVisibleRegion = NULL; + pFBInfo->mcSavedVisibleRegion = 0; + SaveSeamlessRectUnLock(); + + if (pSavedVisibleRegion) { - /* protect mpVM */ - Console::SafeVMPtr pVM (mParent); - AssertComRC (pVM.rc()); + handleSetVisibleRegion(cSavedVisibleRegion, pSavedVisibleRegion); + RTMemFree(pSavedVisibleRegion); + } - STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates."); - stam = 1; +#ifdef DEBUG_sunlover + if (!g_stam) + { + Console::SafeVMPtr ptrVM(mParent); + AssertComRC(ptrVM.rc()); + STAMR3RegisterU(ptrVM.rawUVM(), &g_StatDisplayRefresh, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, + "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates."); + g_stam = 1; } #endif /* DEBUG_sunlover */ - /* Inform VRDP server about the change of display parameters. */ - LogRelFlowFunc (("Calling VRDP\n")); - mParent->consoleVRDPServer()->SendResize(); - #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) { BOOL is3denabled; @@ -884,7 +1113,16 @@ void Display::handleResizeCompletedEMT (void) VMMDev *pVMMDev = mParent->getVMMDev(); if (pVMMDev) + { +#if 0 + if (mhCrOglSvc) + pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SCREEN_CHANGED, &parm, NULL, NULL); + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); +#else pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); +#endif + } } } #endif /* VBOX_WITH_CROGL */ @@ -928,17 +1166,17 @@ unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int { DISPLAYFBINFO *pInfo = pInfos; unsigned uScreenId; - LogSunlover (("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph)); + LogSunlover(("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph)); for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++) { - LogSunlover ((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h)); + LogSunlover((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h)); if ( (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w) && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h)) { /* The rectangle belongs to the screen. Correct coordinates. */ *px -= pInfo->xOrigin; *py -= pInfo->yOrigin; - LogSunlover ((" -> %d,%d", *px, *py)); + LogSunlover((" -> %d,%d", *px, *py)); break; } } @@ -947,7 +1185,7 @@ unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int /* Map to primary screen. */ uScreenId = 0; } - LogSunlover ((" scr %d\n", uScreenId)); + LogSunlover((" scr %d\n", uScreenId)); return uScreenId; } @@ -967,7 +1205,7 @@ void Display::handleDisplayUpdateLegacy (int x, int y, int w, int h) unsigned uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h); #ifdef DEBUG_sunlover - LogFlowFunc (("%d,%d %dx%d (checked)\n", x, y, w, h)); + LogFlowFunc(("%d,%d %dx%d (checked)\n", x, y, w, h)); #endif /* DEBUG_sunlover */ handleDisplayUpdate (uScreenId, x, y, w, h); @@ -981,8 +1219,8 @@ void Display::handleDisplayUpdate (unsigned uScreenId, int x, int y, int w, int */ #ifdef DEBUG_sunlover - LogFlowFunc (("[%d] %d,%d %dx%d (%d,%d)\n", - uScreenId, x, y, w, h, mpDrv->IConnector.cx, mpDrv->IConnector.cy)); + LogFlowFunc(("[%d] %d,%d %dx%d (%d,%d)\n", + uScreenId, x, y, w, h, mpDrv->IConnector.cx, mpDrv->IConnector.cy)); #endif /* DEBUG_sunlover */ IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer; @@ -1041,7 +1279,7 @@ void Display::getFramebufferDimensions(int32_t *px1, int32_t *py1, return; /* If VBVA is not in use then this flag will not be set and this * will still work as it should. */ - if (!(maFramebuffers[0].fDisabled)) + if (!maFramebuffers[0].fDisabled) { x1 = (int32_t)maFramebuffers[0].xOrigin; y1 = (int32_t)maFramebuffers[0].yOrigin; @@ -1050,7 +1288,7 @@ void Display::getFramebufferDimensions(int32_t *px1, int32_t *py1, } for (unsigned i = 1; i < mcMonitors; ++i) { - if (!(maFramebuffers[i].fDisabled)) + if (!maFramebuffers[i].fDisabled) { x1 = RT_MIN(x1, maFramebuffers[i].xOrigin); y1 = RT_MIN(y1, maFramebuffers[i].yOrigin); @@ -1115,6 +1353,38 @@ int Display::handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect) if (!pFBInfo->pFramebuffer.isNull()) { + if (pFBInfo->u32ResizeStatus != ResizeStatus_Void) + { + /* handle the case where new rectangles are received from the GA + * when framebuffer resizing is in progress. + * Just save the rectangles to be applied for later time when FB resizing is complete + * (from handleResizeCompletedEMT). + * This is done to prevent a race condition where a new rectangles are received + * from the GA after a resize event and framebuffer resizing is still in progress + * As a result the coordinates of the framebuffer are still + * not updated and hence there is no intersection with the new rectangles passed + * for the new region (THis is checked in the above if condition ). With 0 intersection, + * cRectVisibleRegions = 0 is returned to the GUI and if GUI has invalidated its + * earlier region then it draws nothihing and seamless mode doesn't display the + * guest desktop. + */ + SaveSeamlessRectLock(); + RTMemFree(pFBInfo->mpSavedVisibleRegion); + + pFBInfo->mpSavedVisibleRegion = (RTRECT *)RTMemAlloc( RT_MAX(cRect, 1) + * sizeof (RTRECT)); + if (pFBInfo->mpSavedVisibleRegion) + { + memcpy(pFBInfo->mpSavedVisibleRegion, pRect, cRect * sizeof(RTRECT)); + pFBInfo->mcSavedVisibleRegion = cRect; + } + else + { + pFBInfo->mcSavedVisibleRegion = 0; + } + SaveSeamlessRectUnLock(); + continue; + } /* Prepare a new array of rectangles which intersect with the framebuffer. */ RTRECT rectFramebuffer; @@ -1156,13 +1426,11 @@ int Display::handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect) cRectVisibleRegion++; } } - pFBInfo->pFramebuffer->SetVisibleRegion((BYTE *)pVisibleRegion, cRectVisibleRegion); } } -#if defined(RT_OS_DARWIN) && defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) - // @todo fix for multimonitor +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) BOOL is3denabled = FALSE; mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); @@ -1170,15 +1438,27 @@ int Display::handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect) VMMDev *vmmDev = mParent->getVMMDev(); if (is3denabled && vmmDev) { - VBOXHGCMSVCPARM parms[2]; + if (mhCrOglSvc) + { + RTRECT *pRectsCopy = (RTRECT *)RTMemAlloc( RT_MAX(cRect, 1) + * sizeof (RTRECT)); + if (pRectsCopy) + { + memcpy(pRectsCopy, pRect, cRect * sizeof (RTRECT)); + + VBOXHGCMSVCPARM parm; - parms[0].type = VBOX_HGCM_SVC_PARM_PTR; - parms[0].u.pointer.addr = pRect; - parms[0].u.pointer.size = 0; /* We don't actually care. */ - parms[1].type = VBOX_HGCM_SVC_PARM_32BIT; - parms[1].u.uint32 = cRect; + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pRectsCopy; + parm.u.pointer.size = cRect * sizeof (RTRECT); - vmmDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_VISIBLE_REGION, 2, &parms[0]); + vmmDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SET_VISIBLE_REGION, &parm, displayCrAsyncCmdCompletion, this); + } + else + AssertMsgFailed(("failed to allocate rects memory\n")); + } + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); } #endif @@ -1215,14 +1495,14 @@ static void vbvaRgnInit (VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, u { DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId]; - memset (&pFBInfo->dirtyRect, 0, sizeof (pFBInfo->dirtyRect)); + RT_ZERO(pFBInfo->dirtyRect); } } static void vbvaRgnDirtyRect (VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr) { - LogSunlover (("x = %d, y = %d, w = %d, h = %d\n", - phdr->x, phdr->y, phdr->w, phdr->h)); + LogSunlover(("x = %d, y = %d, w = %d, h = %d\n", + phdr->x, phdr->y, phdr->w, phdr->h)); /* * Here update rectangles are accumulated to form an update area. @@ -1396,6 +1676,17 @@ void Display::vbvaUnlock(void) RTCritSectLeave(&mVBVALock); } +int Display::SaveSeamlessRectLock(void) +{ + return RTCritSectEnter(&mSaveSeamlessRectLock); +} + +void Display::SaveSeamlessRectUnLock(void) +{ + RTCritSectLeave(&mSaveSeamlessRectLock); +} + + /** * @thread EMT */ @@ -1422,7 +1713,7 @@ int Display::videoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory) * Guest enabled acceleration at will. And it has to enable * acceleration after a mode change. */ - LogRelFlowFunc (("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n", + LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n", mfVideoAccelEnabled, fEnable, pVbvaMemory)); /* Strictly check parameters. Callers must not pass anything in the case. */ @@ -1439,7 +1730,7 @@ int Display::videoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory) { Assert (!mfVideoAccelEnabled); - LogRelFlowFunc (("Machine is not yet running.\n")); + LogRelFlowFunc(("Machine is not yet running.\n")); if (fEnable) { @@ -1507,7 +1798,7 @@ int Display::videoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory) LogRel(("VBVA: Disabled.\n")); } - LogRelFlowFunc (("VideoAccelEnable: rc = %Rrc.\n", rc)); + LogRelFlowFunc(("VideoAccelEnable: rc = %Rrc.\n", rc)); return rc; } @@ -1582,7 +1873,7 @@ static void vbvaFetchBytes (VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t c { if (cbDst >= VBVA_RING_BUFFER_SIZE) { - AssertMsgFailed (("cbDst = 0x%08X, ring buffer size 0x%08X", cbDst, VBVA_RING_BUFFER_SIZE)); + AssertMsgFailed (("cbDst = 0x%08X, ring buffer size 0x%08X\n", cbDst, VBVA_RING_BUFFER_SIZE)); return; } @@ -1662,8 +1953,8 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree; #ifdef DEBUG_sunlover - LogFlowFunc (("first = %d, free = %d\n", - indexRecordFirst, indexRecordFree)); + LogFlowFunc(("first = %d, free = %d\n", + indexRecordFirst, indexRecordFree)); #endif /* DEBUG_sunlover */ if (!vbvaVerifyRingBuffer (mpVbvaMemory)) @@ -1680,7 +1971,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst]; #ifdef DEBUG_sunlover - LogFlowFunc (("cbRecord = 0x%08X\n", pRecord->cbRecord)); + LogFlowFunc(("cbRecord = 0x%08X\n", pRecord->cbRecord)); #endif /* DEBUG_sunlover */ uint32_t cbRecord = pRecord->cbRecord & ~VBVA_F_RECORD_PARTIAL; @@ -1691,7 +1982,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) Assert (mpu8VbvaPartial); - LogFlowFunc (("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n", + LogFlowFunc(("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n", mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree)); if (cbRecord > mcbVbvaPartial) @@ -1716,7 +2007,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; #ifdef DEBUG_sunlover - LogFlowFunc (("partial done ok, data = %d, free = %d\n", + LogFlowFunc(("partial done ok, data = %d, free = %d\n", mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); #endif /* DEBUG_sunlover */ } @@ -1736,7 +2027,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) return false; } - LogFlowFunc (("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n", + LogFlowFunc(("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n", mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree)); } @@ -1771,7 +2062,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) if (!dst) { - LogRelFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord)); + LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord)); mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE; return false; } @@ -1781,7 +2072,7 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) *ppHdr = (VBVACMDHDR *)dst; #ifdef DEBUG_sunlover - LogFlowFunc (("Allocated from heap %p\n", dst)); + LogFlowFunc(("Allocated from heap %p\n", dst)); #endif /* DEBUG_sunlover */ } } @@ -1792,8 +2083,8 @@ bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd) mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; #ifdef DEBUG_sunlover - LogFlowFunc (("done ok, data = %d, free = %d\n", - mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); + LogFlowFunc(("done ok, data = %d, free = %d\n", + mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); #endif /* DEBUG_sunlover */ return true; @@ -1818,7 +2109,7 @@ void Display::vbvaReleaseCmd (VBVACMDHDR *pHdr, int32_t cbCmd) /* The pointer is outside. It is then an allocated copy. */ #ifdef DEBUG_sunlover - LogFlowFunc (("Free heap %p\n", pHdr)); + LogFlowFunc(("Free heap %p\n", pHdr)); #endif /* DEBUG_sunlover */ if ((uint8_t *)pHdr == mpu8VbvaPartial) @@ -1855,7 +2146,7 @@ void Display::VideoAccelFlush (void) void Display::videoAccelFlush (void) { #ifdef DEBUG_sunlover_2 - LogFlowFunc (("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled)); + LogFlowFunc(("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled)); #endif /* DEBUG_sunlover_2 */ if (!mfVideoAccelEnabled) @@ -1868,7 +2159,7 @@ void Display::videoAccelFlush (void) Assert(mpVbvaMemory); #ifdef DEBUG_sunlover_2 - LogFlowFunc (("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n", + LogFlowFunc(("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n", mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree, mpVbvaMemory->off32Data, mpVbvaMemory->off32Free)); #endif /* DEBUG_sunlover_2 */ @@ -1911,8 +2202,8 @@ void Display::videoAccelFlush (void) if (cbCmd != 0) { #ifdef DEBUG_sunlover - LogFlowFunc (("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n", - cbCmd, phdr->x, phdr->y, phdr->w, phdr->h)); + LogFlowFunc(("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n", + cbCmd, phdr->x, phdr->y, phdr->w, phdr->h)); #endif /* DEBUG_sunlover */ VBVACMDHDR hdrSaved = *phdr; @@ -2024,9 +2315,10 @@ int Display::videoAccelRefreshProcess(void) // IDisplay methods ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, - ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel) + ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel, + LONG *aXOrigin, LONG *aYOrigin) { - LogRelFlowFunc (("aScreenId = %d\n", aScreenId)); + LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -2036,10 +2328,12 @@ STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, uint32_t u32Width = 0; uint32_t u32Height = 0; uint32_t u32BitsPerPixel = 0; + int32_t xOrigin = 0; + int32_t yOrigin = 0; if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) { - CHECK_CONSOLE_DRV (mpDrv); + CHECK_CONSOLE_DRV(mpDrv); u32Width = mpDrv->IConnector.cx; u32Height = mpDrv->IConnector.cy; @@ -2052,6 +2346,8 @@ STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, u32Width = pFBInfo->w; u32Height = pFBInfo->h; u32BitsPerPixel = pFBInfo->u16BitsPerPixel; + xOrigin = pFBInfo->xOrigin; + yOrigin = pFBInfo->yOrigin; } else { @@ -2064,33 +2360,37 @@ STDMETHODIMP Display::GetScreenResolution (ULONG aScreenId, *aHeight = u32Height; if (aBitsPerPixel) *aBitsPerPixel = u32BitsPerPixel; + if (aXOrigin) + *aXOrigin = xOrigin; + if (aYOrigin) + *aYOrigin = yOrigin; return S_OK; } -STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId, - IFramebuffer *aFramebuffer) +STDMETHODIMP Display::SetFramebuffer(ULONG aScreenId, IFramebuffer *aFramebuffer) { - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); if (aFramebuffer != NULL) CheckComArgOutPointerValid(aFramebuffer); AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); + if (FAILED(autoCaller.rc())) + return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - Console::SafeVMPtrQuiet pVM (mParent); - if (pVM.isOk()) + Console::SafeVMPtrQuiet ptrVM(mParent); + if (ptrVM.isOk()) { /* Must release the lock here because the changeFramebuffer will * also obtain it. */ alock.release(); /* send request to the EMT thread */ - int vrc = VMR3ReqCallWait (pVM, VMCPUID_ANY, - (PFNRT) changeFramebuffer, 3, this, aFramebuffer, aScreenId); + int vrc = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, + (PFNRT)changeFramebuffer, 3, this, aFramebuffer, aScreenId); alock.acquire(); @@ -2113,7 +2413,16 @@ STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId, alock.release(); if (pVMMDev) - vrc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); + { +#if 0 + if (mhCrOglSvc) + pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SCREEN_CHANGED, &parm, NULL, NULL); + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); +#else + pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); +#endif + } /*ComAssertRCRet (vrc, E_FAIL);*/ alock.acquire(); @@ -2131,10 +2440,10 @@ STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId, return S_OK; } -STDMETHODIMP Display::GetFramebuffer (ULONG aScreenId, - IFramebuffer **aFramebuffer, LONG *aXOrigin, LONG *aYOrigin) +STDMETHODIMP Display::GetFramebuffer(ULONG aScreenId, + IFramebuffer **aFramebuffer, LONG *aXOrigin, LONG *aYOrigin) { - LogRelFlowFunc (("aScreenId = %d\n", aScreenId)); + LogRelFlowFunc(("aScreenId = %d\n", aScreenId)); CheckComArgOutPointerValid(aFramebuffer); @@ -2169,13 +2478,7 @@ STDMETHODIMP Display::SetVideoModeHint(ULONG aDisplay, BOOL aEnabled, AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV (mpDrv); - - /* XXX Ignore these parameters for now: */ - NOREF(aChangeOrigin); - NOREF(aOriginX); - NOREF(aOriginY); - NOREF(aEnabled); + CHECK_CONSOLE_DRV(mpDrv); /* * Do some rough checks for valid input @@ -2215,7 +2518,9 @@ STDMETHODIMP Display::SetVideoModeHint(ULONG aDisplay, BOOL aEnabled, { PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); if (pVMMDevPort) - pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel, aDisplay); + pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel, + aDisplay, aOriginX, aOriginY, + RT_BOOL(aEnabled), RT_BOOL(aChangeOrigin)); } return S_OK; } @@ -2237,9 +2542,83 @@ STDMETHODIMP Display::SetSeamlessMode (BOOL enabled) if (pVMMDevPort) pVMMDevPort->pfnRequestSeamlessChange(pVMMDevPort, !!enabled); } + +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + if (!enabled) + { + BOOL is3denabled = FALSE; + + mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + + VMMDev *vmmDev = mParent->getVMMDev(); + if (is3denabled && vmmDev) + { + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + /* NULL means disable */ + parm.u.pointer.addr = NULL; + parm.u.pointer.size = 0; /* <- means null rects, NULL pRects address and 0 rects means "disable" */ + + if (mhCrOglSvc) + vmmDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_SET_VISIBLE_REGION, &parm, NULL, NULL); + else + AssertMsgFailed(("mhCrOglSvc is NULL\n")); + + } + } +#endif return S_OK; } +#ifdef VBOX_WITH_CROGL +BOOL Display::displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data, uint32_t u32Width, uint32_t u32Height) +{ + BOOL is3denabled; + pDisplay->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + if (is3denabled && pDisplay->mCrOglCallbacks.pfnHasData()) + { + VMMDev *pVMMDev = pDisplay->mParent->getVMMDev(); + if (pVMMDev) + { + CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)RTMemAlloc(sizeof (*pScreenshot)); + if (pScreenshot) + { + /* screen id or CRSCREEN_ALL to specify all enabled */ + pScreenshot->u32Screen = aScreenId; + pScreenshot->u32Width = u32Width; + pScreenshot->u32Height = u32Height; + pScreenshot->u32Pitch = u32Width * 4; + pScreenshot->pvBuffer = pu8Data; + pScreenshot->pvContext = NULL; + pScreenshot->pfnScreenshotBegin = NULL; + pScreenshot->pfnScreenshotPerform = NULL; + pScreenshot->pfnScreenshotEnd = NULL; + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pScreenshot; + parm.u.pointer.size = sizeof (*pScreenshot); + + int rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_TAKE_SCREENSHOT, 1, &parm); + + RTMemFree(pScreenshot); + + if (RT_SUCCESS(rc)) + return TRUE; + else + { + AssertMsgFailed(("failed to get screenshot data from crOgl %d\n", rc)); + /* fall back to the non-3d mechanism */ + } + } + } + } + return FALSE; +} +#endif + int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height) { int rc; @@ -2287,15 +2666,15 @@ int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_ uint32_t u32DstBitsPerPixel = 32; rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, - width, height, - pu8Src, - xSrc, ySrc, - u32SrcWidth, u32SrcHeight, - u32SrcLineSize, u32SrcBitsPerPixel, - pu8Dst, - xDst, yDst, - u32DstWidth, u32DstHeight, - u32DstLineSize, u32DstBitsPerPixel); + width, height, + pu8Src, + xSrc, ySrc, + u32SrcWidth, u32SrcHeight, + u32SrcLineSize, u32SrcBitsPerPixel, + pu8Dst, + xDst, yDst, + u32DstWidth, u32DstHeight, + u32DstLineSize, u32DstBitsPerPixel); if (RT_SUCCESS(rc)) { *ppu8Data = pu8Data; @@ -2306,6 +2685,14 @@ int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_ else { RTMemFree(pu8Data); + + /* CopyRect can fail if VBVA was paused in VGA device, retry using the generic method. */ + if ( rc == VERR_INVALID_STATE + && aScreenId == VBOX_VIDEO_PRIMARY_SCREEN) + { + rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, + ppu8Data, pcbData, pu32Width, pu32Height); + } } } } @@ -2327,7 +2714,8 @@ int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_ return rc; } -static int displayTakeScreenshot(PVM pVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId, BYTE *address, ULONG width, ULONG height) +static int displayTakeScreenshot(PUVM pUVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId, + BYTE *address, ULONG width, ULONG height) { uint8_t *pu8Data = NULL; size_t cbData = 0; @@ -2335,6 +2723,11 @@ static int displayTakeScreenshot(PVM pVM, Display *pDisplay, struct DRVMAINDISPL uint32_t cy = 0; int vrc = VINF_SUCCESS; +# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + if (Display::displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t*)address, width, height)) + return VINF_SUCCESS; +#endif + int cRetries = 5; while (cRetries-- > 0) @@ -2342,8 +2735,8 @@ static int displayTakeScreenshot(PVM pVM, Display *pDisplay, struct DRVMAINDISPL /* Note! Not sure if the priority call is such a good idea here, but it would be nice to have an accurate screenshot for the bug report if the VM deadlocks. */ - vrc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)Display::displayTakeScreenshotEMT, 6, - pDisplay, aScreenId, &pu8Data, &cbData, &cx, &cy); + vrc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)Display::displayTakeScreenshotEMT, 6, + pDisplay, aScreenId, &pu8Data, &cbData, &cx, &cy); if (vrc != VERR_TRY_AGAIN) { break; @@ -2419,10 +2812,12 @@ STDMETHODIMP Display::TakeScreenShot(ULONG aScreenId, BYTE *address, ULONG width AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV(mpDrv); + if (!mpDrv) + return E_FAIL; - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; @@ -2435,7 +2830,7 @@ STDMETHODIMP Display::TakeScreenShot(ULONG aScreenId, BYTE *address, ULONG width */ alock.release(); - int vrc = displayTakeScreenshot(pVM, this, mpDrv, aScreenId, address, width, height); + int vrc = displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, address, width, height); if (vrc == VERR_NOT_IMPLEMENTED) rc = setError(E_NOTIMPL, @@ -2447,7 +2842,7 @@ STDMETHODIMP Display::TakeScreenShot(ULONG aScreenId, BYTE *address, ULONG width rc = setError(VBOX_E_IPRT_ERROR, tr("Could not take a screenshot (%Rrc)"), vrc); - LogRelFlowFunc(("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } @@ -2471,10 +2866,12 @@ STDMETHODIMP Display::TakeScreenShotToArray(ULONG aScreenId, ULONG width, ULONG AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV(mpDrv); + if (!mpDrv) + return E_FAIL; - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; @@ -2493,7 +2890,7 @@ STDMETHODIMP Display::TakeScreenShotToArray(ULONG aScreenId, ULONG width, ULONG if (!pu8Data) return E_OUTOFMEMORY; - int vrc = displayTakeScreenshot(pVM, this, mpDrv, aScreenId, pu8Data, width, height); + int vrc = displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, pu8Data, width, height); if (RT_SUCCESS(vrc)) { @@ -2523,7 +2920,7 @@ STDMETHODIMP Display::TakeScreenShotToArray(ULONG aScreenId, ULONG width, ULONG RTMemFree(pu8Data); - LogRelFlowFunc(("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } @@ -2549,8 +2946,9 @@ STDMETHODIMP Display::TakeScreenShotPNGToArray(ULONG aScreenId, ULONG width, ULO CHECK_CONSOLE_DRV(mpDrv); - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; @@ -2569,7 +2967,7 @@ STDMETHODIMP Display::TakeScreenShotPNGToArray(ULONG aScreenId, ULONG width, ULO if (!pu8Data) return E_OUTOFMEMORY; - int vrc = displayTakeScreenshot(pVM, this, mpDrv, aScreenId, pu8Data, width, height); + int vrc = displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, pu8Data, width, height); if (RT_SUCCESS(vrc)) { @@ -2605,12 +3003,136 @@ STDMETHODIMP Display::TakeScreenShotPNGToArray(ULONG aScreenId, ULONG width, ULO RTMemFree(pu8Data); - LogRelFlowFunc(("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } +int Display::VideoCaptureEnableScreens(ComSafeArrayIn(BOOL, aScreens)) +{ +#ifdef VBOX_WITH_VPX + com::SafeArray<BOOL> Screens(ComSafeArrayInArg(aScreens)); + for (unsigned i = 0; i < Screens.size(); i++) + maVideoRecEnabled[i] = RT_BOOL(Screens[i]); + return VINF_SUCCESS; +#else + return VERR_NOT_IMPLEMENTED; +#endif +} -int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height) +/** + * Start video capturing. Does nothing if capturing is already active. + */ +int Display::VideoCaptureStart() +{ +#ifdef VBOX_WITH_VPX + if (VideoRecIsEnabled(mpVideoRecCtx)) + return VINF_SUCCESS; + + int rc = VideoRecContextCreate(&mpVideoRecCtx, mcMonitors); + if (RT_FAILURE(rc)) + { + LogFlow(("Failed to create video recording context (%Rrc)!\n", rc)); + return rc; + } + ComPtr<IMachine> pMachine = mParent->machine(); + com::SafeArray<BOOL> screens; + HRESULT hrc = pMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens)); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++) + maVideoRecEnabled[i] = i < screens.size() && screens[i]; + ULONG ulWidth; + hrc = pMachine->COMGETTER(VideoCaptureWidth)(&ulWidth); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + ULONG ulHeight; + hrc = pMachine->COMGETTER(VideoCaptureHeight)(&ulHeight); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + ULONG ulRate; + hrc = pMachine->COMGETTER(VideoCaptureRate)(&ulRate); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + ULONG ulFPS; + hrc = pMachine->COMGETTER(VideoCaptureFPS)(&ulFPS); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + BSTR strFile; + hrc = pMachine->COMGETTER(VideoCaptureFile)(&strFile); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + RTTIMESPEC ts; + RTTimeNow(&ts); + RTTIME time; + RTTimeExplode(&time, &ts); + for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++) + { + char *pszAbsPath = RTPathAbsDup(com::Utf8Str(strFile).c_str()); + char *pszExt = RTPathExt(pszAbsPath); + if (pszExt) + pszExt = RTStrDup(pszExt); + RTPathStripExt(pszAbsPath); + if (!pszAbsPath) + rc = VERR_INVALID_PARAMETER; + if (!pszExt) + pszExt = RTStrDup(".webm"); + char *pszName = NULL; + if (RT_SUCCESS(rc)) + { + if (mcMonitors > 1) + rc = RTStrAPrintf(&pszName, "%s-%u%s", pszAbsPath, uScreen+1, pszExt); + else + rc = RTStrAPrintf(&pszName, "%s%s", pszAbsPath, pszExt); + } + if (RT_SUCCESS(rc)) + { + rc = VideoRecStrmInit(mpVideoRecCtx, uScreen, + pszName, ulWidth, ulHeight, ulRate, ulFPS); + if (rc == VERR_ALREADY_EXISTS) + { + RTStrFree(pszName); + pszName = NULL; + + if (mcMonitors > 1) + rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s", + pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay, + time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond, + uScreen+1, pszExt); + else + rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s", + pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay, + time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond, + pszExt); + if (RT_SUCCESS(rc)) + rc = VideoRecStrmInit(mpVideoRecCtx, uScreen, + pszName, ulWidth, ulHeight, ulRate, ulFPS); + } + } + + if (RT_SUCCESS(rc)) + LogRel(("WebM/VP8 video recording screen #%u with %ux%u @ %u kbps, %u fps to '%s' enabled.\n", + uScreen, ulWidth, ulHeight, ulRate, ulFPS, pszName)); + else + LogRel(("Failed to initialize video recording context #%u (%Rrc)!\n", uScreen, rc)); + RTStrFree(pszName); + RTStrFree(pszExt); + RTStrFree(pszAbsPath); + } + return rc; +#else + return VERR_NOT_IMPLEMENTED; +#endif +} + +/** + * Stop video capturing. Does nothing if video capturing is not active. + */ +void Display::VideoCaptureStop() +{ +#ifdef VBOX_WITH_VPX + if (VideoRecIsEnabled(mpVideoRecCtx)) + LogRel(("WebM/VP8 video recording stopped.\n")); + VideoRecContextClose(mpVideoRecCtx); + mpVideoRecCtx = NULL; +#endif +} + +int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, + ULONG x, ULONG y, ULONG width, ULONG height) { int rc = VINF_SUCCESS; pDisplay->vbvaLock(); @@ -2661,7 +3183,7 @@ int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, * it to update. And for default format, render the guest VRAM to framebuffer. */ if ( pFBInfo->fDefaultFormat - && !(pFBInfo->fDisabled)) + && !pFBInfo->fDisabled) { address = NULL; HRESULT hrc = pFBInfo->pFramebuffer->COMGETTER(Address) (&address); @@ -2706,15 +3228,16 @@ int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, rc = VERR_INVALID_PARAMETER; } - if (RT_SUCCESS(rc) && pDisplay->maFramebuffers[aScreenId].u32ResizeStatus == ResizeStatus_Void) + if ( RT_SUCCESS(rc) + && pDisplay->maFramebuffers[aScreenId].u32ResizeStatus == ResizeStatus_Void) pDisplay->mParent->consoleVRDPServer()->SendUpdateBitmap(aScreenId, x, y, width, height); pDisplay->vbvaUnlock(); return rc; } -STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULONG y, - ULONG width, ULONG height) +STDMETHODIMP Display::DrawToScreen(ULONG aScreenId, BYTE *address, + ULONG x, ULONG y, ULONG width, ULONG height) { /// @todo (r=dmik) this function may take too long to complete if the VM // is doing something like saving state right now. Which, in case if it @@ -2722,7 +3245,7 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO // check the machine state here (by enclosing the check and VMRequCall // within the Console lock to make it atomic). - LogRelFlowFunc (("address=%p, x=%d, y=%d, width=%d, height=%d\n", + LogRelFlowFunc(("address=%p, x=%d, y=%d, width=%d, height=%d\n", (void *)address, x, y, width, height)); CheckComArgNotNull(address); @@ -2734,10 +3257,11 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV (mpDrv); + CHECK_CONSOLE_DRV(mpDrv); - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); /* Release lock because the call scheduled on EMT may also try to take it. */ alock.release(); @@ -2746,8 +3270,8 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO * Again we're lazy and make the graphics device do all the * dirty conversion work. */ - int rcVBox = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)Display::drawToScreenEMT, 7, - this, aScreenId, address, x, y, width, height); + int rcVBox = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::drawToScreenEMT, 7, + this, aScreenId, address, x, y, width, height); /* * If the function returns not supported, we'll have to do all the @@ -2769,15 +3293,15 @@ STDMETHODIMP Display::DrawToScreen (ULONG aScreenId, BYTE *address, ULONG x, ULO // handleDisplayUpdate (x, y, width, height); // } - LogRelFlowFunc (("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } -void Display::InvalidateAndUpdateEMT(Display *pDisplay) +void Display::InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll) { pDisplay->vbvaLock(); unsigned uScreenId; - for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) + for (uScreenId = (fUpdateAll ? 0 : uId); uScreenId < pDisplay->mcMonitors; uScreenId++) { DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; @@ -2788,7 +3312,8 @@ void Display::InvalidateAndUpdateEMT(Display *pDisplay) else { if ( !pFBInfo->pFramebuffer.isNull() - && !(pFBInfo->fDisabled)) + && !pFBInfo->fDisabled + && pFBInfo->u32ResizeStatus == ResizeStatus_Void) { /* Render complete VRAM screen to the framebuffer. * When framebuffer uses VRAM directly, just notify it to update. @@ -2796,6 +3321,10 @@ void Display::InvalidateAndUpdateEMT(Display *pDisplay) if (pFBInfo->fDefaultFormat) { BYTE *address = NULL; + ULONG uWidth = 0; + ULONG uHeight = 0; + pFBInfo->pFramebuffer->COMGETTER(Width) (&uWidth); + pFBInfo->pFramebuffer->COMGETTER(Height) (&uHeight); HRESULT hrc = pFBInfo->pFramebuffer->COMGETTER(Address) (&address); if (SUCCEEDED(hrc) && address != NULL) { @@ -2819,22 +3348,32 @@ void Display::InvalidateAndUpdateEMT(Display *pDisplay) uint32_t u32DstLineSize = u32DstWidth * 4; uint32_t u32DstBitsPerPixel = 32; - pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, - width, height, - pu8Src, - xSrc, ySrc, - u32SrcWidth, u32SrcHeight, - u32SrcLineSize, u32SrcBitsPerPixel, - pu8Dst, - xDst, yDst, - u32DstWidth, u32DstHeight, - u32DstLineSize, u32DstBitsPerPixel); + /* if uWidth != pFBInfo->w and uHeight != pFBInfo->h + * implies resize of Framebuffer is in progress and + * copyrect should not be called. + */ + if (uWidth == pFBInfo->w && uHeight == pFBInfo->h) + { + + pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort, + width, height, + pu8Src, + xSrc, ySrc, + u32SrcWidth, u32SrcHeight, + u32SrcLineSize, u32SrcBitsPerPixel, + pu8Dst, + xDst, yDst, + u32DstWidth, u32DstHeight, + u32DstLineSize, u32DstBitsPerPixel); + } } } pDisplay->handleDisplayUpdate (uScreenId, 0, 0, pFBInfo->w, pFBInfo->h); } } + if (!fUpdateAll) + break; } pDisplay->vbvaUnlock(); } @@ -2854,28 +3393,29 @@ STDMETHODIMP Display::InvalidateAndUpdate() AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - CHECK_CONSOLE_DRV (mpDrv); + CHECK_CONSOLE_DRV(mpDrv); - Console::SafeVMPtr pVM(mParent); - if (FAILED(pVM.rc())) return pVM.rc(); + Console::SafeVMPtr ptrVM(mParent); + if (!ptrVM.isOk()) + return ptrVM.rc(); HRESULT rc = S_OK; - LogRelFlowFunc (("Sending DPYUPDATE request\n")); + LogRelFlowFunc(("Sending DPYUPDATE request\n")); /* Have to release the lock when calling EMT. */ alock.release(); /* pdm.h says that this has to be called from the EMT thread */ - int rcVBox = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)Display::InvalidateAndUpdateEMT, - 1, this); + int rcVBox = VMR3ReqCallVoidWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::InvalidateAndUpdateEMT, + 3, this, 0, true); alock.acquire(); if (RT_FAILURE(rcVBox)) rc = setError(VBOX_E_IPRT_ERROR, tr("Could not invalidate and update the screen (%Rrc)"), rcVBox); - LogRelFlowFunc (("rc=%08X\n", rc)); + LogRelFlowFunc(("rc=%Rhrc\n", rc)); return rc; } @@ -2887,7 +3427,7 @@ STDMETHODIMP Display::InvalidateAndUpdate() */ STDMETHODIMP Display::ResizeCompleted(ULONG aScreenId) { - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); /// @todo (dmik) can we AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); here? // This will require general code review and may add some details. @@ -2926,33 +3466,33 @@ STDMETHODIMP Display::CompleteVHWACommand(BYTE *pCommand) STDMETHODIMP Display::ViewportChanged(ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height) { #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + + if (mcMonitors <= aScreenId) + { + AssertMsgFailed(("invalid screen id\n")); + return E_INVALIDARG; + } + BOOL is3denabled; mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); if (is3denabled) { - VBOXHGCMSVCPARM aParms[5]; - - aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[0].u.uint32 = aScreenId; - - aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[1].u.uint32 = x; - - aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[2].u.uint32 = y; - - - aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[3].u.uint32 = width; - - aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT; - aParms[4].u.uint32 = height; - VMMDev *pVMMDev = mParent->getVMMDev(); if (pVMMDev) - pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_VIEWPORT_CHANGED, SHCRGL_CPARMS_VIEWPORT_CHANGED, aParms); + { + crViewportNotify(pVMMDev, aScreenId, x, y, width, height); + } + else + { + DISPLAYFBINFO *pFb = &maFramebuffers[aScreenId]; + pFb->pendingViewportInfo.fPending = true; + pFb->pendingViewportInfo.x = x; + pFb->pendingViewportInfo.y = y; + pFb->pendingViewportInfo.width = width; + pFb->pendingViewportInfo.height = height; + } } #endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */ return S_OK; @@ -2966,15 +3506,15 @@ STDMETHODIMP Display::ViewportChanged(ULONG aScreenId, ULONG x, ULONG y, ULONG w * * @thread EMT */ -void Display::updateDisplayData(void) +int Display::updateDisplayData(void) { - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); /* the driver might not have been constructed yet */ if (!mpDrv) - return; + return VINF_SUCCESS; -#if DEBUG +#ifdef VBOX_STRICT /* * Sanity check. Note that this method may be called on EMT after Console * has started the power down procedure (but before our #drvDestruct() is @@ -2983,9 +3523,12 @@ void Display::updateDisplayData(void) * build to save some ms (necessary to construct SafeVMPtrQuiet) in this * time-critical method. */ - Console::SafeVMPtrQuiet pVM (mParent); - if (pVM.isOk()) - VM_ASSERT_EMT (pVM.raw()); + Console::SafeVMPtrQuiet ptrVM(mParent); + if (ptrVM.isOk()) + { + PVM pVM = VMR3GetVM(ptrVM.rawUVM()); + Assert(VM_IS_EMT(pVM)); + } #endif /* The method is only relevant to the primary framebuffer. */ @@ -3010,6 +3553,14 @@ void Display::updateDisplayData(void) rc = pFramebuffer->COMGETTER(Height) (&height); AssertComRC (rc); + if ( (width != mLastWidth && mLastWidth != 0) + || (height != mLastHeight && mLastHeight != 0)) + { + LogRel(("updateDisplayData: size mismatch w %d(%d) h %d(%d)\n", + width, mLastWidth, height, mLastHeight)); + return VERR_INVALID_STATE; + } + mpDrv->IConnector.pu8Data = (uint8_t *) address; mpDrv->IConnector.cbScanline = bytesPerLine; mpDrv->IConnector.cBits = bitsPerPixel; @@ -3025,8 +3576,57 @@ void Display::updateDisplayData(void) mpDrv->IConnector.cx = 0; mpDrv->IConnector.cy = 0; } - LogRelFlowFunc (("leave\n")); + LogRelFlowFunc(("leave\n")); + return VINF_SUCCESS; +} + +#ifdef VBOX_WITH_CROGL +void Display::crViewportNotify(VMMDev *pVMMDev, ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height) +{ +#if 0 + VBOXHGCMSVCPARM parm; + + CRVBOXHGCMVIEWPORT *pViewportInfo = (CRVBOXHGCMVIEWPORT*)RTMemAlloc(sizeof (*pViewportInfo)); + if(!pViewportInfo) + { + AssertMsgFailed(("RTMemAlloc failed!\n")); + return; + } + + pViewportInfo->u32Screen = aScreenId; + pViewportInfo->x = x; + pViewportInfo->y = y; + pViewportInfo->width = width; + pViewportInfo->height = height; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pViewportInfo; + parm.u.pointer.size = sizeof (*pViewportInfo); + + pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_VIEWPORT_CHANGED2, &parm, displayCrAsyncCmdCompletion, this); +#else + VBOXHGCMSVCPARM aParms[5]; + + aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[0].u.uint32 = aScreenId; + + aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[1].u.uint32 = x; + + aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[2].u.uint32 = y; + + + aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[3].u.uint32 = width; + + aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT; + aParms[4].u.uint32 = height; + + pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_VIEWPORT_CHANGED, SHCRGL_CPARMS_VIEWPORT_CHANGED, aParms); +#endif } +#endif #ifdef VBOX_WITH_CRHGSMI void Display::setupCrHgsmiData(void) @@ -3041,8 +3641,8 @@ void Display::setupCrHgsmiData(void) { Assert(mhCrOglSvc); /* setup command completion callback */ - VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION Completion; - Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION; + VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion; + Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB; Completion.Hdr.cbCmd = sizeof (Completion); Completion.hCompletion = mpDrv->pVBVACallbacks; Completion.pfnCompletion = mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync; @@ -3054,7 +3654,23 @@ void Display::setupCrHgsmiData(void) rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_CRHGSMI_CTL, 1, &parm); if (RT_SUCCESS(rc)) + { + ULONG ul; + + for (ul = 0; ul < mcMonitors; ul++) + { + DISPLAYFBINFO *pFb = &maFramebuffers[ul]; + if (!pFb->pendingViewportInfo.fPending) + continue; + + crViewportNotify(pVMMDev, ul, pFb->pendingViewportInfo.x, pFb->pendingViewportInfo.y, pFb->pendingViewportInfo.width, pFb->pendingViewportInfo.height); + pFb->pendingViewportInfo.fPending = false; + } + + mCrOglCallbacks = Completion.MainInterface; + return; + } AssertMsgFailed(("VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION failed rc %d", rc)); } @@ -3079,7 +3695,7 @@ void Display::destructCrHgsmiData(void) DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB, unsigned uScreenId) { - LogRelFlowFunc (("uScreenId = %d\n", uScreenId)); + LogRelFlowFunc(("uScreenId = %d\n", uScreenId)); AssertReturn(that, VERR_INVALID_PARAMETER); AssertReturn(uScreenId < that->mcMonitors, VERR_INVALID_PARAMETER); @@ -3137,7 +3753,7 @@ DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB, } } - LogRelFlowFunc (("leave\n")); + LogRelFlowFunc(("leave\n")); return VINF_SUCCESS; } @@ -3151,7 +3767,7 @@ DECLCALLBACK(int) Display::displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterfac { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - LogRelFlowFunc (("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n", + LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n", bpp, pvVRAM, cbLine, cx, cy)); return pDrv->pDisplay->handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE); @@ -3168,8 +3784,8 @@ DECLCALLBACK(void) Display::displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterfa PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); #ifdef DEBUG_sunlover - LogFlowFunc (("mfVideoAccelEnabled = %d, %d,%d %dx%d\n", - pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy)); + LogFlowFunc(("mfVideoAccelEnabled = %d, %d,%d %dx%d\n", + pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy)); #endif /* DEBUG_sunlover */ /* This call does update regardless of VBVA status. @@ -3184,25 +3800,26 @@ DECLCALLBACK(void) Display::displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterfa * Periodic display refresh callback. * * @see PDMIDISPLAYCONNECTOR::pfnRefresh + * @thread EMT */ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); #ifdef DEBUG_sunlover - STAM_PROFILE_START(&StatDisplayRefresh, a); + STAM_PROFILE_START(&g_StatDisplayRefresh, a); #endif /* DEBUG_sunlover */ #ifdef DEBUG_sunlover_2 - LogFlowFunc (("pDrv->pDisplay->mfVideoAccelEnabled = %d\n", - pDrv->pDisplay->mfVideoAccelEnabled)); + LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n", + pDrv->pDisplay->mfVideoAccelEnabled)); #endif /* DEBUG_sunlover_2 */ Display *pDisplay = pDrv->pDisplay; bool fNoUpdate = false; /* Do not update the display if any of the framebuffers is being resized. */ unsigned uScreenId; - LogFlow(("DisplayRefreshCallback\n")); + Log2(("DisplayRefreshCallback\n")); for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) { DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; @@ -3214,7 +3831,7 @@ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterf if (u32ResizeStatus == ResizeStatus_UpdateDisplayData) { - LogRelFlowFunc (("ResizeStatus_UpdateDisplayData %d\n", uScreenId)); + LogRelFlowFunc(("ResizeStatus_UpdateDisplayData %d\n", uScreenId)); fNoUpdate = true; /* Always set it here, because pfnUpdateDisplayAll can cause a new resize. */ /* The framebuffer was resized and display data need to be updated. */ pDisplay->handleResizeCompletedEMT (); @@ -3226,12 +3843,12 @@ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterf /* Continue with normal processing because the status here is ResizeStatus_Void. * Repaint all displays because VM continued to run during the framebuffer resize. */ - pDisplay->InvalidateAndUpdateEMT(pDisplay); + pDisplay->InvalidateAndUpdateEMT(pDisplay, uScreenId, false); } else if (u32ResizeStatus == ResizeStatus_InProgress) { /* The framebuffer is being resized. Do not call the VGA device back. Immediately return. */ - LogRelFlowFunc (("ResizeStatus_InProcess\n")); + LogRelFlowFunc(("ResizeStatus_InProcess\n")); fNoUpdate = true; continue; } @@ -3275,72 +3892,94 @@ DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterf } #ifdef VBOX_WITH_VPX - if (VideoRecIsEnabled(pDisplay->mpVideoRecContext)) - { - uint32_t u32VideoRecImgFormat = VPX_IMG_FMT_NONE; - ULONG ulGuestHeight = 0; - ULONG ulGuestWidth = 0; - ULONG ulBitsPerPixel; - int rc; - DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN]; - - if ( !pFBInfo->pFramebuffer.isNull() - && !(pFBInfo->fDisabled) - && pFBInfo->u32ResizeStatus == ResizeStatus_Void) - { - if (pFBInfo->fVBVAEnabled && pFBInfo->pu8FramebufferVRAM) - { - rc = VideoRecCopyToIntBuffer(pDisplay->mpVideoRecContext, 0, 0, - FramebufferPixelFormat_FOURCC_RGB, pFBInfo->u16BitsPerPixel, - pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h, - pFBInfo->pu8FramebufferVRAM); - ulGuestWidth = pFBInfo->w; - ulGuestHeight = pFBInfo->h; - ulBitsPerPixel = pFBInfo->u16BitsPerPixel; - } - else + if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx)) + { + do { +# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) + BOOL is3denabled; + pDisplay->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); + if (is3denabled) { - rc = VideoRecCopyToIntBuffer(pDisplay->mpVideoRecContext, 0, 0, - FramebufferPixelFormat_FOURCC_RGB, pDrv->IConnector.cBits, - pDrv->IConnector.cbScanline, pDrv->IConnector.cx, - pDrv->IConnector.cy, pDrv->IConnector.pu8Data); - ulGuestWidth = pDrv->IConnector.cx; - ulGuestHeight = pDrv->IConnector.cy; - ulBitsPerPixel = pDrv->IConnector.cBits; - } + if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE)) + { + if (pDisplay->mCrOglCallbacks.pfnHasData()) + { + /* submit */ + + VBOXHGCMSVCPARM parm; + + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = &pDisplay->mCrOglScreenshotData; + parm.u.pointer.size = sizeof (pDisplay->mCrOglScreenshotData); + + VMMDev *pVMMDev = pDisplay->mParent->getVMMDev(); + if (pVMMDev) + { + int rc = pVMMDev->hgcmHostFastCallAsync(pDisplay->mhCrOglSvc, SHCRGL_HOST_FN_TAKE_SCREENSHOT, &parm, displayVRecCompletion, pDisplay); + if (RT_SUCCESS(rc)) + break; + else + AssertMsgFailed(("hgcmHostFastCallAsync failed %f\n", rc)); + } + else + AssertMsgFailed(("no VMMDev\n")); + } - switch (ulBitsPerPixel) - { - case 32: - u32VideoRecImgFormat = VPX_IMG_FMT_RGB32; - Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB32\n")); - break; - case 24: - u32VideoRecImgFormat = VPX_IMG_FMT_RGB24; - Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB24\n")); - break; - case 16: - u32VideoRecImgFormat = VPX_IMG_FMT_RGB565; - Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB565\n")); - break; - default: - Log2(("No Proper Format detected\n")); + /* no 3D data available, or error has occured, + * go the straight way */ + ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE); + } + else + { + /* record request is still in progress, don't do anything */ break; + } } +# endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */ - /* Just return in case of failure without any assertion */ - if( RT_SUCCESS(rc)) - if (RT_SUCCESS(VideoRecDoRGBToYUV(pDisplay->mpVideoRecContext, u32VideoRecImgFormat))) - VideoRecEncodeAndWrite(pDisplay->mpVideoRecContext, ulGuestWidth, ulGuestHeight); - } + uint64_t u64Now = RTTimeProgramMilliTS(); + for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++) + { + if (!pDisplay->maVideoRecEnabled[uScreenId]) + continue; + + DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId]; + + if ( !pFBInfo->pFramebuffer.isNull() + && !pFBInfo->fDisabled + && pFBInfo->u32ResizeStatus == ResizeStatus_Void) + { + int rc; + if ( pFBInfo->fVBVAEnabled + && pFBInfo->pu8FramebufferVRAM) + { + rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0, + FramebufferPixelFormat_FOURCC_RGB, + pFBInfo->u16BitsPerPixel, + pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h, + pFBInfo->pu8FramebufferVRAM, u64Now); + } + else + { + rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0, + FramebufferPixelFormat_FOURCC_RGB, + pDrv->IConnector.cBits, + pDrv->IConnector.cbScanline, pDrv->IConnector.cx, + pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now); + } + if (rc == VINF_TRY_AGAIN) + break; + } + } + } while (0); } -#endif +#endif /* VBOX_WITH_VPX */ #ifdef DEBUG_sunlover - STAM_PROFILE_STOP(&StatDisplayRefresh, a); + STAM_PROFILE_STOP(&g_StatDisplayRefresh, a); #endif /* DEBUG_sunlover */ #ifdef DEBUG_sunlover_2 - LogFlowFunc (("leave\n")); + LogFlowFunc(("leave\n")); #endif /* DEBUG_sunlover_2 */ } @@ -3353,7 +3992,7 @@ DECLCALLBACK(void) Display::displayResetCallback(PPDMIDISPLAYCONNECTOR pInterfac { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - LogRelFlowFunc (("\n")); + LogRelFlowFunc(("\n")); /* Disable VBVA mode. */ pDrv->pDisplay->VideoAccelEnable (false, NULL); @@ -3368,7 +4007,7 @@ DECLCALLBACK(void) Display::displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR p { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - LogRelFlowFunc (("fEnabled=%d\n", fEnabled)); + LogRelFlowFunc(("fEnabled=%d\n", fEnabled)); NOREF(fEnabled); @@ -3611,48 +4250,42 @@ DECLCALLBACK(void) Display::displayProcessDisplayDataCallback(PPDMIDISPLAYCONNEC #ifdef VBOX_WITH_VIDEOHWACCEL -void Display::handleVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand) +#ifndef S_FALSE +# define S_FALSE ((HRESULT)1L) +#endif + +int Display::handleVHWACommandProcess(PVBOXVHWACMD pCommand) { unsigned id = (unsigned)pCommand->iDisplay; int rc = VINF_SUCCESS; - if (id < mcMonitors) - { - IFramebuffer *pFramebuffer = maFramebuffers[id].pFramebuffer; -#ifdef DEBUG_misha - Assert (pFramebuffer); -#endif + if (id >= mcMonitors) + return VERR_INVALID_PARAMETER; - if (pFramebuffer != NULL) - { - HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand); - if (FAILED(hr)) - { - rc = (hr == E_NOTIMPL) ? VERR_NOT_IMPLEMENTED : VERR_GENERAL_FAILURE; - } - } - else - { - rc = VERR_NOT_IMPLEMENTED; - } - } - else - { - rc = VERR_INVALID_PARAMETER; - } + ComPtr<IFramebuffer> pFramebuffer; + AutoReadLock arlock(this COMMA_LOCKVAL_SRC_POS); + pFramebuffer = maFramebuffers[id].pFramebuffer; + arlock.release(); - if (RT_FAILURE(rc)) - { - /* tell the guest the command is complete */ - pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH); - pCommand->rc = rc; - } + if (pFramebuffer == NULL) + return VERR_INVALID_STATE; /* notify we can not handle request atm */ + + HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand); + if (hr == S_FALSE) + return VINF_SUCCESS; + else if (SUCCEEDED(hr)) + return VINF_CALLBACK_RETURN; + else if (hr == E_ACCESSDENIED) + return VERR_INVALID_STATE; /* notify we can not handle request atm */ + else if (hr == E_NOTIMPL) + return VERR_NOT_IMPLEMENTED; + return VERR_GENERAL_FAILURE; } -DECLCALLBACK(void) Display::displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand) +DECLCALLBACK(int) Display::displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - pDrv->pDisplay->handleVHWACommandProcess(pInterface, pCommand); + return pDrv->pDisplay->handleVHWACommandProcess(pCommand); } #endif @@ -3667,9 +4300,9 @@ void Display::handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Functio mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr, result); } -void Display::handleCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) +void Display::handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) { - int rc = VERR_INVALID_FUNCTION; + int rc = VERR_NOT_SUPPORTED; VBOXHGCMSVCPARM parm; parm.type = VBOX_HGCM_SVC_PARM_PTR; parm.u.pointer.addr = pCmd; @@ -3695,9 +4328,9 @@ void Display::handleCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBO handleCrHgsmiCommandCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm); } -void Display::handleCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl) +void Display::handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl) { - int rc = VERR_INVALID_FUNCTION; + int rc = VERR_NOT_SUPPORTED; VBOXHGCMSVCPARM parm; parm.type = VBOX_HGCM_SVC_PARM_PTR; parm.u.pointer.addr = pCtl; @@ -3721,19 +4354,18 @@ void Display::handleCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBO handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm); } - DECLCALLBACK(void) Display::displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - pDrv->pDisplay->handleCrHgsmiCommandProcess(pInterface, pCmd, cbCmd); + pDrv->pDisplay->handleCrHgsmiCommandProcess(pCmd, cbCmd); } DECLCALLBACK(void) Display::displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd, uint32_t cbCmd) { PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); - pDrv->pDisplay->handleCrHgsmiControlProcess(pInterface, pCmd, cbCmd); + pDrv->pDisplay->handleCrHgsmiControlProcess(pCmd, cbCmd); } DECLCALLBACK(void) Display::displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) @@ -3750,6 +4382,131 @@ DECLCALLBACK(void) Display::displayCrHgsmiControlCompletion(int32_t result, uint } #endif +DECLCALLBACK(void) Display::displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr; + if (pCmd->pfnInternal) + ((PFNCRCTLCOMPLETION)pCmd->pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext); +} + +int Display::handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion) +{ + VMMDev *pVMMDev = mParent->getVMMDev(); + if (!pVMMDev) + { + AssertMsgFailed(("no vmmdev\n")); + return VERR_INVALID_STATE; + } + + Assert(mhCrOglSvc); + VBOXHGCMSVCPARM parm; + parm.type = VBOX_HGCM_SVC_PARM_PTR; + parm.u.pointer.addr = pCmd; + parm.u.pointer.size = cbCmd; + + pCmd->pfnInternal = (void(*)())pfnCompletion; + int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, displayCrHgcmCtlSubmitCompletion, pvCompletion); + if (!RT_SUCCESS(rc)) + AssertMsgFailed(("hgcmHostFastCallAsync failed rc %n", rc)); + + return rc; +} + +DECLCALLBACK(int) Display::displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface, + struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, + PFNCRCTLCOMPLETION pfnCompletion, + void *pvCompletion) +{ + PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface); + Display *pThis = pDrv->pDisplay; + return pThis->handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion); +} + +#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) +DECLCALLBACK(void) Display::displayCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + Display *pDisplay = (Display *)pvContext; + pDisplay->handleCrAsyncCmdCompletion(result, u32Function, pParam); +} + + +void Display::handleCrAsyncCmdCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam) +{ + if (pParam->type == VBOX_HGCM_SVC_PARM_PTR && pParam->u.pointer.addr) + RTMemFree(pParam->u.pointer.addr); +} + +bool Display::handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64TimeStamp) +{ +# if VBOX_WITH_VPX + return VideoRecIsReady(mpVideoRecCtx, uScreen, u64TimeStamp); +# else + return false; +# endif +} + +void Display::handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64TimeStamp) +{ +} + +void Display::handleCrVRecScreenshotPerform(uint32_t uScreen, + uint32_t x, uint32_t y, uint32_t uPixelFormat, + uint32_t uBitsPerPixel, uint32_t uBytesPerLine, + uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp) +{ + Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED); +# if VBOX_WITH_VPX + int rc = VideoRecCopyToIntBuf(mpVideoRecCtx, uScreen, x, y, + uPixelFormat, + uBitsPerPixel, uBytesPerLine, + uGuestWidth, uGuestHeight, + pu8BufferAddress, u64TimeStamp); + Assert(rc == VINF_SUCCESS /* || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN*/); +# endif +} + +void Display::handleVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED); + ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE); +} + +DECLCALLBACK(void) Display::displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen, + uint32_t x, uint32_t y, + uint32_t uBitsPerPixel, uint32_t uBytesPerLine, + uint32_t uGuestWidth, uint32_t uGuestHeight, + uint8_t *pu8BufferAddress, uint64_t u64TimeStamp) +{ + Display *pDisplay = (Display *)pvCtx; + pDisplay->handleCrVRecScreenshotPerform(uScreen, + x, y, FramebufferPixelFormat_FOURCC_RGB, uBitsPerPixel, + uBytesPerLine, uGuestWidth, uGuestHeight, + pu8BufferAddress, u64TimeStamp); +} + +DECLCALLBACK(bool) Display::displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp) +{ + Display *pDisplay = (Display *)pvCtx; + return pDisplay->handleCrVRecScreenshotBegin(uScreen, u64TimeStamp); +} + +DECLCALLBACK(void) Display::displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp) +{ + Display *pDisplay = (Display *)pvCtx; + pDisplay->handleCrVRecScreenshotEnd(uScreen, u64TimeStamp); +} + +DECLCALLBACK(void) Display::displayVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext) +{ + Display *pDisplay = (Display *)pvContext; + pDisplay->handleVRecCompletion(result, u32Function, pParam, pvContext); +} + +#endif + #ifdef VBOX_WITH_HGSMI DECLCALLBACK(int) Display::displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags) @@ -3868,7 +4625,7 @@ DECLCALLBACK(void) Display::displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInte pDrv->pUpPort->pfnUpdateDisplayRect (pDrv->pUpPort, pCmd->x, pCmd->y, pCmd->w, pCmd->h); } else if ( !pFBInfo->pFramebuffer.isNull() - && !(pFBInfo->fDisabled)) + && !pFBInfo->fDisabled) { /* Render VRAM content to the framebuffer. */ BYTE *address = NULL; @@ -3916,7 +4673,7 @@ DECLCALLBACK(void) Display::displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInte pHdrUnconst->y -= (int16_t)pFBInfo->yOrigin; /* @todo new SendUpdate entry which can get a separate cmd header or coords. */ - pThis->mParent->consoleVRDPServer()->SendUpdate (uScreenId, pCmd, cbCmd); + pThis->mParent->consoleVRDPServer()->SendUpdate (uScreenId, pCmd, (uint32_t)cbCmd); *pHdrUnconst = hdrSaved; } @@ -4078,14 +4835,18 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED) { + pThis->notifyCroglResize(pView, pScreen, pvVRAM); + pFBInfo->fDisabled = true; pFBInfo->flags = pScreen->u16Flags; - /* Temporary: ask framebuffer to resize using a default format. The framebuffer will be black. */ - pThis->handleDisplayResize(pScreen->u32ViewIndex, 0, - (uint8_t *)NULL, - pScreen->u32LineSize, pScreen->u32Width, - pScreen->u32Height, pScreen->u16Flags); + /* Ask the framebuffer to resize using a default format. The framebuffer will be black. + * So if the frontend does not support GuestMonitorChangedEventType_Disabled event, + * the VM window will be black. */ + uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640; + uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480; + pThis->handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0, + u32Width, u32Height, pScreen->u16Flags); fireGuestMonitorChangedEvent(pThis->mParent->getEventSource(), GuestMonitorChangedEventType_Disabled, @@ -4099,17 +4860,6 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c */ bool fResize = pFBInfo->fDisabled || pFBInfo->pFramebuffer.isNull(); - if (pFBInfo->fDisabled) - { - pFBInfo->fDisabled = false; - fireGuestMonitorChangedEvent(pThis->mParent->getEventSource(), - GuestMonitorChangedEventType_Enabled, - pScreen->u32ViewIndex, - pScreen->i32OriginX, pScreen->i32OriginY, - pScreen->u32Width, pScreen->u32Height); - /* Continue to update pFBInfo. */ - } - /* Check if this is a real resize or a notification about the screen origin. * The guest uses this VBVAResize call for both. */ @@ -4123,6 +4873,20 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c bool fNewOrigin = pFBInfo->xOrigin != pScreen->i32OriginX || pFBInfo->yOrigin != pScreen->i32OriginY; + if (fNewOrigin || fResize) + pThis->notifyCroglResize(pView, pScreen, pvVRAM); + + if (pFBInfo->fDisabled) + { + pFBInfo->fDisabled = false; + fireGuestMonitorChangedEvent(pThis->mParent->getEventSource(), + GuestMonitorChangedEventType_Enabled, + pScreen->u32ViewIndex, + pScreen->i32OriginX, pScreen->i32OriginY, + pScreen->u32Width, pScreen->u32Height); + /* Continue to update pFBInfo. */ + } + pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */ pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */ pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */ @@ -4148,34 +4912,13 @@ DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, c 0, 0); } -#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) - if (fNewOrigin && !fResize) - { - BOOL is3denabled; - pThis->mParent->machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled); - - if (is3denabled) - { - VBOXHGCMSVCPARM parm; - - parm.type = VBOX_HGCM_SVC_PARM_32BIT; - parm.u.uint32 = pScreen->u32ViewIndex; - - VMMDev *pVMMDev = pThis->mParent->getVMMDev(); - - if (pVMMDev) - pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm); - } - } -#endif /* VBOX_WITH_CROGL */ - if (!fResize) { /* No parameters of the framebuffer have actually changed. */ if (fNewOrigin) { /* VRDP server still need this notification. */ - LogRelFlowFunc (("Calling VRDP\n")); + LogRelFlowFunc(("Calling VRDP\n")); pThis->mParent->consoleVRDPServer()->SendResize(); } return VINF_SUCCESS; @@ -4244,23 +4987,26 @@ DECLCALLBACK(void *) Display::drvQueryInterface(PPDMIBASE pInterface, const cha */ DECLCALLBACK(void) Display::drvDestruct(PPDMDRVINS pDrvIns) { - PDRVMAINDISPLAY pData = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); - LogRelFlowFunc (("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); + PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); + LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); - if (pData->pDisplay) + if (pThis->pDisplay) { - AutoWriteLock displayLock(pData->pDisplay COMMA_LOCKVAL_SRC_POS); + AutoWriteLock displayLock(pThis->pDisplay COMMA_LOCKVAL_SRC_POS); +#ifdef VBOX_WITH_VPX + pThis->pDisplay->VideoCaptureStop(); +#endif #ifdef VBOX_WITH_CRHGSMI - pData->pDisplay->destructCrHgsmiData(); + pThis->pDisplay->destructCrHgsmiData(); #endif - pData->pDisplay->mpDrv = NULL; - pData->pDisplay->mpVMMDev = NULL; - pData->pDisplay->mLastAddress = NULL; - pData->pDisplay->mLastBytesPerLine = 0; - pData->pDisplay->mLastBitsPerPixel = 0, - pData->pDisplay->mLastWidth = 0; - pData->pDisplay->mLastHeight = 0; + pThis->pDisplay->mpDrv = NULL; + pThis->pDisplay->mpVMMDev = NULL; + pThis->pDisplay->mLastAddress = NULL; + pThis->pDisplay->mLastBytesPerLine = 0; + pThis->pDisplay->mLastBitsPerPixel = 0, + pThis->pDisplay->mLastWidth = 0; + pThis->pDisplay->mLastHeight = 0; } } @@ -4272,9 +5018,9 @@ DECLCALLBACK(void) Display::drvDestruct(PPDMDRVINS pDrvIns) */ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { - PDRVMAINDISPLAY pData = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); - LogRelFlowFunc (("iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); + LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance)); /* * Validate configuration. @@ -4288,44 +5034,45 @@ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint /* * Init Interfaces. */ - pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface; - - pData->IConnector.pfnResize = Display::displayResizeCallback; - pData->IConnector.pfnUpdateRect = Display::displayUpdateCallback; - pData->IConnector.pfnRefresh = Display::displayRefreshCallback; - pData->IConnector.pfnReset = Display::displayResetCallback; - pData->IConnector.pfnLFBModeChange = Display::displayLFBModeChangeCallback; - pData->IConnector.pfnProcessAdapterData = Display::displayProcessAdapterDataCallback; - pData->IConnector.pfnProcessDisplayData = Display::displayProcessDisplayDataCallback; + pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface; + + pThis->IConnector.pfnResize = Display::displayResizeCallback; + pThis->IConnector.pfnUpdateRect = Display::displayUpdateCallback; + pThis->IConnector.pfnRefresh = Display::displayRefreshCallback; + pThis->IConnector.pfnReset = Display::displayResetCallback; + pThis->IConnector.pfnLFBModeChange = Display::displayLFBModeChangeCallback; + pThis->IConnector.pfnProcessAdapterData = Display::displayProcessAdapterDataCallback; + pThis->IConnector.pfnProcessDisplayData = Display::displayProcessDisplayDataCallback; #ifdef VBOX_WITH_VIDEOHWACCEL - pData->IConnector.pfnVHWACommandProcess = Display::displayVHWACommandProcess; + pThis->IConnector.pfnVHWACommandProcess = Display::displayVHWACommandProcess; #endif #ifdef VBOX_WITH_CRHGSMI - pData->IConnector.pfnCrHgsmiCommandProcess = Display::displayCrHgsmiCommandProcess; - pData->IConnector.pfnCrHgsmiControlProcess = Display::displayCrHgsmiControlProcess; + pThis->IConnector.pfnCrHgsmiCommandProcess = Display::displayCrHgsmiCommandProcess; + pThis->IConnector.pfnCrHgsmiControlProcess = Display::displayCrHgsmiControlProcess; #endif + pThis->IConnector.pfnCrHgcmCtlSubmit = Display::displayCrHgcmCtlSubmit; #ifdef VBOX_WITH_HGSMI - pData->IConnector.pfnVBVAEnable = Display::displayVBVAEnable; - pData->IConnector.pfnVBVADisable = Display::displayVBVADisable; - pData->IConnector.pfnVBVAUpdateBegin = Display::displayVBVAUpdateBegin; - pData->IConnector.pfnVBVAUpdateProcess = Display::displayVBVAUpdateProcess; - pData->IConnector.pfnVBVAUpdateEnd = Display::displayVBVAUpdateEnd; - pData->IConnector.pfnVBVAResize = Display::displayVBVAResize; - pData->IConnector.pfnVBVAMousePointerShape = Display::displayVBVAMousePointerShape; + pThis->IConnector.pfnVBVAEnable = Display::displayVBVAEnable; + pThis->IConnector.pfnVBVADisable = Display::displayVBVADisable; + pThis->IConnector.pfnVBVAUpdateBegin = Display::displayVBVAUpdateBegin; + pThis->IConnector.pfnVBVAUpdateProcess = Display::displayVBVAUpdateProcess; + pThis->IConnector.pfnVBVAUpdateEnd = Display::displayVBVAUpdateEnd; + pThis->IConnector.pfnVBVAResize = Display::displayVBVAResize; + pThis->IConnector.pfnVBVAMousePointerShape = Display::displayVBVAMousePointerShape; #endif /* * Get the IDisplayPort interface of the above driver/device. */ - pData->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT); - if (!pData->pUpPort) + pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT); + if (!pThis->pUpPort) { AssertMsgFailed(("Configuration error: No display port interface above!\n")); return VERR_PDM_MISSING_INTERFACE_ABOVE; } #if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI) - pData->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS); - if (!pData->pVBVACallbacks) + pThis->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS); + if (!pThis->pVBVACallbacks) { AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n")); return VERR_PDM_MISSING_INTERFACE_ABOVE; @@ -4341,24 +5088,36 @@ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc)); return rc; } - pData->pDisplay = (Display *)pv; /** @todo Check this cast! */ - pData->pDisplay->mpDrv = pData; - + Display *pDisplay = (Display *)pv; /** @todo Check this cast! */ + pThis->pDisplay = pDisplay; + pThis->pDisplay->mpDrv = pThis; /* * Update our display information according to the framebuffer */ - pData->pDisplay->updateDisplayData(); + pDisplay->updateDisplayData(); /* * Start periodic screen refreshes */ - pData->pUpPort->pfnSetRefreshRate(pData->pUpPort, 20); + pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20); #ifdef VBOX_WITH_CRHGSMI - pData->pDisplay->setupCrHgsmiData(); + pDisplay->setupCrHgsmiData(); #endif - return VINF_SUCCESS; +#ifdef VBOX_WITH_VPX + ComPtr<IMachine> pMachine = pDisplay->mParent->machine(); + BOOL fEnabled = false; + HRESULT hrc = pMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled); + AssertComRCReturn(hrc, VERR_COM_UNEXPECTED); + if (fEnabled) + { + rc = pDisplay->VideoCaptureStart(); + fireVideoCaptureChangedEvent(pDisplay->mParent->getEventSource()); + } +#endif + + return rc; } |