diff options
author | Louis-Francis Ratté-Boulianne <lfrb@collabora.com> | 2014-12-04 22:25:56 -0500 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2014-12-15 22:47:07 +0100 |
commit | ff55a35975e677b74d3b7632bbfc39b8633d6b0a (patch) | |
tree | 92e1a3271c523bee78fb66211afc61635a728bc1 /vcl | |
parent | a6ba404dcaaf1e284f52e2a1e1b988274d35d7f9 (diff) |
vcl: Re-use a framebuffer of the same size when possible
Conflicts:
include/vcl/opengl/OpenGLContext.hxx
Change-Id: Id9c7932976ce9d9282776c20d93d9cca4d290056
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/opengl/framebuffer.hxx | 4 | ||||
-rw-r--r-- | vcl/opengl/framebuffer.cxx | 4 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 12 | ||||
-rw-r--r-- | vcl/source/opengl/OpenGLContext.cxx | 88 |
4 files changed, 89 insertions, 19 deletions
diff --git a/vcl/inc/opengl/framebuffer.hxx b/vcl/inc/opengl/framebuffer.hxx index 4ccc1c5728ea..e9c9065f1edc 100644 --- a/vcl/inc/opengl/framebuffer.hxx +++ b/vcl/inc/opengl/framebuffer.hxx @@ -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(); diff --git a/vcl/opengl/framebuffer.cxx b/vcl/opengl/framebuffer.cxx index 29f9a781130a..e760b53f614d 100644 --- a/vcl/opengl/framebuffer.cxx +++ b/vcl/opengl/framebuffer.cxx @@ -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(); diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index dcc4d85780b2..0e14fada7418 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -121,6 +121,8 @@ void OpenGLSalGraphicsImpl::Init() maOffscreenTex.GetWidth() != GetWidth() || maOffscreenTex.GetHeight() != GetHeight() ) { + if( mpContext ) // valid context + mpContext->ReleaseFramebuffer( maOffscreenTex ); maOffscreenTex = OpenGLTexture(); } } @@ -162,15 +164,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 ) @@ -1584,6 +1589,7 @@ void OpenGLSalGraphicsImpl::endPaint() if( mpContext->mnPainting == 0 && !mbOffscreen ) { mpContext->makeCurrent(); + mpContext->AcquireDefaultFramebuffer(); glFlush(); } } diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx index f662f2fc95d3..578cc02e84f1 100644 --- a/vcl/source/opengl/OpenGLContext.cxx +++ b/vcl/source/opengl/OpenGLContext.cxx @@ -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), @@ -1275,6 +1278,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(); @@ -1282,6 +1297,8 @@ void OpenGLContext::makeCurrent() if (isCurrent()) return; + clearCurrent(); + #if defined( WNT ) if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) { @@ -1322,6 +1339,8 @@ void OpenGLContext::makeCurrent() void OpenGLContext::resetCurrent() { + clearCurrent(); + #if defined( WNT ) wglMakeCurrent( m_aGLWin.hDC, 0 ); #elif defined( MACOSX ) @@ -1389,14 +1408,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 @@ -1409,13 +1424,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; @@ -1423,18 +1439,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 ) { @@ -1449,9 +1474,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; @@ -1463,6 +1493,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; |