[Libreoffice-commits] core.git: Branch 'feature/opengl-vcl2' - 5 commits - include/vcl vcl/inc vcl/opengl vcl/source vcl/unx

Louis-Francis Ratté-Boulianne lfrb at collabora.com
Thu Dec 4 19:28:48 PST 2014


 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 <lfrb at collabora.com>
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 <lfrb at collabora.com>
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 <lfrb at collabora.com>
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 <lfrb at collabora.com>
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 <lfrb at collabora.com>
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;
 };


More information about the Libreoffice-commits mailing list