summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/VBox/HGSMI/HGSMIChSetup.h2
-rw-r--r--include/VBox/VBoxVideo.h37
-rw-r--r--include/VBox/vmm/pdmifs.h44
-rw-r--r--src/VBox/Devices/Graphics/DevVGA.cpp1
-rw-r--r--src/VBox/Devices/Graphics/DevVGA.h5
-rw-r--r--src/VBox/Devices/Graphics/DevVGA_VBVA.cpp98
-rw-r--r--src/VBox/Devices/PC/DevACPI.cpp19
-rw-r--r--src/VBox/Devices/PC/vbox.dsl33
-rw-r--r--src/VBox/Main/include/ConsoleImpl.h1
-rw-r--r--src/VBox/Main/include/DisplayImpl.h11
-rw-r--r--src/VBox/Main/src-client/ConsoleImpl.cpp41
-rw-r--r--src/VBox/Main/src-client/DisplayImpl.cpp80
-rw-r--r--src/VBox/Main/src-client/GuestImpl.cpp3
-rw-r--r--src/VBox/Main/src-client/VMMDevInterface.cpp9
14 files changed, 378 insertions, 6 deletions
diff --git a/include/VBox/HGSMI/HGSMIChSetup.h b/include/VBox/HGSMI/HGSMIChSetup.h
index 3084a76d6de..b86d16c0849 100644
--- a/include/VBox/HGSMI/HGSMIChSetup.h
+++ b/include/VBox/HGSMI/HGSMIChSetup.h
@@ -55,6 +55,8 @@ AssertCompileSize(HGSMIBUFFERLOCATION, 8);
#endif
/* vsync interrupt flag, should be accessed under VGAState::lock only */
#define HGSMIHOSTFLAGS_VSYNC 0x10
+/** monitor hotplug flag, should be accessed under VGAState::lock only */
+#define HGSMIHOSTFLAGS_HOTPLUG 0x20
typedef struct _HGSMIHOSTFLAGS
{
diff --git a/include/VBox/VBoxVideo.h b/include/VBox/VBoxVideo.h
index cc148c4e391..246da015c85 100644
--- a/include/VBox/VBoxVideo.h
+++ b/include/VBox/VBoxVideo.h
@@ -855,6 +855,7 @@ typedef struct VBVABUFFER
#define VBVA_CMDVBVA_SUBMIT 16 /* inform host about VBVA Command submission */
#define VBVA_CMDVBVA_FLUSH 17 /* inform host about VBVA Command submission */
#define VBVA_CMDVBVA_CTL 18 /* G->H DMA command */
+#define VBVA_QUERY_MODE_HINTS 19 /* Query most recent mode hints sent. */
/* host->guest commands */
#define VBVAHG_EVENT 1
@@ -910,6 +911,8 @@ typedef struct VBVAHOSTCMD
/* VBVACONF32::u32Index */
#define VBOX_VBVA_CONF32_MONITOR_COUNT 0
#define VBOX_VBVA_CONF32_HOST_HEAP_SIZE 1
+/** Returns VINF_SUCCESS if the host can report mode hints via VBVA. */
+#define VBOX_VBVA_CONF32_MODE_HINT_REPORTING 2
typedef struct VBVACONF32
{
@@ -1076,6 +1079,8 @@ typedef struct VBVAMOUSEPOINTERSHAPE
#define VBVACAPS_COMPLETEGCMD_BY_IOREAD 0x00000001
/* the guest driver can handle video adapter IRQs */
#define VBVACAPS_IRQ 0x00000002
+/** The guest can read video mode hints sent via VBVA. */
+#define VBVACAPS_VIDEO_MODE_HINTS 0x00000004
typedef struct VBVACAPS
{
int32_t rc;
@@ -1109,6 +1114,38 @@ typedef struct VBVASCANLINEINFO
uint32_t u32ScanLine;
} VBVASCANLINEINFO;
+/** Query the most recent mode hints received from the host. */
+typedef struct VBVAQUERYMODEHINTS
+{
+ /** The maximum number of screens to return hints for. */
+ uint16_t cHintsQueried;
+ /** The size of the mode hint structures directly following this one. */
+ uint16_t cbHintStructureGuest;
+ /** The return code for the operation. Initialise to VERR_NOT_SUPPORTED. */
+ int32_t rc;
+} VBVAQUERYMODEHINTS;
+
+/** Structure in which a mode hint is returned. The guest allocates an array
+ * of these immediately after the VBVAQUERYMODEHINTS structure. To accomodate
+ * future extensions, the VBVAQUERYMODEHINTS structure specifies the size of
+ * the VBVAMODEHINT structures allocated by the guest, and the host only fills
+ * out structure elements which fit into that size. The host should fill any
+ * unused members (e.g. dx, dy) or structure space on the end with ~0. The
+ * whole structure can legally be set to ~0 to skip a screen. */
+typedef struct VBVAMODEHINT
+{
+ uint32_t magic;
+ uint32_t cx;
+ uint32_t cy;
+ uint32_t cBPP; /* Which has never been used... */
+ uint32_t cDisplay;
+ uint32_t dx; /**< X offset into the virtual frame-buffer. */
+ uint32_t dy; /**< Y offset into the virtual frame-buffer. */
+ uint32_t fEnabled; /* Not fFlags. Add new members for new flags. */
+} VBVAMODEHINT;
+
+#define VBVAMODEHINT_MAGIC UINT32_C(0x0801add9)
+
#pragma pack()
typedef uint64_t VBOXVIDEOOFFSET;
diff --git a/include/VBox/vmm/pdmifs.h b/include/VBox/vmm/pdmifs.h
index fe820527193..591934a3d22 100644
--- a/include/VBox/vmm/pdmifs.h
+++ b/include/VBox/vmm/pdmifs.h
@@ -659,12 +659,32 @@ typedef struct PDMIDISPLAYPORT
*/
DECLR3CALLBACKMEMBER(void, pfnSetViewPort,(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy));
#endif
+
+ /**
+ * Send a video mode hint to the VGA device.
+ *
+ * @param pInterface Pointer to this interface.
+ * @param cx The X resolution.
+ * @param cy The Y resolution.
+ * @param cBPP The bit count.
+ * @param iDisplay The screen number.
+ * @param dx X offset into the virtual framebuffer or ~0.
+ * @param dy Y offset into the virtual framebuffer or ~0.
+ * @param fEnabled Is this screen currently enabled?
+ * @param fNotifyGuest Should the device send the guest an IRQ?
+ * Set for the last hint of a series.
+ * @thread Schedules on the emulation thread.
+ */
+ DECLR3CALLBACKMEMBER(int, pfnSendModeHint,
+ (PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy,
+ uint32_t cBPP, uint32_t iDisplay, uint32_t dx,
+ uint32_t dy, uint32_t fEnabled, uint32_t fNotifyGuest));
} PDMIDISPLAYPORT;
/** PDMIDISPLAYPORT interface ID. */
#ifdef VBOX_WITH_VMSVGA
#define PDMIDISPLAYPORT_IID "f7ed5b9a-3940-4862-9310-1de7e3d118a4"
#else
-#define PDMIDISPLAYPORT_IID "dae29a50-5e24-4fd6-9a6a-65f6bf900acb"
+#define PDMIDISPLAYPORT_IID "613ed6c0-817a-11e4-bc1e-931613071d2c"
#endif
@@ -924,6 +944,15 @@ typedef struct PDMIDISPLAYCONNECTOR
uint32_t cx, uint32_t cy,
const void *pvShape));
+ /**
+ * The guest capabilities were updated.
+ *
+ * @param pInterface Pointer to this interface.
+ * @param fCapabilities The new capability flag state.
+ * @thread The emulation thread.
+ */
+ DECLR3CALLBACKMEMBER(void, pfnVBVAGuestCapabilityUpdate,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities));
+
/** Read-only attributes.
* For preformance reasons some readonly attributes are kept in the interface.
* We trust the interface users to respect the readonlyness of these.
@@ -942,7 +971,7 @@ typedef struct PDMIDISPLAYCONNECTOR
/** @} */
} PDMIDISPLAYCONNECTOR;
/** PDMIDISPLAYCONNECTOR interface ID. */
-#define PDMIDISPLAYCONNECTOR_IID "906d0c25-091f-497e-908c-1d70cb7e6114"
+#define PDMIDISPLAYCONNECTOR_IID "33a332b3-0850-4b0f-a697-dcc140bb2e05"
/** Pointer to a block port interface. */
@@ -2244,9 +2273,18 @@ typedef struct PDMIACPIPORT
* @param pfLocked Is set to true if the CPU is still locked by the guest, false otherwise.
*/
DECLR3CALLBACKMEMBER(int, pfnGetCpuStatus,(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked));
+
+ /**
+ * Send an ACPI monitor hot-plug event.
+ *
+ * @returns VBox status code
+ * @param pInterface Pointer to the interface structure containing
+ * the called function pointer.
+ */
+ DECLR3CALLBACKMEMBER(int, pfnMonitorHotPlugEvent,(PPDMIACPIPORT pInterface));
} PDMIACPIPORT;
/** PDMIACPIPORT interface ID. */
-#define PDMIACPIPORT_IID "30d3dc4c-6a73-40c8-80e9-34309deacbb3"
+#define PDMIACPIPORT_IID "d64233e3-7bb0-4ef1-a313-2bcfafbe6260"
/** Pointer to an ACPI connector interface. */
diff --git a/src/VBox/Devices/Graphics/DevVGA.cpp b/src/VBox/Devices/Graphics/DevVGA.cpp
index f59809057a3..47159ba77a3 100644
--- a/src/VBox/Devices/Graphics/DevVGA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA.cpp
@@ -6061,6 +6061,7 @@ static DECLCALLBACK(int) vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
#ifdef VBOX_WITH_VMSVGA
pThis->IPort.pfnSetViewPort = vmsvgaPortSetViewPort;
#endif
+ pThis->IPort.pfnSendModeHint = vbvaPortSendModeHint;
#if defined(VBOX_WITH_HGSMI)
# if defined(VBOX_WITH_VIDEOHWACCEL)
diff --git a/src/VBox/Devices/Graphics/DevVGA.h b/src/VBox/Devices/Graphics/DevVGA.h
index 95cdf624116..fed7e33f300 100644
--- a/src/VBox/Devices/Graphics/DevVGA.h
+++ b/src/VBox/Devices/Graphics/DevVGA.h
@@ -685,6 +685,11 @@ int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Vers
int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
DECLCALLBACK(int) vgaUpdateDisplayAll(PVGASTATE pThis, bool fFailOnResize);
+DECLCALLBACK(int) vbvaPortSendModeHint(PPDMIDISPLAYPORT pInterface, uint32_t cx,
+ uint32_t cy, uint32_t cBPP,
+ uint32_t cDisplay, uint32_t dx,
+ uint32_t dy, uint32_t fEnabled,
+ uint32_t fNotifyGuest);
# ifdef VBOX_WITH_VDMA
typedef struct VBOXVDMAHOST *PVBOXVDMAHOST;
diff --git a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
index c5a27428ede..77ba8cf6e30 100644
--- a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
@@ -82,6 +82,7 @@ typedef struct VBVACONTEXT
VBVAVIEW aViews[64 /* @todo SchemaDefs::MaxGuestMonitors*/];
VBVAMOUSESHAPEINFO mouseShapeInfo;
bool fPaused;
+ VBVAMODEHINT aModeHints[VBOX_VIDEO_MAX_SCREENS];
} VBVACONTEXT;
@@ -494,6 +495,8 @@ static int vbvaEnable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCt
{
pVBVA->hostFlags.u32HostEvents = 0;
pVBVA->hostFlags.u32SupportedOrders = 0;
+ pVGAState->fGuestCaps = 0;
+ pVGAState->pDrv->pfnVBVAGuestCapabilityUpdate(pVGAState->pDrv, 0);
rc = pVGAState->pDrv->pfnVBVAEnable (pVGAState->pDrv, uScreenId, &pVBVA->hostFlags, false);
}
@@ -1598,6 +1601,16 @@ int vboxVBVASaveDevStateExec (PVGASTATE pVGAState, PSSMHANDLE pSSM)
rc = SSMR3PutU32 (pSSM, 0);
AssertRCReturn(rc, rc);
#endif
+ rc = SSMR3PutU32 (pSSM, RT_ELEMENTS(pCtx->aModeHints));
+ AssertRCReturn(rc, rc);
+ rc = SSMR3PutU32 (pSSM, sizeof(VBVAMODEHINT));
+ AssertRCReturn(rc, rc);
+ for (unsigned i = 0; i < RT_ELEMENTS(pCtx->aModeHints); ++i)
+ {
+ rc = SSMR3PutMem (pSSM, pCtx->aModeHints[i],
+ sizeof(VBVAMODEHINT));
+ AssertRCReturn(rc, rc);
+ }
}
}
@@ -2145,6 +2158,10 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe
/* @todo a value calculated from the vram size */
pConf32->u32Value = 64*_1K;
}
+ else if (pConf32->u32Index == VBOX_VBVA_CONF32_MODE_HINT_REPORTING)
+ {
+ pConf32->u32Value = VINF_SUCCESS;
+ }
else
{
Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
@@ -2396,6 +2413,8 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe
VBVACAPS *pCaps = (VBVACAPS*)pvBuffer;
pVGAState->fGuestCaps = pCaps->fCaps;
+ pVGAState->pDrv->pfnVBVAGuestCapabilityUpdate(pVGAState->pDrv,
+ pCaps->fCaps);
pCaps->rc = VINF_SUCCESS;
} break;
#endif
@@ -2411,6 +2430,40 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe
pVGAState->fScanLineCfg = pCfg->fFlags;
pCfg->rc = VINF_SUCCESS;
} break;
+
+ case VBVA_QUERY_MODE_HINTS:
+ {
+ if (cbBuffer < sizeof(VBVAQUERYMODEHINTS))
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ VBVAQUERYMODEHINTS *pModeHintQuery = (VBVAQUERYMODEHINTS*)pvBuffer;
+ LogRelFlowFunc(("VBVA_QUERY_MODE_HINTS: cHintsQueried=%u, cbHintStructureGuest=%u\n",
+ (unsigned)pModeHintQuery->cHintsQueried,
+ (unsigned)pModeHintQuery->cbHintStructureGuest));
+ if (cbBuffer < sizeof (VBVAQUERYMODEHINTS)
+ + (uint64_t)pModeHintQuery->cHintsQueried
+ * pModeHintQuery->cbHintStructureGuest)
+ {
+ pModeHintQuery->rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ pModeHintQuery->rc = VINF_SUCCESS;
+ uint8_t *pbHint = (uint8_t *)pvBuffer + sizeof(VBVAQUERYMODEHINTS);
+ memset(pbHint, ~0, cbBuffer - sizeof(VBVAQUERYMODEHINTS));
+ unsigned iHint;
+ for (iHint = 0; iHint < pModeHintQuery->cHintsQueried && iHint < 64;
+ ++iHint)
+ {
+ memcpy(pbHint, &pCtx->aModeHints[iHint],
+ RT_MIN(pModeHintQuery->cbHintStructureGuest,
+ sizeof(VBVAMODEHINT)));
+ pbHint += pModeHintQuery->cbHintStructureGuest;
+ Assert(pbHint - (uint8_t *)pvBuffer <= cbBuffer);
+ }
+ } break;
+
default:
Log(("Unsupported VBVA guest command %d!!!\n",
u16ChannelInfo));
@@ -2504,6 +2557,50 @@ int VBVAUpdateDisplay (PVGASTATE pVGAState)
return rc;
}
+static int vbvaSendModeHintWorker(PVGASTATE pThis, uint32_t cx, uint32_t cy,
+ uint32_t cBPP, uint32_t iDisplay, uint32_t dx,
+ uint32_t dy, uint32_t fEnabled,
+ uint32_t fNotifyGuest)
+{
+ VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pThis->pHGSMI);
+ /** @note See Display::setVideoModeHint: "It is up to the guest to decide
+ * whether the hint is valid. Therefore don't do any VRAM sanity checks
+ * here! */
+ if (iDisplay > RT_MIN(pThis->cMonitors, RT_ELEMENTS(pCtx->aModeHints)))
+ return VERR_OUT_OF_RANGE;
+ pCtx->aModeHints[iDisplay].magic = VBVAMODEHINT_MAGIC;
+ pCtx->aModeHints[iDisplay].cx = cx;
+ pCtx->aModeHints[iDisplay].cy = cy;
+ pCtx->aModeHints[iDisplay].cBPP = cBPP;
+ pCtx->aModeHints[iDisplay].dx = dx;
+ pCtx->aModeHints[iDisplay].dy = dy;
+ pCtx->aModeHints[iDisplay].fEnabled = fEnabled;
+ if (fNotifyGuest && pThis->fGuestCaps & VBVACAPS_IRQ)
+ VBVARaiseIrq(pThis, HGSMIHOSTFLAGS_HOTPLUG);
+ return VINF_SUCCESS;
+}
+
+/** Converts a display port interface pointer to a vga state pointer. */
+#define IDISPLAYPORT_2_VGASTATE(pInterface) ( (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, IPort)) )
+
+DECLCALLBACK(int) vbvaPortSendModeHint(PPDMIDISPLAYPORT pInterface, uint32_t cx,
+ uint32_t cy, uint32_t cBPP,
+ uint32_t iDisplay, uint32_t dx,
+ uint32_t dy, uint32_t fEnabled,
+ uint32_t fNotifyGuest)
+{
+ PVGASTATE pThis;
+ int rc;
+
+ pThis = IDISPLAYPORT_2_VGASTATE(pInterface);
+ rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
+ AssertRC(rc);
+ rc = vbvaSendModeHintWorker(pThis, cx, cy, cBPP, iDisplay, dx, dy, fEnabled,
+ fNotifyGuest);
+ PDMCritSectLeave(&pThis->CritSect);
+ return rc;
+}
+
static HGSMICHANNELHANDLER sOldChannelHandler;
int VBVAInit (PVGASTATE pVGAState)
@@ -2534,6 +2631,7 @@ int VBVAInit (PVGASTATE pVGAState)
VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI);
pCtx->cViews = pVGAState->cMonitors;
pCtx->fPaused = true;
+ memset(pCtx->aModeHints, ~0, sizeof(*pCtx->aModeHints));
}
}
diff --git a/src/VBox/Devices/PC/DevACPI.cpp b/src/VBox/Devices/PC/DevACPI.cpp
index 0738f9812b2..40cc81978e8 100644
--- a/src/VBox/Devices/PC/DevACPI.cpp
+++ b/src/VBox/Devices/PC/DevACPI.cpp
@@ -853,6 +853,24 @@ static DECLCALLBACK(int) acpiR3Port_SleepButtonPress(PPDMIACPIPORT pInterface)
}
/**
+ * Send an ACPI monitor hot-plug event.
+ *
+ * @returns VBox status code
+ * @param pInterface Pointer to the interface structure containing the
+ * called function pointer.
+ */
+static DECLCALLBACK(int) acpiR3Port_MonitorHotPlugEvent(PPDMIACPIPORT pInterface)
+{
+ ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
+ DEVACPI_LOCK_R3(pThis);
+
+ apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x4, pThis->gpe0_en);
+
+ DEVACPI_UNLOCK(pThis);
+ return VINF_SUCCESS;
+}
+
+/**
* Used by acpiR3PmTimer to re-arm the PM timer.
*
* The caller is expected to either hold the clock lock or to have made sure
@@ -2988,6 +3006,7 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
pThis->IACPIPort.pfnGetPowerButtonHandled = acpiR3Port_GetPowerButtonHandled;
pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiR3Port_GetGuestEnteredACPIMode;
pThis->IACPIPort.pfnGetCpuStatus = acpiR3Port_GetCpuStatus;
+ pThis->IACPIPort.pfnMonitorHotPlugEvent = acpiR3Port_MonitorHotPlugEvent;
/*
* Set the default critical section to NOP (related to the PM timer).
diff --git a/src/VBox/Devices/PC/vbox.dsl b/src/VBox/Devices/PC/vbox.dsl
index 3703b77a9a8..4689c204b1a 100644
--- a/src/VBox/Devices/PC/vbox.dsl
+++ b/src/VBox/Devices/PC/vbox.dsl
@@ -909,6 +909,39 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
}
}
+ // Graphics device
+ Device (GFX0)
+ {
+ Name (_ADR, 0x00020000)
+
+ Scope (\_GPE)
+ {
+ // GPE bit 2 handler
+ // GPE.2 must be set and SCI raised when
+ // display information changes.
+ Method (_L02, 0, NotSerialized)
+ {
+ Notify (\_SB.PCI0.GFX0, 0x81)
+ }
+ }
+
+ Method (_DOD, 0, NotSerialized)
+ {
+ Return (Package()
+ {
+ 0x80000100
+ })
+ }
+
+ Device (VGA)
+ {
+ Method (_ADR, 0, Serialized)
+ {
+ Return (0x0100)
+ }
+ }
+ }
+
// HDA Audio card
Device (HDEF)
{
diff --git a/src/VBox/Main/include/ConsoleImpl.h b/src/VBox/Main/include/ConsoleImpl.h
index 3f2aa1a6368..077876bb09c 100644
--- a/src/VBox/Main/include/ConsoleImpl.h
+++ b/src/VBox/Main/include/ConsoleImpl.h
@@ -249,6 +249,7 @@ public:
void i_onRuntimeError(BOOL aFatal, IN_BSTR aErrorID, IN_BSTR aMessage);
HRESULT i_onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId);
void i_onVRDEServerInfoChange();
+ HRESULT i_sendACPIMonitorHotPlugEvent();
static const PDMDRVREG DrvStatusReg;
diff --git a/src/VBox/Main/include/DisplayImpl.h b/src/VBox/Main/include/DisplayImpl.h
index b8ca4d37906..fc23ce28f79 100644
--- a/src/VBox/Main/include/DisplayImpl.h
+++ b/src/VBox/Main/include/DisplayImpl.h
@@ -147,6 +147,8 @@ public:
int i_handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM, uint32_t cbLine,
uint32_t w, uint32_t h, uint16_t flags);
void i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h);
+ void i_handleUpdateVMMDevSupportsGraphics(bool fSupportsGraphics);
+ void i_handleUpdateGuestVBVACapabilities(uint32_t fNewCapabilities);
#ifdef VBOX_WITH_VIDEOHWACCEL
int i_handleVHWACommandProcess(PVBOXVHWACMD pCommand);
#endif
@@ -326,6 +328,7 @@ private:
static DECLCALLBACK(int) i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
uint32_t xHot, uint32_t yHot, uint32_t cx, uint32_t cy,
const void *pvShape);
+ static DECLCALLBACK(void) i_displayVBVAGuestCapabilityUpdate(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities);
#endif
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
@@ -356,6 +359,12 @@ private:
unsigned mcMonitors;
DISPLAYFBINFO maFramebuffers[SchemaDefs::MaxGuestMonitors];
+ /** Does the VMM device have the "supports graphics" capability set?
+ * Does not go into the saved state as it is refreshed on restore. */
+ bool mfVMMDevSupportsGraphics;
+ /** Mirror of the current guest VBVA capabilities.
+ * Does not go into the saved state as it is refreshed on restore. */
+ uint32_t mfGuestVBVACapabilities;
bool mfSourceBitmapEnabled;
bool volatile fVGAResizing;
@@ -425,6 +434,8 @@ private:
static int i_InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll);
static int i_drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height);
+ void i_updateGuestGraphicsFacility(void);
+
#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
int i_crOglWindowsShow(bool fShow);
#endif
diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp
index 45e4c680f83..d4da370f72c 100644
--- a/src/VBox/Main/src-client/ConsoleImpl.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl.cpp
@@ -5185,6 +5185,47 @@ void Console::i_onVRDEServerInfoChange()
fireVRDEServerInfoChangedEvent(mEventSource);
}
+HRESULT Console::i_sendACPIMonitorHotPlugEvent()
+{
+ LogFlowThisFuncEnter();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if ( mMachineState != MachineState_Running
+ && mMachineState != MachineState_Teleporting
+ && mMachineState != MachineState_LiveSnapshotting)
+ return i_setInvalidMachineStateError();
+
+ /* get the VM handle. */
+ SafeVMPtr ptrVM(this);
+ if (!ptrVM.isOk())
+ return ptrVM.rc();
+
+ // no need to release lock, as there are no cross-thread callbacks
+
+ /* get the acpi device interface and press the sleep button. */
+ PPDMIBASE pBase;
+ int vrc = PDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
+ if (RT_SUCCESS(vrc))
+ {
+ Assert(pBase);
+ PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
+ if (pPort)
+ vrc = pPort->pfnMonitorHotPlugEvent(pPort);
+ else
+ vrc = VERR_PDM_MISSING_INTERFACE;
+ }
+
+ HRESULT rc = RT_SUCCESS(vrc) ? S_OK :
+ setError(VBOX_E_PDM_ERROR,
+ tr("Sending monitor hot-plug event failed (%Rrc)"),
+ vrc);
+
+ LogFlowThisFunc(("rc=%Rhrc\n", rc));
+ LogFlowThisFuncLeave();
+ return rc;
+}
+
HRESULT Console::i_onVideoCaptureChange()
{
AutoCaller autoCaller(this);
diff --git a/src/VBox/Main/src-client/DisplayImpl.cpp b/src/VBox/Main/src-client/DisplayImpl.cpp
index 17c1fa41186..c3c94d603c5 100644
--- a/src/VBox/Main/src-client/DisplayImpl.cpp
+++ b/src/VBox/Main/src-client/DisplayImpl.cpp
@@ -19,6 +19,7 @@
#include "DisplayUtils.h"
#include "ConsoleImpl.h"
#include "ConsoleVRDPServer.h"
+#include "GuestImpl.h"
#include "VMMDev.h"
#include "AutoCaller.h"
@@ -121,6 +122,8 @@ HRESULT Display::FinalConstruct()
#ifdef VBOX_WITH_HGSMI
mu32UpdateVBVAFlags = 0;
+ mfVMMDevSupportsGraphics = false;
+ mfGuestVBVACapabilities = 0;
#endif
#ifdef VBOX_WITH_VPX
mpVideoRecCtx = NULL;
@@ -1033,6 +1036,51 @@ void Display::i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int
}
}
+void Display::i_updateGuestGraphicsFacility(void)
+{
+ Guest* pGuest = mParent->i_getGuest();
+ AssertPtrReturnVoid(pGuest);
+ /* 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. */
+ RTTIMESPEC TimeSpecTS;
+ RTTimeNow(&TimeSpecTS);
+
+ if ( mfVMMDevSupportsGraphics
+ || (mfGuestVBVACapabilities & VBVACAPS_VIDEO_MODE_HINTS) != 0)
+ pGuest->i_setAdditionsStatus(VBoxGuestFacilityType_Graphics,
+ VBoxGuestFacilityStatus_Active,
+ 0 /*fFlags*/, &TimeSpecTS);
+ else
+ pGuest->i_setAdditionsStatus(VBoxGuestFacilityType_Graphics,
+ VBoxGuestFacilityStatus_Inactive,
+ 0 /*fFlags*/, &TimeSpecTS);
+}
+
+void Display::i_handleUpdateVMMDevSupportsGraphics(bool fSupportsGraphics)
+{
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ if (mfVMMDevSupportsGraphics == fSupportsGraphics)
+ return;
+ mfVMMDevSupportsGraphics = fSupportsGraphics;
+ i_updateGuestGraphicsFacility();
+ /* The VMMDev interface notifies the console. */
+}
+
+void Display::i_handleUpdateGuestVBVACapabilities(uint32_t fNewCapabilities)
+{
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ bool fNotify = (fNewCapabilities & VBVACAPS_VIDEO_MODE_HINTS) != 0;
+
+ mfGuestVBVACapabilities = fNewCapabilities;
+ if (!fNotify)
+ return;
+ i_updateGuestGraphicsFacility();
+ /* Tell the console about it */
+ mParent->i_onAdditionsStateChange();
+}
+
/**
* Returns the upper left and lower right corners of the virtual framebuffer.
* The lower right is "exclusive" (i.e. first pixel beyond the framebuffer),
@@ -1636,6 +1684,27 @@ HRESULT Display::setVideoModeHint(ULONG aDisplay, BOOL aEnabled,
* will call EMT. */
alock.release();
+ /* 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. */
+ mpDrv->pUpPort->pfnSendModeHint(mpDrv->pUpPort, aWidth, aHeight,
+ aBitsPerPixel, aDisplay,
+ aChangeOrigin ? aOriginX : ~0,
+ aChangeOrigin ? aOriginY : ~0,
+ RT_BOOL(aEnabled),
+ mfGuestVBVACapabilities
+ & VBVACAPS_VIDEO_MODE_HINTS);
+ if ( mfGuestVBVACapabilities & VBVACAPS_VIDEO_MODE_HINTS
+ && !(mfGuestVBVACapabilities & VBVACAPS_IRQ))
+ {
+ HRESULT hrc = mParent->i_sendACPIMonitorHotPlugEvent();
+ if (FAILED(hrc))
+ 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. */
VMMDev *pVMMDev = mParent->i_getVMMDev();
if (pVMMDev)
{
@@ -3780,6 +3849,16 @@ DECLCALLBACK(int) Display::i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR
return VINF_SUCCESS;
}
+
+DECLCALLBACK(void) Display::i_displayVBVAGuestCapabilityUpdate(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities)
+{
+ LogFlowFunc(("\n"));
+
+ PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
+ Display *pThis = pDrv->pDisplay;
+
+ pThis->i_handleUpdateGuestVBVACapabilities(fCapabilities);
+}
#endif /* VBOX_WITH_HGSMI */
/**
@@ -3880,6 +3959,7 @@ DECLCALLBACK(int) Display::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, ui
pThis->IConnector.pfnVBVAUpdateEnd = Display::i_displayVBVAUpdateEnd;
pThis->IConnector.pfnVBVAResize = Display::i_displayVBVAResize;
pThis->IConnector.pfnVBVAMousePointerShape = Display::i_displayVBVAMousePointerShape;
+ pThis->IConnector.pfnVBVAGuestCapabilityUpdate = Display::i_displayVBVAGuestCapabilityUpdate;
#endif
/*
diff --git a/src/VBox/Main/src-client/GuestImpl.cpp b/src/VBox/Main/src-client/GuestImpl.cpp
index 958f91d6cd3..d5f2dec2589 100644
--- a/src/VBox/Main/src-client/GuestImpl.cpp
+++ b/src/VBox/Main/src-client/GuestImpl.cpp
@@ -1082,8 +1082,5 @@ void Guest::i_setSupportedFeatures(uint32_t aCaps)
aCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
0 /*fFlags*/, &TimeSpecTS);
/** @todo Add VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING */
- i_facilityUpdate(VBoxGuestFacilityType_Graphics,
- aCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
- 0 /*fFlags*/, &TimeSpecTS);
}
diff --git a/src/VBox/Main/src-client/VMMDevInterface.cpp b/src/VBox/Main/src-client/VMMDevInterface.cpp
index d4c721d5891..675ad2f4e8a 100644
--- a/src/VBox/Main/src-client/VMMDevInterface.cpp
+++ b/src/VBox/Main/src-client/VMMDevInterface.cpp
@@ -291,6 +291,15 @@ DECLCALLBACK(void) vmmdevUpdateGuestCapabilities(PPDMIVMMDEVCONNECTOR pInterface
pGuest->i_setSupportedFeatures(newCapabilities);
/*
+ * Tell the Display, so that it can update the "supports graphics"
+ * capability if the graphics card has not asserted it.
+ */
+ Display* pDisplay = pConsole->i_getDisplay();
+ AssertPtrReturnVoid(pDisplay);
+ pDisplay->i_handleUpdateVMMDevSupportsGraphics(newCapabilities
+ & VMMDEV_GUEST_SUPPORTS_GRAPHICS);
+
+ /*
* Tell the console interface about the event
* so that it can notify its consumers.
*/