server_muralfbo.c revision 35eff0d985946a77d015272714a53e99f0d5ce8f
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * VBox crOpenGL: Window to FBO redirect support.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Copyright (C) 2010 Oracle Corporation
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * available from http://www.virtualbox.org. This file is free software;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * you can redistribute it and/or modify it under the terms of the GNU
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * General Public License (GPL) as published by the Free Software
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if ((x>=cr_server.screen[i].x && x<cr_server.screen[i].x+(int)cr_server.screen[i].w)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && (y>=cr_server.screen[i].y && y<cr_server.screen[i].y+(int)cr_server.screen[i].h))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncstatic GLboolean crServerMuralCoverScreen(CRMuralInfo *mural, int sId)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && mural->gX+(int)mural->width > cr_server.screen[sId].x+(int)cr_server.screen[sId].w
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && mural->gY+(int)mural->height > cr_server.screen[sId].y+(int)cr_server.screen[sId].h;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync/* Called when a new CRMuralInfo is created
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync * or when OutputRedirect status is changed.
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsyncvoid crServerSetupOutputRedirect(CRMuralInfo *mural)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Unset the previous redirect. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.outputRedirect.CROREnd(mural->pvOutputRedirectInstance);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Setup a new redirect. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /* Query supported formats. */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync int rc = cr_server.outputRedirect.CRORContextProperty(cr_server.outputRedirect.pvContext,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (RTStrStr(pachFormats, "H3DOR_FMT_RGBA_TOPDOWN"))
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.outputRedirect.CRORBegin(cr_server.outputRedirect.pvContext,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* If this is not NULL then there was a supported format. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync // @todo the code assumes that RTRECT == four of GLInts
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.outputRedirect.CRORVisibleRegion(mural->pvOutputRedirectInstance,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync mural->cVisibleRects, (RTRECT *)mural->pVisibleRects);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (cr_server.screenCount<2 && !cr_server.bForceOffscreenRendering)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync tlS = crServerGetPointScreen(mural->gX, mural->gY);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync brS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY+mural->height-1);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync trS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync blS = crServerGetPointScreen(mural->gX, mural->gY+mural->height-1);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync renderspuSetWindowId(cr_server.screen[primaryS].winID);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync mural->hX = mural->gX-cr_server.screen[primaryS].x;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync mural->hY = mural->gY-cr_server.screen[primaryS].y;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (overlappingScreenCount<2 && !cr_server.bForceOffscreenRendering)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX, mural->hY);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance,
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync fSupported = ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object")
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object"))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two");
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsyncvoid crServerRedirMuralFBO(CRMuralInfo *mural, GLboolean redir)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync crWarning("FBO not supported, can't redirect window output");
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, GL_FALSE);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (!crStateGetCurrent()->framebufferobject.drawFB)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, mural->idFBO);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (!crStateGetCurrent()->framebufferobject.readFB)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, mural->idFBO);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, mural->bVisible);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (mural->bUseFBO && crServerSupportRedirMuralFBO())
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (!crStateGetCurrent()->framebufferobject.drawFB)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (!crStateGetCurrent()->framebufferobject.readFB)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync crStateGetCurrent()->buffer.height = mural->height;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*Color texture*/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
2ca0ef39e90f953a6517aa2a658146c70485425dvboxsync gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*Depth&Stencil*/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->GenRenderbuffersEXT(1, &mural->idDepthStencilRB);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->idFBO);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync crWarning("FBO status(0x%x) isn't complete", status);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mural->idPBO);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, mural->width*mural->height*4, 0, GL_STREAM_READ_ARB);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*Restore gl state*/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync uid = ctx->framebufferobject.readFB ? ctx->framebufferobject.readFB->hwid:0;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->idColorTex);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->idFBO);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.DeleteBuffersARB(1, &mural->idPBO);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define MIN(a, b) ((a) < (b) ? (a) : (b))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync#define MAX(a, b) ((a) > (b) ? (a) : (b))
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsyncstatic GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncstatic GLboolean crServerIntersectScreen(CRMuralInfo *mural, int sId, CRrecti *rect)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync rect->x1 = MAX(mural->gX, cr_server.screen[sId].x);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rect->x2 = MIN(mural->gX+(int)mural->fboWidth, cr_server.screen[sId].x+(int)cr_server.screen[sId].w);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rect->y1 = MAX(mural->gY, cr_server.screen[sId].y);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync rect->y2 = MIN(mural->gY+(int)mural->fboHeight, cr_server.screen[sId].y+(int)cr_server.screen[sId].h);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsyncstatic void crServerCopySubImage(char *pDst, char* pSrc, CRrecti *pRect, int srcWidth, int srcHeight)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync pSrc += 4*pRect->x1 + srcrowsize*(srcHeight-1-pRect->y1);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync for (i=0; i<height; ++i)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsyncstatic void crServerTransformRect(CRrecti *pDst, CRrecti *pSrc, int dx, int dy)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync crWarning("Mural doesn't have PBO even though bUsePBOForReadback is set!");
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync bUsePBO = cr_server.bUsePBOForReadback && mural->idPBO;
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, mural->idColorTex);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mural->idPBO);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pixels = crAlloc(4*mural->fboWidth*mural->fboHeight);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync /*restore gl state*/
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid;
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, uid);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync pixels = cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync crWarning("Failed to MapBuffer in crServerPresentFBO");
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* rect in window relative coords */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync crServerTransformRect(&rectwr, &rect, -mural->gX, -mural->gY);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*we don't get any rects info for guest compiz windows, so we treat windows as visible unless explicitly received 0 visible rects*/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync tmppixels = crAlloc(4*(rect.x2-rect.x1)*(rect.y2-rect.y1));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync crServerCopySubImage(tmppixels, pixels, &rectwr, mural->fboWidth, mural->fboHeight);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*Note: pfnPresentFBO would free tmppixels*/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.pfnPresentFBO(tmppixels, i, rect.x1-cr_server.screen[i].x, rect.y1-cr_server.screen[i].y, rect.x2-rect.x1, rect.y2-rect.y1);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (crServerIntersectRect(&rectwr, (CRrecti*) &mural->pVisibleRects[4*j], §r))
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync tmppixels = crAlloc(4*(sectr.x2-sectr.x1)*(sectr.y2-sectr.y1));
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync crServerCopySubImage(tmppixels, pixels, §r, mural->fboWidth, mural->fboHeight);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /*Note: pfnPresentFBO would free tmppixels*/
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* @todo find out why presentfbo is not called but crorframe is called. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.outputRedirect.CRORFrame(mural->pvOutputRedirectInstance,
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))