91334d
From 6969cdac8e04e65f00f4fec9f681ebbf243f0945 Mon Sep 17 00:00:00 2001
91334d
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
91334d
Date: Sun, 10 Sep 2017 16:07:49 +0100
91334d
Subject: [PATCH] gtk3: flicker-free opengl transitions
91334d
MIME-Version: 1.0
91334d
Content-Type: text/plain; charset=UTF-8
91334d
Content-Transfer-Encoding: 8bit
91334d
91334d
leave the GtkGLArea opengl context alone except for the final render into it,
91334d
create a new context for the slide transitions to play with
91334d
91334d
set up a pair of framebuffers, a scratch one to let the transitions render
91334d
into, the other to take a snapshot when the transition is finished with it and
91334d
then tell GtkGLArea we're ready to render it and when the callback comes around
91334d
copy the snapshot into it.
91334d
91334d
Change-Id: I3515614baf7eea0ff53c46edbaf9cf66f926eef2
91334d
91334d
hidpi+gtk3: move setting the opengl slide viewport
91334d
91334d
to when the window size is set, and adjust to gtk3 hidpi
91334d
scaling factor
91334d
91334d
Change-Id: Id9bd0defd0b6ae640ac57f88133d954202d4bcc3
91334d
Reviewed-on: https://gerrit.libreoffice.org/42143
91334d
Tested-by: Jenkins <ci@libreoffice.org>
91334d
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
91334d
Tested-by: Caolán McNamara <caolanm@redhat.com>
91334d
(cherry picked from commit 1a547a566eba5943f9e4d9987baf4aee80846dd1)
91334d
---
91334d
 include/vcl/opengl/OpenGLContext.hxx               |   1 +
91334d
 .../source/engine/opengl/TransitionerImpl.cxx      |   1 -
91334d
 vcl/source/opengl/OpenGLContext.cxx                |  11 +-
91334d
 vcl/unx/gtk3/gtk3gtkinst.cxx                       | 151 ++++++++++++++++++++-
91334d
 5 files changed, 166 insertions(+), 23 deletions(-)
91334d
91334d
diff --git a/include/vcl/opengl/OpenGLContext.hxx b/include/vcl/opengl/OpenGLContext.hxx
91334d
index 5796f7e..c9b1c81 100644
91334d
--- a/include/vcl/opengl/OpenGLContext.hxx
91334d
+++ b/include/vcl/opengl/OpenGLContext.hxx
91334d
@@ -158,6 +158,7 @@ public:
91334d
 private:
91334d
     virtual bool initWindow();
91334d
     virtual void destroyCurrentContext();
91334d
+    virtual void adjustToNewSize();
91334d
 
91334d
 protected:
91334d
     bool InitGL();
91334d
diff --git a/slideshow/source/engine/opengl/TransitionerImpl.cxx b/slideshow/source/engine/opengl/TransitionerImpl.cxx
91334d
index c958389..06e1123 100644
91334d
--- a/slideshow/source/engine/opengl/TransitionerImpl.cxx
91334d
+++ b/slideshow/source/engine/opengl/TransitionerImpl.cxx
91334d
@@ -346,7 +346,6 @@ bool OGLTransitionerImpl::initWindowFromSlideShowView( const Reference< presenta
91334d
 
91334d
     mpContext->swapBuffers();
91334d
 
91334d
-    glViewport(0, 0, aCanvasArea.Width, aCanvasArea.Height);
91334d
     CHECK_GL_ERROR();
91334d
 
91334d
     return true;
91334d
diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx
91334d
index 42fba6d..51517ca 100644
91334d
--- a/vcl/source/opengl/OpenGLContext.cxx
91334d
+++ b/vcl/source/opengl/OpenGLContext.cxx
91334d
@@ -338,14 +338,21 @@ void OpenGLContext::restoreDefaultFramebuffer()
91334d
 
91334d
 void OpenGLContext::setWinPosAndSize(const Point &rPos, const Size& rSize)
91334d
 {
91334d
-    if(m_xWindow)
91334d
+    if (m_xWindow)
91334d
         m_xWindow->SetPosSizePixel(rPos, rSize);
91334d
-    if( m_pChildWindow )
91334d
+    if (m_pChildWindow)
91334d
         m_pChildWindow->SetPosSizePixel(rPos, rSize);
91334d
 
91334d
     GLWindow& rGLWin = getModifiableOpenGLWindow();
91334d
     rGLWin.Width = rSize.Width();
91334d
     rGLWin.Height = rSize.Height();
91334d
+    adjustToNewSize();
91334d
+}
91334d
+
91334d
+void OpenGLContext::adjustToNewSize()
91334d
+{
91334d
+    const GLWindow& rGLWin = getOpenGLWindow();
91334d
+    glViewport(0, 0, rGLWin.Width, rGLWin.Height);
91334d
 }
91334d
 
91334d
 void OpenGLContext::setWinSize(const Size& rSize)
91334d
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
91334d
index 3d20cca..a37deb0 100644
91334d
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
91334d
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
91334d
@@ -923,12 +923,32 @@ Reference< XInterface > GtkInstance::CreateDragSource()
91334d
 class GtkOpenGLContext : public OpenGLContext
91334d
 {
91334d
     GLWindow m_aGLWin;
91334d
+#if GTK_CHECK_VERSION(3,16,0)
91334d
     GtkWidget *m_pGLArea;
91334d
+    GdkGLContext *m_pContext;
91334d
+    guint m_nAreaFrameBuffer;
91334d
+    guint m_nFrameBuffer;
91334d
+    guint m_nRenderBuffer;
91334d
+    guint m_nDepthBuffer;
91334d
+    guint m_nFrameScratchBuffer;
91334d
+    guint m_nRenderScratchBuffer;
91334d
+    guint m_nDepthScratchBuffer;
91334d
+#endif
91334d
 
91334d
 public:
91334d
     GtkOpenGLContext()
91334d
         : OpenGLContext()
91334d
+#if GTK_CHECK_VERSION(3,16,0)
91334d
         , m_pGLArea(nullptr)
91334d
+        , m_pContext(nullptr)
91334d
+        , m_nAreaFrameBuffer(0)
91334d
+        , m_nFrameBuffer(0)
91334d
+        , m_nRenderBuffer(0)
91334d
+        , m_nDepthBuffer(0)
91334d
+        , m_nFrameScratchBuffer(0)
91334d
+        , m_nRenderScratchBuffer(0)
91334d
+        , m_nDepthScratchBuffer(0)
91334d
+#endif
91334d
     {
91334d
     }
91334d
 
91334d
@@ -952,12 +972,78 @@ private:
91334d
     virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
91334d
     virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
91334d
 
91334d
+#if GTK_CHECK_VERSION(3,16,0)
91334d
     static void signalDestroy(GtkWidget*, gpointer context)
91334d
     {
91334d
         GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(context);
91334d
         pThis->m_pGLArea = nullptr;
91334d
     }
91334d
 
91334d
+    static gboolean signalRender(GtkGLArea*, GdkGLContext*, gpointer window)
91334d
+    {
91334d
+        GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(window);
91334d
+
91334d
+        int scale = gtk_widget_get_scale_factor(pThis->m_pGLArea);
91334d
+        int width = pThis->m_aGLWin.Width * scale;
91334d
+        int height = pThis->m_aGLWin.Height * scale;
91334d
+
91334d
+        glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
91334d
+
91334d
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, pThis->m_nAreaFrameBuffer);
91334d
+        glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
91334d
+
91334d
+        glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
91334d
+                          GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
91334d
+
91334d
+        gdk_gl_context_make_current(pThis->m_pContext);
91334d
+        return true;
91334d
+    }
91334d
+#endif
91334d
+
91334d
+    virtual void adjustToNewSize() override
91334d
+    {
91334d
+#if GTK_CHECK_VERSION(3,16,0)
91334d
+        if (m_pGLArea)
91334d
+        {
91334d
+            int scale = gtk_widget_get_scale_factor(m_pGLArea);
91334d
+            int width = m_aGLWin.Width * scale;
91334d
+            int height = m_aGLWin.Height * scale;
91334d
+
91334d
+            gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderBuffer);
91334d
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, width, height);
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthBuffer);
91334d
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
91334d
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nAreaFrameBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nRenderBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nDepthBuffer);
91334d
+
91334d
+            gdk_gl_context_make_current(m_pContext);
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderBuffer);
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthBuffer);
91334d
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nRenderBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nDepthBuffer);
91334d
+            glViewport(0, 0, width, height);
91334d
+
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderScratchBuffer);
91334d
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, width, height);
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthScratchBuffer);
91334d
+            glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
91334d
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nRenderScratchBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nDepthScratchBuffer);
91334d
+            glViewport(0, 0, width, height);
91334d
+        }
91334d
+#endif
91334d
+    }
91334d
+
91334d
     virtual bool ImplInit() override
91334d
     {
91334d
 #if GTK_CHECK_VERSION(3,16,0)
91334d
@@ -965,14 +1051,28 @@ private:
91334d
         GtkWidget *pParent = static_cast<GtkWidget*>(pEnvData->pWidget);
91334d
         m_pGLArea = gtk_gl_area_new();
91334d
         g_signal_connect(G_OBJECT(m_pGLArea), "destroy", G_CALLBACK(signalDestroy), this);
91334d
+        g_signal_connect(G_OBJECT(m_pGLArea), "render", G_CALLBACK(signalRender), this);
91334d
         gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA(m_pGLArea), true);
91334d
         gtk_gl_area_set_auto_render(GTK_GL_AREA(m_pGLArea), false);
91334d
         gtk_widget_set_hexpand(m_pGLArea, true);
91334d
         gtk_widget_set_vexpand(m_pGLArea, true);
91334d
         gtk_container_add(GTK_CONTAINER(pParent), m_pGLArea);
91334d
         gtk_widget_show_all(pParent);
91334d
+
91334d
         gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
91334d
         gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea));
91334d
+        glGenFramebuffersEXT(1, &m_nAreaFrameBuffer);
91334d
+
91334d
+        GdkWindow *pWindow = gtk_widget_get_window(pParent);
91334d
+        m_pContext = gdk_window_create_gl_context(pWindow, nullptr);
91334d
+        gdk_gl_context_realize(m_pContext, nullptr);
91334d
+        gdk_gl_context_make_current(m_pContext);
91334d
+        glGenFramebuffersEXT(1, &m_nFrameBuffer);
91334d
+        glGenRenderbuffersEXT(1, &m_nRenderBuffer);
91334d
+        glGenRenderbuffersEXT(1, &m_nDepthBuffer);
91334d
+        glGenFramebuffersEXT(1, &m_nFrameScratchBuffer);
91334d
+        glGenRenderbuffersEXT(1, &m_nRenderScratchBuffer);
91334d
+        glGenRenderbuffersEXT(1, &m_nDepthScratchBuffer);
91334d
 #endif
91334d
         bool bRet = InitGL();
91334d
         InitGLDebugging();
91334d
@@ -983,7 +1083,9 @@ private:
91334d
     {
91334d
         OpenGLContext::restoreDefaultFramebuffer();
91334d
 #if GTK_CHECK_VERSION(3,16,0)
91334d
-        gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea));
91334d
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
91334d
+        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
91334d
+                                     GL_RENDERBUFFER_EXT, m_nRenderScratchBuffer);
91334d
 #endif
91334d
     }
91334d
 
91334d
@@ -996,7 +1098,22 @@ private:
91334d
 
91334d
 #if GTK_CHECK_VERSION(3,16,0)
91334d
         if (m_pGLArea)
91334d
-            gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea));
91334d
+        {
91334d
+            int scale = gtk_widget_get_scale_factor(m_pGLArea);
91334d
+            int width = m_aGLWin.Width * scale;
91334d
+            int height = m_aGLWin.Height * scale;
91334d
+
91334d
+            gdk_gl_context_make_current(m_pContext);
91334d
+
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nRenderScratchBuffer);
91334d
+            glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthScratchBuffer);
91334d
+            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameScratchBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nRenderScratchBuffer);
91334d
+            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
91334d
+                                         GL_RENDERBUFFER_EXT, m_nDepthScratchBuffer);
91334d
+            glViewport(0, 0, width, height);
91334d
+        }
91334d
 #endif
91334d
 
91334d
         registerAsCurrent();
91334d
@@ -1012,7 +1129,7 @@ private:
91334d
     virtual bool isCurrent() override
91334d
     {
91334d
 #if GTK_CHECK_VERSION(3,16,0)
91334d
-        return m_pGLArea && gdk_gl_context_get_current() == gtk_gl_area_get_context(GTK_GL_AREA(m_pGLArea));
91334d
+        return m_pGLArea && gdk_gl_context_get_current() == m_pContext;
91334d
 #else
91334d
         return false;
91334d
 #endif
91334d
@@ -1020,9 +1137,6 @@ private:
91334d
 
91334d
     virtual void sync() override
91334d
     {
91334d
-#if GTK_CHECK_VERSION(3,16,0)
91334d
-        gtk_gl_area_queue_render(GTK_GL_AREA(m_pGLArea));
91334d
-#endif
91334d
     }
91334d
 
91334d
     virtual void resetCurrent() override
91334d
@@ -1036,10 +1150,35 @@ private:
91334d
     virtual void swapBuffers() override
91334d
     {
91334d
 #if GTK_CHECK_VERSION(3,16,0)
91334d
+        int scale = gtk_widget_get_scale_factor(m_pGLArea);
91334d
+        int width = m_aGLWin.Width * scale;
91334d
+        int height = m_aGLWin.Height * scale;
91334d
+
91334d
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_nFrameBuffer);
91334d
+        glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
91334d
+
91334d
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, m_nFrameScratchBuffer);
91334d
+        glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
91334d
+
91334d
+        glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
91334d
+                          GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
91334d
+
91334d
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_nFrameScratchBuffer);
91334d
+        glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
91334d
+
91334d
         gtk_gl_area_queue_render(GTK_GL_AREA(m_pGLArea));
91334d
 #endif
91334d
         BuffersSwapped();
91334d
     }
91334d
+#if GTK_CHECK_VERSION(3,16,0)
91334d
+    virtual ~GtkOpenGLContext() override
91334d
+    {
91334d
+        if (m_pContext)
91334d
+        {
91334d
+            g_clear_object(&m_pContext);
91334d
+        }
91334d
+    }
91334d
+#endif
91334d
 };
91334d
 
91334d
 OpenGLContext* GtkInstance::CreateOpenGLContext()
91334d
-- 
91334d
2.9.5
91334d