DisplayImpl.cpp revision d3d163b305d19a30d16dbea3647d09bbcd2462cf
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * VirtualBox COM class implementation
d6aa6429f99fb7648883eb612f8a52b9aaf3bff4vboxsync * Copyright (C) 2006-2010 Sun Microsystems, Inc.
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * available from http://www.virtualbox.org. This file is free software;
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * General Public License (GPL) as published by the Free Software
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync * additional information or have any questions.
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * Display driver instance data.
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * @implements PDMIDISPLAYCONNECTOR
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync /** Pointer to the display object. */
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync /** Pointer to the driver instance structure. */
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync /** Pointer to the keyboard port interface of the driver/device above us. */
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync /** Our display connector interface. */
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync /** VBVA callbacks */
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector)
b0dfb334954c0552bb583967a3077ec88fd00471vboxsyncstatic int stam = 0;
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync#endif /* DEBUG_sunlover */
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync// constructor / destructor
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync/////////////////////////////////////////////////////////////////////////////
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsync#endif /* VBOX_WITH_OLD_VBVA_LOCK */
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync#endif /* VBOX_WITH_OLD_VBVA_LOCK */
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync// public initializer/uninitializer for internal purposes only
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync/////////////////////////////////////////////////////////////////////////////
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * Save thumbnail and screenshot of the guest screen.
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsyncstatic int displayMakeThumbnail(uint8_t *pu8Data, uint32_t cx, uint32_t cy,
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync uint8_t **ppu8Thumbnail, uint32_t *pcbThumbnail, uint32_t *pcxThumbnail, uint32_t *pcyThumbnail)
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync LogFlowFunc(("%dx%d -> %dx%d\n", cx, cy, cxThumbnail, cyThumbnail));
2077a9092ce42fb009a3ab89b095ec02af18213evboxsynctypedef struct PNGWriteCtx
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void PNGAPI png_write_data_fn(png_structp png_ptr, png_bytep p, png_size_t cb)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync PNGWriteCtx *pCtx = (PNGWriteCtx *)png_get_io_ptr(png_ptr);
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync LogFlowFunc(("png_ptr %p, p %p, cb %d, pCtx %p\n", png_ptr, p, cb, pCtx));
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync AssertReturnVoidStmt(cbNew > pCtx->cbPNG && cbNew <= _1G, pCtx->rc = VERR_TOO_MUCH_DATA);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void PNGAPI png_output_flush_fn(png_structp png_ptr)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Do nothing. */
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsyncstatic int displayMakePNG(uint8_t *pu8Data, uint32_t cx, uint32_t cy,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint8_t **ppu8PNG, uint32_t *pcbPNG, uint32_t *pcxPNG, uint32_t *pcyPNG)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint8_t * volatile pu8Bitmap = NULL; /* gcc setjmp warning */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint32_t volatile cbBitmap = 0; /* gcc setjmp warning */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint32_t volatile cxBitmap = 0; /* gcc setjmp warning */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint32_t volatile cyBitmap = 0; /* gcc setjmp warning */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Save unscaled screenshot. */
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync /* Large screenshot, scale. */
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;
mfMachineRunning = true;
mfMachineRunning = false;
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)
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;
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
/* @todo pfnTakeScreenshot is probably callable from any thread, because it uses the VGA device lock. */
int dstX = 0;
int dstY = 0;
int srcX = 0;
int srcY = 0;
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);
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)
if (aCheckParams &&
unsigned uScreenId)
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
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)
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)
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)
return VINF_SUCCESS;
DECLCALLBACK(int) Display::displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
const void *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,