DisplayImpl.cpp revision a60aa561f1dd9095f0838463d71f644aedd06606
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * VirtualBox COM class implementation
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2010 Oracle Corporation
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * available from http://www.virtualbox.org. This file is free software;
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync * Display driver instance data.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @implements PDMIDISPLAYCONNECTOR
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync /** Pointer to the display object. */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync /** Pointer to the driver instance structure. */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync /** Pointer to the keyboard port interface of the driver/device above us. */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync /** Our display connector interface. */
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync /** VBVA callbacks */
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector)
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsyncstatic int stam = 0;
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync#endif /* DEBUG_sunlover */
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync// constructor / destructor
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync/////////////////////////////////////////////////////////////////////////////
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#endif /* VBOX_WITH_OLD_VBVA_LOCK */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#endif /* VBOX_WITH_OLD_VBVA_LOCK */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync// public initializer/uninitializer for internal purposes only
a9981806c72edadef6cccd253f4747c35677e9a1vboxsync/////////////////////////////////////////////////////////////////////////////
a9981806c72edadef6cccd253f4747c35677e9a1vboxsync * Save thumbnail and screenshot of the guest screen.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsyncstatic int displayMakeThumbnail(uint8_t *pu8Data, uint32_t cx, uint32_t cy,
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync uint8_t **ppu8Thumbnail, uint32_t *pcbThumbnail, uint32_t *pcxThumbnail, uint32_t *pcyThumbnail)
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync LogFlowFunc(("%dx%d -> %dx%d\n", cx, cy, cxThumbnail, cyThumbnail));
src,
return rc;
typedef struct PNGWriteCtx
int rc;
} PNGWriteCtx;
if (!pNew)
if (pu8Bitmap)
src,
if (row_pointers)
if (png_ptr)
if (info_ptr)
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);
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 (*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 (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_VRDP
#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)
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;
return S_OK;
!!enabled);
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--;
for (unsigned i = 0; i < cbData; i++)
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)
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_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 (!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_VIDEOHWACCEL
#ifdef VBOX_WITH_HGSMI
return VERR_PDM_MISSING_INTERFACE_ABOVE;
#if defined(VBOX_WITH_VIDEOHWACCEL)
return VERR_PDM_MISSING_INTERFACE_ABOVE;
void *pv;
return rc;
return VINF_SUCCESS;
sizeof(DRVMAINDISPLAY),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,