diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/HostServices/SharedOpenGL/crserverlib/presenter | |
parent | Initial commit. (diff) | |
download | virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib/presenter')
9 files changed, 7016 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp new file mode 100644 index 00000000..797104f0 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp @@ -0,0 +1,390 @@ +/* $Id: display_base.cpp $ */ + +/** @file + * Presenter API: display base class implementation. + */ + +/* + * Copyright (C) 2014-2019 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 "server_presenter.h" + +CrFbDisplayBase::CrFbDisplayBase() : + mpContainer(NULL), + mpFb(NULL), + mcUpdates(0), + mhSlot(CRHTABLE_HANDLE_INVALID) +{ + mFlags.u32Value = 0; +} + + +CrFbDisplayBase::~CrFbDisplayBase() +{ + Assert(!mcUpdates); + + if (mpContainer) + mpContainer->remove(this); +} + + +bool CrFbDisplayBase::isComposite() +{ + return false; +} + + +class CrFbDisplayComposite* CrFbDisplayBase::getContainer() +{ + return mpContainer; +} + + +bool CrFbDisplayBase::isInList() +{ + return !!mpContainer; +} + + +bool CrFbDisplayBase::isUpdating() +{ + return !!mcUpdates; +} + + +int CrFbDisplayBase::setRegionsChanged() +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::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* CrFbDisplayBase::getFramebuffer() +{ + return mpFb; +} + + +int CrFbDisplayBase::UpdateBegin(struct CR_FRAMEBUFFER *pFb) +{ + ++mcUpdates; + Assert(!mFlags.fRegionsShanged || mcUpdates > 1); + return VINF_SUCCESS; +} + + +void CrFbDisplayBase::UpdateEnd(struct CR_FRAMEBUFFER *pFb) +{ + --mcUpdates; + Assert(mcUpdates < UINT32_MAX/2); + if (!mcUpdates) + onUpdateEnd(); +} + + +int CrFbDisplayBase::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, + HCR_FRAMEBUFFER_ENTRY hReplacedEntry) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::RegionsChanged(struct CR_FRAMEBUFFER *pFb) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::FramebufferChanged(struct CR_FRAMEBUFFER *pFb) +{ + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; +} + + +void CrFbDisplayBase::onUpdateEnd() +{ + if (mFlags.fRegionsShanged) + { + mFlags.fRegionsShanged = 0; + if (getFramebuffer()) /*<-dont't do anything on cleanup*/ + ueRegions(); + } +} + + +void CrFbDisplayBase::ueRegions() +{ +} + + +DECLCALLBACK(bool) CrFbDisplayBase::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; +} + + +DECLCALLBACK(bool) CrFbDisplayBase::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 CrFbDisplayBase::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 CrFbDisplayBase::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; +} + + +int CrFbDisplayBase::setFramebufferBegin(struct CR_FRAMEBUFFER *pFb) +{ + return UpdateBegin(pFb); +} + + +void CrFbDisplayBase::setFramebufferEnd(struct CR_FRAMEBUFFER *pFb) +{ + UpdateEnd(pFb); +} + + +DECLCALLBACK(void) CrFbDisplayBase::slotEntryReleaseCB(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext) +{ +} + + +void CrFbDisplayBase::slotRelease() +{ + Assert(mhSlot); + CrFbDDataReleaseSlot(mpFb, mhSlot, slotEntryReleaseCB, this); +} + + +int CrFbDisplayBase::fbCleanup() +{ + if (mhSlot) + { + slotRelease(); + mhSlot = 0; + } + + mpFb = NULL; + return VINF_SUCCESS; +} + + +int CrFbDisplayBase::fbSync() +{ + return VINF_SUCCESS; +} + + +CRHTABLE_HANDLE CrFbDisplayBase::slotGet() +{ + if (!mhSlot) + { + if (mpFb) + mhSlot = CrFbDDataAllocSlot(mpFb); + } + + return mhSlot; +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp new file mode 100644 index 00000000..697c2c96 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp @@ -0,0 +1,341 @@ +/* $Id: display_composite.cpp $ */ + +/** @file + * Presenter API: display composite class implementation. + */ + +/* + * Copyright (C) 2014-2019 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 "server_presenter.h" + +CrFbDisplayComposite::CrFbDisplayComposite() : + mcDisplays(0) +{ + RTListInit(&mDisplays); +} + + +bool CrFbDisplayComposite::isComposite() +{ + return true; +} + + +uint32_t CrFbDisplayComposite::getDisplayCount() +{ + return mcDisplays; +} + + +bool CrFbDisplayComposite::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 CrFbDisplayComposite::remove(CrFbDisplayBase *pDisplay, bool fCleanupDisplay) +{ + 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* CrFbDisplayComposite::first() +{ + return RTListGetFirstCpp(&mDisplays, CrFbDisplayBase, mNode); +} + + +CrFbDisplayBase* CrFbDisplayComposite::next(CrFbDisplayBase* pDisplay) +{ + if (pDisplay->getContainer() != this) + { + WARN(("invalid entry container")); + return NULL; + } + + return RTListGetNextCpp(&mDisplays, pDisplay, CrFbDisplayBase, mNode); +} + + +int CrFbDisplayComposite::setFramebuffer(struct CR_FRAMEBUFFER *pFb) +{ + CrFbDisplayBase::setFramebuffer(pFb); + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + pIter->setFramebuffer(pFb); + } + + return VINF_SUCCESS; +} + + +int CrFbDisplayComposite::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; +} + + +void CrFbDisplayComposite::UpdateEnd(struct CR_FRAMEBUFFER *pFb) +{ + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + pIter->UpdateEnd(pFb); + } + + CrFbDisplayBase::UpdateEnd(pFb); +} + + +int CrFbDisplayComposite::EntryAdded(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->EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; +} + + +int CrFbDisplayComposite::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; +} + + +int CrFbDisplayComposite::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; + } + + 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; +} + + +int CrFbDisplayComposite::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; +} + + +int CrFbDisplayComposite::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; +} + + +int CrFbDisplayComposite::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; +} + + +int CrFbDisplayComposite::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; +} + + +int CrFbDisplayComposite::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; +} + + +CrFbDisplayComposite::~CrFbDisplayComposite() +{ + cleanup(); +} + + +void CrFbDisplayComposite::cleanup(bool fCleanupDisplays) +{ + CrFbDisplayBase *pIter, *pIterNext; + RTListForEachSafeCpp(&mDisplays, pIter, pIterNext, CrFbDisplayBase, mNode) + { + remove(pIter, fCleanupDisplays); + } +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp new file mode 100644 index 00000000..908117d4 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp @@ -0,0 +1,381 @@ +/* $Id: display_vrdp.cpp $ */ + +/** @file + * Presenter API: CrFbDisplayVrdp class implementation -- display content over VRDP. + */ + +/* + * Copyright (C) 2014-2019 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 "server_presenter.h" + + +CrFbDisplayVrdp::CrFbDisplayVrdp() +{ + memset(&mPos, 0, sizeof (mPos)); +} + + +int CrFbDisplayVrdp::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + 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 CrFbDisplayVrdp::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; + } + + 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; +} + + +int CrFbDisplayVrdp::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; +} + + +int CrFbDisplayVrdp::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); +} + + +int CrFbDisplayVrdp::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; +} + + +int CrFbDisplayVrdp::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; +} + + +int CrFbDisplayVrdp::RegionsChanged(struct CR_FRAMEBUFFER *pFb) +{ + int rc = CrFbDisplayBase::RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return vrdpRegionsAll(pFb); +} + + +int CrFbDisplayVrdp::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); +} + + +void CrFbDisplayVrdp::syncPos() +{ + const struct VBVAINFOSCREEN* pScreenInfo = CrFbGetScreenInfo(getFramebuffer()); + mPos.x = pScreenInfo->i32OriginX; + mPos.y = pScreenInfo->i32OriginY; +} + +int CrFbDisplayVrdp::fbCleanup() +{ + int rc = fbCleanupRemoveAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayBase::fbCleanup(); +} + + +int CrFbDisplayVrdp::fbSync() +{ + syncPos(); + + int rc = fbSynchAddAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayBase::fbSync(); +} + + +void CrFbDisplayVrdp::vrdpDestroy(HCR_FRAMEBUFFER_ENTRY hEntry) +{ + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + cr_server.outputRedirect.CROREnd(pVrdp); +} + + +void CrFbDisplayVrdp::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 CrFbDisplayVrdp::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, &pRects, NULL, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc)); + return rc; + } + + cr_server.outputRedirect.CRORVisibleRegion(pVrdp, cRects, pRects); + return VINF_SUCCESS; +} + + +int CrFbDisplayVrdp::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 CrFbDisplayVrdp::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 CrFbDisplayVrdp::vrdpSynchEntry(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + vrdpGeometry(hEntry); + + return vrdpRegions(pFb, hEntry);; +} + + +int CrFbDisplayVrdp::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 CrFbDisplayVrdp::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; +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp new file mode 100644 index 00000000..c888987c --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp @@ -0,0 +1,574 @@ +/* $Id: display_window.cpp $ */ + +/** @file + * Presenter API: CrFbDisplayWindow class implementation -- display content into host GUI window. + */ + +/* + * Copyright (C) 2014-2019 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 "server_presenter.h" + +CrFbDisplayWindow::CrFbDisplayWindow(const RTRECT *pViewportRect, uint64_t parentId) : + mpWindow(NULL), + mViewportRect(*pViewportRect), + mu32Screen(~0), + mParentId(parentId) +{ + mFlags.u32Value = 0; +} + + +CrFbDisplayWindow::~CrFbDisplayWindow() +{ + if (mpWindow) + delete mpWindow; +} + + +int CrFbDisplayWindow::UpdateBegin(struct CR_FRAMEBUFFER *pFb) +{ + int rc = mpWindow ? mpWindow->UpdateBegin() : VINF_SUCCESS; + if (RT_SUCCESS(rc)) + { + rc = CrFbDisplayBase::UpdateBegin(pFb); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + else + { + WARN(("err")); + if (mpWindow) + mpWindow->UpdateEnd(); + } + } + else + WARN(("err")); + + return rc; +} + + +void CrFbDisplayWindow::UpdateEnd(struct CR_FRAMEBUFFER *pFb) +{ + CrFbDisplayBase::UpdateEnd(pFb); + + if (mpWindow) + mpWindow->UpdateEnd(); +} + + +int CrFbDisplayWindow::RegionsChanged(struct CR_FRAMEBUFFER *pFb) +{ + int rc = CrFbDisplayBase::RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpWindow && mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + return VINF_SUCCESS; +} + + +int CrFbDisplayWindow::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpWindow && mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + return VINF_SUCCESS; +} + + +int CrFbDisplayWindow::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 (mpWindow && mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + return VINF_SUCCESS; +} + + +int CrFbDisplayWindow::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpWindow && mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + return VINF_SUCCESS; +} + + +int CrFbDisplayWindow::FramebufferChanged(struct CR_FRAMEBUFFER *pFb) +{ + int rc = CrFbDisplayBase::FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return screenChanged(); +} + + +const RTRECT* CrFbDisplayWindow::getViewportRect() +{ + return &mViewportRect; +} + + +int CrFbDisplayWindow::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) + if (mpWindow) + { + 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; +} + + +CrFbWindow * CrFbDisplayWindow::windowDetach(bool fCleanup) +{ + if (isUpdating()) + { + WARN(("updating!")); + return NULL; + } + + CrFbWindow * pWindow = mpWindow; + if (mpWindow) + { + if (fCleanup) + windowCleanup(); + mpWindow = NULL; + } + return pWindow; +} + + +CrFbWindow * CrFbDisplayWindow::windowAttach(CrFbWindow * pNewWindow) +{ + if (isUpdating()) + { + WARN(("updating!")); + return NULL; + } + + CrFbWindow * pOld = mpWindow; + if (mpWindow) + windowDetach(); + + mpWindow = pNewWindow; + if (pNewWindow) + windowSync(); + + return mpWindow; +} + + +int CrFbDisplayWindow::reparent(uint64_t parentId) +{ + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } + + crDebug("CrFbDisplayWindow: change parent from %p to %p.", mParentId, parentId); + + mParentId = parentId; + int rc = VINF_SUCCESS; + + /* Force notify Render SPU about parent window ID change in order to prevent + * crashes when it tries to access already deallocated parent window. + * Previously, we also used isActive() here, however it might become FALSE for the case + * when VM Window goes fullscreen mode and back. */ + if ( /* isActive() && */ mpWindow) + { + rc = mpWindow->Reparent(parentId); + if (!RT_SUCCESS(rc)) + WARN(("window reparent failed")); + + mFlags.fNeForce = 1; + } + + return rc; +} + + +bool CrFbDisplayWindow::isVisible() +{ + HCR_FRAMEBUFFER hFb = getFramebuffer(); + if (!hFb) + return false; + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb); + return !CrVrScrCompositorIsEmpty(pCompositor); +} + + +int CrFbDisplayWindow::winVisibilityChanged() +{ + HCR_FRAMEBUFFER hFb = getFramebuffer(); + if (!hFb || !CrFbIsEnabled(hFb)) + { + Assert(!mpWindow || !mpWindow->IsVisivle()); + return VINF_SUCCESS; + } + + int rc = VINF_SUCCESS; + + if (mpWindow) + { + 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; +} + + +CrFbWindow* CrFbDisplayWindow::getWindow() +{ + return mpWindow; +} + + +void CrFbDisplayWindow::onUpdateEnd() +{ + CrFbDisplayBase::onUpdateEnd(); + bool fVisible = isVisible(); + if (mFlags.fNeVisible != fVisible || mFlags.fNeForce) + { + crVBoxServerNotifyEvent(mu32Screen, + fVisible? VBOX3D_NOTIFY_EVENT_TYPE_3DDATA_VISIBLE: + VBOX3D_NOTIFY_EVENT_TYPE_3DDATA_HIDDEN, + NULL, 0); + mFlags.fNeVisible = fVisible; + mFlags.fNeForce = 0; + } +} + + +void CrFbDisplayWindow::ueRegions() +{ + if (mpWindow) + mpWindow->SetVisibleRegionsChanged(); +} + + +int CrFbDisplayWindow::screenChanged() +{ + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } + + int rc = windowDimensionsSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("windowDimensionsSync failed rc %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + + +int CrFbDisplayWindow::windowSetCompositor(bool fSet) +{ + if (!mpWindow) + return VINF_SUCCESS; + + if (fSet) + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); + return mpWindow->SetCompositor(pCompositor); + } + return mpWindow->SetCompositor(NULL); +} + + +int CrFbDisplayWindow::windowCleanup() +{ + if (!mpWindow) + return VINF_SUCCESS; + + int rc = mpWindow->UpdateBegin(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = windowDimensionsSync(true); + 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; +} + + +int CrFbDisplayWindow::fbCleanup() +{ + int rc = windowCleanup(); + if (!RT_SUCCESS(rc)) + { + WARN(("windowCleanup failed")); + return rc; + } + return CrFbDisplayBase::fbCleanup(); +} + + +bool CrFbDisplayWindow::isActive() +{ + HCR_FRAMEBUFFER hFb = getFramebuffer(); + return hFb && CrFbIsEnabled(hFb); +} + + +int CrFbDisplayWindow::windowDimensionsSync(bool fForceCleanup) +{ + int rc = VINF_SUCCESS; + + if (!mpWindow) + return VINF_SUCCESS; + + //HCR_FRAMEBUFFER hFb = getFramebuffer(); + if (!fForceCleanup && isActive()) + { + const RTRECT* pRect = getRect(); + + if (mpWindow->GetParentId() != mParentId) + { + rc = mpWindow->Reparent(mParentId); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + rc = mpWindow->SetPosition(pRect->xLeft - mViewportRect.xLeft, pRect->yTop - mViewportRect.yTop); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + setRegionsChanged(); + + rc = mpWindow->SetSize((uint32_t)(pRect->xRight - pRect->xLeft), (uint32_t)(pRect->yBottom - pRect->yTop)); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + else + { + rc = mpWindow->SetVisible(false); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } +#if 0 + rc = mpWindow->Reparent(mDefaultParentId); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } +#endif + } + + return rc; +} + + +int CrFbDisplayWindow::windowSync() +{ + if (!mpWindow) + return VINF_SUCCESS; + + 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 = windowDimensionsSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + mpWindow->UpdateEnd(); + + return rc; +} + + +int CrFbDisplayWindow::fbSync() +{ + int rc = CrFbDisplayBase::fbSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + HCR_FRAMEBUFFER hFb = getFramebuffer(); + + mu32Screen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + + rc = windowSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("windowSync failed %d", rc)); + return rc; + } + + if (CrFbHas3DData(hFb)) + { + if (mpWindow && mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + } + + return VINF_SUCCESS; +} + + +const struct RTRECT* CrFbDisplayWindow::getRect() +{ + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); + return CrVrScrCompositorRectGet(pCompositor); +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp new file mode 100644 index 00000000..ddc76848 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp @@ -0,0 +1,347 @@ +/* $Id: display_window_rootvr.cpp $ */ + +/** @file + * Presenter API: CrFbDisplayWindowRootVr class implementation -- display seamless content (visible regions). + */ + +/* + * Copyright (C) 2014-2019 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 "server_presenter.h" + + +CrFbDisplayWindowRootVr::CrFbDisplayWindowRootVr(const RTRECT *pViewportRect, uint64_t parentId) : + CrFbDisplayWindow(pViewportRect, parentId) +{ + CrVrScrCompositorInit(&mCompositor, NULL); +} + + +int CrFbDisplayWindowRootVr::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + 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; +} + + +int CrFbDisplayWindowRootVr::EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + 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; +} + + +int CrFbDisplayWindowRootVr::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)); + + return VINF_SUCCESS; +} + + +int CrFbDisplayWindowRootVr::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + 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; +} + + +int CrFbDisplayWindowRootVr::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; +} + + +int CrFbDisplayWindowRootVr::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; +} + + +int CrFbDisplayWindowRootVr::setViewportRect(const RTRECT *pViewportRect) +{ + 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; +} + + +int CrFbDisplayWindowRootVr::windowSetCompositor(bool fSet) +{ + if (fSet) + return getWindow()->SetCompositor(&mCompositor); + return getWindow()->SetCompositor(NULL); +} + + +void CrFbDisplayWindowRootVr::ueRegions() +{ + synchCompositorRegions(); +} + + +int CrFbDisplayWindowRootVr::compositorMarkUpdated() +{ + CrVrScrCompositorClear(&mCompositor); + + int rc = CrVrScrCompositorRectSet(&mCompositor, CrVrScrCompositorRectGet(CrFbGetCompositor(getFramebuffer())), NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = setRegionsChanged(); + if (!RT_SUCCESS(rc)) + { + WARN(("screenChanged failed %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + + +int CrFbDisplayWindowRootVr::screenChanged() +{ + 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; +} + + +const struct RTRECT* CrFbDisplayWindowRootVr::getRect() +{ + return CrVrScrCompositorRectGet(&mCompositor); +} + +int CrFbDisplayWindowRootVr::fbCleanup() +{ + int rc = clearCompositor(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayWindow::fbCleanup(); +} + + +int CrFbDisplayWindowRootVr::fbSync() +{ + int rc = synchCompositor(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayWindow::fbSync(); +} + + +VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbDisplayWindowRootVr::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 CrFbDisplayWindowRootVr::entryFree(VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry) +{ + Assert(!CrVrScrCompositorEntryIsUsed(pEntry)); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheFree(g_CrPresenter.CEntryLookasideList, pEntry); +#else + RTMemFree(pEntry); +#endif +} + + +int CrFbDisplayWindowRootVr::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(); +} + + +int CrFbDisplayWindowRootVr::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; +} + + +int CrFbDisplayWindowRootVr::clearCompositor() +{ + return fbCleanupRemoveAllEntries(); +} + + +void CrFbDisplayWindowRootVr::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); +} + + +DECLCALLBACK(VBOXVR_SCR_COMPOSITOR_ENTRY*) CrFbDisplayWindowRootVr::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; +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp new file mode 100644 index 00000000..7ced10de --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp @@ -0,0 +1,4063 @@ +/* $Id: server_presenter.cpp $ */ + +/** @file + * Presenter API + */ + +/* + * Copyright (C) 2012-2019 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. + */ + +#ifdef DEBUG_misha +# define VBOXVDBG_MEMCACHE_DISABLE +#endif + +#ifndef VBOXVDBG_MEMCACHE_DISABLE +# include <iprt/memcache.h> +#endif + +#include "server_presenter.h" + +//#define CR_SERVER_WITH_CLIENT_CALLOUTS + +#define PCR_FBTEX_FROM_TEX(_pTex) ((CR_FBTEX*)((uint8_t*)(_pTex) - RT_UOFFSETOF(CR_FBTEX, Tex))) +#define PCR_FRAMEBUFFER_FROM_COMPOSITOR(_pCompositor) ((CR_FRAMEBUFFER*)((uint8_t*)(_pCompositor) - RT_UOFFSETOF(CR_FRAMEBUFFER, Compositor))) +#define PCR_FBENTRY_FROM_ENTRY(_pEntry) ((CR_FRAMEBUFFER_ENTRY*)((uint8_t*)(_pEntry) - RT_UOFFSETOF(CR_FRAMEBUFFER_ENTRY, Entry))) + + +static int crPMgrFbConnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeAdd); + +CR_PRESENTER_GLOBALS g_CrPresenter; + +/* FRAMEBUFFER */ + +void CrFbInit(CR_FRAMEBUFFER *pFb, uint32_t idFb) +{ + 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 = idFb; + CrVrScrCompositorInit(&pFb->Compositor, &Rect); + RTListInit(&pFb->EntriesList); + CrHTableCreate(&pFb->SlotTable, 0); +} + + +bool CrFbIsEnabled(CR_FRAMEBUFFER *pFb) +{ + return !(pFb->ScreenInfo.u16Flags & VBVA_SCREEN_F_DISABLED); +} + + +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 CrFbUpdateBegin(CR_FRAMEBUFFER *pFb) +{ + ++pFb->cUpdating; + + if (pFb->cUpdating == 1) + { + if (pFb->pDisplay) + pFb->pDisplay->UpdateBegin(pFb); + } + + return VINF_SUCCESS; +} + +void CrFbUpdateEnd(CR_FRAMEBUFFER *pFb) +{ + if (!pFb->cUpdating) + { + WARN(("invalid UpdateEnd call!")); + return; + } + + --pFb->cUpdating; + + if (!pFb->cUpdating) + { + if (pFb->pDisplay) + pFb->pDisplay->UpdateEnd(pFb); + } +} + +bool CrFbIsUpdating(const CR_FRAMEBUFFER *pFb) +{ + return !!pFb->cUpdating; +} + +bool CrFbHas3DData(HCR_FRAMEBUFFER hFb) +{ + return !CrVrScrCompositorIsEmpty(&hFb->Compositor); +} + +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; +} + +static void crFbImgFromDimPtrBGRA(void *pvVram, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg) +{ + pImg->pvData = pvVram; + pImg->cbData = width * height * 4; + pImg->enmFormat = GL_BGRA; + pImg->width = width; + pImg->height = height; + pImg->bpp = 32; + pImg->pitch = width * 4; +} + +static int8_t crFbImgFromDimOffVramBGRA(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg) +{ + uint32_t cbBuff = width * height * 4; + if (offVRAM >= g_cbVRam + || offVRAM + cbBuff >= g_cbVRam) + { + WARN(("invalid param")); + return -1; + } + + uint8_t *pu8Buf = g_pvVRamBase + offVRAM; + crFbImgFromDimPtrBGRA(pu8Buf, width, height, pImg); + + return 0; +} + +static int8_t crFbImgFromDescBGRA(const VBOXCMDVBVA_ALLOCDESC *pDesc, CR_BLITTER_IMG *pImg) +{ + return crFbImgFromDimOffVramBGRA(pDesc->Info.u.offVRAM, pDesc->u16Width, pDesc->u16Height, pImg); +} + +static void crFbImgFromFb(HCR_FRAMEBUFFER hFb, CR_BLITTER_IMG *pImg) +{ + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + void *pvVram = CrFbGetVRAM(hFb); + crFbImgFromScreenVram(pScreen, pvVram, pImg); +} + +static int crFbTexDataGetContents(CR_TEXDATA *pTex, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst) +{ + const CR_BLITTER_IMG *pSrcImg; + int rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + return rc; + } + + CrMBltImg(pSrcImg, pPos, cRects, pRects, pDst); + + CrTdBltDataRelease(pTex); + + return VINF_SUCCESS; +} + +static int crFbBltGetContentsScaledDirect(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst) +{ + VBOXVR_LIST List; + uint32_t c2DRects = 0; + CR_TEXDATA *pEnteredTex = NULL; + PCR_BLITTER pEnteredBlitter = NULL; + + /* Scaled texture size and rect calculated for every new "entered" texture. */ + uint32_t width = 0, height = 0; + RTRECT ScaledSrcRect = {0}; + + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + int32_t srcWidth = pSrcRectSize->cx; + int32_t srcHeight = pSrcRectSize->cy; + int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft; + int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop; + + RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop}; + float strX = ((float)dstWidth) / srcWidth; + float strY = ((float)dstHeight) / srcHeight; + bool fScale = (dstWidth != srcWidth || dstHeight != srcHeight); + Assert(fScale); + + /* 'List' contains the destination rectangles to be updated (in pDst coords). */ + VBoxVrListInit(&List); + int rc = VBoxVrListRectsAdd(&List, cRects, pRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsAdd failed rc %d", rc)); + goto end; + } + + CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter); + + for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter); + pEntry; + pEntry = CrVrScrCompositorConstIterNext(&Iter)) + { + /* Where the entry would be located in pDst coords, i.e. convert pEntry hFb coord to pDst coord. */ + RTPOINT ScaledEntryPoint; + ScaledEntryPoint.x = CR_FLOAT_RCAST(int32_t, strX * CrVrScrCompositorEntryRectGet(pEntry)->xLeft) + pDstRect->xLeft; + ScaledEntryPoint.y = CR_FLOAT_RCAST(int32_t, strY * CrVrScrCompositorEntryRectGet(pEntry)->yTop) + pDstRect->yTop; + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + + /* Optimization to avoid entering/leaving the same texture and its blitter. */ + 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); + ScaledSrcRect.xLeft = ScaledEntryPoint.x; + ScaledSrcRect.yTop = ScaledEntryPoint.y; + ScaledSrcRect.xRight = width + ScaledEntryPoint.x; + ScaledSrcRect.yBottom = height + ScaledEntryPoint.y; + } + + bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS); + + /* pRegions is where the pEntry was drawn in hFb coords. */ + 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; + } + + /* CrTdBltDataAcquireScaled/CrTdBltDataReleaseScaled can use cached data, + * so it is not necessary to optimize and Aquire only when Tex changes. + */ + const CR_BLITTER_IMG *pSrcImg; + rc = CrTdBltDataAcquireScaled(pTex, GL_BGRA, false, width, height, &pSrcImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + goto end; + } + + for (uint32_t j = 0; j < cRegions; ++j) + { + /* rects are in dst coordinates, + * while the pReg is in source coords + * convert */ + const RTRECT * pReg = &pRegions[j]; + RTRECT ScaledReg; + /* scale */ + VBoxRectScaled(pReg, strX, strY, &ScaledReg); + /* translate */ + VBoxRectTranslate(&ScaledReg, pDstRect->xLeft, pDstRect->yTop); + + /* Exclude the pEntry rectangle, because it will be updated now in pDst. + * List uses dst coords and pRegions use hFb coords, therefore use + * ScaledReg which is already translated to dst. + */ + rc = VBoxVrListRectsSubst(&List, 1, &ScaledReg, 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]; + + RTRECT Intersection; + VBoxRectIntersected(pRect, &ScaledReg, &Intersection); + if (VBoxRectIsZero(&Intersection)) + continue; + + VBoxRectIntersect(&Intersection, &ScaledSrcRect); + if (VBoxRectIsZero(&Intersection)) + continue; + + CrMBltImgRect(pSrcImg, &ScaledEntryPoint, fInvert, &Intersection, pDst); + } + } + + CrTdBltDataReleaseScaled(pTex, pSrcImg); + } + + /* Blit still not updated dst rects, i.e. not covered by 3D entries. */ + c2DRects = VBoxVrListRectsCount(&List); + if (c2DRects) + { + if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT)) + { + if (g_CrPresenter.pvTmpBuf2) + RTMemFree(g_CrPresenter.pvTmpBuf2); + + 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; + } + } + + RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2; + + rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsGet failed, rc %d", rc)); + goto end; + } + + /* p2DRects are in pDst coords and already scaled. */ + + CR_BLITTER_IMG FbImg; + + crFbImgFromFb(hFb, &FbImg); + + CrMBltImgScaled(&FbImg, pSrcRectSize, pDstRect, c2DRects, p2DRects, pDst); + } + +end: + + if (pEnteredTex) + CrTdBltLeave(pEnteredTex); + + if (pEnteredBlitter) + CrBltLeave(pEnteredBlitter); + + VBoxVrListClear(&List); + + return rc; +} + +static int crFbBltGetContentsScaledCPU(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + WARN(("not implemented!")); + return VERR_NOT_IMPLEMENTED; +#if 0 + int32_t srcWidth = pSrcRectSize->cx; + int32_t srcHeight = pSrcRectSize->cy; + int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft; + int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop; + + RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop}; + float strX = ((float)dstWidth) / srcWidth; + float strY = ((float)dstHeight) / srcHeight; + + RTPOINT UnscaledPos; + UnscaledPos.x = CR_FLOAT_RCAST(int32_t, pDstRect->xLeft / strX); + UnscaledPos.y = CR_FLOAT_RCAST(int32_t, pDstRect->yTop / strY); + + /* 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, &UnscaledPos, 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; +#endif +} + +static int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst) +{ + VBOXVR_LIST List; + uint32_t c2DRects = 0; + CR_TEXDATA *pEnteredTex = NULL; + PCR_BLITTER pEnteredBlitter = NULL; + + /* 'List' contains the destination rectangles to be updated (in pDst coords). */ + VBoxVrListInit(&List); + int rc = VBoxVrListRectsAdd(&List, cRects, pRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsAdd failed rc %d", rc)); + goto end; + } + + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter); + + for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter); + pEntry; + pEntry = CrVrScrCompositorConstIterNext(&Iter)) + { + /* Where the entry would be located in pDst coords (pPos = pDst_coord - hFb_coord). */ + RTPOINT EntryPoint; + EntryPoint.x = CrVrScrCompositorEntryRectGet(pEntry)->xLeft + pPos->x; + EntryPoint.y = CrVrScrCompositorEntryRectGet(pEntry)->yTop + pPos->y; + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + + /* Optimization to avoid entering/leaving the same texture and its blitter. */ + 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; + } + + bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS); + + /* pRegions is where the pEntry was drawn in hFb coords. */ + 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; + } + + /* CrTdBltDataAcquire/CrTdBltDataRelease can use cached data, + * so it is not necessary to optimize and Aquire only when Tex changes. + */ + const CR_BLITTER_IMG *pSrcImg; + rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + goto end; + } + + for (uint32_t j = 0; j < cRegions; ++j) + { + /* rects are in dst coordinates, + * while the pReg is in source coords + * convert */ + const RTRECT * pReg = &pRegions[j]; + RTRECT SrcReg; + /* translate */ + VBoxRectTranslated(pReg, pPos->x, pPos->y, &SrcReg); + + /* Exclude the pEntry rectangle, because it will be updated now in pDst. + * List uses dst coords and pRegions use hFb coords, therefore use + * SrcReg which is already translated to dst. + */ + rc = VBoxVrListRectsSubst(&List, 1, &SrcReg, 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]; + + RTRECT Intersection; + VBoxRectIntersected(pRect, &SrcReg, &Intersection); + if (VBoxRectIsZero(&Intersection)) + continue; + + CrMBltImgRect(pSrcImg, &EntryPoint, fInvert, &Intersection, pDst); + } + } + + CrTdBltDataRelease(pTex); + } + + /* Blit still not updated dst rects, i.e. not covered by 3D entries. */ + c2DRects = VBoxVrListRectsCount(&List); + if (c2DRects) + { + if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT)) + { + if (g_CrPresenter.pvTmpBuf2) + RTMemFree(g_CrPresenter.pvTmpBuf2); + + 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; + } + } + + RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2; + + rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsGet failed, rc %d", rc)); + goto end; + } + + CR_BLITTER_IMG FbImg; + + crFbImgFromFb(hFb, &FbImg); + + CrMBltImg(&FbImg, pPos, c2DRects, p2DRects, pDst); + } + +end: + + if (pEnteredTex) + CrTdBltLeave(pEnteredTex); + + if (pEnteredBlitter) + CrBltLeave(pEnteredBlitter); + + VBoxVrListClear(&List); + + return rc; +} + +int CrFbBltGetContentsEx(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + uint32_t srcWidth = pSrcRectSize->cx; + uint32_t srcHeight = pSrcRectSize->cy; + uint32_t dstWidth = pDstRect->xRight - pDstRect->xLeft; + uint32_t dstHeight = pDstRect->yBottom - pDstRect->yTop; + if (srcWidth == dstWidth + && srcHeight == dstHeight) + { + RTPOINT Pos = {pDstRect->xLeft, pDstRect->yTop}; + return CrFbBltGetContents(hFb, &Pos, cRects, pRects, pImg); + } + if (!CrFbHas3DData(hFb) + || (srcWidth * srcHeight > dstWidth * dstHeight)) + return crFbBltGetContentsScaledDirect(hFb, pSrcRectSize, pDstRect, cRects, pRects, pImg); + + return crFbBltGetContentsScaledCPU(hFb, pSrcRectSize, pDstRect, cRects, pRects, pImg); +} + +static void crFbBltPutContentsFbVram(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pSrc) +{ + const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor); + + CR_BLITTER_IMG FbImg; + + crFbImgFromFb(hFb, &FbImg); + + CrMBltImg(pSrc, pPos, cRects, pRects, &FbImg); +} + +static void crFbClrFillFbVram(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color) +{ + CR_BLITTER_IMG FbImg; + + crFbImgFromFb(hFb, &FbImg); + + CrMClrFillImg(&FbImg, cRects, pRects, u32Color); +} + +int CrFbClrFill(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color) +{ + if (!hFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + crFbClrFillFbVram(hFb, cRects, pRects, u32Color); + + RTPOINT DstPoint = {0, 0}; + + int rc = CrFbEntryRegionsAdd(hFb, NULL, &DstPoint, cRects, pRects, false); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryRegionsAdd failed %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + +static int crFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + crFbBltPutContentsFbVram(hFb, pPos, cRects, pRects, pImg); + + int rc = CrFbEntryRegionsAdd(hFb, NULL, pPos, cRects, pRects, false); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryRegionsAdd failed %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + +int CrFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + if (!hFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + return crFbBltPutContents(hFb, pPos, cRects, pRects, pImg); +} + +static int crFbRegionsIsIntersectRects(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, bool *pfRegChanged) +{ + uint32_t cCompRects; + const RTRECT *pCompRects; + int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cCompRects, NULL, NULL, &pCompRects); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc)); + return rc; + } + + bool fRegChanged = false; + for (uint32_t i = 0; i < cCompRects; ++i) + { + const RTRECT *pCompRect = &pCompRects[i]; + for (uint32_t j = 0; j < cRects; ++j) + { + const RTRECT *pRect = &pRects[j]; + if (VBoxRectIsIntersect(pCompRect, pRect)) + { + *pfRegChanged = true; + return VINF_SUCCESS; + } + } + } + + *pfRegChanged = false; + return VINF_SUCCESS; +} + +int CrFbBltPutContentsNe(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + bool fRegChanged = false; + int rc = crFbRegionsIsIntersectRects(hFb, cRects, pRects, &fRegChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("crFbRegionsIsIntersectRects failed rc %d", rc)); + return rc; + } + + if (fRegChanged) + { + rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + rc = CrFbBltPutContents(hFb, pPos, cRects, pRects, pImg); + if (!RT_SUCCESS(rc)) + WARN(("CrFbBltPutContents failed rc %d", rc)); + CrFbUpdateEnd(hFb); + } + else + WARN(("CrFbUpdateBegin failed rc %d", rc)); + + return rc; + } + + crFbBltPutContentsFbVram(hFb, pPos, cRects, pRects, pImg); + return VINF_SUCCESS; +} + +int CrFbClrFillNe(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color) +{ + bool fRegChanged = false; + int rc = crFbRegionsIsIntersectRects(hFb, cRects, pRects, &fRegChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("crFbRegionsIsIntersectRects failed rc %d", rc)); + return rc; + } + + if (fRegChanged) + { + rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + rc = CrFbClrFill(hFb, cRects, pRects, u32Color); + if (!RT_SUCCESS(rc)) + WARN(("CrFbClrFill failed rc %d", rc)); + CrFbUpdateEnd(hFb); + } + else + WARN(("CrFbUpdateBegin failed rc %d", rc)); + + return rc; + } + + crFbClrFillFbVram(hFb, cRects, pRects, u32Color); + return VINF_SUCCESS; +} + +int CrFbResize(CR_FRAMEBUFFER *pFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM) +{ + if (!pFb->cUpdating) + { + WARN(("no update in progress")); + return VERR_INVALID_STATE; + } + + int rc = VINF_SUCCESS; + if (CrFbIsEnabled(pFb)) + { + rc = CrFbRegionsClear(pFb); + if (RT_FAILURE(rc)) + { + WARN(("CrFbRegionsClear failed %d", rc)); + return rc; + } + } + + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = pScreen->u32Width; + Rect.yBottom = pScreen->u32Height; + rc = CrVrScrCompositorRectSet(&pFb->Compositor, &Rect, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorRectSet failed rc %d", rc)); + return rc; + } + + pFb->ScreenInfo = *pScreen; + pFb->pvVram = pvVRAM ? pvVRAM : g_pvVRamBase + pScreen->u32StartOffset; + + if (pFb->pDisplay) + pFb->pDisplay->FramebufferChanged(pFb); + + return VINF_SUCCESS; +} + +void CrFbTerm(CR_FRAMEBUFFER *pFb) +{ + if (pFb->cUpdating) + { + WARN(("update in progress")); + return; + } + uint32_t idFb = pFb->ScreenInfo.u32ViewIndex; + + 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 = idFb; +} + +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; + + pFb->pDisplay = pDisplay; + + 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 void crPMgrCleanUnusedDisplays(); + +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) + { + crHashtableDelete(g_CrPresenter.pFbTexMap, pTobj->id, NULL); + + crStateReleaseTexture(cr_server.MainContextInfo.pContext, pTobj); + + + 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; + + 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 CR_TEXDATA* CrFbTexDataAcquire(GLuint idTexture) +{ + CR_FBTEX* pTex = crFbTexAcquire(idTexture); + if (!pTex) + { + WARN(("crFbTexAcquire failed for %d", idTexture)); + return NULL; + } + + return &pTex->Tex; +} + +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) + { + pFbEntry->Flags.fInList = 0; + if (pFb->pDisplay) + pFb->pDisplay->EntryRemoved(pFb, pFbEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + } + + crFbEntryRelease(pFb, pFbEntry); +} + +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; + } + + 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) +{ + if (pTex == NULL) + { + WARN(("pTex is NULL")); + return VERR_INVALID_PARAMETER; + } + + 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); + + 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) +{ + 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 CrFbEntryAddRef(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + ++hEntry->cRefs; +} + +void CrFbEntryRelease(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + crFbEntryRelease(pFb, hEntry); +} + +static int8_t crVBoxServerCrCmdBltPrimaryVramGenericProcess(uint32_t u32PrimaryID, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, bool fToPrimary); + +int CrFbRegionsClear(HCR_FRAMEBUFFER hFb) +{ + if (!hFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + uint32_t cRegions; + const RTRECT *pRegions; + int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cRegions, NULL, NULL, &pRegions); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc)); + return rc; + } + + const struct VBVAINFOSCREEN* pScreen = CrFbGetScreenInfo(hFb); + VBOXCMDVBVAOFFSET offVRAM = (VBOXCMDVBVAOFFSET)(((uintptr_t)CrFbGetVRAM(hFb)) - ((uintptr_t)g_pvVRamBase)); + RTPOINT Pos = {0,0}; + int8_t i8Result = crVBoxServerCrCmdBltPrimaryVramGenericProcess(pScreen->u32ViewIndex, offVRAM, pScreen->u32Width, pScreen->u32Height, &Pos, cRegions, pRegions, true); + if (i8Result) + { + WARN(("crVBoxServerCrCmdBltPrimaryVramGenericProcess failed")); + return VERR_INTERNAL_ERROR; + } + +#ifdef DEBUG + { + uint32_t cTmpRegions; + const RTRECT *pTmpRegions; + int tmpRc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cTmpRegions, NULL, NULL, &pTmpRegions); + if (!RT_SUCCESS(tmpRc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", tmpRc)); + } + Assert(!cTmpRegions); + } +#endif + + /* just in case */ + bool fChanged = false; + CrVrScrCompositorRegionsClear(&hFb->Compositor, &fChanged); + Assert(!fChanged); + + if (cRegions) + { + if (hFb->pDisplay) + hFb->pDisplay->RegionsChanged(hFb); + } + + return VINF_SUCCESS; +} + +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); + + Assert(!hEntry->Flags.fInList == !fEntryWasInList); + } + else + { + pNewEntry = NULL; + fEntryWasInList = false; + } + + 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) + { + if (!fEntryWasInList && pNewEntry) + { + Assert(CrVrScrCompositorEntryIsUsed(pNewEntry)); + if (!hEntry->Flags.fCreateNotified) + { + hEntry->Flags.fCreateNotified = 1; + if (pFb->pDisplay) + pFb->pDisplay->EntryCreated(pFb, hEntry); + } + +#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; + + if (pFb->pDisplay) + pFb->pDisplay->EntryAdded(pFb, hEntry); + } + } + if (pFb->pDisplay) + pFb->pDisplay->RegionsChanged(pFb); + + Assert(!pReplacedScrEntry); + } + 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 (CrVrScrCompositorEntryIsUsed(&hEntry->Entry)) + { + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, hEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + } + } + 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) + { + if (CrVrScrCompositorEntryIsUsed(pNewEntry)) + { + if (!hEntry->Flags.fCreateNotified) + { + hEntry->Flags.fCreateNotified = 1; + + if (pFb->pDisplay) + pFb->pDisplay->EntryCreated(pFb, hEntry); + } + + Assert(!hEntry->Flags.fInList); + hEntry->Flags.fInList = 1; + + if (pFb->pDisplay) + pFb->pDisplay->EntryAdded(pFb, hEntry); + } + } + + if (pFb->pDisplay) + pFb->pDisplay->RegionsChanged(pFb); + } + + if (hEntry) + { + if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry)) + { + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, hEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + } + } + else + WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + + return rc; +} + +const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry) +{ + return &hEntry->Entry; +} + +HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry) +{ + return RT_FROM_MEMBER(pCEntry, CR_FRAMEBUFFER_ENTRY, Entry); +} + +void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext) +{ + HCR_FRAMEBUFFER_ENTRY hEntry, hNext; + RTListForEachSafe(&hFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node) + { + if (hEntry->Flags.fCreateNotified) + { + if (!pfnVisitorCb(hFb, hEntry, pvContext)) + return; + } + } +} + + +CRHTABLE_HANDLE CrFbDDataAllocSlot(CR_FRAMEBUFFER *pFb) +{ + return CrHTablePut(&pFb->SlotTable, (void*)1); +} + +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) + { + if (CrFbDDataEntryGet(hEntry, hSlot)) + { + if (pfnReleaseCb) + pfnReleaseCb(pFb, hEntry, pvContext); + + CrFbDDataEntryClear(hEntry, hSlot); + } + } + + CrHTableRemove(&pFb->SlotTable, hSlot); +} + +int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData) +{ + return CrHTablePutToSlot(&hEntry->HTable, hSlot, pvData); +} + +void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot) +{ + return CrHTableRemove(&hEntry->HTable, hSlot); +} + +void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot) +{ + return CrHTableGet(&hEntry->HTable, hSlot); +} + +int CrPMgrDisable() +{ + if (!g_CrPresenter.fEnabled) + return VINF_SUCCESS; + + g_CrPresenter.u32DisabledDisplayMode = g_CrPresenter.u32DisplayMode; + + int rc = crPMgrModeModifyGlobal(0, CR_PMGR_MODE_WINDOW); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrModeModifyGlobal failed %d", rc)); + return rc; + } + + crPMgrCleanUnusedDisplays(); + + g_CrPresenter.fEnabled = false; + + return VINF_SUCCESS; +} + +int CrPMgrEnable() +{ + if (g_CrPresenter.fEnabled) + return VINF_SUCCESS; + + g_CrPresenter.fEnabled = true; + + int rc = crPMgrModeModifyGlobal(g_CrPresenter.u32DisabledDisplayMode, 0); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrModeModifyGlobal failed %d", rc)); + g_CrPresenter.fEnabled = false; + return rc; + } + + g_CrPresenter.u32DisabledDisplayMode = 0; + + return VINF_SUCCESS; +} + +int CrPMgrInit() +{ + int rc = VINF_SUCCESS; + memset(&g_CrPresenter, 0, sizeof (g_CrPresenter)); + g_CrPresenter.fEnabled = true; + for (int i = 0; i < RT_ELEMENTS(g_CrPresenter.aDisplayInfos); ++i) + { + g_CrPresenter.aDisplayInfos[i].u32Id = i; + g_CrPresenter.aDisplayInfos[i].iFb = -1; + + g_CrPresenter.aFbInfos[i].u32Id = i; + } + + g_CrPresenter.pFbTexMap = crAllocHashtable(); + if (g_CrPresenter.pFbTexMap) + { +#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)); + + RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); + + RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); +#endif + } + else + { + WARN(("crAllocHashtable failed")); + rc = VERR_NO_MEMORY; + } + return rc; +} + +void CrPMgrTerm() +{ + crPMgrModeModifyGlobal(0, CR_PMGR_MODE_ALL); + + HCR_FRAMEBUFFER hFb; + + for (hFb = CrPMgrFbGetFirstInitialized(); + hFb; + hFb = CrPMgrFbGetNextInitialized(hFb)) + { + uint32_t iFb = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CrFbDisplaySet(hFb, NULL); + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[iFb]; + if (pFbInfo->pDpComposite) + { + delete pFbInfo->pDpComposite; + pFbInfo->pDpComposite = NULL; + } + + CrFbTerm(hFb); + } + + crPMgrCleanUnusedDisplays(); + +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList); + RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList); + RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList); +#endif + crFreeHashtable(g_CrPresenter.pFbTexMap, NULL); + + 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 idFb) +{ + if (idFb >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idFb %d", idFb)); + return NULL; + } + + if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idFb)) + { + CrFbInit(&g_CrPresenter.aFramebuffers[idFb], idFb); + CrFBmSetAtomic(&g_CrPresenter.FramebufferInitMap, idFb); + } + else + Assert(g_CrPresenter.aFramebuffers[idFb].ScreenInfo.u32ViewIndex == idFb); + + return &g_CrPresenter.aFramebuffers[idFb]; +} + +HCR_FRAMEBUFFER CrPMgrFbGetInitialized(uint32_t idFb) +{ + if (idFb >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idFb %d", idFb)); + return NULL; + } + + if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idFb)) + { + return NULL; + } + else + Assert(g_CrPresenter.aFramebuffers[idFb].ScreenInfo.u32ViewIndex == idFb); + + return &g_CrPresenter.aFramebuffers[idFb]; +} + +HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idFb) +{ + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(idFb); + + if(hFb && CrFbIsEnabled(hFb)) + return hFb; + + return NULL; +} + +HCR_FRAMEBUFFER CrPMgrFbGetEnabledForScreen(uint32_t idScreen) +{ + if (idScreen >= (uint32_t)cr_server.screenCount) + { + WARN(("invalid target id")); + return NULL; + } + + const CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pDpInfo->iFb < 0) + return NULL; + + return CrPMgrFbGetEnabled(pDpInfo->iFb); +} + +static HCR_FRAMEBUFFER crPMgrFbGetNextEnabled(uint32_t i) +{ + for (;i < (uint32_t)cr_server.screenCount; ++i) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(i); + if (hFb) + return hFb; + } + + return NULL; +} + +static HCR_FRAMEBUFFER crPMgrFbGetNextInitialized(uint32_t i) +{ + for (;i < (uint32_t)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); +} + +HCR_FRAMEBUFFER CrPMgrFbGetEnabledByVramStart(VBOXCMDVBVAOFFSET offVRAM) +{ + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + if (pScreen->u32StartOffset == offVRAM) + return hFb; + } + + return NULL; +} + + +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; +} + +static int crPMgrCheckInitWindowDisplays(uint32_t idScreen) +{ +#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pDpInfo->iFb >= 0) + { + uint32_t u32ModeAdd = g_CrPresenter.u32DisplayMode & (CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR); + int rc = crPMgrFbConnectTargetDisplays(&g_CrPresenter.aFramebuffers[pDpInfo->iFb], pDpInfo, u32ModeAdd); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnectTargetDisplays failed %d", rc)); + return rc; + } + } +#endif + return VINF_SUCCESS; +} + +extern "C" DECLEXPORT(int) VBoxOglSetScaleFactor(uint32_t idScreen, double dScaleFactorW, double dScaleFactorH) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + crDebug("Can't set scale factor because specified screen ID (%u) is out of range (max=%d).", idScreen, CR_MAX_GUEST_MONITORS); + return VERR_INVALID_PARAMETER; + } + + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pDpInfo->pDpWin) + { + CrFbWindow *pWin = pDpInfo->pDpWin->getWindow(); + if (pWin) + { + bool rc; + crDebug("Set scale factor for initialized display."); + rc = pWin->SetScaleFactor((GLdouble)dScaleFactorW, (GLdouble)dScaleFactorH); + return rc ? 0 : VERR_LOCK_FAILED; + } + else + crDebug("Can't apply scale factor at the moment bacause overlay window obgect not yet created. Will be chached."); + } + else + crDebug("Can't apply scale factor at the moment bacause display not yet initialized. Will be chached."); + + /* Display output not yet initialized. Let's cache values. */ + pDpInfo->dInitialScaleFactorW = dScaleFactorW; + pDpInfo->dInitialScaleFactorH = dScaleFactorH; + + return 0; +} + +int CrPMgrScreenChanged(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return VERR_INVALID_PARAMETER; + } + + int rc = VINF_SUCCESS; + + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + HCR_FRAMEBUFFER hFb = pDpInfo->iFb >= 0 ? CrPMgrFbGet(pDpInfo->iFb) : NULL; + + if (hFb && CrFbIsUpdating(hFb)) + { + WARN(("trying to update viewport while framebuffer is being updated")); + return VERR_INVALID_STATE; + } + + if (pDpInfo->pDpWin) + { + CRASSERT(pDpInfo->pDpWin->getWindow()); + + rc = pDpInfo->pDpWin->UpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + pDpInfo->pDpWin->reparent(cr_server.screen[idScreen].winID); + pDpInfo->pDpWin->UpdateEnd(hFb); + } + } + else + { + if (pDpInfo->pWindow) + { + rc = pDpInfo->pWindow->UpdateBegin(); + if (RT_SUCCESS(rc)) + { + rc = pDpInfo->pWindow->SetVisible(false); + if (RT_SUCCESS(rc)) + rc = pDpInfo->pWindow->Reparent(cr_server.screen[idScreen].winID); + + pDpInfo->pWindow->UpdateEnd(); + } + } + + if (RT_SUCCESS(rc)) + rc = crPMgrCheckInitWindowDisplays(idScreen); + } + + CRASSERT(!rc); + + return rc; +} + +int CrPMgrViewportUpdate(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return VERR_INVALID_PARAMETER; + } + + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pDpInfo->iFb >= 0) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pDpInfo->iFb); + if (CrFbIsUpdating(hFb)) + { + WARN(("trying to update viewport while framebuffer is being updated")); + return VERR_INVALID_STATE; + } + + if (pDpInfo->pDpWin) + { + CRASSERT(pDpInfo->pDpWin->getWindow()); + int rc = pDpInfo->pDpWin->UpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + pDpInfo->pDpWin->setViewportRect(&cr_server.screenVieport[idScreen].Rect); + pDpInfo->pDpWin->UpdateEnd(hFb); + } + else + WARN(("UpdateBegin failed %d", rc)); + } + } + + return VINF_SUCCESS; +} + +static int crPMgrFbDisconnectDisplay(HCR_FRAMEBUFFER hFb, CrFbDisplayBase *pDp) +{ + if (pDp->getFramebuffer() != hFb) + return VINF_SUCCESS; + + CrFbDisplayBase * pCurDp = (CrFbDisplayBase*)CrFbDisplayGet(hFb); + if (!pCurDp) + { + WARN(("no display set, unexpected")); + return VERR_INTERNAL_ERROR; + } + + if (pCurDp == pDp) + { + pDp->setFramebuffer(NULL); + CrFbDisplaySet(hFb, NULL); + return VINF_SUCCESS; + } + + uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb]; + if (pFbInfo->pDpComposite != pCurDp) + { + WARN(("misconfig, expectig the curret framebuffer to be present, and thus composite is expected")); + return VERR_INTERNAL_ERROR; + } + + if (pDp->getContainer() == pFbInfo->pDpComposite) + { + pFbInfo->pDpComposite->remove(pDp); + uint32_t cDisplays = pFbInfo->pDpComposite->getDisplayCount(); + if (cDisplays <= 1) + { + Assert(cDisplays == 1); + CrFbDisplayBase *pDpFirst = pFbInfo->pDpComposite->first(); + if (pDpFirst) + pFbInfo->pDpComposite->remove(pDpFirst, false); + CrFbDisplaySet(hFb, pDpFirst); + } + return VINF_SUCCESS; + } + + WARN(("misconfig")); + return VERR_INTERNAL_ERROR; +} + +static int crPMgrFbConnectDisplay(HCR_FRAMEBUFFER hFb, CrFbDisplayBase *pDp) +{ + if (pDp->getFramebuffer() == hFb) + return VINF_SUCCESS; + + CrFbDisplayBase * pCurDp = (CrFbDisplayBase*)CrFbDisplayGet(hFb); + if (!pCurDp) + { + pDp->setFramebuffer(hFb); + CrFbDisplaySet(hFb, pDp); + return VINF_SUCCESS; + } + + if (pCurDp == pDp) + { + WARN(("misconfig, current framebuffer is not expected to be set")); + return VERR_INTERNAL_ERROR; + } + + uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb]; + if (pFbInfo->pDpComposite != pCurDp) + { + if (!pFbInfo->pDpComposite) + { + pFbInfo->pDpComposite = new CrFbDisplayComposite(); + pFbInfo->pDpComposite->setFramebuffer(hFb); + } + + pFbInfo->pDpComposite->add(pCurDp); + CrFbDisplaySet(hFb, pFbInfo->pDpComposite); + } + + pFbInfo->pDpComposite->add(pDp); + return VINF_SUCCESS; +} + +static int crPMgrFbDisconnectTarget(HCR_FRAMEBUFFER hFb, uint32_t i) +{ + uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb]; + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i]; + if (pDpInfo->iFb != idFb) + { + WARN(("target not connected")); + Assert(!ASMBitTest(pFbInfo->aTargetMap, i)); + return VINF_SUCCESS; + } + + Assert(ASMBitTest(pFbInfo->aTargetMap, i)); + + int rc = VINF_SUCCESS; + if (pDpInfo->pDpVrdp) + { + rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpVrdp); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectDisplay failed %d", rc)); + return rc; + } + } + + if (pDpInfo->pDpWinRootVr) + { +#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS + CrFbWindow *pWindow = pDpInfo->pDpWinRootVr->windowDetach(false); + Assert(pWindow == pDpInfo->pWindow); +#endif + rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWinRootVr); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectDisplay failed %d", rc)); + return rc; + } + } + else if (pDpInfo->pDpWin) + { +#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS + CrFbWindow *pWindow = pDpInfo->pDpWin->windowDetach(false); + Assert(pWindow == pDpInfo->pWindow); +#endif + rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWin); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectDisplay failed %d", rc)); + return rc; + } + } + + ASMBitClear(pFbInfo->aTargetMap, i); + pDpInfo->iFb = -1; + + return VINF_SUCCESS; +} + +static void crPMgrDpWinRootVrCreate(CR_FBDISPLAY_INFO *pDpInfo) +{ + if (!pDpInfo->pDpWinRootVr) + { + if (pDpInfo->pDpWin) + { + CrFbWindow *pWin = pDpInfo->pDpWin->windowDetach(); + CRASSERT(pWin); + Assert(pWin == pDpInfo->pWindow); + delete pDpInfo->pDpWin; + pDpInfo->pDpWin = NULL; + } + else if (!pDpInfo->pWindow) + { + pDpInfo->pWindow = new CrFbWindow(0); + } + + pDpInfo->pDpWinRootVr = new CrFbDisplayWindowRootVr(&cr_server.screenVieport[pDpInfo->u32Id].Rect, cr_server.screen[pDpInfo->u32Id].winID); + pDpInfo->pDpWin = pDpInfo->pDpWinRootVr; + pDpInfo->pDpWinRootVr->windowAttach(pDpInfo->pWindow); + + /* Set scale factor once it was previously cached when display output was not yet initialized. */ + if (pDpInfo->dInitialScaleFactorW || pDpInfo->dInitialScaleFactorH) + { + crDebug("Set cached scale factor for seamless mode."); + pDpInfo->pWindow->SetScaleFactor((GLdouble)pDpInfo->dInitialScaleFactorW, (GLdouble)pDpInfo->dInitialScaleFactorH); + /* Invalidate cache. */ + pDpInfo->dInitialScaleFactorW = pDpInfo->dInitialScaleFactorH = 0; + } + } +} + +static void crPMgrDpWinCreate(CR_FBDISPLAY_INFO *pDpInfo) +{ + if (pDpInfo->pDpWinRootVr) + { + CRASSERT(pDpInfo->pDpWinRootVr == pDpInfo->pDpWin); + CrFbWindow *pWin = pDpInfo->pDpWin->windowDetach(); + CRASSERT(pWin); + Assert(pWin == pDpInfo->pWindow); + delete pDpInfo->pDpWinRootVr; + pDpInfo->pDpWinRootVr = NULL; + pDpInfo->pDpWin = NULL; + } + + if (!pDpInfo->pDpWin) + { + if (!pDpInfo->pWindow) + pDpInfo->pWindow = new CrFbWindow(0); + + pDpInfo->pDpWin = new CrFbDisplayWindow(&cr_server.screenVieport[pDpInfo->u32Id].Rect, cr_server.screen[pDpInfo->u32Id].winID); + pDpInfo->pDpWin->windowAttach(pDpInfo->pWindow); + + /* Set scale factor once it was previously cached when display output was not yet initialized. */ + if (pDpInfo->dInitialScaleFactorW || pDpInfo->dInitialScaleFactorH) + { + crDebug("Set cached scale factor for host window."); + pDpInfo->pWindow->SetScaleFactor((GLdouble)pDpInfo->dInitialScaleFactorW, (GLdouble)pDpInfo->dInitialScaleFactorH); + /* Invalidate cache. */ + pDpInfo->dInitialScaleFactorW = pDpInfo->dInitialScaleFactorH = 0; + } + } +} + +static int crPMgrFbDisconnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeRemove) +{ + int rc = VINF_SUCCESS; + if (u32ModeRemove & CR_PMGR_MODE_ROOTVR) + { + if (pDpInfo->pDpWinRootVr) + { +#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS + CrFbWindow *pWindow = pDpInfo->pDpWinRootVr->windowDetach(false); + Assert(pWindow == pDpInfo->pWindow); +#endif + CRASSERT(pDpInfo->pDpWin == pDpInfo->pDpWinRootVr); + rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWinRootVr); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectDisplay pDpWinRootVr failed %d", rc)); + return rc; + } + } + } + else if (u32ModeRemove & CR_PMGR_MODE_WINDOW) + { + CRASSERT(!pDpInfo->pDpWinRootVr); + if (pDpInfo->pDpWin) + { +#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS + CrFbWindow *pWindow = pDpInfo->pDpWin->windowDetach(false); + Assert(pWindow == pDpInfo->pWindow); +#endif + rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWin); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectDisplay pDpWin failed %d", rc)); + return rc; + } + } + } + + if (u32ModeRemove & CR_PMGR_MODE_VRDP) + { + if (pDpInfo->pDpVrdp) + { + rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpVrdp); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectDisplay pDpVrdp failed %d", rc)); + return rc; + } + } + } + + pDpInfo->u32DisplayMode &= ~u32ModeRemove; + + return VINF_SUCCESS; +} + +static int crPMgrFbConnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeAdd) +{ + int rc = VINF_SUCCESS; + + if (u32ModeAdd & CR_PMGR_MODE_ROOTVR) + { + crPMgrDpWinRootVrCreate(pDpInfo); + + rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpWinRootVr); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnectDisplay pDpWinRootVr failed %d", rc)); + return rc; + } + } + else if (u32ModeAdd & CR_PMGR_MODE_WINDOW) + { + crPMgrDpWinCreate(pDpInfo); + + rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpWin); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnectDisplay pDpWin failed %d", rc)); + return rc; + } + } + + if (u32ModeAdd & CR_PMGR_MODE_VRDP) + { + if (!pDpInfo->pDpVrdp) + pDpInfo->pDpVrdp = new CrFbDisplayVrdp(); + + rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpVrdp); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnectDisplay pDpVrdp failed %d", rc)); + return rc; + } + } + + pDpInfo->u32DisplayMode |= u32ModeAdd; + + return VINF_SUCCESS; +} + +static int crPMgrFbConnectTarget(HCR_FRAMEBUFFER hFb, uint32_t i) +{ + uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb]; + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i]; + if (pDpInfo->iFb == idFb) + { + WARN(("target not connected")); + Assert(ASMBitTest(pFbInfo->aTargetMap, i)); + return VINF_SUCCESS; + } + + Assert(!ASMBitTest(pFbInfo->aTargetMap, i)); + + int rc = VINF_SUCCESS; + + if (pDpInfo->iFb != -1) + { + Assert(pDpInfo->iFb < cr_server.screenCount); + HCR_FRAMEBUFFER hAssignedFb = CrPMgrFbGet(pDpInfo->iFb); + Assert(hAssignedFb); + rc = crPMgrFbDisconnectTarget(hAssignedFb, i); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectTarget failed %d", rc)); + return rc; + } + } + + rc = crPMgrFbConnectTargetDisplays(hFb, pDpInfo, g_CrPresenter.u32DisplayMode +#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS + & ~(CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR) +#endif + ); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnectTargetDisplays failed %d", rc)); + return rc; + } + + ASMBitSet(pFbInfo->aTargetMap, i); + pDpInfo->iFb = idFb; + + return VINF_SUCCESS; +} + +static int crPMgrFbDisconnect(HCR_FRAMEBUFFER hFb, const uint32_t *pTargetMap) +{ + int rc = VINF_SUCCESS; + for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount); + i >= 0; + i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i)) + { + rc = crPMgrFbDisconnectTarget(hFb, (uint32_t)i); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectTarget failed %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; +} + +static int crPMgrFbConnect(HCR_FRAMEBUFFER hFb, const uint32_t *pTargetMap) +{ + int rc = VINF_SUCCESS; + for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount); + i >= 0; + i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i)) + { + rc = crPMgrFbConnectTarget(hFb, (uint32_t)i); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnectTarget failed %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; +} + +static int crPMgrModeModifyTarget(HCR_FRAMEBUFFER hFb, uint32_t iDisplay, uint32_t u32ModeAdd, uint32_t u32ModeRemove) +{ + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[iDisplay]; + int rc = crPMgrFbDisconnectTargetDisplays(hFb, pDpInfo, u32ModeRemove); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectTargetDisplays failed %d", rc)); + return rc; + } + + rc = crPMgrFbConnectTargetDisplays(hFb, pDpInfo, u32ModeAdd); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnectTargetDisplays failed %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + +static int crPMgrModeModify(HCR_FRAMEBUFFER hFb, uint32_t u32ModeAdd, uint32_t u32ModeRemove) +{ + int rc = VINF_SUCCESS; + uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb]; + for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount); + i >= 0; + i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i)) + { + rc = crPMgrModeModifyTarget(hFb, (uint32_t)i, u32ModeAdd, u32ModeRemove); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrModeModifyTarget failed %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; +} + +static void crPMgrCleanUnusedDisplays() +{ + for (int i = 0; i < cr_server.screenCount; ++i) + { + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i]; + + if (pDpInfo->pDpWinRootVr) + { + if (!pDpInfo->pDpWinRootVr->getFramebuffer()) + { + pDpInfo->pDpWinRootVr->windowDetach(false); + delete pDpInfo->pDpWinRootVr; + pDpInfo->pDpWinRootVr = NULL; + pDpInfo->pDpWin = NULL; + if (pDpInfo->pWindow) + { + delete pDpInfo->pWindow; + pDpInfo->pWindow = NULL; + } + } + else + WARN(("pDpWinRootVr is used")); + } + else if (pDpInfo->pDpWin) + { + if (!pDpInfo->pDpWin->getFramebuffer()) + { + pDpInfo->pDpWin->windowDetach(false); + delete pDpInfo->pDpWin; + pDpInfo->pDpWin = NULL; + if (pDpInfo->pWindow) + { + delete pDpInfo->pWindow; + pDpInfo->pWindow = NULL; + } + } + else + WARN(("pDpWin is used")); + } + + if (pDpInfo->pDpVrdp) + { + if (!pDpInfo->pDpVrdp->getFramebuffer()) + { + delete pDpInfo->pDpVrdp; + pDpInfo->pDpVrdp = NULL; + } + else + WARN(("pDpVrdp is used")); + } + } +} + +static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove) +{ + uint32_t u32InternalMode = g_CrPresenter.fEnabled ? g_CrPresenter.u32DisplayMode : g_CrPresenter.u32DisabledDisplayMode; + + u32ModeRemove = ((u32ModeRemove | crPMgrModeAdjustVal(u32ModeRemove)) & CR_PMGR_MODE_ALL); + u32ModeAdd = crPMgrModeAdjustVal(u32ModeAdd); + u32ModeRemove &= u32InternalMode; + u32ModeAdd &= ~(u32ModeRemove | u32InternalMode); + uint32_t u32ModeResulting = ((u32InternalMode | u32ModeAdd) & ~u32ModeRemove); + uint32_t u32Tmp = crPMgrModeAdjustVal(u32ModeResulting); + if (u32Tmp != u32ModeResulting) + { + u32ModeAdd |= (u32Tmp & ~u32ModeResulting); + u32ModeRemove |= (~u32Tmp & u32ModeResulting); + u32ModeResulting = u32Tmp; + Assert(u32ModeResulting == ((u32InternalMode | u32ModeAdd) & ~u32ModeRemove)); + } + if (!u32ModeRemove && !u32ModeAdd) + return VINF_SUCCESS; + + uint32_t u32DisplayMode = (g_CrPresenter.u32DisplayMode | u32ModeAdd) & ~u32ModeRemove; + if (!g_CrPresenter.fEnabled) + { + Assert(g_CrPresenter.u32DisplayMode == 0); + g_CrPresenter.u32DisabledDisplayMode = u32DisplayMode; + return VINF_SUCCESS; + } + + g_CrPresenter.u32DisplayMode = u32DisplayMode; + + /* disabled framebuffers may still have displays attached */ + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstInitialized(); + hFb; + hFb = CrPMgrFbGetNextInitialized(hFb)) + { + crPMgrModeModify(hFb, u32ModeAdd, u32ModeRemove); + } + + return VINF_SUCCESS; +} + +int CrPMgrClearRegionsGlobal() +{ + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + int rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + rc = CrFbRegionsClear(hFb); + if (RT_FAILURE(rc)) + { + WARN(("CrFbRegionsClear failed %d", rc)); + } + + CrFbUpdateEnd(hFb); + } + } + + return VINF_SUCCESS; +} + +int CrPMgrModeVrdp(bool fEnable) +{ + uint32_t u32ModeAdd, u32ModeRemove; + if (fEnable) + { + u32ModeAdd = CR_PMGR_MODE_VRDP; + u32ModeRemove = 0; + } + else + { + u32ModeAdd = 0; + u32ModeRemove = CR_PMGR_MODE_VRDP; + } + return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove); +} + +int CrPMgrModeRootVr(bool fEnable) +{ + uint32_t u32ModeAdd, u32ModeRemove; + if (fEnable) + { + u32ModeAdd = CR_PMGR_MODE_ROOTVR; + u32ModeRemove = CR_PMGR_MODE_WINDOW; + } + else + { + u32ModeAdd = CR_PMGR_MODE_WINDOW; + u32ModeRemove = CR_PMGR_MODE_ROOTVR; + } + + return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove); +} + +int CrPMgrModeWinVisible(bool fEnable) +{ + if (!g_CrPresenter.fWindowsForceHidden == !!fEnable) + return VINF_SUCCESS; + + g_CrPresenter.fWindowsForceHidden = !fEnable; + + for (int i = 0; i < cr_server.screenCount; ++i) + { + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i]; + + if (pDpInfo->pDpWin) + pDpInfo->pDpWin->winVisibilityChanged(); + } + + return VINF_SUCCESS; +} + +int CrPMgrRootVrUpdate() +{ + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + if (!CrFbHas3DData(hFb)) + continue; + + uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb]; + int rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount); + i >= 0; + i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i)) + { + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i]; + Assert(pDpInfo->iFb == (int32_t)idFb); + + pDpInfo->pDpWinRootVr->RegionsChanged(hFb); + } + + CrFbUpdateEnd(hFb); + } + else + WARN(("CrFbUpdateBegin failed %d", rc)); + } + + 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)) + { + 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); + } + + return VINF_SUCCESS; +} + +/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */ +void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap) +{ + for (uint32_t i = 0; i < (uint32_t)cr_server.screenCount; ++i) + { + if (!CrFBmIsSet(pMap, i)) + continue; + + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i); + CRASSERT(hFb); + CrFbUpdateEnd(hFb); + } +} + +int CrPMgrResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM, const uint32_t *pTargetMap) +{ + int rc = VINF_SUCCESS; + + if (pScreen->u32ViewIndex == 0xffffffff) + { + /* this is just a request to disable targets, search and disable */ + for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount); + i >= 0; + i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i)) + { + CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i]; + if (pDpInfo->iFb < 0) + continue; + + Assert(pDpInfo->iFb < cr_server.screenCount); + HCR_FRAMEBUFFER hAssignedFb = CrPMgrFbGet(pDpInfo->iFb); + + rc = crPMgrFbDisconnectTarget(hAssignedFb, (uint32_t)i); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnectTarget failed %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; + } + + HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pScreen->u32ViewIndex); + if (!hFb) + { + WARN(("CrPMgrFbGet failed")); + return VERR_INVALID_PARAMETER; + } + + const VBVAINFOSCREEN *pFbScreen = CrFbGetScreenInfo(hFb); + bool fFbInfoChanged = true; + + if (!memcmp(pFbScreen, pScreen, sizeof (*pScreen))) + { + if (!pvVRAM || pvVRAM == CrFbGetVRAM(hFb)) + fFbInfoChanged = false; + } + + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[pScreen->u32ViewIndex]; + + VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aRemovedTargetMap); + VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aAddedTargetMap); + + bool fDisplaysAdded = false, fDisplaysRemoved = false; + + memcpy(aRemovedTargetMap, pFbInfo->aTargetMap, sizeof (aRemovedTargetMap)); + + if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED) + { + /* so far there is no need in keeping displays attached to disabled Framebffer, + * just disconnect everything */ + for (int i = 0; i < RT_ELEMENTS(aRemovedTargetMap); ++i) + { + if (aRemovedTargetMap[i]) + { + fDisplaysRemoved = true; + break; + } + } + + memset(aAddedTargetMap, 0, sizeof (aAddedTargetMap)); + } + else + { + for (int i = 0; i < RT_ELEMENTS(aRemovedTargetMap); ++i) + { + aRemovedTargetMap[i] = (aRemovedTargetMap[i] & ~pTargetMap[i]); + if (aRemovedTargetMap[i]) + fDisplaysRemoved = true; + } + + memcpy(aAddedTargetMap, pFbInfo->aTargetMap, sizeof (aAddedTargetMap)); + for (int i = 0; i < RT_ELEMENTS(aAddedTargetMap); ++i) + { + aAddedTargetMap[i] = (pTargetMap[i] & ~aAddedTargetMap[i]); + if (aAddedTargetMap[i]) + fDisplaysAdded = true; + } + } + + if (!fFbInfoChanged && !fDisplaysRemoved && !fDisplaysAdded) + { + crDebug("resize: no changes"); + return VINF_SUCCESS; + } + + if (fDisplaysRemoved) + { + rc = crPMgrFbDisconnect(hFb, aRemovedTargetMap); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbDisconnect failed %d", rc)); + return rc; + } + } + + if (fFbInfoChanged) + { +#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS + rc = crPMgrModeModify(hFb, 0, CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR); + if (!RT_SUCCESS(rc)) + { + WARN(("crPMgrModeModifyTarget failed %d", rc)); + return rc; + } +#endif + rc = CrFbUpdateBegin(hFb); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbUpdateBegin failed %d", rc)); + return rc; + } + + crVBoxServerMuralFbResizeBegin(hFb); + + rc = CrFbResize(hFb, pScreen, pvVRAM); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbResize failed %d", rc)); + } + + crVBoxServerMuralFbResizeEnd(hFb); + + CrFbUpdateEnd(hFb); + } + + if (fDisplaysAdded) + { + rc = crPMgrFbConnect(hFb, aAddedTargetMap); + if (RT_FAILURE(rc)) + { + WARN(("crPMgrFbConnect failed %d", rc)); + return rc; + } + } + + 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) + { + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + if (pFbTex->pTobj) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + rc = CrFbEntrySaveState(pFb, hEntry, pSSM); + AssertRCReturn(rc, rc); + } + } + + 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, hFb->ScreenInfo.u32StartOffset); + AssertRCReturn(rc, rc); + + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[hFb->ScreenInfo.u32ViewIndex]; + rc = SSMR3PutMem(pSSM, pFbInfo->aTargetMap, sizeof (pFbInfo->aTargetMap)); + 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); + + VBVAINFOSCREEN Screen; + + Screen.u32ViewIndex = iScreen; + + VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap); + + memset(aTargetMap, 0, sizeof (aTargetMap)); + ASMBitSet(aTargetMap, 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; + } + 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); + + rc = SSMR3GetU32(pSSM, &Screen.u32StartOffset); + AssertRCReturn(rc, rc); + if (Screen.u32StartOffset == 0xffffffff) + { + WARN(("not expected offVram")); + Screen.u32StartOffset = 0; + } + + if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_MAP_REORDERED) + { + rc = SSMR3GetMem(pSSM, aTargetMap, sizeof (aTargetMap)); + AssertRCReturn(rc, rc); + } + + if (version == SHCROGL_SSM_VERSION_WITH_SCREEN_MAP) + { + VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aEmptyTargetMap); + + memset(aEmptyTargetMap, 0, sizeof (aEmptyTargetMap)); + + rc = CrPMgrResize(&Screen, cr_server.fCrCmdEnabled ? NULL : CrFbGetVRAM(pFb), aEmptyTargetMap); + AssertRCReturn(rc, rc); + + rc = CrFbLoadState(pFb, pSSM, version); + AssertRCReturn(rc, rc); + + rc = SSMR3GetMem(pSSM, aTargetMap, sizeof (aTargetMap)); + AssertRCReturn(rc, rc); + } + } + + rc = CrPMgrResize(&Screen, cr_server.fCrCmdEnabled ? NULL : CrFbGetVRAM(pFb), aTargetMap); + AssertRCReturn(rc, rc); + + if (version >= SHCROGL_SSM_VERSION_WITH_FB_INFO && version != SHCROGL_SSM_VERSION_WITH_SCREEN_MAP) + { + rc = CrFbLoadState(pFb, pSSM, version); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + + +void SERVER_DISPATCH_APIENTRY +crServerDispatchVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects) +{ + uint32_t idFb = CR_PRESENT_GET_SCREEN(cfg); + if (idFb >= CR_MAX_GUEST_MONITORS) + { + WARN(("Invalid guest screen")); + return; + } + + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idFb); + if (!hFb) + { + WARN(("request to present on disabled framebuffer, ignore")); + return; + } + + HCR_FRAMEBUFFER_ENTRY hEntry; + int rc; + if (texture) + { + rc = CrFbEntryCreateForTexId(hFb, texture, (cfg & CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD) ? 0 : CRBLT_F_INVERT_SRC_YCOORDS, &hEntry); + if (!RT_SUCCESS(rc)) + { + LOG(("CrFbEntryCreateForTexId Failed")); + return; + } + + Assert(hEntry); + +#if 0 + if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) + { + CR_SERVER_DUMP_TEXPRESENT(&pEntry->CEntry.Tex); + } +#endif + } + else + hEntry = NULL; + + rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) + { + RTPOINT Point = {xPos, yPos}; + rc = CrFbEntryRegionsAdd(hFb, hEntry, &Point, (uint32_t)cRects, (const RTRECT*)pRects, false); + } + else + { + CrFbRegionsClear(hFb); + } + + CrFbUpdateEnd(hFb); + } + else + { + WARN(("CrFbUpdateBegin Failed")); + } + + 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; +} + +DECLINLINE(void) crVBoxPRectUnpacks(const VBOXCMDVBVA_RECT *paVbvaRects, RTRECT *paRects, uint32_t cRects) +{ + uint32_t i = 0; + for (; i < cRects; ++i) + { + crVBoxPRectUnpack(&paVbvaRects[i], &paRects[i]); + } +} + +static RTRECT * crVBoxServerCrCmdBltRecsUnpack(const VBOXCMDVBVA_RECT *pPRects, uint32_t cRects) +{ + 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; + return NULL; + } + } + + RTRECT *pRects = (RTRECT *)g_CrPresenter.pvTmpBuf; + crVBoxPRectUnpacks(pPRects, pRects, cRects); + + return pRects; +} + +static void crPMgrPrimaryUpdateScreen(HCR_FRAMEBUFFER hFb, uint32_t idScreen, uint32_t cRects, const RTRECT *pRects) +{ + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + + bool fDirtyEmpty = true; + RTRECT dirtyRect = {0}; + cr_server.CrCmdClientInfo.pfnCltScrUpdateBegin(cr_server.CrCmdClientInfo.hCltScr, idScreen); + + VBVACMDHDR hdr; + for (uint32_t i = 0; i < cRects; ++i) + { + hdr.x = pRects[i].xLeft; + hdr.y = pRects[i].yTop; + hdr.w = hdr.x + pRects[i].xRight; + hdr.h = hdr.y + pRects[i].yBottom; + + cr_server.CrCmdClientInfo.pfnCltScrUpdateProcess(cr_server.CrCmdClientInfo.hCltScr, idScreen, &hdr, sizeof (hdr)); + + if (fDirtyEmpty) + { + /* This is the first rectangle to be added. */ + dirtyRect.xLeft = pRects[i].xLeft; + dirtyRect.yTop = pRects[i].yTop; + dirtyRect.xRight = pRects[i].xRight; + dirtyRect.yBottom = pRects[i].yBottom; + fDirtyEmpty = false; + } + else + { + /* Adjust region coordinates. */ + if (dirtyRect.xLeft > pRects[i].xLeft) + { + dirtyRect.xLeft = pRects[i].xLeft; + } + + if (dirtyRect.yTop > pRects[i].yTop) + { + dirtyRect.yTop = pRects[i].yTop; + } + + if (dirtyRect.xRight < pRects[i].xRight) + { + dirtyRect.xRight = pRects[i].xRight; + } + + if (dirtyRect.yBottom < pRects[i].yBottom) + { + dirtyRect.yBottom = pRects[i].yBottom; + } + } + } + + if (dirtyRect.xRight - dirtyRect.xLeft) + { + cr_server.CrCmdClientInfo.pfnCltScrUpdateEnd(cr_server.CrCmdClientInfo.hCltScr, idScreen, pScreen->i32OriginX + dirtyRect.xLeft, pScreen->i32OriginY + dirtyRect.yTop, + dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop); + } + else + { + cr_server.CrCmdClientInfo.pfnCltScrUpdateEnd(cr_server.CrCmdClientInfo.hCltScr, idScreen, 0, 0, 0, 0); + } + +} + +static void crPMgrPrimaryUpdate(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects) +{ + if (!cRects) + return; + + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + + uint32_t idFb = pScreen->u32ViewIndex; + CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb]; + + for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount); + i >= 0; + i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i)) + { + crPMgrPrimaryUpdateScreen(hFb, i, cRects, pRects); + } +} + +static int8_t crVBoxServerCrCmdBltPrimaryVramGenericProcess(uint32_t u32PrimaryID, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, bool fToPrimary) +{ + CR_BLITTER_IMG Img; + int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img); + if (i8Result) + { + WARN(("invalid param")); + return -1; + } + + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID); + if (!hFb) + { + WARN(("request to present on disabled framebuffer")); + return -1; + } + + if (!fToPrimary) + { + int rc = CrFbBltGetContents(hFb, pPos, cRects, pRects, &Img); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbBltGetContents failed %d", rc)); + return -1; + } + + return 0; + } + + int rc = CrFbBltPutContentsNe(hFb, pPos, cRects, pRects, &Img); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbBltPutContentsNe failed %d", rc)); + return -1; + } + + return 0; +} + +static int8_t crVBoxServerCrCmdBltPrimaryProcess(const VBOXCMDVBVA_BLT_PRIMARY *pCmd, uint32_t cbCmd) +{ + uint32_t u32PrimaryID = (uint32_t)pCmd->Hdr.Hdr.u.u8PrimaryID; + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID); + if (!hFb) + { + WARN(("request to present on disabled framebuffer, ignore")); + return 0; + } + + uint32_t cRects; + const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects; + if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) % sizeof (VBOXCMDVBVA_RECT)) + { + WARN(("invalid argument size")); + return -1; + } + + cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) / sizeof (VBOXCMDVBVA_RECT); + + RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects); + if (!pRects) + { + WARN(("crVBoxServerCrCmdBltRecsUnpack failed")); + return -1; + } + + uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags; + + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID) + { + uint32_t texId = pCmd->alloc.u.id; + if (!texId) + { + WARN(("texId is NULL!\n")); + return -1; + } + + if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2) + { + WARN(("blit from primary to texture not implemented")); + return -1; + } + + crServerDispatchVBoxTexPresent(texId, u32PrimaryID, pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y, cRects, (const GLint*)pRects); + + return 0; + } + else + { + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + uint32_t width = pScreen->u32Width, height = pScreen->u32Height; + VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc.u.offVRAM; + + bool fToPrymary = !(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2); + RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y}; + int8_t i8Result = crVBoxServerCrCmdBltPrimaryVramGenericProcess(u32PrimaryID, offVRAM, width, height, &Pos, cRects, pRects, fToPrymary); + if (i8Result < 0) + { + WARN(("crVBoxServerCrCmdBltPrimaryVramGenericProcess failed")); + return i8Result; + } + + if (!fToPrymary) + return 0; + } + + crPMgrPrimaryUpdate(hFb, cRects, pRects); + + return 0; +} + +static int8_t crVBoxServerCrCmdBltIdToVramMem(uint32_t hostId, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects) +{ + CR_TEXDATA* pTex = CrFbTexDataAcquire(hostId); + if (!pTex) + { + WARN(("pTex failed for %d", hostId)); + return -1; + } + + const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex); + if (!width) + { + width = pVrTex->width; + height = pVrTex->height; + } + + CR_BLITTER_IMG Img; + int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img); + if (i8Result) + { + WARN(("invalid param")); + return -1; + } + + int rc = CrTdBltEnter(pTex); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltEnter failed %d", rc)); + return -1; + } + + rc = crFbTexDataGetContents(pTex, pPos, cRects, pRects, &Img); + + CrTdBltLeave(pTex); + + CrTdRelease(pTex); + + if (!RT_SUCCESS(rc)) + { + WARN(("crFbTexDataGetContents failed %d", rc)); + return -1; + } + + return 0; +} + +static int8_t crVBoxServerCrCmdBltIdToVram(uint32_t hostId, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects) +{ + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledByVramStart(offVRAM); + if (hFb) + { + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + Assert(!width || pScreen->u32Width == width); + Assert(!height || pScreen->u32Height == height); + + crServerDispatchVBoxTexPresent(hostId, pScreen->u32ViewIndex, pPos->x, pPos->y, cRects, (const GLint*)pRects); + return 0; + } + + return crVBoxServerCrCmdBltIdToVramMem(hostId, offVRAM, width, height, pPos, cRects, pRects); +} + +static int8_t crVBoxServerCrCmdBltVramToVramMem(VBOXCMDVBVAOFFSET offSrcVRAM, uint32_t srcWidth, uint32_t srcHeight, VBOXCMDVBVAOFFSET offDstVRAM, uint32_t dstWidth, uint32_t dstHeight, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects) +{ + CR_BLITTER_IMG srcImg, dstImg; + int8_t i8Result = crFbImgFromDimOffVramBGRA(offSrcVRAM, srcWidth, srcHeight, &srcImg); + if (i8Result) + { + WARN(("invalid param")); + return -1; + } + + i8Result = crFbImgFromDimOffVramBGRA(offDstVRAM, dstWidth, dstHeight, &dstImg); + if (i8Result) + { + WARN(("invalid param")); + return -1; + } + + CrMBltImg(&srcImg, pPos, cRects, pRects, &dstImg); + + return 0; +} + +static int8_t crVBoxServerCrCmdBltVramToVram(VBOXCMDVBVAOFFSET offSrcVRAM, uint32_t srcWidth, uint32_t srcHeight, + VBOXCMDVBVAOFFSET offDstVRAM, uint32_t dstWidth, uint32_t dstHeight, + const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects) +{ + HCR_FRAMEBUFFER hSrcFb = CrPMgrFbGetEnabledByVramStart(offSrcVRAM); + HCR_FRAMEBUFFER hDstFb = CrPMgrFbGetEnabledByVramStart(offDstVRAM); + + if (hDstFb) + { + if (hSrcFb) + { + LOG(("blit from one framebuffer, wow")); + + int rc = CrFbUpdateBegin(hSrcFb); + if (RT_SUCCESS(rc)) + { + CrFbRegionsClear(hSrcFb); + + CrFbUpdateEnd(hSrcFb); + } + else + WARN(("CrFbUpdateBegin failed %d", rc)); + } + + CR_BLITTER_IMG Img; + int8_t i8Result = crFbImgFromDimOffVramBGRA(offSrcVRAM, srcWidth, srcHeight, &Img); + if (i8Result) + { + WARN(("invalid param")); + return -1; + } + + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hDstFb); + if (pScreen->u32Width == dstWidth && pScreen->u32Height == dstHeight) + { + int rc = CrFbBltPutContentsNe(hDstFb, pPos, cRects, pRects, &Img); + if (RT_FAILURE(rc)) + { + WARN(("CrFbBltPutContentsNe failed %d", rc)); + return -1; + } + } + else + { + int rc = CrFbUpdateBegin(hDstFb); + if (RT_SUCCESS(rc)) + { + CrFbRegionsClear(hDstFb); + + CrFbUpdateEnd(hDstFb); + } + else + WARN(("CrFbUpdateBegin failed %d", rc)); + + rc = crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects); + if (RT_FAILURE(rc)) + { + WARN(("crVBoxServerCrCmdBltVramToVramMem failed, %d", rc)); + return -1; + } + } + + crPMgrPrimaryUpdate(hDstFb, cRects, pRects); + + return 0; + } + else if (hSrcFb) + { + CR_BLITTER_IMG Img; + int8_t i8Result = crFbImgFromDimOffVramBGRA(offDstVRAM, dstWidth, dstHeight, &Img); + if (i8Result) + { + WARN(("invalid param")); + return -1; + } + + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hSrcFb); + if (pScreen->u32Width == srcWidth && pScreen->u32Height == srcHeight) + { + int rc = CrFbBltGetContents(hSrcFb, pPos, cRects, pRects, &Img); + if (RT_FAILURE(rc)) + { + WARN(("CrFbBltGetContents failed %d", rc)); + return -1; + } + } + else + { + int rc = CrFbUpdateBegin(hSrcFb); + if (RT_SUCCESS(rc)) + { + CrFbRegionsClear(hSrcFb); + + CrFbUpdateEnd(hSrcFb); + } + else + WARN(("CrFbUpdateBegin failed %d", rc)); + + rc = crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects); + if (RT_FAILURE(rc)) + { + WARN(("crVBoxServerCrCmdBltVramToVramMem failed, %d", rc)); + return -1; + } + } + + return 0; + } + + return crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects); +} + + +static int8_t crVBoxServerCrCmdBltOffIdProcess(const VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID *pCmd, uint32_t cbCmd) +{ + uint32_t cRects; + const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects; + if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, aRects)) % sizeof (VBOXCMDVBVA_RECT)) + { + WARN(("invalid argument size")); + return -1; + } + + cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, aRects)) / sizeof (VBOXCMDVBVA_RECT); + + RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects); + if (!pRects) + { + WARN(("crVBoxServerCrCmdBltRecsUnpack failed")); + return -1; + } + + uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags; + uint32_t hostId = pCmd->id; + + Assert(u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID); + + if (!hostId) + { + WARN(("zero host id")); + return -1; + } + + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID) + { + WARN(("blit from texture to texture not implemented")); + return -1; + } + + if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2) + { + WARN(("blit to texture not implemented")); + return -1; + } + + VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc.u.offVRAM; + + RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y}; + return crVBoxServerCrCmdBltIdToVram(hostId, offVRAM, 0, 0, &Pos, cRects, pRects); +} + +static int8_t crVBoxServerCrCmdBltSameDimOrId(const VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8 *pCmd, uint32_t cbCmd) +{ + uint32_t cRects; + const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects; + if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT)) + { + WARN(("invalid argument size")); + return -1; + } + + cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT); + + RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects); + if (!pRects) + { + WARN(("crVBoxServerCrCmdBltRecsUnpack failed")); + return -1; + } + + uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags; + VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc1.Info.u.offVRAM; + uint32_t width = pCmd->alloc1.u16Width; + uint32_t height = pCmd->alloc1.u16Height; + RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y}; + + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID) + { + uint32_t hostId = pCmd->info2.u.id; + + if (!hostId) + { + WARN(("zero host id")); + return -1; + } + + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID) + { + WARN(("blit from texture to texture not implemented")); + return -1; + } + + if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2) + { + WARN(("blit to texture not implemented")); + return -1; + } + + return crVBoxServerCrCmdBltIdToVram(hostId, offVRAM, width, height, &Pos, cRects, pRects); + } + + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID) + { + if (!(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)) + { + WARN(("blit to texture not implemented")); + return -1; + } + + return crVBoxServerCrCmdBltIdToVram(pCmd->alloc1.Info.u.id, pCmd->info2.u.offVRAM, width, height, &Pos, cRects, pRects); + } + + if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2) + crVBoxServerCrCmdBltVramToVram(offVRAM, width, height, pCmd->info2.u.offVRAM, width, height, &Pos, cRects, pRects); + else + crVBoxServerCrCmdBltVramToVram(pCmd->info2.u.offVRAM, width, height, offVRAM, width, height, &Pos, cRects, pRects); + + return 0; +} + +static int8_t crVBoxServerCrCmdBltGenericBGRAProcess(const VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8 *pCmd, uint32_t cbCmd) +{ + uint32_t cRects; + const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects; + if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT)) + { + WARN(("invalid argument size")); + return -1; + } + + cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT); + + RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects); + if (!pRects) + { + WARN(("crVBoxServerCrCmdBltRecsUnpack failed")); + return -1; + } + + uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags; + RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y}; + + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID) + { + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID) + { + WARN(("blit from texture to texture not implemented")); + return -1; + } + + if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2) + { + WARN(("blit to texture not implemented")); + return -1; + } + + return crVBoxServerCrCmdBltIdToVram(pCmd->alloc2.Info.u.id, pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, &Pos, cRects, pRects); + } + else + { + if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID) + { + if (!(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)) + { + WARN(("blit to texture not implemented")); + return -1; + } + + RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y}; + return crVBoxServerCrCmdBltIdToVram(pCmd->alloc1.Info.u.id, pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, &Pos, cRects, pRects); + } + + if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2) + crVBoxServerCrCmdBltVramToVram(pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, &Pos, cRects, pRects); + else + crVBoxServerCrCmdBltVramToVram(pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, &Pos, cRects, pRects); + + return 0; + } +} + +static int8_t crVBoxServerCrCmdClrFillPrimaryGenericProcess(uint32_t u32PrimaryID, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color) +{ + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID); + if (!hFb) + { + WARN(("request to present on disabled framebuffer, ignore")); + return 0; + } + + int rc = CrFbClrFillNe(hFb, cRects, pRects, u32Color); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbClrFillNe failed %d", rc)); + return -1; + } + + return 0; +} + +static int8_t crVBoxServerCrCmdClrFillVramGenericProcess(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color) +{ + CR_BLITTER_IMG Img; + int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img); + if (i8Result) + { + WARN(("invalid param")); + return -1; + } + + CrMClrFillImg(&Img, cRects, pRects, u32Color); + + return 0; +} + +static int8_t crVBoxServerCrCmdClrFillGenericBGRAProcess(const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8 *pCmd, uint32_t cbCmd) +{ + uint32_t cRects; + const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects; + if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT)) + { + WARN(("invalid argument size")); + return -1; + } + + cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT); + + RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects); + if (!pRects) + { + WARN(("crVBoxServerCrCmdBltRecsUnpack failed")); + return -1; + } + +// uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags; + int8_t i8Result = crVBoxServerCrCmdClrFillVramGenericProcess(pCmd->dst.Info.u.offVRAM, pCmd->dst.u16Width, pCmd->dst.u16Height, pRects, cRects, pCmd->Hdr.u32Color); + if (i8Result < 0) + { + WARN(("crVBoxServerCrCmdClrFillVramGenericProcess failed")); + return i8Result; + } + + return 0; +} + +/** @todo RT_UNTRUSTED_VOLATILE_GUEST */ +int8_t crVBoxServerCrCmdClrFillProcess(VBOXCMDVBVA_CLRFILL_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd) +{ + VBOXCMDVBVA_CLRFILL_HDR const *pCmd = (VBOXCMDVBVA_CLRFILL_HDR const *)pCmdTodo; + uint8_t u8Flags = pCmd->Hdr.u8Flags; + uint8_t u8Cmd = (VBOXCMDVBVA_OPF_CLRFILL_TYPE_MASK & u8Flags); + + switch (u8Cmd) + { + case VBOXCMDVBVA_OPF_CLRFILL_TYPE_GENERIC_A8R8G8B8: + { + if (cbCmd < sizeof (VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8)) + { + WARN(("VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8: invalid command size")); + return -1; + } + + return crVBoxServerCrCmdClrFillGenericBGRAProcess((const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8*)pCmd, cbCmd); + } + default: + WARN(("unsupported command")); + return -1; + } + +} + +/** @todo RT_UNTRUSTED_VOLATILE_GUEST */ +int8_t crVBoxServerCrCmdBltProcess(VBOXCMDVBVA_BLT_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd) +{ + VBOXCMDVBVA_BLT_HDR const *pCmd = (VBOXCMDVBVA_BLT_HDR const *)pCmdTodo; + uint8_t u8Flags = pCmd->Hdr.u8Flags; + uint8_t u8Cmd = (VBOXCMDVBVA_OPF_BLT_TYPE_MASK & u8Flags); + + switch (u8Cmd) + { + case VBOXCMDVBVA_OPF_BLT_TYPE_SAMEDIM_A8R8G8B8: + { + if (cbCmd < sizeof (VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8)) + { + WARN(("VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8: invalid command size")); + return -1; + } + + return crVBoxServerCrCmdBltSameDimOrId((const VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8 *)pCmd, cbCmd); + } + case VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID: + { + if (cbCmd < sizeof (VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID)) + { + WARN(("VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID: invalid command size")); + return -1; + } + + return crVBoxServerCrCmdBltOffIdProcess((const VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID *)pCmd, cbCmd); + } + case VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8: + { + if (cbCmd < sizeof (VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8)) + { + WARN(("VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8: invalid command size")); + return -1; + } + + return crVBoxServerCrCmdBltGenericBGRAProcess((const VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8 *)pCmd, cbCmd); + } + default: + WARN(("unsupported command")); + return -1; + } +} + +/** @todo RT_UNTRUSTED_VOLATILE_GUEST */ +int8_t crVBoxServerCrCmdFlipProcess(VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *pFlipTodo, uint32_t cbCmd) +{ + VBOXCMDVBVA_FLIP const *pFlip = (VBOXCMDVBVA_FLIP const *)pFlipTodo; + uint32_t hostId; + const VBOXCMDVBVA_RECT *pPRects = pFlip->aRects; + uint32_t cRects; + + if (pFlip->Hdr.u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID) + { + hostId = pFlip->src.u.id; + if (!hostId) + { + WARN(("hostId is NULL")); + return -1; + } + } + else + { + WARN(("VBOXCMDVBVA_OPF_ALLOC_SRCID not specified")); + hostId = 0; + } + + uint32_t idFb = pFlip->Hdr.u.u8PrimaryID; + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idFb); + if (!hFb) + { + WARN(("request to present on disabled framebuffer, ignore")); + return 0; + } + + cRects = (cbCmd - VBOXCMDVBVA_SIZEOF_FLIPSTRUCT_MIN) / sizeof (VBOXCMDVBVA_RECT); + if (cRects > 0) + { + RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects); + if (pRects) + { + crServerDispatchVBoxTexPresent(hostId, idFb, 0, 0, cRects, (const GLint*)pRects); + return 0; + } + } + else + { + /* Prior to r100476 guest WDDM driver was not supplying us with sub-rectangles + * data obtained in DxgkDdiPresentNew() callback. Therefore, in order to support backward compatibility, + * lets play in old way if no rectangles were supplied. */ + const RTRECT *pRect = CrVrScrCompositorRectGet(&hFb->Compositor); + crServerDispatchVBoxTexPresent(hostId, idFb, 0, 0, 1, (const GLint*)pRect); + } + + return -1; +} + +typedef struct CRSERVER_CLIENT_CALLOUT +{ + VBOXCRCMDCTL_CALLOUT_LISTENTRY Entry; + PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb; + void*pvCb; +} CRSERVER_CLIENT_CALLOUT; + +static DECLCALLBACK(void) crServerClientCalloutCb(struct VBOXCRCMDCTL_CALLOUT_LISTENTRY *pEntry) +{ + CRSERVER_CLIENT_CALLOUT *pCallout = RT_FROM_MEMBER(pEntry, CRSERVER_CLIENT_CALLOUT, Entry); + pCallout->pfnCb(pCallout->pvCb); + int rc = RTSemEventSignal(cr_server.hCalloutCompletionEvent); + if (RT_FAILURE(rc)) + WARN(("RTSemEventSignal failed rc %d", rc)); +} + +static DECLCALLBACK(void) crServerClientCallout(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void*pvCb) +{ + Assert(cr_server.pCurrentCalloutCtl); + CRSERVER_CLIENT_CALLOUT Callout; + Callout.pfnCb = pfnCb; + Callout.pvCb = pvCb; + cr_server.ClientInfo.pfnCallout(cr_server.ClientInfo.hClient, cr_server.pCurrentCalloutCtl, &Callout.Entry, crServerClientCalloutCb); + + int rc = RTSemEventWait(cr_server.hCalloutCompletionEvent, RT_INDEFINITE_WAIT); + if (RT_FAILURE(rc)) + WARN(("RTSemEventWait failed %d", rc)); +} + + +DECLEXPORT(void) crVBoxServerCalloutEnable(VBOXCRCMDCTL *pCtl) +{ +#if 1 //def CR_SERVER_WITH_CLIENT_CALLOUTS + Assert(!cr_server.pCurrentCalloutCtl); + cr_server.pCurrentCalloutCtl = pCtl; + + cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_CLIENT_CALLOUT, 0, 0, (void*)crServerClientCallout); +#endif +} + +extern DECLEXPORT(void) crVBoxServerCalloutDisable() +{ +#if 1 //def CR_SERVER_WITH_CLIENT_CALLOUTS + Assert(cr_server.pCurrentCalloutCtl); + + cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_CLIENT_CALLOUT, 0, 0, NULL); + + cr_server.pCurrentCalloutCtl = NULL; +#endif +} diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h new file mode 100644 index 00000000..759f8dbd --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h @@ -0,0 +1,440 @@ +/* $Id: server_presenter.h $ */ + +/** @file + * Presenter API definitions. + */ + +/* + * Copyright (C) 2014-2019 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. + */ + +#ifndef __SERVER_PRESENTER_H__ +#define __SERVER_PRESENTER_H__ + +#include "cr_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "server_dispatch.h" +#include "server.h" +#include "cr_mem.h" +#include "cr_string.h" +#include <cr_vreg.h> +#include <cr_htable.h> +#include <cr_bmpscale.h> + +#include "render/renderspu.h" + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/asm.h> +#include <iprt/mem.h> +#include <iprt/list.h> + + +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() {} +}; + + +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; + + +class CrFbDisplayBase : public ICrFbDisplay +{ + public: + + CrFbDisplayBase(); + + virtual bool isComposite(); + class CrFbDisplayComposite* getContainer(); + bool isInList(); + bool isUpdating(); + int setRegionsChanged(); + int setFramebuffer(struct CR_FRAMEBUFFER *pFb); + struct CR_FRAMEBUFFER* getFramebuffer(); + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb); + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb); + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry); + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb); + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb); + virtual ~CrFbDisplayBase(); + + /*@todo: move to protected and switch from RTLISTNODE*/ + RTLISTNODE mNode; + class CrFbDisplayComposite* mpContainer; + + protected: + + virtual void onUpdateEnd(); + virtual void ueRegions(); + static DECLCALLBACK(bool) entriesCreateCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext); + static DECLCALLBACK(bool) entriesDestroyCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext); + int fbSynchAddAllEntries(); + int fbCleanupRemoveAllEntries(); + virtual int setFramebufferBegin(struct CR_FRAMEBUFFER *pFb); + virtual void setFramebufferEnd(struct CR_FRAMEBUFFER *pFb); + static DECLCALLBACK(void) slotEntryReleaseCB(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext); + virtual void slotRelease(); + virtual int fbCleanup(); + virtual int fbSync(); + CRHTABLE_HANDLE slotGet(); + + private: + + typedef union CR_FBDISPBASE_FLAGS + { + struct { + uint32_t fRegionsShanged : 1; + uint32_t Reserved : 31; + }; + uint32_t u32Value; + } CR_FBDISPBASE_FLAGS; + + struct CR_FRAMEBUFFER *mpFb; + uint32_t mcUpdates; + CRHTABLE_HANDLE mhSlot; + CR_FBDISPBASE_FLAGS mFlags; +}; + + +class CrFbDisplayComposite : public CrFbDisplayBase +{ + public: + + CrFbDisplayComposite(); + virtual bool isComposite(); + uint32_t getDisplayCount(); + bool add(CrFbDisplayBase *pDisplay); + bool remove(CrFbDisplayBase *pDisplay, bool fCleanupDisplay = true); + CrFbDisplayBase* first(); + CrFbDisplayBase* next(CrFbDisplayBase* pDisplay); + virtual int setFramebuffer(struct CR_FRAMEBUFFER *pFb); + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb); + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb); + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry); + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb); + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb); + virtual ~CrFbDisplayComposite(); + void cleanup(bool fCleanupDisplays = true); + + private: + + RTLISTNODE mDisplays; + uint32_t mcDisplays; +}; + + +class CrFbWindow +{ + public: + + CrFbWindow(uint64_t parentId); + bool IsCreated() const; + bool IsVisivle() const; + void Destroy(); + int Reparent(uint64_t parentId); + int SetVisible(bool fVisible); + int SetSize(uint32_t width, uint32_t height, bool fForced=false); + int SetPosition(int32_t x, int32_t y, bool fForced=false); + int SetVisibleRegionsChanged(); + int SetCompositor(const struct VBOXVR_SCR_COMPOSITOR * pCompositor); + bool SetScaleFactor(GLdouble scaleFactorW, GLdouble scaleFactorH); + bool GetScaleFactor(GLdouble *scaleFactorW, GLdouble *scaleFactorH); + int UpdateBegin(); + void UpdateEnd(); + uint64_t GetParentId(); + int Create(); + ~CrFbWindow(); + + protected: + + void checkRegions(); + bool isPresentNeeded(); + bool checkInitedUpdating(); + + private: + + typedef union CR_FBWIN_FLAGS + { + 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; + + 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; + + RTSEMRW scaleFactorLock; + GLdouble mScaleFactorWStorage; + GLdouble mScaleFactorHStorage; +}; + + +class CrFbDisplayWindow : public CrFbDisplayBase +{ + public: + + CrFbDisplayWindow(const RTRECT *pViewportRect, uint64_t parentId); + virtual ~CrFbDisplayWindow(); + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb); + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb); + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb); + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry); + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb); + const RTRECT* getViewportRect(); + virtual int setViewportRect(const RTRECT *pViewportRect); + virtual CrFbWindow * windowDetach(bool fCleanup = true); + virtual CrFbWindow * windowAttach(CrFbWindow * pNewWindow); + virtual int reparent(uint64_t parentId); + virtual bool isVisible(); + int winVisibilityChanged(); + CrFbWindow* getWindow(); + + protected: + + virtual void onUpdateEnd(); + virtual void ueRegions(); + virtual int screenChanged(); + virtual int windowSetCompositor(bool fSet); + virtual int windowCleanup(); + virtual int fbCleanup(); + bool isActive(); + int windowDimensionsSync(bool fForceCleanup = false); + virtual int windowSync(); + virtual int fbSync(); + virtual const struct RTRECT* getRect(); + + private: + + typedef union CR_FBDISPWINDOW_FLAGS + { + struct { + uint32_t fNeVisible : 1; + uint32_t fNeForce : 1; + uint32_t Reserved : 30; + }; + uint32_t u32Value; + } CR_FBDISPWINDOW_FLAGS; + + CrFbWindow *mpWindow; + RTRECT mViewportRect; + CR_FBDISPWINDOW_FLAGS mFlags; + uint32_t mu32Screen; + uint64_t mParentId; +}; + + +class CrFbDisplayWindowRootVr : public CrFbDisplayWindow +{ + public: + + CrFbDisplayWindowRootVr(const RTRECT *pViewportRect, uint64_t parentId); + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry); + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int setViewportRect(const RTRECT *pViewportRect); + + protected: + + virtual int windowSetCompositor(bool fSet); + virtual void ueRegions(); + int compositorMarkUpdated(); + virtual int screenChanged(); + virtual const struct RTRECT* getRect(); + virtual int fbCleanup(); + virtual int fbSync(); + VBOXVR_SCR_COMPOSITOR_ENTRY* entryAlloc(); + void entryFree(VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry); + int synchCompositorRegions(); + virtual int synchCompositor(); + virtual int clearCompositor(); + void rootVrTranslateForPos(); + static DECLCALLBACK(VBOXVR_SCR_COMPOSITOR_ENTRY*) rootVrGetCEntry(const VBOXVR_SCR_COMPOSITOR_ENTRY*pEntry, void *pvContext); + + private: + + VBOXVR_SCR_COMPOSITOR mCompositor; +}; + + +class CrFbDisplayVrdp : public CrFbDisplayBase +{ + public: + + CrFbDisplayVrdp(); + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry); + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb); + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb); + + protected: + + void syncPos(); + virtual int fbCleanup(); + virtual int fbSync(); + void vrdpDestroy(HCR_FRAMEBUFFER_ENTRY hEntry); + void vrdpGeometry(HCR_FRAMEBUFFER_ENTRY hEntry); + int vrdpRegions(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + int vrdpFrame(HCR_FRAMEBUFFER_ENTRY hEntry); + int vrdpRegionsAll(struct CR_FRAMEBUFFER *pFb); + int vrdpSynchEntry(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry); + int vrdpSyncEntryAll(struct CR_FRAMEBUFFER *pFb); + int vrdpCreate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry); + + private: + + RTPOINT mPos; +}; + + +typedef struct CR_FB_INFO +{ + CrFbDisplayComposite *pDpComposite; + uint32_t u32Id; + VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap); +} CR_FB_INFO; + +typedef struct CR_FBDISPLAY_INFO +{ + CrFbDisplayWindow *pDpWin; + CrFbDisplayWindowRootVr *pDpWinRootVr; + CrFbDisplayVrdp *pDpVrdp; + CrFbWindow *pWindow; + uint32_t u32DisplayMode; + uint32_t u32Id; + int32_t iFb; + + /* Cache scaling factor here before display output + * initialized (i.e., guest not yet initiated first 3D call). + * No synchronization stuff needed here because all the reads + * and writes are done in context of 3D HGCM thread. */ + double dInitialScaleFactorW; + double dInitialScaleFactorH; +} CR_FBDISPLAY_INFO; + +typedef struct CR_PRESENTER_GLOBALS +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMEMCACHE FbEntryLookasideList; + RTMEMCACHE FbTexLookasideList; + RTMEMCACHE CEntryLookasideList; +#endif + uint32_t u32DisplayMode; + uint32_t u32DisabledDisplayMode; + bool fEnabled; + CRHashTable *pFbTexMap; + CR_FBDISPLAY_INFO aDisplayInfos[CR_MAX_GUEST_MONITORS]; + CR_FBMAP FramebufferInitMap; + CR_FRAMEBUFFER aFramebuffers[CR_MAX_GUEST_MONITORS]; + CR_FB_INFO aFbInfos[CR_MAX_GUEST_MONITORS]; + bool fWindowsForceHidden; + uint32_t cbTmpBuf; + void *pvTmpBuf; + uint32_t cbTmpBuf2; + void *pvTmpBuf2; +} CR_PRESENTER_GLOBALS; + +extern CR_PRESENTER_GLOBALS g_CrPresenter; + + +HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry); + +#endif /* __SERVER_PRESENTER_H__ */ + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp new file mode 100644 index 00000000..dd160996 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp @@ -0,0 +1,480 @@ +/* $Id: window.cpp $ */ + +/** @file + * Presenter API: window class implementation. + */ + +/* + * Copyright (C) 2014-2019 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 "server_presenter.h" +#include <VBox/VBoxOGL.h> + +CrFbWindow::CrFbWindow(uint64_t parentId) : + mSpuWindow(0), + mpCompositor(NULL), + mcUpdates(0), + mxPos(0), + myPos(0), + mWidth(0), + mHeight(0), + mParentId(parentId), + mScaleFactorWStorage(1.0), + mScaleFactorHStorage(1.0) +{ + int rc; + + mFlags.Value = 0; + + rc = RTSemRWCreate(&scaleFactorLock); + if (!RT_SUCCESS(rc)) + WARN(("Unable to initialize scaling factor data lock.")); +} + + +bool CrFbWindow::IsCreated() const +{ + return !!mSpuWindow; +} + +bool CrFbWindow::IsVisivle() const +{ + return mFlags.fVisible; +} + + +void CrFbWindow::Destroy() +{ + CRASSERT(!mcUpdates); + + if (!mSpuWindow) + return; + + cr_server.head_spu->dispatch_table.WindowDestroy(mSpuWindow); + + mSpuWindow = 0; + mFlags.fDataPresented = 0; +} + + +int CrFbWindow::Reparent(uint64_t parentId) +{ + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + crDebug("CrFbWindow: reparent to %p (current mxPos=%d, myPos=%d, mWidth=%u, mHeight=%u)", + parentId, mxPos, myPos, mWidth, mHeight); + + 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) + { + if (mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos); + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, mFlags.fVisible); + } + } + + return VINF_SUCCESS; +} + + +int CrFbWindow::SetVisible(bool fVisible) +{ + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + LOG(("CrWIN: Visible [%d]", fVisible)); + + if (!fVisible != !mFlags.fVisible) + { + mFlags.fVisible = fVisible; + if (mSpuWindow && mParentId) + { + if (fVisible) + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos); + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, fVisible); + } + } + + return VINF_SUCCESS; +} + + +int CrFbWindow::SetSize(uint32_t width, uint32_t height, bool fForced) +{ + if (!fForced && !checkInitedUpdating()) + { + crDebug("CrFbWindow: SetSize request dropped because window is currently updating" + "(width=%d, height=%d, mWidth=%d, mHeight=%d).", width, height, mWidth, mHeight); + return VERR_INVALID_STATE; + } + + if (mWidth != width || mHeight != height || fForced) + { + GLdouble scaleFactorW, scaleFactorH; + uint32_t scaledWidth, scaledHeight; + + /* Reset to default values if operation was unsuccessfull. */ + if (!GetScaleFactor(&scaleFactorW, &scaleFactorH)) + scaleFactorW = scaleFactorH = 1.0; + + mFlags.fCompositoEntriesModified = 1; + + /* Keep mWidth and mHeight unchanged (not multiplied by scale factor scalar). */ + mWidth = width; + mHeight = height; + + scaledWidth = (uint32_t)((GLdouble)width * scaleFactorW); + scaledHeight = (uint32_t)((GLdouble)height * scaleFactorH); + + if (mSpuWindow) + { + cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, scaledWidth, scaledHeight); + crDebug("CrFbWindow: SetSize request performed successfully " + "(width=%d, height=%d, scaledWidth=%d, scaledHeight=%d).", width, height, scaledWidth, scaledHeight); + } + else + crDebug("CrFbWindow: SetSize request skipped because mSpuWindow not yet constructed " + "(width=%d, height=%d, scaledWidth=%d, scaledHeight=%d).", width, height, scaledWidth, scaledHeight); + } + else + crDebug("CrFbWindow: SetSize request skipped because window arleady has requested size " + "(width=%d, height=%d, mWidth=%d, mHeight=%d).", width, height, mWidth, mHeight); + + return VINF_SUCCESS; +} + + +int CrFbWindow::SetPosition(int32_t x, int32_t y, bool fForced) +{ + if (!fForced && !checkInitedUpdating()) + { + crDebug("CrFbWindow: SetPosition request dropped because window is currently updating (x=%d, y=%d).", x, y); + 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); + crDebug("CrFbWindow: SetPosition performed successfully (x=%d, y=%d).", x, y); + } + + return VINF_SUCCESS; +} + + +int CrFbWindow::SetVisibleRegionsChanged() +{ + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mFlags.fCompositoEntriesModified = 1; + return VINF_SUCCESS; +} + + +int CrFbWindow::SetCompositor(const struct VBOXVR_SCR_COMPOSITOR * pCompositor) +{ + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mpCompositor = pCompositor; + mFlags.fCompositoEntriesModified = 1; + + return VINF_SUCCESS; +} + + +bool CrFbWindow::SetScaleFactor(GLdouble scaleFactorW, GLdouble scaleFactorH) +{ + int rc; + + /* Simple check for input values. */ + if ( !( (scaleFactorW >= VBOX_OGL_SCALE_FACTOR_MIN && scaleFactorW <= VBOX_OGL_SCALE_FACTOR_MAX) + && (scaleFactorH >= VBOX_OGL_SCALE_FACTOR_MIN && scaleFactorH <= VBOX_OGL_SCALE_FACTOR_MAX))) + { + crDebug("CrFbWindow: attempt to set scale factor out of valid values range: scaleFactorW=%d, scaleFactorH=%d, multiplier=%d.", + (int)(scaleFactorW * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), (int)(scaleFactorH * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), + (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER); + + return false; + } + + rc = RTSemRWRequestWrite(scaleFactorLock, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + mScaleFactorWStorage = scaleFactorW; + mScaleFactorHStorage = scaleFactorH; + RTSemRWReleaseWrite(scaleFactorLock); + + crDebug("CrFbWindow: set scale factor: scaleFactorW=%d, scaleFactorH=%d, multiplier=%d.", + (int)(scaleFactorW * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), (int)(scaleFactorH * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), + (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER); + + /* Update window geometry. Do not wait for GAs to send SetSize() and SetPosition() + * events since they might not be running or installed at all. */ + SetSize(mWidth, mHeight, true); + SetPosition(mxPos, myPos, true); + + return true; + } + + crDebug("CrFbWindow: unable to set scale factor because RW lock cannot be aquired: scaleFactorW=%d, scaleFactorH=%d, multiplier=%d.", + (int)(scaleFactorW * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), (int)(scaleFactorH * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), + (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER); + + return false; +} + + +bool CrFbWindow::GetScaleFactor(GLdouble *scaleFactorW, GLdouble *scaleFactorH) +{ + int rc; + + rc = RTSemRWRequestRead(scaleFactorLock, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + *scaleFactorW = mScaleFactorWStorage; + *scaleFactorH = mScaleFactorHStorage; + RTSemRWReleaseRead(scaleFactorLock); + return true; + } + + return false; +} + + +int CrFbWindow::UpdateBegin() +{ + ++mcUpdates; + if (mcUpdates > 1) + return VINF_SUCCESS; + + Assert(!mFlags.fForcePresentOnReenable); + + crDebug("CrFbWindow::UpdateBegin ENTER, mSpuWindow(0x%X) fDataPresented(%d)", mSpuWindow, mFlags.fDataPresented); + + if (mFlags.fDataPresented) + { + Assert(mSpuWindow); + cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, NULL, NULL); + mFlags.fForcePresentOnReenable = isPresentNeeded(); + } + + crDebug("CrFbWindow::UpdateBegin LEAVE, fForcePresentOnReenable(%d)", mFlags.fForcePresentOnReenable); + + return VINF_SUCCESS; +} + + +void CrFbWindow::UpdateEnd() +{ + --mcUpdates; + Assert(mcUpdates < UINT32_MAX/2); + if (mcUpdates) + return; + + crDebug("CrFbWindow::UpdateEnd ENTER, mSpuWindow(0x%X) mpCompositor(0x%X) fForcePresentOnReenable(%d)", mSpuWindow, mpCompositor, mFlags.fForcePresentOnReenable); + + if (mSpuWindow) + { + bool fPresentNeeded = isPresentNeeded(); + GLdouble scaleFactorW, scaleFactorH; + /* Reset to default values if operation was unseccessfull. */ + if (!GetScaleFactor(&scaleFactorW, &scaleFactorH)) + scaleFactorW = scaleFactorH = 1.0; + + if (mpCompositor) + { + CrVrScrCompositorSetStretching((VBOXVR_SCR_COMPOSITOR *)mpCompositor, scaleFactorW, scaleFactorH); + checkRegions(); + } + + if (fPresentNeeded || mFlags.fForcePresentOnReenable) + { + mFlags.fForcePresentOnReenable = false; + if (mpCompositor) + { + cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, mpCompositor, NULL); + } + else + { + VBOXVR_SCR_COMPOSITOR TmpCompositor; + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = (uint32_t)((GLdouble)mWidth * scaleFactorW); + Rect.yBottom = (uint32_t)((GLdouble)mHeight * scaleFactorH); + CrVrScrCompositorInit(&TmpCompositor, &Rect); + CrVrScrCompositorSetStretching((VBOXVR_SCR_COMPOSITOR *)&TmpCompositor, scaleFactorW, scaleFactorH); + /* this is a cleanup operation + * empty compositor is guarantid to be released on VBoxPresentComposition return */ + cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, &TmpCompositor, NULL); + } + g_pLed->Asserted.s.fWriting = 1; + } + + /* 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 + { + Assert(!mFlags.fDataPresented); + Assert(!mFlags.fForcePresentOnReenable); + } +} + + +uint64_t CrFbWindow::GetParentId() +{ + return mParentId; +} + + +int CrFbWindow::Create() +{ + if (mSpuWindow) + { + //WARN(("window already created")); + return VINF_ALREADY_INITIALIZED; + } + + crDebug("CrFbWindow::Create ENTER, mParentId(0x%X)\n", mParentId); + + 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; + } + + GLdouble scaleFactorW, scaleFactorH; + /* Reset to default values if operation was unseccessfull. */ + if (!GetScaleFactor(&scaleFactorW, &scaleFactorH)) + scaleFactorW = scaleFactorH = 1.0; + + uint32_t scaledWidth, scaledHeight; + + scaledWidth = (uint32_t)((GLdouble)mWidth * scaleFactorW); + scaledHeight = (uint32_t)((GLdouble)mHeight * scaleFactorH); + + cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, scaledWidth, scaledHeight); + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos); + + checkRegions(); + + if (mParentId && mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, true); + + crDebug("CrFbWindow::Create LEAVE, mParentId(0x%X) mSpuWindow(0x%X)\n", mParentId, mSpuWindow); + return VINF_SUCCESS; +} + + +CrFbWindow::~CrFbWindow() +{ + int rc; + + Destroy(); + + rc = RTSemRWDestroy(scaleFactorLock); + if (!RT_SUCCESS(rc)) + WARN(("Unable to release scaling factor data lock.")); +} + + +void CrFbWindow::checkRegions() +{ + crDebug("CrFbWindow::checkRegions ENTER, mSpuWindow(0x%X) mpCompositor(0x%X) fCompositoEntriesModified(%d)", + mSpuWindow, mpCompositor, mFlags.fCompositoEntriesModified); + + 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; + + crDebug("CrFbWindow::checkRegions LEAVE, cRects(%d)", cRects); +} + + +bool CrFbWindow::isPresentNeeded() +{ + return mFlags.fVisible && mWidth && mHeight && mpCompositor && !CrVrScrCompositorIsEmpty(mpCompositor); +} + + +bool CrFbWindow::checkInitedUpdating() +{ + if (!mcUpdates) + { + WARN(("not updating")); + return false; + } + + return true; +} + |