diff options
Diffstat (limited to 'src/VBox/Devices/Graphics/DevVGA_VBVA.cpp')
-rw-r--r-- | src/VBox/Devices/Graphics/DevVGA_VBVA.cpp | 408 |
1 files changed, 382 insertions, 26 deletions
diff --git a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp index 01269b17..ed727b13 100644 --- a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp +++ b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp @@ -1,9 +1,10 @@ +/* $Id: DevVGA_VBVA.cpp $ */ /** @file * VirtualBox Video Acceleration (VBVA). */ /* - * Copyright (C) 2006-2009 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -14,6 +15,9 @@ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ +/******************************************************************************* +* Header Files * +*******************************************************************************/ #define LOG_GROUP LOG_GROUP_DEV_VGA #include <VBox/vmm/pdmifs.h> #include <VBox/vmm/pdmdev.h> @@ -36,9 +40,12 @@ #if 0 // def DEBUG_sunlover #define LOGVBVABUFFER(a) LogFlow(a) #else -#define LOGVBVABUFFER(a) do {} while(0) +#define LOGVBVABUFFER(a) do {} while (0) #endif +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ typedef struct VBVAPARTIALRECORD { uint8_t *pu8; @@ -68,20 +75,23 @@ typedef struct VBVAMOUSESHAPEINFO uint8_t *pu8Shape; } VBVAMOUSESHAPEINFO; -/* @todo saved state: save and restore VBVACONTEXT */ +/** @todo saved state: save and restore VBVACONTEXT */ typedef struct VBVACONTEXT { uint32_t cViews; VBVAVIEW aViews[64 /* @todo SchemaDefs::MaxGuestMonitors*/]; VBVAMOUSESHAPEINFO mouseShapeInfo; + bool fPaused; } VBVACONTEXT; -/* Copies 'cb' bytes from the VBVA ring buffer to the 'pu8Dst'. + + +/** Copies @a cb bytes from the VBVA ring buffer to the @a pu8Dst. * Used for partial records or for records which cross the ring boundary. */ static void vbvaFetchBytes (VBVABUFFER *pVBVA, uint8_t *pu8Dst, uint32_t cb) { - /* @todo replace the 'if' with an assert. The caller must ensure this condition. */ + /** @todo replace the 'if' with an assert. The caller must ensure this condition. */ if (cb >= pVBVA->cbData) { AssertMsgFailed (("cb = 0x%08X, ring buffer size 0x%08X", cb, pVBVA->cbData)); @@ -620,6 +630,13 @@ static int vbvaMousePointerShape (PVGASTATE pVGAState, VBVACONTEXT *pCtx, const if (fShape) { + if (pShape->u32Width > 8192 || pShape->u32Height > 8192) + { + Log(("vbvaMousePointerShape: unsupported size %ux%u\n", + pShape->u32Width, pShape->u32Height)); + return VERR_INVALID_PARAMETER; + } + cbPointerData = ((((pShape->u32Width + 7) / 8) * pShape->u32Height + 3) & ~3) + pShape->u32Width * 4 * pShape->u32Height; } @@ -757,7 +774,7 @@ static void vbvaVHWAHHCommandReinit(VBOXVHWACMD* pHdr, VBOXVHWACMD_TYPE enmCmd, static VBOXVHWACMD* vbvaVHWAHHCommandCreate (PVGASTATE pVGAState, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd) { - VBOXVHWACMD* pHdr = (VBOXVHWACMD*)RTMemAlloc(cbCmd + VBOXVHWACMD_HEADSIZE()); + VBOXVHWACMD* pHdr = (VBOXVHWACMD*)RTMemAllocZ(cbCmd + VBOXVHWACMD_HEADSIZE()); Assert(pHdr); if (pHdr) vbvaVHWAHHCommandReinit(pHdr, enmCmd, iDisplay); @@ -779,15 +796,237 @@ DECLINLINE(void) vbvaVHWAHHCommandRetain (VBOXVHWACMD* pCmd) ASMAtomicIncU32(&pCmd->cRefs); } -static unsigned vbvaVHWAHandleCommand (PVGASTATE pVGAState, VBVACONTEXT *pCtx, PVBOXVHWACMD pCmd) +static void vbvaVHWACommandComplete(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand) +{ + if (fAsyncCommand) + { + Assert(pCommand->Flags & VBOXVHWACMD_FLAG_HG_ASYNCH); + vbvaVHWACommandCompleteAsynch(&pVGAState->IVBVACallbacks, pCommand); + } + else + { + Log(("VGA Command <<< Sync rc %d %#p, %d\n", pCommand->rc, pCommand, pCommand->enmCmd)); + pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH); + } + +} + +static void vbvaVHWACommandCompleteAllPending(PVGASTATE pVGAState, int rc) +{ + if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending)) + return; + + VBOX_VHWA_PENDINGCMD *pIter, *pNext; + + PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY); + + RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node) + { + pIter->pCommand->rc = rc; + vbvaVHWACommandComplete(pVGAState, pIter->pCommand, true); + + /* the command is submitted/processed, remove from the pend list */ + RTListNodeRemove(&pIter->Node); + ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending); + RTMemFree(pIter); + } + + PDMCritSectLeave(&pVGAState->CritSect); +} + +static void vbvaVHWACommandClearAllPending(PVGASTATE pVGAState) +{ + if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending)) + return; + + VBOX_VHWA_PENDINGCMD *pIter, *pNext; + + PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY); + + RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node) + { + RTListNodeRemove(&pIter->Node); + ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending); + RTMemFree(pIter); + } + + PDMCritSectLeave(&pVGAState->CritSect); +} + +static void vbvaVHWACommandPend(PVGASTATE pVGAState, PVBOXVHWACMD pCommand) +{ + int rc = VERR_BUFFER_OVERFLOW; + + if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS) + { + VBOX_VHWA_PENDINGCMD *pPend = (VBOX_VHWA_PENDINGCMD*)RTMemAlloc(sizeof (*pPend)); + if (pPend) + { + pCommand->Flags |= VBOXVHWACMD_FLAG_HG_ASYNCH; + pPend->pCommand = pCommand; + PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY); + if (ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending) < VBOX_VHWA_MAX_PENDING_COMMANDS) + { + RTListAppend(&pVGAState->pendingVhwaCommands.PendingList, &pPend->Node); + ASMAtomicIncU32(&pVGAState->pendingVhwaCommands.cPending); + PDMCritSectLeave(&pVGAState->CritSect); + return; + } + PDMCritSectLeave(&pVGAState->CritSect); + LogRel(("Pending command count has reached its threshold.. completing them all..")); + RTMemFree(pPend); + } + else + rc = VERR_NO_MEMORY; + } + else + LogRel(("Pending command count has reached its threshold, completing them all..")); + + vbvaVHWACommandCompleteAllPending(pVGAState, rc); + + pCommand->rc = rc; + + vbvaVHWACommandComplete(pVGAState, pCommand, false); +} + +static bool vbvaVHWACommandCanPend(PVBOXVHWACMD pCommand) +{ + switch (pCommand->enmCmd) + { + case VBOXVHWACMD_TYPE_HH_CONSTRUCT: + case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN: + case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND: + case VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM: + case VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM: + return false; + default: + return true; + } +} + +static int vbvaVHWACommandSavePending(PVGASTATE pVGAState, PSSMHANDLE pSSM) +{ + int rc = SSMR3PutU32(pSSM, pVGAState->pendingVhwaCommands.cPending); + AssertRCReturn(rc, rc); + VBOX_VHWA_PENDINGCMD *pIter; + RTListForEach(&pVGAState->pendingVhwaCommands.PendingList, pIter, VBOX_VHWA_PENDINGCMD, Node) + { + rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pIter->pCommand) - ((uint8_t*)pVGAState->vram_ptrR3))); + AssertRCReturn(rc, rc); + } + return rc; +} + +static int vbvaVHWACommandLoadPending(PVGASTATE pVGAState, PSSMHANDLE pSSM, uint32_t u32Version) { + if (u32Version < VGA_SAVEDSTATE_VERSION_WITH_PENDVHWA) + return VINF_SUCCESS; + + int rc; + uint32_t u32; + rc = SSMR3GetU32(pSSM, &u32); + AssertRCReturn(rc, rc); + for (uint32_t i = 0; i < u32; ++i) + { + uint32_t off32; + rc = SSMR3GetU32(pSSM, &off32); + AssertRCReturn(rc, rc); + PVBOXVHWACMD pCommand = (PVBOXVHWACMD)(((uint8_t*)pVGAState->vram_ptrR3) + off32); + vbvaVHWACommandPend(pVGAState, pCommand); + } + return rc; +} + + +static bool vbvaVHWACommandSubmit(PVGASTATE pVGAState, PVBOXVHWACMD pCommand, bool fAsyncCommand) +{ + unsigned id = (unsigned)pCommand->iDisplay; + bool fPend = false; + if (pVGAState->pDrv->pfnVHWACommandProcess) - pVGAState->pDrv->pfnVHWACommandProcess(pVGAState->pDrv, pCmd); -#ifdef DEBUG_misha + { + Log(("VGA Command >>> %#p, %d\n", pCommand, pCommand->enmCmd)); + int rc = pVGAState->pDrv->pfnVHWACommandProcess(pVGAState->pDrv, pCommand); + if (rc == VINF_CALLBACK_RETURN) + { + Log(("VGA Command --- Going Async %#p, %d\n", pCommand, pCommand->enmCmd)); + return true; /* command will be completed asynchronously, return right away */ + } + else if (rc == VERR_INVALID_STATE) + { + Log(("VGA Command --- Trying Pend %#p, %d\n", pCommand, pCommand->enmCmd)); + fPend = vbvaVHWACommandCanPend(pCommand); + if (!fPend) + { + Log(("VGA Command --- Can NOT Pend %#p, %d\n", pCommand, pCommand->enmCmd)); + pCommand->rc = rc; + } + else + Log(("VGA Command --- Can Pend %#p, %d\n", pCommand, pCommand->enmCmd)); + } + else + { + Log(("VGA Command --- Going Complete Sync rc %d %#p, %d\n", rc, pCommand, pCommand->enmCmd)); + pCommand->rc = rc; + } + + /* the command was completed, take a special care about it (seee below) */ + } else + { AssertFailed(); -#endif - return 0; + pCommand->rc = VERR_INVALID_STATE; + } + + if (fPend) + return false; + + vbvaVHWACommandComplete(pVGAState, pCommand, fAsyncCommand); + + return true; +} + +static bool vbvaVHWACheckPendingCommands(PVGASTATE pVGAState) +{ + if (!ASMAtomicUoReadU32(&pVGAState->pendingVhwaCommands.cPending)) + return true; + + VBOX_VHWA_PENDINGCMD *pIter, *pNext; + + PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY); + + RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node) + { + if (!vbvaVHWACommandSubmit(pVGAState, pIter->pCommand, true)) + { + PDMCritSectLeave(&pVGAState->CritSect); + return false; /* the command should be pended still */ + } + + /* the command is submitted/processed, remove from the pend list */ + RTListNodeRemove(&pIter->Node); + ASMAtomicDecU32(&pVGAState->pendingVhwaCommands.cPending); + RTMemFree(pIter); + } + + PDMCritSectLeave(&pVGAState->CritSect); + + return true; +} + +void vbvaTimerCb(PVGASTATE pVGAState) +{ + vbvaVHWACheckPendingCommands(pVGAState); +} +static void vbvaVHWAHandleCommand(PVGASTATE pVGAState, PVBOXVHWACMD pCmd) +{ + if (vbvaVHWACheckPendingCommands(pVGAState)) + { + if (vbvaVHWACommandSubmit(pVGAState, pCmd, false)) + return; + } + + vbvaVHWACommandPend(pVGAState, pCmd); } static DECLCALLBACK(void) vbvaVHWAHHCommandSetEventCallback(void * pContext) @@ -805,7 +1044,7 @@ static int vbvaVHWAHHCommandPost(PVGASTATE pVGAState, VBOXVHWACMD* pCmd) /* ensure the cmd is not deleted until we process it */ vbvaVHWAHHCommandRetain (pCmd); VBOXVHWA_HH_CALLBACK_SET(pCmd, vbvaVHWAHHCommandSetEventCallback, (void*)hComplEvent); - vbvaVHWAHandleCommand(pVGAState, NULL, pCmd); + vbvaVHWAHandleCommand(pVGAState, pCmd); if((ASMAtomicReadU32((volatile uint32_t *)&pCmd->Flags) & VBOXVHWACMD_FLAG_HG_ASYNCH) != 0) { rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT); @@ -827,6 +1066,9 @@ static int vbvaVHWAHHCommandPost(PVGASTATE pVGAState, VBOXVHWACMD* pCmd) int vbvaVHWAConstruct (PVGASTATE pVGAState) { + pVGAState->pendingVhwaCommands.cPending = 0; + RTListInit(&pVGAState->pendingVhwaCommands.PendingList); + VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT)); Assert(pCmd); if(pCmd) @@ -880,6 +1122,8 @@ int vbvaVHWAConstruct (PVGASTATE pVGAState) int vbvaVHWAReset (PVGASTATE pVGAState) { + vbvaVHWACommandClearAllPending(pVGAState); + /* ensure we have all pending cmds processed and h->g cmds disabled */ VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_RESET, 0, 0); Assert(pCmd); @@ -999,6 +1243,8 @@ int vboxVBVASaveStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM) int vbvaVHWACommandCompleteAsynch(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVHWACMD pCmd) { int rc; + Log(("VGA Command <<< Async rc %d %#p, %d\n", pCmd->rc, pCmd, pCmd->enmCmd)); + if((pCmd->Flags & VBOXVHWACMD_FLAG_HH_CMD) == 0) { PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface); @@ -1384,6 +1630,9 @@ int vboxVBVASaveStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM) AssertRC(rc); if (RT_SUCCESS(rc)) { + rc = vbvaVHWACommandSavePending(pVGAState, pSSM); + AssertRCReturn(rc, rc); + vbvaVHWAHHCommandReinit(pCmd, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND, 0); vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVASaveStateEndPreCb, NULL, &VhwaData); rc = VhwaData.rc; @@ -1497,8 +1746,7 @@ int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Vers AssertRCReturn(rc, rc); } - if ( pView->u32VBVAOffset == HGSMIOFFSET_VOID - || pView->screen.u32LineSize == 0) /* Earlier broken saved states. */ + if (pView->u32VBVAOffset == HGSMIOFFSET_VOID) { pView->pVBVA = NULL; } @@ -1579,8 +1827,11 @@ int vboxVBVALoadStateExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t u32Vers pLoad->pSSM = pSSM; vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData); rc = VhwaData.rc; - AssertRC(rc); vbvaVHWAHHCommandRelease(pCmd); + AssertRCReturn(rc, rc); + + rc = vbvaVHWACommandLoadPending(pVGAState, pSSM, u32Version); + AssertRCReturn(rc, rc); } else { @@ -1632,12 +1883,26 @@ int vboxVBVALoadStateDone (PPDMDEVINS pDevIns, PSSMHANDLE pSSM) void VBVARaiseIrq (PVGASTATE pVGAState, uint32_t fFlags) { PPDMDEVINS pDevIns = pVGAState->pDevInsR3; - PDMCritSectEnter(&pVGAState->lock, VERR_SEM_BUSY); + PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY); + HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags); PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH); - PDMCritSectLeave(&pVGAState->lock); + + PDMCritSectLeave(&pVGAState->CritSect); } +void VBVARaiseIrqNoWait(PVGASTATE pVGAState, uint32_t fFlags) +{ + PPDMDEVINS pDevIns = pVGAState->pDevInsR3; + PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY); + + HGSMISetHostGuestFlags(pVGAState->pHGSMI, HGSMIHOSTFLAGS_IRQ | fFlags); + PDMDevHlpPCISetIrqNoWait(pDevIns, 0, PDM_IRQ_LEVEL_HIGH); + + PDMCritSectLeave(&pVGAState->CritSect); +} + + /* * * New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01 @@ -1653,7 +1918,7 @@ static DECLCALLBACK(void) vbvaNotifyGuest (void *pvCallback) { #if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM)) PVGASTATE pVGAState = (PVGASTATE)pvCallback; - VBVARaiseIrq (pVGAState, 0); + VBVARaiseIrqNoWait (pVGAState, 0); #else NOREF(pvCallback); /* Do nothing. Later the VMMDev/VGA IRQ can be used for the notification. */ @@ -1674,6 +1939,32 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe switch (u16ChannelInfo) { + case VBVA_CMDVBVA_SUBMIT: + { + rc = vboxCmdVBVACmdSubmit(pVGAState); + break; + } + case VBVA_CMDVBVA_FLUSH: + { + rc =vboxCmdVBVACmdFlush(pVGAState); + break; + } + case VBVA_CMDVBVA_CTL: + { + if (cbBuffer < VBoxSHGSMIBufferHeaderSize() + sizeof (VBOXCMDVBVA_CTL)) + { + Log(("buffer too small\n")); +#ifdef DEBUG_misha + AssertMsgFailed(("buffer too small\n")); +#endif + rc = VERR_INVALID_PARAMETER; + break; + } + + VBOXCMDVBVA_CTL *pCtl = (VBOXCMDVBVA_CTL*)VBoxSHGSMIBufferData((PVBOXSHGSMIHEADER)pvBuffer); + rc = vboxCmdVBVACmdCtl(pVGAState, pCtl, cbBuffer - VBoxSHGSMIBufferHeaderSize()); + break; + } #ifdef VBOX_WITH_VDMA case VBVA_VDMA_CMD: { @@ -1833,7 +2124,7 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe * implemented. */ int64_t offEnd = (int64_t)pScreen->u32Height * pScreen->u32LineSize + pScreen->u32Width + pScreen->u32StartOffset; - LogRelFlowFunc(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n", + LogRel(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n", pScreen->u32ViewIndex, pScreen->i32OriginX, pScreen->i32OriginY, pScreen->u32Width, pScreen->u32Height, pScreen->u32LineSize, pScreen->u16BitsPerPixel, pScreen->u16Flags)); @@ -1962,7 +2253,14 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe #ifdef VBOX_WITH_VIDEOHWACCEL case VBVA_VHWA_CMD: { - rc = vbvaVHWAHandleCommand (pVGAState, pCtx, (PVBOXVHWACMD)pvBuffer); + if (cbBuffer < sizeof (VBOXVHWACMD)) + { + rc = VERR_INVALID_PARAMETER; + break; + } + vbvaVHWAHandleCommand(pVGAState, (PVBOXVHWACMD)pvBuffer); + rc = VINF_SUCCESS; + break; } break; #endif @@ -2001,6 +2299,24 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe return rc; } +/* When VBVA is paused, then VGA device is allowed to work but + * no HGSMI etc state is changed. + */ +void VBVAPause(PVGASTATE pVGAState, bool fPause) +{ + if (!pVGAState || !pVGAState->pHGSMI) + { + return; + } + + VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext(pVGAState->pHGSMI); + + if (pCtx) + { + pCtx->fPaused = fPause; + } +} + void VBVAReset (PVGASTATE pVGAState) { if (!pVGAState || !pVGAState->pHGSMI) @@ -2049,14 +2365,17 @@ int VBVAUpdateDisplay (PVGASTATE pVGAState) if (pCtx) { - rc = vbvaFlush (pVGAState, pCtx); - - if (RT_SUCCESS (rc)) + if (!pCtx->fPaused) { - if (!pCtx->aViews[0].pVBVA) + rc = vbvaFlush (pVGAState, pCtx); + + if (RT_SUCCESS (rc)) { - /* VBVA is not enabled for the first view, so VGA device must do updates. */ - rc = VERR_NOT_SUPPORTED; + if (!pCtx->aViews[0].pVBVA) + { + /* VBVA is not enabled for the first view, so VGA device must do updates. */ + rc = VERR_NOT_SUPPORTED; + } } } } @@ -2093,6 +2412,7 @@ int VBVAInit (PVGASTATE pVGAState) { VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pVGAState->pHGSMI); pCtx->cViews = pVGAState->cMonitors; + pCtx->fPaused = true; } } @@ -2116,3 +2436,39 @@ void VBVADestroy (PVGASTATE pVGAState) HGSMIDestroy (pVGAState->pHGSMI); pVGAState->pHGSMI = NULL; } + +int VBVAGetScreenInfo(PVGASTATE pVGAState, unsigned uScreenId, struct VBVAINFOSCREEN *pScreen, void **ppvVram) +{ + PPDMDEVINS pDevIns = pVGAState->pDevInsR3; + PHGSMIINSTANCE pIns = pVGAState->pHGSMI; + VBVACONTEXT *pCtx = (VBVACONTEXT *)HGSMIContext (pIns); + int rc = PDMCritSectEnter(&pVGAState->CritSect, VERR_SEM_BUSY); + if (RT_SUCCESS(rc)) + { + if (uScreenId < pCtx->cViews) + { + VBVAVIEW *pView = &pCtx->aViews[uScreenId]; + if (pView->pVBVA) + { + uint8_t *pu8VRAM = pVGAState->vram_ptrR3 + pView->view.u32ViewOffset; + *pScreen = pView->screen; + *ppvVram = (void*)pu8VRAM; + rc = VINF_SUCCESS; + } + else + { + /* pretend disabled */ + memset(pScreen, 0, sizeof (*pScreen)); + pScreen->u16Flags = VBVA_SCREEN_F_DISABLED; + pScreen->u32ViewIndex = uScreenId; + *ppvVram = NULL; + rc = VINF_SUCCESS; + } + } + else + rc = VERR_INVALID_PARAMETER; + + PDMCritSectLeave(&pVGAState->CritSect); + } + return rc; +} |