DisplayImpl.cpp revision 27152389a84c6dec057fba6fc21241991e079006
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox COM class implementation
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Copyright (C) 2006-2010 Oracle Corporation
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * available from http://www.virtualbox.org. This file is free software;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * General Public License (GPL) as published by the Free Software
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
#ifdef VBOX_WITH_VIDEOHWACCEL
#ifdef VBOX_WITH_CROGL
typedef struct DRVMAINDISPLAY
#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector)
#ifdef DEBUG_sunlover
static int stam = 0;
mfVideoAccelEnabled = false;
mfVideoAccelVRDP = false;
mfu32SupportedOrders = 0;
mcVideoAccelVRDPRefs = 0;
mfPendingVideoAccelEnable = false;
mfMachineRunning = false;
mcbVbvaPartial = 0;
mfVMMDevInited = false;
mLastBytesPerLine = 0;
mLastBitsPerPixel = 0,
mLastWidth = 0;
mLastHeight = 0;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
mfu32PendingVideoAccelDisable = false;
#ifdef VBOX_WITH_HGSMI
mu32UpdateVBVAFlags = 0;
return S_OK;
uninit();
#ifdef VBOX_WITH_OLD_VBVA_LOCK
// public initializer/uninitializer for internal purposes only
if (pu8Thumbnail)
src,
return rc;
DECLCALLBACK(void)
#ifdef VBOX_WITH_OLD_VBVA_LOCK
int rc = Display::displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy);
int rc = that->mpDrv->pUpPort->pfnTakeScreenshot (that->mpDrv->pUpPort, &pu8Data, &cbData, &cx, &cy);
if (cbThumbnail)
if (cbPNG)
DECLCALLBACK(int)
return rc;
DECLCALLBACK(void)
DECLCALLBACK(int)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Number of monitors changed (%d->%d)!"), cMonitors, that->mcMonitors);
uint32_t w;
uint32_t h;
return VINF_SUCCESS;
mFramebufferOpened = false;
#ifdef VBOX_WITH_HGSMI
return S_OK;
if (mParent)
if (mpDrv)
mfVMMDevInited = true;
/* 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*/,
return VINF_SUCCESS;
switch (aType)
mfMachineRunning = true;
mfMachineRunning = false;
AssertFailed();
return S_OK;
if (!finished)
return VINF_VGA_RESIZE_IN_PROGRESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
mLastWidth = w;
mLastHeight = h;
switch (bpp)
return VINF_VGA_RESIZE_IN_PROGRESS;
return rc;
return VINF_SUCCESS;
unsigned uScreenId;
bool f = ASMAtomicCmpXchgU32 (&pFBInfo->u32ResizeStatus, ResizeStatus_Void, ResizeStatus_UpdateDisplayData);
#ifdef DEBUG_sunlover
if (!stam)
STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates.");
if (is3denabled)
if (pVMMDev)
pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm);
if (*px < 0)
*px = 0;
if (*py < 0)
*py = 0;
unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph)
unsigned uScreenId;
LogSunlover ((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h));
uScreenId = 0;
return uScreenId;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
#ifdef DEBUG_sunlover
#ifdef DEBUG_sunlover
#ifndef VBOX_WITH_HGSMI
if (!mfVideoAccelEnabled)
#ifdef MMSEAMLESS
if (!pVisibleRegion)
return VERR_NO_TMP_MEMORY;
unsigned uScreenId;
if (mpDrv)
uint32_t i;
for (i = 0; i < cRect; i++)
if (cRectVisibleRegion > 0)
return VINF_SUCCESS;
return VERR_NOT_SUPPORTED;
typedef struct _VBVADIRTYREGION
unsigned cMonitors;
static void vbvaRgnInit (VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, unsigned cMonitors, Display *pd, PPDMIDISPLAYPORT pp)
unsigned uScreenId;
prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, pFBInfo->dirtyRect.xLeft, pFBInfo->dirtyRect.yTop, w, h);
bool fVideoAccelEnabled,
bool fVideoAccelVRDP,
unsigned cFBInfos)
if (pVbvaMemory)
if (fVideoAccelEnabled)
if (fVideoAccelVRDP)
unsigned uScreenId;
#ifdef VBOX_WITH_HGSMI
bool fVideoAccelVRDP,
if (fVideoAccelVRDP)
LogFlowFunc((" fu32HostEvents = 0x%08X, fu32SupportedOrders = 0x%08X\n", fu32HostEvents, fu32SupportedOrders));
bool fVideoAccelVRDP,
unsigned cFBInfos)
unsigned uScreenId;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
#ifdef VBOX_WITH_OLD_VBVA_LOCK
int rc;
vbvaLock();
vbvaUnlock();
return rc;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
if (!VideoAccelAllowed ())
return VERR_NOT_SUPPORTED;
if (!mfMachineRunning)
if (fEnable)
return rc;
return rc;
if (mfVideoAccelEnabled)
#ifdef VBOX_WITH_OLD_VBVA_LOCK
videoAccelFlush ();
VideoAccelFlush ();
mfVideoAccelEnabled = false;
if (pVMMDev)
if (pVMMDevPort)
if (fEnable)
mfVideoAccelEnabled = true;
vbvaSetMemoryFlags(mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
#ifdef VBOX_WITH_OLD_VBVA_LOCK
mfu32PendingVideoAccelDisable = false;
return rc;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
vbvaLock();
int c = fEnable?
Assert (c >= 0);
mfVideoAccelVRDP = false;
mfu32SupportedOrders = 0;
vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
#ifdef VBOX_WITH_HGSMI
&& !mfVideoAccelVRDP)
mfVideoAccelVRDP = true;
mfu32SupportedOrders = ~0;
vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
#ifdef VBOX_WITH_HGSMI
#ifdef VBOX_WITH_OLD_VBVA_LOCK
vbvaUnlock();
if (i32Diff <= 0)
static bool vbvaPartialRead (uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)
if (*ppu8)
if (!pu8New)
cbRecord));
if (*ppu8)
*pcb = 0;
#ifdef DEBUG_sunlover
#ifdef DEBUG_sunlover
if (mcbVbvaPartial)
LogFlowFunc (("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",
mcbVbvaPartial = 0;
#ifdef DEBUG_sunlover
LogFlowFunc (("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
if (cbRecord)
if (!dst)
#ifdef DEBUG_sunlover
#ifdef DEBUG_sunlover
#ifdef DEBUG_sunlover
mcbVbvaPartial = 0;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
vbvaLock();
vbvaUnlock();
#ifdef VBOX_WITH_OLD_VBVA_LOCK
#ifdef DEBUG_sunlover_2
if (!mfVideoAccelEnabled)
#ifdef DEBUG_sunlover_2
mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree, mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
unsigned uScreenId;
#ifndef VBOX_WITH_OLD_VBVA_LOCK
Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",
#ifdef VBOX_WITH_OLD_VBVA_LOCK
if (cbCmd != 0)
#ifdef DEBUG_sunlover
int x = phdr->x;
int y = phdr->y;
int w = phdr->w;
int h = phdr->h;
#ifndef VBOX_WITH_OLD_VBVA_LOCK
#ifdef VBOX_WITH_OLD_VBVA_LOCK
vbvaLock();
else if (mfPendingVideoAccelEnable)
if (mfMachineRunning)
mfPendingVideoAccelEnable = false;
if (mfVideoAccelEnabled)
videoAccelFlush ();
vbvaUnlock();
return rc;
return E_INVALIDARG;
if (aWidth)
if (aHeight)
if (aBitsPerPixel)
return S_OK;
if (is3denabled)
if (pVMMDev)
vrc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm);
return S_OK;
return E_INVALIDARG;
if (*aFramebuffer)
if (aXOrigin)
if (aYOrigin)
return S_OK;
if (!width)
if (!height)
if (!bpp)
return E_INVALIDARG;
return E_INVALIDARG;
if (pVMMDev)
if (pVMMDevPort)
return S_OK;
if (pVMMDev)
if (pVMMDevPort)
return S_OK;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
int Display::displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height)
int rc;
rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, ppu8Data, pcbData, pu32Width, pu32Height);
if (cbRequired)
*pcbData = 0;
*pu32Width = 0;
*pu32Height = 0;
return rc;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
static int displayTakeScreenshot(PVM pVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId, BYTE *address, ULONG width, ULONG height)
static int displayTakeScreenshot(PVM pVM, struct DRVMAINDISPLAY *pDrv, BYTE *address, ULONG width, ULONG height)
#ifdef VBOX_WITH_OLD_VBVA_LOCK
while (cRetries-- > 0)
/* @todo pfnTakeScreenshot is probably callable from any thread, because it uses the VGA device lock. */
src,
return vrc;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
return rc;
if (!pu8Data)
return E_OUTOFMEMORY;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
while (cPixels)
cPixels--;
return rc;
if (!pu8Data)
return E_OUTOFMEMORY;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
return rc;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
int Display::drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height)
int rc;
rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height);
xSrc = x;
ySrc = y;
return rc;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
return rc;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
unsigned uScreenId;
/* pdm.h says that this has to be called from the EMT thread */
#ifdef VBOX_WITH_OLD_VBVA_LOCK
return rc;
return S_OK;
#ifdef VBOX_WITH_VIDEOHWACCEL
return S_OK;
return E_NOTIMPL;
if (!mpDrv)
#if DEBUG
if (pFramebuffer)
#ifdef VBOX_WITH_CRHGSMI
if (pVMMDev)
unsigned uScreenId)
pFBInfo->w,
pFBInfo->h);
return VINF_SUCCESS;
#ifdef DEBUG_sunlover
#ifdef DEBUG_sunlover
#ifdef DEBUG_sunlover_2
bool fNoUpdate = false; /* Do not update the display if any of the framebuffers is being resized. */
unsigned uScreenId;
#ifdef VBOX_WITH_OLD_VBVA_LOCK
#ifdef VBOX_WITH_OLD_VBVA_LOCK
fNoUpdate = true;
if (!fNoUpdate)
#ifdef VBOX_WITH_OLD_VBVA_LOCK
#ifdef DEBUG_sunlover
#ifdef DEBUG_sunlover_2
DECLCALLBACK(void) Display::displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
#ifdef VBOX_WITH_OLD_VBVA_LOCK
DECLCALLBACK(void) Display::displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, uint32_t u32VRAMSize)
#ifndef VBOX_WITH_HGSMI
LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "DISPLAY", pHdr->u16Length));
LogFlow(("VBOX_VIDEO_INFO_TYPE_DISPLAY: %d: at 0x%08X, size 0x%08X, info 0x%08X\n", pDisplay->u32Index, pDisplay->u32Offset, pDisplay->u32FramebufferSize, pDisplay->u32InformationSize));
LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "CONF32", pHdr->u16Length));
else if (pHdr->u8Type != VBOX_VIDEO_INFO_TYPE_NV_HEAP) /** @todo why is Additions/WINNT/Graphics/Miniport/VBoxVideo.cpp pushing this to us? */
LogRel(("Guest adapter information contains unsupported type %d. The block has been skipped.\n", pHdr->u8Type));
DECLCALLBACK(void) Display::displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId)
LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "SCREEN", pHdr->u16Length));
LogFlow(("VBOX_VIDEO_INFO_TYPE_SCREEN: (%p) %d: at %d,%d, linesize 0x%X, size %dx%d, bpp %d, flags 0x%02X\n",
pHdr, uScreenId, pScreen->xOrigin, pScreen->yOrigin, pScreen->u32LineSize, pScreen->u16Width, pScreen->u16Height, pScreen->bitsPerPixel, pScreen->u8Flags));
pDrv->pDisplay->handleDisplayResize(uScreenId, pScreen->bitsPerPixel, (uint8_t *)pvVRAM + pFBInfo->u32Offset, pScreen->u32LineSize, pScreen->u16Width, pScreen->u16Height);
LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "HOST_EVENTS", pHdr->u16Length));
pHostEvents));
LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "LINK", pHdr->u16Length));
#ifdef VBOX_WITH_VIDEOHWACCEL
#ifdef DEBUG_misha
DECLCALLBACK(void) Display::displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
#ifdef VBOX_WITH_CRHGSMI
void Display::handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVDMACMD_CHROMIUM_CMD)pParam->u.pointer.addr, result);
void Display::handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr, result);
void Display::handleCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd)
if (mhCrOglSvc)
if (pVMMDev)
rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm, Display::displayCrHgsmiCommandCompletion, this);
void Display::handleCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl)
if (mhCrOglSvc)
if (pVMMDev)
rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm, Display::displayCrHgsmiControlCompletion, this);
DECLCALLBACK(void) Display::displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd)
DECLCALLBACK(void) Display::displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd)
DECLCALLBACK(void) Display::displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext)
DECLCALLBACK(void) Display::displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext)
#ifdef VBOX_WITH_HGSMI
DECLCALLBACK(int) Display::displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags)
vbvaSetMemoryFlagsHGSMI(uScreenId, pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, &pThis->maFramebuffers[uScreenId]);
return VINF_SUCCESS;
DECLCALLBACK(void) Display::displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
pFBInfo->w = 0;
pFBInfo->h = 0;
DECLCALLBACK(void) Display::displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
vbvaSetMemoryFlagsAllHGSMI(pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, pThis->maFramebuffers, pThis->mcMonitors);
DECLCALLBACK(void) Display::displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, const PVBVACMDHDR pCmd, size_t cbCmd)
LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d, @%d,%d %dx%d\n", uScreenId, pCmd, cbCmd, pCmd->x, pCmd->y, pCmd->w, pCmd->h));
DECLCALLBACK(void) Display::displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y, uint32_t cx, uint32_t cy)
DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM)
if (fNewOrigin)
/* @todo May be framebuffer/display should be notified in this case. */
if (is3denabled)
if (pVMMDev)
pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SCREEN_CHANGED, SHCRGL_CPARMS_SCREEN_CHANGED, &parm);
if (!fResize)
if (fNewOrigin)
return VINF_SUCCESS;
DECLCALLBACK(int) Display::displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
const void *pvShape)
if (pvShape)
if (pvShape)
return VINF_SUCCESS;
return NULL;
#ifdef VBOX_WITH_CRHGSMI
#ifdef VBOX_WITH_VIDEOHWACCEL
#ifdef VBOX_WITH_CRHGSMI
#ifdef VBOX_WITH_HGSMI
return VERR_PDM_MISSING_INTERFACE_ABOVE;
return VERR_PDM_MISSING_INTERFACE_ABOVE;
void *pv;
return rc;
#ifdef VBOX_WITH_CRHGSMI
return VINF_SUCCESS;
sizeof(DRVMAINDISPLAY),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,