diff options
-rw-r--r-- | include/vcl/opengl/OpenGLContext.hxx | 5 | ||||
-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 |
5 files changed, 93 insertions, 20 deletions
diff --git a/include/vcl/opengl/OpenGLContext.hxx b/include/vcl/opengl/OpenGLContext.hxx index 21f45d207d6f..a98f82592e1b 100644 --- a/include/vcl/opengl/OpenGLContext.hxx +++ b/include/vcl/opengl/OpenGLContext.hxx @@ -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(); 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 4edd843355c3..9520c863f5d7 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -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(); } } diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx index 47150256fc05..5e9e942cb0f8 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), @@ -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; |