diff options
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/util/compositor.cpp')
| -rw-r--r-- | src/VBox/GuestHost/OpenGL/util/compositor.cpp | 1015 |
1 files changed, 1015 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/OpenGL/util/compositor.cpp b/src/VBox/GuestHost/OpenGL/util/compositor.cpp new file mode 100644 index 00000000..f7c50bcd --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/util/compositor.cpp @@ -0,0 +1,1015 @@ +/* $Id: compositor.cpp $ */ + +/** @file + * Compositor impl + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ +#include <cr_compositor.h> + +#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX + + +static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects) +{ + Assert(cRects); + + if (pCompositor->cRectsBuffer >= cRects) + { + pCompositor->cRects = cRects; + return VINF_SUCCESS; + } + + if (pCompositor->cRectsBuffer) + { + Assert(pCompositor->paSrcRects); + RTMemFree(pCompositor->paSrcRects); + pCompositor->paSrcRects = NULL; + Assert(pCompositor->paDstRects); + RTMemFree(pCompositor->paDstRects); + pCompositor->paDstRects = NULL; + Assert(pCompositor->paDstUnstretchedRects); + RTMemFree(pCompositor->paDstUnstretchedRects); + pCompositor->paDstUnstretchedRects = NULL; + } + else + { + Assert(!pCompositor->paSrcRects); + Assert(!pCompositor->paDstRects); + Assert(!pCompositor->paDstUnstretchedRects); + } + + pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects); + if (pCompositor->paSrcRects) + { + pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects); + if (pCompositor->paDstRects) + { + pCompositor->paDstUnstretchedRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstUnstretchedRects) * cRects); + if (pCompositor->paDstUnstretchedRects) + { + pCompositor->cRects = cRects; + pCompositor->cRectsBuffer = cRects; + return VINF_SUCCESS; + } + + RTMemFree(pCompositor->paDstRects); + pCompositor->paDstRects = NULL; + } + else + { + WARN(("RTMemAlloc failed!")); + } + RTMemFree(pCompositor->paSrcRects); + pCompositor->paSrcRects = NULL; + } + else + { + WARN(("RTMemAlloc failed!")); + } + + pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED; + pCompositor->cRectsBuffer = 0; + + return VERR_NO_MEMORY; +} + +static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor) +{ + pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED; +} + +static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor) +{ + uint32_t* pCounter = (uint32_t*)pvVisitor; + Assert(VBoxVrListRectsCount(&pEntry->Vr)); + *pCounter += VBoxVrListRectsCount(&pEntry->Vr); + return true; +} + +typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER +{ + PRTRECT paSrcRects; + PRTRECT paDstRects; + PRTRECT paDstUnstretchedRects; + uint32_t cRects; +} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER; + +static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor) +{ + PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor; + PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry); + pEntry->paSrcRects = pData->paSrcRects; + pEntry->paDstRects = pData->paDstRects; + pEntry->paDstUnstretchedRects = pData->paDstUnstretchedRects; + uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr); + Assert(cRects); + Assert(cRects <= pData->cRects); + int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstUnstretchedRects); + AssertRC(rc); + + if (!pEntry->Rect.xLeft && !pEntry->Rect.yTop) + { + memcpy(pEntry->paSrcRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paSrcRects)); + } + else + { + for (uint32_t i = 0; i < cRects; ++i) + { + pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstUnstretchedRects[i].xLeft - pEntry->Rect.xLeft)); + pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstUnstretchedRects[i].yTop - pEntry->Rect.yTop)); + pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstUnstretchedRects[i].xRight - pEntry->Rect.xLeft)); + pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstUnstretchedRects[i].yBottom - pEntry->Rect.yTop)); + } + } + +#ifndef IN_RING0 + if (pCompositor->StretchX != 1. || pCompositor->StretchY != 1.) + { + for (uint32_t i = 0; i < cRects; ++i) + { + if (pCompositor->StretchX != 1.) + { + pEntry->paDstRects[i].xLeft = (int32_t)(pEntry->paDstUnstretchedRects[i].xLeft * pCompositor->StretchX); + pEntry->paDstRects[i].xRight = (int32_t)(pEntry->paDstUnstretchedRects[i].xRight * pCompositor->StretchX); + } + if (pCompositor->StretchY != 1.) + { + pEntry->paDstRects[i].yTop = (int32_t)(pEntry->paDstUnstretchedRects[i].yTop * pCompositor->StretchY); + pEntry->paDstRects[i].yBottom = (int32_t)(pEntry->paDstUnstretchedRects[i].yBottom * pCompositor->StretchY); + } + } + } + else +#endif + { + memcpy(pEntry->paDstRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paDstUnstretchedRects)); + } + +#if 0//ndef IN_RING0 + bool canZeroX = (pCompositor->StretchX < 1.); + bool canZeroY = (pCompositor->StretchY < 1.); + if (canZeroX && canZeroY) + { + /* filter out zero rectangles*/ + uint32_t iOrig, iNew; + for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig) + { + PRTRECT pOrigRect = &pEntry->paDstRects[iOrig]; + if (pOrigRect->xLeft != pOrigRect->xRight + && pOrigRect->yTop != pOrigRect->yBottom) + continue; + + if (iNew != iOrig) + { + PRTRECT pNewRect = &pEntry->paSrcRects[iNew]; + *pNewRect = *pOrigRect; + } + + ++iNew; + } + + Assert(iNew <= iOrig); + + uint32_t cDiff = iOrig - iNew; + + if (cDiff) + { + pCompositor->cRects -= cDiff; + cRects -= cDiff; + } + } +#endif + + pEntry->cRects = cRects; + pData->paDstRects += cRects; + pData->paSrcRects += cRects; + pData->paDstUnstretchedRects += cRects; + pData->cRects -= cRects; + return true; +} + +static int crVrScrCompositorRectsCheckInit(const VBOXVR_SCR_COMPOSITOR *pcCompositor) +{ + VBOXVR_SCR_COMPOSITOR *pCompositor = const_cast<VBOXVR_SCR_COMPOSITOR*>(pcCompositor); + + if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED) + return VINF_SUCCESS; + + uint32_t cRects = 0; + VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects); + + if (!cRects) + { + pCompositor->cRects = 0; + return VINF_SUCCESS; + } + + int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects); + if (!RT_SUCCESS(rc)) + return rc; + + VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData; + AssignerData.paSrcRects = pCompositor->paSrcRects; + AssignerData.paDstRects = pCompositor->paDstRects; + AssignerData.paDstUnstretchedRects = pCompositor->paDstUnstretchedRects; + AssignerData.cRects = pCompositor->cRects; + VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData); + Assert(!AssignerData.cRects); + return VINF_SUCCESS; +} + + +static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangedFlags) +{ + uint32_t fChangedFlags = 0; + PVBOXVR_COMPOSITOR_ENTRY pReplacedEntry; + int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, pEntry ? &pEntry->Ce : NULL, cRegions, paRegions, &pReplacedEntry, &fChangedFlags); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc)); + return rc; + } + + VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacedEntry); + + if (fChangedFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED) + { + crVrScrCompositorRectsInvalidate(pCompositor); + } + else if (fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) + { + Assert(pReplacedScrEntry); + } + + if (fChangedFlags & VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED) + { + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); + } + else if ((fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED) && pEntry) + { + CrVrScrCompositorEntrySetChanged(pEntry, true); + } + + if (pfChangedFlags) + *pfChangedFlags = fChangedFlags; + + if (ppReplacedScrEntry) + *ppReplacedScrEntry = pReplacedScrEntry; + + return VINF_SUCCESS; +} + +static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged) +{ + bool fChanged; + int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc)); + return rc; + } + + if (fChanged) + { + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); + if (!CrVrScrCompositorEntryIsInList(pEntry)) + { + pEntry->cRects = 0; + pEntry->paSrcRects = NULL; + pEntry->paDstRects = NULL; + pEntry->paDstUnstretchedRects = NULL; + } + crVrScrCompositorRectsInvalidate(pCompositor); + } + + + if (pfChanged) + *pfChanged = fChanged; + return VINF_SUCCESS; +} + +static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged) +{ + if (pfChanged) + *pfChanged = false; + if (pEntry && (pEntry->Rect.xLeft != pPos->x || pEntry->Rect.yTop != pPos->y)) + { + if (VBoxVrCompositorEntryIsInList(&pEntry->Ce)) + { + int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Rect.xLeft, pPos->y - pEntry->Rect.yTop, pfChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc)); + return rc; + } + + crVrScrCompositorRectsInvalidate(pCompositor); + } + + VBoxRectMove(&pEntry->Rect, pPos->x, pPos->y); + CrVrScrCompositorEntrySetChanged(pEntry, true); + + if (pfChanged) + *pfChanged = true; + } + return VINF_SUCCESS; +} + +static int crVrScrCompositorEntryEnsureRegionsBounds(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, bool *pfChanged) +{ + RTRECT Rect; + Rect.xLeft = RT_MAX(pCompositor->Rect.xLeft, pEntry->Rect.xLeft); + Rect.yTop = RT_MAX(pCompositor->Rect.yTop, pEntry->Rect.yTop); + Rect.xRight = RT_MIN(pCompositor->Rect.xRight, pEntry->Rect.xRight); + Rect.yBottom = RT_MIN(pCompositor->Rect.yBottom, pEntry->Rect.yBottom); + bool fChanged = false; + + if (pfChanged) + *pfChanged = false; + + int rc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, 1, &Rect, &fChanged); + if (!RT_SUCCESS(rc)) + WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", rc)); + + if (pfChanged) + *pfChanged = fChanged; + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangeFlags) +{ + int rc; + uint32_t fChangeFlags = 0; + bool fPosChanged = false; + RTRECT *paTranslatedRects = NULL; + if (pPos) + { + rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc)); + return rc; + } + } + + if (fPosRelated) + { + if (!pEntry) + { + WARN(("Entry is expected to be specified for pos-related regions")); + return VERR_INVALID_PARAMETER; + } + + if (cRegions && (pEntry->Rect.xLeft || pEntry->Rect.yTop)) + { + paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions); + if (!paTranslatedRects) + { + WARN(("RTMemAlloc failed")); + return VERR_NO_MEMORY; + } + memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions); + for (uint32_t i = 0; i < cRegions; ++i) + { + VBoxRectTranslate(&paTranslatedRects[i], pEntry->Rect.xLeft, pEntry->Rect.yTop); + paRegions = paTranslatedRects; + } + } + } + + rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, ppReplacedScrEntry, &fChangeFlags); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc)); + goto done; + } + + if ((fPosChanged || (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)) && pEntry) + { + bool fAdjusted = false; + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, &fAdjusted); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + goto done; + } + + if (fAdjusted) + { + if (CrVrScrCompositorEntryIsUsed(pEntry)) + { + fChangeFlags &= ~VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED; + fChangeFlags |= VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED; + } + else + { + fChangeFlags = 0; + } + } + } + + if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) + fPosChanged = false; + else if (ppReplacedScrEntry) + *ppReplacedScrEntry = NULL; + + if (pfChangeFlags) + { + if (fPosChanged) + { + /* means entry was in list and was moved, so regions changed */ + *pfChangeFlags = VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED; + } + else + *pfChangeFlags = fChangeFlags; + } + +done: + + if (paTranslatedRects) + RTMemFree(paTranslatedRects); + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTRECT *pRect) +{ + if (!memcmp(&pEntry->Rect, pRect, sizeof (*pRect))) + { + return VINF_SUCCESS; + } + RTPOINT Point = {pRect->xLeft, pRect->yTop}; + bool fChanged = false; + int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, &Point, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryPositionSet failed %d", rc)); + return rc; + } + + pEntry->Rect = *pRect; + + if (!CrVrScrCompositorEntryIsUsed(pEntry)) + return VINF_SUCCESS; + + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryTexAssign(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, CR_TEXDATA *pTex) +{ + if (pEntry->pTex == pTex) + return VINF_SUCCESS; + + if (pEntry->pTex) + CrTdRelease(pEntry->pTex); + if (pTex) + CrTdAddRef(pTex); + pEntry->pTex = pTex; + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, bool *pfChanged) +{ + /* @todo: the fChanged sate calculation is really rough now, this is enough for now though */ + bool fChanged = false, fPosChanged = false; + bool fWasInList = CrVrScrCompositorEntryIsInList(pEntry); + RTRECT *paTranslatedRects = NULL; + int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc)); + return rc; + } + + if (pPos) + { + rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc)); + return rc; + } + } + + if (fPosRelated) + { + if (!pEntry) + { + WARN(("Entry is expected to be specified for pos-related regions")); + return VERR_INVALID_PARAMETER; + } + + if (cRegions && (pEntry->Rect.xLeft || pEntry->Rect.yTop)) + { + paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions); + if (!paTranslatedRects) + { + WARN(("RTMemAlloc failed")); + return VERR_NO_MEMORY; + } + memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions); + for (uint32_t i = 0; i < cRegions; ++i) + { + VBoxRectTranslate(&paTranslatedRects[i], pEntry->Rect.xLeft, pEntry->Rect.yTop); + paRegions = paTranslatedRects; + } + } + } + + rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + return rc; + } + + if (fChanged && CrVrScrCompositorEntryIsUsed(pEntry)) + { + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + return rc; + } + } + + if (pfChanged) + *pfChanged = fPosChanged || fChanged || fWasInList; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + bool fChanged = false; + int rc = VBoxVrCompositorEntryListIntersect(&pCompositor->Compositor, &pEntry->Ce, pList2, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc)); + return rc; + } + + if (fChanged) + { + CrVrScrCompositorEntrySetChanged(pEntry, true); + crVrScrCompositorRectsInvalidate(pCompositor); + } + + if (pfChanged) + *pfChanged = fChanged; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged) +{ + bool fChanged = false; + int rc = VBoxVrCompositorEntryRegionsIntersect(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc)); + return rc; + } + + if (fChanged) + crVrScrCompositorRectsInvalidate(pCompositor); + + if (pfChanged) + *pfChanged = fChanged; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; + CrVrScrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + { + bool fTmpChanged = false; + int tmpRc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged); + if (RT_SUCCESS(tmpRc)) + { + fChanged |= fTmpChanged; + } + else + { + WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc)); + rc = tmpRc; + } + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; + CrVrScrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + { + bool fTmpChanged = false; + int tmpRc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged); + if (RT_SUCCESS(tmpRc)) + { + fChanged |= fTmpChanged; + } + else + { + WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc)); + rc = tmpRc; + } + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos) +{ + int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc)); + return rc; + } + + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: crVrScrCompositorEntryEnsureRegionsBounds failed rc %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + +/* regions are valid until the next CrVrScrCompositor call */ +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects) +{ + if (CrVrScrCompositorEntryIsUsed(pEntry)) + { + int rc = crVrScrCompositorRectsCheckInit(pCompositor); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc)); + return rc; + } + } + + Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED); + + *pcRegions = pEntry->cRects; + if (ppaSrcRegions) + *ppaSrcRegions = pEntry->paSrcRects; + if (ppaDstRegions) + *ppaDstRegions = pEntry->paDstRects; + if (ppaDstUnstretchedRects) + *ppaDstUnstretchedRects = pEntry->paDstUnstretchedRects; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(uint32_t) CrVrScrCompositorEntryFlagsCombinedGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return CRBLT_FOP_COMBINE(pCompositor->fFlags, pEntry->fFlags); +} + +VBOXVREGDECL(void) CrVrScrCompositorEntryFlagsSet(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t fFlags) +{ + if (pEntry->fFlags == fFlags) + return; + + pEntry->fFlags = fFlags; + CrVrScrCompositorEntrySetChanged(pEntry, true); +} + +static void crVrScrCompositorEntryDataCleanup(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry) +{ + pEntry->cRects = 0; + pEntry->paSrcRects = NULL; + pEntry->paDstRects = NULL; + pEntry->paDstUnstretchedRects = NULL; +} + +static void crVrScrCompositorEntryDataCopy(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pToEntry) +{ + pToEntry->cRects = pEntry->cRects; + pToEntry->paSrcRects = pEntry->paSrcRects; + pToEntry->paDstRects = pEntry->paDstRects; + pToEntry->paDstUnstretchedRects = pEntry->paDstUnstretchedRects; + crVrScrCompositorEntryDataCleanup(pEntry); +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry) +{ + if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce)) + return VINF_SUCCESS; + + CrVrScrCompositorEntrySetChanged(pEntry, true); + crVrScrCompositorEntryDataCleanup(pEntry); + + crVrScrCompositorRectsInvalidate(pCompositor); + return VINF_SUCCESS; +} + +VBOXVREGDECL(bool) CrVrScrCompositorEntryReplace(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pNewEntry) +{ + Assert(!CrVrScrCompositorEntryIsUsed(pNewEntry)); + + if (!VBoxVrCompositorEntryReplace(&pCompositor->Compositor, &pEntry->Ce, &pNewEntry->Ce)) + return false; + + CrVrScrCompositorEntrySetChanged(pEntry, true); + crVrScrCompositorEntryDataCopy(pEntry, pNewEntry); + CrVrScrCompositorEntrySetChanged(pNewEntry, true); + + return true; +} + +static DECLCALLBACK(void) crVrScrCompositorEntryReleasedCB(const struct VBOXVR_COMPOSITOR *pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry) +{ + PVBOXVR_SCR_COMPOSITOR_ENTRY pCEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pEntry); + + CrVrScrCompositorEntrySetChanged(pCEntry, true); + + Assert(!CrVrScrCompositorEntryIsInList(pCEntry)); + + if (pReplacingEntry) + { + PVBOXVR_SCR_COMPOSITOR_ENTRY pCReplacingEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacingEntry); + Assert(CrVrScrCompositorEntryIsInList(pCReplacingEntry)); + pCReplacingEntry->cRects = pCEntry->cRects; + pCReplacingEntry->paSrcRects = pCEntry->paSrcRects; + pCReplacingEntry->paDstRects = pCEntry->paDstRects; + pCReplacingEntry->paDstUnstretchedRects = pCEntry->paDstUnstretchedRects; + } + + if (pCEntry->pfnEntryReleased) + { + PVBOXVR_SCR_COMPOSITOR_ENTRY pCReplacingEntry = pReplacingEntry ? VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacingEntry) : NULL; + PVBOXVR_SCR_COMPOSITOR pCConpositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCompositor); + pCEntry->pfnEntryReleased(pCConpositor, pCEntry, pCReplacingEntry); + } +} + +VBOXVREGDECL(int) CrVrScrCompositorRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect, bool *pfChanged) +{ + if (!memcmp(&pCompositor->Rect, pRect, sizeof (pCompositor->Rect))) + { + if (pfChanged) + *pfChanged = false; + return VINF_SUCCESS; + } + + pCompositor->Rect = *pRect; + + VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; + CrVrScrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + { + int rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; +} + +VBOXVREGDECL(void) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect) +{ + memset(pCompositor, 0, sizeof (*pCompositor)); + VBoxVrCompositorInit(&pCompositor->Compositor, crVrScrCompositorEntryReleasedCB); + pCompositor->fFlags = CRBLT_F_LINEAR | CRBLT_F_INVERT_YCOORDS; + if (pRect) + pCompositor->Rect = *pRect; +#ifndef IN_RING0 + pCompositor->StretchX = 1.0; + pCompositor->StretchY = 1.0; +#endif +} + +VBOXVREGDECL(void) CrVrScrCompositorRegionsClear(PVBOXVR_SCR_COMPOSITOR pCompositor, bool *pfChanged) +{ + /* set changed flag first, while entries are in the list and we have them */ + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); + VBoxVrCompositorRegionsClear(&pCompositor->Compositor, pfChanged); + crVrScrCompositorRectsInvalidate(pCompositor); +} + +VBOXVREGDECL(void) CrVrScrCompositorClear(PVBOXVR_SCR_COMPOSITOR pCompositor) +{ + CrVrScrCompositorRegionsClear(pCompositor, NULL); + if (pCompositor->paDstRects) + { + RTMemFree(pCompositor->paDstRects); + pCompositor->paDstRects = NULL; + } + if (pCompositor->paSrcRects) + { + RTMemFree(pCompositor->paSrcRects); + pCompositor->paSrcRects = NULL; + } + if (pCompositor->paDstUnstretchedRects) + { + RTMemFree(pCompositor->paDstUnstretchedRects); + pCompositor->paDstUnstretchedRects = NULL; + } + + pCompositor->cRects = 0; + pCompositor->cRectsBuffer = 0; +} + +VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR CIter; + PVBOXVR_SCR_COMPOSITOR_ENTRY pCurEntry; + CrVrScrCompositorIterInit(pCompositor, &CIter); + + while ((pCurEntry = CrVrScrCompositorIterNext(&CIter)) != NULL) + { + CrVrScrCompositorEntrySetChanged(pCurEntry, fChanged); + } +} + +#ifndef IN_RING0 +VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY) +{ + if (pCompositor->StretchX == StretchX && pCompositor->StretchY == StretchY) + return; + + pCompositor->StretchX = StretchX; + pCompositor->StretchY = StretchY; + crVrScrCompositorRectsInvalidate(pCompositor); + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); +} +#endif + +/* regions are valid until the next CrVrScrCompositor call */ +VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects) +{ + int rc = crVrScrCompositorRectsCheckInit(pCompositor); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc)); + return rc; + } + + Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED); + + *pcRegions = pCompositor->cRects; + if (ppaSrcRegions) + *ppaSrcRegions = pCompositor->paSrcRects; + if (ppaDstRegions) + *ppaDstRegions = pCompositor->paDstRects; + if (ppaDstUnstretchedRects) + *ppaDstUnstretchedRects = pCompositor->paDstUnstretchedRects; + + return VINF_SUCCESS; +} + +typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB +{ + PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor; + void *pvVisitor; +} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB; + +static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor) +{ + PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor; + PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry); + return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor); +} + +VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor) +{ + VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data; + Data.pfnVisitor = pfnVisitor; + Data.pvVisitor = pvVisitor; + VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data); +} + +VBOXVREGDECL(int) CrVrScrCompositorClone(const VBOXVR_SCR_COMPOSITOR *pCompositor, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor) +{ + /* for simplicity just copy from one to another */ + CrVrScrCompositorInit(pDstCompositor, CrVrScrCompositorRectGet(pCompositor)); + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + CrVrScrCompositorConstIterInit(pCompositor, &CIter); + int rc = VINF_SUCCESS; + uint32_t cRects; + const RTRECT *pRects; + + while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL) + { + /* get source rects, that will be non-stretched and entry pos - pased */ + rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRects, NULL, NULL, &pRects); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc)); + return rc; + } + + PVBOXVR_SCR_COMPOSITOR_ENTRY pDstEntry = pfnEntryFor(pEntry, pvEntryFor); + if (!pDstEntry) + { + WARN(("pfnEntryFor failed")); + return VERR_INVALID_STATE; + } + + rc = CrVrScrCompositorEntryRegionsSet(pDstCompositor, pDstEntry, NULL, cRects, pRects, false, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + return rc; + } + } + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorIntersectList(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pVr, bool *pfChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR CIter; + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + CrVrScrCompositorIterInit(pCompositor, &CIter); + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = CrVrScrCompositorIterNext(&CIter)) != NULL) + { + bool fCurChanged = false; + + rc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pVr, &fCurChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + break; + } + + fChanged |= fCurChanged; + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorIntersectedList(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_LIST *pVr, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor, bool *pfChanged) +{ + int rc = CrVrScrCompositorClone(pCompositor, pDstCompositor, pfnEntryFor, pvEntryFor); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorClone failed, rc %d", rc)); + return rc; + } + + rc = CrVrScrCompositorIntersectList(pDstCompositor, pVr, pfChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorIntersectList failed, rc %d", rc)); + CrVrScrCompositorClear(pDstCompositor); + return rc; + } + + return VINF_SUCCESS; +} + |
