/* $Id: server_presenter.cpp 49448 2013-11-12 12:15:10Z vboxsync $ */ /** @file * Presenter API */ /* * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "cr_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 #include #include #include #include #include #include #include "render/renderspu.h" /* DISPLAY */ int CrDpInit(PCR_DISPLAY pDisplay) { const GLint visBits = cr_server.MainContextInfo.CreateInfo.visualBits; if (crServerMuralInit(&pDisplay->Mural, "", visBits, -1, GL_FALSE) < 0) { crWarning("crServerMuralInit failed!"); return VERR_GENERAL_FAILURE; } crServerWindowVisibleRegion(&pDisplay->Mural); crServerDEntryAllVibleRegions(&pDisplay->Mural); crServerMuralShow(&pDisplay->Mural, GL_TRUE); pDisplay->fForcePresent = GL_FALSE; return VINF_SUCCESS; } void CrDpTerm(PCR_DISPLAY pDisplay) { crServerMuralTerm(&pDisplay->Mural); } void CrDpResize(PCR_DISPLAY pDisplay, int32_t xPos, int32_t yPos, uint32_t width, uint32_t height) { if (xPos != pDisplay->Mural.gX || yPos != pDisplay->Mural.gY || width != pDisplay->Mural.width || height != pDisplay->Mural.height) { crServerMuralPosition(&pDisplay->Mural, xPos, yPos, GL_TRUE); if (!crServerMuralSize(&pDisplay->Mural, width, height)) crServerCheckMuralGeometry(&pDisplay->Mural); } else crServerCheckMuralGeometry(&pDisplay->Mural); } void CrDpReparent(PCR_DISPLAY pDisplay, CRScreenInfo *pScreen) { renderspuSetWindowId(pScreen->winID); crServerWindowReparent(&pDisplay->Mural); renderspuSetWindowId(cr_server.screen[0].winID); CrDpResize(pDisplay, pScreen->x, pScreen->y, pScreen->w, pScreen->h); if (pScreen->winID) { /* need to do this on win, since otherwise the window ends up being with empty visible regions for some reason */ crServerWindowVisibleRegion(&pDisplay->Mural); } } int CrDpSaveState(PCR_DISPLAY pDisplay, PSSMHANDLE pSSM) { VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; CrVrScrCompositorIterInit(&pDisplay->Mural.Compositor, &Iter); PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; uint32_t u32 = 0; while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) { ++u32; } int rc = SSMR3PutU32(pSSM, u32); AssertRCReturn(rc, rc); CrVrScrCompositorIterInit(&pDisplay->Mural.Compositor, &Iter); while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) { CR_DISPLAY_ENTRY *pDEntry = CR_DENTRY_FROM_CENTRY(pEntry); rc = CrDemEntrySaveState(pDEntry, pSSM); AssertRCReturn(rc, rc); u32 = CrVrScrCompositorEntryFlagsGet(&pDEntry->CEntry); rc = SSMR3PutU32(pSSM, u32); AssertRCReturn(rc, rc); rc = SSMR3PutS32(pSSM, CrVrScrCompositorEntryPosGet(&pDEntry->CEntry)->x); AssertRCReturn(rc, rc); rc = SSMR3PutS32(pSSM, CrVrScrCompositorEntryPosGet(&pDEntry->CEntry)->y); AssertRCReturn(rc, rc); const RTRECT * pRects; rc = CrVrScrCompositorEntryRegionsGet(&pDisplay->Mural.Compositor, &pDEntry->CEntry, &u32, NULL, NULL, &pRects); AssertRCReturn(rc, rc); rc = SSMR3PutU32(pSSM, u32); AssertRCReturn(rc, rc); if (u32) { rc = SSMR3PutMem(pSSM, pRects, u32 * sizeof (*pRects)); AssertRCReturn(rc, rc); } } return VINF_SUCCESS; } int CrDpLoadState(PCR_DISPLAY pDisplay, PSSMHANDLE pSSM, uint32_t version) { uint32_t u32 = 0; int rc = SSMR3GetU32(pSSM, &u32); AssertRCReturn(rc, rc); if (!u32) return VINF_SUCCESS; CrDpEnter(pDisplay); for (uint32_t i = 0; i < u32; ++i) { CR_DISPLAY_ENTRY *pDEntry; rc = CrDemEntryLoadState(&cr_server.PresentTexturepMap, &pDEntry, pSSM); AssertRCReturn(rc, rc); uint32_t fFlags; rc = SSMR3GetU32(pSSM, &fFlags); AssertRCReturn(rc, rc); CrVrScrCompositorEntryFlagsSet(&pDEntry->CEntry, fFlags); RTPOINT Pos; rc = SSMR3GetS32(pSSM, &Pos.x); AssertRCReturn(rc, rc); rc = SSMR3GetS32(pSSM, &Pos.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 = CrDpEntryRegionsAdd(pDisplay, pDEntry, &Pos, (uint32_t)cRects, (const RTRECT*)pRects, NULL); AssertRCReturn(rc, rc); if (pRects) crFree(pRects); } CrDpLeave(pDisplay); return VINF_SUCCESS; } int CrDpEntryRegionsSet(PCR_DISPLAY pDisplay, PCR_DISPLAY_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions) { int rc = CrVrScrCompositorEntryRegionsSet(&pDisplay->Mural.Compositor, pEntry ? &pEntry->CEntry : NULL, pPos, cRegions, paRegions, false, NULL); return rc; } void crDbgDumpRect(uint32_t i, const RTRECT *pRect) { crDebug("%d: (%d;%d) X (%d;%d)", i, pRect->xLeft, pRect->yTop, pRect->xRight, pRect->yBottom); } void crDbgDumpRects(uint32_t cRects, const RTRECT *paRects) { crDebug("Dumping rects (%d)", cRects); for (uint32_t i = 0; i < cRects; ++i) { crDbgDumpRect(i, &paRects[i]); } crDebug("End Dumping rects (%d)", cRects); } int CrDpEntryRegionsAdd(PCR_DISPLAY pDisplay, PCR_DISPLAY_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, CR_DISPLAY_ENTRY_MAP *pMap) { uint32_t fChangeFlags = 0; VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL; if (pMap) CrDemEnter(pMap); int rc = CrVrScrCompositorEntryRegionsAdd(&pDisplay->Mural.Compositor, pEntry ? &pEntry->CEntry : NULL, pPos, cRegions, paRegions, false, &pReplacedScrEntry, &fChangeFlags); if (RT_SUCCESS(rc)) { if (fChangeFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED) { bool fChanged = true; if (pDisplay->Mural.fRootVrOn) { int rc = crServerMuralSynchRootVr(&pDisplay->Mural, &fChanged); if (!RT_SUCCESS(rc)) { crWarning("crServerMuralSynchRootVr failed, rc %d", rc); fChanged = false; } } if (fChanged) crServerWindowVisibleRegion(&pDisplay->Mural); crServerDEntryAllVibleRegions(&pDisplay->Mural); Assert(!pReplacedScrEntry); } else if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED) { if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) { Assert(pReplacedScrEntry); Assert(pEntry); if (pDisplay->Mural.fRootVrOn) { CR_DISPLAY_ENTRY *pReplacedDEntry = CR_DENTRY_FROM_CENTRY(pReplacedScrEntry); Assert(CrVrScrCompositorEntryIsUsed(&pReplacedDEntry->RootVrCEntry)); Assert(!CrVrScrCompositorEntryIsUsed(&pEntry->RootVrCEntry)); CrVrScrCompositorEntryInit(&pEntry->RootVrCEntry, CrVrScrCompositorEntryTexGet(&pEntry->CEntry), NULL); CrVrScrCompositorEntryFlagsSet(&pEntry->RootVrCEntry, CrVrScrCompositorEntryFlagsGet(&pEntry->CEntry)); CrVrScrCompositorEntryReplace(&pDisplay->Mural.RootVrCompositor, &pReplacedDEntry->RootVrCEntry, &pEntry->RootVrCEntry); } } else { Assert(!pReplacedScrEntry); if (pDisplay->Mural.fRootVrOn) { bool fChanged = false; int rc = crServerMuralSynchRootVr(&pDisplay->Mural, &fChanged); if (RT_SUCCESS(rc)) { if (fChanged) crServerWindowVisibleRegion(&pDisplay->Mural); } else crWarning("crServerMuralSynchRootVr failed, rc %d", rc); } } } else { Assert(!(fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)); Assert(!pReplacedScrEntry); } } else crWarning("CrVrScrCompositorEntryRegionsAdd failed, rc %d", rc); if (pMap) CrDemLeave(pMap, CR_DENTRY_FROM_CENTRY(pEntry), CR_DENTRY_FROM_CENTRY(pReplacedScrEntry)); return rc; } void CrDpRegionsClear(PCR_DISPLAY pDisplay) { bool fChanged = false; CrVrScrCompositorRegionsClear(&pDisplay->Mural.Compositor, &fChanged); if (fChanged) { crServerMuralVisibleRegion(&pDisplay->Mural, 0, NULL); } } #define PCR_DISPLAY_ENTRY_FROM_CENTRY(_pe) ((PCR_DISPLAY_ENTRY)((uint8_t*)(_pe) - RT_OFFSETOF(CR_DISPLAY_ENTRY, CEntry))) static DECLCALLBACK(void) crDpEntryCEntryReleaseCB(const struct VBOXVR_SCR_COMPOSITOR *pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacingEntry) { PCR_DISPLAY_ENTRY pCEntry = PCR_DISPLAY_ENTRY_FROM_CENTRY(pEntry); CrDemEntryRelease(pCEntry); } void CrDpEntryInit(PCR_DISPLAY_ENTRY pEntry, const VBOXVR_TEXTURE *pTextureData, uint32_t fFlags, PFNVBOXVRSCRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased) { CrVrScrCompositorEntryInit(&pEntry->CEntry, pTextureData, pfnEntryReleased); CrVrScrCompositorEntryFlagsSet(&pEntry->CEntry, fFlags); CrVrScrCompositorEntryInit(&pEntry->RootVrCEntry, pTextureData, NULL); CrVrScrCompositorEntryFlagsSet(&pEntry->RootVrCEntry, fFlags); pEntry->pvORInstance = NULL; pEntry->idPBO = 0; pEntry->idInvertTex = 0; } void CrDpEntryCleanup(PCR_DISPLAY_ENTRY pDEntry) { if (pDEntry->idPBO) { CRASSERT(cr_server.bUsePBOForReadback); cr_server.head_spu->dispatch_table.DeleteBuffersARB(1, &pDEntry->idPBO); pDEntry->idPBO = 0; } if (pDEntry->idInvertTex) { cr_server.head_spu->dispatch_table.DeleteTextures(1, &pDEntry->idInvertTex); pDEntry->idInvertTex = 0; } if (pDEntry->pvORInstance) { cr_server.outputRedirect.CROREnd(pDEntry->pvORInstance); pDEntry->pvORInstance = NULL; } } void CrDpEnter(PCR_DISPLAY pDisplay) { pDisplay->fForcePresent |= crServerVBoxCompositionPresentNeeded(&pDisplay->Mural); crServerVBoxCompositionDisableEnter(&pDisplay->Mural); } void CrDpLeave(PCR_DISPLAY pDisplay) { pDisplay->Mural.fDataPresented = GL_TRUE; pDisplay->Mural.fOrPresentOnReenable = GL_TRUE; crServerVBoxCompositionDisableLeave(&pDisplay->Mural, pDisplay->fForcePresent); pDisplay->fForcePresent = GL_FALSE; } void CrDpRootUpdate(PCR_DISPLAY pDisplay) { crVBoxServerUpdateMuralRootVisibleRegion(&pDisplay->Mural); } typedef struct CR_DEM_ENTRY_INFO { CRTextureObj *pTobj; uint32_t cEntries; } CR_DEM_ENTRY_INFO; typedef struct CR_DEM_ENTRY { CR_DISPLAY_ENTRY Entry; CR_DEM_ENTRY_INFO *pInfo; CR_DISPLAY_ENTRY_MAP *pMap; RTLISTNODE Node; } CR_DEM_ENTRY; #define PCR_DEM_ENTRY_FROM_ENTRY(_pEntry) ((CR_DEM_ENTRY*)((uint8_t*)(_pEntry) - RT_OFFSETOF(CR_DEM_ENTRY, Entry))) static RTMEMCACHE g_VBoxCrDemLookasideList; static RTMEMCACHE g_VBoxCrDemInfoLookasideList; int CrDemGlobalInit() { int rc = RTMemCacheCreate(&g_VBoxCrDemLookasideList, sizeof (CR_DEM_ENTRY), 0, /* size_t cbAlignment */ UINT32_MAX, /* uint32_t cMaxObjects */ NULL, /* PFNMEMCACHECTOR pfnCtor*/ NULL, /* PFNMEMCACHEDTOR pfnDtor*/ NULL, /* void *pvUser*/ 0 /* uint32_t fFlags*/ ); if (RT_SUCCESS(rc)) { rc = RTMemCacheCreate(&g_VBoxCrDemInfoLookasideList, sizeof (CR_DEM_ENTRY_INFO), 0, /* size_t cbAlignment */ UINT32_MAX, /* uint32_t cMaxObjects */ NULL, /* PFNMEMCACHECTOR pfnCtor*/ NULL, /* PFNMEMCACHEDTOR pfnDtor*/ NULL, /* void *pvUser*/ 0 /* uint32_t fFlags*/ ); if (RT_SUCCESS(rc)) return VINF_SUCCESS; else crWarning("RTMemCacheCreate failed rc %d", rc); RTMemCacheDestroy(g_VBoxCrDemLookasideList); } else crWarning("RTMemCacheCreate failed rc %d", rc); return VINF_SUCCESS; } void CrDemTeGlobalTerm() { RTMemCacheDestroy(g_VBoxCrDemLookasideList); RTMemCacheDestroy(g_VBoxCrDemInfoLookasideList); } static CR_DEM_ENTRY* crDemEntryAlloc() { return (CR_DEM_ENTRY*)RTMemCacheAlloc(g_VBoxCrDemLookasideList); } static CR_DEM_ENTRY_INFO* crDemEntryInfoAlloc() { return (CR_DEM_ENTRY_INFO*)RTMemCacheAlloc(g_VBoxCrDemInfoLookasideList); } static void crDemEntryFree(CR_DEM_ENTRY* pDemEntry) { CrDpEntryCleanup(&pDemEntry->Entry); RTMemCacheFree(g_VBoxCrDemLookasideList, pDemEntry); } static void crDemEntryInfoFree(CR_DEM_ENTRY_INFO* pDemEntryInfo) { RTMemCacheFree(g_VBoxCrDemInfoLookasideList, pDemEntryInfo); } void crDemEntryRelease(PCR_DISPLAY_ENTRY_MAP pMap, CR_DEM_ENTRY *pDemEntry) { CR_DEM_ENTRY_INFO *pInfo = pDemEntry->pInfo; CRTextureObj *pTobj = pInfo->pTobj; --pInfo->cEntries; if (!pInfo->cEntries) { CR_STATE_SHAREDOBJ_USAGE_CLEAR(pInfo->pTobj, cr_server.MainContextInfo.pContext); crHashtableDelete(pMap->pTexIdToDemInfoMap, pTobj->id, NULL); crDemEntryInfoFree(pInfo); } if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pTobj)) { CRSharedState *pShared = crStateGlobalSharedAcquire(); CRASSERT(pShared); /* on the host side, we need to delete an ogl texture object here as well, which crStateDeleteTextureCallback will do * in addition to calling crStateDeleteTextureObject to delete a state object */ crHashtableDelete(pShared->textureTable, pTobj->id, crStateDeleteTextureCallback); crStateGlobalSharedRelease(); } crStateGlobalSharedRelease(); if (!pMap->cEntered) crDemEntryFree(pDemEntry); else RTListNodeInsertAfter(&pMap->ReleasedList, &pDemEntry->Node); } int CrDemInit(PCR_DISPLAY_ENTRY_MAP pMap) { pMap->pTexIdToDemInfoMap = crAllocHashtable(); if (pMap->pTexIdToDemInfoMap) { RTListInit(&pMap->ReleasedList); return VINF_SUCCESS; } crWarning("crAllocHashtable failed"); return VERR_NO_MEMORY; } void CrDemTerm(PCR_DISPLAY_ENTRY_MAP pMap) { CRASSERT(RTListIsEmpty(&pMap->ReleasedList)); CRASSERT(!pMap->cEntered); crFreeHashtable(pMap->pTexIdToDemInfoMap, NULL); pMap->pTexIdToDemInfoMap = NULL; } void CrDemEnter(PCR_DISPLAY_ENTRY_MAP pMap) { ++pMap->cEntered; Assert(pMap->cEntered); } void CrDemLeave(PCR_DISPLAY_ENTRY_MAP pMap, PCR_DISPLAY_ENTRY pNewEntry, PCR_DISPLAY_ENTRY pReplacedEntry) { Assert(pMap->cEntered); --pMap->cEntered; Assert(!pReplacedEntry || pNewEntry); if (pNewEntry && pReplacedEntry) { CR_DEM_ENTRY *pNewDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pNewEntry); CR_DEM_ENTRY *pReplacedDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pReplacedEntry); Assert(!RTListIsEmpty(&pMap->ReleasedList)); Assert(!RTListIsEmpty(&pReplacedDemEntry->Node)); Assert(RTListIsEmpty(&pNewDemEntry->Node)); Assert(!pNewDemEntry->Entry.pvORInstance); if (!pNewDemEntry->Entry.pvORInstance) { pNewDemEntry->Entry.pvORInstance = pReplacedDemEntry->Entry.pvORInstance; pReplacedDemEntry->Entry.pvORInstance = NULL; } RTListNodeRemove(&pReplacedDemEntry->Node); crDemEntryFree(pReplacedDemEntry); } if (!pMap->cEntered) { CR_DEM_ENTRY *pCurEntry, *pNextEntry; RTListForEachSafe(&pMap->ReleasedList, pCurEntry, pNextEntry, CR_DEM_ENTRY, Node) { RTListNodeRemove(&pCurEntry->Node); crDemEntryFree(pCurEntry); } } } void CrDemEntryRelease(PCR_DISPLAY_ENTRY pEntry) { CR_DEM_ENTRY *pDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pEntry); crDemEntryRelease(pDemEntry->pMap, pDemEntry); } int CrDemEntrySaveState(PCR_DISPLAY_ENTRY pEntry, PSSMHANDLE pSSM) { CR_DEM_ENTRY *pDemEntry = PCR_DEM_ENTRY_FROM_ENTRY(pEntry); int rc = SSMR3PutU32(pSSM, pDemEntry->pInfo->pTobj->id); AssertRCReturn(rc, rc); return rc; } int CrDemEntryLoadState(PCR_DISPLAY_ENTRY_MAP pMap, PCR_DISPLAY_ENTRY *ppEntry, PSSMHANDLE pSSM) { uint32_t u32; int rc = SSMR3GetU32(pSSM, &u32); AssertRCReturn(rc, rc); PCR_DISPLAY_ENTRY pEntry = CrDemEntryAcquire(pMap, u32, CRBLT_F_INVERT_SRC_YCOORDS); if (!pEntry) { crWarning("CrDemEntryAcquire failed"); return VERR_NO_MEMORY; } *ppEntry = pEntry; return VINF_SUCCESS; } PCR_DISPLAY_ENTRY CrDemEntryAcquire(PCR_DISPLAY_ENTRY_MAP pMap, GLuint idTexture, uint32_t fFlags) { CR_DEM_ENTRY *pDemEntry = NULL; CRSharedState *pShared = crStateGlobalSharedAcquire(); if (!pShared) { crWarning("pShared is null!"); return NULL; } CRTextureObj *pTobj = (CRTextureObj*)crHashtableSearch(pShared->textureTable, idTexture); if (!pTobj) { crWarning("pTobj is null!"); crStateGlobalSharedRelease(); return NULL; } Assert(pTobj->id == idTexture); GLuint hwId = crStateGetTextureObjHWID(pTobj); if (!hwId) { crWarning("hwId is null!"); crStateGlobalSharedRelease(); return NULL; } VBOXVR_TEXTURE TextureData; TextureData.width = pTobj->level[0]->width; TextureData.height = pTobj->level[0]->height; TextureData.target = pTobj->target; TextureData.hwid = hwId; pDemEntry = crDemEntryAlloc(); if (!pDemEntry) { crWarning("crDemEntryAlloc failed allocating CR_DEM_ENTRY"); crStateGlobalSharedRelease(); return NULL; } CrDpEntryInit(&pDemEntry->Entry, &TextureData, fFlags, crDpEntryCEntryReleaseCB); CR_DEM_ENTRY_INFO *pInfo = (CR_DEM_ENTRY_INFO*)crHashtableSearch(pMap->pTexIdToDemInfoMap, pTobj->id); if (!pInfo) { pInfo = crDemEntryInfoAlloc(); CRASSERT(pInfo); crHashtableAdd(pMap->pTexIdToDemInfoMap, pTobj->id, pInfo); pInfo->cEntries = 0; pInfo->pTobj = pTobj; } ++pInfo->cEntries; pDemEntry->pInfo = pInfo; pDemEntry->pMap = pMap; RTListInit(&pDemEntry->Node); /* just use main context info's context to hold the texture reference */ CR_STATE_SHAREDOBJ_USAGE_SET(pTobj, cr_server.MainContextInfo.pContext); return &pDemEntry->Entry; } PCR_DISPLAY crServerDisplayGetInitialized(uint32_t idScreen) { if (idScreen >= CR_MAX_GUEST_MONITORS) { crWarning("invalid idScreen %d", idScreen); return NULL; } if (ASMBitTest(cr_server.DisplaysInitMap, idScreen)) { Assert(cr_server.aDispplays[idScreen].Mural.screenId == idScreen); return &cr_server.aDispplays[idScreen]; } return NULL; } static PCR_DISPLAY crServerDisplayGet(uint32_t idScreen) { if (idScreen >= CR_MAX_GUEST_MONITORS) { crWarning("invalid idScreen %d", idScreen); return NULL; } if (ASMBitTest(cr_server.DisplaysInitMap, idScreen)) { Assert(cr_server.aDispplays[idScreen].Mural.screenId == idScreen); return &cr_server.aDispplays[idScreen]; } int rc = CrDpInit(&cr_server.aDispplays[idScreen]); if (RT_SUCCESS(rc)) { CrDpResize(&cr_server.aDispplays[idScreen], cr_server.screen[idScreen].x, cr_server.screen[idScreen].y, cr_server.screen[idScreen].w, cr_server.screen[idScreen].h); ASMBitSet(cr_server.DisplaysInitMap, idScreen); return &cr_server.aDispplays[idScreen]; } else { crWarning("CrDpInit failed for screen %d", idScreen); } return NULL; } int crServerDisplaySaveState(PSSMHANDLE pSSM) { int rc; int cDisplays = 0, i; for (i = 0; i < cr_server.screenCount; ++i) { if (ASMBitTest(cr_server.DisplaysInitMap, i) && !CrDpIsEmpty(&cr_server.aDispplays[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) { rc = SSMR3PutS32(pSSM, cr_server.screen[i].x); AssertRCReturn(rc, rc); rc = SSMR3PutS32(pSSM, cr_server.screen[i].y); AssertRCReturn(rc, rc); rc = SSMR3PutU32(pSSM, cr_server.screen[i].w); AssertRCReturn(rc, rc); rc = SSMR3PutU32(pSSM, cr_server.screen[i].h); AssertRCReturn(rc, rc); } for (i = 0; i < cr_server.screenCount; ++i) { if (ASMBitTest(cr_server.DisplaysInitMap, i) && !CrDpIsEmpty(&cr_server.aDispplays[i])) { rc = SSMR3PutS32(pSSM, i); AssertRCReturn(rc, rc); rc = CrDpSaveState(&cr_server.aDispplays[i], pSSM); AssertRCReturn(rc, rc); } } return VINF_SUCCESS; } int crServerDisplayLoadState(PSSMHANDLE pSSM, uint32_t u32Version) { 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); crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE); for (i = 0; i < cr_server.screenCount; ++i) { int32_t x, y; uint32_t w, h; rc = SSMR3GetS32(pSSM, &x); AssertRCReturn(rc, rc); rc = SSMR3GetS32(pSSM, &y); AssertRCReturn(rc, rc); rc = SSMR3GetU32(pSSM, &w); AssertRCReturn(rc, rc); rc = SSMR3GetU32(pSSM, &h); AssertRCReturn(rc, rc); rc = crVBoxServerMapScreen(i, x, y, w, h, cr_server.screen[i].winID); AssertRCReturn(rc, rc); } crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE); for (i = 0; i < cDisplays; ++i) { int iScreen; rc = SSMR3GetS32(pSSM, &iScreen); AssertRCReturn(rc, rc); PCR_DISPLAY pDisplay = crServerDisplayGet((uint32_t)iScreen); if (!pDisplay) { crWarning("crServerDisplayGet failed"); return VERR_GENERAL_FAILURE; } rc = CrDpLoadState(pDisplay, pSSM, u32Version); AssertRCReturn(rc, rc); } return VINF_SUCCESS; } void crServerDisplayTermAll() { int i; for (i = 0; i < cr_server.screenCount; ++i) { if (ASMBitTest(cr_server.DisplaysInitMap, i)) { CrDpTerm(&cr_server.aDispplays[i]); ASMBitClear(cr_server.DisplaysInitMap, i); } } } void CrHlpFreeTexImage(CRContext *pCurCtx, GLuint idPBO, void *pvData) { if (idPBO) { cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); if (pCurCtx) cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pCurCtx->bufferobject.packBuffer->hwid); else cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); } else { crFree(pvData); if (pCurCtx && crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_PACK_BUFFER_ARB)) cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pCurCtx->bufferobject.packBuffer->hwid); } } void CrHlpPutTexImage(CRContext *pCurCtx, const VBOXVR_TEXTURE *pTexture, GLenum enmFormat, void *pvData) { CRASSERT(pTexture->hwid); cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, pTexture->hwid); if (!pCurCtx || crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_UNPACK_BUFFER_ARB)) { cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); } /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/ cr_server.head_spu->dispatch_table.TexSubImage2D(GL_TEXTURE_2D, 0 /* level*/, 0 /*xoffset*/, 0 /*yoffset*/, pTexture->width, pTexture->height, enmFormat, GL_UNSIGNED_BYTE, pvData); /*restore gl state*/ if (pCurCtx) { CRTextureObj *pTObj; CRTextureLevel *pTImg; crStateGetTextureObjectAndImage(pCurCtx, pTexture->target, 0, &pTObj, &pTImg); GLuint uid = pTObj->hwid; cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, uid); } else { cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, 0); } if (pCurCtx && crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_UNPACK_BUFFER_ARB)) cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pCurCtx->bufferobject.unpackBuffer->hwid); } void* CrHlpGetTexImage(CRContext *pCurCtx, const VBOXVR_TEXTURE *pTexture, GLuint idPBO, GLenum enmFormat) { void *pvData = NULL; cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, pTexture->hwid); if (idPBO) { cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, idPBO); } else { if (!pCurCtx || crStateIsBufferBoundForCtx(pCurCtx, GL_PIXEL_PACK_BUFFER_ARB)) { cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); } pvData = crAlloc(4*pTexture->width*pTexture->height); if (!pvData) { crWarning("Out of memory in CrHlpGetTexImage"); return NULL; } } /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/ cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, enmFormat, GL_UNSIGNED_BYTE, pvData); /*restore gl state*/ if (pCurCtx) { CRTextureObj *pTObj; CRTextureLevel *pTImg; crStateGetTextureObjectAndImage(pCurCtx, pTexture->target, 0, &pTObj, &pTImg); GLuint uid = pTObj->hwid; cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, uid); } else { cr_server.head_spu->dispatch_table.BindTexture(pTexture->target, 0); } if (idPBO) { pvData = cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); if (!pvData) { crWarning("Failed to MapBuffer in CrHlpGetTexImage"); return NULL; } } CRASSERT(pvData); return pvData; } void SERVER_DISPATCH_APIENTRY crServerDispatchVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects) { uint32_t idScreen = CR_PRESENT_GET_SCREEN(cfg); if (idScreen >= CR_MAX_GUEST_MONITORS) { crWarning("Invalid guest screen"); return; } PCR_DISPLAY pDisplay; PCR_DISPLAY_ENTRY pEntry = NULL; if (texture) { pEntry = CrDemEntryAcquire(&cr_server.PresentTexturepMap, texture, (cfg & CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD) ? 0 : CRBLT_F_INVERT_SRC_YCOORDS); if (!pEntry) { crWarning("CrDemEntryAcquire Failed"); return; } pDisplay = crServerDisplayGet(idScreen); if (!pDisplay) { crWarning("crServerDisplayGet Failed"); CrDemEntryRelease(pEntry); return; } } else { pDisplay = crServerDisplayGetInitialized(idScreen); if (!pDisplay) { /* no display initialized, and nothing to present */ return; } } if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) { CR_SERVER_DUMP_TEXPRESENT(&pEntry->CEntry.Tex); } CrDpEnter(pDisplay); if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) { RTPOINT Point = {xPos, yPos}; int rc = CrDpEntryRegionsAdd(pDisplay, pEntry, &Point, (uint32_t)cRects, (const RTRECT*)pRects, &cr_server.PresentTexturepMap); if (!RT_SUCCESS(rc)) { crWarning("CrDpEntryRegionsAdd Failed rc %d", rc); /* no need to release anything, as CrDpEntryRegionsAdd would do everything for us as needed */ // if (pEntry) // CrDemEntryRelease(pEntry); } } else { if (pEntry) CrDemEntryRelease(pEntry); CrDpRegionsClear(pDisplay); } CrDpLeave(pDisplay); }