diff options
-rw-r--r-- | include/VBox/HGSMI/HGSMIChSetup.h | 2 | ||||
-rw-r--r-- | include/VBox/VBoxVideo.h | 37 | ||||
-rw-r--r-- | include/VBox/vmm/pdmifs.h | 44 | ||||
-rw-r--r-- | src/VBox/Devices/Graphics/DevVGA.cpp | 1 | ||||
-rw-r--r-- | src/VBox/Devices/Graphics/DevVGA.h | 5 | ||||
-rw-r--r-- | src/VBox/Devices/Graphics/DevVGA_VBVA.cpp | 98 | ||||
-rw-r--r-- | src/VBox/Devices/PC/DevACPI.cpp | 19 | ||||
-rw-r--r-- | src/VBox/Devices/PC/vbox.dsl | 33 | ||||
-rw-r--r-- | src/VBox/Main/include/ConsoleImpl.h | 1 | ||||
-rw-r--r-- | src/VBox/Main/include/DisplayImpl.h | 11 | ||||
-rw-r--r-- | src/VBox/Main/src-client/ConsoleImpl.cpp | 41 | ||||
-rw-r--r-- | src/VBox/Main/src-client/DisplayImpl.cpp | 80 | ||||
-rw-r--r-- | src/VBox/Main/src-client/GuestImpl.cpp | 3 | ||||
-rw-r--r-- | src/VBox/Main/src-client/VMMDevInterface.cpp | 9 |
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. */ |