vcl/unx/gtk3/gtk3gtkinst.cxx |  159 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 140 insertions(+), 19 deletions(-)

New commits:
commit 22e39ae69825e0b83f03b343f22faf065602a72a
Author: Caolán McNamara <caol...@redhat.com>
Date:   Sun Sep 10 21:23:24 2017 +0100

    gtk3: flicker-free opengl transitions
    
    leave the GtkGLArea opengl context alone except for the final render into 
it,
    create a new context for the slide transitions to play with
    
    set up a pair of framebuffers, a scratch one to let the transitions render
    into, the other to take a snapshot when the transition is finished with it 
and
    then tell GtkGLArea we're ready to render it and when the callback comes 
around
    copy the snapshot into it.
    
    Change-Id: I3515614baf7eea0ff53c46edbaf9cf66f926eef2
    Reviewed-on: https://gerrit.libreoffice.org/42144
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Tested-by: Caolán McNamara <caol...@redhat.com>

diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 72b71c9d7519..3cab164d80cf 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -910,6 +910,14 @@ class GtkOpenGLContext : public OpenGLContext
     GLWindow m_aGLWin;
 #if GTK_CHECK_VERSION(3,16,0)
     GtkWidget *m_pGLArea;
+    GdkGLContext *m_pContext;
+    guint m_nAreaFrameBuffer;
+    guint m_nFrameBuffer;
+    guint m_nRenderBuffer;
+    guint m_nDepthBuffer;
+    guint m_nFrameScratchBuffer;
+    guint m_nRenderScratchBuffer;
+    guint m_nDepthScratchBuffer;
 #endif
 
 public:
@@ -917,6 +925,14 @@ public:
         : OpenGLContext()
 #if GTK_CHECK_VERSION(3,16,0)
         , m_pGLArea(nullptr)
+        , m_pContext(nullptr)
+        , m_nAreaFrameBuffer(0)
+        , m_nFrameBuffer(0)
+        , m_nRenderBuffer(0)
+        , m_nDepthBuffer(0)
+        , m_nFrameScratchBuffer(0)
+        , m_nRenderScratchBuffer(0)
+        , m_nDepthScratchBuffer(0)
 #endif
     {
     }
@@ -947,8 +963,73 @@ private:
         GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(context);
         pThis->m_pGLArea = nullptr;
     }
+
+    static gboolean signalRender(GtkGLArea*, GdkGLContext*, gpointer window)
+    {
+        GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(window);
+
+        int scale = gtk_widget_get_scale_factor(pThis->m_pGLArea);
+        int width = pThis->m_aGLWin.Width * scale;
+        int height = pThis->m_aGLWin.Height * scale;
+
+        glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, pThis->m_nAreaFrameBuffer);
+        glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+        glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
+                          GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, 
GL_NEAREST);
+
+        gdk_gl_context_make_current(pThis->m_pContext);
+        return true;
+    }
+
 #endif
 
+    virtual void adjustToNewSize() override
+    {
+#if GTK_CHECK_VERSION(3,16,0)
+        if (m_pGLArea)
+        {
+            int scale = gtk_widget_get_scale_factor(m_pGLArea);
+            int width = m_aGLWin.Width * scale;
+            int height = m_aGLWin.Height * scale;
+
+            gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderBuffer);
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, width, height);
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthBuffer);
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 
width, height);
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nAreaFrameBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_COLOR_ATTACHMENT0_EXT,
+                                         GL_RENDERBUFFER_EXT, m_nRenderBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_DEPTH_ATTACHMENT_EXT,
+                                         GL_RENDERBUFFER_EXT, m_nDepthBuffer);
+
+            gdk_gl_context_make_current(m_pContext);
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderBuffer);
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthBuffer);
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_COLOR_ATTACHMENT0_EXT,
+                                         GL_RENDERBUFFER_EXT, m_nRenderBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_DEPTH_ATTACHMENT_EXT,
+                                         GL_RENDERBUFFER_EXT, m_nDepthBuffer);
+            glViewport(0, 0, width, height);
+
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderScratchBuffer);
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, width, height);
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthScratchBuffer);
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 
width, height);
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_COLOR_ATTACHMENT0_EXT,
+                                         GL_RENDERBUFFER_EXT, 
m_nRenderScratchBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_DEPTH_ATTACHMENT_EXT,
+                                         GL_RENDERBUFFER_EXT, 
m_nDepthScratchBuffer);
+            glViewport(0, 0, width, height);
+        }
+#endif
+    }
+
     virtual bool ImplInit() override
     {
 #if GTK_CHECK_VERSION(3,16,0)
@@ -956,14 +1037,28 @@ private:
         GtkWidget *pParent = static_cast<GtkWidget*>(pEnvData->pWidget);
         m_pGLArea = gtk_gl_area_new();
         g_signal_connect(G_OBJECT(m_pGLArea), "destroy", 
G_CALLBACK(signalDestroy), this);
+        g_signal_connect(G_OBJECT(m_pGLArea), "render", 
G_CALLBACK(signalRender), this);
         gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA(m_pGLArea), true);
         gtk_gl_area_set_auto_render(GTK_GL_AREA(m_pGLArea), false);
         gtk_widget_set_hexpand(m_pGLArea, true);
         gtk_widget_set_vexpand(m_pGLArea, true);
         gtk_container_add(GTK_CONTAINER(pParent), m_pGLArea);
         gtk_widget_show_all(pParent);
+
         gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
         gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea));
+        glGenFramebuffersEXT(1, &m_nAreaFrameBuffer);
+
+        GdkWindow *pWindow = gtk_widget_get_window(pParent);
+        m_pContext = gdk_window_create_gl_context(pWindow, nullptr);
+        gdk_gl_context_realize(m_pContext, nullptr);
+        gdk_gl_context_make_current(m_pContext);
+        glGenFramebuffersEXT(1, &m_nFrameBuffer);
+        glGenRenderbuffersEXT(1, &m_nRenderBuffer);
+        glGenRenderbuffersEXT(1, &m_nDepthBuffer);
+        glGenFramebuffersEXT(1, &m_nFrameScratchBuffer);
+        glGenRenderbuffersEXT(1, &m_nRenderScratchBuffer);
+        glGenRenderbuffersEXT(1, &m_nDepthScratchBuffer);
 #endif
         bool bRet = InitGL();
         InitGLDebugging();
@@ -974,23 +1069,12 @@ private:
     virtual void restoreDefaultFramebuffer() override
     {
         OpenGLContext::restoreDefaultFramebuffer();
-        gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea));
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
+        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_COLOR_ATTACHMENT0_EXT,
+                                     GL_RENDERBUFFER_EXT, 
m_nRenderScratchBuffer);
     }
 #endif
 
-    virtual void adjustToNewSize() override
-    {
-#if GTK_CHECK_VERSION(3,16,0)
-        if (m_pGLArea)
-        {
-            int scale = gtk_widget_get_scale_factor(m_pGLArea);
-            int width = m_aGLWin.Width * scale;
-            int height = m_aGLWin.Height * scale;
-            glViewport(0, 0, width, height);
-        }
-#endif
-    }
-
     virtual void makeCurrent() override
     {
         if (isCurrent())
@@ -1000,7 +1084,22 @@ private:
 
 #if GTK_CHECK_VERSION(3,16,0)
         if (m_pGLArea)
-            gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
+        {
+            int scale = gtk_widget_get_scale_factor(m_pGLArea);
+            int width = m_aGLWin.Width * scale;
+            int height = m_aGLWin.Height * scale;
+
+            gdk_gl_context_make_current(m_pContext);
+
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderScratchBuffer);
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthScratchBuffer);
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_COLOR_ATTACHMENT0_EXT,
+                                         GL_RENDERBUFFER_EXT, 
m_nRenderScratchBuffer);
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 
GL_DEPTH_ATTACHMENT_EXT,
+                                         GL_RENDERBUFFER_EXT, 
m_nDepthScratchBuffer);
+            glViewport(0, 0, width, height);
+        }
 #endif
 
         registerAsCurrent();
@@ -1016,7 +1115,7 @@ private:
     virtual bool isCurrent() override
     {
 #if GTK_CHECK_VERSION(3,16,0)
-        return m_pGLArea && gdk_gl_context_get_current() == 
gtk_gl_area_get_context(GTK_GL_AREA(m_pGLArea));
+        return m_pGLArea && gdk_gl_context_get_current() == m_pContext;
 #else
         return false;
 #endif
@@ -1024,9 +1123,6 @@ private:
 
     virtual void sync() override
     {
-#if GTK_CHECK_VERSION(3,16,0)
-        gtk_gl_area_queue_render(GTK_GL_AREA(m_pGLArea));
-#endif
     }
 
     virtual void resetCurrent() override
@@ -1040,10 +1136,35 @@ private:
     virtual void swapBuffers() override
     {
 #if GTK_CHECK_VERSION(3,16,0)
+        int scale = gtk_widget_get_scale_factor(m_pGLArea);
+        int width = m_aGLWin.Width * scale;
+        int height = m_aGLWin.Height * scale;
+
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_nFrameBuffer);
+        glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, m_nFrameScratchBuffer);
+        glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+        glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
+                          GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, 
GL_NEAREST);
+
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_nFrameScratchBuffer);
+        glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
         gtk_gl_area_queue_render(GTK_GL_AREA(m_pGLArea));
 #endif
         BuffersSwapped();
     }
+#if GTK_CHECK_VERSION(3,16,0)
+    virtual ~GtkOpenGLContext() override
+    {
+        if (m_pContext)
+        {
+            g_clear_object(&m_pContext);
+        }
+    }
+#endif
 };
 
 OpenGLContext* GtkInstance::CreateOpenGLContext()
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to