DisplayImpl.cpp revision ed13928f815429d20fb211602bc4bedae5593293
/* $Id$ */
/** @file
* VirtualBox COM class implementation
*/
/*
* Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "DisplayImpl.h"
#include "DisplayUtils.h"
#include "ConsoleImpl.h"
#include "ConsoleVRDPServer.h"
#include "GuestImpl.h"
#include "VMMDev.h"
#include "AutoCaller.h"
#include "Logging.h"
/* generated header */
#include "VBoxEvents.h"
#include <iprt/semaphore.h>
#endif
#ifdef VBOX_WITH_VIDEOHWACCEL
# include <VBox/VBoxVideo.h>
#endif
#if defined(VBOX_WITH_CROGL) || defined(VBOX_WITH_CRHGSMI)
#endif
#ifdef VBOX_WITH_VPX
# include "VideoRec.h"
#endif
#ifdef VBOX_WITH_CROGL
typedef enum
{
} CRVREC_STATE;
#endif
/**
* Display driver instance data.
*
* @implements PDMIDISPLAYCONNECTOR
*/
typedef struct DRVMAINDISPLAY
{
/** Pointer to the display object. */
/** Pointer to the driver instance structure. */
/** Our display connector interface. */
#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
/** VBVA callbacks */
#endif
/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector)
// constructor / destructor
/////////////////////////////////////////////////////////////////////////////
{
}
{
}
{
mfVideoAccelVRDP = false;
mfu32SupportedOrders = 0;
mcVideoAccelVRDPRefs = 0;
#ifdef VBOX_WITH_CROGL
mfCrOglDataHidden = false;
#endif
mfVMMDevInited = false;
#ifdef VBOX_WITH_HGSMI
mu32UpdateVBVAFlags = 0;
mfVMMDevSupportsGraphics = false;
#endif
#ifdef VBOX_WITH_VPX
for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
maVideoRecEnabled[i] = true;
#endif
#ifdef VBOX_WITH_CRHGSMI
mhCrOglSvc = NULL;
#endif
#ifdef VBOX_WITH_CROGL
mCrOglScreenshotData.pvContext = this;
#endif
return BaseFinalConstruct();
}
void Display::FinalRelease()
{
uninit();
{
}
#ifdef VBOX_WITH_CRHGSMI
if (RTCritSectRwIsInitialized (&mCrOglLock))
{
}
#endif
}
// public initializer/uninitializer for internal purposes only
/////////////////////////////////////////////////////////////////////////////
#define kMaxSizeThumbnail 64
/**
* Save thumbnail and screenshot of the guest screen.
*/
{
int rc = VINF_SUCCESS;
uint32_t cbThumbnail = 0;
uint32_t cxThumbnail = 0;
uint32_t cyThumbnail = 0;
{
}
else
{
}
if (pu8Thumbnail)
{
int dstW = cxThumbnail;
int dstH = cyThumbnail;
src,
}
else
{
rc = VERR_NO_MEMORY;
}
return rc;
}
#ifdef VBOX_WITH_CROGL
typedef struct
{
/* 32bpp small RGB image. */
/* PNG screenshot. */
{
if (RT_FAILURE(rc))
{
{
}
}
}
#endif
{
/* 32bpp small RGB image. */
uint32_t cbThumbnail = 0;
uint32_t cxThumbnail = 0;
uint32_t cyThumbnail = 0;
/* PNG screenshot. */
{
/* Query RGB bitmap. */
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if ( that->mfIsCr3DEnabled
{
if (pVMMDev)
{
if (pScreenshot)
{
/* screen id or CRSCREEN_ALL to specify all enabled */
if (RT_SUCCESS(rc))
{
if (pScreenshot->pu8PNG)
{
/* PNG screenshot. */
f3DSnapshot = TRUE;
}
else
AssertMsgFailed(("no png\n"));
}
else
}
}
}
if (!f3DSnapshot)
#endif
{
/* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */
int rc = Display::i_displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy);
/*
* 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)
*/
{
/* Prepare a small thumbnail and a PNG screenshot. */
if (RT_FAILURE(rc))
{
if (pu8PNG)
{
}
cbPNG = 0;
cxPNG = 0;
cyPNG = 0;
}
/* This can be called from any thread. */
}
}
}
else
{
}
/* Regardless of rc, save what is available:
* Data format:
* uint32_t cBlocks;
* [blocks]
*
* Each block is:
* uint32_t cbBlock; if 0 - no 'block data'.
* uint32_t typeOfBlock; 0 - 32bpp RGB bitmap, 1 - PNG, ignored if 'cbBlock' is 0.
* [block data]
*
* Block data for bitmap and PNG:
* uint32_t cx;
* uint32_t cy;
* [image data]
*/
/* First block. */
if (cbThumbnail)
{
}
/* Second block. */
if (cbPNG)
{
}
}
DECLCALLBACK(int)
Display::i_displaySSMLoadScreenshot(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass)
{
if (uVersion != sSSMDisplayScreenshotVer)
/* Skip data. */
{
/* Note: displaySSMSaveScreenshot writes size of a block = 8 and
* do not write any data if the image size was 0.
* @todo Fix and increase saved state version.
*/
{
}
}
return rc;
}
/**
*/
DECLCALLBACK(void)
{
for (unsigned i = 0; i < that->mcMonitors; i++)
{
}
}
DECLCALLBACK(int)
{
if ( uVersion != sSSMDisplayVer
&& uVersion != sSSMDisplayVer2
&& uVersion != sSSMDisplayVer3
&& uVersion != sSSMDisplayVer4
&& uVersion != sSSMDisplayVer5)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Number of monitors changed (%d->%d)!"), cMonitors, that->mcMonitors);
{
if ( uVersion == sSSMDisplayVer2
|| uVersion == sSSMDisplayVer3
|| uVersion == sSSMDisplayVer4
|| uVersion == sSSMDisplayVer5)
{
uint32_t w;
uint32_t h;
SSMR3GetU32(pSSM, &w);
SSMR3GetU32(pSSM, &h);
that->maFramebuffers[i].w = w;
that->maFramebuffers[i].h = h;
}
if ( uVersion == sSSMDisplayVer3
|| uVersion == sSSMDisplayVer4
|| uVersion == sSSMDisplayVer5)
{
}
}
if ( uVersion == sSSMDisplayVer4
|| uVersion == sSSMDisplayVer5)
{
}
if (uVersion == sSSMDisplayVer5)
{
}
return VINF_SUCCESS;
}
/**
* Initializes the display object.
*
* @returns COM result indicator
* @param parent handle of our parent object
* @param qemuConsoleData address of common console data structure
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
mfSourceBitmapEnabled = true;
fVGAResizing = false;
mcMonitors = ul;
xInputMappingOrigin = 0;
yInputMappingOrigin = 0;
cxInputMapping = 0;
cyInputMapping = 0;
{
/* All secondary monitors are disabled at startup. */
maFramebuffers[ul].w = 0;
maFramebuffers[ul].h = 0;
#ifdef VBOX_WITH_HGSMI
#endif /* VBOX_WITH_HGSMI */
#ifdef VBOX_WITH_CROGL
#endif
}
{
// register listener for state change events
}
/* Cache the 3D settings. */
/* Confirm a successful initialization */
return S_OK;
}
/**
* Uninitializes the instance and sets the ready flag to FALSE.
* Called either from FinalRelease() or by the parent when it gets destroyed.
*/
{
LogRelFlowFunc(("this=%p\n", this));
/* Enclose the state transition Ready->InUninit->NotReady */
AutoUninitSpan autoUninitSpan(this);
if (autoUninitSpan.uninitDone())
return;
unsigned uScreenId;
{
}
if (mParent)
{
es->UnregisterListener(this);
}
if (mpDrv)
mfVMMDevInited = true;
}
/**
* Register the SSM methods. Called by the power up thread to be able to
* pass pVM
*/
{
/* Version 2 adds width and height of the framebuffer; version 3 adds
* the framebuffer offset in the virtual desktop and the framebuffer flags;
* version 4 adds guest to host input event mapping and version 5 adds
* guest VBVA and host cursor capabilities.
*/
/*
* Register loaders for old saved states where iInstance was
* 3 * sizeof(uint32_t *) due to a code mistake.
*/
/* uInstance is an arbitrary value greater than 1024. Such a value will ensure a quick seek in saved state file. */
rc = SSMR3RegisterExternal(pUVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/,
return VINF_SUCCESS;
}
DECLCALLBACK(void) Display::i_displayCrCmdFree(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
{
}
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
{
if (!mfCrOglDataHidden == !!fShow)
return VINF_SUCCESS;
if (!mhCrOglSvc)
{
/* No 3D or the VMSVGA3d kind. */
return VERR_INVALID_STATE;
}
if (!pVMMDev)
{
AssertMsgFailed(("no vmmdev\n"));
return VERR_INVALID_STATE;
}
if (!pData)
{
AssertMsgFailed(("RTMemAlloc failed\n"));
return VERR_NO_MEMORY;
}
if (RT_SUCCESS(rc))
else
{
}
return rc;
}
#endif
// public methods only for internal purposes
/////////////////////////////////////////////////////////////////////////////
int Display::i_notifyCroglResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM)
{
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
return VINF_SUCCESS; /* nop it */
if (mfIsCr3DEnabled)
{
int rc = VERR_INVALID_STATE;
if (mhCrOglSvc)
{
if (pVMMDev)
{
if (pCtl)
{
if (RT_FAILURE(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.
*
* @param w New display width
* @param h New display height
*
* @thread EMT
*/
{
LogRel(("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p "
"w=%d h=%d bpp=%d cbLine=0x%X, flags=0x%X\n",
if (uScreenId >= mcMonitors)
{
return VINF_SUCCESS;
}
/* Reset the update mode. */
if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
pFBInfo->w = w;
pFBInfo->h = h;
}
/* Guest screen image will be invalid during resize, make sure that it is not updated. */
if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
}
{
HRESULT hr = maFramebuffers[uScreenId].pFramebuffer->NotifyChange(uScreenId, 0, 0, w, h); /* @todo origin */
}
{
{
ULONG ulBitsPerPixel = 0;
ULONG ulBytesPerLine = 0;
ULONG ulPixelFormat = 0;
&ulWidth,
&ulHeight,
{
}
}
}
/* Inform the VRDP server about the change of display parameters. */
LogRelFlowFunc(("Calling VRDP\n"));
return VINF_SUCCESS;
}
{
/* Correct negative x and y coordinates. */
if (*px < 0)
{
*px = 0;
}
if (*py < 0)
{
*py = 0;
}
/* Also check if coords are greater than the display resolution. */
{
}
{
}
}
{
/*
* Always runs under either VBVA lock or, for HGSMI, DevVGA lock.
* Safe to use VBVA vars and take the framebuffer lock.
*/
#ifdef DEBUG_sunlover
LogFlowFunc(("[%d] %d,%d %dx%d (%d,%d)\n",
#endif /* DEBUG_sunlover */
/* No updates for a disabled guest screen. */
return;
/* No updates for a blank guest screen. */
return;
if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
else
maFramebuffers[uScreenId].h);
if (pFramebuffer != NULL)
{
if (w != 0 && h != 0)
{
bool fUpdateImage = RT_BOOL(maFramebuffers[uScreenId].u32Caps & FramebufferCapabilities_UpdateImage);
if (RT_LIKELY(!fUpdateImage))
{
pFramebuffer->NotifyUpdate(x, y, w, h);
}
else
{
{
int i;
for (i = y; i < y + h; ++i)
{
pu8Dst += w * 4;
}
}
}
}
}
#ifndef VBOX_WITH_HGSMI
{
#else
{
#endif /* VBOX_WITH_HGSMI */
/* When VBVA is enabled, the VRDP server is informed
* either in VideoAccelFlush or displayVBVAUpdateProcess.
* Inform the server here only if VBVA is disabled.
*/
}
}
void Display::i_updateGuestGraphicsFacility(void)
{
/* The following is from GuestImpl.cpp. */
/** @todo A nit: The timestamp is wrong on saved state restore. Would be better
* to move the graphics and seamless capability -> facility translation to
* VMMDev so this could be saved. */
|| (mfGuestVBVACapabilities & VBVACAPS_VIDEO_MODE_HINTS) != 0)
0 /*fFlags*/, &TimeSpecTS);
else
0 /*fFlags*/, &TimeSpecTS);
}
{
return;
/* The VMMDev interface notifies the console. */
}
{
if (!fNotify)
return;
/* Tell the console about it */
}
void Display::i_handleUpdateVBVAInputMapping(int32_t xOrigin, int32_t yOrigin, uint32_t cx, uint32_t cy)
{
cxInputMapping = cx;
cyInputMapping = cy;
}
/**
* Returns the upper left and lower right corners of the virtual framebuffer.
* The lower right is "exclusive" (i.e. first pixel beyond the framebuffer),
* and the origin is (0, 0), not (1, 1) like the GUI returns.
*/
{
LogRelFlowFunc(("\n"));
if (!mpDrv)
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 (cxInputMapping && cyInputMapping)
{
}
else
for (unsigned i = 1; i < mcMonitors; ++i)
{
if (!maFramebuffers[i].fDisabled)
{
}
}
}
HRESULT Display::i_reportHostCursorCapabilities(uint32_t fCapabilitiesAdded, uint32_t fCapabilitiesRemoved)
{
/* Do we need this to access mParent? I presume that the safe VM pointer
* ensures that mpDrv will remain valid. */
return S_OK;
mpDrv->pUpPort->pfnReportHostCursorCapabilities (mpDrv->pUpPort, fCapabilitiesAdded, fCapabilitiesRemoved);
return S_OK;
}
{
return S_OK;
}
{
/* Initialize result to an empty record. */
if (xLeftResult < xRightResult)
{
/* There is intersection by X. */
if (yTopResult < yBottomResult)
{
/* There is intersection by Y. */
return true;
}
}
return false;
}
{
* sizeof(RTRECT));
if (!pVisibleRegion)
{
return VERR_NO_TMP_MEMORY;
}
unsigned uScreenId;
{
{
/* Prepare a new array of rectangles which intersect with the framebuffer.
*/
if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
rectFramebuffer.xLeft = 0;
rectFramebuffer.yTop = 0;
if (mpDrv)
{
}
else
{
rectFramebuffer.xRight = 0;
rectFramebuffer.yBottom = 0;
}
}
else
{
}
uint32_t i;
for (i = 0; i < cRect; i++)
{
{
}
}
}
}
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if (mfIsCr3DEnabled && vmmDev)
{
if (mhCrOglSvc)
{
pCtl = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(RT_MAX(cRect, 1) * sizeof(RTRECT) + sizeof(VBOXCRCMDCTL_HGCM));
if (pCtl)
{
if (!RT_SUCCESS(rc))
{
}
}
else
AssertMsgFailed(("failed to allocate rects memory\n"));
}
else
AssertMsgFailed(("mhCrOglSvc is NULL\n"));
}
#endif
return VINF_SUCCESS;
}
{
// @todo Currently not used by the guest and is not implemented in framebuffers. Remove?
return VERR_NOT_SUPPORTED;
}
#ifdef VBOX_WITH_HGSMI
static void vbvaSetMemoryFlagsHGSMI(unsigned uScreenId,
bool fVideoAccelVRDP,
{
if (pFBInfo->pVBVAHostFlags)
{
if (pFBInfo->fVBVAEnabled)
{
if (fVideoAccelVRDP)
{
}
}
LogRelFlowFunc((" fu32HostEvents = 0x%08X, fu32SupportedOrders = 0x%08X\n", fu32HostEvents, fu32SupportedOrders));
}
}
bool fVideoAccelVRDP,
unsigned cFBInfos)
{
unsigned uScreenId;
{
}
}
#endif /* VBOX_WITH_HGSMI */
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
}
return rc;
}
void Display::VideoAccelFlushVMMDev(void)
{
LogFlowFunc(("enter\n"));
if (RT_SUCCESS(rc))
{
}
LogFlowFunc(("leave\n"));
}
/* Called always by one VRDP server thread. Can be thread-unsafe.
*/
{
int c = fEnable?
Assert (c >= 0);
/* This can run concurrently with Display videoaccel state change. */
if (c == 0)
{
/* The last client has disconnected, and the accel can be
* disabled.
*/
mfVideoAccelVRDP = false;
mfu32SupportedOrders = 0;
i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
#ifdef VBOX_WITH_HGSMI
/* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
#endif /* VBOX_WITH_HGSMI */
LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
}
else if ( c == 1
&& !mfVideoAccelVRDP)
{
/* The first client has connected. Enable the accel.
*/
mfVideoAccelVRDP = true;
/* Supporting all orders. */
mfu32SupportedOrders = ~0;
i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
#ifdef VBOX_WITH_HGSMI
/* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
#endif /* VBOX_WITH_HGSMI */
LogRel(("VBVA: VRDP acceleration has been requested.\n"));
}
else
{
/* A client is connected or disconnected but there is no change in the
* accel state. It remains enabled.
*/
Assert(mfVideoAccelVRDP == true);
}
}
void Display::i_notifyPowerDown(void)
{
LogRelFlowFunc(("\n"));
/* Source bitmaps are not available anymore. */
mfSourceBitmapEnabled = false;
/* Resize all displays to tell framebuffers to forget current source bitmap. */
unsigned uScreenId = mcMonitors;
while (uScreenId > 0)
{
--uScreenId;
{
pFBInfo->w,
pFBInfo->h,
}
}
}
// Wrapped IDisplay methods
/////////////////////////////////////////////////////////////////////////////
HRESULT Display::getScreenResolution(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel,
{
uint32_t u32BitsPerPixel = 0;
if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
if (mpDrv)
{
}
}
else if (aScreenId < mcMonitors)
{
}
else
{
return E_INVALIDARG;
}
if (aWidth)
if (aHeight)
if (aBitsPerPixel)
if (aXOrigin)
if (aYOrigin)
if (aGuestMonitorStatus)
return S_OK;
}
{
if (aScreenId >= mcMonitors)
size_t i;
/* The driver might not have been constructed yet */
if (mpDrv)
{
/* Setup the new framebuffer. */
pFBInfo->w,
pFBInfo->h,
}
{
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if (mfIsCr3DEnabled)
{
}
#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
3, this, aScreenId, false);
}
return S_OK;
}
{
if (aScreenId >= mcMonitors)
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
{
if (mfIsCr3DEnabled)
{
}
}
#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
return S_OK;
}
{
if (aScreenId >= mcMonitors)
return S_OK;
}
{
/*
* Do some rough checks for valid input.
*/
if (!width)
if (!height)
if (!bpp)
{
}
return E_INVALIDARG;
return E_INVALIDARG;
/*
* sunlover 20070614: It is up to the guest to decide whether the hint is
* valid. Therefore don't do any VRAM sanity checks here!
*/
/* Have to release the lock because the pfnRequestDisplayChange
* will call EMT. */
/* We always send the hint to the graphics card in case the guest enables
* support later. For now we notify exactly when support is enabled. */
aChangeOrigin ? aOriginX : ~0,
aChangeOrigin ? aOriginY : ~0,
&& !(mfGuestVBVACapabilities & VBVACAPS_IRQ))
{
return hrc;
}
/* We currently never suppress the VMMDev hint if the guest has requested
* it. Specifically the video graphics driver may not be responsible for
* screen positioning in the guest virtual desktop, and the component
* responsible may want to get the hint from VMMDev. */
if (pVMMDev)
{
if (pVMMDevPort)
}
return S_OK;
}
{
/* Have to release the lock because the pfnRequestSeamlessChange will call EMT. */
if (pVMMDev)
{
if (pVMMDevPort)
}
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if (!enabled)
{
if (mfIsCr3DEnabled && vmmDev)
{
if (!pData)
{
AssertMsgFailed(("RTMemAlloc failed\n"));
return VERR_NO_MEMORY;
}
pData->aParms[0].u.pointer.size = 0; /* <- means null rects, NULL pRects address and 0 rects means "disable" */
if (!RT_SUCCESS(rc))
{
}
}
}
#endif
return S_OK;
}
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
BOOL Display::i_displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data,
{
if ( pDisplay->mfIsCr3DEnabled
{
if (pVMMDev)
{
CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)RTMemAlloc(sizeof(*pScreenshot));
if (pScreenshot)
{
/* screen id or CRSCREEN_ALL to specify all enabled */
if (RT_SUCCESS(rc))
return TRUE;
/* fall back to the non-3d mechanism */
}
}
}
return FALSE;
}
#endif
int Display::i_displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData,
{
int rc;
if ( aScreenId == VBOX_VIDEO_PRIMARY_SCREEN
{
rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, ppu8Data, pcbData, pu32Width, pu32Height);
}
{
/* Allocate 32 bit per pixel bitmap. */
if (cbRequired)
{
{
rc = VERR_NO_MEMORY;
}
else
{
/* Copy guest VRAM to the allocated 32bpp buffer. */
if (RT_SUCCESS(rc))
{
*pcbData = cbRequired;
*pu32Height = height;
}
else
{
/* CopyRect can fail if VBVA was paused in VGA device, retry using the generic method. */
if ( rc == VERR_INVALID_STATE
{
}
}
}
}
else
{
/* No image. */
*pcbData = 0;
*pu32Width = 0;
*pu32Height = 0;
rc = VINF_SUCCESS;
}
}
else
{
}
return rc;
}
static int i_displayTakeScreenshot(PUVM pUVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId,
{
int vrc = VINF_SUCCESS;
# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if (Display::i_displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t*)address, width, height))
return VINF_SUCCESS;
#endif
int cRetries = 5;
while (cRetries-- > 0)
{
/* 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. */
if (vrc != VERR_TRY_AGAIN)
{
break;
}
RTThreadSleep(10);
}
{
{
/* No scaling required. */
}
else
{
/* Scale. */
src,
}
if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
/* This can be called from any thread. */
}
else
{
}
}
return vrc;
}
{
/* Do not allow too small and too large screenshots. This also filters out negative
* values passed as either 'aWidth' or 'aHeight'.
*/
if ( aBitmapFormat != BitmapFormat_BGR0
&& aBitmapFormat != BitmapFormat_PNG)
{
}
int vrc = i_displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, aAddress, aWidth, aHeight);
if (RT_SUCCESS(vrc))
{
/* Most of uncompressed formats. */
if (aBitmapFormat == BitmapFormat_BGR0)
{
/* Do nothing. */
}
else if (aBitmapFormat == BitmapFormat_BGRA)
{
while (cPixels--)
{
}
}
else if (aBitmapFormat == BitmapFormat_RGBA)
{
while (cPixels--)
{
pu8 += 4;
}
}
else if (aBitmapFormat == BitmapFormat_PNG)
{
if (RT_SUCCESS(vrc))
{
{
}
else
{
tr("PNG is larger than 32bpp bitmap"));
}
}
else
{
}
}
}
else if (vrc == VERR_TRY_AGAIN)
tr("Screenshot is not available at this time"));
else if (RT_FAILURE(vrc))
return rc;
}
{
LogRelFlowFunc(("[%d] address=%p, width=%d, height=%d, format 0x%08X\n",
return rc;
}
{
LogRelFlowFunc(("[%d] width=%d, height=%d, format 0x%08X\n",
/* Do not allow too small and too large screenshots. This also filters out negative
* values passed as either 'aWidth' or 'aHeight'.
*/
cbOut = 0;
return rc;
}
{
#ifdef VBOX_WITH_VPX
return VINF_SUCCESS;
#else
return VERR_NOT_IMPLEMENTED;
#endif
}
/**
* Start video capturing. Does nothing if capturing is already active.
*/
int Display::i_VideoCaptureStart()
{
#ifdef VBOX_WITH_VPX
return VINF_SUCCESS;
if (RT_FAILURE(rc))
{
return rc;
}
for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
{
if (pszSuff)
if (!pszAbsPath)
if (!pszSuff)
if (RT_SUCCESS(rc))
{
if (mcMonitors > 1)
else
}
if (RT_SUCCESS(rc))
{
if (rc == VERR_ALREADY_EXISTS)
{
if (mcMonitors > 1)
else
pszSuff);
if (RT_SUCCESS(rc))
}
}
if (RT_SUCCESS(rc))
else
}
return rc;
#else
return VERR_NOT_IMPLEMENTED;
#endif
}
/**
* Stop video capturing. Does nothing if video capturing is not active.
*/
void Display::i_VideoCaptureStop()
{
#ifdef VBOX_WITH_VPX
#endif
}
{
int rc = VINF_SUCCESS;
if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height);
}
{
/* Copy the bitmap to the guest VRAM. */
if (RT_SUCCESS(rc))
{
{
/* Update the changed screen area. When source bitmap uses VRAM directly, just notify
* frontend to update. And for default format, render the guest VRAM to the source bitmap.
*/
if ( pFBInfo->fDefaultFormat
{
ULONG ulBitsPerPixel = 0;
ULONG ulBytesPerLine = 0;
ULONG ulPixelFormat = 0;
&ulWidth,
&ulHeight,
{
xSrc = x;
ySrc = y;
u32SrcWidth = pFBInfo->w;
u32SrcHeight = pFBInfo->h;
/* Default format is 32 bpp. */
u32DstBitsPerPixel = 32;
}
}
}
}
}
else
{
}
if (RT_SUCCESS(rc))
return rc;
}
HRESULT Display::drawToScreen(ULONG aScreenId, BYTE *aAddress, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight)
{
/// @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
// is called on the GUI thread, will make it unresponsive. We should
// check the machine state here (by enclosing the check and VMRequCall
// within the Console lock to make it atomic).
LogRelFlowFunc(("aAddress=%p, x=%d, y=%d, width=%d, height=%d\n",
/* Release lock because the call scheduled on EMT may also try to take it. */
/*
* Again we're lazy and make the graphics device do all the
* dirty conversion work.
*/
/*
* If the function returns not supported, we'll have to do all the
* work ourselves using the framebuffer.
*/
{
/** @todo implement generic fallback for screen blitting. */
}
else if (RT_FAILURE(rcVBox))
//@todo
// else
// {
// /* All ok. Redraw the screen. */
// handleDisplayUpdate (x, y, width, height);
// }
return rc;
}
{
unsigned uScreenId;
{
if ( !pFBInfo->fVBVAEnabled
{
pDisplay->mpDrv->pUpPort->pfnUpdateDisplayAll(pDisplay->mpDrv->pUpPort, /* fFailOnResize = */ true);
}
else
{
{
/* Render complete VRAM screen to the framebuffer.
* When framebuffer uses VRAM directly, just notify it to update.
*/
{
ULONG ulBitsPerPixel = 0;
ULONG ulBytesPerLine = 0;
ULONG ulPixelFormat = 0;
&ulWidth,
&ulHeight,
{
/* Default format is 32 bpp. */
/* if uWidth != pFBInfo->w and uHeight != pFBInfo->h
* implies resize of Framebuffer is in progress and
* copyrect should not be called.
*/
{
}
}
}
}
}
if (!fUpdateAll)
break;
}
LogRelFlowFunc(("done\n"));
return VINF_SUCCESS;
}
/**
* Does a full invalidation of the VM display and instructs the VM
* to update it immediately.
*
* @returns COM status code
*/
{
LogRelFlowFunc(("\n"));
LogRelFlowFunc(("Sending DPYUPDATE request\n"));
/* Have to release the lock when calling EMT. */
int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3, this, 0, true);
if (RT_FAILURE(rcVBox))
return rc;
}
{
LogRelFlowFunc(("\n"));
int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3, this, aScreenId, false);
if (RT_FAILURE(rcVBox))
return rc;
}
{
#ifdef VBOX_WITH_VIDEOHWACCEL
return S_OK;
#else
return E_NOTIMPL;
#endif
}
{
AssertMsgReturn(aScreenId < mcMonitors, ("aScreendId=%d mcMonitors=%d\n", aScreenId, mcMonitors), E_INVALIDARG);
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if (mfIsCr3DEnabled)
{
if (RT_FAILURE(rc))
{
}
}
#endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */
#ifdef VBOX_WITH_VMSVGA
/* The driver might not have been constructed yet */
if (mpDrv)
#endif
return S_OK;
}
{
bool fSetRenderVRAM = false;
bool fInvalidate = false;
if (aScreenId >= mcMonitors)
if (!mfSourceBitmapEnabled)
{
return E_FAIL;
}
/* No source bitmap for a blank guest screen. */
{
return E_FAIL;
}
{
/* Create a new object. */
{
if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
/* Start buffer updates. */
ULONG ulBitsPerPixel = 0;
ULONG ulBytesPerLine = 0;
ULONG ulPixelFormat = 0;
&ulWidth,
&ulHeight,
}
/* Make sure that the bitmap contains the latest image. */
}
}
{
}
/* Leave the IDisplay lock because the VGA device must not be called under it. */
{
if (fSetRenderVRAM)
{
}
if (fInvalidate)
3, this, aScreenId, false);
}
return hr;
}
// wrapped IEventListener method
{
switch (aType)
{
{
if ( machineState == MachineState_Running
)
{
LogRelFlowFunc(("Machine is running.\n"));
#ifdef VBOX_WITH_CROGL
i_crOglWindowsShow(true);
#endif
}
else
{
#ifdef VBOX_WITH_CROGL
if (machineState == MachineState_Paused)
i_crOglWindowsShow(false);
#endif
}
break;
}
default:
AssertFailed();
}
return S_OK;
}
// private methods
/////////////////////////////////////////////////////////////////////////////
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
{
if (!pVMMDev)
return VERR_INVALID_STATE;
}
#endif
#ifdef VBOX_WITH_CRHGSMI
void Display::i_setupCrHgsmiData(void)
{
if (pVMMDev)
else
if (RT_SUCCESS(rc))
{
/* setup command completion callback */
if (RT_SUCCESS(rc))
else
}
if (RT_FAILURE(rc))
mhCrOglSvc = NULL;
}
void Display::i_destructCrHgsmiData(void)
{
mhCrOglSvc = NULL;
}
#endif /* VBOX_WITH_CRHGSMI */
/**
* Handle display resize event issued by the VGA device for the primary screen.
*
* @see PDMIDISPLAYCONNECTOR::pfnResize
*/
{
LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
if (!f)
{
/* This is a result of recursive call when the source bitmap is being updated
* during a VGA resize. Tell the VGA device to ignore the call.
*
* @todo It is a workaround, actually pfnUpdateDisplayAll must
* fail on resize.
*/
LogRel(("displayResizeCallback: already processing\n"));
return VINF_VGA_RESIZE_IN_PROGRESS;
}
int rc = pThis->i_handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE);
/* Restore the flag. */
AssertRelease(f);
return rc;
}
/**
* Handle display update.
*
* @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
*/
{
#ifdef DEBUG_sunlover
LogFlowFunc(("fVideoAccelEnabled = %d, %d,%d %dx%d\n",
#endif /* DEBUG_sunlover */
/* This call does update regardless of VBVA status.
* But in VBVA mode this is called only as result of
* pfnUpdateDisplayAll in the VGA device.
*/
}
/**
* Periodic display refresh callback.
*
* @see PDMIDISPLAYCONNECTOR::pfnRefresh
* @thread EMT
*/
{
#ifdef DEBUG_sunlover_2
LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
#endif /* DEBUG_sunlover_2 */
unsigned uScreenId;
{
if (rc == VWRN_INVALID_STATE)
{
/* No VBVA do a display update. */
}
/* Inform the VRDP server that the current display update sequence is
* completed. At this moment the framebuffer memory contains a definite
* image, that is synchronized with the orders already sent to VRDP client.
* The server can now process redraw requests from clients or initial
* fullscreen updates for new clients.
*/
{
}
}
#ifdef VBOX_WITH_VPX
{
do {
# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if (pDisplay->mfIsCr3DEnabled)
{
if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE))
{
{
/* submit */
rc = pDisplay->i_crCtlSubmit(&pData->Hdr, sizeof(*pData), Display::i_displayVRecCompletion, pDisplay);
if (RT_SUCCESS(rc))
break;
}
/* no 3D data available, or error has occured,
* go the straight way */
}
else
{
/* record request is still in progress, don't do anything */
break;
}
}
# endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
{
continue;
{
break;
}
{
if ( pFBInfo->fVBVAEnabled
{
}
{
}
if (rc == VINF_TRY_AGAIN)
break;
}
}
} while (0);
}
#endif /* VBOX_WITH_VPX */
#ifdef DEBUG_sunlover_2
LogFlowFunc(("leave\n"));
#endif /* DEBUG_sunlover_2 */
}
/**
* Reset notification
*
* @see PDMIDISPLAYCONNECTOR::pfnReset
*/
{
LogRelFlowFunc(("\n"));
/* Disable VBVA mode. */
}
/**
* LFBModeChange notification
*
* @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
*/
DECLCALLBACK(void) Display::i_displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
{
/* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
}
/**
* Adapter information change notification.
*
* @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
*/
DECLCALLBACK(void) Display::i_displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM,
{
}
/**
* Display information change notification.
*
* @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
*/
{
}
#ifdef VBOX_WITH_VIDEOHWACCEL
#ifndef S_FALSE
#endif
{
int rc = VINF_SUCCESS;
if (id >= mcMonitors)
return VERR_INVALID_PARAMETER;
return VERR_NOT_IMPLEMENTED; /* Implementation is not available. */
return VINF_SUCCESS;
return VINF_CALLBACK_RETURN;
else if (hr == E_ACCESSDENIED)
return VERR_INVALID_STATE; /* notify we can not handle request atm */
return VERR_NOT_IMPLEMENTED;
return VERR_GENERAL_FAILURE;
}
DECLCALLBACK(int) Display::i_displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
{
}
#endif
#ifdef VBOX_WITH_CRHGSMI
void Display::i_handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
{
}
void Display::i_handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
{
}
{
int rc = VERR_NOT_SUPPORTED;
if (mhCrOglSvc)
{
if (pVMMDev)
{
/* no completion callback is specified with this call,
* the CrOgl code will complete the CrHgsmi command once it processes it */
if (RT_SUCCESS(rc))
return;
}
else
}
/* we are here because something went wrong with command processing, complete it */
}
{
int rc = VERR_NOT_SUPPORTED;
if (mhCrOglSvc)
{
if (pVMMDev)
{
Display::i_displayCrHgsmiControlCompletion, this);
if (RT_SUCCESS(rc))
{
{
{
continue;
if (RT_SUCCESS(rc))
else
{
rc = VINF_SUCCESS;
}
}
}
return;
}
}
else
}
/* we are here because something went wrong with command processing, complete it */
}
DECLCALLBACK(void) Display::i_displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd,
{
}
DECLCALLBACK(void) Display::i_displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd,
{
}
DECLCALLBACK(void) Display::i_displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
void *pvContext)
{
AssertMsgFailed(("not expected!\n"));
}
DECLCALLBACK(void) Display::i_displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
void *pvContext)
{
}
#endif
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
DECLCALLBACK(void) Display::i_displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
void *pvContext)
{
if (pCmd->u.pfnInternal)
}
void *pvCompletion)
{
if (!pVMMDev)
{
AssertMsgFailed(("no vmmdev\n"));
return VERR_INVALID_STATE;
}
int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, i_displayCrHgcmCtlSubmitCompletion,
if (!RT_SUCCESS(rc))
return rc;
}
void *pvCompletion)
{
}
int Display::i_crCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, PFNCRCTLCOMPLETION pfnCompletion, void *pvCompletion)
{
if (RT_SUCCESS(rc))
{
if (mhCrOglSvc)
rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmit(mpDrv->pVBVACallbacks, pCmd, cbCmd, pfnCompletion, pvCompletion);
else
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
if (mhCrOglSvc)
else
}
return rc;
}
{
if (!pCmdCopy)
{
LogRel(("RTMemAlloc failed\n"));
return VERR_NO_MEMORY;
}
if (RT_FAILURE(rc))
{
return rc;
}
return VINF_SUCCESS;
}
int Display::i_crCtlSubmitSyncIfHasDataForScreen(uint32_t u32ScreenID, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
{
else
return rc;
}
{
# if VBOX_WITH_VPX
# else
return false;
# endif
}
{
}
{
# if VBOX_WITH_VPX
# endif
}
void Display::i_handleVRecCompletion()
{
}
#endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
HRESULT Display::notifyScaleFactorChange(ULONG aScreenId, ULONG aScaleFactorWMultiplied, ULONG aScaleFactorHMultiplied)
{
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
if (aScreenId >= mcMonitors)
return E_INVALIDARG;
/* 3D acceleration enabled in VM config. */
if (mfIsCr3DEnabled)
{
/* VBoxSharedCrOpenGL HGCM host service is running. */
if (mhCrOglSvc)
{
if (pVMMDev)
{
pCtl = (VBOXCRCMDCTL_HGCM *)RTMemAlloc(sizeof(CRVBOXHGCMSETSCALEFACTOR) + sizeof(VBOXCRCMDCTL_HGCM));
if (pCtl)
{
int rc;
if (RT_FAILURE(rc))
else
}
else
{
LogRel(("Running out of memory on attempt to set OpenGL content scale factor. Ignored.\n"));
hr = E_OUTOFMEMORY;
}
}
else
LogRel(("Internal error occurred on attempt to set OpenGL content scale factor. Ignored.\n"));
}
else
LogRel(("Attempt to specify OpenGL content scale factor while corresponding HGCM host service not yet runing. Ignored.\n"));
}
else
# if 0 /** @todo Thank you so very much from anyone using VMSVGA3d! */
AssertMsgFailed(("Attempt to specify OpenGL content scale factor while 3D acceleration is disabled in VM config. Ignored.\n"));
# else
{
/* Need an interface like this here (and the #ifdefs needs adjusting):
PPDMIDISPLAYPORT pUpPort = mpDrv ? mpDrv->pUpPort : NULL;
if (pUpPort && pUpPort->pfnSetScaleFactor)
pUpPort->pfnSetScaleFactor(pUpPort, aScreeId, aScaleFactorWMultiplied, aScaleFactorHMultiplied); */
}
# endif
return hr;
#else
AssertMsgFailed(("Attempt to specify OpenGL content scale factor while corresponding functionality is disabled."));
return E_UNEXPECTED;
#endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
}
{
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
/* 3D acceleration enabled in VM config. */
if (mfIsCr3DEnabled)
{
/* VBoxSharedCrOpenGL HGCM host service is running. */
if (mhCrOglSvc)
{
if (pVMMDev)
{
pCtl = (VBOXCRCMDCTL_HGCM *)RTMemAlloc(sizeof(CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT) + sizeof(VBOXCRCMDCTL_HGCM));
if (pCtl)
{
int rc;
if (RT_FAILURE(rc))
else
}
else
{
LogRel(("Running out of memory on attempt to notify OpenGL about HiDPI output scaling policy change. Ignored.\n"));
hr = E_OUTOFMEMORY;
}
}
else
LogRel(("Internal error occurred on attempt to notify OpenGL about HiDPI output scaling policy change. Ignored.\n"));
}
else
LogRel(("Attempt to notify OpenGL about HiDPI output scaling policy change while corresponding HGCM host service not yet runing. Ignored.\n"));
}
else
{
/* Need an interface like this here (and the #ifdefs needs adjusting):
PPDMIDISPLAYPORT pUpPort = mpDrv ? mpDrv->pUpPort : NULL;
if (pUpPort && pUpPort->pfnSetScaleFactor)
pUpPort->pfnSetScaleFactor(pUpPort, aScreeId, aScaleFactorWMultiplied, aScaleFactorHMultiplied); */
}
return hr;
#else
AssertMsgFailed(("Attempt to notify OpenGL about HiDPI output scaling policy change while corresponding functionality is disabled."));
return E_UNEXPECTED;
#endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
}
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
{
x, y, BitmapFormat_BGR, uBitsPerPixel,
}
DECLCALLBACK(bool) Display::i_displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
{
}
DECLCALLBACK(void) Display::i_displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
{
}
DECLCALLBACK(void) Display::i_displayVRecCompletion(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
{
}
#endif
#ifdef VBOX_WITH_HGSMI
DECLCALLBACK(int) Display::i_displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags,
bool fRenderThreadMode)
{
if (pThis->maFramebuffers[uScreenId].fVBVAEnabled && pThis->maFramebuffers[uScreenId].fRenderThreadMode != fRenderThreadMode)
{
LogRel(("Enabling different vbva mode\n"));
#ifdef DEBUG_misha
AssertMsgFailed(("enabling different vbva mode\n"));
#endif
return VERR_INVALID_STATE;
}
vbvaSetMemoryFlagsHGSMI(uScreenId, pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, &pThis->maFramebuffers[uScreenId]);
return VINF_SUCCESS;
}
DECLCALLBACK(void) Display::i_displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
{
if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
{
/* Make sure that the primary screen is visible now.
* The guest can't use VBVA anymore, so only only the VGA device output works.
*/
{
}
}
pFBInfo->fVBVAEnabled = false;
pFBInfo->fVBVAForceResize = false;
pFBInfo->fRenderThreadMode = false;
{
/* Force full screen update, because VGA device must take control, do resize, etc. */
}
}
DECLCALLBACK(void) Display::i_displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
{
{
vbvaSetMemoryFlagsAllHGSMI(pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, pThis->maFramebuffers,
pThis->mcMonitors);
}
}
DECLCALLBACK(void) Display::i_displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId,
{
LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d, @%d,%d %dx%d\n", uScreenId, pCmd, cbCmd, pCmd->x, pCmd->y, pCmd->w, pCmd->h));
if (pFBInfo->fDefaultFormat)
{
/* Make sure that framebuffer contains the same image as the guest VRAM. */
if ( uScreenId == VBOX_VIDEO_PRIMARY_SCREEN
{
}
{
/* Render VRAM content to the framebuffer. */
ULONG ulBitsPerPixel = 0;
ULONG ulBytesPerLine = 0;
ULONG ulPixelFormat = 0;
&ulWidth,
&ulHeight,
{
}
}
}
/* @todo new SendUpdate entry which can get a separate cmd header or coords. */
*pHdrUnconst = hdrSaved;
}
DECLCALLBACK(void) Display::i_displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y,
{
/* @todo handleFramebufferUpdate (uScreenId,
* x - pThis->maFramebuffers[uScreenId].xOrigin,
* y - pThis->maFramebuffers[uScreenId].yOrigin,
* cx, cy);
*/
}
#ifdef DEBUG_sunlover
static void logVBVAResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, const DISPLAYFBINFO *pFBInfo)
{
LogRel(("displayVBVAResize: [%d] %s\n"
" pView->u32ViewIndex %d\n"
" pView->u32ViewOffset 0x%08X\n"
" pView->u32ViewSize 0x%08X\n"
" pView->u32MaxScreenSize 0x%08X\n"
" pScreen->i32OriginX %d\n"
" pScreen->i32OriginY %d\n"
" pScreen->u32StartOffset 0x%08X\n"
" pScreen->u32LineSize 0x%08X\n"
" pScreen->u32Width %d\n"
" pScreen->u32Height %d\n"
" pScreen->u16BitsPerPixel %d\n"
" pScreen->u16Flags 0x%04X\n"
" pFBInfo->u32Offset 0x%08X\n"
" pFBInfo->u32MaxFramebufferSize 0x%08X\n"
" pFBInfo->u32InformationSize 0x%08X\n"
" pFBInfo->fDisabled %d\n"
" xOrigin, yOrigin, w, h: %d,%d %dx%d\n"
" pFBInfo->u16BitsPerPixel %d\n"
" pFBInfo->pu8FramebufferVRAM %p\n"
" pFBInfo->u32LineSize 0x%08X\n"
" pFBInfo->flags 0x%04X\n"
" pFBInfo->pHostEvents %p\n"
" pFBInfo->fDefaultFormat %d\n"
" pFBInfo->fVBVAEnabled %d\n"
" pFBInfo->fVBVAForceResize %d\n"
" pFBInfo->pVBVAHostFlags %p\n"
"",
pFBInfo->w,
pFBInfo->h,
));
}
#endif /* DEBUG_sunlover */
DECLCALLBACK(int) Display::i_displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView,
{
{
/* 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. */
0, 0, 0, 0);
return VINF_SUCCESS;
}
/* If display was disabled or there is no framebuffer, a resize will be required,
*/
if (pFBInfo->fVBVAForceResize)
{
/* VBVA was just enabled. Do the resize. */
fResize = true;
pFBInfo->fVBVAForceResize = false;
}
/* If the screen if blanked, then do a resize request to make sure that the framebuffer
* switches to the default format.
*/
/* Check if this is a real resize or a notification about the screen origin.
* The guest uses this VBVAResize call for both.
*/
if (fNewOrigin || fResize)
{
/* Continue to update pFBInfo. */
}
pThis->xInputMappingOrigin = 0;
pThis->yInputMappingOrigin = 0;
pThis->cxInputMapping = 0;
pThis->cyInputMapping = 0;
if (fNewOrigin)
{
0, 0);
}
if (!fResize)
{
/* No parameters of the framebuffer have actually changed. */
if (fNewOrigin)
{
/* VRDP server still need this notification. */
LogRelFlowFunc(("Calling VRDP\n"));
}
return VINF_SUCCESS;
}
/* Do a regular resize. */
}
DECLCALLBACK(int) Display::i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
const void *pvShape)
{
LogFlowFunc(("\n"));
if (pvShape)
{
}
/* Tell the console about it */
return VINF_SUCCESS;
}
DECLCALLBACK(void) Display::i_displayVBVAGuestCapabilityUpdate(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities)
{
LogFlowFunc(("\n"));
}
DECLCALLBACK(void) Display::i_displayVBVAInputMappingUpdate(PPDMIDISPLAYCONNECTOR pInterface, int32_t xOrigin, int32_t yOrigin,
{
LogFlowFunc(("\n"));
}
#endif /* VBOX_WITH_HGSMI */
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
return NULL;
}
/**
* Destruct a display driver instance.
*
* @returns VBox status.
* @param pDrvIns The driver instance data.
*/
{
{
#ifdef VBOX_WITH_VPX
#endif
#ifdef VBOX_WITH_CRHGSMI
#endif
}
}
/**
* Construct a display driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
{
/*
* Validate configuration.
*/
("Configuration error: Not possible to attach anything to this driver!\n"),
/*
* Init Interfaces.
*/
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
#ifdef VBOX_WITH_CRHGSMI
#endif
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
#endif
#ifdef VBOX_WITH_HGSMI
#endif
/*
*/
{
AssertMsgFailed(("Configuration error: No display port interface above!\n"));
return VERR_PDM_MISSING_INTERFACE_ABOVE;
}
#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
if (!pThis->pVBVACallbacks)
{
AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n"));
return VERR_PDM_MISSING_INTERFACE_ABOVE;
}
#endif
/*
* Get the Display object pointer and update the mpDrv member.
*/
void *pv;
if (RT_FAILURE(rc))
{
return rc;
}
/* Disable VRAM to a buffer copy initially. */
/*
* Start periodic screen refreshes
*/
#ifdef VBOX_WITH_CRHGSMI
#endif
#ifdef VBOX_WITH_VPX
if (fEnabled)
{
}
#endif
return rc;
}
/**
* Display driver registration record.
*/
{
/* u32Version */
/* szName */
"MainDisplay",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Main display driver (Main as in the API).",
/* fFlags */
/* fClass. */
/* cMaxInstances */
~0U,
/* cbInstance */
sizeof(DRVMAINDISPLAY),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
};
/* vi: set tabstop=4 shiftwidth=4 expandtab: */