[Libreoffice-commits] core.git: Branch 'private/mmeeks/opengl-backbuffer2' - vcl/inc vcl/opengl

Michael Meeks michael.meeks at collabora.com
Fri Dec 4 06:57:00 PST 2015


Rebased ref, commits from common ancestor:
commit a594a901aa3e37c157427735c269f1109c2ab953
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Fri Nov 13 12:00:59 2015 +0000

    tdf#93529 - move to a Mac-like double-buffered OpenGL model.
    
    This moves us to always rendering to an off-screen texture, and then
    (at idle) blitting this to the screen & swapping buffers. Ideally we
    should never see any rendering, or flicker again with this approach.
    
    Several fixes are included:
       + avoid multiple OpenGL contexts being created for the same window,
         created excessive flicker problems.
       + de-virtualize UseContext - which context we use is less critical.
       + kill 'mbOffscreen' distinction - all VCL rendering is offscreen.
       + implement 'doFlush' and high priority idle flushing.
    
    Change-Id: I6be08595b6c8deb7e6db0dbd81308b2c97d2b4ff

diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx
index ecefede..8102d2e 100644
--- a/vcl/inc/opengl/win/gdiimpl.hxx
+++ b/vcl/inc/opengl/win/gdiimpl.hxx
@@ -31,7 +31,6 @@ public:
 
 protected:
     virtual rtl::Reference<OpenGLContext> CreateWinContext() override;
-    virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) override;
 
     bool RenderTextureCombo(TextureCombo& rCombo, int nX, int nY);
 
diff --git a/vcl/inc/opengl/x11/gdiimpl.hxx b/vcl/inc/opengl/x11/gdiimpl.hxx
index f07468d..eccd0ef 100644
--- a/vcl/inc/opengl/x11/gdiimpl.hxx
+++ b/vcl/inc/opengl/x11/gdiimpl.hxx
@@ -29,7 +29,6 @@ public:
 
 protected:
     virtual rtl::Reference<OpenGLContext> CreateWinContext() override;
-    virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) override;
 
     bool RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo);
 
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index 667b2ec..b2969cc 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -52,12 +52,20 @@ struct TextureCombo
     std::unique_ptr<OpenGLTexture> mpMask;
 };
 
+class OpenGLFlushIdle;
+
 class VCL_DLLPUBLIC OpenGLSalGraphicsImpl : public SalGraphicsImpl
 {
     friend class OpenGLTests;
 protected:
 
+    /// This context is solely for blitting @maOffscreenTex
+    rtl::Reference<OpenGLContext> mpWindowContext;
+
+    /// This context is whatever is most convenient to render
+    /// to @maOffscreenTex with.
     rtl::Reference<OpenGLContext> mpContext;
+
     SalGraphics& mrParent;
     /// Pointer to the SalFrame or SalVirtualDevice
     SalGeometryProvider* mpProvider;
@@ -67,18 +75,27 @@ protected:
     /// Is it someone else's context we shouldn't be fiddling with ?
     static bool IsForeignContext(const rtl::Reference<OpenGLContext> &xContext);
 
+    /// This idle handler is used to swap buffers after rendering.
+    OpenGLFlushIdle *mpFlush;
+
     // clipping
     vcl::Region maClipRegion;
     bool mbUseScissor;
     bool mbUseStencil;
 
-    bool mbOffscreen;
+    /**
+     * All rendering happens to this off-screen texture. For
+     * non-virtual devices, ie. windows - we will blit it and
+     * swapBuffers later.
+     */
     OpenGLTexture maOffscreenTex;
 
     SalColor mnLineColor;
     SalColor mnFillColor;
 #ifdef DBG_UTIL
     bool mProgramIsSolidColor;
+    sal_uInt32 mnDrawCount;
+    sal_uInt32 mnDrawCountAtFlush;
 #endif
     SalColor mProgramSolidColor;
     double mProgramSolidTransparency;
@@ -131,7 +148,10 @@ public:
     // get the height of the device
     GLfloat GetHeight() const { return mpProvider ? mpProvider->GetHeight() : 1; }
 
-    // check whether this instance is used for offscreen rendering
+    /**
+     * check whether this instance is used for offscreen (Virtual Device)
+     * rendering ie. does it need its own context.
+     */
     bool IsOffscreen() const { return mpProvider == nullptr || mpProvider->IsOffScreen(); }
 
     // operations to do before painting
@@ -144,14 +164,18 @@ protected:
     bool AcquireContext();
     bool ReleaseContext();
 
-    // retrieve the default context for offscreen rendering
+    /// retrieve the default context for offscreen rendering
     static rtl::Reference<OpenGLContext> GetDefaultContext();
 
-    // create a new context for window rendering
+    /// create a new context for rendering to the underlying window
     virtual rtl::Reference<OpenGLContext> CreateWinContext() = 0;
 
-    // check whether the given context can be used by this instance
-    virtual bool UseContext( const rtl::Reference<OpenGLContext> &pContext ) = 0;
+    /// check whether the given context can be used for off-screen rendering
+    bool UseContext( const rtl::Reference<OpenGLContext> &pContext )
+    {
+        return pContext->isInitialized() &&  // not released by the OS etc.
+               IsForeignContext( pContext ); // a genuine VCL context.
+    }
 
 public:
     OpenGLSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider *pProvider);
@@ -328,8 +352,12 @@ public:
 
     virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override;
 
-    virtual OpenGLContext *beginPaint() override;
-private:
+    /// queue an idle flush of contents of the back-buffer to the screen
+    void flush();
+
+public:
+    /// do flush of contents of the back-buffer to the screen & swap.
+    void doFlush();
 };
 
 #endif
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 413f802..3266dea 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -37,19 +37,43 @@
 
 #include <vector>
 
+#include <stdlib.h>
+
+class OpenGLFlushIdle : public Idle
+{
+    OpenGLSalGraphicsImpl *m_pImpl;
+public:
+    OpenGLFlushIdle( OpenGLSalGraphicsImpl *pImpl )
+        : Idle( "gl idle swap" )
+        , m_pImpl( pImpl )
+    {
+        SetPriority( SchedulerPriority::HIGHEST );
+    }
+    ~OpenGLFlushIdle()
+    {
+    }
+    virtual void Invoke() override
+    {
+        m_pImpl->doFlush();
+        Stop();
+    }
+};
+
 OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider *pProvider)
     : mpContext(nullptr)
     , mrParent(rParent)
     , mpProvider(pProvider)
     , mpFramebuffer(nullptr)
     , mpProgram(nullptr)
+    , mpFlush(new OpenGLFlushIdle(this))
     , mbUseScissor(false)
     , mbUseStencil(false)
-    , mbOffscreen(false)
     , mnLineColor(SALCOLOR_NONE)
     , mnFillColor(SALCOLOR_NONE)
 #ifdef DBG_UTIL
     , mProgramIsSolidColor(false)
+    , mnDrawCount(0)
+    , mnDrawCountAtFlush(0)
 #endif
     , mProgramSolidColor(SALCOLOR_NONE)
     , mProgramSolidTransparency(0.0)
@@ -58,6 +82,11 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr
 
 OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl()
 {
+    if( !IsOffscreen() && mnDrawCountAtFlush != mnDrawCount )
+        VCL_GL_INFO( "Destroying un-flushed on-screen graphics" );
+
+    delete mpFlush;
+
     ReleaseContext();
 }
 
@@ -79,10 +108,9 @@ bool OpenGLSalGraphicsImpl::AcquireContext( )
 
     // We always prefer to bind our VirtualDevice / offscreen graphics
     // to the current OpenGLContext - to avoid switching contexts.
-    if (mpContext.is() && mbOffscreen)
+    if (mpContext.is() && OpenGLContext::hasCurrent() && !mpContext->isCurrent())
     {
-        if (OpenGLContext::hasCurrent() && !mpContext->isCurrent())
-            mpContext.clear();
+        mpContext.clear();
     }
 
     if( mpContext.is() )
@@ -97,15 +125,17 @@ bool OpenGLSalGraphicsImpl::AcquireContext( )
     while( pContext )
     {
         // check if this context can be used by this SalGraphicsImpl instance
-        if( UseContext( pContext )  )
+        if( UseContext( pContext ) )
             break;
         pContext = pContext->mpPrevContext;
     }
 
-    if( pContext )
+    if( mpContext.is() )
         mpContext = pContext;
+    else if( mpWindowContext.is() )
+        mpContext = mpWindowContext;
     else
-        mpContext = mbOffscreen ? GetDefaultContext() : CreateWinContext();
+        mpContext = GetDefaultContext();
 
     return mpContext.is();
 }
@@ -124,19 +154,15 @@ void OpenGLSalGraphicsImpl::Init()
     if( !mpProvider )
         return;
 
-    mbOffscreen = IsOffscreen();
-
     // check if we can simply re-use the same context
     if( mpContext.is() )
     {
-        if( !mpContext->isInitialized() ||
-            !UseContext( mpContext ) )
+        if( !UseContext( mpContext ) )
             ReleaseContext();
     }
 
-    // reset the offscreen texture
-    if( !mbOffscreen ||
-        maOffscreenTex.GetWidth()  != GetWidth() ||
+    // Always create the offscreen texture
+    if( maOffscreenTex.GetWidth()  != GetWidth() ||
         maOffscreenTex.GetHeight() != GetHeight() )
     {
         if( maOffscreenTex && // don't work to release empty textures
@@ -146,6 +172,14 @@ void OpenGLSalGraphicsImpl::Init()
             mpContext->ReleaseFramebuffer( maOffscreenTex );
         }
         maOffscreenTex = OpenGLTexture();
+        VCL_GL_INFO("::Init - re-size offscreen texture");
+    }
+
+    if( !IsOffscreen() )
+    {
+        if( mpWindowContext.is() )
+            mpWindowContext->reset();
+        mpWindowContext = CreateWinContext();
     }
 }
 
@@ -160,12 +194,15 @@ void OpenGLSalGraphicsImpl::DeInit()
     // get a shiny new context in AcquireContext:: next PreDraw.
     if( mpContext.is() && !IsOffscreen() )
         mpContext->reset();
+    mpContext.clear();
 }
 
 void OpenGLSalGraphicsImpl::PreDraw()
 {
     OpenGLZone::enter();
 
+    mnDrawCount++;
+
     if( !AcquireContext() )
     {
         SAL_WARN( "vcl.opengl", "Couldn't acquire context" );
@@ -175,10 +212,7 @@ void OpenGLSalGraphicsImpl::PreDraw()
     mpContext->makeCurrent();
     CHECK_GL_ERROR();
 
-    if( !mbOffscreen )
-        mpContext->AcquireDefaultFramebuffer();
-    else
-        CheckOffscreenTexture();
+    CheckOffscreenTexture();
     CHECK_GL_ERROR();
 
     glViewport( 0, 0, GetWidth(), GetHeight() );
@@ -190,15 +224,13 @@ void OpenGLSalGraphicsImpl::PreDraw()
 
 void OpenGLSalGraphicsImpl::PostDraw()
 {
-    if( !mbOffscreen && mpContext->mnPainting == 0 )
-        glFlush();
     if( mbUseScissor )
     {
         glDisable( GL_SCISSOR_TEST );
         CHECK_GL_ERROR();
     }
-   if( mbUseStencil )
-   {
+    if( mbUseStencil )
+    {
         glDisable( GL_STENCIL_TEST );
         CHECK_GL_ERROR();
     }
@@ -210,6 +242,18 @@ void OpenGLSalGraphicsImpl::PostDraw()
         mProgramIsSolidColor = false;
 #endif
     }
+
+    assert (maOffscreenTex);
+
+    if( IsOffscreen() )
+        assert( !mpWindowContext.is() );
+    else
+        assert( mpWindowContext.is() );
+
+    // Always queue the flush.
+    if( !IsOffscreen() )
+        flush();
+
     OpenGLZone::leave();
 }
 
@@ -221,8 +265,9 @@ void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset)
 void OpenGLSalGraphicsImpl::freeResources()
 {
     // TODO Delete shaders, programs and textures if not shared
-    if( mbOffscreen && mpContext.is() && mpContext->isInitialized() )
+    if( mpContext.is() && mpContext->isInitialized() )
     {
+        VCL_GL_INFO( "freeResources" );
         mpContext->makeCurrent();
         mpContext->ReleaseFramebuffer( maOffscreenTex );
     }
@@ -387,8 +432,29 @@ void OpenGLSalGraphicsImpl::SetROPFillColor( SalROPColor /*nROPColor*/ )
 
 bool OpenGLSalGraphicsImpl::CheckOffscreenTexture()
 {
+    bool bClearTexture = false;
+
+    VCL_GL_INFO( "Check Offscreen texture" );
+
+    // Always create the offscreen texture
+    if( maOffscreenTex )
+    {
+        if( maOffscreenTex.GetWidth()  != GetWidth() ||
+            maOffscreenTex.GetHeight() != GetHeight() )
+        {
+            mpContext->ReleaseFramebuffer( maOffscreenTex );
+            maOffscreenTex = OpenGLTexture();
+            VCL_GL_INFO( "re-size offscreen texture" );
+        }
+    }
+
     if( !maOffscreenTex )
+    {
+        VCL_GL_INFO( "create texture of size "
+                     << GetWidth() << " x " << GetHeight() );
         maOffscreenTex = OpenGLTexture( GetWidth(), GetHeight() );
+        bClearTexture = true;
+    }
 
     if( !maOffscreenTex.IsUnique() )
     {
@@ -405,8 +471,19 @@ bool OpenGLSalGraphicsImpl::CheckOffscreenTexture()
     else
     {
         mpFramebuffer = mpContext->AcquireFramebuffer( maOffscreenTex );
+        CHECK_GL_ERROR();
+
+        if( bClearTexture )
+        {
+            glDrawBuffer( GL_COLOR_ATTACHMENT0 );
+            GLfloat clearColor[4] = { 1.0, 0, 0, 0 };
+            glClearBufferfv( GL_COLOR, 0, clearColor );
+            // FIXME: use glClearTexImage if we have it ?
+        }
     }
 
+    assert( maOffscreenTex );
+
     CHECK_GL_ERROR();
     return true;
 }
@@ -1546,17 +1623,9 @@ void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGrap
         return;
     }
 
-    if( rImpl.mbOffscreen )
-    {
-        PreDraw();
-        DrawTexture( rImpl.maOffscreenTex, rPosAry );
-        PostDraw();
-        return;
-    }
-
-    SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** copyBits" );
-    // TODO: Copy from one FBO to the other (glBlitFramebuffer)
-    //       ie. copying from one visible window to another visible window
+    PreDraw();
+    DrawTexture( rImpl.maOffscreenTex, rPosAry );
+    PostDraw();
 }
 
 void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap )
@@ -1883,12 +1952,126 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
     return true;
 }
 
-OpenGLContext *OpenGLSalGraphicsImpl::beginPaint()
+void OpenGLSalGraphicsImpl::flush()
 {
-    if( mbOffscreen || !AcquireContext() )
-        return nullptr;
+    if( IsOffscreen() )
+        return;
+
+    if( !Application::IsInExecute() )
+    {
+        // otherwise nothing would trigger idle rendering
+        doFlush();
+    }
+    else if( !mpFlush->IsActive() )
+        mpFlush->Start();
+}
+
+void OpenGLSalGraphicsImpl::doFlush()
+{
+    if( IsOffscreen() )
+        return;
+
+    assert( mpWindowContext.is() );
+
+    if( !maOffscreenTex )
+    {
+        VCL_GL_INFO( "flushAndSwap - odd no texture !" );
+        return;
+    }
+
+    if (mnDrawCountAtFlush == mnDrawCount)
+    {
+        VCL_GL_INFO( "eliding redundant flushAndSwap, no drawing since last!" );
+        return;
+    }
+
+    mnDrawCountAtFlush = mnDrawCount;
+
+    OpenGLZone aZone;
+
+    VCL_GL_INFO( "flushAndSwap" );
+
+    // Interesting ! -> this destroys a context [ somehow ] ...
+    mpWindowContext->makeCurrent();
+    CHECK_GL_ERROR();
+
+    VCL_GL_INFO( "flushAndSwap - acquire default frame buffer" );
+
+    mpWindowContext->AcquireDefaultFramebuffer();
+    glBindFramebuffer( GL_FRAMEBUFFER, 0 ); // FIXME: paranoid double check.
+    CHECK_GL_ERROR();
+
+    VCL_GL_INFO( "flushAndSwap - acquired default frame buffer" );
+
+    glDisable( GL_SCISSOR_TEST ); // FIXME: paranoia ...
+    CHECK_GL_ERROR();
+    glDisable( GL_STENCIL_TEST ); // FIXME: paranoia ...
+    CHECK_GL_ERROR();
+
+    glViewport( 0, 0, GetWidth(), GetHeight() );
+    CHECK_GL_ERROR();
+
+    glClearColor((float)rand()/RAND_MAX, (float)rand()/RAND_MAX,
+                 (float)rand()/RAND_MAX, 1.0);
+    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
+    CHECK_GL_ERROR();
+
+    SalTwoRect aPosAry( 0, 0, maOffscreenTex.GetWidth(), maOffscreenTex.GetHeight(),
+                        0, 0, maOffscreenTex.GetWidth(), maOffscreenTex.GetHeight() );
+    VCL_GL_INFO( "Texture height " << maOffscreenTex.GetHeight() << " vs. window height " << GetHeight() );
+
+    OpenGLProgram *pProgram =
+        mpWindowContext->UseProgram( "textureVertexShader", "textureFragmentShader", "" );
+    if( !pProgram )
+        VCL_GL_INFO( "Can't compile simple copying shader !" );
     else
-        return mpContext.get();
+    {
+        pProgram->Use(); // FIXME: paranoia ...
+        VCL_GL_INFO( "done paranoid re-use." );
+        pProgram->SetTexture( "sampler", maOffscreenTex );
+        maOffscreenTex.Bind(); // FIXME: paranoia ...
+
+        VCL_GL_INFO( "bound bits etc." );
+
+        GLfloat aTexCoord[8];
+        maOffscreenTex.GetCoord( aTexCoord, aPosAry, false );
+        pProgram->SetTextureCoord( aTexCoord );
+
+        long nX1( aPosAry.mnDestX );
+        long nY1( aPosAry.mnDestY );
+        long nX2( nX1 + aPosAry.mnDestWidth );
+        long nY2( nY1 + aPosAry.mnDestHeight );
+        const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 },
+                                     { nX2, nY1 }, { nX2, nY2 }};
+
+        sal_uInt32 nPoints = 4;
+        std::vector<GLfloat> aVertices(nPoints * 2);
+        sal_uInt32 i, j;
+
+        for( i = 0, j = 0; i < nPoints; i++, j += 2 )
+        {
+            aVertices[j]   = GLfloat(aPoints[i].mnX);
+            aVertices[j+1] = GLfloat(aPoints[i].mnY);
+        }
+
+        pProgram->ApplyMatrix(GetWidth(), GetHeight(), 0.0);
+        pProgram->SetVertices( &aVertices[0] );
+        if (!getenv("NO_COPY"))
+            glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
+
+        pProgram->Clean();
+
+        glBindTexture( GL_TEXTURE_2D, 0 );
+
+        if (!getenv("NO_SWAP"))
+        {
+            mpWindowContext->swapBuffers();
+            if (!getenv("NO_SLEEP"))
+                usleep(500 * 1000);
+        }
+    }
+
+    VCL_GL_INFO( "flushAndSwap - end." );
 }
 
 bool OpenGLSalGraphicsImpl::IsForeignContext(const rtl::Reference<OpenGLContext> &xContext)
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx
index 2d4cb40..b540e96 100644
--- a/vcl/opengl/texture.cxx
+++ b/vcl/opengl/texture.cxx
@@ -349,6 +349,10 @@ void OpenGLTexture::Bind()
         glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture );
         CHECK_GL_ERROR();
     }
+    else
+        VCL_GL_INFO( "OpenGLTexture::Binding invalid texture" );
+
+    CHECK_GL_ERROR();
 }
 
 void OpenGLTexture::Unbind()
diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx
index f57c82d..666cdbf 100644
--- a/vcl/opengl/win/gdiimpl.cxx
+++ b/vcl/opengl/win/gdiimpl.cxx
@@ -29,21 +29,10 @@ void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics*
 rtl::Reference<OpenGLContext> WinOpenGLSalGraphicsImpl::CreateWinContext()
 {
     rtl::Reference<OpenGLContext> pContext = OpenGLContext::Create();
-    pContext->requestSingleBufferedRendering();
     pContext->init( mrParent.mhLocalDC, mrParent.mhWnd );
     return pContext;
 }
 
-bool WinOpenGLSalGraphicsImpl::UseContext( const rtl::Reference<OpenGLContext> &pContext )
-{
-    if( !pContext.is() || !pContext->isInitialized() || IsForeignContext( pContext ) )
-        return false;
-    if( IsOffscreen() )
-        return true;
-    return pContext->getOpenGLWindow().hWnd == mrParent.mhWnd &&
-           pContext->getOpenGLWindow().hDC == mrParent.mhLocalDC;
-}
-
 void WinOpenGLSalGraphicsImpl::Init()
 {
     if ( !IsOffscreen() && mpContext.is() && mpContext->isInitialized() &&
diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx
index 2418bc6..595ca45c 100644
--- a/vcl/opengl/x11/gdiimpl.cxx
+++ b/vcl/opengl/x11/gdiimpl.cxx
@@ -58,18 +58,6 @@ rtl::Reference<OpenGLContext> X11OpenGLSalGraphicsImpl::CreateWinContext()
     return pContext;
 }
 
-bool X11OpenGLSalGraphicsImpl::UseContext( const rtl::Reference<OpenGLContext> &pContext )
-{
-    X11WindowProvider *pProvider = dynamic_cast<X11WindowProvider*>(mrParent.m_pFrame);
-
-    if( !pContext->isInitialized() || IsForeignContext( pContext ) )
-        return false;
-    if( !pProvider )
-        return pContext->getOpenGLWindow().win != None;
-    else
-        return pContext->getOpenGLWindow().win == pProvider->GetX11Window();
-}
-
 void X11OpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics )
 {
     OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrParent.GetImpl());


More information about the Libreoffice-commits mailing list