server_muralfbo.cpp revision 7ea49b4765b66fc68d2e6c1cb2a647b53a4aea24
/* $Id$ */
/** @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)]);
}