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