diff options
author | Caolán McNamara <caolanm@redhat.com> | 2017-09-10 21:23:24 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2017-09-11 11:45:06 +0200 |
commit | 22e39ae69825e0b83f03b343f22faf065602a72a (patch) | |
tree | 65b86499e17173b991ff7436e9b8babff50053b4 | |
parent | 80b04f3d767bced56c68839731c48284bc1a59e3 (diff) |
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 <ci@libreoffice.org>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 159 |
1 files changed, 140 insertions, 19 deletions
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() |