include/vcl/opengl/OpenGLContext.hxx | 7 vcl/inc/cairotextrender.hxx | 1 vcl/inc/opengl/framebuffer.hxx | 8 vcl/inc/openglgdiimpl.hxx | 2 vcl/opengl/framebuffer.cxx | 26 +- vcl/opengl/gdiimpl.cxx | 36 ++- vcl/opengl/salbmp.cxx | 2 vcl/source/opengl/OpenGLContext.cxx | 255 ++++++++++++++++------- vcl/unx/generic/gdi/cairotextrender.cxx | 4 vcl/unx/generic/gdi/openglx11cairotextrender.cxx | 48 +++- vcl/unx/generic/gdi/openglx11cairotextrender.hxx | 1 vcl/unx/generic/gdi/x11cairotextrender.cxx | 6 vcl/unx/generic/gdi/x11cairotextrender.hxx | 1 vcl/unx/generic/window/salframe.cxx | 11 14 files changed, 299 insertions(+), 109 deletions(-)
New commits: commit fb2574334c3da0630484de74d22a6f25d21d507a Author: Louis-Francis Ratté-Boulianne <[email protected]> Date: Thu Dec 4 22:27:38 2014 -0500 vcl: Don't keep a reference to the texture in the FBO object Change-Id: I240d2b44e77d28af3cd5952b6d666a1709c4c54a diff --git a/vcl/inc/opengl/framebuffer.hxx b/vcl/inc/opengl/framebuffer.hxx index e9c9065..915008c 100644 --- a/vcl/inc/opengl/framebuffer.hxx +++ b/vcl/inc/opengl/framebuffer.hxx @@ -18,10 +18,10 @@ class VCL_PLUGIN_PUBLIC OpenGLFramebuffer { private: - GLuint mnId; - OpenGLTexture maAttachedTexture; + GLuint mnId; int mnWidth; int mnHeight; + GLuint mnAttachedTexture; public: OpenGLFramebuffer(); diff --git a/vcl/opengl/framebuffer.cxx b/vcl/opengl/framebuffer.cxx index e760b53..c4dfb05 100644 --- a/vcl/opengl/framebuffer.cxx +++ b/vcl/opengl/framebuffer.cxx @@ -17,6 +17,7 @@ OpenGLFramebuffer::OpenGLFramebuffer() : mnId( 0 ), mnWidth( 0 ), mnHeight( 0 ), + mnAttachedTexture( 0 ), mpPrevFramebuffer( NULL ), mpNextFramebuffer( NULL ) { @@ -45,30 +46,37 @@ void OpenGLFramebuffer::Unbind() bool OpenGLFramebuffer::IsFree() const { - return (!maAttachedTexture); + return (!mnAttachedTexture); } bool OpenGLFramebuffer::IsAttached( const OpenGLTexture& rTexture ) const { - return ( maAttachedTexture == rTexture ); + return ( mnAttachedTexture == rTexture.Id() ); } void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture ) { + if( rTexture.Id() == mnAttachedTexture ) + return; + SAL_INFO( "vcl.opengl", "Attaching texture " << rTexture.Id() << " to framebuffer " << (int)mnId ); - maAttachedTexture = rTexture; + mnAttachedTexture = rTexture.Id(); mnWidth = rTexture.GetWidth(); mnHeight = rTexture.GetHeight(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - maAttachedTexture.Id(), 0 ); + mnAttachedTexture, 0 ); CHECK_GL_ERROR(); } void OpenGLFramebuffer::DetachTexture() { - maAttachedTexture = OpenGLTexture(); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 ); - CHECK_GL_ERROR(); + if( mnAttachedTexture != 0 ) + { + CHECK_GL_ERROR(); + mnAttachedTexture = 0; + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 ); + CHECK_GL_ERROR(); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit f186da3f21c3b6633123be95131f62d6b390491e Author: Louis-Francis Ratté-Boulianne <[email protected]> Date: Thu Dec 4 22:25:56 2014 -0500 vcl: Re-use a framebuffer of the same size when possible Change-Id: Id9c7932976ce9d9282776c20d93d9cca4d290056 diff --git a/include/vcl/opengl/OpenGLContext.hxx b/include/vcl/opengl/OpenGLContext.hxx index 84174c1..11d37fa 100644 --- a/include/vcl/opengl/OpenGLContext.hxx +++ b/include/vcl/opengl/OpenGLContext.hxx @@ -210,16 +210,19 @@ 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 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 4ccc1c5..e9c9065 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 29f9a78..e760b53 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 1cd61ea..c477f4e 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -119,6 +119,8 @@ void OpenGLSalGraphicsImpl::Init() maOffscreenTex.GetWidth() != GetWidth() || maOffscreenTex.GetHeight() != GetHeight() ) { + if( mpContext ) // valid context + mpContext->ReleaseFramebuffer( maOffscreenTex ); maOffscreenTex = OpenGLTexture(); } } @@ -160,15 +162,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 ) @@ -1442,6 +1447,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 780bbf9..4093b5f 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> vShareList; @@ -57,6 +59,7 @@ OpenGLContext::OpenGLContext(): mbRequestLegacyContext(false), mbUseDoubleBufferedRendering(true), mbRequestVirtualDevice(false), + mnFramebufferCount(0), mpCurrentFramebuffer(NULL), mpFirstFramebuffer(NULL), mpLastFramebuffer(NULL), @@ -1245,6 +1248,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(); @@ -1252,6 +1267,8 @@ void OpenGLContext::makeCurrent() if (isCurrent()) return; + clearCurrent(); + #if defined( WNT ) if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) { @@ -1292,6 +1309,8 @@ void OpenGLContext::makeCurrent() void OpenGLContext::resetCurrent() { + clearCurrent(); + #if defined( WNT ) wglMakeCurrent( m_aGLWin.hDC, 0 ); #elif defined( MACOSX ) @@ -1359,14 +1378,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 @@ -1379,13 +1394,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; @@ -1393,18 +1409,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 ) { @@ -1419,9 +1444,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; @@ -1433,6 +1463,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; commit d6718423d36e83a13d01f098aaf32fc145cf6a33 Author: Louis-Francis Ratté-Boulianne <[email protected]> Date: Thu Dec 4 22:21:50 2014 -0500 vcl: Keep the same context for VirtualDevice to avoid FBO switches Change-Id: I66496fae902db9df5b8301b00bb779f42adaa7a7 diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index c7423a4..1cd61ea 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -56,8 +56,8 @@ OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl() OpenGLContext* OpenGLSalGraphicsImpl::GetOpenGLContext() { - if( !mpContext ) - AcquireContext(); + if( !AcquireContext() ) + return NULL; return mpContext; } @@ -71,7 +71,11 @@ bool OpenGLSalGraphicsImpl::AcquireContext( ) ImplSVData* pSVData = ImplGetSVData(); if( mpContext ) + { + if( mpContext->isInitialized() ) + return true; mpContext->DeRef(); + } OpenGLContext* pContext = pSVData->maGDIData.mpLastContext; while( pContext ) @@ -121,7 +125,7 @@ void OpenGLSalGraphicsImpl::Init() void OpenGLSalGraphicsImpl::PreDraw() { - if( !mpContext && !AcquireContext() ) + if( !AcquireContext() ) { SAL_WARN( "vcl.opengl", "Couldn't acquire context" ); return; @@ -160,11 +164,6 @@ void OpenGLSalGraphicsImpl::PostDraw() mpFramebuffer = NULL; CHECK_GL_ERROR(); - - // release the context as there is no guarantee the underlying window - // will still be valid for the next draw operation - if( mbOffscreen ) - ReleaseContext(); } void OpenGLSalGraphicsImpl::freeResources() @@ -1427,7 +1426,7 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, void OpenGLSalGraphicsImpl::beginPaint() { - if( !mpContext && !AcquireContext() ) + if( !AcquireContext() ) return; mpContext->mnPainting++; @@ -1435,7 +1434,7 @@ void OpenGLSalGraphicsImpl::beginPaint() void OpenGLSalGraphicsImpl::endPaint() { - if( !mpContext && !AcquireContext() ) + if( !AcquireContext() ) return; mpContext->mnPainting--; commit 5bf989edbb0bf83190665cc97cafdcdd6cdbe4a9 Author: Louis-Francis Ratté-Boulianne <[email protected]> Date: Thu Dec 4 22:17:58 2014 -0500 vcl: Reset context when the backind window is destroyed Change-Id: Ie2b93de8efe5ea56b0420adf23639c0153103385 diff --git a/include/vcl/opengl/OpenGLContext.hxx b/include/vcl/opengl/OpenGLContext.hxx index 6546dde..84174c1 100644 --- a/include/vcl/opengl/OpenGLContext.hxx +++ b/include/vcl/opengl/OpenGLContext.hxx @@ -203,6 +203,7 @@ public: #elif defined( _WIN32 ) bool init( HDC hDC, HWND hWnd ); #endif + void reset(); void AddRef(); void DeRef(); @@ -218,6 +219,7 @@ public: OpenGLProgram* GetProgram( const OUString& rVertexShader, const OUString& rFragmentShader ); OpenGLProgram* UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader ); + bool isCurrent(); void makeCurrent(); void resetCurrent(); void swapBuffers(); diff --git a/vcl/opengl/salbmp.cxx b/vcl/opengl/salbmp.cxx index 20ef2c4..61d8358 100644 --- a/vcl/opengl/salbmp.cxx +++ b/vcl/opengl/salbmp.cxx @@ -471,6 +471,8 @@ void OpenGLSalBitmap::makeCurrent() // TODO: make sure we can really use the last used context mpContext = pSVData->maGDIData.mpLastContext; + while( mpContext && !mpContext->isInitialized() ) + mpContext = mpContext->mpPrevContext; if( !mpContext ) mpContext = GetBitmapContext(); assert(mpContext && "Couldn't get an OpenGL context"); diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx index 5dfdd54..780bbf9 100644 --- a/vcl/source/opengl/OpenGLContext.cxx +++ b/vcl/source/opengl/OpenGLContext.cxx @@ -82,6 +82,8 @@ OpenGLContext::OpenGLContext(): OpenGLContext::~OpenGLContext() { + reset(); + ImplSVData* pSVData = ImplGetSVData(); if( mpPrevContext ) mpPrevContext->mpNextContext = mpNextContext; @@ -91,36 +93,6 @@ OpenGLContext::~OpenGLContext() mpNextContext->mpPrevContext = mpPrevContext; else pSVData->maGDIData.mpLastContext = mpPrevContext; - -#if defined( WNT ) - if (m_aGLWin.hRC) - { - vShareList.erase(std::remove(vShareList.begin(), vShareList.end(), m_aGLWin.hRC)); - - wglMakeCurrent( m_aGLWin.hDC, 0 ); - wglDeleteContext( m_aGLWin.hRC ); - ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC ); - } -#elif defined( MACOSX ) - OpenGLWrapper::resetCurrent(); -#elif defined( IOS ) || defined( ANDROID ) - // nothing -#elif defined( UNX ) - if(m_aGLWin.ctx) - { - vShareList.erase(std::remove( vShareList.begin(), vShareList.end(), m_aGLWin.ctx )); - - glXMakeCurrent(m_aGLWin.dpy, None, NULL); - if( glGetError() != GL_NO_ERROR ) - { - SAL_WARN("vcl.opengl", "glError: " << (char *)gluErrorString(glGetError())); - } - glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx); - - if (mbPixmap) - glXDestroyGLXPixmap(m_aGLWin.dpy, m_aGLWin.glPix); - } -#endif } void OpenGLContext::AddRef() @@ -1154,6 +1126,73 @@ void OpenGLContext::initGLWindow(Visual* pVisual) #endif +void OpenGLContext::reset() +{ + if( !mbInitialized ) + return; + + // reset the clip region + maClipRegion.SetEmpty(); + + // destroy all framebuffers + if( mpLastFramebuffer ) + { + OpenGLFramebuffer* pFramebuffer = mpLastFramebuffer; + + makeCurrent(); + while( pFramebuffer ) + { + OpenGLFramebuffer* pPrevFramebuffer = pFramebuffer->mpPrevFramebuffer; + delete pFramebuffer; + pFramebuffer = pPrevFramebuffer; + } + mpFirstFramebuffer = NULL; + mpLastFramebuffer = NULL; + } + + // destroy all programs + if( !maPrograms.empty() ) + { + boost::unordered_map<ProgramKey, OpenGLProgram*>::iterator it; + + makeCurrent(); + it = maPrograms.begin(); + while( it != maPrograms.end() ) + { + delete it->second; + it++; + } + maPrograms.clear(); + } + + if( isCurrent() ) + resetCurrent(); + + mbInitialized = false; + + // destroy the context itself +#if defined( WNT ) + if (m_aGLWin.hRC) + { + vShareList.erase(std::remove(vShareList.begin(), vShareList.end(), m_aGLWin.hRC)); + wglDeleteContext( m_aGLWin.hRC ); + ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC ); + } +#elif defined( MACOSX ) + // nothing +#elif defined( IOS ) || defined( ANDROID ) + // nothing +#elif defined( UNX ) + if(m_aGLWin.ctx) + { + vShareList.erase(std::remove( vShareList.begin(), vShareList.end(), m_aGLWin.ctx )); + glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx); + if (mbPixmap) + glXDestroyGLXPixmap(m_aGLWin.dpy, m_aGLWin.glPix); + } +#endif +} + #if defined( WNT ) || defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) SystemWindowData OpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool bRequestLegacyContext) @@ -1191,17 +1230,33 @@ SystemWindowData OpenGLContext::generateWinData(vcl::Window* pParent, bool) #endif +bool OpenGLContext::isCurrent() +{ +#if defined( WNT ) + return (wglGetCurrentContext() == m_aGLWin.hRC && + wglGetCurrentDC() == m_aGLWin.hDC); +#elif defined( MACOSX ) + return false; +#elif defined( IOS ) || defined( ANDROID ) + return false; +#elif defined( UNX ) + GLXDrawable nDrawable = mbPixmap ? m_aGLWin.glPix : m_aGLWin.win; + return (glXGetCurrentContext() == m_aGLWin.ctx && + glXGetCurrentDrawable() == nDrawable); +#endif +} void OpenGLContext::makeCurrent() { + ImplSVData* pSVData = ImplGetSVData(); + + if (isCurrent()) + return; + #if defined( WNT ) - if (wglGetCurrentContext() == m_aGLWin.hRC && - wglGetCurrentDC() == m_aGLWin.hDC) - { - SAL_INFO("vcl.opengl", "OpenGLContext::makeCurrent(): Avoid setting the same context"); - } - else if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) + if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) { SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent(): wglMakeCurrent failed: " << GetLastError()); + return; } #elif defined( MACOSX ) NSOpenGLView* pView = getOpenGLView(); @@ -1210,33 +1265,29 @@ void OpenGLContext::makeCurrent() // nothing #elif defined( UNX ) GLXDrawable nDrawable = mbPixmap ? m_aGLWin.glPix : m_aGLWin.win; - static int nSwitch = 0; - if (glXGetCurrentContext() == m_aGLWin.ctx && - glXGetCurrentDrawable() == nDrawable) + if (!glXMakeCurrent( m_aGLWin.dpy, nDrawable, m_aGLWin.ctx )) { - ; // no-op - } - else if (!glXMakeCurrent( m_aGLWin.dpy, nDrawable, m_aGLWin.ctx )) SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed on drawable " << nDrawable << " pixmap? " << mbPixmap); - else + return; + } +#endif + + // move the context at the end of the contexts list + static int nSwitch = 0; + SAL_INFO("vcl.opengl", "******* CONTEXT SWITCH " << ++nSwitch << " *********"); + if( mpNextContext ) { - SAL_INFO("vcl.opengl", "******* CONTEXT SWITCH " << ++nSwitch << " *********"); - ImplSVData* pSVData = ImplGetSVData(); - if( mpNextContext ) - { - if( mpPrevContext ) - mpPrevContext->mpNextContext = mpNextContext; - else - pSVData->maGDIData.mpFirstContext = mpNextContext; - mpNextContext->mpPrevContext = mpPrevContext; + if( mpPrevContext ) + mpPrevContext->mpNextContext = mpNextContext; + else + pSVData->maGDIData.mpFirstContext = mpNextContext; + mpNextContext->mpPrevContext = mpPrevContext; - mpPrevContext = pSVData->maGDIData.mpLastContext; - mpNextContext = NULL; - pSVData->maGDIData.mpLastContext->mpNextContext = this; - pSVData->maGDIData.mpLastContext = this; - } + mpPrevContext = pSVData->maGDIData.mpLastContext; + mpNextContext = NULL; + pSVData->maGDIData.mpLastContext->mpNextContext = this; + pSVData->maGDIData.mpLastContext = this; } -#endif } void OpenGLContext::resetCurrent() diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx index ee94a19..ff63c7a 100644 --- a/vcl/unx/generic/window/salframe.cxx +++ b/vcl/unx/generic/window/salframe.cxx @@ -34,6 +34,7 @@ #include "vcl/printerinfomanager.hxx" #include "vcl/settings.hxx" #include "vcl/bmpacc.hxx" +#include "vcl/opengl/OpenGLContext.hxx" #include <prex.h> #include <X11/Xatom.h> @@ -65,6 +66,7 @@ #include <sal/macros.h> #include <com/sun/star/uno/Exception.hpp> +#include "svdata.hxx" #include "svids.hrc" #include "impbmp.hxx" @@ -894,6 +896,15 @@ X11SalFrame::~X11SalFrame() delete pFreeGraphics_; } + // reset all OpenGL contexts using this window + OpenGLContext* pContext = ImplGetSVData()->maGDIData.mpLastContext; + while( pContext ) + { + if( pContext->getOpenGLWindow().win == mhWindow ) + pContext->reset(); + pContext = pContext->mpPrevContext; + } + XDestroyWindow( GetXDisplay(), mhWindow ); /* commit 5d717ae96c08c4a74641422ef99b359b56aa0630 Author: Louis-Francis Ratté-Boulianne <[email protected]> Date: Thu Dec 4 11:45:55 2014 -0500 vcl: Limit Cairo surface size to the clipping region to improve performance Change-Id: I469b34c9f1047a274550229391d3dfb578291df6 diff --git a/vcl/inc/cairotextrender.hxx b/vcl/inc/cairotextrender.hxx index e5db2ab..2b8a21e 100644 --- a/vcl/inc/cairotextrender.hxx +++ b/vcl/inc/cairotextrender.hxx @@ -77,6 +77,7 @@ class CairoTextRender : public TextRenderImpl protected: virtual GlyphCache& getPlatformGlyphCache() = 0; virtual cairo_surface_t* getCairoSurface() = 0; + virtual void getSurfaceOffset(double& nDX, double& nDY) = 0; virtual void drawSurface(cairo_t* cr) = 0; bool setFont( const FontSelectPattern *pEntry, int nFallbackLevel ); diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx index 3a4222e..0011692 100644 --- a/vcl/inc/openglgdiimpl.hxx +++ b/vcl/inc/openglgdiimpl.hxx @@ -129,7 +129,9 @@ public: virtual void freeResources() SAL_OVERRIDE; + virtual const vcl::Region& getClipRegion() const; virtual bool setClipRegion( const vcl::Region& ) SAL_OVERRIDE; + // // get the depth of the device virtual sal_uInt16 GetBitCount() const SAL_OVERRIDE; diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index 1fb59a2..c7423a4 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -224,6 +224,11 @@ void OpenGLSalGraphicsImpl::ImplInitClipRegion() CHECK_GL_ERROR(); } +const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const +{ + return maClipRegion; +} + bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip ) { SAL_INFO( "vcl.opengl", "::setClipRegion " << rClip ); diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index 5b31b92..589b53a 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -222,6 +222,10 @@ void CairoTextRender::DrawServerFontLayout( const ServerFontLayout& rLayout ) if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions()) cairo_set_font_options(cr, static_cast<const cairo_font_options_t*>(pOptions)); + double nDX, nDY; + getSurfaceOffset(nDX, nDY); + cairo_translate(cr, nDX, nDY); + clipRegion(cr); cairo_set_source_rgb(cr, diff --git a/vcl/unx/generic/gdi/openglx11cairotextrender.cxx b/vcl/unx/generic/gdi/openglx11cairotextrender.cxx index 38a7213..b49df00 100644 --- a/vcl/unx/generic/gdi/openglx11cairotextrender.cxx +++ b/vcl/unx/generic/gdi/openglx11cairotextrender.cxx @@ -25,32 +25,56 @@ cairo_surface_t* OpenGLX11CairoTextRender::getCairoSurface() // static size_t id = 0; // OString aFileName = OString("/tmp/libo_logs/text_rendering") + OString::number(id++) + OString(".svg"); // cairo_surface_t* surface = cairo_svg_surface_create(aFileName.getStr(), GetWidth(), GetHeight()); - cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, GetWidth(), GetHeight()); + cairo_surface_t* surface = NULL; + OpenGLSalGraphicsImpl *pImpl = dynamic_cast< OpenGLSalGraphicsImpl* >(mrParent.GetImpl()); + if( pImpl ) + { + Rectangle aClipRect = pImpl->getClipRegion().GetBoundRect(); + if( aClipRect.GetWidth() == 0 || aClipRect.GetHeight() == 0 ) + { + aClipRect.setWidth( GetWidth() ); + aClipRect.setHeight( GetHeight() ); + } + surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, aClipRect.GetWidth(), aClipRect.GetHeight() ); + } return surface; } +void OpenGLX11CairoTextRender::getSurfaceOffset( double& nDX, double& nDY ) +{ + OpenGLSalGraphicsImpl *pImpl = dynamic_cast< OpenGLSalGraphicsImpl* >(mrParent.GetImpl()); + if( pImpl ) + { + Rectangle aClipRect = pImpl->getClipRegion().GetBoundRect(); + nDX = -aClipRect.Left(); + nDY = -aClipRect.Top(); + } +} + void OpenGLX11CairoTextRender::drawSurface(cairo_t* cr) { - cairo_surface_t* pSurface = cairo_get_target(cr); + cairo_surface_t* pSurface = cairo_get_target( cr ); int nWidth = cairo_image_surface_get_width( pSurface ); int nHeight = cairo_image_surface_get_height( pSurface ); cairo_surface_flush( pSurface ); unsigned char *pSrc = cairo_image_surface_get_data( pSurface ); - SalTwoRect aRect; - aRect.mnSrcX = 0; - aRect.mnSrcY = 0; - aRect.mnSrcWidth = nWidth; - aRect.mnSrcHeight = nHeight; - aRect.mnDestX = 0; - aRect.mnDestY = 0; - aRect.mnDestWidth = nWidth; - aRect.mnDestHeight = nHeight; - // XXX: lfrb: GLES 2.0 doesn't support GL_UNSIGNED_INT_8_8_8_8_REV OpenGLSalGraphicsImpl *pImpl = dynamic_cast< OpenGLSalGraphicsImpl* >(mrParent.GetImpl()); if( pImpl ) { + Rectangle aClipRect = pImpl->getClipRegion().GetBoundRect(); + + SalTwoRect aRect; + aRect.mnSrcX = 0; + aRect.mnSrcY = 0; + aRect.mnSrcWidth = nWidth; + aRect.mnSrcHeight = nHeight; + aRect.mnDestX = aClipRect.Left(); + aRect.mnDestY = aClipRect.Top(); + aRect.mnDestWidth = nWidth; + aRect.mnDestHeight = nHeight; + // Cairo surface data is ARGB with premultiplied alpha and is Y-inverted OpenGLTexture aTexture( nWidth, nHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pSrc ); pImpl->PreDraw(); diff --git a/vcl/unx/generic/gdi/openglx11cairotextrender.hxx b/vcl/unx/generic/gdi/openglx11cairotextrender.hxx index 87ef948..1719496 100644 --- a/vcl/unx/generic/gdi/openglx11cairotextrender.hxx +++ b/vcl/unx/generic/gdi/openglx11cairotextrender.hxx @@ -18,6 +18,7 @@ public: OpenGLX11CairoTextRender(bool bPrinter, X11SalGraphics& rParent); virtual cairo_surface_t* getCairoSurface() SAL_OVERRIDE; + virtual void getSurfaceOffset(double& nDX, double& nDY) SAL_OVERRIDE; virtual void drawSurface(cairo_t* cr) SAL_OVERRIDE; }; diff --git a/vcl/unx/generic/gdi/x11cairotextrender.cxx b/vcl/unx/generic/gdi/x11cairotextrender.cxx index 0449b98..f3aa47d 100644 --- a/vcl/unx/generic/gdi/x11cairotextrender.cxx +++ b/vcl/unx/generic/gdi/x11cairotextrender.cxx @@ -77,6 +77,12 @@ cairo_surface_t* X11CairoTextRender::getCairoSurface() return surface; } +void X11CairoTextRender::getSurfaceOffset( double& nDX, double& nDY ) +{ + nDX = 0; + nDY = 0; +} + void X11CairoTextRender::clipRegion(cairo_t* cr) { Region pClipRegion = mrParent.mpClipRegion; diff --git a/vcl/unx/generic/gdi/x11cairotextrender.hxx b/vcl/unx/generic/gdi/x11cairotextrender.hxx index fb0c130..1449b3a 100644 --- a/vcl/unx/generic/gdi/x11cairotextrender.hxx +++ b/vcl/unx/generic/gdi/x11cairotextrender.hxx @@ -41,6 +41,7 @@ public: virtual GlyphCache& getPlatformGlyphCache() SAL_OVERRIDE; virtual cairo_surface_t* getCairoSurface() SAL_OVERRIDE; + virtual void getSurfaceOffset(double& nDX, double& nDY) SAL_OVERRIDE; virtual void clipRegion(cairo_t* cr) SAL_OVERRIDE; virtual void drawSurface(cairo_t* cr) SAL_OVERRIDE; };
_______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
