diff options
author | Gianfranco Costamagna <costamagnagianfranco@yahoo.it> | 2014-03-10 10:14:28 +0100 |
---|---|---|
committer | Gianfranco Costamagna <costamagnagianfranco@yahoo.it> | 2014-03-10 10:14:28 +0100 |
commit | 1e85aed889b772c2f2daa7a6d9e8bd967aa213d8 (patch) | |
tree | c1f9c44de9363e60eb2bf3f2ddf7f6b3c0c574cb /src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp | |
parent | a0f18d47861c16d7dc3a1b7b8f177a076b14051e (diff) | |
download | virtualbox-1e85aed889b772c2f2daa7a6d9e8bd967aa213d8.tar.gz |
Imported Upstream version 4.3.8-dfsg
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp')
-rw-r--r-- | src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp | 4634 |
1 files changed, 4095 insertions, 539 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp index 0c9354cca..49fa537cd 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp @@ -25,664 +25,3322 @@ #include "cr_mem.h" #include "cr_string.h" #include <cr_vreg.h> +#include <cr_htable.h> +#include <cr_bmpscale.h> #include <iprt/cdefs.h> #include <iprt/types.h> #include <iprt/asm.h> #include <iprt/mem.h> #include <iprt/list.h> -#include <iprt/memcache.h> + + +#ifdef DEBUG_misha +# define VBOXVDBG_MEMCACHE_DISABLE +#endif + +#ifndef VBOXVDBG_MEMCACHE_DISABLE +# include <iprt/memcache.h> +#endif #include "render/renderspu.h" -/* DISPLAY */ +class ICrFbDisplay +{ +public: + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) = 0; + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) = 0; + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) = 0; + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) = 0; + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) = 0; + + virtual ~ICrFbDisplay() {} +}; + +class CrFbDisplayComposite; +class CrFbDisplayBase; +class CrFbDisplayWindow; +class CrFbDisplayWindowRootVr; +class CrFbDisplayVrdp; + +typedef struct CR_FRAMEBUFFER +{ + VBOXVR_SCR_COMPOSITOR Compositor; + struct VBVAINFOSCREEN ScreenInfo; + void *pvVram; + ICrFbDisplay *pDisplay; + RTLISTNODE EntriesList; + uint32_t cEntries; /* <- just for debugging */ + uint32_t cUpdating; + CRHTABLE SlotTable; +} CR_FRAMEBUFFER; + +typedef union CR_FBENTRY_FLAGS +{ + struct { + uint32_t fCreateNotified : 1; + uint32_t fInList : 1; + uint32_t Reserved : 30; + }; + uint32_t Value; +} CR_FBENTRY_FLAGS; + +typedef struct CR_FRAMEBUFFER_ENTRY +{ + VBOXVR_SCR_COMPOSITOR_ENTRY Entry; + RTLISTNODE Node; + uint32_t cRefs; + CR_FBENTRY_FLAGS Flags; + CRHTABLE HTable; +} CR_FRAMEBUFFER_ENTRY; + +typedef struct CR_FBTEX +{ + CR_TEXDATA Tex; + CRTextureObj *pTobj; +} CR_FBTEX; + +#define PCR_FBTEX_FROM_TEX(_pTex) ((CR_FBTEX*)((uint8_t*)(_pTex) - RT_OFFSETOF(CR_FBTEX, Tex))) +#define PCR_FRAMEBUFFER_FROM_COMPOSITOR(_pCompositor) ((CR_FRAMEBUFFER*)((uint8_t*)(_pCompositor) - RT_OFFSETOF(CR_FRAMEBUFFER, Compositor))) +#define PCR_FBENTRY_FROM_ENTRY(_pEntry) ((CR_FRAMEBUFFER_ENTRY*)((uint8_t*)(_pEntry) - RT_OFFSETOF(CR_FRAMEBUFFER_ENTRY, Entry))) + + +typedef struct CR_FBDISPLAY_INFO +{ + uint32_t u32Mode; + CrFbDisplayWindow *pDpWin; + CrFbDisplayWindowRootVr *pDpWinRootVr; + CrFbDisplayVrdp *pDpVrdp; + CrFbDisplayComposite *pDpComposite; +} CR_FBDISPLAY_INFO; + +typedef struct CR_PRESENTER_GLOBALS +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMEMCACHE FbEntryLookasideList; + RTMEMCACHE FbTexLookasideList; + RTMEMCACHE CEntryLookasideList; +#endif + uint32_t u32DisplayMode; + CRHashTable *pFbTexMap; + CR_FBDISPLAY_INFO aDisplayInfos[CR_MAX_GUEST_MONITORS]; + CR_FBMAP FramebufferInitMap; + CR_FRAMEBUFFER aFramebuffers[CR_MAX_GUEST_MONITORS]; + bool fWindowsForceHidden; + uint32_t cbTmpBuf; + void *pvTmpBuf; + uint32_t cbTmpBuf2; + void *pvTmpBuf2; +} CR_PRESENTER_GLOBALS; + +static CR_PRESENTER_GLOBALS g_CrPresenter; + +/* FRAMEBUFFER */ + +void CrFbInit(CR_FRAMEBUFFER *pFb, uint32_t idScreen) +{ + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = 1; + Rect.yBottom = 1; + memset(pFb, 0, sizeof (*pFb)); + pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED; + pFb->ScreenInfo.u32ViewIndex = idScreen; + CrVrScrCompositorInit(&pFb->Compositor, &Rect); + RTListInit(&pFb->EntriesList); + CrHTableCreate(&pFb->SlotTable, 0); +} + +bool CrFbIsEnabled(CR_FRAMEBUFFER *pFb) +{ + return !(pFb->ScreenInfo.u16Flags & VBVA_SCREEN_F_DISABLED); +} + +HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry); + +const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(CR_FRAMEBUFFER *pFb) +{ + return &pFb->Compositor; +} + +DECLINLINE(CR_FRAMEBUFFER*) CrFbFromCompositor(const struct VBOXVR_SCR_COMPOSITOR* pCompositor) +{ + return RT_FROM_MEMBER(pCompositor, CR_FRAMEBUFFER, Compositor); +} + +const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb) +{ + return &hFb->ScreenInfo; +} + +void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb) +{ + return hFb->pvVram; +} -int CrDpInit(PCR_DISPLAY pDisplay) +int CrFbUpdateBegin(CR_FRAMEBUFFER *pFb) { - const GLint visBits = cr_server.MainContextInfo.CreateInfo.visualBits; - if (crServerMuralInit(&pDisplay->Mural, "", visBits, -1, GL_FALSE) < 0) + ++pFb->cUpdating; + + if (pFb->cUpdating == 1) { - crWarning("crServerMuralInit failed!"); - return VERR_GENERAL_FAILURE; + if (pFb->pDisplay) + pFb->pDisplay->UpdateBegin(pFb); } - crServerWindowVisibleRegion(&pDisplay->Mural); - crServerDEntryAllVibleRegions(&pDisplay->Mural); + return VINF_SUCCESS; +} - crServerMuralShow(&pDisplay->Mural, GL_TRUE); +void CrFbUpdateEnd(CR_FRAMEBUFFER *pFb) +{ + if (!pFb->cUpdating) + { + WARN(("invalid UpdateEnd call!")); + return; + } - pDisplay->fForcePresent = GL_FALSE; - return VINF_SUCCESS; + --pFb->cUpdating; + + if (!pFb->cUpdating) + { + if (pFb->pDisplay) + pFb->pDisplay->UpdateEnd(pFb); + } } -void CrDpTerm(PCR_DISPLAY pDisplay) +bool CrFbIsUpdating(const CR_FRAMEBUFFER *pFb) { - crServerMuralTerm(&pDisplay->Mural); + return !!pFb->cUpdating; } -void CrDpResize(PCR_DISPLAY pDisplay, int32_t xPos, int32_t yPos, uint32_t width, uint32_t height) +bool CrFbHas3DData(HCR_FRAMEBUFFER hFb) { - if (xPos != pDisplay->Mural.gX - || yPos != pDisplay->Mural.gY - || width != pDisplay->Mural.width - || height != pDisplay->Mural.height) + return !CrVrScrCompositorIsEmpty(&hFb->Compositor); +} + +static void crFbBltMem(uint8_t *pu8Src, int32_t cbSrcPitch, uint8_t *pu8Dst, int32_t cbDstPitch, uint32_t width, uint32_t height) +{ + uint32_t cbCopyRow = width * 4; + + for (uint32_t i = 0; i < height; ++i) { - crServerMuralPosition(&pDisplay->Mural, xPos, yPos, GL_TRUE); - if (!crServerMuralSize(&pDisplay->Mural, width, height)) - crServerCheckMuralGeometry(&pDisplay->Mural); + memcpy(pu8Dst, pu8Src, cbCopyRow); + + pu8Src += cbSrcPitch; + pu8Dst += cbDstPitch; } - else - crServerCheckMuralGeometry(&pDisplay->Mural); } -void CrDpReparent(PCR_DISPLAY pDisplay, CRScreenInfo *pScreen) +static void crFbBltImg(const CR_BLITTER_IMG *pSrc, const RTPOINT *pSrcDataPoint, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, CR_BLITTER_IMG *pDst) { - renderspuSetWindowId(pScreen->winID); - crServerWindowReparent(&pDisplay->Mural); - renderspuSetWindowId(cr_server.screen[0].winID); + int32_t srcX = pCopyRect->xLeft - pSrcDataPoint->x; + int32_t srcY = pCopyRect->yTop - pSrcDataPoint->y; + Assert(srcX >= 0); + Assert(srcY >= 0); + Assert(srcX < pSrc->width); + Assert(srcY < pSrc->height); + + int32_t dstX = pCopyRect->xLeft - pDstDataPoint->x; + int32_t dstY = pCopyRect->yTop - pDstDataPoint->y; + Assert(dstX >= 0); + Assert(dstY >= 0); + + uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4; + uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4; + + crFbBltMem(pu8Src, fSrcInvert ? -pSrc->pitch : pSrc->pitch, pu8Dst, pDst->pitch, pCopyRect->xRight - pCopyRect->xLeft, pCopyRect->yBottom - pCopyRect->yTop); +} - CrDpResize(pDisplay, pScreen->x, pScreen->y, pScreen->w, pScreen->h); +static void crFbBltImgScaled(const CR_BLITTER_IMG *pSrc, const RTPOINT *pSrcDataPoint, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, float strX, float strY, CR_BLITTER_IMG *pDst) +{ + int32_t srcX = pCopyRect->xLeft - pSrcDataPoint->x; + int32_t srcY = pCopyRect->yTop - pSrcDataPoint->y; + Assert(srcX >= 0); + Assert(srcY >= 0); + Assert(srcX < pSrc->width); + Assert(srcY < pSrc->height); + + RTPOINT ScaledDtsDataPoint; + RTRECT ScaledCopyRect; + + VBoxRectScaled(pCopyRect, strX, strY, &ScaledCopyRect); + ScaledDtsDataPoint.x = CR_FLOAT_RCAST(int32_t, strX * pDstDataPoint->x); + ScaledDtsDataPoint.y = CR_FLOAT_RCAST(int32_t, strY * pDstDataPoint->y); + + int32_t dstX = ScaledCopyRect.xLeft - ScaledDtsDataPoint.x; + int32_t dstY = ScaledCopyRect.yTop - ScaledDtsDataPoint.y; + Assert(dstX >= 0); + Assert(dstY >= 0); + + int32_t ScaledDstWidth = ScaledCopyRect.xRight - ScaledCopyRect.xLeft; + int32_t delta = (int32_t)pDst->width - dstX - ScaledDstWidth; + if (delta < 0) + ScaledDstWidth += delta; + + if (ScaledDstWidth <= 0) + { + LOG(("ScaledDstWidth <= 0")); + if (ScaledDstWidth < 0) + WARN(("dst width (%d) < 0", ScaledDstWidth)); + return; + } - if (pScreen->winID) + int32_t ScaledDstHeight = ScaledCopyRect.yBottom - ScaledCopyRect.yTop; + delta = (int32_t)pDst->height - dstY - ScaledDstHeight; + if (delta < 0) + ScaledDstHeight += delta; + + if (ScaledDstHeight <= 0) { - /* need to do this on win, since otherwise the window ends up being with empty visible regions for some reason */ - crServerWindowVisibleRegion(&pDisplay->Mural); + LOG(("ScaledDstHeight <= 0")); + if (ScaledDstHeight < 0) + WARN(("dst height (%d) < 0", ScaledDstHeight)); + return; } + + uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4; + uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4; + + CrBmpScale32(pu8Dst, pDst->pitch, + ScaledDstWidth, + ScaledDstHeight, + pu8Src, + fSrcInvert ? -pSrc->pitch : pSrc->pitch, + pCopyRect->xRight - pCopyRect->xLeft, pCopyRect->yBottom - pCopyRect->yTop); } +static void crFbImgFromScreenVram(const VBVAINFOSCREEN *pScreen, void *pvVram, CR_BLITTER_IMG *pImg) +{ + pImg->pvData = pvVram; + pImg->cbData = pScreen->u32LineSize * pScreen->u32Height; + pImg->enmFormat = GL_BGRA; + pImg->width = pScreen->u32Width; + pImg->height = pScreen->u32Height; + pImg->bpp = pScreen->u16BitsPerPixel; + pImg->pitch = pScreen->u32LineSize; +} -int CrDpSaveState(PCR_DISPLAY pDisplay, PSSMHANDLE pSSM) +static void crFbImgFromFb(HCR_FRAMEBUFFER hFb, CR_BLITTER_IMG *pImg) { - VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; - CrVrScrCompositorIterInit(&pDisplay->Mural.Compositor, &Iter); - PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; - uint32_t u32 = 0; - while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + void *pvVram = CrFbGetVRAM(hFb); + crFbImgFromScreenVram(pScreen, pvVram, pImg); +} + +static int crFbBltGetContentsDirect(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + VBOXVR_LIST List; + uint32_t c2DRects = 0; + CR_TEXDATA *pEnteredTex = NULL; + PCR_BLITTER pEnteredBlitter = NULL; + uint32_t width = 0, height = 0; + RTPOINT ScaledEntryPoint = {0}; + + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + RTPOINT SrcPoint = {pSrcRect->xLeft, pSrcRect->yTop}; + float strX = ((float)pImg->width) / (pSrcRect->xRight - pSrcRect->xLeft); + float strY = ((float)pImg->height) / (pSrcRect->yBottom - pSrcRect->yTop); + + RTPOINT ScaledSrcPoint; + ScaledSrcPoint.x = CR_FLOAT_RCAST(int32_t, strX * SrcPoint.x); + ScaledSrcPoint.y = CR_FLOAT_RCAST(int32_t, strY * SrcPoint.y); + + RTPOINT ZeroPoint = {0, 0}; + + VBoxVrListInit(&List); + int rc = VBoxVrListRectsAdd(&List, 1, CrVrScrCompositorRectGet(&hFb->Compositor), NULL); + if (!RT_SUCCESS(rc)) { - ++u32; + WARN(("VBoxVrListRectsAdd failed rc %d", rc)); + goto end; } - int rc = SSMR3PutU32(pSSM, u32); - AssertRCReturn(rc, rc); + CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter); - CrVrScrCompositorIterInit(&pDisplay->Mural.Compositor, &Iter); + for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter); + pEntry; + pEntry = CrVrScrCompositorConstIterNext(&Iter)) + { + uint32_t cRegions; + const RTRECT *pRegions; + rc = CrVrScrCompositorEntryRegionsGet(&hFb->Compositor, pEntry, &cRegions, NULL, NULL, &pRegions); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc)); + goto end; + } - while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + rc = VBoxVrListRectsSubst(&List, cRegions, pRegions, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsSubst failed rc %d", rc)); + goto end; + } + + for (uint32_t i = 0; i < cRects; ++i) + { + const RTRECT * pRect = &pRects[i]; + for (uint32_t j = 0; j < cRegions; ++j) + { + const RTRECT * pReg = &pRegions[j]; + RTRECT Intersection; + VBoxRectIntersected(pRect, pReg, &Intersection); + if (VBoxRectIsZero(&Intersection)) + continue; + + VBoxRectScale(&Intersection, strX, strY); + if (VBoxRectIsZero(&Intersection)) + continue; + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + const CR_BLITTER_IMG *pSrcImg; + + if (pEnteredTex != pTex) + { + if (!pEnteredBlitter) + { + pEnteredBlitter = CrTdBlitterGet(pTex); + rc = CrBltEnter(pEnteredBlitter); + if (!RT_SUCCESS(rc)) + { + WARN(("CrBltEnter failed %d", rc)); + pEnteredBlitter = NULL; + goto end; + } + } + + if (pEnteredTex) + { + CrTdBltLeave(pEnteredTex); + + pEnteredTex = NULL; + + if (pEnteredBlitter != CrTdBlitterGet(pTex)) + { + WARN(("blitters not equal!")); + CrBltLeave(pEnteredBlitter); + + pEnteredBlitter = CrTdBlitterGet(pTex); + rc = CrBltEnter(pEnteredBlitter); + if (!RT_SUCCESS(rc)) + { + WARN(("CrBltEnter failed %d", rc)); + pEnteredBlitter = NULL; + goto end; + } + } + } + + rc = CrTdBltEnter(pTex); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltEnter failed %d", rc)); + goto end; + } + + pEnteredTex = pTex; + + const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex); + + width = CR_FLOAT_RCAST(uint32_t, strX * pVrTex->width); + height = CR_FLOAT_RCAST(uint32_t, strY * pVrTex->height); + ScaledEntryPoint.x = CR_FLOAT_RCAST(int32_t, strX * CrVrScrCompositorEntryRectGet(pEntry)->xLeft); + ScaledEntryPoint.y = CR_FLOAT_RCAST(int32_t, strY * CrVrScrCompositorEntryRectGet(pEntry)->yTop); + } + + rc = CrTdBltDataAcquireScaled(pTex, GL_BGRA, false, width, height, &pSrcImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + goto end; + } + + bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS); + + crFbBltImg(pSrcImg, &ScaledEntryPoint, fInvert, &Intersection, &ScaledSrcPoint, pImg); + + CrTdBltDataReleaseScaled(pTex, pSrcImg); + } + } + } + + c2DRects = VBoxVrListRectsCount(&List); + if (c2DRects) { - CR_DISPLAY_ENTRY *pDEntry = CR_DENTRY_FROM_CENTRY(pEntry); - rc = CrDemEntrySaveState(pDEntry, pSSM); - AssertRCReturn(rc, rc); + if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT)) + { + if (g_CrPresenter.pvTmpBuf2) + RTMemFree(g_CrPresenter.pvTmpBuf2); - u32 = CrVrScrCompositorEntryFlagsGet(&pDEntry->CEntry); - rc = SSMR3PutU32(pSSM, u32); - AssertRCReturn(rc, rc); + g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT); + g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2); + if (!g_CrPresenter.pvTmpBuf2) + { + WARN(("RTMemAlloc failed!")); + g_CrPresenter.cbTmpBuf2 = 0; + rc = VERR_NO_MEMORY; + goto end; + } + } - rc = SSMR3PutS32(pSSM, CrVrScrCompositorEntryPosGet(&pDEntry->CEntry)->x); - AssertRCReturn(rc, rc); + RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2; - rc = SSMR3PutS32(pSSM, CrVrScrCompositorEntryPosGet(&pDEntry->CEntry)->y); - AssertRCReturn(rc, rc); + rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsGet failed, rc %d", rc)); + goto end; + } - const RTRECT * pRects; - rc = CrVrScrCompositorEntryRegionsGet(&pDisplay->Mural.Compositor, &pDEntry->CEntry, &u32, NULL, NULL, &pRects); - AssertRCReturn(rc, rc); + RTPOINT Pos = {0}; + const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor); - rc = SSMR3PutU32(pSSM, u32); - AssertRCReturn(rc, rc); + uint32_t fbWidth = (pCompRect->xRight - pCompRect->xLeft); + uint32_t fbHeight = pCompRect->yBottom - pCompRect->yTop; + + uint32_t stretchedWidth = CR_FLOAT_RCAST(uint32_t, strX * fbWidth); + uint32_t stretchedHeight = CR_FLOAT_RCAST(uint32_t, strY * fbHeight); + + CR_BLITTER_IMG FbImg; + + bool fScale = fbWidth != stretchedWidth || fbHeight != stretchedHeight; - if (u32) + crFbImgFromFb(hFb, &FbImg); + + for (uint32_t i = 0; i < cRects; ++i) { - rc = SSMR3PutMem(pSSM, pRects, u32 * sizeof (*pRects)); - AssertRCReturn(rc, rc); + const RTRECT * pRect = &pRects[i]; + for (uint32_t j = 0; j < c2DRects; ++j) + { + const RTRECT * p2DRect = &p2DRects[j]; + RTRECT Intersection; + VBoxRectIntersected(pRect, p2DRect, &Intersection); + if (VBoxRectIsZero(&Intersection)) + continue; + + if (!fScale) + crFbBltImg(&FbImg, &ZeroPoint, false, &Intersection, &SrcPoint, pImg); + else + crFbBltImgScaled(&FbImg, &ZeroPoint, false, &Intersection, &SrcPoint, strX, strY, pImg); + } } } +end: + + if (pEnteredTex) + CrTdBltLeave(pEnteredTex); + + if (pEnteredBlitter) + CrBltLeave(pEnteredBlitter); + + VBoxVrListClear(&List); + + return rc; +} + +static int crFbBltGetContentsScaleCPU(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + uint32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft; + uint32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop; + + /* destination is bigger than the source, do 3D data stretching with CPU */ + CR_BLITTER_IMG Img; + Img.cbData = srcWidth * srcHeight * 4; + Img.pvData = RTMemAlloc(Img.cbData); + if (!Img.pvData) + { + WARN(("RTMemAlloc Failed")); + return VERR_NO_MEMORY; + } + Img.enmFormat = pImg->enmFormat; + Img.width = srcWidth; + Img.height = srcHeight; + Img.bpp = pImg->bpp; + Img.pitch = Img.width * 4; + + int rc = CrFbBltGetContents(hFb, pSrcRect, cRects, pRects, &Img); + if (RT_SUCCESS(rc)) + { + CrBmpScale32((uint8_t *)pImg->pvData, + pImg->pitch, + pImg->width, pImg->height, + (const uint8_t *)Img.pvData, + Img.pitch, + Img.width, Img.height); + } + else + WARN(("CrFbBltGetContents failed %d", rc)); + + RTMemFree(Img.pvData); + + return rc; + +} + +int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + uint32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft; + uint32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop; + if ((srcWidth == pImg->width + && srcHeight == pImg->height) + || !CrFbHas3DData(hFb) + || (srcWidth * srcHeight > pImg->width * pImg->height)) + { + return crFbBltGetContentsDirect(hFb, pSrcRect, cRects, pRects, pImg); + } + + return crFbBltGetContentsScaleCPU(hFb, pSrcRect, cRects, pRects, pImg); +} + + +int CrFbResize(CR_FRAMEBUFFER *pFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM) +{ + if (!pFb->cUpdating) + { + WARN(("no update in progress")); + return VERR_INVALID_STATE; + } + + if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED) + { + CrVrScrCompositorClear(&pFb->Compositor); + } + + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = pScreen->u32Width; + Rect.yBottom = pScreen->u32Height; + int rc = CrVrScrCompositorRectSet(&pFb->Compositor, &Rect, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorRectSet failed rc %d", rc)); + return rc; + } + + pFb->ScreenInfo = *pScreen; + pFb->pvVram = pvVRAM; + + if (pFb->pDisplay) + pFb->pDisplay->FramebufferChanged(pFb); + return VINF_SUCCESS; } -int CrDpLoadState(PCR_DISPLAY pDisplay, PSSMHANDLE pSSM, uint32_t version) +void CrFbTerm(CR_FRAMEBUFFER *pFb) { - uint32_t u32 = 0; - int rc = SSMR3GetU32(pSSM, &u32); - AssertRCReturn(rc, rc); + if (pFb->cUpdating) + { + WARN(("update in progress")); + return; + } + uint32_t idScreen = pFb->ScreenInfo.u32ViewIndex; - if (!u32) + CrVrScrCompositorClear(&pFb->Compositor); + CrHTableDestroy(&pFb->SlotTable); + + Assert(RTListIsEmpty(&pFb->EntriesList)); + Assert(!pFb->cEntries); + + memset(pFb, 0, sizeof (*pFb)); + + pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED; + pFb->ScreenInfo.u32ViewIndex = idScreen; +} + +ICrFbDisplay* CrFbDisplayGet(CR_FRAMEBUFFER *pFb) +{ + return pFb->pDisplay; +} + +int CrFbDisplaySet(CR_FRAMEBUFFER *pFb, ICrFbDisplay *pDisplay) +{ + if (pFb->cUpdating) + { + WARN(("update in progress")); + return VERR_INVALID_STATE; + } + + if (pFb->pDisplay == pDisplay) return VINF_SUCCESS; - CrDpEnter(pDisplay); + pFb->pDisplay = pDisplay; - for (uint32_t i = 0; i < u32; ++i) + return VINF_SUCCESS; +} + +#define CR_PMGR_MODE_WINDOW 0x1 +/* mutually exclusive with CR_PMGR_MODE_WINDOW */ +#define CR_PMGR_MODE_ROOTVR 0x2 +#define CR_PMGR_MODE_VRDP 0x4 +#define CR_PMGR_MODE_ALL 0x7 + +static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove); + +static CR_FBTEX* crFbTexAlloc() +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + return (CR_FBTEX*)RTMemCacheAlloc(g_CrPresenter.FbTexLookasideList); +#else + return (CR_FBTEX*)RTMemAlloc(sizeof (CR_FBTEX)); +#endif +} + +static void crFbTexFree(CR_FBTEX *pTex) +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheFree(g_CrPresenter.FbTexLookasideList, pTex); +#else + RTMemFree(pTex); +#endif +} + +static CR_FRAMEBUFFER_ENTRY* crFbEntryAlloc() +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + return (CR_FRAMEBUFFER_ENTRY*)RTMemCacheAlloc(g_CrPresenter.FbEntryLookasideList); +#else + return (CR_FRAMEBUFFER_ENTRY*)RTMemAlloc(sizeof (CR_FRAMEBUFFER_ENTRY)); +#endif +} + +static void crFbEntryFree(CR_FRAMEBUFFER_ENTRY *pEntry) +{ + Assert(!CrVrScrCompositorEntryIsUsed(&pEntry->Entry)); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheFree(g_CrPresenter.FbEntryLookasideList, pEntry); +#else + RTMemFree(pEntry); +#endif +} + +DECLCALLBACK(void) crFbTexRelease(CR_TEXDATA *pTex) +{ + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTex); + CRTextureObj *pTobj = pFbTex->pTobj; + + CrTdBltDataCleanupNe(pTex); + + if (pTobj) { - CR_DISPLAY_ENTRY *pDEntry; - rc = CrDemEntryLoadState(&cr_server.PresentTexturepMap, &pDEntry, pSSM); - AssertRCReturn(rc, rc); + CR_STATE_SHAREDOBJ_USAGE_CLEAR(pTobj, cr_server.MainContextInfo.pContext); - uint32_t fFlags; - rc = SSMR3GetU32(pSSM, &fFlags); - AssertRCReturn(rc, rc); + crHashtableDelete(g_CrPresenter.pFbTexMap, pTobj->id, NULL); - CrVrScrCompositorEntryFlagsSet(&pDEntry->CEntry, fFlags); + if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pTobj)) + { + CRSharedState *pShared = crStateGlobalSharedAcquire(); - RTPOINT Pos; - rc = SSMR3GetS32(pSSM, &Pos.x); - AssertRCReturn(rc, rc); + CRASSERT(pShared); + /* on the host side, we need to delete an ogl texture object here as well, which crStateDeleteTextureCallback will do + * in addition to calling crStateDeleteTextureObject to delete a state object */ + crHashtableDelete(pShared->textureTable, pTobj->id, crStateDeleteTextureCallback); - rc = SSMR3GetS32(pSSM, &Pos.y); - AssertRCReturn(rc, rc); + crStateGlobalSharedRelease(); + } - uint32_t cRects; - rc = SSMR3GetU32(pSSM, &cRects); - AssertRCReturn(rc, rc); + crStateGlobalSharedRelease(); + } + + crFbTexFree(pFbTex); +} + +void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased) +{ + PCR_BLITTER pBlitter = crServerVBoxBlitterGet(); + + CrTdInit(pFbTex, pTex, pBlitter, pfnTextureReleased); +} + +static CR_FBTEX* crFbTexCreate(const VBOXVR_TEXTURE *pTex) +{ + CR_FBTEX *pFbTex = crFbTexAlloc(); + if (!pFbTex) + { + WARN(("crFbTexAlloc failed!")); + return NULL; + } + + CrFbTexDataInit(&pFbTex->Tex, pTex, crFbTexRelease); + pFbTex->pTobj = NULL; - RTRECT * pRects = NULL; - if (cRects) + return pFbTex; +} + + +CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex) +{ + CR_FBTEX *pFbTex = crFbTexCreate(pTex); + if (!pFbTex) + { + WARN(("crFbTexCreate failed!")); + return NULL; + } + + return &pFbTex->Tex; +} + +static CR_FBTEX* crFbTexAcquire(GLuint idTexture) +{ + CR_FBTEX *pFbTex = (CR_FBTEX *)crHashtableSearch(g_CrPresenter.pFbTexMap, idTexture); + if (pFbTex) + { + CrTdAddRef(&pFbTex->Tex); + return pFbTex; + } + + CRSharedState *pShared = crStateGlobalSharedAcquire(); + if (!pShared) + { + WARN(("pShared is null!")); + return NULL; + } + + CRTextureObj *pTobj = (CRTextureObj*)crHashtableSearch(pShared->textureTable, idTexture); + if (!pTobj) + { + LOG(("pTobj is null!")); + crStateGlobalSharedRelease(); + return NULL; + } + + Assert(pTobj->id == idTexture); + + GLuint hwid = crStateGetTextureObjHWID(pTobj); + if (!hwid) + { + WARN(("hwId is null!")); + crStateGlobalSharedRelease(); + return NULL; + } + + VBOXVR_TEXTURE Tex; + Tex.width = pTobj->level[0]->width; + Tex.height = pTobj->level[0]->height; + Tex.hwid = hwid; + Tex.target = pTobj->target; + + pFbTex = crFbTexCreate(&Tex); + if (!pFbTex) + { + WARN(("crFbTexCreate failed!")); + crStateGlobalSharedRelease(); + return NULL; + } + + CR_STATE_SHAREDOBJ_USAGE_SET(pTobj, cr_server.MainContextInfo.pContext); + + pFbTex->pTobj = pTobj; + + crHashtableAdd(g_CrPresenter.pFbTexMap, idTexture, pFbTex); + + return pFbTex; +} + +static void crFbEntryMarkDestroyed(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry) +{ + if (pEntry->Flags.fCreateNotified) + { + pEntry->Flags.fCreateNotified = 0; + if (pFb->pDisplay) + pFb->pDisplay->EntryDestroyed(pFb, pEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } +} + +static void crFbEntryDestroy(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry) +{ + crFbEntryMarkDestroyed(pFb, pEntry); + CrVrScrCompositorEntryCleanup(&pEntry->Entry); + CrHTableDestroy(&pEntry->HTable); + Assert(pFb->cEntries); + RTListNodeRemove(&pEntry->Node); + --pFb->cEntries; + crFbEntryFree(pEntry); +} + +DECLINLINE(uint32_t) crFbEntryAddRef(CR_FRAMEBUFFER_ENTRY* pEntry) +{ + return ++pEntry->cRefs; +} + +DECLINLINE(uint32_t) crFbEntryRelease(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry) +{ + uint32_t cRefs = --pEntry->cRefs; + if (!cRefs) + crFbEntryDestroy(pFb, pEntry); + return cRefs; +} + +static DECLCALLBACK(void) crFbEntryReleased(const struct VBOXVR_SCR_COMPOSITOR *pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacingEntry) +{ + CR_FRAMEBUFFER *pFb = PCR_FRAMEBUFFER_FROM_COMPOSITOR(pCompositor); + CR_FRAMEBUFFER_ENTRY *pFbEntry = PCR_FBENTRY_FROM_ENTRY(pEntry); + CR_FRAMEBUFFER_ENTRY *pFbReplacingEntry = pReplacingEntry ? PCR_FBENTRY_FROM_ENTRY(pReplacingEntry) : NULL; + if (pFbReplacingEntry) + { + /*replace operation implies the replaced entry gets auto-destroyed, + * while all its data gets moved to the *clean* replacing entry + * 1. ensure the replacing entry is cleaned up */ + crFbEntryMarkDestroyed(pFb, pFbReplacingEntry); + + CrHTableMoveTo(&pFbEntry->HTable, &pFbReplacingEntry->HTable); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry); + CR_TEXDATA *pReplacingTex = CrVrScrCompositorEntryTexGet(&pFbReplacingEntry->Entry); + + CrTdBltScaleCacheMoveTo(pTex, pReplacingTex); + + if (pFb->pDisplay) + pFb->pDisplay->EntryReplaced(pFb, pFbReplacingEntry, pFbEntry); + + CrTdBltDataInvalidateNe(pTex); + + /* 2. mark the replaced entry is destroyed */ + Assert(pFbEntry->Flags.fCreateNotified); + Assert(pFbEntry->Flags.fInList); + pFbEntry->Flags.fCreateNotified = 0; + pFbEntry->Flags.fInList = 0; + pFbReplacingEntry->Flags.fCreateNotified = 1; + pFbReplacingEntry->Flags.fInList = 1; + } + else + { + if (pFbEntry->Flags.fInList) { - pRects = (RTRECT *)crAlloc(cRects * sizeof (*pRects)); - AssertReturn(pRects, VERR_NO_MEMORY); + pFbEntry->Flags.fInList = 0; + if (pFb->pDisplay) + pFb->pDisplay->EntryRemoved(pFb, pFbEntry); - rc = SSMR3GetMem(pSSM, pRects, cRects * sizeof (*pRects)); - AssertRCReturn(rc, rc); + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); } + } - rc = CrDpEntryRegionsAdd(pDisplay, pDEntry, &Pos, (uint32_t)cRects, (const RTRECT*)pRects, NULL); - AssertRCReturn(rc, rc); + crFbEntryRelease(pFb, pFbEntry); +} - if (pRects) - crFree(pRects); +static CR_FRAMEBUFFER_ENTRY* crFbEntryCreate(CR_FRAMEBUFFER *pFb, CR_TEXDATA* pTex, const RTRECT *pRect, uint32_t fFlags) +{ + CR_FRAMEBUFFER_ENTRY *pEntry = crFbEntryAlloc(); + if (!pEntry) + { + WARN(("crFbEntryAlloc failed!")); + return NULL; } - CrDpLeave(pDisplay); + CrVrScrCompositorEntryInit(&pEntry->Entry, pRect, pTex, crFbEntryReleased); + CrVrScrCompositorEntryFlagsSet(&pEntry->Entry, fFlags); + pEntry->cRefs = 1; + pEntry->Flags.Value = 0; + CrHTableCreate(&pEntry->HTable, 0); + RTListAppend(&pFb->EntriesList, &pEntry->Node); + ++pFb->cEntries; + + return pEntry; +} + +int CrFbEntryCreateForTexData(CR_FRAMEBUFFER *pFb, struct CR_TEXDATA *pTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry) +{ + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = pTex->Tex.width; + Rect.yBottom = pTex->Tex.height; + CR_FRAMEBUFFER_ENTRY* pEntry = crFbEntryCreate(pFb, pTex, &Rect, fFlags); + if (!pEntry) + { + WARN(("crFbEntryCreate failed")); + return VERR_NO_MEMORY; + } + + *phEntry = pEntry; return VINF_SUCCESS; } +int CrFbEntryTexDataUpdate(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY pEntry, struct CR_TEXDATA *pTex) +{ + if (!pFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + if (pTex) + CrVrScrCompositorEntryTexSet(&pEntry->Entry, pTex); + + if (CrVrScrCompositorEntryIsUsed(&pEntry->Entry)) + { + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, pEntry); -int CrDpEntryRegionsSet(PCR_DISPLAY pDisplay, PCR_DISPLAY_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions) + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + + return VINF_SUCCESS; +} + + +int CrFbEntryCreateForTexId(CR_FRAMEBUFFER *pFb, GLuint idTexture, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry) { - int rc = CrVrScrCompositorEntryRegionsSet(&pDisplay->Mural.Compositor, pEntry ? &pEntry->CEntry : NULL, pPos, cRegions, paRegions, false, NULL); + CR_FBTEX* pFbTex = crFbTexAcquire(idTexture); + if (!pFbTex) + { + LOG(("crFbTexAcquire failed")); + return VERR_INVALID_PARAMETER; + } + + CR_TEXDATA* pTex = &pFbTex->Tex; + int rc = CrFbEntryCreateForTexData(pFb, pTex, fFlags, phEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryCreateForTexData failed rc %d", rc)); + } + + /*always release the tex, the CrFbEntryCreateForTexData will do incref as necessary */ + CrTdRelease(pTex); return rc; } -void crDbgDumpRect(uint32_t i, const RTRECT *pRect) +void CrFbEntryAddRef(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - crDebug("%d: (%d;%d) X (%d;%d)", i, pRect->xLeft, pRect->yTop, pRect->xRight, pRect->yBottom); + ++hEntry->cRefs; } -void crDbgDumpRects(uint32_t cRects, const RTRECT *paRects) +void CrFbEntryRelease(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - crDebug("Dumping rects (%d)", cRects); - for (uint32_t i = 0; i < cRects; ++i) + crFbEntryRelease(pFb, hEntry); +} + +int CrFbRegionsClear(HCR_FRAMEBUFFER hFb) +{ + if (!hFb->cUpdating) { - crDbgDumpRect(i, &paRects[i]); + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; } - crDebug("End Dumping rects (%d)", cRects); + + bool fChanged = false; + CrVrScrCompositorRegionsClear(&hFb->Compositor, &fChanged); + if (fChanged) + { + if (hFb->pDisplay) + hFb->pDisplay->RegionsChanged(hFb); + } + + return VINF_SUCCESS; } -int CrDpEntryRegionsAdd(PCR_DISPLAY pDisplay, PCR_DISPLAY_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, CR_DISPLAY_ENTRY_MAP *pMap) +int CrFbEntryRegionsAdd(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated) { + if (!pFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + uint32_t fChangeFlags = 0; VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL; + VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry; + bool fEntryWasInList; + + if (hEntry) + { + crFbEntryAddRef(hEntry); + pNewEntry = &hEntry->Entry; + fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry); - if (pMap) - CrDemEnter(pMap); + Assert(!hEntry->Flags.fInList == !fEntryWasInList); + } + else + { + pNewEntry = NULL; + fEntryWasInList = false; + } - int rc = CrVrScrCompositorEntryRegionsAdd(&pDisplay->Mural.Compositor, pEntry ? &pEntry->CEntry : NULL, pPos, cRegions, paRegions, false, &pReplacedScrEntry, &fChangeFlags); + int rc = CrVrScrCompositorEntryRegionsAdd(&pFb->Compositor, hEntry ? &hEntry->Entry : NULL, pPos, cRegions, paRegions, fPosRelated, &pReplacedScrEntry, &fChangeFlags); if (RT_SUCCESS(rc)) { if (fChangeFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED) { - bool fChanged = true; - if (pDisplay->Mural.fRootVrOn) + if (!fEntryWasInList && pNewEntry) { - int rc = crServerMuralSynchRootVr(&pDisplay->Mural, &fChanged); - if (!RT_SUCCESS(rc)) + Assert(CrVrScrCompositorEntryIsUsed(pNewEntry)); + if (!hEntry->Flags.fCreateNotified) { - crWarning("crServerMuralSynchRootVr failed, rc %d", rc); - fChanged = false; + hEntry->Flags.fCreateNotified = 1; + if (pFb->pDisplay) + pFb->pDisplay->EntryCreated(pFb, hEntry); } - } - if (fChanged) - crServerWindowVisibleRegion(&pDisplay->Mural); +#ifdef DEBUG_misha + /* in theory hEntry->Flags.fInList can be set if entry is replaced, + * but then modified to fit the compositor rects, + * and so we get the regions changed notification as a result + * this should not generally happen though, so put an assertion to debug that situation */ + Assert(!hEntry->Flags.fInList); +#endif + if (!hEntry->Flags.fInList) + { + hEntry->Flags.fInList = 1; - crServerDEntryAllVibleRegions(&pDisplay->Mural); + if (pFb->pDisplay) + pFb->pDisplay->EntryAdded(pFb, hEntry); + } + } + if (pFb->pDisplay) + pFb->pDisplay->RegionsChanged(pFb); Assert(!pReplacedScrEntry); } - else if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED) + else if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) + { + Assert(pReplacedScrEntry); + /* we have already processed that in a "release" callback */ + Assert(hEntry); + } + else + { + Assert(!fChangeFlags); + Assert(!pReplacedScrEntry); + } + + if (hEntry) { - if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) + if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry)) { - Assert(pReplacedScrEntry); - Assert(pEntry); - if (pDisplay->Mural.fRootVrOn) - { - CR_DISPLAY_ENTRY *pReplacedDEntry = CR_DENTRY_FROM_CENTRY(pReplacedScrEntry); - Assert(CrVrScrCompositorEntryIsUsed(&pReplacedDEntry->RootVrCEntry)); - Assert(!CrVrScrCompositorEntryIsUsed(&pEntry->RootVrCEntry)); - CrVrScrCompositorEntryInit(&pEntry->RootVrCEntry, CrVrScrCompositorEntryTexGet(&pEntry->CEntry), NULL); - CrVrScrCompositorEntryFlagsSet(&pEntry->RootVrCEntry, CrVrScrCompositorEntryFlagsGet(&pEntry->CEntry)); - CrVrScrCompositorEntryReplace(&pDisplay->Mural.RootVrCompositor, &pReplacedDEntry->RootVrCEntry, &pEntry->RootVrCEntry); - } + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, hEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); } - else + } + } + else + WARN(("CrVrScrCompositorEntryRegionsAdd failed, rc %d", rc)); + + return rc; +} + +int CrFbEntryRegionsSet(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated) +{ + if (!pFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + bool fChanged = 0; + VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL; + VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry; + bool fEntryWasInList; + + if (hEntry) + { + crFbEntryAddRef(hEntry); + pNewEntry = &hEntry->Entry; + fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry); + Assert(!hEntry->Flags.fInList == !fEntryWasInList); + } + else + { + pNewEntry = NULL; + fEntryWasInList = false; + } + + int rc = CrVrScrCompositorEntryRegionsSet(&pFb->Compositor, pNewEntry, pPos, cRegions, paRegions, fPosRelated, &fChanged); + if (RT_SUCCESS(rc)) + { + if (fChanged) + { + if (!fEntryWasInList && pNewEntry) { - Assert(!pReplacedScrEntry); - if (pDisplay->Mural.fRootVrOn) + if (CrVrScrCompositorEntryIsUsed(pNewEntry)) { - bool fChanged = false; - int rc = crServerMuralSynchRootVr(&pDisplay->Mural, &fChanged); - if (RT_SUCCESS(rc)) + if (!hEntry->Flags.fCreateNotified) { - if (fChanged) - crServerWindowVisibleRegion(&pDisplay->Mural); + hEntry->Flags.fCreateNotified = 1; + + if (pFb->pDisplay) + pFb->pDisplay->EntryCreated(pFb, hEntry); } - else - crWarning("crServerMuralSynchRootVr failed, rc %d", rc); + + Assert(!hEntry->Flags.fInList); + hEntry->Flags.fInList = 1; + + if (pFb->pDisplay) + pFb->pDisplay->EntryAdded(pFb, hEntry); } } + + if (pFb->pDisplay) + pFb->pDisplay->RegionsChanged(pFb); } - else + + if (hEntry) { - Assert(!(fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)); - Assert(!pReplacedScrEntry); + if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry)) + { + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, hEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } } } else - crWarning("CrVrScrCompositorEntryRegionsAdd failed, rc %d", rc); - - if (pMap) - CrDemLeave(pMap, CR_DENTRY_FROM_CENTRY(pEntry), CR_DENTRY_FROM_CENTRY(pReplacedScrEntry)); + WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc)); return rc; } -void CrDpRegionsClear(PCR_DISPLAY pDisplay) +const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry) { - bool fChanged = false; - CrVrScrCompositorRegionsClear(&pDisplay->Mural.Compositor, &fChanged); - if (fChanged) - { - crServerMuralVisibleRegion(&pDisplay->Mural, 0, NULL); - } + return &hEntry->Entry; } -#define PCR_DISPLAY_ENTRY_FROM_CENTRY(_pe) ((PCR_DISPLAY_ENTRY)((uint8_t*)(_pe) - RT_OFFSETOF(CR_DISPLAY_ENTRY, CEntry))) -static DECLCALLBACK(void) crDpEntryCEntryReleaseCB(const struct VBOXVR_SCR_COMPOSITOR *pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacingEntry) +HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry) { - PCR_DISPLAY_ENTRY pCEntry = PCR_DISPLAY_ENTRY_FROM_CENTRY(pEntry); - CrDemEntryRelease(pCEntry); + return RT_FROM_MEMBER(pCEntry, CR_FRAMEBUFFER_ENTRY, Entry); } -void CrDpEntryInit(PCR_DISPLAY_ENTRY pEntry, const VBOXVR_TEXTURE *pTextureData, uint32_t fFlags, PFNVBOXVRSCRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased) +void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext) { - CrVrScrCompositorEntryInit(&pEntry->CEntry, pTextureData, pfnEntryReleased); - CrVrScrCompositorEntryFlagsSet(&pEntry->CEntry, fFlags); - CrVrScrCompositorEntryInit(&pEntry->RootVrCEntry, pTextureData, NULL); - CrVrScrCompositorEntryFlagsSet(&pEntry->RootVrCEntry, fFlags); - pEntry->pvORInstance = NULL; - pEntry->idPBO = 0; - pEntry->idInvertTex = 0; + HCR_FRAMEBUFFER_ENTRY hEntry, hNext; + RTListForEachSafe(&hFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node) + { + if (hEntry->Flags.fCreateNotified) + { + if (!pfnVisitorCb(hFb, hEntry, pvContext)) + return; + } + } } -void CrDpEntryCleanup(PCR_DISPLAY_ENTRY pDEntry) + +CRHTABLE_HANDLE CrFbDDataAllocSlot(CR_FRAMEBUFFER *pFb) { - if (pDEntry->idPBO) - { - CRASSERT(cr_server.bUsePBOForReadback); - cr_server.head_spu->dispatch_table.DeleteBuffersARB(1, &pDEntry->idPBO); - pDEntry->idPBO = 0; - } + return CrHTablePut(&pFb->SlotTable, (void*)1); +} - if (pDEntry->idInvertTex) +void CrFbDDataReleaseSlot(CR_FRAMEBUFFER *pFb, CRHTABLE_HANDLE hSlot, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB pfnReleaseCb, void *pvContext) +{ + HCR_FRAMEBUFFER_ENTRY hEntry, hNext; + RTListForEachSafe(&pFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node) { - cr_server.head_spu->dispatch_table.DeleteTextures(1, &pDEntry->idInvertTex); - pDEntry->idInvertTex = 0; - } + if (CrFbDDataEntryGet(hEntry, hSlot)) + { + if (pfnReleaseCb) + pfnReleaseCb(pFb, hEntry, pvContext); - if (pDEntry->pvORInstance) - { - cr_server.outputRedirect.CROREnd(pDEntry->pvORInstance); - pDEntry->pvORInstance = NULL; + CrFbDDataEntryClear(hEntry, hSlot); + } } + + CrHTableRemove(&pFb->SlotTable, hSlot); } -void CrDpEnter(PCR_DISPLAY pDisplay) +int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData) { - pDisplay->fForcePresent |= crServerVBoxCompositionPresentNeeded(&pDisplay->Mural); - crServerVBoxCompositionDisableEnter(&pDisplay->Mural); + return CrHTablePutToSlot(&hEntry->HTable, hSlot, pvData); } -void CrDpLeave(PCR_DISPLAY pDisplay) +void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot) { - pDisplay->Mural.fDataPresented = GL_TRUE; - pDisplay->Mural.fOrPresentOnReenable = GL_TRUE; - crServerVBoxCompositionDisableLeave(&pDisplay->Mural, pDisplay->fForcePresent); - pDisplay->fForcePresent = GL_FALSE; + return CrHTableRemove(&hEntry->HTable, hSlot); } -void CrDpRootUpdate(PCR_DISPLAY pDisplay) +void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot) { - crVBoxServerUpdateMuralRootVisibleRegion(&pDisplay->Mural); + return CrHTableGet(&hEntry->HTable, hSlot); } - -typedef struct CR_DEM_ENTRY_INFO +typedef union CR_FBDISPBASE_FLAGS { - CRTextureObj *pTobj; - uint32_t cEntries; -} CR_DEM_ENTRY_INFO; + struct { + uint32_t fRegionsShanged : 1; + uint32_t Reserved : 31; + }; + uint32_t u32Value; +} CR_FBDISPBASE_FLAGS; + +class CrFbDisplayBase : public ICrFbDisplay +{ +public: + CrFbDisplayBase() : + mpContainer(NULL), + mpFb(NULL), + mcUpdates(0), + mhSlot(CRHTABLE_HANDLE_INVALID) + { + mFlags.u32Value = 0; + } + + virtual bool isComposite() + { + return false; + } + + class CrFbDisplayComposite* getContainer() + { + return mpContainer; + } + + bool isInList() + { + return !!mpContainer; + } + + bool isUpdating() + { + return !!mcUpdates; + } + + int setRegionsChanged() + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + int setFramebuffer(struct CR_FRAMEBUFFER *pFb) + { + if (mcUpdates) + { + WARN(("trying to set framebuffer while update is in progress")); + return VERR_INVALID_STATE; + } + + if (mpFb == pFb) + return VINF_SUCCESS; + + int rc = setFramebufferBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpFb) + { + rc = fbCleanup(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + setFramebufferEnd(pFb); + return rc; + } + } + + mpFb = pFb; + + if (mpFb) + { + rc = fbSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + setFramebufferEnd(pFb); + return rc; + } + } + + setFramebufferEnd(pFb); + return VINF_SUCCESS; + } + + struct CR_FRAMEBUFFER* getFramebuffer() + { + return mpFb; + } + + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) + { + ++mcUpdates; + Assert(!mFlags.fRegionsShanged || mcUpdates > 1); + return VINF_SUCCESS; + } + + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) + { + --mcUpdates; + Assert(mcUpdates < UINT32_MAX/2); + if (!mcUpdates) + onUpdateEnd(); + } + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + return VINF_SUCCESS; + } -typedef struct CR_DEM_ENTRY + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual ~CrFbDisplayBase(); + + /*@todo: move to protected and switch from RTLISTNODE*/ + RTLISTNODE mNode; + class CrFbDisplayComposite* mpContainer; +protected: + virtual void onUpdateEnd() + { + if (mFlags.fRegionsShanged) + { + mFlags.fRegionsShanged = 0; + if (getFramebuffer()) /*<-dont't do anything on cleanup*/ + ueRegions(); + } + } + + virtual void ueRegions() + { + } + + static DECLCALLBACK(bool) entriesCreateCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext) + { + int rc = ((ICrFbDisplay*)(pvContext))->EntryCreated(hFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + } + return true; + } + + static DECLCALLBACK(bool) entriesDestroyCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext) + { + int rc = ((ICrFbDisplay*)(pvContext))->EntryDestroyed(hFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + } + return true; + } + + int fbSynchAddAllEntries() + { + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + + CrVrScrCompositorConstIterInit(CrFbGetCompositor(mpFb), &Iter); + + int rc = VINF_SUCCESS; + + CrFbVisitCreatedEntries(mpFb, entriesCreateCb, this); + + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + + rc = EntryAdded(mpFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + EntryDestroyed(mpFb, hEntry); + break; + } + } + + return rc; + } + + int fbCleanupRemoveAllEntries() + { + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + + CrVrScrCompositorConstIterInit(CrFbGetCompositor(mpFb), &Iter); + + int rc = VINF_SUCCESS; + + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + rc = EntryRemoved(mpFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + break; + } + + CrFbVisitCreatedEntries(mpFb, entriesDestroyCb, this); + } + + return rc; + } + + virtual int setFramebufferBegin(struct CR_FRAMEBUFFER *pFb) + { + return UpdateBegin(pFb); + } + virtual void setFramebufferEnd(struct CR_FRAMEBUFFER *pFb) + { + UpdateEnd(pFb); + } + + static DECLCALLBACK(void) slotEntryReleaseCB(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext) + { + } + + virtual void slotRelease() + { + Assert(mhSlot); + CrFbDDataReleaseSlot(mpFb, mhSlot, slotEntryReleaseCB, this); + } + + virtual int fbCleanup() + { + if (mhSlot) + { + slotRelease(); + mhSlot = 0; + } + mpFb = NULL; + return VINF_SUCCESS; + } + + virtual int fbSync() + { + return VINF_SUCCESS; + } + + CRHTABLE_HANDLE slotGet() + { + if (!mhSlot) + { + if (mpFb) + mhSlot = CrFbDDataAllocSlot(mpFb); + } + + return mhSlot; + } + +private: + struct CR_FRAMEBUFFER *mpFb; + uint32_t mcUpdates; + CRHTABLE_HANDLE mhSlot; + CR_FBDISPBASE_FLAGS mFlags; +}; + +class CrFbDisplayComposite : public CrFbDisplayBase { - CR_DISPLAY_ENTRY Entry; - CR_DEM_ENTRY_INFO *pInfo; - CR_DISPLAY_ENTRY_MAP *pMap; - RTLISTNODE Node; -} CR_DEM_ENTRY; +public: + CrFbDisplayComposite() : + mcDisplays(0) + { + RTListInit(&mDisplays); + } + + virtual bool isComposite() + { + return true; + } + + uint32_t getDisplayCount() + { + return mcDisplays; + } + + bool add(CrFbDisplayBase *pDisplay) + { + if (pDisplay->isInList()) + { + WARN(("entry in list already")); + return false; + } + + RTListAppend(&mDisplays, &pDisplay->mNode); + pDisplay->mpContainer = this; + pDisplay->setFramebuffer(getFramebuffer()); + ++mcDisplays; + return true; + } + + bool remove(CrFbDisplayBase *pDisplay, bool fCleanupDisplay = true) + { + if (pDisplay->getContainer() != this) + { + WARN(("invalid entry container")); + return false; + } + + RTListNodeRemove(&pDisplay->mNode); + pDisplay->mpContainer = NULL; + if (fCleanupDisplay) + pDisplay->setFramebuffer(NULL); + --mcDisplays; + return true; + } + + CrFbDisplayBase* first() + { + return RTListGetFirstCpp(&mDisplays, CrFbDisplayBase, mNode); + } + + CrFbDisplayBase* next(CrFbDisplayBase* pDisplay) + { + if (pDisplay->getContainer() != this) + { + WARN(("invalid entry container")); + return NULL; + } + + return RTListGetNextCpp(&mDisplays, pDisplay, CrFbDisplayBase, mNode); + } + + virtual int setFramebuffer(struct CR_FRAMEBUFFER *pFb) + { + CrFbDisplayBase::setFramebuffer(pFb); + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + pIter->setFramebuffer(pFb); + } + + return VINF_SUCCESS; + } + + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::UpdateBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + rc = pIter->UpdateBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) + { + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + pIter->UpdateEnd(pFb); + } + + CrFbDisplayBase::UpdateEnd(pFb); + } + + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } -#define PCR_DEM_ENTRY_FROM_ENTRY(_pEntry) ((CR_DEM_ENTRY*)((uint8_t*)(_pEntry) - RT_OFFSETOF(CR_DEM_ENTRY, Entry))) + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } -static RTMEMCACHE g_VBoxCrDemLookasideList; -static RTMEMCACHE g_VBoxCrDemInfoLookasideList; + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } -int CrDemGlobalInit() + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual ~CrFbDisplayComposite() + { + cleanup(); + } + + void cleanup(bool fCleanupDisplays = true) + { + CrFbDisplayBase *pIter, *pIterNext; + RTListForEachSafeCpp(&mDisplays, pIter, pIterNext, CrFbDisplayBase, mNode) + { + remove(pIter, fCleanupDisplays); + } + } +private: + RTLISTNODE mDisplays; + uint32_t mcDisplays; +}; + +typedef union CR_FBWIN_FLAGS { - int rc = RTMemCacheCreate(&g_VBoxCrDemLookasideList, sizeof (CR_DEM_ENTRY), - 0, /* size_t cbAlignment */ - UINT32_MAX, /* uint32_t cMaxObjects */ - NULL, /* PFNMEMCACHECTOR pfnCtor*/ - NULL, /* PFNMEMCACHEDTOR pfnDtor*/ - NULL, /* void *pvUser*/ - 0 /* uint32_t fFlags*/ - ); - if (RT_SUCCESS(rc)) + struct { + uint32_t fVisible : 1; + uint32_t fDataPresented : 1; + uint32_t fForcePresentOnReenable : 1; + uint32_t fCompositoEntriesModified : 1; + uint32_t Reserved : 28; + }; + uint32_t Value; +} CR_FBWIN_FLAGS; + +class CrFbWindow +{ +public: + CrFbWindow(uint64_t parentId) : + mSpuWindow(0), + mpCompositor(NULL), + mcUpdates(0), + mxPos(0), + myPos(0), + mWidth(0), + mHeight(0), + mParentId(parentId) { - rc = RTMemCacheCreate(&g_VBoxCrDemInfoLookasideList, sizeof (CR_DEM_ENTRY_INFO), - 0, /* size_t cbAlignment */ - UINT32_MAX, /* uint32_t cMaxObjects */ - NULL, /* PFNMEMCACHECTOR pfnCtor*/ - NULL, /* PFNMEMCACHEDTOR pfnDtor*/ - NULL, /* void *pvUser*/ - 0 /* uint32_t fFlags*/ - ); - if (RT_SUCCESS(rc)) + mFlags.Value = 0; + } + + bool IsCreated() + { + return !!mSpuWindow; + } + + void Destroy() + { + CRASSERT(!mcUpdates); + + if (!mSpuWindow) + return; + + cr_server.head_spu->dispatch_table.WindowDestroy(mSpuWindow); + + mSpuWindow = 0; + mFlags.fDataPresented = 0; + } + + int Reparent(uint64_t parentId) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + uint64_t oldParentId = mParentId; + + mParentId = parentId; + + if (mSpuWindow) + { + if (oldParentId && !parentId && mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, false); + + renderspuSetWindowId(mParentId); + renderspuReparentWindow(mSpuWindow); + renderspuSetWindowId(cr_server.screen[0].winID); + + if (parentId) + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos); + + if (!oldParentId && parentId && mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, true); + } + + return VINF_SUCCESS; + } + + int SetVisible(bool fVisible) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + LOG(("CrWIN: Vidible [%d]", fVisible)); + + if (!fVisible != !mFlags.fVisible) + { + mFlags.fVisible = fVisible; + if (mSpuWindow && mParentId) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, fVisible); + } + + return VINF_SUCCESS; + } + + int SetSize(uint32_t width, uint32_t height) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + LOG(("CrWIN: Size [%d ; %d]", width, height)); + + if (mWidth != width || mHeight != height) + { + mFlags.fCompositoEntriesModified = 1; + mWidth = width; + mHeight = height; + if (mSpuWindow) + cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, width, height); + } + + return VINF_SUCCESS; + } + + int SetPosition(int32_t x, int32_t y) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + LOG(("CrWIN: Pos [%d ; %d]", x, y)); +// always do WindowPosition to ensure window is adjusted properly +// if (x != mxPos || y != myPos) + { + mxPos = x; + myPos = y; + if (mSpuWindow) + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, x, y); + } + + return VINF_SUCCESS; + } + + int SetVisibleRegionsChanged() + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mFlags.fCompositoEntriesModified = 1; + return VINF_SUCCESS; + } + + int SetCompositor(const struct VBOXVR_SCR_COMPOSITOR * pCompositor) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mpCompositor = pCompositor; + mFlags.fCompositoEntriesModified = 1; + return VINF_SUCCESS; + } + + int UpdateBegin() + { + ++mcUpdates; + if (mcUpdates > 1) return VINF_SUCCESS; + + Assert(!mFlags.fForcePresentOnReenable); +// Assert(!mFlags.fCompositoEntriesModified); + + if (mFlags.fDataPresented) + { + Assert(mSpuWindow); + cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, NULL, NULL); + mFlags.fForcePresentOnReenable = isPresentNeeded(); + } + + return VINF_SUCCESS; + } + + void UpdateEnd() + { + --mcUpdates; + Assert(mcUpdates < UINT32_MAX/2); + if (mcUpdates) + return; + + checkRegions(); + + if (mSpuWindow) + { + bool fPresentNeeded = isPresentNeeded(); + if (fPresentNeeded || mFlags.fForcePresentOnReenable) + { + mFlags.fForcePresentOnReenable = false; + cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, mpCompositor, NULL); + } + + /* even if the above branch is entered due to mFlags.fForcePresentOnReenable, + * the backend should clean up the compositor as soon as presentation is performed */ + mFlags.fDataPresented = fPresentNeeded; + } else - crWarning("RTMemCacheCreate failed rc %d", rc); + { + Assert(!mFlags.fDataPresented); + Assert(!mFlags.fForcePresentOnReenable); + } + } - RTMemCacheDestroy(g_VBoxCrDemLookasideList); + uint64_t GetParentId() + { + return mParentId; } - else - crWarning("RTMemCacheCreate failed rc %d", rc); - return VINF_SUCCESS; -} -void CrDemTeGlobalTerm() -{ - RTMemCacheDestroy(g_VBoxCrDemLookasideList); - RTMemCacheDestroy(g_VBoxCrDemInfoLookasideList); -} + int Create() + { + if (mSpuWindow) + { + //WARN(("window already created")); + return VINF_ALREADY_INITIALIZED; + } -static CR_DEM_ENTRY* crDemEntryAlloc() -{ - return (CR_DEM_ENTRY*)RTMemCacheAlloc(g_VBoxCrDemLookasideList); -} + CRASSERT(cr_server.fVisualBitsDefault); + renderspuSetWindowId(mParentId); + mSpuWindow = cr_server.head_spu->dispatch_table.WindowCreate("", cr_server.fVisualBitsDefault); + renderspuSetWindowId(cr_server.screen[0].winID); + if (mSpuWindow < 0) { + WARN(("WindowCreate failed")); + return VERR_GENERAL_FAILURE; + } -static CR_DEM_ENTRY_INFO* crDemEntryInfoAlloc() -{ - return (CR_DEM_ENTRY_INFO*)RTMemCacheAlloc(g_VBoxCrDemInfoLookasideList); -} + cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, mWidth, mHeight); + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos); -static void crDemEntryFree(CR_DEM_ENTRY* pDemEntry) -{ - CrDpEntryCleanup(&pDemEntry->Entry); - RTMemCacheFree(g_VBoxCrDemLookasideList, pDemEntry); -} + checkRegions(); -static void crDemEntryInfoFree(CR_DEM_ENTRY_INFO* pDemEntryInfo) -{ - RTMemCacheFree(g_VBoxCrDemInfoLookasideList, pDemEntryInfo); -} + if (mParentId && mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, true); -void crDemEntryRelease(PCR_DISPLAY_ENTRY_MAP pMap, CR_DEM_ENTRY *pDemEntry) + return VINF_SUCCESS; + } + + ~CrFbWindow() + { + Destroy(); + } +protected: + void checkRegions() + { + if (!mSpuWindow) + return; + + if (!mFlags.fCompositoEntriesModified) + return; + + uint32_t cRects; + const RTRECT *pRects; + if (mpCompositor) + { + int rc = CrVrScrCompositorRegionsGet(mpCompositor, &cRects, NULL, &pRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc)); + cRects = 0; + pRects = NULL; + } + } + else + { + cRects = 0; + pRects = NULL; + } + + cr_server.head_spu->dispatch_table.WindowVisibleRegion(mSpuWindow, cRects, (const GLint*)pRects); + + mFlags.fCompositoEntriesModified = 0; + } + + bool isPresentNeeded() + { + return mFlags.fVisible && mWidth && mHeight && mpCompositor && !CrVrScrCompositorIsEmpty(mpCompositor); + } + + bool checkInitedUpdating() + { + if (!mcUpdates) + { + WARN(("not updating")); + return false; + } + + return true; + } +private: + GLint mSpuWindow; + const struct VBOXVR_SCR_COMPOSITOR * mpCompositor; + uint32_t mcUpdates; + int32_t mxPos; + int32_t myPos; + uint32_t mWidth; + uint32_t mHeight; + CR_FBWIN_FLAGS mFlags; + uint64_t mParentId; +}; + +typedef union CR_FBDISPWINDOW_FLAGS { - CR_DEM_ENTRY_INFO *pInfo = pDemEntry->pInfo; - CRTextureObj *pTobj = pInfo->pTobj; + struct { + uint32_t fNeVisible : 1; + uint32_t fNeForce : 1; + uint32_t Reserved : 30; + }; + uint32_t u32Value; +} CR_FBDISPWINDOW_FLAGS; +class CrFbDisplayWindow : public CrFbDisplayBase +{ +public: + CrFbDisplayWindow(CrFbWindow *pWindow, const RTRECT *pViewportRect) : + mpWindow(pWindow), + mViewportRect(*pViewportRect), + mu32Screen(~0) + { + mFlags.u32Value = 0; + CRASSERT(pWindow); + } - --pInfo->cEntries; + virtual ~CrFbDisplayWindow() + { + if (mpWindow) + delete mpWindow; + } - if (!pInfo->cEntries) + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) { - CR_STATE_SHAREDOBJ_USAGE_CLEAR(pInfo->pTobj, cr_server.MainContextInfo.pContext); + int rc = mpWindow->UpdateBegin(); + if (RT_SUCCESS(rc)) + { + rc = CrFbDisplayBase::UpdateBegin(pFb); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + else + WARN(("err")); + } + else + WARN(("err")); + + return rc; + } - crHashtableDelete(pMap->pTexIdToDemInfoMap, pTobj->id, NULL); + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) + { + CrFbDisplayBase::UpdateEnd(pFb); - crDemEntryInfoFree(pInfo); + mpWindow->UpdateEnd(); } - if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pTobj)) + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - CRSharedState *pShared = crStateGlobalSharedAcquire(); + int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } - CRASSERT(pShared); - /* on the host side, we need to delete an ogl texture object here as well, which crStateDeleteTextureCallback will do - * in addition to calling crStateDeleteTextureObject to delete a state object */ - crHashtableDelete(pShared->textureTable, pTobj->id, crStateDeleteTextureCallback); + if (mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } - crStateGlobalSharedRelease(); + return VINF_SUCCESS; } - crStateGlobalSharedRelease(); + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } - if (!pMap->cEntered) - crDemEntryFree(pDemEntry); - else - RTListNodeInsertAfter(&pMap->ReleasedList, &pDemEntry->Node); -} + if (mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } -int CrDemInit(PCR_DISPLAY_ENTRY_MAP pMap) -{ - pMap->pTexIdToDemInfoMap = crAllocHashtable(); - if (pMap->pTexIdToDemInfoMap) + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - RTListInit(&pMap->ReleasedList); + int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; } - crWarning("crAllocHashtable failed"); - return VERR_NO_MEMORY; -} + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } -void CrDemTerm(PCR_DISPLAY_ENTRY_MAP pMap) -{ - CRASSERT(RTListIsEmpty(&pMap->ReleasedList)); - CRASSERT(!pMap->cEntered); - crFreeHashtable(pMap->pTexIdToDemInfoMap, NULL); - pMap->pTexIdToDemInfoMap = NULL; -} + return screenChanged(); + } -void CrDemEnter(PCR_DISPLAY_ENTRY_MAP pMap) -{ - ++pMap->cEntered; - Assert(pMap->cEntered); -} + const RTRECT* getViewportRect() + { + return &mViewportRect; + } -void CrDemLeave(PCR_DISPLAY_ENTRY_MAP pMap, PCR_DISPLAY_ENTRY pNewEntry, PCR_DISPLAY_ENTRY pReplacedEntry) -{ - Assert(pMap->cEntered); - --pMap->cEntered; - Assert(!pReplacedEntry || pNewEntry); - if (pNewEntry && pReplacedEntry) + virtual int setViewportRect(const RTRECT *pViewportRect) + { + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } + +// always call SetPosition to ensure window is adjustep properly +// if (pViewportRect->xLeft != mViewportRect.xLeft || pViewportRect->yTop != mViewportRect.yTop) + { + const RTRECT* pRect = getRect(); + int rc = mpWindow->SetPosition(pRect->xLeft - pViewportRect->xLeft, pRect->yTop - pViewportRect->yTop); + if (!RT_SUCCESS(rc)) + { + WARN(("SetPosition failed")); + return rc; + } + } + + mViewportRect = *pViewportRect; + + return VINF_SUCCESS; + } + + virtual CrFbWindow * windowDetach() { - CR_DEM_ENTRY *pNewDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pNewEntry); - CR_DEM_ENTRY *pReplacedDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pReplacedEntry); - Assert(!RTListIsEmpty(&pMap->ReleasedList)); - Assert(!RTListIsEmpty(&pReplacedDemEntry->Node)); - Assert(RTListIsEmpty(&pNewDemEntry->Node)); - Assert(!pNewDemEntry->Entry.pvORInstance); - if (!pNewDemEntry->Entry.pvORInstance) + if (isUpdating()) + { + WARN(("updating!")); + return NULL; + } + + CrFbWindow * pWindow = mpWindow; + if (mpWindow) { - pNewDemEntry->Entry.pvORInstance = pReplacedDemEntry->Entry.pvORInstance; - pReplacedDemEntry->Entry.pvORInstance = NULL; + windowCleanup(); + mpWindow = NULL; } - RTListNodeRemove(&pReplacedDemEntry->Node); - crDemEntryFree(pReplacedDemEntry); + return pWindow; } - if (!pMap->cEntered) + virtual CrFbWindow * windowAttach(CrFbWindow * pNewWindow) { - CR_DEM_ENTRY *pCurEntry, *pNextEntry; - RTListForEachSafe(&pMap->ReleasedList, pCurEntry, pNextEntry, CR_DEM_ENTRY, Node) + if (isUpdating()) { - RTListNodeRemove(&pCurEntry->Node); - crDemEntryFree(pCurEntry); + WARN(("updating!")); + return NULL; } + + CrFbWindow * pOld = mpWindow; + if (mpWindow) + windowDetach(); + + mpWindow = pNewWindow; + if (pNewWindow) + windowSync(); + + return mpWindow; } -} -void CrDemEntryRelease(PCR_DISPLAY_ENTRY pEntry) -{ - CR_DEM_ENTRY *pDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pEntry); - crDemEntryRelease(pDemEntry->pMap, pDemEntry); -} + virtual int reparent(uint64_t parentId) + { + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } -int CrDemEntrySaveState(PCR_DISPLAY_ENTRY pEntry, PSSMHANDLE pSSM) -{ - CR_DEM_ENTRY *pDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pEntry); - int rc = SSMR3PutU32(pSSM, pDemEntry->pInfo->pTobj->id); - AssertRCReturn(rc, rc); - return rc; -} + int rc = mpWindow->Reparent(parentId); + if (!RT_SUCCESS(rc)) + WARN(("window reparent failed")); -int CrDemEntryLoadState(PCR_DISPLAY_ENTRY_MAP pMap, PCR_DISPLAY_ENTRY *ppEntry, PSSMHANDLE pSSM) -{ - uint32_t u32; - int rc = SSMR3GetU32(pSSM, &u32); - AssertRCReturn(rc, rc); + mFlags.fNeForce = 1; - PCR_DISPLAY_ENTRY pEntry = CrDemEntryAcquire(pMap, u32, CRBLT_F_INVERT_SRC_YCOORDS); - if (!pEntry) + return rc; + } + + virtual bool isVisible() { - crWarning("CrDemEntryAcquire failed"); - return VERR_NO_MEMORY; + HCR_FRAMEBUFFER hFb = getFramebuffer(); + if (!hFb) + return false; + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb); + return !CrVrScrCompositorIsEmpty(pCompositor); } - *ppEntry = pEntry; - return VINF_SUCCESS; -} + int winVisibilityChanged() + { + int rc = mpWindow->UpdateBegin(); + if (RT_SUCCESS(rc)) + { + rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden); + if (!RT_SUCCESS(rc)) + WARN(("SetVisible failed, rc %d", rc)); + + mpWindow->UpdateEnd(); + } + else + WARN(("UpdateBegin failed, rc %d", rc)); + + return rc; + } + +protected: + virtual void onUpdateEnd() + { + CrFbDisplayBase::onUpdateEnd(); + bool fVisible = isVisible(); + if (mFlags.fNeVisible != fVisible || mFlags.fNeForce) + { + crVBoxServerNotifyEvent(mu32Screen, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA, fVisible ? (void*)1 : NULL); + mFlags.fNeVisible = fVisible; + mFlags.fNeForce = 0; + } + } + + virtual void ueRegions() + { + mpWindow->SetVisibleRegionsChanged(); + } + + virtual int screenChanged() + { + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } + + if (CrFbIsEnabled(getFramebuffer())) + { + const RTRECT* pRect = getRect(); + int rc = mpWindow->SetPosition(pRect->xLeft - mViewportRect.xLeft, pRect->yTop - mViewportRect.yTop); + if (!RT_SUCCESS(rc)) + { + WARN(("SetComposition failed rc %d", rc)); + return rc; + } + + setRegionsChanged(); -PCR_DISPLAY_ENTRY CrDemEntryAcquire(PCR_DISPLAY_ENTRY_MAP pMap, GLuint idTexture, uint32_t fFlags) + return mpWindow->SetSize((uint32_t)(pRect->xRight - pRect->xLeft), (uint32_t)(pRect->yBottom - pRect->yTop)); + } + + return mpWindow->SetVisible(false); + } + + virtual int windowSetCompositor(bool fSet) + { + if (fSet) + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); + return mpWindow->SetCompositor(pCompositor); + } + return mpWindow->SetCompositor(NULL); + } + + virtual int windowCleanup() + { + int rc = mpWindow->UpdateBegin(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = mpWindow->SetVisible(false); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = windowSetCompositor(false); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + mpWindow->UpdateEnd(); + + return VINF_SUCCESS; + } + + virtual int fbCleanup() + { + int rc = windowCleanup(); + if (!RT_SUCCESS(rc)) + { + WARN(("windowCleanup failed")); + return rc; + } + return CrFbDisplayBase::fbCleanup(); + } + + virtual int windowSync() + { + const RTRECT* pRect = getRect(); + + int rc = mpWindow->UpdateBegin(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = windowSetCompositor(true); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = mpWindow->SetPosition(pRect->xLeft - mViewportRect.xLeft, pRect->yTop - mViewportRect.yTop); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = mpWindow->SetSize((uint32_t)(pRect->xRight - pRect->xLeft), (uint32_t)(pRect->yBottom - pRect->yTop)); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + mpWindow->UpdateEnd(); + + return rc; + } + + virtual int fbSync() + { + int rc = CrFbDisplayBase::fbSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + mu32Screen = CrFbGetScreenInfo(getFramebuffer())->u32ViewIndex; + + return windowSync(); + } + + virtual const struct RTRECT* getRect() + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); + return CrVrScrCompositorRectGet(pCompositor); + } + + CrFbWindow* getWindow() {return mpWindow;} +private: + CrFbWindow *mpWindow; + RTRECT mViewportRect; + CR_FBDISPWINDOW_FLAGS mFlags; + uint32_t mu32Screen; +}; + +class CrFbDisplayWindowRootVr : public CrFbDisplayWindow { - CR_DEM_ENTRY *pDemEntry = NULL; +public: + CrFbDisplayWindowRootVr(CrFbWindow *pWindow, const RTRECT *pViewportRect) : + CrFbDisplayWindow(pWindow, pViewportRect) + { + CrVrScrCompositorInit(&mCompositor, NULL); + } - CRSharedState *pShared = crStateGlobalSharedAcquire(); - if (!pShared) + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - crWarning("pShared is null!"); - return NULL; + int rc = CrFbDisplayWindow::EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + Assert(!CrFbDDataEntryGet(hEntry, slotGet())); + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = entryAlloc(); + CrVrScrCompositorEntryInit(pMyEntry, CrVrScrCompositorEntryRectGet(pSrcEntry), CrVrScrCompositorEntryTexGet(pSrcEntry), NULL); + CrVrScrCompositorEntryFlagsSet(pMyEntry, CrVrScrCompositorEntryFlagsGet(pSrcEntry)); + rc = CrFbDDataEntryPut(hEntry, slotGet(), pMyEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbDDataEntryPut failed rc %d", rc)); + entryFree(pMyEntry); + return rc; + } + + return VINF_SUCCESS; } - CRTextureObj *pTobj = (CRTextureObj*)crHashtableSearch(pShared->textureTable, idTexture); - if (!pTobj) + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - crWarning("pTobj is null!"); - crStateGlobalSharedRelease(); - return NULL; + int rc = CrFbDisplayWindow::EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + Assert(pMyEntry); + CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcEntry)); + + return VINF_SUCCESS; } - Assert(pTobj->id == idTexture); + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayWindow::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcNewEntry = CrFbEntryGetCompositorEntry(hNewEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hNewEntry, slotGet()); + CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcNewEntry)); - GLuint hwId = crStateGetTextureObjHWID(pTobj); - if (!hwId) + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - crWarning("hwId is null!"); - crStateGlobalSharedRelease(); - return NULL; + int rc = CrFbDisplayWindow::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcEntry)); + + return VINF_SUCCESS; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayWindow::EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + rc = CrVrScrCompositorEntryRegionsSet(&mCompositor, pMyEntry, NULL, 0, NULL, false, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return VINF_SUCCESS; } - VBOXVR_TEXTURE TextureData; - TextureData.width = pTobj->level[0]->width; - TextureData.height = pTobj->level[0]->height; - TextureData.target = pTobj->target; - TextureData.hwid = hwId; + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayWindow::EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + CrVrScrCompositorEntryCleanup(pMyEntry); + entryFree(pMyEntry); + + return VINF_SUCCESS; + } - pDemEntry = crDemEntryAlloc(); - if (!pDemEntry) + virtual int setViewportRect(const RTRECT *pViewportRect) { - crWarning("crDemEntryAlloc failed allocating CR_DEM_ENTRY"); - crStateGlobalSharedRelease(); - return NULL; + int rc = CrFbDisplayWindow::setViewportRect(pViewportRect); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = setRegionsChanged(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return VINF_SUCCESS; } - CrDpEntryInit(&pDemEntry->Entry, &TextureData, fFlags, crDpEntryCEntryReleaseCB); +protected: + virtual int windowSetCompositor(bool fSet) + { + if (fSet) + return getWindow()->SetCompositor(&mCompositor); + return getWindow()->SetCompositor(NULL); + } - CR_DEM_ENTRY_INFO *pInfo = (CR_DEM_ENTRY_INFO*)crHashtableSearch(pMap->pTexIdToDemInfoMap, pTobj->id); - if (!pInfo) + virtual void ueRegions() { - pInfo = crDemEntryInfoAlloc(); - CRASSERT(pInfo); - crHashtableAdd(pMap->pTexIdToDemInfoMap, pTobj->id, pInfo); - pInfo->cEntries = 0; - pInfo->pTobj = pTobj; + synchCompositorRegions(); } - ++pInfo->cEntries; - pDemEntry->pInfo = pInfo; - pDemEntry->pMap = pMap; - RTListInit(&pDemEntry->Node); + int compositorMarkUpdated() + { + CrVrScrCompositorClear(&mCompositor); - /* just use main context info's context to hold the texture reference */ - CR_STATE_SHAREDOBJ_USAGE_SET(pTobj, cr_server.MainContextInfo.pContext); + int rc = CrVrScrCompositorRectSet(&mCompositor, CrVrScrCompositorRectGet(CrFbGetCompositor(getFramebuffer())), NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } - return &pDemEntry->Entry; -} + rc = setRegionsChanged(); + if (!RT_SUCCESS(rc)) + { + WARN(("screenChanged failed %d", rc)); + return rc; + } -PCR_DISPLAY crServerDisplayGetInitialized(uint32_t idScreen) -{ - if (idScreen >= CR_MAX_GUEST_MONITORS) + return VINF_SUCCESS; + } + + virtual int screenChanged() { - crWarning("invalid idScreen %d", idScreen); - return NULL; + int rc = compositorMarkUpdated(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = CrFbDisplayWindow::screenChanged(); + if (!RT_SUCCESS(rc)) + { + WARN(("screenChanged failed %d", rc)); + return rc; + } + + return VINF_SUCCESS; } - if (ASMBitTest(cr_server.DisplaysInitMap, idScreen)) + virtual const struct RTRECT* getRect() { - Assert(cr_server.aDispplays[idScreen].Mural.screenId == idScreen); - return &cr_server.aDispplays[idScreen]; + return CrVrScrCompositorRectGet(&mCompositor); } - return NULL; -} -static PCR_DISPLAY crServerDisplayGet(uint32_t idScreen) + virtual int fbCleanup() + { + int rc = clearCompositor(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayWindow::fbCleanup(); + } + + virtual int fbSync() + { + int rc = synchCompositor(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayWindow::fbSync(); + } + + VBOXVR_SCR_COMPOSITOR_ENTRY* entryAlloc() + { +#ifndef VBOXVDBG_MEMCACHE_DISABLE + return (VBOXVR_SCR_COMPOSITOR_ENTRY*)RTMemCacheAlloc(g_CrPresenter.CEntryLookasideList); +#else + return (VBOXVR_SCR_COMPOSITOR_ENTRY*)RTMemAlloc(sizeof (VBOXVR_SCR_COMPOSITOR_ENTRY)); +#endif + } + + void entryFree(VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry) + { + Assert(!CrVrScrCompositorEntryIsUsed(pEntry)); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheFree(g_CrPresenter.CEntryLookasideList, pEntry); +#else + RTMemFree(pEntry); +#endif + } + + int synchCompositorRegions() + { + int rc; + + rootVrTranslateForPos(); + + /* ensure the rootvr compositor does not hold any data, + * i.e. cleanup all rootvr entries data */ + CrVrScrCompositorClear(&mCompositor); + + rc = CrVrScrCompositorIntersectedList(CrFbGetCompositor(getFramebuffer()), &cr_server.RootVr, &mCompositor, rootVrGetCEntry, this, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorIntersectedList failed, rc %d", rc)); + return rc; + } + + return getWindow()->SetVisibleRegionsChanged(); + } + + virtual int synchCompositor() + { + int rc = compositorMarkUpdated(); + if (!RT_SUCCESS(rc)) + { + WARN(("compositorMarkUpdated failed, rc %d", rc)); + return rc; + } + + rc = fbSynchAddAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("fbSynchAddAllEntries failed, rc %d", rc)); + return rc; + } + + return rc; + } + + virtual int clearCompositor() + { + return fbCleanupRemoveAllEntries(); + } + + void rootVrTranslateForPos() + { + const RTRECT *pRect = getViewportRect(); + const struct VBVAINFOSCREEN* pScreen = CrFbGetScreenInfo(getFramebuffer()); + int32_t x = pScreen->i32OriginX; + int32_t y = pScreen->i32OriginY; + int32_t dx = cr_server.RootVrCurPoint.x - x; + int32_t dy = cr_server.RootVrCurPoint.y - y; + + cr_server.RootVrCurPoint.x = x; + cr_server.RootVrCurPoint.y = y; + + VBoxVrListTranslate(&cr_server.RootVr, dx, dy); + } + + static DECLCALLBACK(VBOXVR_SCR_COMPOSITOR_ENTRY*) rootVrGetCEntry(const VBOXVR_SCR_COMPOSITOR_ENTRY*pEntry, void *pvContext) + { + CrFbDisplayWindowRootVr *pThis = (CrFbDisplayWindowRootVr*)pvContext; + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, pThis->slotGet()); + Assert(!CrVrScrCompositorEntryIsUsed(pMyEntry)); + CrVrScrCompositorEntryRectSet(&pThis->mCompositor, pMyEntry, CrVrScrCompositorEntryRectGet(pEntry)); + return pMyEntry; + } +private: + VBOXVR_SCR_COMPOSITOR mCompositor; +}; + +class CrFbDisplayVrdp : public CrFbDisplayBase { - if (idScreen >= CR_MAX_GUEST_MONITORS) +public: + CrFbDisplayVrdp() { - crWarning("invalid idScreen %d", idScreen); - return NULL; + memset(&mPos, 0, sizeof (mPos)); } - if (ASMBitTest(cr_server.DisplaysInitMap, idScreen)) + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { - Assert(cr_server.aDispplays[idScreen].Mural.screenId == idScreen); - return &cr_server.aDispplays[idScreen]; + int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("EntryAdded failed rc %d", rc)); + return rc; + } + + Assert(!CrFbDDataEntryGet(hEntry, slotGet())); + rc = vrdpCreate(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("vrdpCreate failed rc %d", rc)); + return rc; + } + + return VINF_SUCCESS; } - int rc = CrDpInit(&cr_server.aDispplays[idScreen]); - if (RT_SUCCESS(rc)) - { - CrDpResize(&cr_server.aDispplays[idScreen], - cr_server.screen[idScreen].x, cr_server.screen[idScreen].y, - cr_server.screen[idScreen].w, cr_server.screen[idScreen].h); - ASMBitSet(cr_server.DisplaysInitMap, idScreen); - return &cr_server.aDispplays[idScreen]; - } - else - { - crWarning("CrDpInit failed for screen %d", idScreen); - } + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } - return NULL; + const VBOXVR_SCR_COMPOSITOR_ENTRY* pReplacedEntry = CrFbEntryGetCompositorEntry(hReplacedEntry); + CR_TEXDATA *pReplacedTex = CrVrScrCompositorEntryTexGet(pReplacedEntry); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pNewEntry = CrFbEntryGetCompositorEntry(hNewEntry); + CR_TEXDATA *pNewTex = CrVrScrCompositorEntryTexGet(pNewEntry); + + CrTdBltDataInvalidateNe(pReplacedTex); + + rc = CrTdBltEnter(pNewTex); + if (RT_SUCCESS(rc)) + { + rc = vrdpFrame(hNewEntry); + CrTdBltLeave(pNewTex); + } + else + WARN(("CrTdBltEnter failed %d", rc)); + + return rc; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + + rc = CrTdBltEnter(pTex); + if (RT_SUCCESS(rc)) + { + rc = vrdpFrame(hEntry); + CrTdBltLeave(pTex); + } + else + WARN(("CrTdBltEnter failed %d", rc)); + + return rc; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + CrTdBltDataInvalidateNe(pTex); + + return vrdpRegions(pFb, hEntry); + } + + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + vrdpDestroy(hEntry); + return VINF_SUCCESS; + } + + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryPosChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + vrdpGeometry(hEntry); + + return VINF_SUCCESS; + } + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return vrdpRegionsAll(pFb); + } + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + syncPos(); + + rc = vrdpSyncEntryAll(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return vrdpRegionsAll(pFb); + } + +protected: + void syncPos() + { + const struct VBVAINFOSCREEN* pScreenInfo = CrFbGetScreenInfo(getFramebuffer()); + mPos.x = pScreenInfo->i32OriginX; + mPos.y = pScreenInfo->i32OriginY; + } + + virtual int fbCleanup() + { + int rc = fbCleanupRemoveAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayBase::fbCleanup(); + } + + virtual int fbSync() + { + syncPos(); + + int rc = fbSynchAddAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayBase::fbSync(); + } +protected: + void vrdpDestroy(HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + cr_server.outputRedirect.CROREnd(pVrdp); + } + + void vrdpGeometry(HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + + cr_server.outputRedirect.CRORGeometry(pVrdp, + mPos.x + CrVrScrCompositorEntryRectGet(pEntry)->xLeft, + mPos.y + CrVrScrCompositorEntryRectGet(pEntry)->yTop, + CrVrScrCompositorEntryTexGet(pEntry)->Tex.width, + CrVrScrCompositorEntryTexGet(pEntry)->Tex.height); + } + + int vrdpRegions(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + uint32_t cRects; + const RTRECT *pRects; + + int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRects, NULL, &pRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc)); + return rc; + } + + cr_server.outputRedirect.CRORVisibleRegion(pVrdp, cRects, pRects); + return VINF_SUCCESS; + } + + int vrdpFrame(HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + const CR_BLITTER_IMG *pImg; + CrTdBltDataInvalidateNe(pTex); + int rc = CrTdBltDataAcquire(pTex, GL_BGRA, !!(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS), &pImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + return rc; + } + + cr_server.outputRedirect.CRORFrame(pVrdp, pImg->pvData, pImg->cbData); + CrTdBltDataRelease(pTex); + return VINF_SUCCESS; + } + + int vrdpRegionsAll(struct CR_FRAMEBUFFER *pFb) + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb); + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + CrVrScrCompositorConstIterInit(pCompositor, &Iter); + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + vrdpRegions(pFb, hEntry); + } + + return VINF_SUCCESS; + } + + int vrdpSynchEntry(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + vrdpGeometry(hEntry); + + return vrdpRegions(pFb, hEntry);; + } + + int vrdpSyncEntryAll(struct CR_FRAMEBUFFER *pFb) + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb); + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + CrVrScrCompositorConstIterInit(pCompositor, &Iter); + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + int rc = vrdpSynchEntry(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("vrdpSynchEntry failed rc %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; + } + + int vrdpCreate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp; + + /* Query supported formats. */ + uint32_t cbFormats = 4096; + char *pachFormats = (char *)crAlloc(cbFormats); + + if (!pachFormats) + { + WARN(("crAlloc failed")); + return VERR_NO_MEMORY; + } + + int rc = cr_server.outputRedirect.CRORContextProperty(cr_server.outputRedirect.pvContext, + 0 /* H3DOR_PROP_FORMATS */, // @todo from a header + pachFormats, cbFormats, &cbFormats); + if (RT_SUCCESS(rc)) + { + if (RTStrStr(pachFormats, "H3DOR_FMT_RGBA_TOPDOWN")) + { + cr_server.outputRedirect.CRORBegin(cr_server.outputRedirect.pvContext, + &pVrdp, + "H3DOR_FMT_RGBA_TOPDOWN"); // @todo from a header + + if (pVrdp) + { + rc = CrFbDDataEntryPut(hEntry, slotGet(), pVrdp); + if (RT_SUCCESS(rc)) + { + vrdpGeometry(hEntry); + vrdpRegions(hFb, hEntry); + //vrdpFrame(hEntry); + return VINF_SUCCESS; + } + else + WARN(("CrFbDDataEntryPut failed rc %d", rc)); + + cr_server.outputRedirect.CROREnd(pVrdp); + } + else + { + WARN(("CRORBegin failed")); + rc = VERR_GENERAL_FAILURE; + } + } + } + else + WARN(("CRORContextProperty failed rc %d", rc)); + + crFree(pachFormats); + + return rc; + } +private: + RTPOINT mPos; +}; + +CrFbDisplayBase::~CrFbDisplayBase() +{ + Assert(!mcUpdates); + + if (mpContainer) + mpContainer->remove(this); +} + + +#if 0 + + + + + +void crDbgDumpRect(uint32_t i, const RTRECT *pRect) +{ + crDebug("%d: (%d;%d) X (%d;%d)", i, pRect->xLeft, pRect->yTop, pRect->xRight, pRect->yBottom); +} + +void crDbgDumpRects(uint32_t cRects, const RTRECT *paRects) +{ + crDebug("Dumping rects (%d)", cRects); + for (uint32_t i = 0; i < cRects; ++i) + { + crDbgDumpRect(i, &paRects[i]); + } + crDebug("End Dumping rects (%d)", cRects); } int crServerDisplaySaveState(PSSMHANDLE pSSM) @@ -736,249 +3394,1147 @@ int crServerDisplaySaveState(PSSMHANDLE pSSM) int crServerDisplayLoadState(PSSMHANDLE pSSM, uint32_t u32Version) { - int rc; - int cDisplays, screenCount, i; - rc = SSMR3GetS32(pSSM, &cDisplays); - AssertRCReturn(rc, rc); +} +#endif - if (!cDisplays) +class CrFbDisplayEntryDataMonitor : public CrFbDisplayBase +{ +public: + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + entryDataChanged(pFb, hReplacedEntry); return VINF_SUCCESS; + } - rc = SSMR3GetS32(pSSM, &screenCount); - AssertRCReturn(rc, rc); + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + entryDataChanged(pFb, hEntry); + return VINF_SUCCESS; + } - CRASSERT(screenCount == cr_server.screenCount); + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + entryDataChanged(pFb, hEntry); + return VINF_SUCCESS; + } +protected: + virtual void entryDataChanged(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { - crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE); + } +}; - for (i = 0; i < cr_server.screenCount; ++i) +int CrPMgrInit() +{ + int rc = VINF_SUCCESS; + memset(&g_CrPresenter, 0, sizeof (g_CrPresenter)); + g_CrPresenter.pFbTexMap = crAllocHashtable(); + if (g_CrPresenter.pFbTexMap) { - int32_t x, y; - uint32_t w, h; - rc = SSMR3GetS32(pSSM, &x); - AssertRCReturn(rc, rc); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + rc = RTMemCacheCreate(&g_CrPresenter.FbEntryLookasideList, sizeof (CR_FRAMEBUFFER_ENTRY), + 0, /* size_t cbAlignment */ + UINT32_MAX, /* uint32_t cMaxObjects */ + NULL, /* PFNMEMCACHECTOR pfnCtor*/ + NULL, /* PFNMEMCACHEDTOR pfnDtor*/ + NULL, /* void *pvUser*/ + 0 /* uint32_t fFlags*/ + ); + if (RT_SUCCESS(rc)) + { + rc = RTMemCacheCreate(&g_CrPresenter.FbTexLookasideList, sizeof (CR_FBTEX), + 0, /* size_t cbAlignment */ + UINT32_MAX, /* uint32_t cMaxObjects */ + NULL, /* PFNMEMCACHECTOR pfnCtor*/ + NULL, /* PFNMEMCACHEDTOR pfnDtor*/ + NULL, /* void *pvUser*/ + 0 /* uint32_t fFlags*/ + ); + if (RT_SUCCESS(rc)) + { + rc = RTMemCacheCreate(&g_CrPresenter.CEntryLookasideList, sizeof (VBOXVR_SCR_COMPOSITOR_ENTRY), + 0, /* size_t cbAlignment */ + UINT32_MAX, /* uint32_t cMaxObjects */ + NULL, /* PFNMEMCACHECTOR pfnCtor*/ + NULL, /* PFNMEMCACHEDTOR pfnDtor*/ + NULL, /* void *pvUser*/ + 0 /* uint32_t fFlags*/ + ); + if (RT_SUCCESS(rc)) + { +#endif + rc = crPMgrModeModifyGlobal(CR_PMGR_MODE_WINDOW, 0); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + else + WARN(("crPMgrModeModifyGlobal failed rc %d", rc)); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); - rc = SSMR3GetS32(pSSM, &y); - AssertRCReturn(rc, rc); + RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); - rc = SSMR3GetU32(pSSM, &w); - AssertRCReturn(rc, rc); + RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); +#endif + } + else + { + WARN(("crAllocHashtable failed")); + rc = VERR_NO_MEMORY; + } + return rc; +} - rc = SSMR3GetU32(pSSM, &h); - AssertRCReturn(rc, rc); +void CrPMgrTerm() +{ + crPMgrModeModifyGlobal(0, CR_PMGR_MODE_ALL); - rc = crVBoxServerMapScreen(i, x, y, w, h, cr_server.screen[i].winID); - AssertRCReturn(rc, rc); + HCR_FRAMEBUFFER hFb; + + for (hFb = CrPMgrFbGetFirstInitialized(); + hFb; + hFb = CrPMgrFbGetNextInitialized(hFb)) + { + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CrFbDisplaySet(hFb, NULL); + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + + if (pInfo->pDpComposite) + delete pInfo->pDpComposite; + + Assert(!pInfo->pDpWin); + Assert(!pInfo->pDpWinRootVr); + Assert(!pInfo->pDpVrdp); + + CrFbTerm(hFb); } - crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList); + RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList); + RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList); +#endif + crFreeHashtable(g_CrPresenter.pFbTexMap, NULL); - for (i = 0; i < cDisplays; ++i) + if (g_CrPresenter.pvTmpBuf) + RTMemFree(g_CrPresenter.pvTmpBuf); + + if (g_CrPresenter.pvTmpBuf2) + RTMemFree(g_CrPresenter.pvTmpBuf2); + + memset(&g_CrPresenter, 0, sizeof (g_CrPresenter)); +} + +HCR_FRAMEBUFFER CrPMgrFbGet(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) { - int iScreen; + WARN(("invalid idScreen %d", idScreen)); + return NULL; + } - rc = SSMR3GetS32(pSSM, &iScreen); - AssertRCReturn(rc, rc); + if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idScreen)) + { + CrFbInit(&g_CrPresenter.aFramebuffers[idScreen], idScreen); + CrFBmSetAtomic(&g_CrPresenter.FramebufferInitMap, idScreen); + } + else + Assert(g_CrPresenter.aFramebuffers[idScreen].ScreenInfo.u32ViewIndex == idScreen); + + return &g_CrPresenter.aFramebuffers[idScreen]; +} - PCR_DISPLAY pDisplay = crServerDisplayGet((uint32_t)iScreen); - if (!pDisplay) +HCR_FRAMEBUFFER CrPMgrFbGetInitialized(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return NULL; + } + + if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idScreen)) + { + return NULL; + } + else + Assert(g_CrPresenter.aFramebuffers[idScreen].ScreenInfo.u32ViewIndex == idScreen); + + return &g_CrPresenter.aFramebuffers[idScreen]; +} + +HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idScreen) +{ + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(idScreen); + + if(hFb && CrFbIsEnabled(hFb)) + return hFb; + + return NULL; +} + +static HCR_FRAMEBUFFER crPMgrFbGetNextEnabled(uint32_t i) +{ + for (;i < cr_server.screenCount; ++i) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(i); + if (hFb) + return hFb; + } + + return NULL; +} + +static HCR_FRAMEBUFFER crPMgrFbGetNextInitialized(uint32_t i) +{ + for (;i < cr_server.screenCount; ++i) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i); + if (hFb) + return hFb; + } + + return NULL; +} + +HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled() +{ + HCR_FRAMEBUFFER hFb = crPMgrFbGetNextEnabled(0); +// if (!hFb) +// WARN(("no enabled framebuffer found")); + return hFb; +} + +HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb) +{ + return crPMgrFbGetNextEnabled(hFb->ScreenInfo.u32ViewIndex+1); +} + +HCR_FRAMEBUFFER CrPMgrFbGetFirstInitialized() +{ + HCR_FRAMEBUFFER hFb = crPMgrFbGetNextInitialized(0); +// if (!hFb) +// WARN(("no initialized framebuffer found")); + return hFb; +} + +HCR_FRAMEBUFFER CrPMgrFbGetNextInitialized(HCR_FRAMEBUFFER hFb) +{ + return crPMgrFbGetNextInitialized(hFb->ScreenInfo.u32ViewIndex+1); +} + +static uint32_t crPMgrModeAdjustVal(uint32_t u32Mode) +{ + u32Mode = CR_PMGR_MODE_ALL & u32Mode; + if (CR_PMGR_MODE_ROOTVR & u32Mode) + u32Mode &= ~CR_PMGR_MODE_WINDOW; + return u32Mode; +} + +int CrPMgrScreenChanged(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return VERR_INVALID_PARAMETER; + } + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pInfo->pDpWin) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGet(idScreen); + if (CrFbIsUpdating(hFb)) { - crWarning("crServerDisplayGet failed"); - return VERR_GENERAL_FAILURE; + WARN(("trying to update viewport while framebuffer is being updated")); + return VERR_INVALID_STATE; } - rc = CrDpLoadState(pDisplay, pSSM, u32Version); - AssertRCReturn(rc, rc); + int rc = pInfo->pDpWin->UpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + pInfo->pDpWin->reparent(cr_server.screen[idScreen].winID); + + pInfo->pDpWin->UpdateEnd(hFb); + } + else + WARN(("UpdateBegin failed %d", rc)); } return VINF_SUCCESS; } -void crServerDisplayTermAll() +int CrPMgrViewportUpdate(uint32_t idScreen) { - int i; - for (i = 0; i < cr_server.screenCount; ++i) + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return VERR_INVALID_PARAMETER; + } + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pInfo->pDpWin) { - if (ASMBitTest(cr_server.DisplaysInitMap, i)) + HCR_FRAMEBUFFER hFb = CrPMgrFbGet(idScreen); + if (CrFbIsUpdating(hFb)) { - CrDpTerm(&cr_server.aDispplays[i]); - ASMBitClear(cr_server.DisplaysInitMap, i); + WARN(("trying to update viewport while framebuffer is being updated")); + return VERR_INVALID_STATE; } + + int rc = pInfo->pDpWin->UpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + pInfo->pDpWin->setViewportRect(&cr_server.screenVieport[idScreen].Rect); + pInfo->pDpWin->UpdateEnd(hFb); + } + else + WARN(("UpdateBegin failed %d", rc)); } + + return VINF_SUCCESS; } -void CrHlpFreeTexImage(CRContext *pCurCtx, GLuint idPBO, void *pvData) +int CrPMgrModeModify(HCR_FRAMEBUFFER hFb, uint32_t u32ModeAdd, uint32_t u32ModeRemove) { - if (idPBO) + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + u32ModeRemove = ((u32ModeRemove | crPMgrModeAdjustVal(u32ModeRemove)) & CR_PMGR_MODE_ALL); + u32ModeAdd = crPMgrModeAdjustVal(u32ModeAdd); + u32ModeRemove &= pInfo->u32Mode; + u32ModeAdd &= ~(u32ModeRemove | pInfo->u32Mode); + uint32_t u32ModeResulting = ((pInfo->u32Mode | u32ModeAdd) & ~u32ModeRemove); + uint32_t u32Tmp = crPMgrModeAdjustVal(u32ModeResulting); + if (u32Tmp != u32ModeResulting) { - cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); - if (pCurCtx) - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pCurCtx->bufferobject.packBuffer->hwid); + u32ModeAdd |= (u32Tmp & ~u32ModeResulting); + u32ModeRemove |= (~u32Tmp & u32ModeResulting); + u32ModeResulting = u32Tmp; + Assert(u32ModeResulting == ((pInfo->u32Mode | u32ModeAdd) & ~u32ModeRemove)); + } + if (!u32ModeRemove && !u32ModeAdd) + return VINF_SUCCESS; + + if (!pInfo->pDpComposite) + { + pInfo->pDpComposite = new CrFbDisplayComposite(); + pInfo->pDpComposite->setFramebuffer(hFb); + } + + CrFbWindow * pOldWin = NULL; + + if (u32ModeRemove & CR_PMGR_MODE_ROOTVR) + { + CRASSERT(pInfo->pDpWinRootVr); + CRASSERT(pInfo->pDpWin == pInfo->pDpWinRootVr); + pInfo->pDpComposite->remove(pInfo->pDpWinRootVr); + pOldWin = pInfo->pDpWinRootVr->windowDetach(); + CRASSERT(pOldWin); + delete pInfo->pDpWinRootVr; + pInfo->pDpWinRootVr = NULL; + pInfo->pDpWin = NULL; + } + else if (u32ModeRemove & CR_PMGR_MODE_WINDOW) + { + CRASSERT(!pInfo->pDpWinRootVr); + CRASSERT(pInfo->pDpWin); + pInfo->pDpComposite->remove(pInfo->pDpWin); + pOldWin = pInfo->pDpWin->windowDetach(); + CRASSERT(pOldWin); + delete pInfo->pDpWin; + pInfo->pDpWin = NULL; + } + + if (u32ModeRemove & CR_PMGR_MODE_VRDP) + { + CRASSERT(pInfo->pDpVrdp); + if (pInfo->pDpComposite) + pInfo->pDpComposite->remove(pInfo->pDpVrdp); else - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + CrFbDisplaySet(hFb, NULL); + + delete pInfo->pDpVrdp; + pInfo->pDpVrdp = NULL; + } + + CrFbDisplayBase *pDpToSet = NULL; + + if (u32ModeAdd & CR_PMGR_MODE_ROOTVR) + { + CRASSERT(!pInfo->pDpWin); + CRASSERT(!pInfo->pDpWinRootVr); + + if (!pOldWin) + pOldWin = new CrFbWindow(cr_server.screen[idScreen].winID); + + pInfo->pDpWinRootVr = new CrFbDisplayWindowRootVr(pOldWin, &cr_server.screenVieport[idScreen].Rect); + pOldWin = NULL; + pInfo->pDpWin = pInfo->pDpWinRootVr; + pInfo->pDpComposite->add(pInfo->pDpWinRootVr); + } + else if (u32ModeAdd & CR_PMGR_MODE_WINDOW) + { + CRASSERT(!pInfo->pDpWin); + CRASSERT(!pInfo->pDpWinRootVr); + + if (!pOldWin) + pOldWin = new CrFbWindow(cr_server.screen[idScreen].winID); + + pInfo->pDpWin = new CrFbDisplayWindow(pOldWin, &cr_server.screenVieport[idScreen].Rect); + pOldWin = NULL; + pInfo->pDpComposite->add(pInfo->pDpWin); + } + + if (u32ModeAdd & CR_PMGR_MODE_VRDP) + { + CRASSERT(!pInfo->pDpVrdp); + pInfo->pDpVrdp = new CrFbDisplayVrdp(); + pInfo->pDpComposite->add(pInfo->pDpVrdp); + } + + if (pInfo->pDpComposite->getDisplayCount() > 1) + { + ICrFbDisplay* pCur = CrFbDisplayGet(hFb); + if (pCur != (ICrFbDisplay*)pInfo->pDpComposite) + CrFbDisplaySet(hFb, pInfo->pDpComposite); } else { - crFree(pvData); - if (pCurCtx && crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_PACK_BUFFER_ARB)) - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pCurCtx->bufferobject.packBuffer->hwid); + ICrFbDisplay* pCur = CrFbDisplayGet(hFb); + ICrFbDisplay* pFirst = pInfo->pDpComposite->first(); + if (pCur != pFirst) + CrFbDisplaySet(hFb, pFirst); } + + if (pOldWin) + delete pOldWin; + + pInfo->u32Mode = u32ModeResulting; + + return VINF_SUCCESS; } -void CrHlpPutTexImage(CRContext *pCurCtx, const VBOXVR_TEXTURE *pTexture, GLenum enmFormat, void *pvData) +static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove) { - CRASSERT(pTexture->hwid); - cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, pTexture->hwid); + g_CrPresenter.u32DisplayMode = (g_CrPresenter.u32DisplayMode | u32ModeAdd) & ~u32ModeRemove; - if (!pCurCtx || crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_UNPACK_BUFFER_ARB)) + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) { - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + CrPMgrModeModify(hFb, u32ModeAdd, u32ModeRemove); } - /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/ - cr_server.head_spu->dispatch_table.TexSubImage2D(GL_TEXTURE_2D, 0 /* level*/, 0 /*xoffset*/, 0 /*yoffset*/, pTexture->width, pTexture->height, enmFormat, GL_UNSIGNED_BYTE, pvData); + return VINF_SUCCESS; +} - /*restore gl state*/ - if (pCurCtx) +int CrPMgrModeVrdp(bool fEnable) +{ + uint32_t u32ModeAdd, u32ModeRemove; + if (fEnable) { - CRTextureObj *pTObj; - CRTextureLevel *pTImg; - crStateGetTextureObjectAndImage(pCurCtx, pTexture->target, 0, &pTObj, &pTImg); + u32ModeAdd = CR_PMGR_MODE_VRDP; + u32ModeRemove = 0; + } + else + { + u32ModeAdd = 0; + u32ModeRemove = CR_PMGR_MODE_VRDP; + } + return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove); +} - GLuint uid = pTObj->hwid; - cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, uid); +int CrPMgrModeRootVr(bool fEnable) +{ + uint32_t u32ModeAdd, u32ModeRemove; + if (fEnable) + { + u32ModeAdd = CR_PMGR_MODE_ROOTVR; + u32ModeRemove = CR_PMGR_MODE_WINDOW; } else { - cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, 0); + u32ModeAdd = CR_PMGR_MODE_WINDOW; + u32ModeRemove = CR_PMGR_MODE_ROOTVR; } - if (pCurCtx && crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_UNPACK_BUFFER_ARB)) - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pCurCtx->bufferobject.unpackBuffer->hwid); + return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove); } -void* CrHlpGetTexImage(CRContext *pCurCtx, const VBOXVR_TEXTURE *pTexture, GLuint idPBO, GLenum enmFormat) +int CrPMgrModeWinVisible(bool fEnable) { - void *pvData = NULL; - cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, pTexture->hwid); + if (!g_CrPresenter.fWindowsForceHidden == !!fEnable) + return VINF_SUCCESS; + + g_CrPresenter.fWindowsForceHidden = !fEnable; - if (idPBO) + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) { - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, idPBO); + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + + if (pInfo->pDpWin) + pInfo->pDpWin->winVisibilityChanged(); } - else + + return VINF_SUCCESS; +} + +int CrPMgrRootVrUpdate() +{ + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) { - if (!pCurCtx || crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_PACK_BUFFER_ARB)) + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + int rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) { - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + pInfo->pDpWinRootVr->RegionsChanged(hFb); + CrFbUpdateEnd(hFb); } + else + WARN(("CrFbUpdateBegin failed %d", rc)); + } - pvData = crAlloc(4*pTexture->width*pTexture->height); - if (!pvData) + return VINF_SUCCESS; +} + +/*helper function that calls CrFbUpdateBegin for all enabled framebuffers */ +int CrPMgrHlpGlblUpdateBegin(CR_FBMAP *pMap) +{ + CrFBmInit(pMap); + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + int rc = CrFbUpdateBegin(hFb); + if (!RT_SUCCESS(rc)) { - crWarning("Out of memory in CrHlpGetTexImage"); - return NULL; + WARN(("UpdateBegin failed, rc %d", rc)); + for (HCR_FRAMEBUFFER hTmpFb = CrPMgrFbGetFirstEnabled(); + hFb != hTmpFb; + hTmpFb = CrPMgrFbGetNextEnabled(hTmpFb)) + { + CrFbUpdateEnd(hTmpFb); + CrFBmClear(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex); + } + return rc; } + + CrFBmSet(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex); } - /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/ - cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, enmFormat, GL_UNSIGNED_BYTE, pvData); + return VINF_SUCCESS; +} - /*restore gl state*/ - if (pCurCtx) +/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */ +void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap) +{ + for (uint32_t i = 0; i < cr_server.screenCount; ++i) { - CRTextureObj *pTObj; - CRTextureLevel *pTImg; - crStateGetTextureObjectAndImage(pCurCtx, pTexture->target, 0, &pTObj, &pTImg); + if (!CrFBmIsSet(pMap, i)) + continue; - GLuint uid = pTObj->hwid; - cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, uid); + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i); + CRASSERT(hFb); + CrFbUpdateEnd(hFb); + } +} + +/*client should notify the manager about the framebuffer resize via this function */ +int CrPMgrNotifyResize(HCR_FRAMEBUFFER hFb) +{ + int rc = VINF_SUCCESS; + if (CrFbIsEnabled(hFb)) + { + rc = CrPMgrModeModify(hFb, g_CrPresenter.u32DisplayMode, 0); + if (!RT_SUCCESS(rc)) + { + WARN(("CrPMgrModeModify failed rc %d", rc)); + return rc; + } } else { - cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, 0); + rc = CrPMgrModeModify(hFb, 0, CR_PMGR_MODE_ALL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrPMgrModeModify failed rc %d", rc)); + return rc; + } } - if (idPBO) + return VINF_SUCCESS; +} + +int CrFbEntrySaveState(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY *hEntry, PSSMHANDLE pSSM) +{ + const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + int rc = SSMR3PutU32(pSSM, pFbTex->pTobj->id); + AssertRCReturn(rc, rc); + uint32_t u32 = 0; + + u32 = CrVrScrCompositorEntryFlagsGet(pEntry); + rc = SSMR3PutU32(pSSM, u32); + AssertRCReturn(rc, rc); + + const RTRECT *pRect = CrVrScrCompositorEntryRectGet(pEntry); + + rc = SSMR3PutS32(pSSM, pRect->xLeft); + AssertRCReturn(rc, rc); + rc = SSMR3PutS32(pSSM, pRect->yTop); + AssertRCReturn(rc, rc); +#if 0 + rc = SSMR3PutS32(pSSM, pRect->xRight); + AssertRCReturn(rc, rc); + rc = SSMR3PutS32(pSSM, pRect->yBottom); + AssertRCReturn(rc, rc); +#endif + + rc = CrVrScrCompositorEntryRegionsGet(&pFb->Compositor, pEntry, &u32, NULL, NULL, &pRect); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, u32); + AssertRCReturn(rc, rc); + + if (u32) + { + rc = SSMR3PutMem(pSSM, pRect, u32 * sizeof (*pRect)); + AssertRCReturn(rc, rc); + } + return rc; +} + +int CrFbSaveState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM) +{ + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter); + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + uint32_t u32 = 0; + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CRASSERT(pTexData); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + if (pFbTex->pTobj) + ++u32; + } + + int rc = SSMR3PutU32(pSSM, u32); + AssertRCReturn(rc, rc); + + CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter); + + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) { - pvData = cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); - if (!pvData) + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + if (pFbTex->pTobj) { - crWarning("Failed to MapBuffer in CrHlpGetTexImage"); - return NULL; + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + rc = CrFbEntrySaveState(pFb, hEntry, pSSM); + AssertRCReturn(rc, rc); } } - CRASSERT(pvData); - return pvData; + return VINF_SUCCESS; } +int CrPMgrSaveState(PSSMHANDLE pSSM) +{ + int rc; + int cDisplays = 0, i; + for (i = 0; i < cr_server.screenCount; ++i) + { + if (CrPMgrFbGetEnabled(i)) + ++cDisplays; + } + + rc = SSMR3PutS32(pSSM, cDisplays); + AssertRCReturn(rc, rc); + + if (!cDisplays) + return VINF_SUCCESS; + + rc = SSMR3PutS32(pSSM, cr_server.screenCount); + AssertRCReturn(rc, rc); + + for (i = 0; i < cr_server.screenCount; ++i) + { + CR_FRAMEBUFFER *hFb = CrPMgrFbGetEnabled(i); + if (hFb) + { + Assert(hFb->ScreenInfo.u32ViewIndex == i); + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32ViewIndex); + AssertRCReturn(rc, rc); + + rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginX); + AssertRCReturn(rc, rc); + + rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginY); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32StartOffset); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32LineSize); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Width); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Height); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16BitsPerPixel); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16Flags); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, (uint32_t)(((uintptr_t)hFb->pvVram) - ((uintptr_t)g_pvVRamBase))); + AssertRCReturn(rc, rc); + + rc = CrFbSaveState(hFb, pSSM); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +int CrFbEntryLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version) +{ + uint32_t texture; + int rc = SSMR3GetU32(pSSM, &texture); + AssertRCReturn(rc, rc); + + uint32_t fFlags; + rc = SSMR3GetU32(pSSM, &fFlags); + AssertRCReturn(rc, rc); + + + HCR_FRAMEBUFFER_ENTRY hEntry; + + rc = CrFbEntryCreateForTexId(pFb, texture, fFlags, &hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryCreateForTexId Failed")); + return rc; + } + + Assert(hEntry); + + const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + + RTPOINT Point; + rc = SSMR3GetS32(pSSM, &Point.x); + AssertRCReturn(rc, rc); + + rc = SSMR3GetS32(pSSM, &Point.y); + AssertRCReturn(rc, rc); + + uint32_t cRects; + rc = SSMR3GetU32(pSSM, &cRects); + AssertRCReturn(rc, rc); + + RTRECT * pRects = NULL; + if (cRects) + { + pRects = (RTRECT *)crAlloc(cRects * sizeof (*pRects)); + AssertReturn(pRects, VERR_NO_MEMORY); + + rc = SSMR3GetMem(pSSM, pRects, cRects * sizeof (*pRects)); + AssertRCReturn(rc, rc); + } + + rc = CrFbEntryRegionsSet(pFb, hEntry, &Point, cRects, pRects, false); + AssertRCReturn(rc, rc); + + if (pRects) + crFree(pRects); + + CrFbEntryRelease(pFb, hEntry); + + return VINF_SUCCESS; +} + +int CrFbLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version) +{ + uint32_t u32 = 0; + int rc = SSMR3GetU32(pSSM, &u32); + AssertRCReturn(rc, rc); + + if (!u32) + return VINF_SUCCESS; + + rc = CrFbUpdateBegin(pFb); + AssertRCReturn(rc, rc); + + for (uint32_t i = 0; i < u32; ++i) + { + rc = CrFbEntryLoadState(pFb, pSSM, version); + AssertRCReturn(rc, rc); + + } + + CrFbUpdateEnd(pFb); + + return VINF_SUCCESS; +} + +int CrPMgrLoadState(PSSMHANDLE pSSM, uint32_t version) +{ + int rc; + int cDisplays, screenCount, i; + + rc = SSMR3GetS32(pSSM, &cDisplays); + AssertRCReturn(rc, rc); + + if (!cDisplays) + return VINF_SUCCESS; + + rc = SSMR3GetS32(pSSM, &screenCount); + AssertRCReturn(rc, rc); + + CRASSERT(screenCount == cr_server.screenCount); + + CRScreenInfo screen[CR_MAX_GUEST_MONITORS]; + + if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO) + { + for (i = 0; i < cr_server.screenCount; ++i) + { + rc = SSMR3GetS32(pSSM, &screen[i].x); + AssertRCReturn(rc, rc); + + rc = SSMR3GetS32(pSSM, &screen[i].y); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &screen[i].w); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &screen[i].h); + AssertRCReturn(rc, rc); + } + } + + for (i = 0; i < cDisplays; ++i) + { + int iScreen; + + rc = SSMR3GetS32(pSSM, &iScreen); + AssertRCReturn(rc, rc); + + CR_FRAMEBUFFER *pFb = CrPMgrFbGet(iScreen); + Assert(pFb); + + rc = CrFbUpdateBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbUpdateBegin failed %d", rc)); + return rc; + } + + VBVAINFOSCREEN Screen; + void *pvVRAM; + + Screen.u32ViewIndex = iScreen; + + if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO) + { + memset(&Screen, 0, sizeof (Screen)); + Screen.u32LineSize = 4 * screen[iScreen].w; + Screen.u32Width = screen[iScreen].w; + Screen.u32Height = screen[iScreen].h; + Screen.u16BitsPerPixel = 4; + Screen.u16Flags = VBVA_SCREEN_F_ACTIVE; + + pvVRAM = g_pvVRamBase; + } + else + { + rc = SSMR3GetS32(pSSM, &Screen.i32OriginX); + AssertRCReturn(rc, rc); + + rc = SSMR3GetS32(pSSM, &Screen.i32OriginY); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32StartOffset); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32LineSize); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32Width); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32Height); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU16(pSSM, &Screen.u16BitsPerPixel); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU16(pSSM, &Screen.u16Flags); + AssertRCReturn(rc, rc); + + uint32_t offVram = 0; + rc = SSMR3GetU32(pSSM, &offVram); + AssertRCReturn(rc, rc); + + pvVRAM = (void*)(((uintptr_t)g_pvVRamBase) + offVram); + } + + crVBoxServerMuralFbResizeBegin(pFb); + + rc = CrFbResize(pFb, &Screen, pvVRAM); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbResize failed %d", rc)); + return rc; + } + + rc = CrFbLoadState(pFb, pSSM, version); + AssertRCReturn(rc, rc); + + crVBoxServerMuralFbResizeEnd(pFb); + + CrFbUpdateEnd(pFb); + + CrPMgrNotifyResize(pFb); + } + + return VINF_SUCCESS; +} + + void SERVER_DISPATCH_APIENTRY crServerDispatchVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects) { uint32_t idScreen = CR_PRESENT_GET_SCREEN(cfg); if (idScreen >= CR_MAX_GUEST_MONITORS) { - crWarning("Invalid guest screen"); + WARN(("Invalid guest screen")); return; } - PCR_DISPLAY pDisplay; - PCR_DISPLAY_ENTRY pEntry = NULL; + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idScreen); + if (!hFb) + { + WARN(("request to present on disabled framebuffer, ignore")); + return; + } + HCR_FRAMEBUFFER_ENTRY hEntry; + int rc; if (texture) { - pEntry = CrDemEntryAcquire(&cr_server.PresentTexturepMap, texture, (cfg & CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD) ? 0 : CRBLT_F_INVERT_SRC_YCOORDS); - if (!pEntry) + rc = CrFbEntryCreateForTexId(hFb, texture, (cfg & CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD) ? 0 : CRBLT_F_INVERT_SRC_YCOORDS, &hEntry); + if (!RT_SUCCESS(rc)) { - crWarning("CrDemEntryAcquire Failed"); + LOG(("CrFbEntryCreateForTexId Failed")); return; } - pDisplay = crServerDisplayGet(idScreen); - if (!pDisplay) + Assert(hEntry); + +#if 0 + if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) { - crWarning("crServerDisplayGet Failed"); - CrDemEntryRelease(pEntry); - return; + CR_SERVER_DUMP_TEXPRESENT(&pEntry->CEntry.Tex); } +#endif } else + hEntry = NULL; + + rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) { - pDisplay = crServerDisplayGetInitialized(idScreen); - if (!pDisplay) + if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) { - /* no display initialized, and nothing to present */ - return; + RTPOINT Point = {xPos, yPos}; + rc = CrFbEntryRegionsAdd(hFb, hEntry, &Point, (uint32_t)cRects, (const RTRECT*)pRects, false); + } + else + { + CrFbRegionsClear(hFb); } - } - if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) + CrFbUpdateEnd(hFb); + } + else { - CR_SERVER_DUMP_TEXPRESENT(&pEntry->CEntry.Tex); + WARN(("CrFbUpdateBegin Failed")); } - CrDpEnter(pDisplay); + if (hEntry) + CrFbEntryRelease(hFb, hEntry); +} + +DECLINLINE(void) crVBoxPRectUnpack(const VBOXCMDVBVA_RECT *pVbvaRect, RTRECT *pRect) +{ + pRect->xLeft = pVbvaRect->xLeft; + pRect->yTop = pVbvaRect->yTop; + pRect->xRight = pVbvaRect->xRight; + pRect->yBottom = pVbvaRect->yBottom; +} - if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) +DECLINLINE(void) crVBoxPRectUnpacks(const VBOXCMDVBVA_RECT *paVbvaRects, RTRECT *paRects, uint32_t cRects) +{ + uint32_t i = 0; + for (; i < cRects; ++i) { - RTPOINT Point = {xPos, yPos}; - int rc = CrDpEntryRegionsAdd(pDisplay, pEntry, &Point, (uint32_t)cRects, (const RTRECT*)pRects, &cr_server.PresentTexturepMap); - if (!RT_SUCCESS(rc)) + crVBoxPRectUnpack(&paVbvaRects[i], &paRects[i]); + } +} + +int32_t crVBoxServerCrCmdBltProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd) +{ + uint8_t u8Flags = pCmd->u8Flags; + if (u8Flags & (VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY | VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY)) + { + VBOXCMDVBVA_BLT_PRIMARY *pBlt = (VBOXCMDVBVA_BLT_PRIMARY*)pCmd; + uint8_t u8PrimaryID = pBlt->Hdr.u8PrimaryID; + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u8PrimaryID); + if (!hFb) { - crWarning("CrDpEntryRegionsAdd Failed rc %d", rc); - /* no need to release anything, as CrDpEntryRegionsAdd would do everything for us as needed */ -// if (pEntry) -// CrDemEntryRelease(pEntry); + WARN(("request to present on disabled framebuffer, ignore")); + pCmd->i8Result = -1; + return VINF_SUCCESS; + } + + const VBOXCMDVBVA_RECT *pPRects = pBlt->aRects; + uint32_t cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) / sizeof (VBOXCMDVBVA_RECT); + RTRECT *pRects; + if (g_CrPresenter.cbTmpBuf < cRects * sizeof (RTRECT)) + { + if (g_CrPresenter.pvTmpBuf) + RTMemFree(g_CrPresenter.pvTmpBuf); + + g_CrPresenter.cbTmpBuf = (cRects + 10) * sizeof (RTRECT); + g_CrPresenter.pvTmpBuf = RTMemAlloc(g_CrPresenter.cbTmpBuf); + if (!g_CrPresenter.pvTmpBuf) + { + WARN(("RTMemAlloc failed!")); + g_CrPresenter.cbTmpBuf = 0; + pCmd->i8Result = -1; + return VINF_SUCCESS; + } + } + + pRects = (RTRECT *)g_CrPresenter.pvTmpBuf; + + crVBoxPRectUnpacks(pPRects, pRects, cRects); + + Assert(!((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) % sizeof (VBOXCMDVBVA_RECT))); + + if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY) + { + if (!(u8Flags & VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY)) + { + /* blit to primary from non-primary */ + uint32_t texId; + if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTID) + { + /* TexPresent */ + texId = pBlt->alloc.id; + } + else + { + VBOXCMDVBVAOFFSET offVRAM = pBlt->alloc.offVRAM; + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + uint32_t cbScreen = pScreen->u32LineSize * pScreen->u32Height; + if (offVRAM >= g_cbVRam + || offVRAM + cbScreen >= g_cbVRam) + { + WARN(("invalid param")); + pCmd->i8Result = -1; + return VINF_SUCCESS; + } + + uint8_t *pu8Buf = g_pvVRamBase + offVRAM; + texId = 0; + /*todo: notify VGA device to perform updates */ + } + + crServerDispatchVBoxTexPresent(texId, u8PrimaryID, pBlt->Pos.x, pBlt->Pos.y, cRects, (const GLint*)pRects); + } + else + { + /* blit from one primary to another primary, wow */ + WARN(("not implemented")); + pCmd->i8Result = -1; + return VINF_SUCCESS; + } + } + else + { + Assert(u8Flags & VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY); + /* blit from primary to non-primary */ + if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTID) + { + uint32_t texId = pBlt->alloc.id; + WARN(("not implemented")); + pCmd->i8Result = -1; + return VINF_SUCCESS; + } + else + { + VBOXCMDVBVAOFFSET offVRAM = pBlt->alloc.offVRAM; + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + uint32_t cbScreen = pScreen->u32LineSize * pScreen->u32Height; + if (offVRAM >= g_cbVRam + || offVRAM + cbScreen >= g_cbVRam) + { + WARN(("invalid param")); + pCmd->i8Result = -1; + return VINF_SUCCESS; + } + + uint8_t *pu8Buf = g_pvVRamBase + offVRAM; + + RTRECT Rect; + Rect.xLeft = pBlt->Pos.x; + Rect.yTop = pBlt->Pos.y; + Rect.xRight = Rect.xLeft + pScreen->u32Width; + Rect.yBottom = Rect.yTop + pScreen->u32Height; + CR_BLITTER_IMG Img; + crFbImgFromScreenVram(pScreen, pu8Buf, &Img); + int rc = CrFbBltGetContents(hFb, &Rect, cRects, pRects, &Img); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbBltGetContents failed %d", rc)); + pCmd->i8Result = -1; + return VINF_SUCCESS; + } + } } } else { - if (pEntry) - CrDemEntryRelease(pEntry); - CrDpRegionsClear(pDisplay); + WARN(("not implemented")); + pCmd->i8Result = -1; + return VINF_SUCCESS; } - CrDpLeave(pDisplay); + pCmd->i8Result = 0; + return VINF_SUCCESS; } |