Kaydet (Commit) 01bed808 authored tarafından Louis-Francis Ratté-Boulianne's avatar Louis-Francis Ratté-Boulianne Kaydeden (comit) Markus Mohrhard

vcl: Re-use a framebuffer of the same size when possible

Conflicts:
	include/vcl/opengl/OpenGLContext.hxx

Change-Id: Id9c7932976ce9d9282776c20d93d9cca4d290056
üst 4c424d78
......@@ -208,18 +208,21 @@ public:
// use these methods right after setting a context to make sure drawing happens
// in the right FBO (default one is for onscreen painting)
bool BindFramebuffer( OpenGLFramebuffer* pFramebuffer );
bool AcquireDefaultFramebuffer();
bool AcquireFramebuffer( OpenGLFramebuffer* pFramebuffer );
OpenGLFramebuffer* AcquireFramebuffer( const OpenGLTexture& rTexture );
void ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer );
void AddRef();
void DeRef();
void ReleaseFramebuffer( const OpenGLTexture& rTexture );
void ReleaseFramebuffers();
// retrieve a program from the cache or compile/link it
OpenGLProgram* GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
OpenGLProgram* UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader );
bool isCurrent();
void clearCurrent();
void makeCurrent();
void resetCurrent();
void swapBuffers();
......
......@@ -20,12 +20,16 @@ class VCL_PLUGIN_PUBLIC OpenGLFramebuffer
private:
GLuint mnId;
OpenGLTexture maAttachedTexture;
int mnWidth;
int mnHeight;
public:
OpenGLFramebuffer();
virtual ~OpenGLFramebuffer();
GLuint Id() const { return mnId; };
int GetWidth() const { return mnWidth; };
int GetHeight() const { return mnHeight; };
void Bind();
void Unbind();
......
......@@ -15,6 +15,8 @@
OpenGLFramebuffer::OpenGLFramebuffer() :
mnId( 0 ),
mnWidth( 0 ),
mnHeight( 0 ),
mpPrevFramebuffer( NULL ),
mpNextFramebuffer( NULL )
{
......@@ -55,6 +57,8 @@ void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture )
{
SAL_INFO( "vcl.opengl", "Attaching texture " << rTexture.Id() << " to framebuffer " << (int)mnId );
maAttachedTexture = rTexture;
mnWidth = rTexture.GetWidth();
mnHeight = rTexture.GetHeight();
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
maAttachedTexture.Id(), 0 );
CHECK_GL_ERROR();
......
......@@ -120,6 +120,8 @@ void OpenGLSalGraphicsImpl::Init()
maOffscreenTex.GetWidth() != GetWidth() ||
maOffscreenTex.GetHeight() != GetHeight() )
{
if( mpContext ) // valid context
mpContext->ReleaseFramebuffer( maOffscreenTex );
maOffscreenTex = OpenGLTexture();
}
}
......@@ -161,15 +163,18 @@ void OpenGLSalGraphicsImpl::PostDraw()
mpProgram = NULL;
}
mpContext->ReleaseFramebuffer( mpFramebuffer );
mpFramebuffer = NULL;
CHECK_GL_ERROR();
}
void OpenGLSalGraphicsImpl::freeResources()
{
// TODO Delete shaders, programs and textures if not shared
if( mbOffscreen && mpContext && mpContext->isInitialized() )
{
mpContext->makeCurrent();
mpContext->ReleaseFramebuffer( maOffscreenTex );
}
ReleaseContext();
}
void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask )
......@@ -1429,6 +1434,7 @@ void OpenGLSalGraphicsImpl::endPaint()
if( mpContext->mnPainting == 0 && !mbOffscreen )
{
mpContext->makeCurrent();
mpContext->AcquireDefaultFramebuffer();
glFlush();
}
}
......
......@@ -35,6 +35,8 @@
using namespace com::sun::star;
#define MAX_FRAMEBUFFER_COUNT 30
// TODO use rtl::Static instead of 'static'
#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID
static std::vector<GLXContext> g_vShareList;
......@@ -57,6 +59,7 @@ OpenGLContext::OpenGLContext():
mbRequestLegacyContext(false),
mbUseDoubleBufferedRendering(true),
mbRequestVirtualDevice(false),
mnFramebufferCount(0),
mpCurrentFramebuffer(NULL),
mpFirstFramebuffer(NULL),
mpLastFramebuffer(NULL),
......@@ -1281,6 +1284,18 @@ bool OpenGLContext::isCurrent()
glXGetCurrentDrawable() == nDrawable);
#endif
}
void OpenGLContext::clearCurrent()
{
ImplSVData* pSVData = ImplGetSVData();
// release all framebuffers from the old context so we can re-attach the
// texture in the new context
OpenGLContext* pCurrentCtx = pSVData->maGDIData.mpLastContext;
if( pCurrentCtx && pCurrentCtx->isCurrent() )
pCurrentCtx->ReleaseFramebuffers();
}
void OpenGLContext::makeCurrent()
{
ImplSVData* pSVData = ImplGetSVData();
......@@ -1288,6 +1303,8 @@ void OpenGLContext::makeCurrent()
if (isCurrent())
return;
clearCurrent();
#if defined( WNT )
if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
{
......@@ -1328,6 +1345,8 @@ void OpenGLContext::makeCurrent()
void OpenGLContext::resetCurrent()
{
clearCurrent();
#if defined( WNT )
wglMakeCurrent( m_aGLWin.hDC, 0 );
#elif defined( MACOSX )
......@@ -1395,14 +1414,10 @@ NSOpenGLView* OpenGLContext::getOpenGLView()
}
#endif
bool OpenGLContext::AcquireFramebuffer( OpenGLFramebuffer* pFramebuffer )
bool OpenGLContext::BindFramebuffer( OpenGLFramebuffer* pFramebuffer )
{
if( pFramebuffer != mpCurrentFramebuffer )
{
// release the attached texture so it's available from the other contexts
//if( mpCurrentFramebuffer )
// mpCurrentFramebuffer->DetachTexture();
if( pFramebuffer )
pFramebuffer->Bind();
else
......@@ -1415,13 +1430,14 @@ bool OpenGLContext::AcquireFramebuffer( OpenGLFramebuffer* pFramebuffer )
bool OpenGLContext::AcquireDefaultFramebuffer()
{
return AcquireFramebuffer( NULL );
return BindFramebuffer( NULL );
}
OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rTexture )
{
OpenGLFramebuffer* pFramebuffer = NULL;
OpenGLFramebuffer* pFreeFramebuffer = NULL;
OpenGLFramebuffer* pFreeFbo = NULL;
OpenGLFramebuffer* pSameSizeFbo = NULL;
// check if there is already a framebuffer attached to that texture
pFramebuffer = mpLastFramebuffer;
......@@ -1429,18 +1445,27 @@ OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rText
{
if( pFramebuffer->IsAttached( rTexture ) )
break;
if( !pFreeFramebuffer && pFramebuffer->IsFree() )
pFreeFramebuffer = pFramebuffer;
if( !pFreeFbo && pFramebuffer->IsFree() )
pFreeFbo = pFramebuffer;
if( !pSameSizeFbo &&
pFramebuffer->GetWidth() == rTexture.GetWidth() &&
pFramebuffer->GetHeight() == rTexture.GetHeight() )
pSameSizeFbo = pFramebuffer;
pFramebuffer = pFramebuffer->mpPrevFramebuffer;
}
// else use any framebuffer having the same size
if( !pFramebuffer && pSameSizeFbo )
pFramebuffer = pSameSizeFbo;
// else use the first free framebuffer
if( !pFramebuffer && pFreeFramebuffer )
pFramebuffer = pFreeFramebuffer;
if( !pFramebuffer && pFreeFbo )
pFramebuffer = pFreeFbo;
// if there isn't any free one, create a new one
if( !pFramebuffer )
// if there isn't any free one, create a new one if the limit isn't reached
if( !pFramebuffer && mnFramebufferCount < MAX_FRAMEBUFFER_COUNT )
{
mnFramebufferCount++;
pFramebuffer = new OpenGLFramebuffer();
if( mpLastFramebuffer )
{
......@@ -1455,9 +1480,14 @@ OpenGLFramebuffer* OpenGLContext::AcquireFramebuffer( const OpenGLTexture& rText
}
}
AcquireFramebuffer( pFramebuffer );
if( pFramebuffer->IsFree() )
pFramebuffer->AttachTexture( rTexture );
// last try, use any framebuffer
// TODO order the list of framebuffers as a LRU
if( !pFramebuffer )
pFramebuffer = mpFirstFramebuffer;
assert( pFramebuffer );
BindFramebuffer( pFramebuffer );
pFramebuffer->AttachTexture( rTexture );
glViewport( 0, 0, rTexture.GetWidth(), rTexture.GetHeight() );
return pFramebuffer;
......@@ -1469,6 +1499,32 @@ void OpenGLContext::ReleaseFramebuffer( OpenGLFramebuffer* pFramebuffer )
pFramebuffer->DetachTexture();
}
void OpenGLContext::ReleaseFramebuffer( const OpenGLTexture& rTexture )
{
OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer;
while( pFramebuffer )
{
if( pFramebuffer->IsAttached( rTexture ) )
{
BindFramebuffer( pFramebuffer );
pFramebuffer->DetachTexture();
}
pFramebuffer = pFramebuffer->mpPrevFramebuffer;
}
}
void OpenGLContext::ReleaseFramebuffers()
{
OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer;
while( pFramebuffer )
{
BindFramebuffer( pFramebuffer );
pFramebuffer->DetachTexture();
pFramebuffer = pFramebuffer->mpPrevFramebuffer;
}
}
OpenGLProgram* OpenGLContext::GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader )
{
boost::unordered_map<ProgramKey, OpenGLProgram*>::iterator it;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment