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