summaryrefslogtreecommitdiff
path: root/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp840
1 files changed, 840 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp
new file mode 100644
index 00000000..10cdf5cf
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp
@@ -0,0 +1,840 @@
+/* $Id: server_muralfbo.cpp $ */
+
+/** @file
+ * VBox crOpenGL: Window to FBO redirect support.
+ */
+
+/*
+ * Copyright (C) 2010-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 "server.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_vreg.h"
+#include "render/renderspu.h"
+
+static void crServerRedirMuralFbSync(CRMuralInfo *mural);
+
+void crServerCheckMuralGeometry(CRMuralInfo *mural)
+{
+ if (!mural->CreateInfo.externalID)
+ return;
+
+ CRASSERT(mural->spuWindow);
+ CRASSERT(mural->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID);
+
+ if (!mural->width || !mural->height
+ || mural->fboWidth != mural->width
+ || mural->fboHeight != mural->height)
+ {
+ crServerRedirMuralFbClear(mural);
+ crServerRedirMuralFBO(mural, false);
+ crServerDeleteMuralFBO(mural);
+ }
+
+ if (!mural->width || !mural->height)
+ return;
+
+ crServerRedirMuralFBO(mural, true);
+ crServerRedirMuralFbSync(mural);
+}
+
+static void crServerCheckMuralGeometryCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+
+ if (!pMI->fRedirected || pMI == data2)
+ return;
+
+ crServerCheckMuralGeometry(pMI);
+}
+
+
+void crServerCheckAllMuralGeometry(CRMuralInfo *pMI)
+{
+ CR_FBMAP Map;
+ int rc = CrPMgrHlpGlblUpdateBegin(&Map);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrPMgrHlpGlblUpdateBegin failed %d", rc));
+ return;
+ }
+
+ crHashtableWalk(cr_server.muralTable, crServerCheckMuralGeometryCB, pMI);
+
+ if (pMI)
+ crServerCheckMuralGeometry(pMI);
+
+ CrPMgrHlpGlblUpdateEnd(&Map);
+}
+
+GLboolean crServerSupportRedirMuralFBO(void)
+{
+ static GLboolean fInited = GL_FALSE;
+ static GLboolean fSupported = GL_FALSE;
+ if (!fInited)
+ {
+ const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS);
+
+ fSupported = ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object")
+ || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object"))
+ && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two");
+ fInited = GL_TRUE;
+ }
+ return fSupported;
+}
+
+static void crServerCreateMuralFBO(CRMuralInfo *mural);
+
+void crServerRedirMuralFbClear(CRMuralInfo *mural)
+{
+ uint32_t i;
+ for (i = 0; i < mural->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = mural->apUsedFBDatas[i];
+ int rc = CrFbUpdateBegin(pData->hFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false);
+ CrFbUpdateEnd(pData->hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ }
+ mural->cUsedFBDatas = 0;
+
+ for (i = 0; i < cr_server.screenCount; ++i)
+ {
+ GLuint j;
+ CR_FBDATA *pData = &mural->aFBDatas[i];
+ if (!pData->hFb)
+ continue;
+
+ CrFbEntryRelease(pData->hFb, pData->hFbEntry);
+ pData->hFbEntry = NULL;
+
+ for (j = 0; j < mural->cBuffers; ++j)
+ {
+ CrTdRelease(pData->apTexDatas[j]);
+ pData->apTexDatas[j] = NULL;
+ }
+
+ pData->hFb = NULL;
+ }
+}
+
+static int crServerRedirMuralDbSyncFb(CRMuralInfo *mural, HCR_FRAMEBUFFER hFb, CR_FBDATA **ppData)
+{
+ CR_FBDATA *pData;
+ const struct VBVAINFOSCREEN* pScreenInfo = CrFbGetScreenInfo(hFb);
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb);
+ RTRECT FbRect = *CrVrScrCompositorRectGet(pCompositor);
+ RTRECT DefaultRegionsRect;
+ const RTRECT * pRegions;
+ uint32_t cRegions;
+ RTPOINT Pos;
+ RTRECT MuralRect;
+ int rc;
+
+ CRASSERT(mural->fRedirected);
+
+ *ppData = NULL;
+
+ if (!mural->bVisible)
+ return VINF_SUCCESS;
+
+ MuralRect.xLeft = mural->gX;
+ MuralRect.yTop = mural->gY;
+ MuralRect.xRight = MuralRect.xLeft + mural->width;
+ MuralRect.yBottom = MuralRect.yTop + mural->height;
+
+ Pos.x = mural->gX - pScreenInfo->i32OriginX;
+ Pos.y = mural->gY - pScreenInfo->i32OriginY;
+
+ VBoxRectTranslate(&FbRect, pScreenInfo->i32OriginX, pScreenInfo->i32OriginY);
+
+ VBoxRectIntersect(&FbRect, &MuralRect);
+
+ if (VBoxRectIsZero(&FbRect))
+ return VINF_SUCCESS;
+
+ if (mural->bReceivedRects)
+ {
+ pRegions = (const RTRECT*)mural->pVisibleRects;
+ cRegions = mural->cVisibleRects;
+ }
+ else
+ {
+ DefaultRegionsRect.xLeft = 0;
+ DefaultRegionsRect.yTop = 0;
+ DefaultRegionsRect.xRight = mural->width;
+ DefaultRegionsRect.yBottom = mural->height;
+ pRegions = &DefaultRegionsRect;
+ cRegions = 1;
+ }
+
+ if (!cRegions)
+ return VINF_SUCCESS;
+
+ pData = &mural->aFBDatas[pScreenInfo->u32ViewIndex];
+
+ if (!pData->hFb)
+ {
+ pData->hFb = hFb;
+
+ for (uint32_t i = 0; i < mural->cBuffers; ++i)
+ {
+ VBOXVR_TEXTURE Tex;
+ Tex.width = mural->width;
+ Tex.height = mural->height;
+ Tex.hwid = mural->aidColorTexs[i];
+ Tex.target = GL_TEXTURE_2D;
+
+ pData->apTexDatas[i] = CrFbTexDataCreate(&Tex);
+ }
+
+ rc = CrFbEntryCreateForTexData(hFb, pData->apTexDatas[CR_SERVER_FBO_FB_IDX(mural)], 0, &pData->hFbEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryCreateForTexData failed rc %d", rc));
+ }
+ }
+ else
+ {
+ CRASSERT(pData->hFb == hFb);
+ }
+
+ rc = CrFbUpdateBegin(hFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ return rc;
+ }
+
+ rc = CrFbEntryRegionsSet(hFb, pData->hFbEntry, &Pos, cRegions, pRegions, true);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryRegionsSet failed rc %d", rc));
+ }
+
+ CrFbUpdateEnd(hFb);
+
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry = CrFbEntryGetCompositorEntry(pData->hFbEntry);
+ if (CrVrScrCompositorEntryIsUsed(pCEntry))
+ *ppData = pData;
+
+ return rc;
+}
+
+static void crServerRedirMuralFbSync(CRMuralInfo *mural)
+{
+ uint32_t i;
+ uint32_t cUsedFBs = 0;
+ HCR_FRAMEBUFFER ahUsedFbs[CR_MAX_GUEST_MONITORS];
+ HCR_FRAMEBUFFER hFb;
+
+ for (i = 0; i < mural->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = mural->apUsedFBDatas[i];
+ int rc = CrFbUpdateBegin(pData->hFb);
+ if (RT_SUCCESS(rc))
+ {
+ ahUsedFbs[cUsedFBs] = pData->hFb;
+ CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false);
+ ++cUsedFBs;
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ }
+ mural->cUsedFBDatas = 0;
+
+ if (!mural->width
+ || !mural->height
+ || !mural->bVisible
+ )
+ goto end;
+
+ CRASSERT(mural->fRedirected);
+
+ for (hFb = CrPMgrFbGetFirstEnabled();
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ CR_FBDATA *pData = NULL;
+ int rc = crServerRedirMuralDbSyncFb(mural, hFb, &pData);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crServerRedirMuralDbSyncFb failed %d", rc));
+ continue;
+ }
+
+ if (!pData)
+ continue;
+
+ mural->apUsedFBDatas[mural->cUsedFBDatas] = pData;
+ ++mural->cUsedFBDatas;
+ }
+
+end:
+
+ for (i = 0; i < cUsedFBs; ++i)
+ {
+ CrFbUpdateEnd(ahUsedFbs[i]);
+ }
+}
+
+static void crVBoxServerMuralFbCleanCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+ HCR_FRAMEBUFFER hFb = (HCR_FRAMEBUFFER)data2;
+ uint32_t i;
+ for (i = 0; i < pMI->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = pMI->apUsedFBDatas[i];
+ if (hFb != pData->hFb)
+ continue;
+
+ CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false);
+ break;
+ }
+}
+
+static void crVBoxServerMuralFbSetCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+ HCR_FRAMEBUFFER hFb = (HCR_FRAMEBUFFER)data2;
+ uint32_t i;
+ CR_FBDATA *pData = NULL;
+ bool fFbWasUsed = false;
+
+ Assert(hFb);
+
+ if (!pMI->fRedirected)
+ {
+ Assert(!pMI->cUsedFBDatas);
+ return;
+ }
+
+ for (i = 0; i < pMI->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = pMI->apUsedFBDatas[i];
+ if (hFb != pData->hFb)
+ continue;
+
+ fFbWasUsed = true;
+ break;
+ }
+
+ if (CrFbIsEnabled(hFb))
+ {
+ int rc = crServerRedirMuralDbSyncFb(pMI, hFb, &pData);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crServerRedirMuralDbSyncFb failed %d", rc));
+ pData = NULL;
+ }
+ }
+
+ if (pData)
+ {
+ if (!fFbWasUsed)
+ {
+ uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ for (i = 0; i < pMI->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = pMI->apUsedFBDatas[i];
+ uint32_t idCurScreen = CrFbGetScreenInfo(pData->hFb)->u32ViewIndex;
+ if (idCurScreen > idScreen)
+ break;
+
+ Assert(idCurScreen != idScreen);
+ }
+
+ for (int j = pMI->cUsedFBDatas; j > i; --j)
+ {
+ pMI->apUsedFBDatas[j] = pMI->apUsedFBDatas[j-1];
+ }
+
+ pMI->apUsedFBDatas[i] = pData;
+ ++pMI->cUsedFBDatas;
+ }
+ /* else - nothing to do */
+ }
+ else
+ {
+ if (fFbWasUsed)
+ {
+ for (int j = i; j < pMI->cUsedFBDatas - 1; ++j)
+ {
+ pMI->apUsedFBDatas[j] = pMI->apUsedFBDatas[j+1];
+ }
+ --pMI->cUsedFBDatas;
+ }
+ /* else - nothing to do */
+ }
+}
+
+void crVBoxServerMuralFbResizeEnd(HCR_FRAMEBUFFER hFb)
+{
+ crHashtableWalk(cr_server.muralTable, crVBoxServerMuralFbSetCB, hFb);
+}
+
+void crVBoxServerMuralFbResizeBegin(HCR_FRAMEBUFFER hFb)
+{
+ crHashtableWalk(cr_server.muralTable, crVBoxServerMuralFbCleanCB, hFb);
+}
+
+
+static int crVBoxServerResizeScreen(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM)
+{
+ int rc;
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pScreen->u32ViewIndex);
+ if (!hFb)
+ {
+ WARN(("CrPMgrFbGet failed"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ 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);
+
+ CrPMgrNotifyResize(hFb);
+
+ return rc;
+}
+
+DECLEXPORT(int) crVBoxServerNotifyResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM)
+{
+ int rc = crVBoxServerResizeScreen(pScreen, pvVRAM);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+void crServerRedirMuralFBO(CRMuralInfo *mural, bool fEnabled)
+{
+ if (!mural->fRedirected == !fEnabled)
+ {
+ return;
+ }
+
+ if (!mural->CreateInfo.externalID)
+ {
+ WARN(("trying to change redir setting for internal mural %d", mural->spuWindow));
+ return;
+ }
+
+ if (fEnabled)
+ {
+ if (!crServerSupportRedirMuralFBO())
+ {
+ WARN(("FBO not supported, can't redirect window output"));
+ return;
+ }
+
+ if (mural->aidFBOs[0]==0)
+ {
+ crServerCreateMuralFBO(mural);
+ }
+
+ if (cr_server.curClient && cr_server.curClient->currentMural == mural)
+ {
+ if (!crStateGetCurrent()->framebufferobject.drawFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
+ }
+ if (!crStateGetCurrent()->framebufferobject.readFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
+ }
+
+ crStateGetCurrent()->buffer.width = 0;
+ crStateGetCurrent()->buffer.height = 0;
+ }
+ }
+ else
+ {
+ if (cr_server.curClient && cr_server.curClient->currentMural == mural)
+ {
+ if (!crStateGetCurrent()->framebufferobject.drawFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
+ }
+ if (!crStateGetCurrent()->framebufferobject.readFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
+ }
+
+ crStateGetCurrent()->buffer.width = mural->width;
+ crStateGetCurrent()->buffer.height = mural->height;
+ }
+ }
+
+ mural->fRedirected = !!fEnabled;
+}
+
+static void crServerCreateMuralFBO(CRMuralInfo *mural)
+{
+ CRContext *ctx = crStateGetCurrent();
+ GLuint uid, i;
+ GLenum status;
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+ CRContextInfo *pMuralContextInfo;
+
+ CRASSERT(mural->aidFBOs[0]==0);
+ CRASSERT(mural->aidFBOs[1]==0);
+
+ pMuralContextInfo = cr_server.currentCtxInfo;
+ if (!pMuralContextInfo)
+ {
+ /* happens on saved state load */
+ CRASSERT(cr_server.MainContextInfo.SpuContext);
+ pMuralContextInfo = &cr_server.MainContextInfo;
+ cr_server.head_spu->dispatch_table.MakeCurrent(mural->spuWindow, 0, cr_server.MainContextInfo.SpuContext);
+ }
+
+ if (pMuralContextInfo->CreateInfo.realVisualBits != mural->CreateInfo.realVisualBits)
+ {
+ WARN(("mural visual bits do not match with current context visual bits!"));
+ }
+
+ mural->cBuffers = 2;
+ mural->iBbBuffer = 0;
+ /*Color texture*/
+
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ {
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ }
+
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ gl->GenTextures(1, &mural->aidColorTexs[i]);
+ gl->BindTexture(GL_TEXTURE_2D, mural->aidColorTexs[i]);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height,
+ 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ }
+
+ /*Depth&Stencil*/
+ gl->GenRenderbuffersEXT(1, &mural->idDepthStencilRB);
+ gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
+ gl->RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
+ mural->width, mural->height);
+
+ /*FBO*/
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ gl->GenFramebuffersEXT(1, &mural->aidFBOs[i]);
+ gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->aidFBOs[i]);
+
+ gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, mural->aidColorTexs[i], 0);
+ gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
+ gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
+
+ status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (status!=GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ WARN(("FBO status(0x%x) isn't complete", status));
+ }
+ }
+
+ mural->iCurDrawBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
+ mural->iCurReadBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
+
+ mural->fboWidth = mural->width;
+ mural->fboHeight = mural->height;
+
+ mural->iCurDrawBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
+ mural->iCurReadBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
+
+ /*Restore gl state*/
+ uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid;
+ gl->BindTexture(GL_TEXTURE_2D, uid);
+
+ uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0;
+ gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, uid);
+
+ uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0;
+ gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, uid);
+
+ uid = ctx->framebufferobject.readFB ? ctx->framebufferobject.readFB->hwid:0;
+ gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER, uid);
+
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ {
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid);
+ }
+
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
+ }
+ else
+ {
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ }
+
+ CRASSERT(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
+}
+
+void crServerDeleteMuralFBO(CRMuralInfo *mural)
+{
+ if (mural->aidFBOs[0]!=0)
+ {
+ GLuint i;
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->aidColorTexs[i]);
+ mural->aidColorTexs[i] = 0;
+ }
+
+ cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB);
+ mural->idDepthStencilRB = 0;
+
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->aidFBOs[i]);
+ mural->aidFBOs[i] = 0;
+ }
+ }
+
+ mural->cBuffers = 0;
+}
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+static GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect)
+{
+ CRASSERT(a && b && rect);
+
+ rect->x1 = MAX(a->x1, b->x1);
+ rect->x2 = MIN(a->x2, b->x2);
+ rect->y1 = MAX(a->y1, b->y1);
+ rect->y2 = MIN(a->y2, b->y2);
+
+ return (rect->x2>rect->x1) && (rect->y2>rect->y1);
+}
+
+DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable)
+{
+}
+
+DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot)
+{
+ if (pScreenshot->fDataAllocated)
+ {
+ RTMemFree(pScreenshot->Img.pvData);
+ pScreenshot->fDataAllocated = 0;
+ }
+}
+
+DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, uint32_t width, uint32_t height, uint32_t pitch, void *pvBuffer, CR_SCREENSHOT *pScreenshot)
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32Screen);
+ if (!hFb)
+ return VERR_INVALID_STATE;
+
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+
+ if (!width)
+ width = pScreen->u32Width;
+ if (!height)
+ height = pScreen->u32Height;
+ if (!pitch)
+ pitch = pScreen->u32LineSize;
+
+ if (CrFbHas3DData(hFb)
+ || pScreen->u32Width != width
+ || pScreen->u32Height != height
+ || pScreen->u32LineSize != pitch
+ || pScreen->u16BitsPerPixel != 32)
+ {
+ RTRECT SrcRect;
+ RTRECT DstRect;
+
+ pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+ if (!pvBuffer)
+ {
+ pScreenshot->Img.pvData = RTMemAlloc(pScreenshot->Img.cbData);
+ if (!pScreenshot->Img.pvData)
+ {
+ WARN(("RTMemAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+ pScreenshot->fDataAllocated = 1;
+ }
+ else
+ {
+ pScreenshot->Img.pvData = pvBuffer;
+ pScreenshot->fDataAllocated = 0;
+ }
+
+ pScreenshot->Img.enmFormat = GL_BGRA;
+ pScreenshot->Img.width = width;
+ pScreenshot->Img.height = height;
+ pScreenshot->Img.bpp = 32;
+ pScreenshot->Img.pitch = pitch;
+ SrcRect.xLeft = 0;
+ SrcRect.yTop = 0;
+ SrcRect.xRight = pScreen->u32Width;
+ SrcRect.yBottom = pScreen->u32Height;
+ DstRect.xLeft = 0;
+ DstRect.yTop = 0;
+ DstRect.xRight = width;
+ DstRect.yBottom = height;
+ int rc = CrFbBltGetContents(hFb, &SrcRect, &DstRect, 1, &DstRect, &pScreenshot->Img);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbBltGetContents failed %d", rc));
+ crServerVBoxScreenshotRelease(pScreenshot);
+ return rc;
+ }
+ }
+ else
+ {
+ pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+ if (!pvBuffer)
+ pScreenshot->Img.pvData = CrFbGetVRAM(hFb);
+ else
+ {
+ pScreenshot->Img.pvData = pvBuffer;
+ memcpy(pvBuffer, CrFbGetVRAM(hFb), pScreenshot->Img.cbData);
+ }
+ pScreenshot->Img.enmFormat = GL_BGRA;
+ pScreenshot->Img.width = pScreen->u32Width;
+ pScreenshot->Img.height = pScreen->u32Height;
+ pScreenshot->Img.bpp = pScreen->u16BitsPerPixel;
+ pScreenshot->Img.pitch = pScreen->u32LineSize;
+
+ pScreenshot->fDataAllocated = 0;
+ }
+
+ pScreenshot->u32Screen = u32Screen;
+
+ return VINF_SUCCESS;
+}
+
+extern DECLEXPORT(int) crServerVBoxWindowsShow(bool fShow)
+{
+ return CrPMgrModeWinVisible(fShow);
+}
+
+void crServerPresentFBO(CRMuralInfo *mural)
+{
+ uint32_t i;
+ for (i = 0; i < mural->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = mural->apUsedFBDatas[i];
+ int rc = CrFbUpdateBegin(pData->hFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbEntryTexDataUpdate(pData->hFb, pData->hFbEntry, pData->apTexDatas[CR_SERVER_FBO_FB_IDX(mural)]);
+ CrFbUpdateEnd(pData->hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ }
+}
+
+GLboolean crServerIsRedirectedToFBO()
+{
+#ifdef DEBUG_misha
+ Assert(cr_server.curClient);
+ if (cr_server.curClient)
+ {
+ Assert(cr_server.curClient->currentMural == cr_server.currentMural);
+ Assert(cr_server.curClient->currentCtxInfo == cr_server.currentCtxInfo);
+ }
+#endif
+ return cr_server.curClient
+ && cr_server.curClient->currentMural
+ && cr_server.curClient->currentMural->fRedirected;
+}
+
+GLint crServerMuralFBOIdxFromBufferName(CRMuralInfo *mural, GLenum buffer)
+{
+ switch (buffer)
+ {
+ case GL_FRONT:
+ case GL_FRONT_LEFT:
+ case GL_FRONT_RIGHT:
+ return CR_SERVER_FBO_FB_IDX(mural);
+ case GL_BACK:
+ case GL_BACK_LEFT:
+ case GL_BACK_RIGHT:
+ return CR_SERVER_FBO_BB_IDX(mural);
+ case GL_NONE:
+ case GL_AUX0:
+ case GL_AUX1:
+ case GL_AUX2:
+ case GL_AUX3:
+ case GL_LEFT:
+ case GL_RIGHT:
+ case GL_FRONT_AND_BACK:
+ return -1;
+ default:
+ WARN(("crServerMuralFBOIdxFromBufferName: invalid buffer passed 0x%x", buffer));
+ return -2;
+ }
+}
+
+void crServerMuralFBOSwapBuffers(CRMuralInfo *mural)
+{
+ CRContext *ctx = crStateGetCurrent();
+ GLuint iOldCurDrawBuffer = mural->iCurDrawBuffer;
+ GLuint iOldCurReadBuffer = mural->iCurReadBuffer;
+ mural->iBbBuffer = ((mural->iBbBuffer + 1) % (mural->cBuffers));
+ if (mural->iCurDrawBuffer >= 0)
+ mural->iCurDrawBuffer = ((mural->iCurDrawBuffer + 1) % (mural->cBuffers));
+ if (mural->iCurReadBuffer >= 0)
+ mural->iCurReadBuffer = ((mural->iCurReadBuffer + 1) % (mural->cBuffers));
+ Assert(iOldCurDrawBuffer != mural->iCurDrawBuffer || mural->cBuffers == 1 || mural->iCurDrawBuffer < 0);
+ Assert(iOldCurReadBuffer != mural->iCurReadBuffer || mural->cBuffers == 1 || mural->iCurReadBuffer < 0);
+ if (!ctx->framebufferobject.drawFB && iOldCurDrawBuffer != mural->iCurDrawBuffer)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
+ }
+ if (!ctx->framebufferobject.readFB && iOldCurReadBuffer != mural->iCurReadBuffer)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
+ }
+ Assert(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
+}
+